From ad56a54c68329d8e0c3980e15ceb907eb13f8c4b Mon Sep 17 00:00:00 2001 From: Rainer Orth Date: Mon, 14 Feb 2011 12:32:11 +0000 Subject: [PATCH] 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 , (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 --- gcc/ChangeLog | 18 + gcc/config/sparc/sol2-unwind.h | 626 ++++++++---------- gcc/testsuite/ChangeLog | 6 + gcc/testsuite/gnat.dg/null_pointer_deref1.adb | 2 +- 4 files changed, 303 insertions(+), 349 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6c3f6d43c8b..aa604ee4ab2 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,21 @@ +2011-02-14 Rainer Orth + + PR ada/41929 + * config/sparc/sol2-unwind.h: Include , + (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 * go/gccgo.texi (Top, Import and Export): Fix a typo and a diff --git a/gcc/config/sparc/sol2-unwind.h b/gcc/config/sparc/sol2-unwind.h index aa1358dfae5..f8b99027247 100644 --- a/gcc/config/sparc/sol2-unwind.h +++ b/gcc/config/sparc/sol2-unwind.h @@ -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 +#include +#include #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 + ---------------------------- + : add %g5, %o7, %o2 + : ldx [ %o2 + 0xfa0 ], %g5 + : sra %i0, 0, %o0 + : sllx %o0, 3, %g4 + : ldx [ %g4 + %g5 ], %l0 + : call %l0 + : mov %i2, %o2 + : 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}; + : 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: + : ldx [ %o2 + 0xf68 ], %g5 + Solaris 9 9/05: + : ldx [ %o2 + 0xe50 ], %g5 - /* Deal with frame-less function from which a signal was raised. */ - if (_Unwind_IsSignalFrame (context)) + : sllx %l1, 3, %g4 + : mov %l1, %o0 + : ldx [ %g4 + %g5 ], %l0 + : call %l0 + : mov %i2, %o2 + : 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; + <-- context->cfa + sigacthandler + + */ + *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: + : st %g4, [ %i1 + 0x1c ] - if (cuh_pattern == 0xd25fa7ef) + Since patch 108827-08: + : 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; + <-- context->cfa + __sighndlr + sigacthandler + + */ + *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; + <-- context->cfa + __sighndlr + call_user_handler + sigacthandler + + */ + *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]. + + : add %o1, %o7, %o3 + : mov %i1, %o1 + + : ld [ %o3 + ], %o2 + + : sll %i0, 2, %o0 + : ld [ %o0 + %o2 ], %l0 + : mov %i0, %o0 + : call %l0 + : mov %i2, %o2 + : 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: + + <-- context->cfa + sigacthandler + + */ + *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: + + <-- context->cfa + __libthread_segvhdlr + + */ + *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 + ---------------------------------- + : mov %i0, %o0 */ + savpc[-1] == 0x90100018) + { + /* We need to move up two frames: + + <-- context->cfa + __sighndlr + sigacthandler + + */ + *nframes = 2; + } + else /* Solaris 8 /usr/lib/lwp/libthread.so.1, Solaris 9+ + -------------------------------------------------- */ + { + /* We need to move up three frames: + + <-- context->cfa + __sighndlr + call_user_handler + sigacthandler + + */ + *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 +} diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 1952af98e58..63318f13071 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2011-02-14 Rainer Orth + + PR ada/41929 + * gnat.dg/null_pointer_deref1.exp: Don't skip on + sparc*-sun-solaris2.11. + 2011-02-14 Janus Weil PR fortran/47349 diff --git a/gcc/testsuite/gnat.dg/null_pointer_deref1.adb b/gcc/testsuite/gnat.dg/null_pointer_deref1.adb index f845064685f..6e7bf14e5df 100644 --- a/gcc/testsuite/gnat.dg/null_pointer_deref1.adb +++ b/gcc/testsuite/gnat.dg/null_pointer_deref1.adb @@ -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