00001 /* DWARF2 EH unwinding support for PA Linux. 00002 Copyright (C) 2004, 2005 Free Software Foundation, Inc. 00003 00004 This file is part of GCC. 00005 00006 GCC is free software; you can redistribute it and/or modify 00007 it under the terms of the GNU General Public License as published by 00008 the Free Software Foundation; either version 2, or (at your option) 00009 any later version. 00010 00011 In addition to the permissions in the GNU General Public License, the 00012 Free Software Foundation gives you unlimited permission to link the 00013 compiled version of this file with other programs, and to distribute 00014 those programs without any restriction coming from the use of this 00015 file. (The General Public License restrictions do apply in other 00016 respects; for example, they cover modification of the file, and 00017 distribution when not linked into another program.) 00018 00019 GCC is distributed in the hope that it will be useful, 00020 but WITHOUT ANY WARRANTY; without even the implied warranty of 00021 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00022 GNU General Public License for more details. 00023 00024 You should have received a copy of the GNU General Public License 00025 along with GCC; see the file COPYING. If not, write to 00026 the Free Software Foundation, 59 Temple Place - Suite 330, 00027 Boston, MA 02111-1307, USA. */ 00028 00029 /* Do code reading to identify a signal frame, and set the frame 00030 state data appropriately. See unwind-dw2.c for the structs. */ 00031 00032 #include <signal.h> 00033 #include <sys/ucontext.h> 00034 00035 /* Unfortunately, because of various bugs and changes to the kernel, 00036 we have several cases to deal with. 00037 00038 In 2.4, the signal trampoline is 4 words, and (CONTEXT)->ra should 00039 point directly at the beginning of the trampoline and struct rt_sigframe. 00040 00041 In <= 2.6.5-rc2-pa3, the signal trampoline is 9 words, and 00042 (CONTEXT)->ra points at the 4th word in the trampoline structure. This 00043 is wrong, it should point at the 5th word. This is fixed in 2.6.5-rc2-pa4. 00044 00045 To detect these cases, we first take (CONTEXT)->ra, align it to 64-bytes 00046 to get the beginning of the signal frame, and then check offsets 0, 4 00047 and 5 to see if we found the beginning of the trampoline. This will 00048 tell us how to locate the sigcontext structure. 00049 00050 Note that with a 2.4 64-bit kernel, the signal context is not properly 00051 passed back to userspace so the unwind will not work correctly. */ 00052 00053 #define MD_FALLBACK_FRAME_STATE_FOR pa32_fallback_frame_state 00054 00055 static _Unwind_Reason_Code 00056 pa32_fallback_frame_state (struct _Unwind_Context *context, 00057 _Unwind_FrameState *fs) 00058 { 00059 unsigned long sp = (unsigned long)context->ra & ~63; 00060 unsigned int *pc = (unsigned int *)sp; 00061 unsigned long off; 00062 _Unwind_Ptr new_cfa; 00063 int i; 00064 struct sigcontext *sc; 00065 struct rt_sigframe { 00066 struct siginfo info; 00067 struct ucontext uc; 00068 } *frame; 00069 00070 /* rt_sigreturn trampoline: 00071 3419000x ldi 0, %r25 or ldi 1, %r25 (x = 0 or 2) 00072 3414015a ldi __NR_rt_sigreturn, %r20 00073 e4008200 be,l 0x100(%sr2, %r0), %sr0, %r31 00074 08000240 nop */ 00075 00076 if (pc[0] == 0x34190000 || pc[0] == 0x34190002) 00077 off = 4*4; 00078 else if (pc[4] == 0x34190000 || pc[4] == 0x34190002) 00079 { 00080 pc += 4; 00081 off = 10 * 4; 00082 } 00083 else if (pc[5] == 0x34190000 || pc[5] == 0x34190002) 00084 { 00085 pc += 5; 00086 off = 10 * 4; 00087 } 00088 else 00089 { 00090 /* We may have to unwind through an alternate signal stack. 00091 We assume that the alignment of the alternate signal stack 00092 is BIGGEST_ALIGNMENT (i.e., that it has been allocated using 00093 malloc). As a result, we can't distinguish trampolines 00094 used prior to 2.6.5-rc2-pa4. However after 2.6.5-rc2-pa4, 00095 the return address of a signal trampoline will be on an odd 00096 word boundary and we can then determine the frame offset. */ 00097 sp = (unsigned long)context->ra; 00098 pc = (unsigned int *)sp; 00099 if ((pc[0] == 0x34190000 || pc[0] == 0x34190002) && (sp & 4)) 00100 off = 5 * 4; 00101 else 00102 return _URC_END_OF_STACK; 00103 } 00104 00105 if (pc[1] != 0x3414015a 00106 || pc[2] != 0xe4008200 00107 || pc[3] != 0x08000240) 00108 return _URC_END_OF_STACK; 00109 00110 frame = (struct rt_sigframe *)(sp + off); 00111 sc = &frame->uc.uc_mcontext; 00112 00113 new_cfa = sc->sc_gr[30]; 00114 fs->cfa_how = CFA_REG_OFFSET; 00115 fs->cfa_reg = 30; 00116 fs->cfa_offset = new_cfa - (long) context->cfa; 00117 for (i = 1; i <= 31; i++) 00118 { 00119 fs->regs.reg[i].how = REG_SAVED_OFFSET; 00120 fs->regs.reg[i].loc.offset = (long)&sc->sc_gr[i] - new_cfa; 00121 } 00122 for (i = 4; i <= 31; i++) 00123 { 00124 /* FP regs have left and right halves */ 00125 fs->regs.reg[2*i+24].how = REG_SAVED_OFFSET; 00126 fs->regs.reg[2*i+24].loc.offset 00127 = (long)&sc->sc_fr[i] - new_cfa; 00128 fs->regs.reg[2*i+24+1].how = REG_SAVED_OFFSET; 00129 fs->regs.reg[2*i+24+1].loc.offset 00130 = (long)&sc->sc_fr[i] + 4 - new_cfa; 00131 } 00132 fs->regs.reg[88].how = REG_SAVED_OFFSET; 00133 fs->regs.reg[88].loc.offset = (long) &sc->sc_sar - new_cfa; 00134 fs->regs.reg[0].how = REG_SAVED_OFFSET; 00135 fs->regs.reg[0].loc.offset = (long) &sc->sc_iaoq[0] - new_cfa; 00136 fs->retaddr_column = 0; 00137 return _URC_NO_REASON; 00138 }
1.5.6