public inbox for gdb@sourceware.org
 help / color / mirror / Atom feed
* dwarf-frame.c question
@ 2003-05-27 15:19 Michal Ludvig
  2003-05-29 15:44 ` Mark Kettenis
  0 siblings, 1 reply; 20+ messages in thread
From: Michal Ludvig @ 2003-05-27 15:19 UTC (permalink / raw)
  To: Mark Kettenis; +Cc: gdb

Hi Mark,
why do you decrement unwound PC in dwarf_frame_cache() before using it?

dwarf-frame.c:
478       /* Unwind the PC.  */
479       fs->pc = frame_pc_unwind (next_frame);
480       if (get_frame_type (next_frame) == NORMAL_FRAME
481           && frame_relative_level (next_frame) >= 0)
482         fs->pc--;

This makes a problem for a signal trampoline.
If it is sitting on addresses say 0x40000140-0x40000150, the return 
address from signal handler is 0x40000140, but dwarf_frame_cache() says 
it is 0x4000013f and couldn't find it's CFI...

This has a tragic consequence few lines below were you look for FDE but 
don't check if you find one. If you don't, line 488 segfaults.
484       /* Find the correct FDE.  */
485       fde = dwarf_frame_find_fde (&fs->pc);
486
487       /* Extract any interesting information from the CIE.  */
488       fs->data_align = fde->cie->data_alignment_factor;
489       fs->code_align = fde->cie->code_alignment_factor;
490       fs->retaddr_column = fde->cie->return_address_register;

The problem is, that dwarf_frame_p() looks for the real return address 
and says that there is a debug info and sets unwinder to use dwarf2 
methods for this farme.
But the in unwinder itself in dwarf_frame_cache() looks for the 
decreased one and of course doesn't find it.

I couldn't see any problems when I removed the decrementation, so why is 
it there?

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

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

* Re: dwarf-frame.c question
  2003-05-27 15:19 dwarf-frame.c question Michal Ludvig
@ 2003-05-29 15:44 ` Mark Kettenis
  2003-05-29 19:54   ` Andrew Cagney
  0 siblings, 1 reply; 20+ messages in thread
From: Mark Kettenis @ 2003-05-29 15:44 UTC (permalink / raw)
  To: mludvig, ac131313; +Cc: gdb

   Date: Tue, 27 May 2003 17:18:35 +0200
   From: Michal Ludvig <mludvig@suse.cz>

   Hi Mark,

   why do you decrement unwound PC in dwarf_frame_cache() before using it?

The unwound PC is the return address, i.e. the instruction that will
be executed when the function returns.  This is the instruction after
the call instruction.  The problem is that if the call instruction is
the last instruction of a function, the return address might point to
the next function:

foo:
   ...
   call abort

bar:
   push %ebp
   mov %esp, %ebp
   ...

That's why the GCC unwinder does the same thing.  Note that the
decrementing the PC is wrong for "interrupt frames", which is why the
if-statement is there in the code fragment you cite:

   dwarf-frame.c:
   478       /* Unwind the PC.  */
   479       fs->pc = frame_pc_unwind (next_frame);
   480       if (get_frame_type (next_frame) == NORMAL_FRAME
   481           && frame_relative_level (next_frame) >= 0)
   482         fs->pc--;

   This makes a problem for a signal trampoline.
   If it is sitting on addresses say 0x40000140-0x40000150, the return 
   address from signal handler is 0x40000140, but dwarf_frame_cache() says 
   it is 0x4000013f and couldn't find it's CFI...

Do you have signal trampolnes with CFI?  If the CFI is hand-generated,
you should probably "cheat" by adding a nop before the trampoline and
include it in the address range of the FDE (see the
arch/i386/kernel/vsyscall-sigreturn.S in the Linux kernel sources).

   This has a tragic consequence few lines below were you look for FDE but 
   don't check if you find one. If you don't, line 488 segfaults.
   484       /* Find the correct FDE.  */
   485       fde = dwarf_frame_find_fde (&fs->pc);

Hmm, a gdb_assert() is in order here.

   487       /* Extract any interesting information from the CIE.  */
   488       fs->data_align = fde->cie->data_alignment_factor;
   489       fs->code_align = fde->cie->code_alignment_factor;
   490       fs->retaddr_column = fde->cie->return_address_register;

   The problem is, that dwarf_frame_p() looks for the real return address 
   and says that there is a debug info and sets unwinder to use dwarf2 
   methods for this farme.

Hmm, it should do something similar as dwarf_frame_cache().

   But the in unwinder itself in dwarf_frame_cache() looks for the 
   decreased one and of course doesn't find it.

That defenitely is a bug.  It isn't immediately obvious to me how to
solve this :-(.  Andrew, it seems that we should tweak the frame code
to make sure that frame_unwind_by_pc is always passed a PC *within* the
function.

Mark

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

* Re: dwarf-frame.c question
  2003-05-29 15:44 ` Mark Kettenis
@ 2003-05-29 19:54   ` Andrew Cagney
  2003-05-29 22:22     ` Mark Kettenis
  0 siblings, 1 reply; 20+ messages in thread
From: Andrew Cagney @ 2003-05-29 19:54 UTC (permalink / raw)
  To: Mark Kettenis; +Cc: mludvig, gdb

>    Date: Tue, 27 May 2003 17:18:35 +0200
>    From: Michal Ludvig <mludvig@suse.cz>
> 
>    Hi Mark,
> 
>    why do you decrement unwound PC in dwarf_frame_cache() before using it?
> 
> The unwound PC is the return address, i.e. the instruction that will
> be executed when the function returns.

Yes, the resume address, or the next instruction that will be executed 
when the frame resumes.

frame_address_in_block() also tries to handle this.

>  This is the instruction after
> the call instruction.  The problem is that if the call instruction is
> the last instruction of a function, the return address might point to
> the next function:

> foo:
>    ...
>    call abort
> 
> bar:
>    push %ebp
>    mov %esp, %ebp
>    ...
> 
> That's why the GCC unwinder does the same thing.  Note that the
> decrementing the PC is wrong for "interrupt frames", which is why the
> if-statement is there in the code fragment you cite:
> 
>    dwarf-frame.c:
>    478       /* Unwind the PC.  */
>    479       fs->pc = frame_pc_unwind (next_frame);
>    480       if (get_frame_type (next_frame) == NORMAL_FRAME
>    481           && frame_relative_level (next_frame) >= 0)
>    482         fs->pc--;
> 
>    This makes a problem for a signal trampoline.
>    If it is sitting on addresses say 0x40000140-0x40000150, the return 
>    address from signal handler is 0x40000140, but dwarf_frame_cache() says 
>    it is 0x4000013f and couldn't find it's CFI...
> 
> Do you have signal trampolnes with CFI?  If the CFI is hand-generated,
> you should probably "cheat" by adding a nop before the trampoline and
> include it in the address range of the FDE (see the
> arch/i386/kernel/vsyscall-sigreturn.S in the Linux kernel sources).
> 
>    This has a tragic consequence few lines below were you look for FDE but 
>    don't check if you find one. If you don't, line 488 segfaults.
>    484       /* Find the correct FDE.  */
>    485       fde = dwarf_frame_find_fde (&fs->pc);
> 
> Hmm, a gdb_assert() is in order here.
> 
>    487       /* Extract any interesting information from the CIE.  */
>    488       fs->data_align = fde->cie->data_alignment_factor;
>    489       fs->code_align = fde->cie->code_alignment_factor;
>    490       fs->retaddr_column = fde->cie->return_address_register;
> 
>    The problem is, that dwarf_frame_p() looks for the real return address 
>    and says that there is a debug info and sets unwinder to use dwarf2 
>    methods for this farme.
> 
> Hmm, it should do something similar as dwarf_frame_cache().
> 
>    But the in unwinder itself in dwarf_frame_cache() looks for the 
>    decreased one and of course doesn't find it.
> 
> That defenitely is a bug.  It isn't immediately obvious to me how to
> solve this :-(.

First an FYI.  CFI has that return-address column.  I'm left wondering 
if frame_pc_unwind() should try the frame for the unwound pc before 
trying for registers.  However, there has so far been zero evidence 
supporting this need so I think, until there is, let it be.  It also 
wouldn't help with this case - it to would still point back to beyond 
the function :-(

Second, another FYI.  This isn't just a CFI problem.  There have been 
earlier posts about how GDB, already gets confused by this - printing 
out the wrong function address for instance.  This problem is generic.

Anyway, is it safe to always decrement the resume address before looking 
for the CFI info?  Given a more complex sequence like:

	1: setup call
	2: call xxx with lots of side effects
	3: delay slot saved r0++
	4: discard call

then the CFI info for 4 could be very different to that for 2/3.

 >  Andrew, it seems that we should tweak the frame code
 > to make sure that frame_unwind_by_pc is always passed a PC *within* the
 > function.

True, but how?  It would effectively be frame_unwind_address_in_block() 
but how reliably/where could it be used?

Andrew


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

* Re: dwarf-frame.c question
  2003-05-29 19:54   ` Andrew Cagney
@ 2003-05-29 22:22     ` Mark Kettenis
  2003-05-29 22:43       ` Michal Ludvig
  2003-05-29 23:13       ` Andrew Cagney
  0 siblings, 2 replies; 20+ messages in thread
From: Mark Kettenis @ 2003-05-29 22:22 UTC (permalink / raw)
  To: ac131313; +Cc: mludvig, gdb

   Date: Thu, 29 May 2003 15:54:12 -0400
   From: Andrew Cagney <ac131313@redhat.com>

   >    Date: Tue, 27 May 2003 17:18:35 +0200
   >    From: Michal Ludvig <mludvig@suse.cz>
   > 
   >    Hi Mark,
   > 
   >    why do you decrement unwound PC in dwarf_frame_cache() before using it?
   > 
   > The unwound PC is the return address, i.e. the instruction that will
   > be executed when the function returns.

   Yes, the resume address, or the next instruction that will be executed 
   when the frame resumes.

   frame_address_in_block() also tries to handle this.

Indeed.  When I noted the problems with frame_address_in_block()
before, we more or less agreed that we needed to add properties to our
frames instead of making decision based on a frames type.  One such a
property could whether to decrease the rerturn address or not.

   >  This is the instruction after
   > the call instruction.  The problem is that if the call instruction is
   > the last instruction of a function, the return address might point to
   > the next function:

   > foo:
   >    ...
   >    call abort
   > 
   > bar:
   >    push %ebp
   >    mov %esp, %ebp
   >    ...
   > 
   > That's why the GCC unwinder does the same thing.  Note that the
   > decrementing the PC is wrong for "interrupt frames", which is why the
   > if-statement is there in the code fragment you cite:
   > 
   >    dwarf-frame.c:
   >    478       /* Unwind the PC.  */
   >    479       fs->pc = frame_pc_unwind (next_frame);
   >    480       if (get_frame_type (next_frame) == NORMAL_FRAME
   >    481           && frame_relative_level (next_frame) >= 0)
   >    482         fs->pc--;

   First an FYI.  CFI has that return-address column.  I'm left wondering 
   if frame_pc_unwind() should try the frame for the unwound pc before 
   trying for registers.  However, there has so far been zero evidence 
   supporting this need so I think, until there is, let it be.  It also 
   wouldn't help with this case - it to would still point back to beyond 
   the function :-(

I'm not sure what you mean here, but dwarf-frame.c treats the
return-address column as the saved/unwound pc.

   Second, another FYI.  This isn't just a CFI problem.  There have been 
   earlier posts about how GDB, already gets confused by this - printing 
   out the wrong function address for instance.  This problem is generic.

Yes indeed it is.

   Anyway, is it safe to always decrement the resume address before looking 
   for the CFI info?  Given a more complex sequence like:

	   1: setup call
	   2: call xxx with lots of side effects
	   3: delay slot saved r0++
	   4: discard call

   then the CFI info for 4 could be very different to that for 2/3.

Well, the GCC unwinder seems to think it is safe to do this.  Note
that we only use the decremented resume address to find the FDE, and
that we use the real return address for calculating the CFI.  This
means that as long as the compiler doesn't store the CFI for 3 and 4
in different FDE's, we'll always have the correct CFI.

    >  Andrew, it seems that we should tweak the frame code
    > to make sure that frame_unwind_by_pc is always passed a PC *within* the
    > function.

   True, but how?  It would effectively be frame_unwind_address_in_block() 
   but how reliably/where could it be used?

Oops, I meant frame_unwind_find_by_pc instead of frame_unwind_by_pc.
Anyway, every invocation of get_frame_pc() is a potential candidate.

It seems to me that this deserves a bit more thought.  Should I
postpone moving the CFI unwinder over to mainline until this is
resolved?  Alternatively I can comment out the bit of code that
decrements the return-address.  That would be "acceptable" since the
bug it tries to solve is present in the current code too.

Mark

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

* Re: dwarf-frame.c question
  2003-05-29 22:22     ` Mark Kettenis
@ 2003-05-29 22:43       ` Michal Ludvig
  2003-05-29 23:13       ` Andrew Cagney
  1 sibling, 0 replies; 20+ messages in thread
From: Michal Ludvig @ 2003-05-29 22:43 UTC (permalink / raw)
  To: Mark Kettenis; +Cc: ac131313, gdb

Mark Kettenis wrote:
> It seems to me that this deserves a bit more thought.  Should I
> postpone moving the CFI unwinder over to mainline until this is
> resolved?  Alternatively I can comment out the bit of code that
> decrements the return-address.  That would be "acceptable" since the
> bug it tries to solve is present in the current code too.

I don't think it's a critical bug - it only appears on my hand written 
signal trampoline with a hand written CFI (what is a bit unusual 
situation :-). IMHO no std. glibc user should ever hit it.

So I propose don't wait with merging your branch - I started to use it 
on my AMD64 machines and so far I can say it's very good :-)

Michal Ludvig

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

* Re: dwarf-frame.c question
  2003-05-29 22:22     ` Mark Kettenis
  2003-05-29 22:43       ` Michal Ludvig
@ 2003-05-29 23:13       ` Andrew Cagney
  2003-05-30  1:34         ` Daniel Jacobowitz
                           ` (2 more replies)
  1 sibling, 3 replies; 20+ messages in thread
From: Andrew Cagney @ 2003-05-29 23:13 UTC (permalink / raw)
  To: Mark Kettenis; +Cc: mludvig, gdb, Alexandre Oliva

Discussed this with AlexO (of gcc).  Let us ruin your day.

This problem can occure even without recursion.  Consider the C snippet:

foo ()
{
	if (i)
	  abort (with, lots, of parameters)
	do; normal; stuff;
}

it can be turned into:

	branch !i, 1:
	push with
	push lots
	push of
	push parameters
	call abort
1:
	do
	normal
	stuff

The return address can end up pointing at the ``do'' / 1: line and 
that's CFI info is definitly not correct for unwinding from abort().

One idea (the origins of which are unknown) is for the compiler to 
generate CFI info containing no addresses and have GDB look for that 
dependant on the PC address being obtained using return or resume 
(sigtramp, sentinel).

However, first, does anyone know if the DWARF 2 spec has something to 
say abou this?

Andrew

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

* Re: dwarf-frame.c question
  2003-05-29 23:13       ` Andrew Cagney
@ 2003-05-30  1:34         ` Daniel Jacobowitz
  2003-05-30 20:21         ` Jim Blandy
  2003-05-30 20:21         ` Jim Blandy
  2 siblings, 0 replies; 20+ messages in thread
From: Daniel Jacobowitz @ 2003-05-30  1:34 UTC (permalink / raw)
  To: Andrew Cagney; +Cc: Mark Kettenis, mludvig, gdb, Alexandre Oliva

On Thu, May 29, 2003 at 07:12:53PM -0400, Andrew Cagney wrote:
> Discussed this with AlexO (of gcc).  Let us ruin your day.
> 
> This problem can occure even without recursion.  Consider the C snippet:
> 
> foo ()
> {
> 	if (i)
> 	  abort (with, lots, of parameters)
> 	do; normal; stuff;
> }
> 
> it can be turned into:
> 
> 	branch !i, 1:
> 	push with
> 	push lots
> 	push of
> 	push parameters
> 	call abort
> 1:
> 	do
> 	normal
> 	stuff
> 
> The return address can end up pointing at the ``do'' / 1: line and 
> that's CFI info is definitly not correct for unwinding from abort().

This suggests to me two things:
 - that the problem is writing CFI for a trampoline which begins at the
return address.  Normally that can't happen except for "magic" like
signals.  So there will be an FDE which includes or ends at the return
PC.
 - that there should be a DWARF-3 extension to clarify this; is anyone
interested in discussing it with the committee?

> One idea (the origins of which are unknown) is for the compiler to 
> generate CFI info containing no addresses and have GDB look for that 
> dependant on the PC address being obtained using return or resume 
> (sigtramp, sentinel).
> 
> However, first, does anyone know if the DWARF 2 spec has something to 
> say abou this?

I can't see anything relevant.

-- 
Daniel Jacobowitz
MontaVista Software                         Debian GNU/Linux Developer

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

* Re: dwarf-frame.c question
  2003-05-29 23:13       ` Andrew Cagney
  2003-05-30  1:34         ` Daniel Jacobowitz
  2003-05-30 20:21         ` Jim Blandy
@ 2003-05-30 20:21         ` Jim Blandy
  2003-05-30 20:32           ` Andrew Cagney
  2003-05-30 20:44           ` Alexandre Oliva
  2 siblings, 2 replies; 20+ messages in thread
From: Jim Blandy @ 2003-05-30 20:21 UTC (permalink / raw)
  To: Andrew Cagney; +Cc: Mark Kettenis, mludvig, gdb, Alexandre Oliva


Andrew Cagney <ac131313@redhat.com> writes:
> One idea (the origins of which are unknown) is for the compiler to
> generate CFI info containing no addresses and have GDB look for that
> dependant on the PC address being obtained using return or resume
> (sigtramp, sentinel).

I don't understand this.  Could you explain the idea in more detail?

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

* Re: dwarf-frame.c question
  2003-05-29 23:13       ` Andrew Cagney
  2003-05-30  1:34         ` Daniel Jacobowitz
@ 2003-05-30 20:21         ` Jim Blandy
  2003-05-30 20:21         ` Jim Blandy
  2 siblings, 0 replies; 20+ messages in thread
From: Jim Blandy @ 2003-05-30 20:21 UTC (permalink / raw)
  To: Andrew Cagney; +Cc: Mark Kettenis, mludvig, gdb, Alexandre Oliva


Andrew Cagney <ac131313@redhat.com> writes:
> Discussed this with AlexO (of gcc).  Let us ruin your day.
> 
> This problem can occure even without recursion.  Consider the C snippet:
> 
> foo ()
> {
> 	if (i)
> 	  abort (with, lots, of parameters)
> 	do; normal; stuff;
> }
> 
> it can be turned into:
> 
> 	branch !i, 1:
> 	push with
> 	push lots
> 	push of
> 	push parameters
> 	call abort
> 1:
> 	do
> 	normal
> 	stuff
> 
> The return address can end up pointing at the ``do'' / 1: line and
> that's CFI info is definitly not correct for unwinding from abort().

It's worth pointing out that this problem is not possible to solve in
general.  If the compiler knows that a given call will never return,
it would be completely correct for it to trash the stack, overwrite
its saved return address, etc. before making the call.  Since the
older frames will never be used, they're dead, and code that makes
them unfindable is just as correct as code which trashes the value of
a dead variable.

The only reason it's possible to generate CFI at all in the normal
case is that the function itself needs to return, so the information
must be there somewhere.  Where that precondition doesn't hold,
unwinding is only possible when the compiler is lazy.  :)

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

* Re: dwarf-frame.c question
  2003-05-30 20:21         ` Jim Blandy
@ 2003-05-30 20:32           ` Andrew Cagney
  2003-06-03  0:04             ` Jim Blandy
  2003-05-30 20:44           ` Alexandre Oliva
  1 sibling, 1 reply; 20+ messages in thread
From: Andrew Cagney @ 2003-05-30 20:32 UTC (permalink / raw)
  To: Jim Blandy; +Cc: Mark Kettenis, mludvig, gdb, Alexandre Oliva

> Andrew Cagney <ac131313@redhat.com> writes:
> 
>> One idea (the origins of which are unknown) is for the compiler to
>> generate CFI info containing no addresses and have GDB look for that
>> dependant on the PC address being obtained using return or resume
>> (sigtramp, sentinel).
> 
> 
> I don't understand this.  Could you explain the idea in more detail?

A similar technique to the line number information where there are two 
line number entries for the start of function so that GDB can find the 
end of the function prologue given:

	int foo (int i) { int j = i * i; return j; }

In this case there would be two CFI entries covering the code at "1:" 
(assuming its possible):

> foo ()
> {
>     if (i)
>       abort (with, lots, of parameters)
>     do; normal; stuff;
> }
> 
> it can be turned into:
> 
>     branch !i, 1:
>     push with
>     push lots
>     push of
>     push parameters
>     call abort
> 1:
>     do
>     normal
>     stuff 

- [1:, 1:): describing the lost return instruction
- [1:, end-of-function) describing the real code

GDB could pick 'n' choose.

The other thing to do is to test this on an alternative compiler that 
generates CFI.

Andrew


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

* Re: dwarf-frame.c question
  2003-05-30 20:21         ` Jim Blandy
  2003-05-30 20:32           ` Andrew Cagney
@ 2003-05-30 20:44           ` Alexandre Oliva
  1 sibling, 0 replies; 20+ messages in thread
From: Alexandre Oliva @ 2003-05-30 20:44 UTC (permalink / raw)
  To: Jim Blandy; +Cc: Andrew Cagney, Mark Kettenis, mludvig, gdb

On May 30, 2003, Jim Blandy <jimb@redhat.com> wrote:

> Andrew Cagney <ac131313@redhat.com> writes:
>> One idea (the origins of which are unknown) is for the compiler to
>> generate CFI info containing no addresses and have GDB look for that
>> dependant on the PC address being obtained using return or resume
>> (sigtramp, sentinel).

> I don't understand this.  Could you explain the idea in more detail?

The idea Andrew and I came up with was initially to get GCC to emit a
useless nop (especially when compiling without optimization) that
would hold the post-call CFI information.  Afterwards, one of us
thought that, even if the nop was removed, we could still emit CFI
information for the now-empty region, and have GDB (or, even better,
the DWARF3 spec) recognize this as a special case for non-returning
calls.

I agree with you that, in general, the CFI information might just
indicate that the stack was trashed beyond recognition, but often
the info will still be there, and there's no reason to not present the
information in a usable format in such cases.

-- 
Alexandre Oliva   Enjoy Guarana', see http://www.ic.unicamp.br/~oliva/
Red Hat GCC Developer                 aoliva@{redhat.com, gcc.gnu.org}
CS PhD student at IC-Unicamp        oliva@{lsd.ic.unicamp.br, gnu.org}
Free Software Evangelist                Professional serial bug killer

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

* Re: dwarf-frame.c question
  2003-05-30 20:32           ` Andrew Cagney
@ 2003-06-03  0:04             ` Jim Blandy
  2003-06-03  5:47               ` Richard Henderson
  0 siblings, 1 reply; 20+ messages in thread
From: Jim Blandy @ 2003-06-03  0:04 UTC (permalink / raw)
  To: Andrew Cagney; +Cc: Mark Kettenis, mludvig, gdb, Alexandre Oliva


Andrew Cagney <ac131313@redhat.com> writes:
> > Andrew Cagney <ac131313@redhat.com> writes:
> >
> >> One idea (the origins of which are unknown) is for the compiler to
> >> generate CFI info containing no addresses and have GDB look for that
> >> dependant on the PC address being obtained using return or resume
> >> (sigtramp, sentinel).
> > I don't understand this.  Could you explain the idea in more detail?
> 
> A similar technique to the line number information where there are two
> line number entries for the start of function so that GDB can find the
> end of the function prologue given:
> 
> 	int foo (int i) { int j = i * i; return j; }
> 
> In this case there would be two CFI entries covering the code at "1:"
> (assuming its possible):
> 
> > foo ()
> > {
> >     if (i)
> >       abort (with, lots, of parameters)
> >     do; normal; stuff;
> > }
> > it can be turned into:
> >     branch !i, 1:
> >     push with
> >     push lots
> >     push of
> >     push parameters
> >     call abort
> > 1:
> >     do
> >     normal
> >     stuff
> 
> - [1:, 1:): describing the lost return instruction
> - [1:, end-of-function) describing the real code
> 
> GDB could pick 'n' choose.

Okay --- thanks for that explanation.

We've already added some DW_CFA_GNU_ opcodes to the CFI spec; we could
solve the problem more unambiguously by introducing something like
DW_CFA_GNU_unwind_from_noreturn:

    <rationale italics>

    In some cases, the compiler may determine that a particular
    subroutine will never return.  It may not be possible in general
    to unwind activation frames for calls to such functions: the
    compiler is free to generate code which throws away information
    the debugger would need to do so, since the compiler knows that
    information will never be used by the program itself.  But in
    practice there will often be sufficient information to unwind the
    frame; since developers will often want to look at the
    preceding stack frames, compilers are encouraged to emit call
    frame information for such subroutines anyway.

    However, unwinding the frame of a call to a subroutine which will
    never return yields a processor state which will never actually
    occur in the running program.  Since the compiler is free to place
    arbitrary code (or no code at all) immediately after a call
    instruction which it knows will never return, the unwound return
    address may point to an instruction whose unwinding rules are
    different from those needed after the call has "returned".  In
    this case, the debugger needs two distinct sets of unwinding rules
    for the same code address: one to apply when unwinding again after
    unwinding the call which will never return, and one to apply when
    the code location was reached via other means.

    The debugger can distinguish these two cases by considering the
    next younger frame: if it is a frame for an ordinary function,
    then the first set of rules applies; but if it is a frame for a
    signal handler, or a frame synthesized by the debugger itself (in
    order to call a function in the program, for example), or if there
    is no younger frame, then the second set of rules applies.

    </rationale italics>

    The DW_CFA_GNU_unwind_from_noreturn instruction indicates that the
    current set of rules applies only when the current location was
    reached by unwinding a frame called by this one, not when it was
    reached from elsewhere in the subroutine.

    The DW_CFA_GNU_unwind_from_noreturn instruction also creates a new
    table row whose location value is the same as this one; this
    latter row applies when the given location was reached from
    elsewhere in the same subroutine.

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

* Re: dwarf-frame.c question
  2003-06-03  0:04             ` Jim Blandy
@ 2003-06-03  5:47               ` Richard Henderson
  2003-06-03  6:32                 ` Jim Blandy
  0 siblings, 1 reply; 20+ messages in thread
From: Richard Henderson @ 2003-06-03  5:47 UTC (permalink / raw)
  To: Jim Blandy; +Cc: Andrew Cagney, Mark Kettenis, mludvig, gdb, Alexandre Oliva

On Mon, Jun 02, 2003 at 07:03:56PM -0500, Jim Blandy wrote:
>     The DW_CFA_GNU_unwind_from_noreturn instruction indicates that the
>     current set of rules applies only when the current location was
>     reached by unwinding a frame called by this one, not when it was
>     reached from elsewhere in the subroutine.
> 
>     The DW_CFA_GNU_unwind_from_noreturn instruction also creates a new
>     table row whose location value is the same as this one; this
>     latter row applies when the given location was reached from
>     elsewhere in the same subroutine.

So the effect would be that in the "normal" case we'd continue
evaluating CFA opcodes as usual until we get to an advance that
moves past the PC.

The debugger, on the other hand, would have to know that we are
unwinding from deeper in the call stack, and set a special flag
that would stop at the new note?


r~

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

* Re: dwarf-frame.c question
  2003-06-03  5:47               ` Richard Henderson
@ 2003-06-03  6:32                 ` Jim Blandy
  2003-06-03 15:58                   ` Richard Henderson
  2003-06-03 20:12                   ` Alexandre Oliva
  0 siblings, 2 replies; 20+ messages in thread
From: Jim Blandy @ 2003-06-03  6:32 UTC (permalink / raw)
  To: Richard Henderson
  Cc: Andrew Cagney, Mark Kettenis, mludvig, gdb, Alexandre Oliva

Richard Henderson <rth@redhat.com> writes:

> On Mon, Jun 02, 2003 at 07:03:56PM -0500, Jim Blandy wrote:
> >     The DW_CFA_GNU_unwind_from_noreturn instruction indicates that the
> >     current set of rules applies only when the current location was
> >     reached by unwinding a frame called by this one, not when it was
> >     reached from elsewhere in the subroutine.
> > 
> >     The DW_CFA_GNU_unwind_from_noreturn instruction also creates a new
> >     table row whose location value is the same as this one; this
> >     latter row applies when the given location was reached from
> >     elsewhere in the same subroutine.
> 
> So the effect would be that in the "normal" case we'd continue
> evaluating CFA opcodes as usual until we get to an advance that
> moves past the PC.
> 
> The debugger, on the other hand, would have to know that we are
> unwinding from deeper in the call stack, and set a special flag
> that would stop at the new note?

Yeah, that's the idea.

But I did think of a simpler way to fix this, which wouldn't require
any new Dwarf at all:

Since we're unwinding a frame which will never really be unwound, we
can have that do anything we want.  So, if a function never returns,
why not have the compiler emit CFI that restores the state just
*before* the call insn was executed, not after it returns?  The
unwound PC would point at the call insn itself.  (That's what the user
expects to see anyway.)  The other registers would be as appropriate
before the call was made.  You unwind from there as usual.

I feel like I'm missing something.  Does the compiler have enough info
to do this?  ("No, the compiler doesn't really have enough info to
emit CFI at all, but we do our best, and that's usually okay"?)

It would be weird if you used "return" to artificially pop the frame
and continue.  But that's a bogus thing to do anyway --- the return
address is garbage, so who knows where you're resuming?  If the
function ends with a "call" to 'abort', followed by no more code, then
"return" might just start running at the entry point of the next
function, for goodness' sake.  None of the proposals here will make
that do something sensible, so is this behavior really any more wrong?

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

* Re: dwarf-frame.c question
  2003-06-03  6:32                 ` Jim Blandy
@ 2003-06-03 15:58                   ` Richard Henderson
  2003-06-03 17:38                     ` Richard Henderson
  2003-06-03 20:12                   ` Alexandre Oliva
  1 sibling, 1 reply; 20+ messages in thread
From: Richard Henderson @ 2003-06-03 15:58 UTC (permalink / raw)
  To: Jim Blandy; +Cc: Andrew Cagney, Mark Kettenis, mludvig, gdb, Alexandre Oliva

On Tue, Jun 03, 2003 at 01:30:56AM -0500, Jim Blandy wrote:
> Since we're unwinding a frame which will never really be unwound, we
> can have that do anything we want.  So, if a function never returns,
> why not have the compiler emit CFI that restores the state just
> *before* the call insn was executed, not after it returns?  The
> unwound PC would point at the call insn itself.

Hmm.  You mean that the unwind info for "abort" itself
would change to say that the return address was something
other than it really is?

Certainly this is possible.  If the function has the
noreturn attribute GCC could frob the return address
with DW_CFA_expression.

Does this have any other adverse side effects though?

How about the fact that abort is often written in assembly
language in libc, and so may not have any specific unwind
information at all?


r~

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

* Re: dwarf-frame.c question
  2003-06-03 15:58                   ` Richard Henderson
@ 2003-06-03 17:38                     ` Richard Henderson
  0 siblings, 0 replies; 20+ messages in thread
From: Richard Henderson @ 2003-06-03 17:38 UTC (permalink / raw)
  To: Jim Blandy; +Cc: Andrew Cagney, Mark Kettenis, mludvig, gdb, Alexandre Oliva

On Tue, Jun 03, 2003 at 08:56:46AM -0700, Richard Henderson wrote:
> Does this have any other adverse side effects though?

Actually, I can think of one -- this would break the existing
jiggery-pokery that happens during exception handling.

The __cxa_throw routine is known to be noreturn.  If we changed
the return address at which it unwound, this would render all
existing EH information invalid, since the throw may not be 
"inside" the region that is expecting calls that can throw.

Sorry.


r~

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

* Re: dwarf-frame.c question
  2003-06-03  6:32                 ` Jim Blandy
  2003-06-03 15:58                   ` Richard Henderson
@ 2003-06-03 20:12                   ` Alexandre Oliva
  1 sibling, 0 replies; 20+ messages in thread
From: Alexandre Oliva @ 2003-06-03 20:12 UTC (permalink / raw)
  To: Jim Blandy; +Cc: Richard Henderson, Andrew Cagney, Mark Kettenis, mludvig, gdb

On Jun  3, 2003, Jim Blandy <jimb@redhat.com> wrote:

> So, if a function never returns, why not have the compiler emit CFI
> that restores the state just *before* the call insn was executed,
> not after it returns?

In some ABIs, the callee releases (part of) the stack space allocated
by the caller, so the state is actually different.  I.e., the state
before the call is significantly different from the state after the
return, which is also different from the state during the call.  I'm
not sure whether it would actually matter for GDB, but that's why I
thought we'd be better off taking the CFI from after the call (even if
it's not meaningful given that the call doesn't return), instead of
from before it.

-- 
Alexandre Oliva   Enjoy Guarana', see http://www.ic.unicamp.br/~oliva/
Red Hat GCC Developer                 aoliva@{redhat.com, gcc.gnu.org}
CS PhD student at IC-Unicamp        oliva@{lsd.ic.unicamp.br, gnu.org}
Free Software Evangelist                Professional serial bug killer

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

* Re: dwarf-frame.c question
  2003-06-01 10:00 ` Mark Kettenis
@ 2003-06-02 20:34   ` Richard Henderson
  0 siblings, 0 replies; 20+ messages in thread
From: Richard Henderson @ 2003-06-02 20:34 UTC (permalink / raw)
  To: Mark Kettenis; +Cc: gdb

On Sun, Jun 01, 2003 at 12:00:36PM +0200, Mark Kettenis wrote:
> Do you think we should require (or politely ask ;-)) the compiler to
> put something after a noreturn call on other targets as well?

I think we can arrange something.


r~

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

* Re: dwarf-frame.c question
  2003-06-01  5:59 Richard Henderson
@ 2003-06-01 10:00 ` Mark Kettenis
  2003-06-02 20:34   ` Richard Henderson
  0 siblings, 1 reply; 20+ messages in thread
From: Mark Kettenis @ 2003-06-01 10:00 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gdb

Richard Henderson <rth@redhat.com> writes:

> [ Pasted from web archives, sorry.  ]
> 
> Mark Kettenis:
> >  Andrew, it seems that we should tweak the frame code
> > to make sure that frame_unwind_by_pc is always passed a PC *within* the
> > function.
> 
> Andrew Cagney:
> > True, but how? It would effectively be frame_unwind_address_in_block() but
> > how reliably/where could it be used?
> 
> Careful; this silliness of subtracting one is not universal.
> 
> ABI's with more thought in them (e.g. IA64) require the compiler
> to put *something* after a noreturn call that ends a function.
> This being a relatively uncommon case, it does not add much code
> size, and it solves some of the ambiguity problems you're seeing.

Note that it is not only noreturn calls that end a function that pose
a problem.  As Andrew and Alexandre pointed out, branch instructions
pose a problem too.

Do you think we should require (or politely ask ;-)) the compiler to
put something after a noreturn call on other targets as well?

Mark

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

* Re: dwarf-frame.c question
@ 2003-06-01  5:59 Richard Henderson
  2003-06-01 10:00 ` Mark Kettenis
  0 siblings, 1 reply; 20+ messages in thread
From: Richard Henderson @ 2003-06-01  5:59 UTC (permalink / raw)
  To: gdb

[ Pasted from web archives, sorry.  ]

Mark Kettenis:
>  Andrew, it seems that we should tweak the frame code
> to make sure that frame_unwind_by_pc is always passed a PC *within* the
> function.

Andrew Cagney:
> True, but how? It would effectively be frame_unwind_address_in_block() but
> how reliably/where could it be used?

Careful; this silliness of subtracting one is not universal.

ABI's with more thought in them (e.g. IA64) require the compiler
to put *something* after a noreturn call that ends a function.
This being a relatively uncommon case, it does not add much code
size, and it solves some of the ambiguity problems you're seeing.


r~

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

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

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-05-27 15:19 dwarf-frame.c question Michal Ludvig
2003-05-29 15:44 ` Mark Kettenis
2003-05-29 19:54   ` Andrew Cagney
2003-05-29 22:22     ` Mark Kettenis
2003-05-29 22:43       ` Michal Ludvig
2003-05-29 23:13       ` Andrew Cagney
2003-05-30  1:34         ` Daniel Jacobowitz
2003-05-30 20:21         ` Jim Blandy
2003-05-30 20:21         ` Jim Blandy
2003-05-30 20:32           ` Andrew Cagney
2003-06-03  0:04             ` Jim Blandy
2003-06-03  5:47               ` Richard Henderson
2003-06-03  6:32                 ` Jim Blandy
2003-06-03 15:58                   ` Richard Henderson
2003-06-03 17:38                     ` Richard Henderson
2003-06-03 20:12                   ` Alexandre Oliva
2003-05-30 20:44           ` Alexandre Oliva
2003-06-01  5:59 Richard Henderson
2003-06-01 10:00 ` Mark Kettenis
2003-06-02 20:34   ` Richard Henderson

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).