Bug 18567 - Frame filters apply to 'backtrace' but not 'frame' command
Summary: Frame filters apply to 'backtrace' but not 'frame' command
Status: NEW
Alias: None
Product: gdb
Classification: Unclassified
Component: python (show other bugs)
Version: HEAD
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks: 19923
  Show dependency treegraph
 
Reported: 2015-06-20 17:58 IST by Jan Kratochvil
Modified: 2016-06-23 14:10 IST (History)
4 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jan Kratochvil 2015-06-20 17:58:56 IST
Summary says it all.

(gdb) frame
#0  main () at inlined2.c:14
14	  func (1);
(gdb) bt
#0  0x0000000000400501 in niam () at inlined2.c:14
(gdb) 

This makes the output inconsistent, IMO 'frame' should behave like 'bt 0'.
'core-file' command also calls 'frame' at its end which misses the Python frame filters decorations.
Comment 1 Tom Tromey 2016-02-10 20:32:33 IST
I ran into this today as well.
This is somewhat of a pain when using a frame filter,
because it means that one must refer to the "bt" output
constantly in order to navigate frames properly.
Comment 2 Phil Muldoon 2016-04-13 19:06:07 IST
Yes, that's a design intent. They only apply (at the moment) to backtraces (in MI and CLI). That being said, let's revisit that decision.

I'm not sure how a frame filter can apply to a single line of output? Frame filters receive and return an iterator of frame decorators that are printed out when the frame filter chain is exausted. If one frame is only ever printed (regardless, say, if the iterator had more than one), then a frame filter is not needed: there's nothing to filter. Perhaps we could apply a single frame decorator? 

However, that would be a pain as previously written frame filters that would apply to backtraces would have to adapt to just returning one frame for these and other commands. I suppose we could, in fact, take a frame filter here and just print the first frame as a compromise; this would allow existing frame filters to just work.
Comment 3 Pedro Alves 2016-04-13 19:18:44 IST
I have not delved into the details, but this feels in principle similar to inline frames.

With inline frames, if you do "backtrace", you see all the inline expansions as virtual frames.  For the user, the inline frames look like normal frames.  If you do "up", gdb peels out one inline expansion.  Another "up", another level.  Enough "up"s, and you're now looking at the "real" stack frame where the first inline expansion happened.

With frame filters, a similar thing sounds like would be needed.  If you backtrace and see:

(gdb) bt
#0  0x0000000000400501 in foo () at foo.c:14
#1  0x0000000000401000 in bar () at bar.c:32

... and those were frames cooked by, or decorated by, a frame filter, then, I'd expect that if you "frame", gdb first shows:

#0  0x0000000000400501 in foo () at foo.c:14

and then if you do "up", then "frame", gdb shows:

#1  0x0000000000401000 in bar () at bar.c:32

Does that make sense?
Comment 4 Andrew Dinn 2016-04-14 08:36:24 IST
(In reply to Phil Muldoon from comment #2)
> Yes, that's a design intent. They only apply (at the moment) to backtraces
> (in MI and CLI). That being said, let's revisit that decision.
> 
> I'm not sure how a frame filter can apply to a single line of output? Frame
> filters receive and return an iterator of frame decorators that are printed
> out when the frame filter chain is exausted. If one frame is only ever
> printed (regardless, say, if the iterator had more than one), then a frame
> filter is not needed: there's nothing to filter. Perhaps we could apply a
> single frame decorator? 

Can you not achieve this by subclassing the frame_iter so that only produces one frame at the required index in the frame list? That way when you only need one frame decorated you can pass a subclassed iter to the frame filter and get a single frame decorator back but for the case where you want all frames decorated (under bt) you can pass the current iter.

> However, that would be a pain as previously written frame filters that would
> apply to backtraces would have to adapt to just returning one frame for
> these and other commands. I suppose we could, in fact, take a frame filter
> here and just print the first frame as a compromise; this would allow
> existing frame filters to just work.

I think it would be better for performance if only the one frame were presented to the filter.
Comment 5 Tom Tromey 2016-04-14 17:59:39 IST
(In reply to Phil Muldoon from comment #2)

> I'm not sure how a frame filter can apply to a single line of output?

I think the simplest way here is to start the frame iteration process
at the selected frame (not the newest frame); and then just request a
single frame from the iterator and print that.

> If one frame is only ever
> printed (regardless, say, if the iterator had more than one), then a frame
> filter is not needed: there's nothing to filter. Perhaps we could apply a
> single frame decorator? 

Yeah, just request one from the iteration process.

A frame filter may choose to consume multiple frames in order to do its
filtering.  That's ok though.

The concrete case for SpiderMonkey is that the JIT unwinder has found
some frames -- but we don't add any display information from the unwinder
(you really just can't and anyway if you could it is too hard anyway);
so all the user-useful information is delegated to the frame filter.

In this case the frame filter is always 1:1 with underlying frames,
though of course there's no reason to restrict things in this way.

> However, that would be a pain as previously written frame filters that would
> apply to backtraces would have to adapt to just returning one frame for
> these and other commands.

Well-written frame filters are supposed to be lazy already.
And, even if they aren't, it doesn't matter, since gdb can always
choose exactly what it prints.

One way to look at this is that "bt" is paginated and nothing breaks
if we don't print every single frame in the stack every time.
Comment 6 Tom Tromey 2016-04-14 18:05:42 IST
(In reply to Pedro Alves from comment #3)

> With frame filters, a similar thing sounds like would be needed.  If you
> backtrace and see:
> 
> (gdb) bt
> #0  0x0000000000400501 in foo () at foo.c:14
> #1  0x0000000000401000 in bar () at bar.c:32
> 
> ... and those were frames cooked by, or decorated by, a frame filter, then,
> I'd expect that if you "frame", gdb first shows:
> 
> #0  0x0000000000400501 in foo () at foo.c:14
> 
> and then if you do "up", then "frame", gdb shows:
> 
> #1  0x0000000000401000 in bar () at bar.c:32
> 
> Does that make sense?

It does, but I'm not sure it is really what users will want.

Consider an "aggregating" frame filter.  An example here would be
Python (if it had a frame filter, which it can't due to a gcc bug) --
in Python, it might take multiple C stack frames to implement a single
Python interpreter stack frame.  And, the frame filter would represent
this by collapsing several C frames as the children of one Python frame,
like:

#0 ... something.py:99
  #1 ... something.c
  #2 ... somethingelse.c
#3 ... secondfile.py:10

etc

I would probably be confused if I was in frame #0 and typed "up"
and ended up in frame #3.

Also, one must consider that if frame filters apply to up and down,
then why not step, next, and finish?  And then you're in for some
difficult implementation stuff I think...

So, while I'm not against this -- I think it is necessary for the
long-term goal of interpreted language debugging --   I think it's
better to defer it to a future bug.

Up until now frame filters have been purely a display issue.  I
think it would be fine for them to remain as such, and just make
the output of "frame", stop notifications, etc, respect filtering;
without touching up/down/etc.
Comment 7 Pedro Alves 2016-04-14 18:36:36 IST
> I would probably be confused if I was in frame #0 and typed "up"
> and ended up in frame #3.

Maybe I'm thinking of the opposite scenario.

Say, if you're debugging for example GDB's Python code, and a filter hides the Python interpreter detail of gdb code calling Python code calling gdb code, like:

#0  ... gdb/python/python.c:99
#1  ... something.py:99
  #2  ... python-interp-internals.c
  ...
  #10 ... python-interp-internals.c
#11 ... gdb/python/python.c:99

I'd think that "up" on frame #1 going straight to frame #11 would be helpful.

Likewise in the "hiding glib signal-emission frames" use case.

> Also, one must consider that if frame filters apply to up and down,
> then why not step, next, and finish?  And then you're in for some
> difficult implementation stuff I think...

At least the inline-frames example shows that this should be possible.
GDB already treats "step" when stopped at an inline frame, differently (infcmd.c:prepare_one_step -> inline_skipped_frames), which I was imagining could be generalized to all kinds of virtual frames.

But yeah, if a simpler approach is already helpful, by all means!
Comment 8 Tom Tromey 2016-06-23 14:10:39 IST
I looked into implementing the simplest form of this, just
changing print_stack_frame to use frame filters if they exist.
It turns out that dealing with printing the source line is
somewhat difficult.