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