* Re: [Linux-ia64] Unwind problem for __attribute__ noreturn
2001-03-20 2:10 [Linux-ia64] Unwind problem for __attribute__ noreturn Keith Owens
@ 2001-03-21 0:24 ` Jim Wilson
2001-03-21 6:03 ` Keith Owens
` (23 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Jim Wilson @ 2001-03-21 0:24 UTC (permalink / raw)
To: linux-ia64
I'm not able to understand any of this.
I'm not a kernel expert. It has been months since I've booted a kernel that
I built, and much longer since I've booted a kernel that included kdb.
I do not know what the kernel uses the unwind info for. This question has
been asked on this list by others recently and has not been answered.
If I have to reproduce this problem by building a kernel and running kdb,
then you will have a very long wait before I look at this, since I will fix
everything I know how to fix first.
The comment about "control reaches end of non-void function" warnings doesn't
make sense. panic() is defined as returning void, so it should not be possible
to get this warning. I downloaded 2.4.2 today just to be sure, along with
David's 010228 patch.
I tried deleting the NORET_TYPE from the .c file, but I get identical .i
with and without it (disregarding whitespace). It doesn't seem to do anything.
I tried deleting the noreturn attribute that came from the kernel.h header
file, but doesn't do anything either. I get identical .s files with or
without it.
If you want me to look at this, you will have to give me something I can
understand. Preferably a .i file and a gcc command. But if you want me
to look at a kernel, then you need to tell me what kernel you are using,
what patches you have applied to it, where you got the patches from,
what kernel config file you are using, and what compiler version you are using.
And possibly other stuff that I don't know yet that I need.
I have linux-2.4.2 and David's 010228 patch. I am looking at the function
panic() in the kernel/panic.c file. I am using current FSF gcc development
sources.
The only thing that occurs to me at the moment is that maybe the kdb patch
is doing something here that causes the problem. I've never downloaded the
kdb patch. Last time I used kdb, it was still part of the ia64-linux kernel
sources. If I need the kdb patch, where to I get it from?
Jim
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [Linux-ia64] Unwind problem for __attribute__ noreturn
2001-03-20 2:10 [Linux-ia64] Unwind problem for __attribute__ noreturn Keith Owens
2001-03-21 0:24 ` Jim Wilson
@ 2001-03-21 6:03 ` Keith Owens
2001-03-21 6:53 ` David Mosberger
` (22 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Keith Owens @ 2001-03-21 6:03 UTC (permalink / raw)
To: linux-ia64
On Tue, 20 Mar 2001 13:10:16 +1100,
Keith Owens <kaos@melbourne.sgi.com> wrote:
>panic() is defined as __attribute__ ((noreturn)). Either gcc is
>generating invalid unwind data for this attribute or the kernel unwind
>code is mishandling the data.
Replying to my own mail. It is a fencepost problem caused by gcc
discarding code after a call to a noreturn function. The user that hit
this problem wanted an unconditional panic when scsi_malloc was called
so he inserted panic("testing\n") into scsi_malloc(). gcc recognised
that the rest of scsi_malloc could never be reached and discarded all
the following code. The generated object contains
e0000000007c0ea0 <scsi_malloc>:
e0000000007c0ea0: 01 08 0d 04 80 05 [MII] alloc r33=ar.pfs,3,2,0
e0000000007c0ea6: 20 82 f6 d7 4f 00 addl r34=-2608,r1
e0000000007c0eac: 04 00 c4 00 mov r32°;;
e0000000007c0eb0: 11 10 01 44 18 10 [MIB] ld8 r34=[r34]
e0000000007c0eb6: 00 00 00 02 00 00 nop.i 0x0
e0000000007c0ebc: 58 67 e2 58 br.call.sptk.many b0à000000005e7600 <panic>;;
e0000000007c0ec0 <scsi_free>:
e0000000007c0ec0: 00 18 15 08 80 05 [MII] alloc r35=ar.pfs,5,4,0
e0000000007c0ec6: 20 02 00 62 00 00 mov r34°
e0000000007c0ecc: 00 00 04 00 nop.i 0x0
panic() called kdb, kdb used the unwind data to work out where panic
was called from. Alas b0 is pointing at the first instruction of
scsi_free which completely confuses the unwinder. Instead of unwinding
the body of scsi_malloc it tries to unwind the prologue of scsi_free
and gets gibberish.
My first thought was for the unwind code to adjust b0 to reflect where
the call instruction was issued, which would correctly pick up
scsi_malloc. However bits of the kernel set b0 explicitly instead of
via call so adjusting b0 would not work in all cases.
The long term fix is for gcc to add nop after calls to non-return
functions. That would preserve enough of a code body for the unwinder
to work correctly. BTW this problem almost certainly affects gdb as
well as the kernel. Jim, do you need a gcc change request for this?
The short term fix is to use conditional calls to panic() and other
routines marked as noreturn. Make it conditional on something that you
know is true but the compiler cannot optimize away. This works:
if (current)
panic("testing\n");
I will look at hacking kdb to recognise a panic call as a special case
and work around this problem.
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [Linux-ia64] Unwind problem for __attribute__ noreturn
2001-03-20 2:10 [Linux-ia64] Unwind problem for __attribute__ noreturn Keith Owens
2001-03-21 0:24 ` Jim Wilson
2001-03-21 6:03 ` Keith Owens
@ 2001-03-21 6:53 ` David Mosberger
2001-03-21 7:12 ` Jim Wilson
` (21 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: David Mosberger @ 2001-03-21 6:53 UTC (permalink / raw)
To: linux-ia64
>>>>> On Tue, 20 Mar 2001 16:24:23 -0800, Jim Wilson <wilson@cygnus.com> said:
Jim> I do not know what the kernel uses the unwind info for. This
Jim> question has been asked on this list by others recently and has
Jim> not been answered.
The kernel uses unwind info for a number of things:
- to generate backtraces to aid debugging; kdb uses this
but we also use it in a number of other places where
we want to print a backtrace
- to obtain the register values of "preserved" registers from
"earlier" call frames
- to reconstruct the user-level values of the "preserved"
registers (e.g., this is used for ptrace() and when
creating a core dump)
Please let me know if this doesn't answer your question.
--david
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [Linux-ia64] Unwind problem for __attribute__ noreturn
2001-03-20 2:10 [Linux-ia64] Unwind problem for __attribute__ noreturn Keith Owens
` (2 preceding siblings ...)
2001-03-21 6:53 ` David Mosberger
@ 2001-03-21 7:12 ` Jim Wilson
2001-03-21 7:54 ` David Mosberger
` (20 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Jim Wilson @ 2001-03-21 7:12 UTC (permalink / raw)
To: linux-ia64
I disagree that de-optimizing the compiler output is the obvious solution.
In the case you describe, the return address will be equal to the end of
the scsi_malloc function and the beginning of the scsi_free function. In
that case, it should be obvious that we came from the scsi_malloc function.
You mention that the kernel sets b0 in some places. But if the kernel is
setting b0 differently than a call instruction does, then the kernel must
be broken. If the kernel is setting b0 to point someplace else to optimize
away a branch, then I don't understand how unwinding could work anyways,
because the unwind info will likely be different at the target than where
we are coming from. I would need a really good description of what the
kernel is doing here before I could accept this as a valid reason to
de-optimize code. If what the kernel is doing is valid, then why not
suggest that the kernel be modified to insert nops before the places where
the funny b0 stuff is done, so that b0-1 is still valid.
gdb does not use unwind info as yet, as far as I know.
We use the unwind info for C++ exceptions, but there would be no problem
there I think, because we already subtract one from the return address before
using it.
If I had enough time, I think I could create counterexamples showing that the
problem is not just noreturn calls. What happens if we have a call immediately
followed by something like .body/.copy_state. That would be pretty unlikly,
but it probably isn't impossible. If you use the return address directly,
then you get the wrong unwind state.
Jim
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [Linux-ia64] Unwind problem for __attribute__ noreturn
2001-03-20 2:10 [Linux-ia64] Unwind problem for __attribute__ noreturn Keith Owens
` (3 preceding siblings ...)
2001-03-21 7:12 ` Jim Wilson
@ 2001-03-21 7:54 ` David Mosberger
2001-03-21 8:54 ` Keith Owens
` (19 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: David Mosberger @ 2001-03-21 7:54 UTC (permalink / raw)
To: linux-ia64
>>>>> On Tue, 20 Mar 2001 23:12:49 -0800, Jim Wilson <wilson@cygnus.com> said:
Jim> But if the kernel is setting b0 differently than a call
Jim> instruction does, then the kernel must be broken. If the
Jim> kernel is setting b0 to point someplace else to optimize away a
Jim> branch, then I don't understand how unwinding could work
Jim> anyways, because the unwind info will likely be different at
Jim> the target than where we are coming from. I would need a
Jim> really good description of what the kernel is doing here before
Jim> I could accept this as a valid reason to de-optimize code.
The code path needed to leave the kernel is shared for all types of
interruptions. Before calling an interruption handler, the kernel
arranges things so that the handler will return directly to the shared
exit path, instead of returning to the call site first. This works
fine because the unwind state at the call site and return site are
always the same.
Jim> If what the kernel is doing is valid, then why not suggest that
Jim> the kernel be modified to insert nops before the places where
Jim> the funny b0 stuff is done, so that b0-1 is still valid.
I also doubt that adding "nop"s in the compiler is the right solution.
There is only one place in the kernel that the short-circuit return is
done, so that should be easily fixable.
Jim> We use the unwind info for C++ exceptions, but there would be
Jim> no problem there I think, because we already subtract one from
Jim> the return address before using it.
Perhaps that is the right solution. But I need to think about this
some more.
--david
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [Linux-ia64] Unwind problem for __attribute__ noreturn
2001-03-20 2:10 [Linux-ia64] Unwind problem for __attribute__ noreturn Keith Owens
` (4 preceding siblings ...)
2001-03-21 7:54 ` David Mosberger
@ 2001-03-21 8:54 ` Keith Owens
2001-03-21 17:54 ` David Mosberger
` (18 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Keith Owens @ 2001-03-21 8:54 UTC (permalink / raw)
To: linux-ia64
On Tue, 20 Mar 2001 23:54:44 -0800,
David Mosberger <davidm@hpl.hp.com> wrote:
>I also doubt that adding "nop"s in the compiler is the right solution.
After more thought, the problem of attribute ((noreturn)) affects all
architectures, all debuggers and all programs. It is not just ia64 +
kdb + kernel that has this problem. An unconditional call to function
F which is declared noreturn is converted by gcc into this
A:
...
call F
X:
...
which will cause problems for all debuggers on all architectures. The
return address is pointing at the start of X but F was really called by
A.
It is not valid to always subtract 1 from the return address because
programmers are allowed to do this in assembler.
A:
ret = B
goto F
X:
...
B:
...
F cannot assume that it was entered via call, it can be entered by any
hand coded construct that gives the same environment as a call, even if
the return is not to the code that branched to F. Subtracting 1 from
ret in this case would give B-1 which appears to be in X and is wrong.
Given these two methods of entering a function there is no way for a
debugger to adjust the return address correctly in all cases. Because
the problem case only occurs in C when function F is declared noreturn,
a change to gcc to emit
A:
...
call F
nop
X:
...
if and only if
(1) F is declared noreturn and
(2) gcc is discarding the rest of the function that calls F
will fix the problem. The extra nop is only required to avoid a call
as the very last instruction of a function so it has very little impact
on the size of most programs. It has zero impact on the speed of the
programs because the nop is never executed, it is just a padding code.
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [Linux-ia64] Unwind problem for __attribute__ noreturn
2001-03-20 2:10 [Linux-ia64] Unwind problem for __attribute__ noreturn Keith Owens
` (5 preceding siblings ...)
2001-03-21 8:54 ` Keith Owens
@ 2001-03-21 17:54 ` David Mosberger
2001-03-21 18:48 ` Cary Coutant
` (17 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: David Mosberger @ 2001-03-21 17:54 UTC (permalink / raw)
To: linux-ia64
Keith,
We are dealing with two problems here, both have a solution but the
solutions are conflicting:
Problem A: "noreturn" optimization confuses kernel unwinder because
return address is not inside the caller.
Solution A: Emit a dummy instruction after the last "br.call" in a
"no return" routine. Downside: requires generating extra
code with no purpose other than to make unwinding work
Problem B: "last-call" type optimizations confuse the gcc unwinder
because decrementing the return address does not yield
an address inside the caller.
Solution B: Don't decrement return pointer when determining the
caller. Downside: requires that the frame state
immediately before and after a br.call is identical.
I agree that manipulating the return pointer seems like a bad idea.
Especially on IA-64 where there is no way of reliably determining
which of the three instruction in a bundle was the one that called a
function. But generating dummy code just for the purpose of unwinding
doesn't seem 100% right either, as the unwind convention were
expressedly designed to work with fully optimized code.
Anyhow, I'll re-read the unwind conventions when I'm back at work.
Either the document answers this question unambigiously and one of the
existing unwinder implementation is wrong, or it doesn't answer the
question, in which case we need to pick one solution and work towards
clarifying this point in the manual.
--david
>>>>> On Wed, 21 Mar 2001 19:54:20 +1100, Keith Owens <kaos@ocs.com.au> said:
Keith> On Tue, 20 Mar 2001 23:54:44 -0800, David Mosberger
Keith> <davidm@hpl.hp.com> wrote:
>> I also doubt that adding "nop"s in the compiler is the right
>> solution.
Keith> After more thought, the problem of attribute ((noreturn))
Keith> affects all architectures, all debuggers and all programs.
Keith> It is not just ia64 + kdb + kernel that has this problem. An
Keith> unconditional call to function F which is declared noreturn
Keith> is converted by gcc into this
Keith> A: ... call F X: ...
Keith> which will cause problems for all debuggers on all
Keith> architectures. The return address is pointing at the start
Keith> of X but F was really called by A.
Keith> It is not valid to always subtract 1 from the return address
Keith> because programmers are allowed to do this in assembler.
Keith> A: ret = B goto F X: ... B: ...
Keith> F cannot assume that it was entered via call, it can be
Keith> entered by any hand coded construct that gives the same
Keith> environment as a call, even if the return is not to the code
Keith> that branched to F. Subtracting 1 from ret in this case
Keith> would give B-1 which appears to be in X and is wrong.
Keith> Given these two methods of entering a function there is no
Keith> way for a debugger to adjust the return address correctly in
Keith> all cases. Because the problem case only occurs in C when
Keith> function F is declared noreturn, a change to gcc to emit
Keith> A: ... call F nop X: ...
Keith> if and only if
Keith> (1) F is declared noreturn and (2) gcc is discarding the
Keith> rest of the function that calls F
Keith> will fix the problem. The extra nop is only required to
Keith> avoid a call as the very last instruction of a function so it
Keith> has very little impact on the size of most programs. It has
Keith> zero impact on the speed of the programs because the nop is
Keith> never executed, it is just a padding code.
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [Linux-ia64] Unwind problem for __attribute__ noreturn
2001-03-20 2:10 [Linux-ia64] Unwind problem for __attribute__ noreturn Keith Owens
` (6 preceding siblings ...)
2001-03-21 17:54 ` David Mosberger
@ 2001-03-21 18:48 ` Cary Coutant
2001-03-21 19:07 ` Jim Wilson
` (16 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Cary Coutant @ 2001-03-21 18:48 UTC (permalink / raw)
To: linux-ia64
>Anyhow, I'll re-read the unwind conventions when I'm back at work.
>Either the document answers this question unambigiously and one of the
>existing unwinder implementation is wrong, or it doesn't answer the
>question, in which case we need to pick one solution and work towards
>clarifying this point in the manual.
I'll admit up front that the unwind conventions do not answer this
question explictly, and they should.
The unwind conventions, however, are built on the assumption that the
return pointer can always be used to determine the unwind state of the
caller, whether that return pointer was generated by a br.call
instruction, or through some equivalent assembly code.
Anyone using an assembly coding trick to make the return go somewhere
other than immediately after the call must bear the responsibility of
ensuring that the unwind information is correct.
In the case of a call to a "noreturn" procedure, I'll offer the opinion
that having the unwinder decrement the rp is not correct. Two solutions
immediately come to mind:
1. Emit a bundle of nops following the call. I understand that this is at
odds with the goal of being able to describe fully-optimized code, but it
seems like a rare enough case and a small enough penalty that we could
live with it.
2. Turn the call into a tail call. Thus, in a call chain A calls B calls
C, where C is the noreturn procedure, B would instead branch to C, making
it look like A called C. You have to deallocate B's memory stack frame,
so the bundle of nops may actually be more attractive unless B doesn't
actually have a memory stack frame -- but it's also possible that the
deallocation could be accomplished in spare instruction slots. C would
simply take over B's register stack frame. As noted in the runtime
document, tail calls can be done only when all arguments are in registers.
-cary
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [Linux-ia64] Unwind problem for __attribute__ noreturn
2001-03-20 2:10 [Linux-ia64] Unwind problem for __attribute__ noreturn Keith Owens
` (7 preceding siblings ...)
2001-03-21 18:48 ` Cary Coutant
@ 2001-03-21 19:07 ` Jim Wilson
2001-03-21 19:13 ` David Mosberger
` (15 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Jim Wilson @ 2001-03-21 19:07 UTC (permalink / raw)
To: linux-ia64
At this point, you've made so many false, misleading, and exagerated claims
that I am highly skeptical. I will have to ponder this later. At the moment,
I have a couple of comments.
>It is not valid to always subtract 1 from the return address because
>programmers are allowed to do this in assembler.
>
>A:
> ret = B
> goto F
>X:
> ...
>B:
> ...
You're example is seriously lacking. You haven't provided any evidence to
support your claim that this is valid. Neither have you provided any
explanation of why someone might want to do this. I suspect this is
supposed to be the "last-call" optimization that David Mosberger mentioned.
That makes sense, but still does not prove that the optimization is valid.
>F cannot assume that it was entered via call, it can be entered by any
>hand coded construct that gives the same environment as a call, even if
>the return is not to the code that branched to F. Subtracting 1 from
>ret in this case would give B-1 which appears to be in X and is wrong.
If it is only extremely rare cases of hand-written code that cause a problem,
then why are we fixing the problem by changing the compiler? Shouldn't we
change the hand-written code?
Does the SGI compiler emit nops after calls that don't return? Is the SGI
compiler going to be changed to do this?
Jim
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [Linux-ia64] Unwind problem for __attribute__ noreturn
2001-03-20 2:10 [Linux-ia64] Unwind problem for __attribute__ noreturn Keith Owens
` (8 preceding siblings ...)
2001-03-21 19:07 ` Jim Wilson
@ 2001-03-21 19:13 ` David Mosberger
2001-03-21 19:13 ` Jim Wilson
` (14 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: David Mosberger @ 2001-03-21 19:13 UTC (permalink / raw)
To: linux-ia64
>>>>> On Wed, 21 Mar 2001 10:48:54 -0800, Cary Coutant <cary@cup.hp.com> said:
>> Anyhow, I'll re-read the unwind conventions when I'm back at
>> work. Either the document answers this question unambigiously
>> and one of the existing unwinder implementation is wrong, or it
>> doesn't answer the question, in which case we need to pick one
>> solution and work towards clarifying this point in the manual.
Cary> I'll admit up front that the unwind conventions do not answer
Cary> this question explictly, and they should.
OK.
Cary> The unwind conventions, however, are built on the assumption
Cary> that the return pointer can always be used to determine the
Cary> unwind state of the caller, whether that return pointer was
Cary> generated by a br.call instruction, or through some equivalent
Cary> assembly code.
Yes, that was certainly my _impression_ when reading the unwind
conventions. It would be good to make this explicit, though.
Cary> Anyone using an assembly coding trick to make the return go
Cary> somewhere other than immediately after the call must bear the
Cary> responsibility of ensuring that the unwind information is
Cary> correct.
Yes, the kernel does that.
Cary> In the case of a call to a "noreturn" procedure, I'll offer
Cary> the opinion that having the unwinder decrement the rp is not
Cary> correct. Two solutions immediately come to mind:
Cary> 1. Emit a bundle of nops following the call. I understand that
Cary> this is at odds with the goal of being able to describe
Cary> fully-optimized code, but it seems like a rare enough case and
Cary> a small enough penalty that we could live with it.
OK. But I'd rather see the compiler emit a "break 0" instead of a
"nop 0". With the former, when a noreturn function unexpectedly
returns, it will a generate a SIGILL signal with code ILL_ILLOPC
(illegal opcode) instead of silently executing wrong code.
Cary> 2. Turn the call into a tail call. Thus, in a call chain A
Cary> calls B calls C, where C is the noreturn procedure, B would
Cary> instead branch to C, making it look like A called C. You have
Cary> to deallocate B's memory stack frame, so the bundle of nops
Cary> may actually be more attractive unless B doesn't actually have
Cary> a memory stack frame -- but it's also possible that the
Cary> deallocation could be accomplished in spare instruction
Cary> slots. C would simply take over B's register stack frame. As
Cary> noted in the runtime document, tail calls can be done only
Cary> when all arguments are in registers.
Yes, I considered that, too. But I think the biggest savings of
"noreturn" comes precisely from not having to bother to drop the
current call frame, so emitting an extra bundle containing "break 0"
is probably a better approach.
--david
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [Linux-ia64] Unwind problem for __attribute__ noreturn
2001-03-20 2:10 [Linux-ia64] Unwind problem for __attribute__ noreturn Keith Owens
` (9 preceding siblings ...)
2001-03-21 19:13 ` David Mosberger
@ 2001-03-21 19:13 ` Jim Wilson
2001-03-21 19:26 ` Cary Coutant
` (13 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Jim Wilson @ 2001-03-21 19:13 UTC (permalink / raw)
To: linux-ia64
>I agree that manipulating the return pointer seems like a bad idea.
>Especially on IA-64 where there is no way of reliably determining
>which of the three instruction in a bundle was the one that called a
>function.
It doesn't matter. There can never be anything except a B instruction in the
same bundle after a call, and there are no B instructions that can change the
unwind state.
Jim
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [Linux-ia64] Unwind problem for __attribute__ noreturn
2001-03-20 2:10 [Linux-ia64] Unwind problem for __attribute__ noreturn Keith Owens
` (10 preceding siblings ...)
2001-03-21 19:13 ` Jim Wilson
@ 2001-03-21 19:26 ` Cary Coutant
2001-03-21 19:40 ` Jim Wilson
` (12 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Cary Coutant @ 2001-03-21 19:26 UTC (permalink / raw)
To: linux-ia64
> Cary> 1. Emit a bundle of nops following the call. I understand that
> Cary> this is at odds with the goal of being able to describe
> Cary> fully-optimized code, but it seems like a rare enough case and
> Cary> a small enough penalty that we could live with it.
>
>OK. But I'd rather see the compiler emit a "break 0" instead of a
>"nop 0". With the former, when a noreturn function unexpectedly
>returns, it will a generate a SIGILL signal with code ILL_ILLOPC
>(illegal opcode) instead of silently executing wrong code.
Yes, that's a good idea.
-cary
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [Linux-ia64] Unwind problem for __attribute__ noreturn
2001-03-20 2:10 [Linux-ia64] Unwind problem for __attribute__ noreturn Keith Owens
` (11 preceding siblings ...)
2001-03-21 19:26 ` Cary Coutant
@ 2001-03-21 19:40 ` Jim Wilson
2001-03-21 19:58 ` David Mosberger
` (11 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Jim Wilson @ 2001-03-21 19:40 UTC (permalink / raw)
To: linux-ia64
Consider this case
mutex p6, p7
{ .mib
(p6) instruction that changes the unwind state
(p7) call that does not return
}
unwind directives to declare new unwind state
If p7 is true, and we try to unwind inside the call, then the return address
will point to the modified unwind state which is incorrect, because we did
not execute the p6 instruction. To make this work, we have to subtract one
from the return address to get an address before the new unwind state is
established.
I posit that this example is more realistic and more useful than the example
which modifies b0 to optimize away a branch.
Jim
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [Linux-ia64] Unwind problem for __attribute__ noreturn
2001-03-20 2:10 [Linux-ia64] Unwind problem for __attribute__ noreturn Keith Owens
` (12 preceding siblings ...)
2001-03-21 19:40 ` Jim Wilson
@ 2001-03-21 19:58 ` David Mosberger
2001-03-21 20:00 ` Jim Wilson
` (10 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: David Mosberger @ 2001-03-21 19:58 UTC (permalink / raw)
To: linux-ia64
>>>>> On Wed, 21 Mar 2001 11:40:55 -0800, Jim Wilson <wilson@cygnus.com> said:
Jim> Consider this case
Jim> mutex p6, p7
Jim> { .mib
Jim> (p6) instruction that changes the unwind state
Jim> (p7) call that does not return
Jim> }
Jim> unwind directives to declare new unwind state
This wouldn't be correct: the unwind directives would have to go in
front of the instruction predicated by (p6). Otherwise, you might get
interrupted (e.g., by a signal), after executing that instruction, and
then the unwind info would be wrong.
Now, to fix this, you'd have to use the general unwind directives and
that would imply that instead of p6/p7, you'd have to use a "preserved"
predicate. Given those restrictions, I think you could just as easily
do:
mutex p8, p9
{ .mib
unwind directive describing effect of next insn
(p8) instruction that changes the unwind state
(p9) call that does not return
}
(p9) break 0
This is slightly worse than the optimal code, but not by much. The
biggest potential impact comes from the fact that now you need to
preserve the contents of "pr".
--david
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [Linux-ia64] Unwind problem for __attribute__ noreturn
2001-03-20 2:10 [Linux-ia64] Unwind problem for __attribute__ noreturn Keith Owens
` (13 preceding siblings ...)
2001-03-21 19:58 ` David Mosberger
@ 2001-03-21 20:00 ` Jim Wilson
2001-03-21 20:38 ` Jim Wilson
` (9 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Jim Wilson @ 2001-03-21 20:00 UTC (permalink / raw)
To: linux-ia64
>In the case of a call to a "noreturn" procedure, I'll offer the opinion
>that having the unwinder decrement the rp is not correct.
Why? It isn't good enough to say that this is wrong. You should justify
why you think it is wrong.
I suggest people look at other existing unwinders before discarding the
subtact one idea.
GCC for instance has a DWARF2 based unwinder for exception handling.
It subtracts one from the return address before using it. It has been
doing this for several years, and this works for all architectures.
The relatively recent IA-64 unwinder does the same thing. This ensures that
we get the right frame state, the one that exists at the point of the call,
not the one that exists after the point of the call.
Jim
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [Linux-ia64] Unwind problem for __attribute__ noreturn
2001-03-20 2:10 [Linux-ia64] Unwind problem for __attribute__ noreturn Keith Owens
` (14 preceding siblings ...)
2001-03-21 20:00 ` Jim Wilson
@ 2001-03-21 20:38 ` Jim Wilson
2001-03-21 22:54 ` David Mosberger
` (8 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Jim Wilson @ 2001-03-21 20:38 UTC (permalink / raw)
To: linux-ia64
So my quickie example isn't valid. However, I am not yet convinced that
there is no such example that is valid. I will have to look at this some
more. That will take time, and I am already very busy.
Also, if gcc does have to change, then I need a good explanation of why.
I can't go to the other gcc developers and tell them that the way we've been
doing things for 3-4 years is now suddenly wrong, without also explaining
exactly why it is wrong. As yet, I do not have any explanation I can use.
There are also other issues here as to whether we only have to change the
IA-64 target, or whether we should change all targets, or whether we change
a target depends on which unwinder it uses (IA-64, DWARF2, setjmp/longjmp).
Also, there is the question of whether the gcc IA-64 unwinder and/or the
gcc DWARF2 unwinder needs to change. If gcc has to change, it could take
some time to get all these issues sorted out.
Jim
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [Linux-ia64] Unwind problem for __attribute__ noreturn
2001-03-20 2:10 [Linux-ia64] Unwind problem for __attribute__ noreturn Keith Owens
` (15 preceding siblings ...)
2001-03-21 20:38 ` Jim Wilson
@ 2001-03-21 22:54 ` David Mosberger
2001-03-21 23:42 ` Cary Coutant
` (7 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: David Mosberger @ 2001-03-21 22:54 UTC (permalink / raw)
To: linux-ia64
>>>>> On Wed, 21 Mar 2001 12:38:47 -0800, Jim Wilson <wilson@cygnus.com> said:
Jim> Also, if gcc does have to change, then I need a good
Jim> explanation of why. I can't go to the other gcc developers and
Jim> tell them that the way we've been doing things for 3-4 years is
Jim> now suddenly wrong, without also explaining exactly why it is
Jim> wrong. As yet, I do not have any explanation I can use.
Fair enough. But I hope are not discounting the usefulness of a
short-circuit return just because gcc happens not to generate such
code at the moment. It's certainly a common idiom for assembly
programming and clearly useful. So, the example that Keith gave is
one valid example:
mov rp = common_exit_path_code
br.call b6 = handler
A second example is:
{ .bbb
(p8) br.call rp = function-that-doesn't-return
nop.b 0
cover
}
The cover does affect the current frame state, as it allocates a NULL
register frame. If you were to just decrement the ip, you'd pick up
the frame state for cover (in all likelihood). Note that according to
Cary, the above example would be illegal because the frame state
changes between the point of br.call and the address that "rp" points
to. But it shows that even without Cary's rule you'd could still get
into trouble with decrementing the IP.
Also, I'd like to point out that if X is a valid bundle address, then
X-1 is NOT a valid instruction address as it contains 0xf in the least
significant four bits. I suspect that if you pass such an address to
an unwind library, you end up relying on implementation specific
behavior.
--david
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [Linux-ia64] Unwind problem for __attribute__ noreturn
2001-03-20 2:10 [Linux-ia64] Unwind problem for __attribute__ noreturn Keith Owens
` (16 preceding siblings ...)
2001-03-21 22:54 ` David Mosberger
@ 2001-03-21 23:42 ` Cary Coutant
2001-03-22 17:00 ` Rich Altmaier
` (6 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Cary Coutant @ 2001-03-21 23:42 UTC (permalink / raw)
To: linux-ia64
>>In the case of a call to a "noreturn" procedure, I'll offer the opinion
>>that having the unwinder decrement the rp is not correct.
>
>Why? It isn't good enough to say that this is wrong. You should justify
>why you think it is wrong.
OK. The problem is that rp doesn't tell us where the branch is: even
excluding examples like Keith's, you don't know whether to back up one,
two, or three instruction slots. If you allow for the short-circuit
return, you're totally lost. The only reasonable assumption the unwinder
can make is that rp, being where control would normally resume in that
frame, is the address that determines the unwind state.
-cary
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [Linux-ia64] Unwind problem for __attribute__ noreturn
2001-03-20 2:10 [Linux-ia64] Unwind problem for __attribute__ noreturn Keith Owens
` (17 preceding siblings ...)
2001-03-21 23:42 ` Cary Coutant
@ 2001-03-22 17:00 ` Rich Altmaier
2001-03-23 20:28 ` Jim Wilson
` (5 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Rich Altmaier @ 2001-03-22 17:00 UTC (permalink / raw)
To: linux-ia64
Just a comment in principle, historically in the MIPS compiler we have faced
this trouble. That is, a conflict between the compiler goal of really good
optimization, and the debugger goal of "mapping runtime object code to
something understood by the source code programmer".
The keener you get on optimizations, the more impossible, and finally
simply impossible, is the debuggers job. We should appreciate that
we are asking for a stretch from both the optimizer AND the debugger!
When no mapping is possible, do we give up the optimization or the
debugging? Since the person trying to debug is usually the person
who typed "gcc", they can choose. One effect is for developers to back
off on optimization levels, except for critical functions. We see this quite
a lot from our ISVs. Debug time costs more in "opportunity cost", than
the value of attaining the most optimized code performance.
Thanks, Rich
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [Linux-ia64] Unwind problem for __attribute__ noreturn
2001-03-20 2:10 [Linux-ia64] Unwind problem for __attribute__ noreturn Keith Owens
` (18 preceding siblings ...)
2001-03-22 17:00 ` Rich Altmaier
@ 2001-03-23 20:28 ` Jim Wilson
2001-03-24 0:58 ` Cary Coutant
` (4 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Jim Wilson @ 2001-03-23 20:28 UTC (permalink / raw)
To: linux-ia64
>Fair enough. But I hope are not discounting the usefulness of a
>short-circuit return just because gcc happens not to generate such
>code at the moment.
> mov rp = common_exit_path_code
> br.call b6 = handler
I'm trying not to discount it, but I do need to understand it, and how it
effects other features of the compiler.
If your only interest in unwind info is being able to unwind another frame,
then this optimization works fine. All you need to do is make sure the
frame state is the same at the branch target. This is pretty easy to do,
and you are already doing it.
However, there are conflicts with other compiler features. Someone from SGI
alluded to this, but did not give specific examples.
Consider debugging. If we are in the debugger in the callee, and then go up
one frame and try to look at local variables, then this will fail if the call
and the branch target are in different lexical blocks. This also makes it
difficult to impossible to determine where the call came from when inside the
callee. So this makes debugging more difficult, however, debugging optimized
code has enough problems already that this isn't a good enough reason to avoid
the optimization.
Consider C++ EH. If the call and the branch target are in different
exception regions, and the callee throws an exception, then we will end up
calling the wrong exception handler. This does not prevent us from performing
the optimization if there are no exception regions, or if the call and the
branch target are in the same exception region. The design of the EH system
may have an effect on whether this example is valid. I know it is valid for
the table based EH system that gcc currently uses. I don't know enough about
the new C++ ABI unwind API to know if it is valid there.
Therefore, it makes sense to allow the optimization, and adjust the unwinder
so that it can handle this case.
>the frame state for cover (in all likelihood). Note that according to
>Cary, the above example would be illegal because the frame state
>changes between the point of br.call and the address that "rp" points
>to. But it shows that even without Cary's rule you'd could still get
I don't know who Cary is, or why we have to follow his rules. All I know about
him is his email address. However, he does seem to be relatively knowledgable
about unwind issues, so I'm willing to consider his opinions.
>Also, I'd like to point out that if X is a valid bundle address, then
>X-1 is NOT a valid instruction address as it contains 0xf in the least
>significant four bits. I suspect that if you pass such an address to
>an unwind library, you end up relying on implementation specific
>behavior.
Subtracting one from an instruction address by itself is obviously not a valid
thing to do, but we need to keep in mind the context here.
When unwinding, we are doing a table lookup. The address space is split into
a bunch of separate unwind regions, each one stopping where the next one
starts. This leaves us vulnerable to boundary crossing problems. If a call
occurs in the last bundle of an unwind region, then the return address points
to the next unwind region. In gcc, we fix this problem by subtracting one
from the return address before doing the table lookup. This ensures that
we are always in the same unwind region as the call instruction. This solves
the problem with noreturn calls at the end of functions. It also solves
other potential problems. For the IA-64 unwind ABI, you are trying to solve
this problem by forbidding unwind regions from ending immediately after a call.
This is done partly via Cary's rule, and partly by asking for breaks/nops
after a noreturn call at the end of a function. This also incidentally makes
the kernel optimization work, since the return address subtraction is no longer
needed. In gcc, we still need this for the DWARF2 unwinder though, unless
we are going to apply these same rules for all architectures.
Similarly, when doing C++ exception handling, we are doing a table lookup.
The address space in split into a bunch of separate exception regions, and
there is a boundary-crossing problem if a call is the last instruction of an
exception region. We also fix this by subtracting one from the return address
before the table lookup. In fact, it is the exact same subtraction we do
above, we only have to do it once. I don't know enough about the new C++ ABI
unwind API to know if this problem is still present. There is the problem
that gcc doesn't have the new unwind API as yet. We are still using our
exception table approach, and hence we still need the subtract one in the
IA-64 unwinder to make C++ EH. If the new unwind API does not have this
boundary problem, then the subtraction can go away when we switch to it.
Jim
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [Linux-ia64] Unwind problem for __attribute__ noreturn
2001-03-20 2:10 [Linux-ia64] Unwind problem for __attribute__ noreturn Keith Owens
` (19 preceding siblings ...)
2001-03-23 20:28 ` Jim Wilson
@ 2001-03-24 0:58 ` Cary Coutant
2001-03-24 1:27 ` Keith Owens
` (3 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Cary Coutant @ 2001-03-24 0:58 UTC (permalink / raw)
To: linux-ia64
>I don't know who Cary is
For those who don't know me, I'm responsible for the HP-UX runtime
architecture on both PA-RISC and IA-64. I've worked with Intel on IA-64
from the beginning, contributed to the hardware architecture, co-led the
development of the runtime architecture, and wrote a large part of the
Software Conventions and Runtime Architecture document, including all of
the unwind chapter. (Sometimes I don't like to admit that when it becomes
evident that I neglected a corner case such as the one we're now
discussing!)
While I don't participate in the Linux implementation effort (though I'd
like to), I keep an eye on this mailing list to catch and correct issues
like this one.
>When unwinding, we are doing a table lookup. The address space is split into
>a bunch of separate unwind regions, each one stopping where the next one
>starts. This leaves us vulnerable to boundary crossing problems. If a call
>occurs in the last bundle of an unwind region, then the return address points
>to the next unwind region.
Except for calls to noreturn procedures (which I failed to anticipate in
the design and specification of the unwind architecture), the return
point must always be in the same unwind region as the call, because
nothing can happen to change the unwind state between the call and the
return point.
>Similarly, when doing C++ exception handling, we are doing a table lookup.
>The address space in split into a bunch of separate exception regions, and
>there is a boundary-crossing problem if a call is the last instruction of an
>exception region.
To me, the EH model is better thought of not as a set of regions, but as
a set of discrete points in the code where an exception can be raised.
Each of these points, most of which are return points following calls,
can be described in the EH tables without any ambiguity about what region
the IP address belongs to.
-cary
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [Linux-ia64] Unwind problem for __attribute__ noreturn
2001-03-20 2:10 [Linux-ia64] Unwind problem for __attribute__ noreturn Keith Owens
` (20 preceding siblings ...)
2001-03-24 0:58 ` Cary Coutant
@ 2001-03-24 1:27 ` Keith Owens
2001-03-24 1:37 ` Jim Wilson
` (2 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Keith Owens @ 2001-03-24 1:27 UTC (permalink / raw)
To: linux-ia64
On Fri, 23 Mar 2001 16:58:59 -0800,
Cary Coutant <cary@cup.hp.com> wrote:
>Except for calls to noreturn procedures (which I failed to anticipate in
>the design and specification of the unwind architecture), the return
>point must always be in the same unwind region as the call, because
>nothing can happen to change the unwind state between the call and the
>return point.
Just to make it explicit. Will the runtime architecture be updated to
forbid a call as the last instruction in an unwind region? Or do we
have to somehow cope with this corner case?
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [Linux-ia64] Unwind problem for __attribute__ noreturn
2001-03-20 2:10 [Linux-ia64] Unwind problem for __attribute__ noreturn Keith Owens
` (21 preceding siblings ...)
2001-03-24 1:27 ` Keith Owens
@ 2001-03-24 1:37 ` Jim Wilson
2001-03-26 22:06 ` DE-DINECHIN,CHRISTOPHE (HP-Cupertino,ex1)
2001-03-26 22:58 ` Cary Coutant
24 siblings, 0 replies; 26+ messages in thread
From: Jim Wilson @ 2001-03-24 1:37 UTC (permalink / raw)
To: linux-ia64
>To me, the EH model is better thought of not as a set of regions, but as
>a set of discrete points in the code where an exception can be raised.
Compactness of the representation is a concern. Using tables to describe
ranges of address is relatively compact. I know that the new C++ ABI
uses a possibly different representation that is reasonably compact, but I
don't know how it achieves it.
In C++, exceptions can only be raised by a call to throw. Thus they can
only occur at a few discrete points. However, in other languages, Java and
Ada in particular, exceptions can be raised in many other cases. I think
the Java case is simpler, they only specify a few additional cases like
divide by zero. However, I believe Ada allows any instruction to generate
exceptions. This is called asynchonous exceptions in the gcc source code.
We don't handle asynchronous exceptions correctly in gcc, but it would be
good if we didn't arbitrarily exclude future support for them. If every
instruction can throw an exception, then does it still make sense to keep
track of them as discrete points? I believe the gcc Ada front end already has
its own exception handling code which is different from the gcc middle end
code used for C/C++/Java/etc, so perhaps we don't care whether this EH
scheme ever works for Ada.
Disclaimer: I am not a C++, Java, or Ada expert.
Perhaps I should just go off and study the new EH scheme so I can answer my
own questions.
Jim
^ permalink raw reply [flat|nested] 26+ messages in thread* RE: [Linux-ia64] Unwind problem for __attribute__ noreturn
2001-03-20 2:10 [Linux-ia64] Unwind problem for __attribute__ noreturn Keith Owens
` (22 preceding siblings ...)
2001-03-24 1:37 ` Jim Wilson
@ 2001-03-26 22:06 ` DE-DINECHIN,CHRISTOPHE (HP-Cupertino,ex1)
2001-03-26 22:58 ` Cary Coutant
24 siblings, 0 replies; 26+ messages in thread
From: DE-DINECHIN,CHRISTOPHE (HP-Cupertino,ex1) @ 2001-03-26 22:06 UTC (permalink / raw)
To: linux-ia64
Jim,
Note that the current exception handling model uses two levels of table:
- A first level describes an "unwind region", and it indeed describes ranges
as you would expect.
- A second level is language-specific. For C++, since C++ exceptions occur
only at a call point (including a call to the "throw" library routine), it
is a table of instruction addresses. This allows us, among others, to detect
if an exception is thrown from an unexpected place. And for C++, it is
unclear that it really wastes space compared to a range-based mechanism.
With respect to exceptions in other languages, the most complex case is
probably that of Ada. Although the last time I worked on an Ada compiler was
almost 10 years ago, I know that our current C++ scheme would be difficult
to implement in Ada. So the language-specific part for Ada would have to be
very different (essentially, listing ranges of code as you suggested.)
Regards
Christophe
-----Original Message-----
From: linux-ia64-admin@linuxia64.org
[mailto:linux-ia64-admin@linuxia64.org]On Behalf Of Jim Wilson
Sent: Friday, March 23, 2001 5:37 PM
To: Cary Coutant
Cc: linux-ia64@linuxia64.org
Subject: Re: [Linux-ia64] Unwind problem for __attribute__ noreturn
>To me, the EH model is better thought of not as a set of regions, but as
>a set of discrete points in the code where an exception can be raised.
Compactness of the representation is a concern. Using tables to describe
ranges of address is relatively compact. I know that the new C++ ABI
uses a possibly different representation that is reasonably compact, but I
don't know how it achieves it.
In C++, exceptions can only be raised by a call to throw. Thus they can
only occur at a few discrete points. However, in other languages, Java and
Ada in particular, exceptions can be raised in many other cases. I think
the Java case is simpler, they only specify a few additional cases like
divide by zero. However, I believe Ada allows any instruction to generate
exceptions. This is called asynchonous exceptions in the gcc source code.
We don't handle asynchronous exceptions correctly in gcc, but it would be
good if we didn't arbitrarily exclude future support for them. If every
instruction can throw an exception, then does it still make sense to keep
track of them as discrete points? I believe the gcc Ada front end already
has
its own exception handling code which is different from the gcc middle end
code used for C/C++/Java/etc, so perhaps we don't care whether this EH
scheme ever works for Ada.
Disclaimer: I am not a C++, Java, or Ada expert.
Perhaps I should just go off and study the new EH scheme so I can answer my
own questions.
Jim
_______________________________________________
Linux-IA64 mailing list
Linux-IA64@linuxia64.org
http://lists.linuxia64.org/lists/listinfo/linux-ia64
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [Linux-ia64] Unwind problem for __attribute__ noreturn
2001-03-20 2:10 [Linux-ia64] Unwind problem for __attribute__ noreturn Keith Owens
` (23 preceding siblings ...)
2001-03-26 22:06 ` DE-DINECHIN,CHRISTOPHE (HP-Cupertino,ex1)
@ 2001-03-26 22:58 ` Cary Coutant
24 siblings, 0 replies; 26+ messages in thread
From: Cary Coutant @ 2001-03-26 22:58 UTC (permalink / raw)
To: linux-ia64
>Just to make it explicit. Will the runtime architecture be updated to
>forbid a call as the last instruction in an unwind region? Or do we
>have to somehow cope with this corner case?
I have made the following proposal, in the IA-64 psABI group, to amend
the runtime document:
>... I propose adding the following rule to Section 8.7,
>"Requirements for unwinding the stack," in the Software Conventions and
>Runtime Architecture document:
>
>* The return BR must contain an address that can be used to
> determine the unwind state of the calling procedure. For
> example, a compiler may choose to optimize calls to
> procedures that do not return. If it does so, however, it must
> ensure that the unwind information for the procedure properly
> describes the unwind state at the return point, even though the
> return point will never be executed. This may require the
> insertion of an otherwise unnecessary nop or break instruction.
-cary
^ permalink raw reply [flat|nested] 26+ messages in thread