This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Unwinding through signal handlers on IA-64/Linux
- From: Eric Botcazou <ebotcazou at adacore dot com>
- To: gcc at gcc dot gnu dot org
- Date: Fri, 4 Nov 2005 20:36:30 +0100
- Subject: Unwinding through signal handlers on IA-64/Linux
Hi,
It works if the unwind library is HP's libunwind (aka system libunwind) but
doesn't if the unwind library is the bundled one (config/ia64/unwind-ia64.c).
That's with a 3.4.5pre-based compiler on SLES 9, but the problem is very
likely present on all branches.
The bottom line is that the CFM register is incorrectly restored: it is loaded
with the value of the AR.PFS register when the signal is raised.
Breakpoint 3, 0x4000000000003300 in _ada_p ()
(gdb) info reg cfm
cfm 0x287 647
(gdb) info reg pfs
pfs 0xc000000000000388 -4611686018427387000
(gdb) continue
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0x4000000000003300 in _ada_p ()
(gdb)
Continuing.
Breakpoint 1, 0x40000000000033f2 in _ada_p ()
(gdb) info reg cfm
cfm 0x388 904
Debug session with the same executable using HP's libunwind:
Breakpoint 3, 0x4000000000003300 in _ada_p ()
(gdb) info reg cfm
cfm 0x287 647
(gdb) info reg pfs
pfs 0xc000000000000388 -4611686018427387000
(gdb) continue
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0x4000000000003300 in _ada_p ()
(gdb)
Continuing.
Breakpoint 1, 0x40000000000033f2 in _ada_p ()
(gdb) info reg cfm
cfm 0x287 647
Now the unwinder gets it almost right, that is fs->curr.reg[UNW_REG_PFS] holds
the right values (val = 224, where = UNW_WHERE_SPREL, when = -1). But there
are these lines in ia64_handle_unwabi:
/* pfs_loc already set above. Without this pfs_loc would point
incorrectly to sc_cfm instead of sc_ar_pfs. */
fs->curr.reg[UNW_REG_PFS].where = UNW_WHERE_NONE;
The problem is that we want pfs_loc to essentially[1] point to sc_cfm, which
is the saved CFM in the signal context, because we use the target AR.PFS to
restore the CFM with the help of br.ret; we certainly don't want it to point
to the saved AR.PFS in the signal context, which is a dead value if a
register frame has been allocated[2].
These lines look very questionable to me; if they are removed, all works fine
for the attached testcase (compile with -gnatp). Maybe some confusion comes
from
context->pfs_loc = &(sc->sc_ar_pfs);
a few lines above, which is a dead statement if considered alone.
Can anyone shed some light on this? Thanks in advance.
[1] essentially because we probably would want pfs_loc to point to a CFM+EC
value. But I skimmed through HP's libunwind and I didn't find any attempt to
put together a full AR.PFS value from saved CFM and EC.
[2] if a register frame has not been allocated then AR.PFS is live in the
procedure and would need to be restored too. Incidentally, the current code
probably works in that case, but I think it cannot happen in practice.
--
Eric Botcazou
with Ada.Text_IO;
procedure P is
type Int_Ptr is access all Integer;
Data : Int_Ptr := null;
begin
Data.all := 0;
exception
when others =>
Ada.Text_IO.Put_Line ("Exception handled");
end P;