public inbox for gdb@sourceware.org
 help / color / mirror / Atom feed
* Frame unwind functions
@ 2003-03-11 18:35 Michal Ludvig
  2003-03-11 22:04 ` Andrew Cagney
  0 siblings, 1 reply; 4+ messages in thread
From: Michal Ludvig @ 2003-03-11 18:35 UTC (permalink / raw)
  To: GDB list, Andrew Cagney

Hi all,
since there are different unwind mechanisms in different branches of GDB 
I got a bit lost. I need to sort my thoughts to understand the principles.

First my view of how things now work:

A) One pass to get frame-id:
- process hits a breakpoint and GDB takes control of it.
- it can get values of all registers by simply reading them, and is
   especially interested in PC (%eip on i386) and SP (%esp).
- GDB can somehow determine the frame address FP (ie. top of the stack),
   either by taking it from %ebp on i386 or by CFI unwinding of SP.
- PC and FP together makes a Frame-ID of the innermost frame.
   (Or is frame-id something else?)

B) Now how to do a backtrace:
- first call to get_prev_frame() passes as an argument a pre-filled
   struct frame_info as the 'next_frame' parameter. It only has
   next_frame->pc filled with current PC (%eip), next_frame->unwind
   pointing to sentinel unwinder and a level==-1, which describes
   a sentinel frame.
- GDB creates an empty prev_frame, and sets its level.
- to get current PC we call next_frame->unwind->pc(). In the case of a
   sentinel frame it just reads a PC register from the inferior.
- How to get current FP depends of type of the current frame
   (ie. prev_frame).
   - on i386 we read it from FP register (%ebp)
   - in a CFI frame we read the value of the SP register (by calling
     unwind->reg(SP_REGNUM) for the next_frame, which is a sentinel one,
     ie. we read the SP register directly) and unwind it to get it's
     value at the beginning of the function.
- PC and FP together make up frame id.

C) All subsequent calls to get_prev_frame() always pass next_frame as 
the parameter and:
- Create prev_frame with appropriate level.
- Get current PC in this frame by calling next_frame->unwind->pc()
   - in the case of the normal i386 frame it reads a return address from
     the stack where next_frame->frame points to (plus sizeof(PC)).
   - in the case of CFI frames we must ask the CFI engine to give us the
     return address of the next_frame.
   - if next_frame is a sigtramp frame, PC is read from the saved
     sigcontext on the stack.
- Get FP for this frame
   - in the case of the normal i386 frame it reads the saved %ebp at the
     address of next_frame->frame.
   - in the case of CFI frames we must obtain the SP first. This is
     basically next_frame->frame value (perhaps adjusted by an offset).
     Now we ask the engine to give us the value of SP at the time the
     function was entered, i.e. we must unwind it. This way we get FP.
   - If next_frame is a sigtramp, SP (or FP) is read from the stack
     similarly to PC.
- PC and FP together make up frame id.

So far so good, I hope. Or did I miss something?

But how about registers and parameters?
- In the innermost frame I know the values of all registers.
- By using a CFI engine I could unwind some of them to the state they've
   had when the frame was entered - do I save these values somewhere or
   are they generated on-the-fly when the given frame's unwind_reg() is
   called?
- In the backtrace the function's arguments are printed as well.
   - on i386 it's not a problem since they are on the stack
   - on x86-64 we pass some of them in registers
     - that's fine for the first frame (#0) - I know all registers and I
       can use location lists to find current position of a given arg.
     - for the second frame (#1) I could call
       next_frame->unwind->reg(regnum) to get the register I need and
       unwind it even more by calling this_frame->unwind->reg(regnum) to
       get it's value at the beginning of the frame.
     - but how about the next frames (#2,...)? I can always call
       next_frame->unwind->reg(regnum) and if the next_frame wouldn't
       know its "initial" value (ie. the value at the place of PC) it
       would recursively call next_frame->next_frame->unwind->register()
       untill it get's the value.
This is not desired I think. If I understand the MarkK's code from 
i386newframe branch he saves all known register's positions (stack 
addresses) to frame->unwind_cache (casted to struct i386_frame_cache). 
But it isn't a generic approach. Should all these registers be somehow 
written to the regcache instead? Or to frame->saved_regs? If so, then 
when and where? I think CFI uses it's own frame->context structure for 
this purpose, but I'd like to avoid using it for non-cfi frames.

If I would have all registers saved in each next_frame then I could only 
call next_frame->unwind->reg(regnum) and get the current value. Then 
store it somewhere in this_frame and use as if I just read it from the 
inferior. I believe there is something similar already implemented in 
the GDB but I don't know how. Could someone explain me this thing, please?

Well, long mail, isn't it? But I would like to know if I understand 
correctly what the new frame unwinding stuff does or if I'm missing 
something important.

Thanks for your time,

Michal Ludvig
-- 
* SuSE CR, s.r.o     * mludvig@suse.cz
* (+420) 296.545.373 * http://www.suse.cz

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Frame unwind functions
  2003-03-11 18:35 Frame unwind functions Michal Ludvig
@ 2003-03-11 22:04 ` Andrew Cagney
  2003-03-12  8:11   ` Michal Ludvig
  0 siblings, 1 reply; 4+ messages in thread
From: Andrew Cagney @ 2003-03-11 22:04 UTC (permalink / raw)
  To: Michal Ludvig; +Cc: GDB list

> Hi all,
> since there are different unwind mechanisms in different branches of GDB I got a bit lost. I need to sort my thoughts to understand the principles.
> 
> First my view of how things now work:

To be honest, this a very good description of how GDB did work: special 
case on top of special case on top of ....

The first thing to discard is the assumption that the inner most frame 
is, in anyway special.

The introduction of a sentinel frame has ment the elimination of a 
special case code to handle the inner most frame.  Instead there is 
always a more inner frame.  As a consequence, a body of code can always 
use the frame unwind methods to get value of a register.

What was previously written:

	if (frame->level == 0)
	  return read_pc();
	else if (frame->type == DUMMY_FRAME)
	  return deprecated_read_dummy_register (frame, PC_REGNUM);
	else if (pc in sigtramp (...))
	  return something to do with a sigtramp;
	else
	  return get_saved_register (frame->prev, ...);

can now be written as simply:

	frame_unwind_register (frame, PC_REGNUM, ...);


> A) One pass to get frame-id:

The new way is:

- find prev's frame's PC using gdbarch_unwind_pc(this)
- use the PC to identify prev's frame's unwinder
- use prev's frame's unwinder's id method to find prev's frame's ID

this algorithm is used on any frame.

> - process hits a breakpoint and GDB takes control of it.
> - it can get values of all registers by simply reading them, and is
>   especially interested in PC (%eip on i386) and SP (%esp).

No matter what the frame, to obtain a value for that frame the code uses:

	frame_register_unwind (next, regnum, ...);

> - GDB can somehow determine the frame address FP (ie. top of the stack),
>   either by taking it from %ebp on i386 or by CFI unwinding of SP.

Right.  It get's the ID using that frame's ID method.

> - PC and FP together makes a Frame-ID of the innermost frame.
>   (Or is frame-id something else?)

That's it.

The key property being that the base is consant through out the lifetime 
of a frame (At some stage in the future PC may be replaced by function, 
and a second base might be added).

> B) Now how to do a backtrace:
> - first call to get_prev_frame() passes as an argument a pre-filled
>   struct frame_info as the 'next_frame' parameter. It only has
>   next_frame->pc filled with current PC (%eip), next_frame->unwind
>   pointing to sentinel unwinder and a level==-1, which describes
>   a sentinel frame.

All frames are created alike using get_prev_frame().  Even the inner 
most.  The only exception is the sentinel frame.

There is no `case b'.

> - GDB creates an empty prev_frame, and sets its level.
> - to get current PC we call next_frame->unwind->pc(). In the case of a
>   sentinel frame it just reads a PC register from the inferior.

GDB calls gdbarch_unwind_pc(this_frame) which is expected to use only 
unwind methods to compute the PC of this new frame.  The method must be 
frame agnostic - it works with any next_frame.

> - How to get current FP depends of type of the current frame
>   (ie. prev_frame).

Right.  But for get_prev_frame() it calls the frame's unwinder's get id 
method.  There are separate unwinders for each of the cases you mention, 
the correct unwinder being called by get_prev_frame().

>   - on i386 we read it from FP register (%ebp)
>   - in a CFI frame we read the value of the SP register (by calling
>     unwind->reg(SP_REGNUM) for the next_frame, which is a sentinel one,
>     ie. we read the SP register directly) and unwind it to get it's
>     value at the beginning of the function.
> - PC and FP together make up frame id.

> C) All subsequent calls to get_prev_frame() always pass next_frame as the parameter and:

But, all subsequent calls to get_prev_frame() are identical to the first.

There is no `case c'.

> So far so good, I hope. Or did I miss something?
> 
> But how about registers and parameters?
> - In the innermost frame I know the values of all registers.

No.  The code should never differentiate an inner most frame.  Instead, 
always obtain register values by unwinding them from the next frame.

> - By using a CFI engine I could unwind some of them to the state they've
>   had when the frame was entered - do I save these values somewhere or
>   are they generated on-the-fly when the given frame's unwind_reg() is
>   called?

You just need to compute those values on the fly.  Don't bother with 
efficiency smarts.

If performance is ever demonstrated to be a problem then the frame code 
can be tweaked to cache values.

> - In the backtrace the function's arguments are printed as well.
>   - on i386 it's not a problem since they are on the stack
>   - on x86-64 we pass some of them in registers
>     - that's fine for the first frame (#0) - I know all registers and I
>       can use location lists to find current position of a given arg.
>     - for the second frame (#1) I could call
>       next_frame->unwind->reg(regnum) to get the register I need and
>       unwind it even more by calling this_frame->unwind->reg(regnum) to
>       get it's value at the beginning of the frame.
>     - but how about the next frames (#2,...)? I can always call
>       next_frame->unwind->reg(regnum) and if the next_frame wouldn't
>       know its "initial" value (ie. the value at the place of PC) it
>       would recursively call next_frame->next_frame->unwind->register()
>       untill it get's the value.

The above is the desired and correct behavior.  This recursion is 
required for things to work (a stack is recursive by definition).

Have a look at the `info frames' `saved regs' output.

> This is not desired I think. If I understand the MarkK's code from i386newframe branch he saves all known register's positions (stack addresses) to frame->unwind_cache (casted to struct i386_frame_cache). But it isn't a generic approach. Should all these registers be somehow written to the regcache instead? Or to frame->saved_regs? If so, then when and where? I think CFI uses it's own frame->context structure for this purpose, but I'd like to avoid using it for non-cfi frames.

Mark is handling the simple prologue analysis case.  Consider a a stack 
frame consisting of:

(outer) cfi -> trad -> cfi -> sigtramp -> cfi -> sentinel (inner)

Even though the three CFI frames have different more inner frames, all 
three use an identical code base.  And none contain special case code 
such as:
	if (next is a sentinel, or sigtramp, or normal)
This is because all three CFI frames use pure recursion to obtain 
register values from their next frame.

> If I would have all registers saved in each next_frame then I could only call next_frame->unwind->reg(regnum) and get the current value. Then store it somewhere in this_frame and use as if I just read it from the inferior. I believe there is something similar already implemented in the GDB but I don't know how. Could someone explain me this thing, please?

No, you need to make recursive calls.

Per above, if the recursion ever becomes a problem (evidence?) then the 
generic frame code can do better caching.

> Well, long mail, isn't it? But I would like to know if I understand correctly what the new frame unwinding stuff does or if I'm missing something important.
> 
> Thanks for your time,

Andrew


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Frame unwind functions
  2003-03-11 22:04 ` Andrew Cagney
@ 2003-03-12  8:11   ` Michal Ludvig
  2003-03-12 15:15     ` Andrew Cagney
  0 siblings, 1 reply; 4+ messages in thread
From: Michal Ludvig @ 2003-03-12  8:11 UTC (permalink / raw)
  To: Andrew Cagney; +Cc: GDB list

Andrew Cagney wrote:
>> Hi all,
>> since there are different unwind mechanisms in different branches of 
>> GDB I got a bit lost. I need to sort my thoughts to understand the 
>> principles.
>>
>> First my view of how things now work:
> 
> To be honest, this a very good description of how GDB did work: special 
> case on top of special case on top of ....

Thanks for appreciation :-)
But I'm afraid you didn't understand me. AFAIK these special cases are 
still in there, but now they're hidden in appropriate unwind function 
sets. You were talking about the interface (frame_unwind_register, 
frame_unwind_id, ...) while I was talking about the internals of these 
methods for different frame types. That's what I'm interested in if I 
should implement these methods for different x86-64 frames - I'm 
examining what other types of frame unwinders do to know what my ones 
should do.

>> - In the backtrace the function's arguments are printed as well.
>>   - on i386 it's not a problem since they are on the stack
>>   - on x86-64 we pass some of them in registers
>>     - that's fine for the first frame (#0) - I know all registers and I
>>       can use location lists to find current position of a given arg.
>>     - for the second frame (#1) I could call
>>       next_frame->unwind->reg(regnum) to get the register I need and
>>       unwind it even more by calling this_frame->unwind->reg(regnum) to
>>       get it's value at the beginning of the frame.
>>     - but how about the next frames (#2,...)? I can always call
>>       next_frame->unwind->reg(regnum) and if the next_frame wouldn't
>>       know its "initial" value (ie. the value at the place of PC) it
>>       would recursively call next_frame->next_frame->unwind->register()
>>       untill it get's the value.
> 
> 
> The above is the desired and correct behavior.  This recursion is 
> required for things to work (a stack is recursive by definition).

What if a desired register's value isn't available anymore? How do I 
report it to the caller of my_frame->unwind->reg()? By setting an 
optimizedp parameter?

Michal Ludvig
-- 
* SuSE CR, s.r.o     * mludvig@suse.cz
* (+420) 296.545.373 * http://www.suse.cz

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Frame unwind functions
  2003-03-12  8:11   ` Michal Ludvig
@ 2003-03-12 15:15     ` Andrew Cagney
  0 siblings, 0 replies; 4+ messages in thread
From: Andrew Cagney @ 2003-03-12 15:15 UTC (permalink / raw)
  To: Michal Ludvig; +Cc: GDB list

> Andrew Cagney wrote:
> Hi all,
> since there are different unwind mechanisms in different branches of GDB I got a bit lost. I need to sort my thoughts to understand the principles.
> 
> First my view of how things now work:
> 
> To be honest, this a very good description of how GDB did work: special case on top of special case on top of ....
> 
> Thanks for appreciation :-)
> But I'm afraid you didn't understand me. AFAIK these special cases are still in there, but now they're hidden in appropriate unwind function sets. You were talking about the interface (frame_unwind_register, frame_unwind_id, ...) while I was talking about the internals of these methods for different frame types. That's what I'm interested in if I should implement these methods for different x86-64 frames - I'm examining what other types of frame unwinders do to know what my ones should do.

Ah, ok.  An architecutre could potentially have the following unwinders:

- traditional (prologue based)
- sigtramp

The x86-64 GNU/Linux, appears to only have the second.  In addition, 
there is the generic:

- cfi

unwinder.

> - In the backtrace the function's arguments are printed as well.
>   - on i386 it's not a problem since they are on the stack
>   - on x86-64 we pass some of them in registers
>     - that's fine for the first frame (#0) - I know all registers and I
>       can use location lists to find current position of a given arg.
>     - for the second frame (#1) I could call
>       next_frame->unwind->reg(regnum) to get the register I need and
>       unwind it even more by calling this_frame->unwind->reg(regnum) to
>       get it's value at the beginning of the frame.
>     - but how about the next frames (#2,...)? I can always call
>       next_frame->unwind->reg(regnum) and if the next_frame wouldn't
>       know its "initial" value (ie. the value at the place of PC) it
>       would recursively call next_frame->next_frame->unwind->register()
>       untill it get's the value.
> 
> 
> The above is the desired and correct behavior.  This recursion is required for things to work (a stack is recursive by definition).
> 
> What if a desired register's value isn't available anymore? How do I report it to the caller of my_frame->unwind->reg()? By setting an optimizedp parameter?

Yes, at present setting optimized to non-zero is the best there is.  I 
noticed that the cfi unwinder is already doing this.

Andrew


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2003-03-12 15:15 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-03-11 18:35 Frame unwind functions Michal Ludvig
2003-03-11 22:04 ` Andrew Cagney
2003-03-12  8:11   ` Michal Ludvig
2003-03-12 15:15     ` Andrew Cagney

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).