re PR ada/41929 (64-bit null_pointer_deref1 gnat.dg test consumes all available memory)
gcc: PR ada/41929 * config/sparc/sol2-unwind.h: Include <sys/frame.h>, <sys/stack.h> (IS_SIGHANDLER): Define. (sparc64_is_sighandler): New function, split off from sparc64_fallback_frame_state. (sparc_is_sighandler): New function, split off from sparc_fallback_frame_state. (sparc64_fallback_frame_state): Merge with ... (sparc_fallback_frame_state): ... this into ... (MD_FALLBACK_FRAME_STATE_FOR): ... this. Change new_cfa to long. Remove regs_off, fpu_save_off, fpu_save. Define nframes, mctx. Use IS_SIGHANDLER, handler_args, mctx, walk stack instead of hardcoded offsets. gcc/testsuite: PR ada/41929 * gnat.dg/null_pointer_deref1.exp: Don't skip on sparc*-sun-solaris2.11. From-SVN: r170126
This commit is contained in:
parent
93302a2491
commit
ad56a54c68
4 changed files with 303 additions and 349 deletions
|
@ -1,3 +1,21 @@
|
|||
2011-02-14 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
|
||||
|
||||
PR ada/41929
|
||||
* config/sparc/sol2-unwind.h: Include <sys/frame.h>, <sys/stack.h>
|
||||
(IS_SIGHANDLER): Define.
|
||||
(sparc64_is_sighandler): New function, split off from
|
||||
sparc64_fallback_frame_state.
|
||||
(sparc_is_sighandler): New function, split off from
|
||||
sparc_fallback_frame_state.
|
||||
(sparc64_fallback_frame_state): Merge with ...
|
||||
(sparc_fallback_frame_state): ... this into ...
|
||||
(MD_FALLBACK_FRAME_STATE_FOR): ... this.
|
||||
Change new_cfa to long.
|
||||
Remove regs_off, fpu_save_off, fpu_save.
|
||||
Define nframes, mctx.
|
||||
Use IS_SIGHANDLER, handler_args, mctx, walk stack instead of
|
||||
hardcoded offsets.
|
||||
|
||||
2011-02-14 Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
|
||||
|
||||
* go/gccgo.texi (Top, Import and Export): Fix a typo and a
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* DWARF2 EH unwinding support for SPARC Solaris.
|
||||
Copyright (C) 2009, 2010 Free Software Foundation, Inc.
|
||||
Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
|
@ -26,224 +26,130 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
|||
state data appropriately. See unwind-dw2.c for the structs. */
|
||||
|
||||
#include <ucontext.h>
|
||||
#include <sys/frame.h>
|
||||
#include <sys/stack.h>
|
||||
|
||||
#if defined(__arch64__)
|
||||
|
||||
#define MD_FALLBACK_FRAME_STATE_FOR sparc64_fallback_frame_state
|
||||
#define IS_SIGHANDLER sparc64_is_sighandler
|
||||
|
||||
static _Unwind_Reason_Code
|
||||
sparc64_fallback_frame_state (struct _Unwind_Context *context,
|
||||
_Unwind_FrameState *fs)
|
||||
static int
|
||||
sparc64_is_sighandler (unsigned int *pc, unsigned int *savpc, int *nframes)
|
||||
{
|
||||
void *pc = context->ra;
|
||||
void *this_cfa = context->cfa;
|
||||
void *new_cfa, *ra_location, *shifted_ra_location;
|
||||
int regs_off;
|
||||
int fpu_save_off;
|
||||
unsigned char fpu_save;
|
||||
int i;
|
||||
if (/* Solaris 8 - single-threaded
|
||||
----------------------------
|
||||
<sigacthandler+24>: add %g5, %o7, %o2
|
||||
<sigacthandler+28>: ldx [ %o2 + 0xfa0 ], %g5
|
||||
<sigacthandler+32>: sra %i0, 0, %o0
|
||||
<sigacthandler+36>: sllx %o0, 3, %g4
|
||||
<sigacthandler+40>: ldx [ %g4 + %g5 ], %l0
|
||||
<sigacthandler+44>: call %l0
|
||||
<sigacthandler+48>: mov %i2, %o2
|
||||
<sigacthandler+52>: cmp %i3, 8 <--- PC */
|
||||
( pc[-7] == 0x9401400f
|
||||
&& pc[-6] == 0xca5aafa0
|
||||
&& pc[-5] == 0x913e2000
|
||||
&& pc[-4] == 0x892a3003
|
||||
&& pc[-3] == 0xe0590005
|
||||
&& pc[-2] == 0x9fc40000
|
||||
&& pc[-1] == 0x9410001a
|
||||
&& pc[ 0] == 0x80a6e008)
|
||||
|
||||
/* This is the observed pattern for the sigacthandler in Solaris 8. */
|
||||
unsigned int sigacthandler_sol8_pattern []
|
||||
= {0x9401400f, 0xca5aafa0, 0x913e2000, 0x892a3003,
|
||||
0xe0590005, 0x9fc40000, 0x9410001a, 0x80a6e008};
|
||||
|| /* Solaris 9 - single-threaded
|
||||
----------------------------
|
||||
The pattern changes slightly in different versions of the
|
||||
operating system, so we skip the comparison against pc[-6] for
|
||||
Solaris 9.
|
||||
|
||||
/* This is the observed pattern for the sigacthandler in Solaris 9. */
|
||||
unsigned int sigacthandler_sol9_pattern []
|
||||
= {0xa33e2000, 0x00000000, 0x892c7003, 0x90100011,
|
||||
0xe0590005, 0x9fc40000, 0x9410001a, 0x80a46008};
|
||||
<sigacthandler+24>: sra %i0, 0, %l1
|
||||
|
||||
/* This is the observed pattern for the __sighndlr. */
|
||||
unsigned int sighndlr_pattern []
|
||||
= {0x9de3bf50, 0x90100018, 0x92100019, 0x9fc6c000,
|
||||
0x9410001a, 0x81c7e008, 0x81e80000};
|
||||
Solaris 9 5/02:
|
||||
<sigacthandler+28>: ldx [ %o2 + 0xf68 ], %g5
|
||||
Solaris 9 9/05:
|
||||
<sigacthandler+28>: ldx [ %o2 + 0xe50 ], %g5
|
||||
|
||||
/* Deal with frame-less function from which a signal was raised. */
|
||||
if (_Unwind_IsSignalFrame (context))
|
||||
<sigacthandler+32>: sllx %l1, 3, %g4
|
||||
<sigacthandler+36>: mov %l1, %o0
|
||||
<sigacthandler+40>: ldx [ %g4 + %g5 ], %l0
|
||||
<sigacthandler+44>: call %l0
|
||||
<sigacthandler+48>: mov %i2, %o2
|
||||
<sigacthandler+52>: cmp %l1, 8 <--- PC */
|
||||
( pc[-7] == 0xa33e2000
|
||||
/* skip pc[-6] */
|
||||
&& pc[-5] == 0x892c7003
|
||||
&& pc[-4] == 0x90100011
|
||||
&& pc[-3] == 0xe0590005
|
||||
&& pc[-2] == 0x9fc40000
|
||||
&& pc[-1] == 0x9410001a
|
||||
&& pc[ 0] == 0x80a46008))
|
||||
{
|
||||
/* The CFA is by definition unmodified in this case. */
|
||||
fs->regs.cfa_how = CFA_REG_OFFSET;
|
||||
fs->regs.cfa_reg = __builtin_dwarf_sp_column ();
|
||||
fs->regs.cfa_offset = 0;
|
||||
/* We need to move up one frame:
|
||||
|
||||
/* This is the canonical RA column. */
|
||||
fs->retaddr_column = 15;
|
||||
|
||||
return _URC_NO_REASON;
|
||||
<signal handler> <-- context->cfa
|
||||
sigacthandler
|
||||
<kernel>
|
||||
*/
|
||||
*nframes = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Look for the sigacthandler pattern. The pattern changes slightly
|
||||
in different versions of the operating system, so we skip the
|
||||
comparison against pc-(4*6) for Solaris 9. */
|
||||
if (( *(unsigned int *)(pc-(4*7)) == sigacthandler_sol8_pattern[0]
|
||||
&& *(unsigned int *)(pc-(4*6)) == sigacthandler_sol8_pattern[1]
|
||||
&& *(unsigned int *)(pc-(4*5)) == sigacthandler_sol8_pattern[2]
|
||||
&& *(unsigned int *)(pc-(4*4)) == sigacthandler_sol8_pattern[3]
|
||||
&& *(unsigned int *)(pc-(4*3)) == sigacthandler_sol8_pattern[4]
|
||||
&& *(unsigned int *)(pc-(4*2)) == sigacthandler_sol8_pattern[5]
|
||||
&& *(unsigned int *)(pc-(4*1)) == sigacthandler_sol8_pattern[6]
|
||||
&& *(unsigned int *)(pc-(4*0)) == sigacthandler_sol8_pattern[7] ) ||
|
||||
( *(unsigned int *)(pc-(4*7)) == sigacthandler_sol9_pattern[0]
|
||||
/* skip pc-(4*6) */
|
||||
&& *(unsigned int *)(pc-(4*5)) == sigacthandler_sol9_pattern[2]
|
||||
&& *(unsigned int *)(pc-(4*4)) == sigacthandler_sol9_pattern[3]
|
||||
&& *(unsigned int *)(pc-(4*3)) == sigacthandler_sol9_pattern[4]
|
||||
&& *(unsigned int *)(pc-(4*2)) == sigacthandler_sol9_pattern[5]
|
||||
&& *(unsigned int *)(pc-(4*1)) == sigacthandler_sol9_pattern[6]
|
||||
&& *(unsigned int *)(pc-(4*0)) == sigacthandler_sol9_pattern[7] ) )
|
||||
/* We need to move up two frames (the kernel frame and the handler
|
||||
frame). Minimum stack frame size is 176 bytes (128 + 48): 128
|
||||
bytes for spilling register window (16 extended words for in
|
||||
and local registers), and 6 extended words to store at least
|
||||
6 arguments to callees, The kernel frame and the sigacthandler
|
||||
both have this minimal stack. The ucontext_t structure is after
|
||||
this offset. */
|
||||
regs_off = 176 + 176;
|
||||
|
||||
/* Look for the __sighndlr pattern. */
|
||||
else if ( *(unsigned int *)(pc-(4*5)) == sighndlr_pattern[0]
|
||||
&& *(unsigned int *)(pc-(4*4)) == sighndlr_pattern[1]
|
||||
&& *(unsigned int *)(pc-(4*3)) == sighndlr_pattern[2]
|
||||
&& *(unsigned int *)(pc-(4*2)) == sighndlr_pattern[3]
|
||||
&& *(unsigned int *)(pc-(4*1)) == sighndlr_pattern[4]
|
||||
&& *(unsigned int *)(pc-(4*0)) == sighndlr_pattern[5]
|
||||
&& *(unsigned int *)(pc+(4*1)) == sighndlr_pattern[6] )
|
||||
if (/* Solaris 8+ - multi-threaded
|
||||
----------------------------
|
||||
<__sighndlr>: save %sp, -176, %sp
|
||||
<__sighndlr+4>: mov %i0, %o0
|
||||
<__sighndlr+8>: mov %i1, %o1
|
||||
<__sighndlr+12>: call %i3
|
||||
<__sighndlr+16>: mov %i2, %o2
|
||||
<__sighndlr+20>: ret <--- PC
|
||||
<__sighndlr+24>: restore */
|
||||
pc[-5] == 0x9de3bf50
|
||||
&& pc[-4] == 0x90100018
|
||||
&& pc[-3] == 0x92100019
|
||||
&& pc[-2] == 0x9fc6c000
|
||||
&& pc[-1] == 0x9410001a
|
||||
&& pc[ 0] == 0x81c7e008
|
||||
&& pc[ 1] == 0x81e80000)
|
||||
{
|
||||
/* We have observed different calling frames among different
|
||||
versions of the operating system, so that we need to
|
||||
discriminate using the upper frame. We look for the return
|
||||
address of the caller frame (there is an offset of 15 double
|
||||
words between the frame address and the place where this return
|
||||
address is stored) in order to do some more pattern matching. */
|
||||
unsigned int cuh_pattern
|
||||
= *(unsigned int *)(*(unsigned long *)(this_cfa + 15*8) - 4);
|
||||
if (/* Solaris 8 /usr/lib/sparcv9/libthread.so.1
|
||||
------------------------------------------
|
||||
Before patch 108827-08:
|
||||
<sigacthandler+1760>: st %g4, [ %i1 + 0x1c ]
|
||||
|
||||
if (cuh_pattern == 0xd25fa7ef)
|
||||
Since patch 108827-08:
|
||||
<sigacthandler+1816>: st %l0, [ %i4 + 0x10 ] */
|
||||
savpc[-1] == 0xc826601c
|
||||
|| savpc[-1] == 0xe0272010)
|
||||
{
|
||||
/* This matches the call_user_handler pattern for Solaris 10.
|
||||
There are 2 cases so we look for the return address of the
|
||||
caller's caller frame in order to do more pattern matching. */
|
||||
unsigned int sah_pattern
|
||||
= *(unsigned int *)(*(unsigned long *)(this_cfa + 176 + 15*8) - 4);
|
||||
/* We need to move up three frames:
|
||||
|
||||
if (sah_pattern == 0x92100019)
|
||||
/* This is the same setup as for Solaris 9, see below. */
|
||||
regs_off = 176 + 176 + 176 + 304;
|
||||
else
|
||||
/* We need to move up three frames (the kernel frame, the
|
||||
call_user_handler frame, the __sighndlr frame). Two of them
|
||||
have the minimum stack frame size (kernel and __sighndlr
|
||||
frames) of 176 bytes, and there is another with a stack frame
|
||||
of 304 bytes (the call_user_handler frame). The ucontext_t
|
||||
structure is after this offset. */
|
||||
regs_off = 176 + 176 + 304;
|
||||
<signal handler> <-- context->cfa
|
||||
__sighndlr
|
||||
sigacthandler
|
||||
<kernel>
|
||||
*/
|
||||
*nframes = 2;
|
||||
}
|
||||
else if (cuh_pattern == 0x9410001a || cuh_pattern == 0x94100013)
|
||||
/* This matches the call_user_handler pattern for Solaris 9 and
|
||||
for Solaris 8 running inside Solaris Containers respectively.
|
||||
We need to move up four frames (the kernel frame, the signal
|
||||
frame, the call_user_handler frame, the __sighndlr frame).
|
||||
Three of them have the minimum stack frame size (kernel,
|
||||
signal, and __sighndlr frames) of 176 bytes, and there is
|
||||
another with a stack frame of 304 bytes (the call_user_handler
|
||||
frame). The ucontext_t structure is after this offset. */
|
||||
regs_off = 176 + 176 + 176 + 304;
|
||||
else
|
||||
/* We need to move up three frames (the kernel frame, the
|
||||
sigacthandler frame, and the __sighndlr frame). The kernel
|
||||
frame has a stack frame size of 176, the __sighndlr frames of
|
||||
304 bytes, and there is a stack frame of 176 bytes for the
|
||||
sigacthandler frame. The ucontext_t structure is after this
|
||||
offset. */
|
||||
regs_off = 176 + 304 + 176;
|
||||
}
|
||||
|
||||
/* Exit if the pattern at the return address does not match the
|
||||
previous three patterns. */
|
||||
else
|
||||
return _URC_END_OF_STACK;
|
||||
|
||||
/* FPU information can be extracted from the ucontext_t structure
|
||||
that is the third argument for the signal handler, that is saved
|
||||
in the stack. There are 64 bytes between the beginning of the
|
||||
ucontext_t argument of the signal handler and the uc_mcontext
|
||||
field. There are 176 bytes between the beginning of uc_mcontext
|
||||
and the beginning of the fpregs field. */
|
||||
fpu_save_off = regs_off + (8*10) + 176;
|
||||
|
||||
/* The fpregs field contains 32 extended words at the beginning that
|
||||
contain the FPU state. Then there are 2 extended words and two
|
||||
bytes. */
|
||||
fpu_save = *(unsigned char *)(this_cfa + fpu_save_off + (8*32) + (2*8) + 2);
|
||||
|
||||
/* We need to get the frame pointer for the kernel frame that
|
||||
executes when the signal is raised. This frame is just the
|
||||
following to the application code that generated the signal, so
|
||||
that the later's stack pointer is the former's frame pointer.
|
||||
The stack pointer for the interrupted application code can be
|
||||
calculated from the ucontext_t structure (third argument for the
|
||||
signal handler) that is saved in the stack. There are 10 words
|
||||
between the beginning of the ucontext_t argument of the signal
|
||||
handler and the uc_mcontext.gregs field that contains the
|
||||
registers saved by the signal handler. */
|
||||
new_cfa = *(void **)(this_cfa + regs_off + (8*10) + (REG_SP*8));
|
||||
/* The frame address is %sp + STACK_BIAS in 64-bit mode. */
|
||||
new_cfa += 2047;
|
||||
fs->regs.cfa_how = CFA_REG_OFFSET;
|
||||
fs->regs.cfa_reg = __builtin_dwarf_sp_column ();
|
||||
fs->regs.cfa_offset = new_cfa - this_cfa;
|
||||
|
||||
/* Restore global and out registers (in this order) from the
|
||||
ucontext_t structure, uc_mcontext.gregs field. */
|
||||
for (i = 1; i < 16; i++)
|
||||
{
|
||||
/* We never restore %sp as everything is purely CFA-based. */
|
||||
if ((unsigned int) i == __builtin_dwarf_sp_column ())
|
||||
continue;
|
||||
|
||||
/* First the global registers and then the out registers. */
|
||||
fs->regs.reg[i].how = REG_SAVED_OFFSET;
|
||||
fs->regs.reg[i].loc.offset
|
||||
= this_cfa + regs_off + (8*10) + ((REG_Y+i)*8) - new_cfa;
|
||||
}
|
||||
|
||||
/* Just above the stack pointer there are 16 extended words in which
|
||||
the register window (in and local registers) was saved. */
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
fs->regs.reg[i + 16].how = REG_SAVED_OFFSET;
|
||||
fs->regs.reg[i + 16].loc.offset = i*8;
|
||||
}
|
||||
|
||||
/* Check whether we need to restore FPU registers. */
|
||||
if (fpu_save)
|
||||
{
|
||||
for (i = 0; i < 64; i++)
|
||||
else /* Solaris 8 /usr/lib/lwp/sparcv9/libthread.so.1, Solaris 9+
|
||||
---------------------------------------------------------- */
|
||||
{
|
||||
if (i > 32 && (i & 1))
|
||||
continue;
|
||||
/* We need to move up three frames:
|
||||
|
||||
fs->regs.reg[i + 32].how = REG_SAVED_OFFSET;
|
||||
fs->regs.reg[i + 32].loc.offset
|
||||
= this_cfa + fpu_save_off + (i*4) - new_cfa;
|
||||
<signal handler> <-- context->cfa
|
||||
__sighndlr
|
||||
call_user_handler
|
||||
sigacthandler
|
||||
<kernel>
|
||||
*/
|
||||
*nframes = 3;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* State the rules to find the kernel's code "return address", which is
|
||||
the address of the active instruction when the signal was caught.
|
||||
On the SPARC, since RETURN_ADDR_OFFSET (essentially 8) is defined, we
|
||||
need to preventively subtract it from the purported return address. */
|
||||
ra_location = this_cfa + regs_off + (8*10) + (REG_PC*8);
|
||||
shifted_ra_location = this_cfa + regs_off + (8*10) + (REG_Y*8);
|
||||
*(void **)shifted_ra_location = *(void **)ra_location - 8;
|
||||
fs->retaddr_column = 0;
|
||||
fs->regs.reg[0].how = REG_SAVED_OFFSET;
|
||||
fs->regs.reg[0].loc.offset = shifted_ra_location - new_cfa;
|
||||
fs->signal_frame = 1;
|
||||
|
||||
return _URC_NO_REASON;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MD_FALLBACK_FRAME_STATE_FOR sparc64_fallback_frame_state
|
||||
|
||||
#define MD_FROB_UPDATE_CONTEXT sparc64_frob_update_context
|
||||
|
||||
static void
|
||||
|
@ -258,42 +164,150 @@ sparc64_frob_update_context (struct _Unwind_Context *context,
|
|||
&& fs->regs.cfa_how == CFA_REG_OFFSET
|
||||
&& fs->regs.cfa_offset != 0
|
||||
&& !fs->signal_frame)
|
||||
context->cfa -= 2047;
|
||||
context->cfa -= STACK_BIAS;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define IS_SIGHANDLER sparc_is_sighandler
|
||||
|
||||
static int
|
||||
sparc_is_sighandler (unsigned int *pc, unsigned int * savpc, int *nframes)
|
||||
{
|
||||
if (/* Solaris 8, 9 - single-threaded
|
||||
-------------------------------
|
||||
The pattern changes slightly in different versions of the operating
|
||||
system, so we skip the comparison against pc[-6].
|
||||
|
||||
<sigacthandler+16>: add %o1, %o7, %o3
|
||||
<sigacthandler+20>: mov %i1, %o1
|
||||
|
||||
<sigacthandler+24>: ld [ %o3 + <offset> ], %o2
|
||||
|
||||
<sigacthandler+28>: sll %i0, 2, %o0
|
||||
<sigacthandler+32>: ld [ %o0 + %o2 ], %l0
|
||||
<sigacthandler+36>: mov %i0, %o0
|
||||
<sigacthandler+40>: call %l0
|
||||
<sigacthandler+44>: mov %i2, %o2
|
||||
<sigacthandler+48>: cmp %i0, 8 <--- PC */
|
||||
pc[-8] == 0x9602400f
|
||||
&& pc[-7] == 0x92100019
|
||||
/* skip pc[-6] */
|
||||
&& pc[-5] == 0x912e2002
|
||||
&& pc[-4] == 0xe002000a
|
||||
&& pc[-3] == 0x90100018
|
||||
&& pc[-2] == 0x9fc40000
|
||||
&& pc[-1] == 0x9410001a
|
||||
&& pc[ 0] == 0x80a62008)
|
||||
{
|
||||
/* Need to move up one frame:
|
||||
|
||||
<signal handler> <-- context->cfa
|
||||
sigacthandler
|
||||
<kernel>
|
||||
*/
|
||||
*nframes = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (/* Solaris 8 - multi-threaded
|
||||
---------------------------
|
||||
<__libthread_segvhdlr+212>: clr %o2
|
||||
<__libthread_segvhdlr+216>: ld [ %fp + -28 ], %l0
|
||||
<__libthread_segvhdlr+220>: mov %i4, %o0
|
||||
<__libthread_segvhdlr+224>: mov %i1, %o1
|
||||
<__libthread_segvhdlr+228>: call %l0
|
||||
<__libthread_segvhdlr+232>: mov %i2, %o2
|
||||
<__libthread_segvhdlr+236>: ret <--- PC
|
||||
<__libthread_segvhdlr+240>: restore
|
||||
<__libthread_segvhdlr+244>: cmp %o1, 0 */
|
||||
pc[-6] == 0x94102000
|
||||
&& pc[-5] == 0xe007bfe4
|
||||
&& pc[-4] == 0x9010001c
|
||||
&& pc[-3] == 0x92100019
|
||||
&& pc[-2] == 0x9fc40000
|
||||
&& pc[-1] == 0x9410001a
|
||||
&& pc[ 0] == 0x81c7e008
|
||||
&& pc[ 1] == 0x81e80000
|
||||
&& pc[ 2] == 0x80a26000)
|
||||
{
|
||||
/* Need to move up one frame:
|
||||
|
||||
<signal handler> <-- context->cfa
|
||||
__libthread_segvhdlr
|
||||
<kernel>
|
||||
*/
|
||||
*nframes = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(/* Solaris 8+ - multi-threaded
|
||||
----------------------------
|
||||
<__sighndlr>: save %sp, -96, %sp
|
||||
<__sighndlr+4>: mov %i0, %o0
|
||||
<__sighndlr+8>: mov %i1, %o1
|
||||
<__sighndlr+12>: call %i3
|
||||
<__sighndlr+16>: mov %i2, %o2
|
||||
<__sighndlr+20>: ret <--- PC
|
||||
<__sighndlr+24>: restore */
|
||||
pc[-5] == 0x9de3bfa0
|
||||
&& pc[-4] == 0x90100018
|
||||
&& pc[-3] == 0x92100019
|
||||
&& pc[-2] == 0x9fc6c000
|
||||
&& pc[-1] == 0x9410001a
|
||||
&& pc[ 0] == 0x81c7e008
|
||||
&& pc[ 1] == 0x81e80000)
|
||||
{
|
||||
if (/* Solaris 8 /usr/lib/libthread.so.1
|
||||
----------------------------------
|
||||
<sigacthandler+1796>: mov %i0, %o0 */
|
||||
savpc[-1] == 0x90100018)
|
||||
{
|
||||
/* We need to move up two frames:
|
||||
|
||||
<signal handler> <-- context->cfa
|
||||
__sighndlr
|
||||
sigacthandler
|
||||
<kernel>
|
||||
*/
|
||||
*nframes = 2;
|
||||
}
|
||||
else /* Solaris 8 /usr/lib/lwp/libthread.so.1, Solaris 9+
|
||||
-------------------------------------------------- */
|
||||
{
|
||||
/* We need to move up three frames:
|
||||
|
||||
<signal handler> <-- context->cfa
|
||||
__sighndlr
|
||||
call_user_handler
|
||||
sigacthandler
|
||||
<kernel>
|
||||
*/
|
||||
*nframes = 3;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MD_FALLBACK_FRAME_STATE_FOR sparc_fallback_frame_state
|
||||
|
||||
#endif
|
||||
|
||||
static _Unwind_Reason_Code
|
||||
sparc_fallback_frame_state (struct _Unwind_Context *context,
|
||||
_Unwind_FrameState *fs)
|
||||
MD_FALLBACK_FRAME_STATE_FOR (struct _Unwind_Context *context,
|
||||
_Unwind_FrameState *fs)
|
||||
{
|
||||
void *pc = context->ra;
|
||||
struct frame *fp = (struct frame *) context->cfa;
|
||||
int nframes;
|
||||
void *this_cfa = context->cfa;
|
||||
void *new_cfa, *ra_location, *shifted_ra_location;
|
||||
int regs_off;
|
||||
int fpu_save_off;
|
||||
unsigned char fpu_save;
|
||||
long new_cfa;
|
||||
void *ra_location, *shifted_ra_location;
|
||||
mcontext_t *mctx;
|
||||
int i;
|
||||
|
||||
/* This is the observed pattern for the sigacthandler. */
|
||||
unsigned int sigacthandler_pattern []
|
||||
= {0x9602400f, 0x92100019, 0x00000000, 0x912e2002,
|
||||
0xe002000a, 0x90100018, 0x9fc40000, 0x9410001a,
|
||||
0x80a62008};
|
||||
|
||||
/* This is the observed pattern for the __libthread_segvhdlr. */
|
||||
unsigned int segvhdlr_pattern []
|
||||
= {0x94102000, 0xe007bfe4, 0x9010001c, 0x92100019,
|
||||
0x9fc40000, 0x9410001a, 0x81c7e008, 0x81e80000,
|
||||
0x80a26000};
|
||||
|
||||
/* This is the observed pattern for the __sighndlr. */
|
||||
unsigned int sighndlr_pattern []
|
||||
= {0x9de3bfa0, 0x90100018, 0x92100019, 0x9fc6c000,
|
||||
0x9410001a, 0x81c7e008, 0x81e80000};
|
||||
|
||||
/* Deal with frame-less function from which a signal was raised. */
|
||||
if (_Unwind_IsSignalFrame (context))
|
||||
{
|
||||
|
@ -308,102 +322,27 @@ sparc_fallback_frame_state (struct _Unwind_Context *context,
|
|||
return _URC_NO_REASON;
|
||||
}
|
||||
|
||||
/* Look for the sigacthandler pattern. The pattern changes slightly
|
||||
in different versions of the operating system, so we skip the
|
||||
comparison against pc-(4*6). */
|
||||
if ( *(unsigned int *)(pc-(4*8)) == sigacthandler_pattern[0]
|
||||
&& *(unsigned int *)(pc-(4*7)) == sigacthandler_pattern[1]
|
||||
/* skip pc-(4*6) */
|
||||
&& *(unsigned int *)(pc-(4*5)) == sigacthandler_pattern[3]
|
||||
&& *(unsigned int *)(pc-(4*4)) == sigacthandler_pattern[4]
|
||||
&& *(unsigned int *)(pc-(4*3)) == sigacthandler_pattern[5]
|
||||
&& *(unsigned int *)(pc-(4*2)) == sigacthandler_pattern[6]
|
||||
&& *(unsigned int *)(pc-(4*1)) == sigacthandler_pattern[7]
|
||||
&& *(unsigned int *)(pc-(4*0)) == sigacthandler_pattern[8] )
|
||||
/* We need to move up two frames (the kernel frame and the handler
|
||||
frame). Minimum stack frame size is 96 bytes (64 + 4 + 24): 64
|
||||
bytes for spilling register window (16 words for in and local
|
||||
registers), 4 bytes for a pointer to space for callees
|
||||
returning structs, and 24 bytes to store at least six argument
|
||||
to callees. The ucontext_t structure is after this offset. */
|
||||
regs_off = 96 + 96;
|
||||
|
||||
/* Look for the __libthread_segvhdlr pattern. */
|
||||
else if ( *(unsigned int *)(pc-(4*6)) == segvhdlr_pattern[0]
|
||||
&& *(unsigned int *)(pc-(4*5)) == segvhdlr_pattern[1]
|
||||
&& *(unsigned int *)(pc-(4*4)) == segvhdlr_pattern[2]
|
||||
&& *(unsigned int *)(pc-(4*3)) == segvhdlr_pattern[3]
|
||||
&& *(unsigned int *)(pc-(4*2)) == segvhdlr_pattern[4]
|
||||
&& *(unsigned int *)(pc-(4*1)) == segvhdlr_pattern[5]
|
||||
&& *(unsigned int *)(pc-(4*0)) == segvhdlr_pattern[6]
|
||||
&& *(unsigned int *)(pc+(4*1)) == segvhdlr_pattern[7]
|
||||
&& *(unsigned int *)(pc+(4*2)) == segvhdlr_pattern[8] )
|
||||
/* We need to move up four frames (the kernel frame, the
|
||||
sigacthandler frame, the __sighndlr frame, and the
|
||||
__libthread_segvhdlr). Two of them have the minimum
|
||||
stack frame size (kernel and __sighndlr frames) of 96 bytes,
|
||||
other has a stack frame of 216 bytes (the sigacthandler frame),
|
||||
and there is another with a stack frame of 128 bytes (the
|
||||
__libthread_segvhdlr). The ucontext_t structure is after this
|
||||
offset. */
|
||||
regs_off = 96 + 96 + 128 + 216;
|
||||
|
||||
/* Look for the __sighndlr pattern. */
|
||||
else if ( *(unsigned int *)(pc-(4*5)) == sighndlr_pattern[0]
|
||||
&& *(unsigned int *)(pc-(4*4)) == sighndlr_pattern[1]
|
||||
&& *(unsigned int *)(pc-(4*3)) == sighndlr_pattern[2]
|
||||
&& *(unsigned int *)(pc-(4*2)) == sighndlr_pattern[3]
|
||||
&& *(unsigned int *)(pc-(4*1)) == sighndlr_pattern[4]
|
||||
&& *(unsigned int *)(pc-(4*0)) == sighndlr_pattern[5]
|
||||
&& *(unsigned int *)(pc+(4*1)) == sighndlr_pattern[6] )
|
||||
if (IS_SIGHANDLER (pc, (unsigned int *)fp->fr_savpc, &nframes))
|
||||
{
|
||||
/* We have observed different calling frames among different
|
||||
versions of the operating system, so that we need to
|
||||
discriminate using the upper frame. We look for the return
|
||||
address of the caller frame (there is an offset of 15 words
|
||||
between the frame address and the place where this return
|
||||
address is stored) in order to do some more pattern matching. */
|
||||
unsigned int cuh_pattern
|
||||
= *(unsigned int *)(*(unsigned int *)(this_cfa + 15*4) - 4);
|
||||
struct handler_args {
|
||||
struct frame frwin;
|
||||
ucontext_t ucontext;
|
||||
} *handler_args;
|
||||
ucontext_t *ucp;
|
||||
|
||||
if (cuh_pattern == 0xd407a04c)
|
||||
{
|
||||
/* This matches the call_user_handler pattern for Solaris 10.
|
||||
There are 2 cases so we look for the return address of the
|
||||
caller's caller frame in order to do more pattern matching. */
|
||||
unsigned int sah_pattern
|
||||
= *(unsigned int *)(*(unsigned int *)(this_cfa + 96 + 15*4) - 4);
|
||||
/* context->cfa points into the frame after the saved frame pointer and
|
||||
saved pc (struct frame).
|
||||
|
||||
if (sah_pattern == 0x92100019)
|
||||
/* This is the same setup as for Solaris 9, see below. */
|
||||
regs_off = 96 + 96 + 96 + 160;
|
||||
else
|
||||
/* We need to move up three frames (the kernel frame, the
|
||||
call_user_handler frame, the __sighndlr frame). Two of them
|
||||
have the minimum stack frame size (kernel and __sighndlr
|
||||
frames) of 96 bytes, and there is another with a stack frame
|
||||
of 160 bytes (the call_user_handler frame). The ucontext_t
|
||||
structure is after this offset. */
|
||||
regs_off = 96 + 96 + 160;
|
||||
}
|
||||
else if (cuh_pattern == 0x9410001a || cuh_pattern == 0x9410001b)
|
||||
/* This matches the call_user_handler pattern for Solaris 9 and
|
||||
for Solaris 8 running inside Solaris Containers respectively.
|
||||
We need to move up four frames (the kernel frame, the signal
|
||||
frame, the call_user_handler frame, the __sighndlr frame).
|
||||
Three of them have the minimum stack frame size (kernel,
|
||||
signal, and __sighndlr frames) of 96 bytes, and there is
|
||||
another with a stack frame of 160 bytes (the call_user_handler
|
||||
frame). The ucontext_t structure is after this offset. */
|
||||
regs_off = 96 + 96 + 96 + 160;
|
||||
else
|
||||
/* We need to move up three frames (the kernel frame, the
|
||||
sigacthandler frame, and the __sighndlr frame). Two of them
|
||||
have the minimum stack frame size (kernel and __sighndlr
|
||||
frames) of 96 bytes, and there is another with a stack frame
|
||||
of 216 bytes (the sigacthandler frame). The ucontext_t
|
||||
structure is after this offset. */
|
||||
regs_off = 96 + 96 + 216;
|
||||
The ucontext_t structure is in the kernel frame after a struct
|
||||
frame. Since the frame sizes vary even within OS releases, we
|
||||
need to walk the stack to get there. */
|
||||
|
||||
for (i = 0; i < nframes; i++)
|
||||
fp = (struct frame *) ((char *)fp->fr_savfp + STACK_BIAS);
|
||||
|
||||
handler_args = (struct handler_args *) fp;
|
||||
ucp = &handler_args->ucontext;
|
||||
mctx = &ucp->uc_mcontext;
|
||||
}
|
||||
|
||||
/* Exit if the pattern at the return address does not match the
|
||||
|
@ -411,32 +350,13 @@ sparc_fallback_frame_state (struct _Unwind_Context *context,
|
|||
else
|
||||
return _URC_END_OF_STACK;
|
||||
|
||||
/* FPU information can be extracted from the ucontext_t structure
|
||||
that is the third argument for the signal handler, that is saved
|
||||
in the stack. There are 10 words between the beginning of the
|
||||
ucontext_t argument of the signal handler and the uc_mcontext
|
||||
field. There are 80 bytes between the beginning of uc_mcontext
|
||||
and the beginning of the fpregs field. */
|
||||
fpu_save_off = regs_off + (4*10) + (4*20);
|
||||
new_cfa = mctx->gregs[REG_SP];
|
||||
/* The frame address is %sp + STACK_BIAS in 64-bit mode. */
|
||||
new_cfa += STACK_BIAS;
|
||||
|
||||
/* The fpregs field contains 32 words at the beginning that contain
|
||||
the FPU state. Then there are 2 words and two bytes. */
|
||||
fpu_save = *(unsigned char *)(this_cfa + fpu_save_off + (4*32) + (2*4) + 2);
|
||||
|
||||
/* We need to get the frame pointer for the kernel frame that
|
||||
executes when the signal is raised. This frame is just the
|
||||
following to the application code that generated the signal, so
|
||||
that the later's stack pointer is the former's frame pointer.
|
||||
The stack pointer for the interrupted application code can be
|
||||
calculated from the ucontext_t structure (third argument for the
|
||||
signal handler) that is saved in the stack. There are 10 words
|
||||
between the beginning of the ucontext_t argument of the signal
|
||||
handler and the uc_mcontext.gregs field that contains the
|
||||
registers saved by the signal handler. */
|
||||
new_cfa = *(void **)(this_cfa + regs_off + (4*10) + (REG_SP*4));
|
||||
fs->regs.cfa_how = CFA_REG_OFFSET;
|
||||
fs->regs.cfa_reg = __builtin_dwarf_sp_column ();
|
||||
fs->regs.cfa_offset = new_cfa - this_cfa;
|
||||
fs->regs.cfa_offset = new_cfa - (long) this_cfa;
|
||||
|
||||
/* Restore global and out registers (in this order) from the
|
||||
ucontext_t structure, uc_mcontext.gregs field. */
|
||||
|
@ -446,44 +366,54 @@ sparc_fallback_frame_state (struct _Unwind_Context *context,
|
|||
if ((unsigned int) i == __builtin_dwarf_sp_column ())
|
||||
continue;
|
||||
|
||||
/* First the global registers and then the out registers */
|
||||
/* First the global registers and then the out registers. */
|
||||
fs->regs.reg[i].how = REG_SAVED_OFFSET;
|
||||
fs->regs.reg[i].loc.offset
|
||||
= this_cfa + regs_off + (4*10) + ((REG_Y+i)*4) - new_cfa;
|
||||
fs->regs.reg[i].loc.offset = (long)&mctx->gregs[REG_Y + i] - new_cfa;
|
||||
}
|
||||
|
||||
/* Just above the stack pointer there are 16 words in which the
|
||||
register window (in and local registers) was saved. */
|
||||
/* Just above the stack pointer there are 16 extended words in which
|
||||
the register window (in and local registers) was saved. */
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
fs->regs.reg[i + 16].how = REG_SAVED_OFFSET;
|
||||
fs->regs.reg[i + 16].loc.offset = i*4;
|
||||
fs->regs.reg[i + 16].loc.offset = i*sizeof(long);
|
||||
}
|
||||
|
||||
/* Check whether we need to restore FPU registers. */
|
||||
if (fpu_save)
|
||||
if (mctx->fpregs.fpu_qcnt)
|
||||
{
|
||||
for (i = 0; i < 32; i++)
|
||||
{
|
||||
fs->regs.reg[i + 32].how = REG_SAVED_OFFSET;
|
||||
fs->regs.reg[i + 32].loc.offset
|
||||
= this_cfa + fpu_save_off + (i*4) - new_cfa;
|
||||
= (long)&mctx->fpregs.fpu_fr.fpu_regs[i] - new_cfa;
|
||||
}
|
||||
|
||||
#ifdef __arch64__
|
||||
/* For 64-bit, fpu_fr.fpu_dregs contains 32 instead of 16 doubles. */
|
||||
for (i = 32; i < 64; i++)
|
||||
{
|
||||
if (i > 32 && (i & 1))
|
||||
continue;
|
||||
|
||||
fs->regs.reg[i + 32].how = REG_SAVED_OFFSET;
|
||||
fs->regs.reg[i + 32].loc.offset
|
||||
= (long)&mctx->fpregs.fpu_fr.fpu_dregs[i/2] - new_cfa;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* State the rules to find the kernel's code "return address", which is
|
||||
the address of the active instruction when the signal was caught.
|
||||
On the SPARC, since RETURN_ADDR_OFFSET (essentially 8) is defined, we
|
||||
need to preventively subtract it from the purported return address. */
|
||||
ra_location = this_cfa + regs_off + (4*10) + (REG_PC*4);
|
||||
shifted_ra_location = this_cfa + regs_off + (4*10) + (REG_Y*4);
|
||||
ra_location = &mctx->gregs[REG_PC];
|
||||
shifted_ra_location = &mctx->gregs[REG_Y];
|
||||
*(void **)shifted_ra_location = *(void **)ra_location - 8;
|
||||
fs->retaddr_column = 0;
|
||||
fs->regs.reg[0].how = REG_SAVED_OFFSET;
|
||||
fs->regs.reg[0].loc.offset = shifted_ra_location - new_cfa;
|
||||
fs->regs.reg[0].loc.offset = (long)shifted_ra_location - new_cfa;
|
||||
fs->signal_frame = 1;
|
||||
|
||||
return _URC_NO_REASON;
|
||||
};
|
||||
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
2011-02-14 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
|
||||
|
||||
PR ada/41929
|
||||
* gnat.dg/null_pointer_deref1.exp: Don't skip on
|
||||
sparc*-sun-solaris2.11.
|
||||
|
||||
2011-02-14 Janus Weil <janus@gcc.gnu.org>
|
||||
|
||||
PR fortran/47349
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
-- { dg-do run { target { ! "sparc*-sun-solaris2.11" } } }
|
||||
-- { dg-do run }
|
||||
-- { dg-options "-gnatp" }
|
||||
|
||||
-- This test requires architecture- and OS-specific support code for unwinding
|
||||
|
|
Loading…
Add table
Reference in a new issue