Mercurial > hg > CbC > CbC_gcc
comparison gcc/config/sparc/sol2-unwind.h @ 67:f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
author | nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Tue, 22 Mar 2011 17:18:12 +0900 |
parents | 77e2b8dfacca |
children |
comparison
equal
deleted
inserted
replaced
65:65488c3d617d | 67:f6334be47118 |
---|---|
1 /* DWARF2 EH unwinding support for SPARC Solaris. | 1 /* DWARF2 EH unwinding support for SPARC Solaris. |
2 Copyright (C) 2009 Free Software Foundation, Inc. | 2 Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc. |
3 | 3 |
4 This file is part of GCC. | 4 This file is part of GCC. |
5 | 5 |
6 GCC is free software; you can redistribute it and/or modify | 6 GCC is free software; you can redistribute it and/or modify |
7 it under the terms of the GNU General Public License as published by | 7 it under the terms of the GNU General Public License as published by |
24 | 24 |
25 /* Do code reading to identify a signal frame, and set the frame | 25 /* Do code reading to identify a signal frame, and set the frame |
26 state data appropriately. See unwind-dw2.c for the structs. */ | 26 state data appropriately. See unwind-dw2.c for the structs. */ |
27 | 27 |
28 #include <ucontext.h> | 28 #include <ucontext.h> |
29 #include <sys/frame.h> | |
30 #include <sys/stack.h> | |
29 | 31 |
30 #if defined(__arch64__) | 32 #if defined(__arch64__) |
31 | 33 |
34 #define IS_SIGHANDLER sparc64_is_sighandler | |
35 | |
36 static int | |
37 sparc64_is_sighandler (unsigned int *pc, unsigned int *savpc, int *nframes) | |
38 { | |
39 if (/* Solaris 8 - single-threaded | |
40 ---------------------------- | |
41 <sigacthandler+24>: add %g5, %o7, %o2 | |
42 <sigacthandler+28>: ldx [ %o2 + 0xfa0 ], %g5 | |
43 <sigacthandler+32>: sra %i0, 0, %o0 | |
44 <sigacthandler+36>: sllx %o0, 3, %g4 | |
45 <sigacthandler+40>: ldx [ %g4 + %g5 ], %l0 | |
46 <sigacthandler+44>: call %l0 | |
47 <sigacthandler+48>: mov %i2, %o2 | |
48 <sigacthandler+52>: cmp %i3, 8 <--- PC */ | |
49 ( pc[-7] == 0x9401400f | |
50 && pc[-6] == 0xca5aafa0 | |
51 && pc[-5] == 0x913e2000 | |
52 && pc[-4] == 0x892a3003 | |
53 && pc[-3] == 0xe0590005 | |
54 && pc[-2] == 0x9fc40000 | |
55 && pc[-1] == 0x9410001a | |
56 && pc[ 0] == 0x80a6e008) | |
57 | |
58 || /* Solaris 9 - single-threaded | |
59 ---------------------------- | |
60 The pattern changes slightly in different versions of the | |
61 operating system, so we skip the comparison against pc[-6] for | |
62 Solaris 9. | |
63 | |
64 <sigacthandler+24>: sra %i0, 0, %l1 | |
65 | |
66 Solaris 9 5/02: | |
67 <sigacthandler+28>: ldx [ %o2 + 0xf68 ], %g5 | |
68 Solaris 9 9/05: | |
69 <sigacthandler+28>: ldx [ %o2 + 0xe50 ], %g5 | |
70 | |
71 <sigacthandler+32>: sllx %l1, 3, %g4 | |
72 <sigacthandler+36>: mov %l1, %o0 | |
73 <sigacthandler+40>: ldx [ %g4 + %g5 ], %l0 | |
74 <sigacthandler+44>: call %l0 | |
75 <sigacthandler+48>: mov %i2, %o2 | |
76 <sigacthandler+52>: cmp %l1, 8 <--- PC */ | |
77 ( pc[-7] == 0xa33e2000 | |
78 /* skip pc[-6] */ | |
79 && pc[-5] == 0x892c7003 | |
80 && pc[-4] == 0x90100011 | |
81 && pc[-3] == 0xe0590005 | |
82 && pc[-2] == 0x9fc40000 | |
83 && pc[-1] == 0x9410001a | |
84 && pc[ 0] == 0x80a46008)) | |
85 { | |
86 /* We need to move up one frame: | |
87 | |
88 <signal handler> <-- context->cfa | |
89 sigacthandler | |
90 <kernel> | |
91 */ | |
92 *nframes = 1; | |
93 return 1; | |
94 } | |
95 | |
96 if (/* Solaris 8+ - multi-threaded | |
97 ---------------------------- | |
98 <__sighndlr>: save %sp, -176, %sp | |
99 <__sighndlr+4>: mov %i0, %o0 | |
100 <__sighndlr+8>: mov %i1, %o1 | |
101 <__sighndlr+12>: call %i3 | |
102 <__sighndlr+16>: mov %i2, %o2 | |
103 <__sighndlr+20>: ret <--- PC | |
104 <__sighndlr+24>: restore */ | |
105 pc[-5] == 0x9de3bf50 | |
106 && pc[-4] == 0x90100018 | |
107 && pc[-3] == 0x92100019 | |
108 && pc[-2] == 0x9fc6c000 | |
109 && pc[-1] == 0x9410001a | |
110 && pc[ 0] == 0x81c7e008 | |
111 && pc[ 1] == 0x81e80000) | |
112 { | |
113 if (/* Solaris 8 /usr/lib/sparcv9/libthread.so.1 | |
114 ------------------------------------------ | |
115 Before patch 108827-08: | |
116 <sigacthandler+1760>: st %g4, [ %i1 + 0x1c ] | |
117 | |
118 Since patch 108827-08: | |
119 <sigacthandler+1816>: st %l0, [ %i4 + 0x10 ] */ | |
120 savpc[-1] == 0xc826601c | |
121 || savpc[-1] == 0xe0272010) | |
122 { | |
123 /* We need to move up three frames: | |
124 | |
125 <signal handler> <-- context->cfa | |
126 __sighndlr | |
127 sigacthandler | |
128 <kernel> | |
129 */ | |
130 *nframes = 2; | |
131 } | |
132 else /* Solaris 8 /usr/lib/lwp/sparcv9/libthread.so.1, Solaris 9+ | |
133 ---------------------------------------------------------- */ | |
134 { | |
135 /* We need to move up three frames: | |
136 | |
137 <signal handler> <-- context->cfa | |
138 __sighndlr | |
139 call_user_handler | |
140 sigacthandler | |
141 <kernel> | |
142 */ | |
143 *nframes = 3; | |
144 } | |
145 return 1; | |
146 } | |
147 | |
148 return 0; | |
149 } | |
150 | |
32 #define MD_FALLBACK_FRAME_STATE_FOR sparc64_fallback_frame_state | 151 #define MD_FALLBACK_FRAME_STATE_FOR sparc64_fallback_frame_state |
33 | |
34 static _Unwind_Reason_Code | |
35 sparc64_fallback_frame_state (struct _Unwind_Context *context, | |
36 _Unwind_FrameState *fs) | |
37 { | |
38 void *pc = context->ra; | |
39 void *this_cfa = context->cfa; | |
40 void *new_cfa, *ra_location, *shifted_ra_location; | |
41 int regs_off; | |
42 int fpu_save_off; | |
43 unsigned char fpu_save; | |
44 int i; | |
45 | |
46 /* This is the observed pattern for the sigacthandler in Solaris 8. */ | |
47 unsigned int sigacthandler_sol8_pattern [] | |
48 = {0x9401400f, 0xca5aafa0, 0x913e2000, 0x892a3003, | |
49 0xe0590005, 0x9fc40000, 0x9410001a, 0x80a6e008}; | |
50 | |
51 /* This is the observed pattern for the sigacthandler in Solaris 9. */ | |
52 unsigned int sigacthandler_sol9_pattern [] | |
53 = {0xa33e2000, 0x00000000, 0x892c7003, 0x90100011, | |
54 0xe0590005, 0x9fc40000, 0x9410001a, 0x80a46008}; | |
55 | |
56 /* This is the observed pattern for the __sighndlr. */ | |
57 unsigned int sighndlr_pattern [] | |
58 = {0x9de3bf50, 0x90100018, 0x92100019, 0x9fc6c000, | |
59 0x9410001a, 0x81c7e008, 0x81e80000}; | |
60 | |
61 /* Deal with frame-less function from which a signal was raised. */ | |
62 if (_Unwind_IsSignalFrame (context)) | |
63 { | |
64 /* The CFA is by definition unmodified in this case. */ | |
65 fs->regs.cfa_how = CFA_REG_OFFSET; | |
66 fs->regs.cfa_reg = __builtin_dwarf_sp_column (); | |
67 fs->regs.cfa_offset = 0; | |
68 | |
69 /* This is the canonical RA column. */ | |
70 fs->retaddr_column = 15; | |
71 | |
72 return _URC_NO_REASON; | |
73 } | |
74 | |
75 /* Look for the sigacthandler pattern. The pattern changes slightly | |
76 in different versions of the operating system, so we skip the | |
77 comparison against pc-(4*6) for Solaris 9. */ | |
78 if (( *(unsigned int *)(pc-(4*7)) == sigacthandler_sol8_pattern[0] | |
79 && *(unsigned int *)(pc-(4*6)) == sigacthandler_sol8_pattern[1] | |
80 && *(unsigned int *)(pc-(4*5)) == sigacthandler_sol8_pattern[2] | |
81 && *(unsigned int *)(pc-(4*4)) == sigacthandler_sol8_pattern[3] | |
82 && *(unsigned int *)(pc-(4*3)) == sigacthandler_sol8_pattern[4] | |
83 && *(unsigned int *)(pc-(4*2)) == sigacthandler_sol8_pattern[5] | |
84 && *(unsigned int *)(pc-(4*1)) == sigacthandler_sol8_pattern[6] | |
85 && *(unsigned int *)(pc-(4*0)) == sigacthandler_sol8_pattern[7] ) || | |
86 ( *(unsigned int *)(pc-(4*7)) == sigacthandler_sol9_pattern[0] | |
87 /* skip pc-(4*6) */ | |
88 && *(unsigned int *)(pc-(4*5)) == sigacthandler_sol9_pattern[2] | |
89 && *(unsigned int *)(pc-(4*4)) == sigacthandler_sol9_pattern[3] | |
90 && *(unsigned int *)(pc-(4*3)) == sigacthandler_sol9_pattern[4] | |
91 && *(unsigned int *)(pc-(4*2)) == sigacthandler_sol9_pattern[5] | |
92 && *(unsigned int *)(pc-(4*1)) == sigacthandler_sol9_pattern[6] | |
93 && *(unsigned int *)(pc-(4*0)) == sigacthandler_sol9_pattern[7] ) ) | |
94 /* We need to move up two frames (the kernel frame and the handler | |
95 frame). Minimum stack frame size is 176 bytes (128 + 48): 128 | |
96 bytes for spilling register window (16 extended words for in | |
97 and local registers), and 6 extended words to store at least | |
98 6 arguments to callees, The kernel frame and the sigacthandler | |
99 both have this minimal stack. The ucontext_t structure is after | |
100 this offset. */ | |
101 regs_off = 176 + 176; | |
102 | |
103 /* Look for the __sighndlr pattern. */ | |
104 else if ( *(unsigned int *)(pc-(4*5)) == sighndlr_pattern[0] | |
105 && *(unsigned int *)(pc-(4*4)) == sighndlr_pattern[1] | |
106 && *(unsigned int *)(pc-(4*3)) == sighndlr_pattern[2] | |
107 && *(unsigned int *)(pc-(4*2)) == sighndlr_pattern[3] | |
108 && *(unsigned int *)(pc-(4*1)) == sighndlr_pattern[4] | |
109 && *(unsigned int *)(pc-(4*0)) == sighndlr_pattern[5] | |
110 && *(unsigned int *)(pc+(4*1)) == sighndlr_pattern[6] ) | |
111 { | |
112 /* We have observed different calling frames among different | |
113 versions of the operating system, so that we need to | |
114 discriminate using the upper frame. We look for the return | |
115 address of the caller frame (there is an offset of 15 double | |
116 words between the frame address and the place where this return | |
117 address is stored) in order to do some more pattern matching. */ | |
118 unsigned int cuh_pattern | |
119 = *(unsigned int *)(*(unsigned long *)(this_cfa + 15*8) - 4); | |
120 | |
121 if (cuh_pattern == 0x9410001a || cuh_pattern == 0x94100013) | |
122 /* This matches the call_user_handler pattern for Solaris 9 and | |
123 for Solaris 8 running inside Solaris Containers respectively. | |
124 We need to move up four frames (the kernel frame, the signal | |
125 frame, the call_user_handler frame, the __sighndlr frame). | |
126 Three of them have the minimum stack frame size (kernel, | |
127 signal, and __sighndlr frames) of 176 bytes, and there is | |
128 another with a stack frame of 304 bytes (the call_user_handler | |
129 frame). The ucontext_t structure is after this offset. */ | |
130 regs_off = 176 + 176 + 176 + 304; | |
131 else | |
132 /* We need to move up three frames (the kernel frame, the | |
133 sigacthandler frame, and the __sighndlr frame). The kernel | |
134 frame has a stack frame size of 176, the __sighndlr frames of | |
135 304 bytes, and there is a stack frame of 176 bytes for the | |
136 sigacthandler frame. The ucontext_t structure is after this | |
137 offset. */ | |
138 regs_off = 176 + 304 + 176; | |
139 } | |
140 | |
141 /* Exit if the pattern at the return address does not match the | |
142 previous three patterns. */ | |
143 else | |
144 return _URC_END_OF_STACK; | |
145 | |
146 /* FPU information can be extracted from the ucontext_t structure | |
147 that is the third argument for the signal handler, that is saved | |
148 in the stack. There are 64 bytes between the beginning of the | |
149 ucontext_t argument of the signal handler and the uc_mcontext | |
150 field. There are 176 bytes between the beginning of uc_mcontext | |
151 and the beginning of the fpregs field. */ | |
152 fpu_save_off = regs_off + (8*10) + 176; | |
153 | |
154 /* The fpregs field contains 32 extended words at the beginning that | |
155 contain the fpu state. Then there are 2 extended words and two | |
156 bytes. */ | |
157 fpu_save = *(unsigned char *)(this_cfa + fpu_save_off + (8*32) + (2*8) + 2); | |
158 | |
159 /* We need to get the frame pointer for the kernel frame that | |
160 executes when the signal is raised. This frame is just the | |
161 following to the application code that generated the signal, so | |
162 that the later's stack pointer is the former's frame pointer. | |
163 The stack pointer for the interrupted application code can be | |
164 calculated from the ucontext_t structure (third argument for the | |
165 signal handler) that is saved in the stack. There are 10 words | |
166 between the beginning of the ucontext_t argument of the signal | |
167 handler and the uc_mcontext.gregs field that contains the | |
168 registers saved by the signal handler. */ | |
169 new_cfa = *(void **)(this_cfa + regs_off + (8*10) + (REG_SP*8)); | |
170 /* The frame address is %sp + STACK_BIAS in 64-bit mode. */ | |
171 new_cfa += 2047; | |
172 fs->regs.cfa_how = CFA_REG_OFFSET; | |
173 fs->regs.cfa_reg = __builtin_dwarf_sp_column (); | |
174 fs->regs.cfa_offset = new_cfa - this_cfa; | |
175 | |
176 /* Restore global and out registers (in this order) from the | |
177 ucontext_t structure, uc_mcontext.gregs field. */ | |
178 for (i = 1; i < 16; i++) | |
179 { | |
180 /* We never restore %sp as everything is purely CFA-based. */ | |
181 if ((unsigned int) i == __builtin_dwarf_sp_column ()) | |
182 continue; | |
183 | |
184 /* First the global registers and then the out registers. */ | |
185 fs->regs.reg[i].how = REG_SAVED_OFFSET; | |
186 fs->regs.reg[i].loc.offset | |
187 = this_cfa + regs_off + (8*10) + ((REG_Y+i)*8) - new_cfa; | |
188 } | |
189 | |
190 /* Just above the stack pointer there are 16 extended words in which | |
191 the register window (in and local registers) was saved. */ | |
192 for (i = 0; i < 16; i++) | |
193 { | |
194 fs->regs.reg[i + 16].how = REG_SAVED_OFFSET; | |
195 fs->regs.reg[i + 16].loc.offset = i*8; | |
196 } | |
197 | |
198 /* Check whether we need to restore fpu registers. */ | |
199 if (fpu_save) | |
200 { | |
201 for (i = 0; i < 64; i++) | |
202 { | |
203 if (i > 32 && (i & 1)) | |
204 continue; | |
205 | |
206 fs->regs.reg[i + 32].how = REG_SAVED_OFFSET; | |
207 fs->regs.reg[i + 32].loc.offset | |
208 = this_cfa + fpu_save_off + (i*4) - new_cfa; | |
209 } | |
210 } | |
211 | |
212 /* State the rules to find the kernel's code "return address", which is | |
213 the address of the active instruction when the signal was caught. | |
214 On the SPARC, since RETURN_ADDR_OFFSET (essentially 8) is defined, we | |
215 need to preventively subtract it from the purported return address. */ | |
216 ra_location = this_cfa + regs_off + (8*10) + (REG_PC*8); | |
217 shifted_ra_location = this_cfa + regs_off + (8*10) + (REG_Y*8); | |
218 *(void **)shifted_ra_location = *(void **)ra_location - 8; | |
219 fs->retaddr_column = 0; | |
220 fs->regs.reg[0].how = REG_SAVED_OFFSET; | |
221 fs->regs.reg[0].loc.offset = shifted_ra_location - new_cfa; | |
222 fs->signal_frame = 1; | |
223 | |
224 return _URC_NO_REASON; | |
225 } | |
226 | 152 |
227 #define MD_FROB_UPDATE_CONTEXT sparc64_frob_update_context | 153 #define MD_FROB_UPDATE_CONTEXT sparc64_frob_update_context |
228 | 154 |
229 static void | 155 static void |
230 sparc64_frob_update_context (struct _Unwind_Context *context, | 156 sparc64_frob_update_context (struct _Unwind_Context *context, |
236 do that for signal frames as the offset is artificial for them. */ | 162 do that for signal frames as the offset is artificial for them. */ |
237 if (fs->regs.cfa_reg == __builtin_dwarf_sp_column () | 163 if (fs->regs.cfa_reg == __builtin_dwarf_sp_column () |
238 && fs->regs.cfa_how == CFA_REG_OFFSET | 164 && fs->regs.cfa_how == CFA_REG_OFFSET |
239 && fs->regs.cfa_offset != 0 | 165 && fs->regs.cfa_offset != 0 |
240 && !fs->signal_frame) | 166 && !fs->signal_frame) |
241 context->cfa -= 2047; | 167 context->cfa -= STACK_BIAS; |
242 } | 168 } |
243 | 169 |
244 #else | 170 #else |
245 | 171 |
172 #define IS_SIGHANDLER sparc_is_sighandler | |
173 | |
174 static int | |
175 sparc_is_sighandler (unsigned int *pc, unsigned int * savpc, int *nframes) | |
176 { | |
177 if (/* Solaris 8, 9 - single-threaded | |
178 ------------------------------- | |
179 The pattern changes slightly in different versions of the operating | |
180 system, so we skip the comparison against pc[-6]. | |
181 | |
182 <sigacthandler+16>: add %o1, %o7, %o3 | |
183 <sigacthandler+20>: mov %i1, %o1 | |
184 | |
185 <sigacthandler+24>: ld [ %o3 + <offset> ], %o2 | |
186 | |
187 <sigacthandler+28>: sll %i0, 2, %o0 | |
188 <sigacthandler+32>: ld [ %o0 + %o2 ], %l0 | |
189 <sigacthandler+36>: mov %i0, %o0 | |
190 <sigacthandler+40>: call %l0 | |
191 <sigacthandler+44>: mov %i2, %o2 | |
192 <sigacthandler+48>: cmp %i0, 8 <--- PC */ | |
193 pc[-8] == 0x9602400f | |
194 && pc[-7] == 0x92100019 | |
195 /* skip pc[-6] */ | |
196 && pc[-5] == 0x912e2002 | |
197 && pc[-4] == 0xe002000a | |
198 && pc[-3] == 0x90100018 | |
199 && pc[-2] == 0x9fc40000 | |
200 && pc[-1] == 0x9410001a | |
201 && pc[ 0] == 0x80a62008) | |
202 { | |
203 /* Need to move up one frame: | |
204 | |
205 <signal handler> <-- context->cfa | |
206 sigacthandler | |
207 <kernel> | |
208 */ | |
209 *nframes = 1; | |
210 return 1; | |
211 } | |
212 | |
213 if (/* Solaris 8 - multi-threaded | |
214 --------------------------- | |
215 <__libthread_segvhdlr+212>: clr %o2 | |
216 <__libthread_segvhdlr+216>: ld [ %fp + -28 ], %l0 | |
217 <__libthread_segvhdlr+220>: mov %i4, %o0 | |
218 <__libthread_segvhdlr+224>: mov %i1, %o1 | |
219 <__libthread_segvhdlr+228>: call %l0 | |
220 <__libthread_segvhdlr+232>: mov %i2, %o2 | |
221 <__libthread_segvhdlr+236>: ret <--- PC | |
222 <__libthread_segvhdlr+240>: restore | |
223 <__libthread_segvhdlr+244>: cmp %o1, 0 */ | |
224 pc[-6] == 0x94102000 | |
225 && pc[-5] == 0xe007bfe4 | |
226 && pc[-4] == 0x9010001c | |
227 && pc[-3] == 0x92100019 | |
228 && pc[-2] == 0x9fc40000 | |
229 && pc[-1] == 0x9410001a | |
230 && pc[ 0] == 0x81c7e008 | |
231 && pc[ 1] == 0x81e80000 | |
232 && pc[ 2] == 0x80a26000) | |
233 { | |
234 /* Need to move up one frame: | |
235 | |
236 <signal handler> <-- context->cfa | |
237 __libthread_segvhdlr | |
238 <kernel> | |
239 */ | |
240 *nframes = 1; | |
241 return 1; | |
242 } | |
243 | |
244 if(/* Solaris 8+ - multi-threaded | |
245 ---------------------------- | |
246 <__sighndlr>: save %sp, -96, %sp | |
247 <__sighndlr+4>: mov %i0, %o0 | |
248 <__sighndlr+8>: mov %i1, %o1 | |
249 <__sighndlr+12>: call %i3 | |
250 <__sighndlr+16>: mov %i2, %o2 | |
251 <__sighndlr+20>: ret <--- PC | |
252 <__sighndlr+24>: restore */ | |
253 pc[-5] == 0x9de3bfa0 | |
254 && pc[-4] == 0x90100018 | |
255 && pc[-3] == 0x92100019 | |
256 && pc[-2] == 0x9fc6c000 | |
257 && pc[-1] == 0x9410001a | |
258 && pc[ 0] == 0x81c7e008 | |
259 && pc[ 1] == 0x81e80000) | |
260 { | |
261 if (/* Solaris 8 /usr/lib/libthread.so.1 | |
262 ---------------------------------- | |
263 <sigacthandler+1796>: mov %i0, %o0 */ | |
264 savpc[-1] == 0x90100018) | |
265 { | |
266 /* We need to move up two frames: | |
267 | |
268 <signal handler> <-- context->cfa | |
269 __sighndlr | |
270 sigacthandler | |
271 <kernel> | |
272 */ | |
273 *nframes = 2; | |
274 } | |
275 else /* Solaris 8 /usr/lib/lwp/libthread.so.1, Solaris 9+ | |
276 -------------------------------------------------- */ | |
277 { | |
278 /* We need to move up three frames: | |
279 | |
280 <signal handler> <-- context->cfa | |
281 __sighndlr | |
282 call_user_handler | |
283 sigacthandler | |
284 <kernel> | |
285 */ | |
286 *nframes = 3; | |
287 } | |
288 return 1; | |
289 } | |
290 | |
291 return 0; | |
292 } | |
293 | |
246 #define MD_FALLBACK_FRAME_STATE_FOR sparc_fallback_frame_state | 294 #define MD_FALLBACK_FRAME_STATE_FOR sparc_fallback_frame_state |
247 | 295 |
296 #endif | |
297 | |
248 static _Unwind_Reason_Code | 298 static _Unwind_Reason_Code |
249 sparc_fallback_frame_state (struct _Unwind_Context *context, | 299 MD_FALLBACK_FRAME_STATE_FOR (struct _Unwind_Context *context, |
250 _Unwind_FrameState *fs) | 300 _Unwind_FrameState *fs) |
251 { | 301 { |
252 void *pc = context->ra; | 302 void *pc = context->ra; |
303 struct frame *fp = (struct frame *) context->cfa; | |
304 int nframes; | |
253 void *this_cfa = context->cfa; | 305 void *this_cfa = context->cfa; |
254 void *new_cfa, *ra_location, *shifted_ra_location; | 306 long new_cfa; |
255 int regs_off; | 307 void *ra_location, *shifted_ra_location; |
256 int fpu_save_off; | 308 mcontext_t *mctx; |
257 unsigned char fpu_save; | |
258 int i; | 309 int i; |
259 | |
260 /* This is the observed pattern for the sigacthandler. */ | |
261 unsigned int sigacthandler_pattern [] | |
262 = {0x9602400f, 0x92100019, 0x00000000, 0x912e2002, | |
263 0xe002000a, 0x90100018, 0x9fc40000, 0x9410001a, | |
264 0x80a62008}; | |
265 | |
266 /* This is the observed pattern for the __libthread_segvhdlr. */ | |
267 unsigned int segvhdlr_pattern [] | |
268 = {0x94102000, 0xe007bfe4, 0x9010001c, 0x92100019, | |
269 0x9fc40000, 0x9410001a, 0x81c7e008, 0x81e80000, | |
270 0x80a26000}; | |
271 | |
272 /* This is the observed pattern for the __sighndlr. */ | |
273 unsigned int sighndlr_pattern [] | |
274 = {0x9de3bfa0, 0x90100018, 0x92100019, 0x9fc6c000, | |
275 0x9410001a, 0x81c7e008, 0x81e80000}; | |
276 | 310 |
277 /* Deal with frame-less function from which a signal was raised. */ | 311 /* Deal with frame-less function from which a signal was raised. */ |
278 if (_Unwind_IsSignalFrame (context)) | 312 if (_Unwind_IsSignalFrame (context)) |
279 { | 313 { |
280 /* The CFA is by definition unmodified in this case. */ | 314 /* The CFA is by definition unmodified in this case. */ |
286 fs->retaddr_column = 15; | 320 fs->retaddr_column = 15; |
287 | 321 |
288 return _URC_NO_REASON; | 322 return _URC_NO_REASON; |
289 } | 323 } |
290 | 324 |
291 /* Look for the sigacthandler pattern. The pattern changes slightly | 325 if (IS_SIGHANDLER (pc, (unsigned int *)fp->fr_savpc, &nframes)) |
292 in different versions of the operating system, so we skip the | 326 { |
293 comparison against pc-(4*6). */ | 327 struct handler_args { |
294 if ( *(unsigned int *)(pc-(4*8)) == sigacthandler_pattern[0] | 328 struct frame frwin; |
295 && *(unsigned int *)(pc-(4*7)) == sigacthandler_pattern[1] | 329 ucontext_t ucontext; |
296 /* skip pc-(4*6) */ | 330 } *handler_args; |
297 && *(unsigned int *)(pc-(4*5)) == sigacthandler_pattern[3] | 331 ucontext_t *ucp; |
298 && *(unsigned int *)(pc-(4*4)) == sigacthandler_pattern[4] | 332 |
299 && *(unsigned int *)(pc-(4*3)) == sigacthandler_pattern[5] | 333 /* context->cfa points into the frame after the saved frame pointer and |
300 && *(unsigned int *)(pc-(4*2)) == sigacthandler_pattern[6] | 334 saved pc (struct frame). |
301 && *(unsigned int *)(pc-(4*1)) == sigacthandler_pattern[7] | 335 |
302 && *(unsigned int *)(pc-(4*0)) == sigacthandler_pattern[8] ) | 336 The ucontext_t structure is in the kernel frame after a struct |
303 /* We need to move up two frames (the kernel frame and the handler | 337 frame. Since the frame sizes vary even within OS releases, we |
304 frame). Minimum stack frame size is 96 bytes (64 + 4 + 24): 64 | 338 need to walk the stack to get there. */ |
305 bytes for spilling register window (16 words for in and local | 339 |
306 registers), 4 bytes for a pointer to space for callees | 340 for (i = 0; i < nframes; i++) |
307 returning structs, and 24 bytes to store at least six argument | 341 fp = (struct frame *) ((char *)fp->fr_savfp + STACK_BIAS); |
308 to callees. The ucontext_t structure is after this offset. */ | 342 |
309 regs_off = 96 + 96; | 343 handler_args = (struct handler_args *) fp; |
310 | 344 ucp = &handler_args->ucontext; |
311 /* Look for the __libthread_segvhdlr pattern. */ | 345 mctx = &ucp->uc_mcontext; |
312 else if ( *(unsigned int *)(pc-(4*6)) == segvhdlr_pattern[0] | |
313 && *(unsigned int *)(pc-(4*5)) == segvhdlr_pattern[1] | |
314 && *(unsigned int *)(pc-(4*4)) == segvhdlr_pattern[2] | |
315 && *(unsigned int *)(pc-(4*3)) == segvhdlr_pattern[3] | |
316 && *(unsigned int *)(pc-(4*2)) == segvhdlr_pattern[4] | |
317 && *(unsigned int *)(pc-(4*1)) == segvhdlr_pattern[5] | |
318 && *(unsigned int *)(pc-(4*0)) == segvhdlr_pattern[6] | |
319 && *(unsigned int *)(pc+(4*1)) == segvhdlr_pattern[7] | |
320 && *(unsigned int *)(pc+(4*2)) == segvhdlr_pattern[8] ) | |
321 /* We need to move up four frames (the kernel frame, the | |
322 sigacthandler frame, the __sighndlr frame, and the | |
323 __libthread_segvhdlr). Two of them have the minimum | |
324 stack frame size (kernel and __sighndlr frames) of 96 bytes, | |
325 other has a stack frame of 216 bytes (the sigacthandler frame), | |
326 and there is another with a stack frame of 128 bytes (the | |
327 __libthread_segvhdlr). The ucontext_t structure is after this | |
328 offset. */ | |
329 regs_off = 96 + 96 + 128 + 216; | |
330 | |
331 /* Look for the __sighndlr pattern. */ | |
332 else if ( *(unsigned int *)(pc-(4*5)) == sighndlr_pattern[0] | |
333 && *(unsigned int *)(pc-(4*4)) == sighndlr_pattern[1] | |
334 && *(unsigned int *)(pc-(4*3)) == sighndlr_pattern[2] | |
335 && *(unsigned int *)(pc-(4*2)) == sighndlr_pattern[3] | |
336 && *(unsigned int *)(pc-(4*1)) == sighndlr_pattern[4] | |
337 && *(unsigned int *)(pc-(4*0)) == sighndlr_pattern[5] | |
338 && *(unsigned int *)(pc+(4*1)) == sighndlr_pattern[6] ) | |
339 { | |
340 /* We have observed different calling frames among different | |
341 versions of the operating system, so that we need to | |
342 discriminate using the upper frame. We look for the return | |
343 address of the caller frame (there is an offset of 15 words | |
344 between the frame address and the place where this return | |
345 address is stored) in order to do some more pattern matching. */ | |
346 unsigned int cuh_pattern | |
347 = *(unsigned int *)(*(unsigned int *)(this_cfa + 15*4) - 4); | |
348 | |
349 if (cuh_pattern == 0xd407a04c) | |
350 /* This matches the call_user_handler pattern for Solaris 10. | |
351 We need to move up three frames (the kernel frame, the | |
352 call_user_handler frame, the __sighndlr frame). Two of them | |
353 have the minimum stack frame size (kernel and __sighndlr | |
354 frames) of 96 bytes, and there is another with a stack frame | |
355 of 160 bytes (the call_user_handler frame). The ucontext_t | |
356 structure is after this offset. */ | |
357 regs_off = 96 + 96 + 160; | |
358 else if (cuh_pattern == 0x9410001a || cuh_pattern == 0x9410001b) | |
359 /* This matches the call_user_handler pattern for Solaris 9 and | |
360 for Solaris 8 running inside Solaris Containers respectively. | |
361 We need to move up four frames (the kernel frame, the signal | |
362 frame, the call_user_handler frame, the __sighndlr frame). | |
363 Three of them have the minimum stack frame size (kernel, | |
364 signal, and __sighndlr frames) of 96 bytes, and there is | |
365 another with a stack frame of 160 bytes (the call_user_handler | |
366 frame). The ucontext_t structure is after this offset. */ | |
367 regs_off = 96 + 96 + 96 + 160; | |
368 else | |
369 /* We need to move up three frames (the kernel frame, the | |
370 sigacthandler frame, and the __sighndlr frame). Two of them | |
371 have the minimum stack frame size (kernel and __sighndlr | |
372 frames) of 96 bytes, and there is another with a stack frame | |
373 of 216 bytes (the sigacthandler frame). The ucontext_t | |
374 structure is after this offset. */ | |
375 regs_off = 96 + 96 + 216; | |
376 } | 346 } |
377 | 347 |
378 /* Exit if the pattern at the return address does not match the | 348 /* Exit if the pattern at the return address does not match the |
379 previous three patterns. */ | 349 previous three patterns. */ |
380 else | 350 else |
381 return _URC_END_OF_STACK; | 351 return _URC_END_OF_STACK; |
382 | 352 |
383 /* FPU information can be extracted from the ucontext_t structure | 353 new_cfa = mctx->gregs[REG_SP]; |
384 that is the third argument for the signal handler, that is saved | 354 /* The frame address is %sp + STACK_BIAS in 64-bit mode. */ |
385 in the stack. There are 10 words between the beginning of the | 355 new_cfa += STACK_BIAS; |
386 ucontext_t argument of the signal handler and the uc_mcontext | 356 |
387 field. There are 80 bytes between the beginning of uc_mcontext | |
388 and the beginning of the fpregs field. */ | |
389 fpu_save_off = regs_off + (4*10) + (4*20); | |
390 | |
391 /* The fpregs field contains 32 words at the beginning that contain | |
392 the fpu state. Then there are 2 words and two bytes. */ | |
393 fpu_save = *(unsigned char *)(this_cfa + fpu_save_off + (4*32) + (2*4) + 2); | |
394 | |
395 /* We need to get the frame pointer for the kernel frame that | |
396 executes when the signal is raised. This frame is just the | |
397 following to the application code that generated the signal, so | |
398 that the later's stack pointer is the former's frame pointer. | |
399 The stack pointer for the interrupted application code can be | |
400 calculated from the ucontext_t structure (third argument for the | |
401 signal handler) that is saved in the stack. There are 10 words | |
402 between the beginning of the ucontext_t argument of the signal | |
403 handler and the uc_mcontext.gregs field that contains the | |
404 registers saved by the signal handler. */ | |
405 new_cfa = *(void **)(this_cfa + regs_off + (4*10) + (REG_SP*4)); | |
406 fs->regs.cfa_how = CFA_REG_OFFSET; | 357 fs->regs.cfa_how = CFA_REG_OFFSET; |
407 fs->regs.cfa_reg = __builtin_dwarf_sp_column (); | 358 fs->regs.cfa_reg = __builtin_dwarf_sp_column (); |
408 fs->regs.cfa_offset = new_cfa - this_cfa; | 359 fs->regs.cfa_offset = new_cfa - (long) this_cfa; |
409 | 360 |
410 /* Restore global and out registers (in this order) from the | 361 /* Restore global and out registers (in this order) from the |
411 ucontext_t structure, uc_mcontext.gregs field. */ | 362 ucontext_t structure, uc_mcontext.gregs field. */ |
412 for (i = 1; i < 16; i++) | 363 for (i = 1; i < 16; i++) |
413 { | 364 { |
414 /* We never restore %sp as everything is purely CFA-based. */ | 365 /* We never restore %sp as everything is purely CFA-based. */ |
415 if ((unsigned int) i == __builtin_dwarf_sp_column ()) | 366 if ((unsigned int) i == __builtin_dwarf_sp_column ()) |
416 continue; | 367 continue; |
417 | 368 |
418 /* First the global registers and then the out registers */ | 369 /* First the global registers and then the out registers. */ |
419 fs->regs.reg[i].how = REG_SAVED_OFFSET; | 370 fs->regs.reg[i].how = REG_SAVED_OFFSET; |
420 fs->regs.reg[i].loc.offset | 371 fs->regs.reg[i].loc.offset = (long)&mctx->gregs[REG_Y + i] - new_cfa; |
421 = this_cfa + regs_off + (4*10) + ((REG_Y+i)*4) - new_cfa; | 372 } |
422 } | 373 |
423 | 374 /* Just above the stack pointer there are 16 extended words in which |
424 /* Just above the stack pointer there are 16 words in which the | 375 the register window (in and local registers) was saved. */ |
425 register window (in and local registers) was saved. */ | |
426 for (i = 0; i < 16; i++) | 376 for (i = 0; i < 16; i++) |
427 { | 377 { |
428 fs->regs.reg[i + 16].how = REG_SAVED_OFFSET; | 378 fs->regs.reg[i + 16].how = REG_SAVED_OFFSET; |
429 fs->regs.reg[i + 16].loc.offset = i*4; | 379 fs->regs.reg[i + 16].loc.offset = i*sizeof(long); |
430 } | 380 } |
431 | 381 |
432 /* Check whether we need to restore fpu registers. */ | 382 /* Check whether we need to restore FPU registers. */ |
433 if (fpu_save) | 383 if (mctx->fpregs.fpu_qcnt) |
434 { | 384 { |
435 for (i = 0; i < 32; i++) | 385 for (i = 0; i < 32; i++) |
436 { | 386 { |
437 fs->regs.reg[i + 32].how = REG_SAVED_OFFSET; | 387 fs->regs.reg[i + 32].how = REG_SAVED_OFFSET; |
438 fs->regs.reg[i + 32].loc.offset | 388 fs->regs.reg[i + 32].loc.offset |
439 = this_cfa + fpu_save_off + (i*4) - new_cfa; | 389 = (long)&mctx->fpregs.fpu_fr.fpu_regs[i] - new_cfa; |
440 } | 390 } |
391 | |
392 #ifdef __arch64__ | |
393 /* For 64-bit, fpu_fr.fpu_dregs contains 32 instead of 16 doubles. */ | |
394 for (i = 32; i < 64; i++) | |
395 { | |
396 if (i > 32 && (i & 1)) | |
397 continue; | |
398 | |
399 fs->regs.reg[i + 32].how = REG_SAVED_OFFSET; | |
400 fs->regs.reg[i + 32].loc.offset | |
401 = (long)&mctx->fpregs.fpu_fr.fpu_dregs[i/2] - new_cfa; | |
402 } | |
403 #endif | |
441 } | 404 } |
442 | 405 |
443 /* State the rules to find the kernel's code "return address", which is | 406 /* State the rules to find the kernel's code "return address", which is |
444 the address of the active instruction when the signal was caught. | 407 the address of the active instruction when the signal was caught. |
445 On the SPARC, since RETURN_ADDR_OFFSET (essentially 8) is defined, we | 408 On the SPARC, since RETURN_ADDR_OFFSET (essentially 8) is defined, we |
446 need to preventively subtract it from the purported return address. */ | 409 need to preventively subtract it from the purported return address. */ |
447 ra_location = this_cfa + regs_off + (4*10) + (REG_PC*4); | 410 ra_location = &mctx->gregs[REG_PC]; |
448 shifted_ra_location = this_cfa + regs_off + (4*10) + (REG_Y*4); | 411 shifted_ra_location = &mctx->gregs[REG_Y]; |
449 *(void **)shifted_ra_location = *(void **)ra_location - 8; | 412 *(void **)shifted_ra_location = *(void **)ra_location - 8; |
450 fs->retaddr_column = 0; | 413 fs->retaddr_column = 0; |
451 fs->regs.reg[0].how = REG_SAVED_OFFSET; | 414 fs->regs.reg[0].how = REG_SAVED_OFFSET; |
452 fs->regs.reg[0].loc.offset = shifted_ra_location - new_cfa; | 415 fs->regs.reg[0].loc.offset = (long)shifted_ra_location - new_cfa; |
453 fs->signal_frame = 1; | 416 fs->signal_frame = 1; |
454 | 417 |
455 return _URC_NO_REASON; | 418 return _URC_NO_REASON; |
456 }; | 419 } |
457 | |
458 #endif |