]>
Commit | Line | Data |
---|---|---|
df4b504c | 1 | /* DWARF2 exception handling and frame unwind runtime interface routines. |
15c73eb7 | 2 | Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 |
ac0c7fb1 | 3 | Free Software Foundation, Inc. |
df4b504c | 4 | |
f12b58b3 | 5 | This file is part of GCC. |
df4b504c | 6 | |
f12b58b3 | 7 | GCC is free software; you can redistribute it and/or modify it |
8 | under the terms of the GNU General Public License as published by | |
df4b504c | 9 | the Free Software Foundation; either version 2, or (at your option) |
10 | any later version. | |
11 | ||
7ad3dd5c | 12 | In addition to the permissions in the GNU General Public License, the |
13 | Free Software Foundation gives you unlimited permission to link the | |
14 | compiled version of this file into combinations with other programs, | |
15 | and to distribute those combinations without any restriction coming | |
16 | from the use of this file. (The General Public License restrictions | |
17 | do apply in other respects; for example, they cover modification of | |
18 | the file, and distribution when not linked into a combined | |
19 | executable.) | |
20 | ||
f12b58b3 | 21 | GCC is distributed in the hope that it will be useful, but WITHOUT |
22 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
23 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public | |
24 | License for more details. | |
df4b504c | 25 | |
26 | You should have received a copy of the GNU General Public License | |
f12b58b3 | 27 | along with GCC; see the file COPYING. If not, write to the Free |
67ce556b | 28 | Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA |
29 | 02110-1301, USA. */ | |
df4b504c | 30 | |
31 | #include "tconfig.h" | |
32 | #include "tsystem.h" | |
805e22b2 | 33 | #include "coretypes.h" |
34 | #include "tm.h" | |
df4b504c | 35 | #include "dwarf2.h" |
36 | #include "unwind.h" | |
db0f4f32 | 37 | #ifdef __USING_SJLJ_EXCEPTIONS__ |
38 | # define NO_SIZE_OF_ENCODED_VALUE | |
39 | #endif | |
9b84bf7d | 40 | #include "unwind-pe.h" |
df4b504c | 41 | #include "unwind-dw2-fde.h" |
42 | #include "gthr.h" | |
60ea93bb | 43 | #include "unwind-dw2.h" |
df4b504c | 44 | |
a1a7e9d5 | 45 | #ifndef __USING_SJLJ_EXCEPTIONS__ |
df4b504c | 46 | |
47 | #ifndef STACK_GROWS_DOWNWARD | |
48 | #define STACK_GROWS_DOWNWARD 0 | |
49 | #else | |
50 | #undef STACK_GROWS_DOWNWARD | |
51 | #define STACK_GROWS_DOWNWARD 1 | |
52 | #endif | |
53 | ||
ba7065a9 | 54 | /* Dwarf frame registers used for pre gcc 3.0 compiled glibc. */ |
55 | #ifndef PRE_GCC3_DWARF_FRAME_REGISTERS | |
56 | #define PRE_GCC3_DWARF_FRAME_REGISTERS DWARF_FRAME_REGISTERS | |
57 | #endif | |
58 | ||
e92aec9e | 59 | #ifndef DWARF_REG_TO_UNWIND_COLUMN |
60 | #define DWARF_REG_TO_UNWIND_COLUMN(REGNO) (REGNO) | |
61 | #endif | |
62 | ||
9081a51e | 63 | /* This is the register and unwind state for a particular frame. This |
64 | provides the information necessary to unwind up past a frame and return | |
65 | to its caller. */ | |
df4b504c | 66 | struct _Unwind_Context |
67 | { | |
68 | void *reg[DWARF_FRAME_REGISTERS+1]; | |
69 | void *cfa; | |
70 | void *ra; | |
71 | void *lsda; | |
72 | struct dwarf_eh_bases bases; | |
73 | _Unwind_Word args_size; | |
15c73eb7 | 74 | char signal_frame; |
706f0818 | 75 | char by_value[DWARF_FRAME_REGISTERS+1]; |
df4b504c | 76 | }; |
77 | ||
78 | /* Byte size of every register managed by these routines. */ | |
c49ad9ef | 79 | static unsigned char dwarf_reg_size_table[DWARF_FRAME_REGISTERS+1]; |
df4b504c | 80 | |
df4b504c | 81 | \f |
df4b504c | 82 | /* Read unaligned data from the instruction buffer. */ |
83 | ||
84 | union unaligned | |
85 | { | |
86 | void *p; | |
87 | unsigned u2 __attribute__ ((mode (HI))); | |
88 | unsigned u4 __attribute__ ((mode (SI))); | |
89 | unsigned u8 __attribute__ ((mode (DI))); | |
90 | signed s2 __attribute__ ((mode (HI))); | |
91 | signed s4 __attribute__ ((mode (SI))); | |
92 | signed s8 __attribute__ ((mode (DI))); | |
93 | } __attribute__ ((packed)); | |
94 | ||
68528f68 | 95 | static void uw_update_context (struct _Unwind_Context *, _Unwind_FrameState *); |
96 | static _Unwind_Reason_Code uw_frame_state_for (struct _Unwind_Context *, | |
97 | _Unwind_FrameState *); | |
98 | ||
df4b504c | 99 | static inline void * |
9b84bf7d | 100 | read_pointer (const void *p) { const union unaligned *up = p; return up->p; } |
df4b504c | 101 | |
102 | static inline int | |
188879e7 | 103 | read_1u (const void *p) { return *(const unsigned char *) p; } |
df4b504c | 104 | |
105 | static inline int | |
188879e7 | 106 | read_1s (const void *p) { return *(const signed char *) p; } |
df4b504c | 107 | |
108 | static inline int | |
9b84bf7d | 109 | read_2u (const void *p) { const union unaligned *up = p; return up->u2; } |
df4b504c | 110 | |
111 | static inline int | |
9b84bf7d | 112 | read_2s (const void *p) { const union unaligned *up = p; return up->s2; } |
df4b504c | 113 | |
114 | static inline unsigned int | |
9b84bf7d | 115 | read_4u (const void *p) { const union unaligned *up = p; return up->u4; } |
df4b504c | 116 | |
117 | static inline int | |
9b84bf7d | 118 | read_4s (const void *p) { const union unaligned *up = p; return up->s4; } |
df4b504c | 119 | |
120 | static inline unsigned long | |
9b84bf7d | 121 | read_8u (const void *p) { const union unaligned *up = p; return up->u8; } |
df4b504c | 122 | |
123 | static inline unsigned long | |
9b84bf7d | 124 | read_8s (const void *p) { const union unaligned *up = p; return up->s8; } |
df4b504c | 125 | \f |
706f0818 | 126 | /* Get the value of register INDEX as saved in CONTEXT. */ |
df4b504c | 127 | |
128 | inline _Unwind_Word | |
129 | _Unwind_GetGR (struct _Unwind_Context *context, int index) | |
130 | { | |
5fec5f34 | 131 | int size; |
132 | void *ptr; | |
133 | ||
223e8e29 | 134 | #ifdef DWARF_ZERO_REG |
135 | if (index == DWARF_ZERO_REG) | |
136 | return 0; | |
137 | #endif | |
138 | ||
e92aec9e | 139 | index = DWARF_REG_TO_UNWIND_COLUMN (index); |
51536141 | 140 | gcc_assert (index < (int) sizeof(dwarf_reg_size_table)); |
5fec5f34 | 141 | size = dwarf_reg_size_table[index]; |
142 | ptr = context->reg[index]; | |
143 | ||
706f0818 | 144 | if (context->by_value[index]) |
145 | return (_Unwind_Word) (_Unwind_Internal_Ptr) ptr; | |
146 | ||
df4b504c | 147 | /* This will segfault if the register hasn't been saved. */ |
5fec5f34 | 148 | if (size == sizeof(_Unwind_Ptr)) |
149 | return * (_Unwind_Ptr *) ptr; | |
51536141 | 150 | else |
151 | { | |
152 | gcc_assert (size == sizeof(_Unwind_Word)); | |
153 | return * (_Unwind_Word *) ptr; | |
154 | } | |
5fec5f34 | 155 | } |
156 | ||
157 | static inline void * | |
158 | _Unwind_GetPtr (struct _Unwind_Context *context, int index) | |
159 | { | |
160 | return (void *)(_Unwind_Ptr) _Unwind_GetGR (context, index); | |
df4b504c | 161 | } |
162 | ||
c7beb4b3 | 163 | /* Get the value of the CFA as saved in CONTEXT. */ |
164 | ||
165 | _Unwind_Word | |
166 | _Unwind_GetCFA (struct _Unwind_Context *context) | |
167 | { | |
9d34a184 | 168 | return (_Unwind_Ptr) context->cfa; |
c7beb4b3 | 169 | } |
170 | ||
706f0818 | 171 | /* Overwrite the saved value for register INDEX in CONTEXT with VAL. */ |
df4b504c | 172 | |
173 | inline void | |
174 | _Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val) | |
175 | { | |
5fec5f34 | 176 | int size; |
177 | void *ptr; | |
178 | ||
e92aec9e | 179 | index = DWARF_REG_TO_UNWIND_COLUMN (index); |
51536141 | 180 | gcc_assert (index < (int) sizeof(dwarf_reg_size_table)); |
5fec5f34 | 181 | size = dwarf_reg_size_table[index]; |
706f0818 | 182 | |
183 | if (context->by_value[index]) | |
184 | { | |
185 | context->reg[index] = (void *) (_Unwind_Internal_Ptr) val; | |
186 | return; | |
187 | } | |
188 | ||
5fec5f34 | 189 | ptr = context->reg[index]; |
190 | ||
191 | if (size == sizeof(_Unwind_Ptr)) | |
192 | * (_Unwind_Ptr *) ptr = val; | |
5fec5f34 | 193 | else |
51536141 | 194 | { |
195 | gcc_assert (size == sizeof(_Unwind_Word)); | |
196 | * (_Unwind_Word *) ptr = val; | |
197 | } | |
df4b504c | 198 | } |
199 | ||
e92aec9e | 200 | /* Get the pointer to a register INDEX as saved in CONTEXT. */ |
201 | ||
202 | static inline void * | |
203 | _Unwind_GetGRPtr (struct _Unwind_Context *context, int index) | |
204 | { | |
205 | index = DWARF_REG_TO_UNWIND_COLUMN (index); | |
706f0818 | 206 | if (context->by_value[index]) |
207 | return &context->reg[index]; | |
e92aec9e | 208 | return context->reg[index]; |
209 | } | |
210 | ||
211 | /* Set the pointer to a register INDEX as saved in CONTEXT. */ | |
212 | ||
213 | static inline void | |
214 | _Unwind_SetGRPtr (struct _Unwind_Context *context, int index, void *p) | |
215 | { | |
216 | index = DWARF_REG_TO_UNWIND_COLUMN (index); | |
706f0818 | 217 | context->by_value[index] = 0; |
e92aec9e | 218 | context->reg[index] = p; |
219 | } | |
220 | ||
706f0818 | 221 | /* Overwrite the saved value for register INDEX in CONTEXT with VAL. */ |
222 | ||
223 | static inline void | |
224 | _Unwind_SetGRValue (struct _Unwind_Context *context, int index, | |
225 | _Unwind_Word val) | |
226 | { | |
227 | index = DWARF_REG_TO_UNWIND_COLUMN (index); | |
228 | gcc_assert (index < (int) sizeof(dwarf_reg_size_table)); | |
229 | gcc_assert (dwarf_reg_size_table[index] == sizeof (_Unwind_Ptr)); | |
230 | ||
231 | context->by_value[index] = 1; | |
232 | context->reg[index] = (void *) (_Unwind_Internal_Ptr) val; | |
233 | } | |
234 | ||
334ec2d8 | 235 | /* Return nonzero if register INDEX is stored by value rather than |
706f0818 | 236 | by reference. */ |
237 | ||
238 | static inline int | |
239 | _Unwind_GRByValue (struct _Unwind_Context *context, int index) | |
240 | { | |
241 | index = DWARF_REG_TO_UNWIND_COLUMN (index); | |
242 | return context->by_value[index]; | |
243 | } | |
244 | ||
df4b504c | 245 | /* Retrieve the return address for CONTEXT. */ |
246 | ||
247 | inline _Unwind_Ptr | |
248 | _Unwind_GetIP (struct _Unwind_Context *context) | |
249 | { | |
250 | return (_Unwind_Ptr) context->ra; | |
251 | } | |
252 | ||
15c73eb7 | 253 | /* Retrieve the return address and flag whether that IP is before |
254 | or after first not yet fully executed instruction. */ | |
255 | ||
256 | inline _Unwind_Ptr | |
257 | _Unwind_GetIPInfo (struct _Unwind_Context *context, int *ip_before_insn) | |
258 | { | |
259 | *ip_before_insn = context->signal_frame != 0; | |
260 | return (_Unwind_Ptr) context->ra; | |
261 | } | |
262 | ||
df4b504c | 263 | /* Overwrite the return address for CONTEXT with VAL. */ |
264 | ||
265 | inline void | |
266 | _Unwind_SetIP (struct _Unwind_Context *context, _Unwind_Ptr val) | |
267 | { | |
268 | context->ra = (void *) val; | |
269 | } | |
270 | ||
271 | void * | |
272 | _Unwind_GetLanguageSpecificData (struct _Unwind_Context *context) | |
273 | { | |
274 | return context->lsda; | |
275 | } | |
276 | ||
277 | _Unwind_Ptr | |
278 | _Unwind_GetRegionStart (struct _Unwind_Context *context) | |
279 | { | |
280 | return (_Unwind_Ptr) context->bases.func; | |
281 | } | |
282 | ||
19799cdd | 283 | void * |
41acc81b | 284 | _Unwind_FindEnclosingFunction (void *pc) |
19799cdd | 285 | { |
286 | struct dwarf_eh_bases bases; | |
358738f4 | 287 | const struct dwarf_fde *fde = _Unwind_Find_FDE (pc-1, &bases); |
19799cdd | 288 | if (fde) |
289 | return bases.func; | |
290 | else | |
291 | return NULL; | |
292 | } | |
293 | ||
ad5818ae | 294 | #ifndef __ia64__ |
295 | _Unwind_Ptr | |
296 | _Unwind_GetDataRelBase (struct _Unwind_Context *context) | |
297 | { | |
298 | return (_Unwind_Ptr) context->bases.dbase; | |
299 | } | |
300 | ||
301 | _Unwind_Ptr | |
302 | _Unwind_GetTextRelBase (struct _Unwind_Context *context) | |
303 | { | |
304 | return (_Unwind_Ptr) context->bases.tbase; | |
305 | } | |
306 | #endif | |
aebd6cb6 | 307 | |
308 | #ifdef MD_UNWIND_SUPPORT | |
309 | #include MD_UNWIND_SUPPORT | |
310 | #endif | |
df4b504c | 311 | \f |
312 | /* Extract any interesting information from the CIE for the translation | |
313 | unit F belongs to. Return a pointer to the byte after the augmentation, | |
314 | or NULL if we encountered an undecipherable augmentation. */ | |
315 | ||
9b84bf7d | 316 | static const unsigned char * |
358738f4 | 317 | extract_cie_info (const struct dwarf_cie *cie, struct _Unwind_Context *context, |
df4b504c | 318 | _Unwind_FrameState *fs) |
319 | { | |
9b84bf7d | 320 | const unsigned char *aug = cie->augmentation; |
88cbb18b | 321 | const unsigned char *p = aug + strlen ((const char *)aug) + 1; |
9b84bf7d | 322 | const unsigned char *ret = NULL; |
a6398abe | 323 | _Unwind_Word utmp; |
df4b504c | 324 | |
44b157cf | 325 | /* g++ v2 "eh" has pointer immediately following augmentation string, |
326 | so it must be handled first. */ | |
327 | if (aug[0] == 'e' && aug[1] == 'h') | |
328 | { | |
329 | fs->eh_ptr = read_pointer (p); | |
330 | p += sizeof (void *); | |
331 | aug += 2; | |
332 | } | |
333 | ||
df4b504c | 334 | /* Immediately following the augmentation are the code and |
335 | data alignment and return address column. */ | |
a6398abe | 336 | p = read_uleb128 (p, &fs->code_align); |
337 | p = read_sleb128 (p, &fs->data_align); | |
c0d45e55 | 338 | if (cie->version == 1) |
339 | fs->retaddr_column = *p++; | |
340 | else | |
341 | p = read_uleb128 (p, &fs->retaddr_column); | |
9b84bf7d | 342 | fs->lsda_encoding = DW_EH_PE_omit; |
df4b504c | 343 | |
344 | /* If the augmentation starts with 'z', then a uleb128 immediately | |
345 | follows containing the length of the augmentation field following | |
346 | the size. */ | |
347 | if (*aug == 'z') | |
348 | { | |
a6398abe | 349 | p = read_uleb128 (p, &utmp); |
350 | ret = p + utmp; | |
df4b504c | 351 | |
352 | fs->saw_z = 1; | |
353 | ++aug; | |
354 | } | |
355 | ||
356 | /* Iterate over recognized augmentation subsequences. */ | |
357 | while (*aug != '\0') | |
358 | { | |
9b84bf7d | 359 | /* "L" indicates a byte showing how the LSDA pointer is encoded. */ |
44b157cf | 360 | if (aug[0] == 'L') |
9b84bf7d | 361 | { |
362 | fs->lsda_encoding = *p++; | |
363 | aug += 1; | |
364 | } | |
365 | ||
366 | /* "R" indicates a byte indicating how FDE addresses are encoded. */ | |
df4b504c | 367 | else if (aug[0] == 'R') |
368 | { | |
9b84bf7d | 369 | fs->fde_encoding = *p++; |
df4b504c | 370 | aug += 1; |
371 | } | |
372 | ||
9b84bf7d | 373 | /* "P" indicates a personality routine in the CIE augmentation. */ |
df4b504c | 374 | else if (aug[0] == 'P') |
375 | { | |
fa29d733 | 376 | _Unwind_Ptr personality; |
377 | ||
378 | p = read_encoded_value (context, *p, p + 1, &personality); | |
379 | fs->personality = (_Unwind_Personality_Fn) personality; | |
df4b504c | 380 | aug += 1; |
381 | } | |
382 | ||
15c73eb7 | 383 | /* "S" indicates a signal frame. */ |
384 | else if (aug[0] == 'S') | |
385 | { | |
386 | fs->signal_frame = 1; | |
387 | aug += 1; | |
388 | } | |
389 | ||
df4b504c | 390 | /* Otherwise we have an unknown augmentation string. |
391 | Bail unless we saw a 'z' prefix. */ | |
392 | else | |
393 | return ret; | |
394 | } | |
395 | ||
396 | return ret ? ret : p; | |
397 | } | |
398 | ||
399 | ||
400 | /* Decode a DW_OP stack program. Return the top of stack. Push INITIAL | |
401 | onto the stack to start. */ | |
402 | ||
403 | static _Unwind_Word | |
9b84bf7d | 404 | execute_stack_op (const unsigned char *op_ptr, const unsigned char *op_end, |
df4b504c | 405 | struct _Unwind_Context *context, _Unwind_Word initial) |
406 | { | |
1be87b72 | 407 | _Unwind_Word stack[64]; /* ??? Assume this is enough. */ |
df4b504c | 408 | int stack_elt; |
409 | ||
410 | stack[0] = initial; | |
411 | stack_elt = 1; | |
412 | ||
413 | while (op_ptr < op_end) | |
414 | { | |
415 | enum dwarf_location_atom op = *op_ptr++; | |
a6398abe | 416 | _Unwind_Word result, reg, utmp; |
417 | _Unwind_Sword offset, stmp; | |
df4b504c | 418 | |
419 | switch (op) | |
420 | { | |
421 | case DW_OP_lit0: | |
422 | case DW_OP_lit1: | |
423 | case DW_OP_lit2: | |
424 | case DW_OP_lit3: | |
425 | case DW_OP_lit4: | |
426 | case DW_OP_lit5: | |
427 | case DW_OP_lit6: | |
428 | case DW_OP_lit7: | |
429 | case DW_OP_lit8: | |
430 | case DW_OP_lit9: | |
431 | case DW_OP_lit10: | |
432 | case DW_OP_lit11: | |
433 | case DW_OP_lit12: | |
434 | case DW_OP_lit13: | |
435 | case DW_OP_lit14: | |
436 | case DW_OP_lit15: | |
437 | case DW_OP_lit16: | |
438 | case DW_OP_lit17: | |
439 | case DW_OP_lit18: | |
440 | case DW_OP_lit19: | |
441 | case DW_OP_lit20: | |
442 | case DW_OP_lit21: | |
443 | case DW_OP_lit22: | |
444 | case DW_OP_lit23: | |
445 | case DW_OP_lit24: | |
446 | case DW_OP_lit25: | |
447 | case DW_OP_lit26: | |
448 | case DW_OP_lit27: | |
449 | case DW_OP_lit28: | |
450 | case DW_OP_lit29: | |
451 | case DW_OP_lit30: | |
452 | case DW_OP_lit31: | |
453 | result = op - DW_OP_lit0; | |
454 | break; | |
455 | ||
456 | case DW_OP_addr: | |
457 | result = (_Unwind_Word) (_Unwind_Ptr) read_pointer (op_ptr); | |
458 | op_ptr += sizeof (void *); | |
459 | break; | |
460 | ||
461 | case DW_OP_const1u: | |
462 | result = read_1u (op_ptr); | |
463 | op_ptr += 1; | |
464 | break; | |
465 | case DW_OP_const1s: | |
466 | result = read_1s (op_ptr); | |
467 | op_ptr += 1; | |
468 | break; | |
469 | case DW_OP_const2u: | |
470 | result = read_2u (op_ptr); | |
471 | op_ptr += 2; | |
472 | break; | |
473 | case DW_OP_const2s: | |
474 | result = read_2s (op_ptr); | |
475 | op_ptr += 2; | |
476 | break; | |
477 | case DW_OP_const4u: | |
478 | result = read_4u (op_ptr); | |
479 | op_ptr += 4; | |
480 | break; | |
481 | case DW_OP_const4s: | |
482 | result = read_4s (op_ptr); | |
483 | op_ptr += 4; | |
484 | break; | |
485 | case DW_OP_const8u: | |
486 | result = read_8u (op_ptr); | |
487 | op_ptr += 8; | |
488 | break; | |
489 | case DW_OP_const8s: | |
490 | result = read_8s (op_ptr); | |
491 | op_ptr += 8; | |
492 | break; | |
493 | case DW_OP_constu: | |
a6398abe | 494 | op_ptr = read_uleb128 (op_ptr, &result); |
df4b504c | 495 | break; |
496 | case DW_OP_consts: | |
a6398abe | 497 | op_ptr = read_sleb128 (op_ptr, &stmp); |
498 | result = stmp; | |
df4b504c | 499 | break; |
500 | ||
501 | case DW_OP_reg0: | |
502 | case DW_OP_reg1: | |
503 | case DW_OP_reg2: | |
504 | case DW_OP_reg3: | |
505 | case DW_OP_reg4: | |
506 | case DW_OP_reg5: | |
507 | case DW_OP_reg6: | |
508 | case DW_OP_reg7: | |
509 | case DW_OP_reg8: | |
510 | case DW_OP_reg9: | |
511 | case DW_OP_reg10: | |
512 | case DW_OP_reg11: | |
513 | case DW_OP_reg12: | |
514 | case DW_OP_reg13: | |
515 | case DW_OP_reg14: | |
516 | case DW_OP_reg15: | |
517 | case DW_OP_reg16: | |
518 | case DW_OP_reg17: | |
519 | case DW_OP_reg18: | |
520 | case DW_OP_reg19: | |
521 | case DW_OP_reg20: | |
522 | case DW_OP_reg21: | |
523 | case DW_OP_reg22: | |
524 | case DW_OP_reg23: | |
525 | case DW_OP_reg24: | |
526 | case DW_OP_reg25: | |
527 | case DW_OP_reg26: | |
528 | case DW_OP_reg27: | |
529 | case DW_OP_reg28: | |
530 | case DW_OP_reg29: | |
531 | case DW_OP_reg30: | |
532 | case DW_OP_reg31: | |
533 | result = _Unwind_GetGR (context, op - DW_OP_reg0); | |
534 | break; | |
535 | case DW_OP_regx: | |
a6398abe | 536 | op_ptr = read_uleb128 (op_ptr, ®); |
df4b504c | 537 | result = _Unwind_GetGR (context, reg); |
538 | break; | |
539 | ||
540 | case DW_OP_breg0: | |
541 | case DW_OP_breg1: | |
542 | case DW_OP_breg2: | |
543 | case DW_OP_breg3: | |
544 | case DW_OP_breg4: | |
545 | case DW_OP_breg5: | |
546 | case DW_OP_breg6: | |
547 | case DW_OP_breg7: | |
548 | case DW_OP_breg8: | |
549 | case DW_OP_breg9: | |
550 | case DW_OP_breg10: | |
551 | case DW_OP_breg11: | |
552 | case DW_OP_breg12: | |
553 | case DW_OP_breg13: | |
554 | case DW_OP_breg14: | |
555 | case DW_OP_breg15: | |
556 | case DW_OP_breg16: | |
557 | case DW_OP_breg17: | |
558 | case DW_OP_breg18: | |
559 | case DW_OP_breg19: | |
560 | case DW_OP_breg20: | |
561 | case DW_OP_breg21: | |
562 | case DW_OP_breg22: | |
563 | case DW_OP_breg23: | |
564 | case DW_OP_breg24: | |
565 | case DW_OP_breg25: | |
566 | case DW_OP_breg26: | |
567 | case DW_OP_breg27: | |
568 | case DW_OP_breg28: | |
569 | case DW_OP_breg29: | |
570 | case DW_OP_breg30: | |
571 | case DW_OP_breg31: | |
a6398abe | 572 | op_ptr = read_sleb128 (op_ptr, &offset); |
df4b504c | 573 | result = _Unwind_GetGR (context, op - DW_OP_breg0) + offset; |
574 | break; | |
575 | case DW_OP_bregx: | |
a6398abe | 576 | op_ptr = read_uleb128 (op_ptr, ®); |
577 | op_ptr = read_sleb128 (op_ptr, &offset); | |
df4b504c | 578 | result = _Unwind_GetGR (context, reg) + offset; |
579 | break; | |
580 | ||
581 | case DW_OP_dup: | |
51536141 | 582 | gcc_assert (stack_elt); |
df4b504c | 583 | result = stack[stack_elt - 1]; |
584 | break; | |
585 | ||
586 | case DW_OP_drop: | |
51536141 | 587 | gcc_assert (stack_elt); |
588 | stack_elt -= 1; | |
df4b504c | 589 | goto no_push; |
590 | ||
591 | case DW_OP_pick: | |
592 | offset = *op_ptr++; | |
51536141 | 593 | gcc_assert (offset < stack_elt - 1); |
df4b504c | 594 | result = stack[stack_elt - 1 - offset]; |
595 | break; | |
596 | ||
597 | case DW_OP_over: | |
51536141 | 598 | gcc_assert (stack_elt >= 2); |
df4b504c | 599 | result = stack[stack_elt - 2]; |
600 | break; | |
601 | ||
602 | case DW_OP_rot: | |
603 | { | |
604 | _Unwind_Word t1, t2, t3; | |
605 | ||
51536141 | 606 | gcc_assert (stack_elt >= 3); |
df4b504c | 607 | t1 = stack[stack_elt - 1]; |
608 | t2 = stack[stack_elt - 2]; | |
609 | t3 = stack[stack_elt - 3]; | |
610 | stack[stack_elt - 1] = t2; | |
611 | stack[stack_elt - 2] = t3; | |
612 | stack[stack_elt - 3] = t1; | |
613 | goto no_push; | |
614 | } | |
615 | ||
616 | case DW_OP_deref: | |
617 | case DW_OP_deref_size: | |
618 | case DW_OP_abs: | |
619 | case DW_OP_neg: | |
620 | case DW_OP_not: | |
621 | case DW_OP_plus_uconst: | |
622 | /* Unary operations. */ | |
51536141 | 623 | gcc_assert (stack_elt); |
624 | stack_elt -= 1; | |
625 | ||
df4b504c | 626 | result = stack[stack_elt]; |
627 | ||
628 | switch (op) | |
629 | { | |
630 | case DW_OP_deref: | |
631 | { | |
ac0c7fb1 | 632 | void *ptr = (void *) (_Unwind_Ptr) result; |
df4b504c | 633 | result = (_Unwind_Ptr) read_pointer (ptr); |
634 | } | |
635 | break; | |
636 | ||
637 | case DW_OP_deref_size: | |
638 | { | |
ac0c7fb1 | 639 | void *ptr = (void *) (_Unwind_Ptr) result; |
df4b504c | 640 | switch (*op_ptr++) |
641 | { | |
642 | case 1: | |
643 | result = read_1u (ptr); | |
644 | break; | |
645 | case 2: | |
646 | result = read_2u (ptr); | |
647 | break; | |
648 | case 4: | |
649 | result = read_4u (ptr); | |
650 | break; | |
651 | case 8: | |
652 | result = read_8u (ptr); | |
653 | break; | |
654 | default: | |
51536141 | 655 | gcc_unreachable (); |
df4b504c | 656 | } |
657 | } | |
658 | break; | |
659 | ||
660 | case DW_OP_abs: | |
661 | if ((_Unwind_Sword) result < 0) | |
662 | result = -result; | |
663 | break; | |
664 | case DW_OP_neg: | |
665 | result = -result; | |
666 | break; | |
667 | case DW_OP_not: | |
668 | result = ~result; | |
669 | break; | |
670 | case DW_OP_plus_uconst: | |
a6398abe | 671 | op_ptr = read_uleb128 (op_ptr, &utmp); |
672 | result += utmp; | |
df4b504c | 673 | break; |
4edf665d | 674 | |
675 | default: | |
51536141 | 676 | gcc_unreachable (); |
df4b504c | 677 | } |
678 | break; | |
679 | ||
680 | case DW_OP_and: | |
681 | case DW_OP_div: | |
682 | case DW_OP_minus: | |
683 | case DW_OP_mod: | |
684 | case DW_OP_mul: | |
685 | case DW_OP_or: | |
686 | case DW_OP_plus: | |
89640de2 | 687 | case DW_OP_shl: |
688 | case DW_OP_shr: | |
689 | case DW_OP_shra: | |
690 | case DW_OP_xor: | |
df4b504c | 691 | case DW_OP_le: |
692 | case DW_OP_ge: | |
693 | case DW_OP_eq: | |
694 | case DW_OP_lt: | |
695 | case DW_OP_gt: | |
696 | case DW_OP_ne: | |
697 | { | |
698 | /* Binary operations. */ | |
699 | _Unwind_Word first, second; | |
51536141 | 700 | gcc_assert (stack_elt >= 2); |
701 | stack_elt -= 2; | |
702 | ||
6c34d0c2 | 703 | second = stack[stack_elt]; |
704 | first = stack[stack_elt + 1]; | |
705 | ||
706 | switch (op) | |
707 | { | |
708 | case DW_OP_and: | |
709 | result = second & first; | |
710 | break; | |
711 | case DW_OP_div: | |
712 | result = (_Unwind_Sword) second / (_Unwind_Sword) first; | |
713 | break; | |
714 | case DW_OP_minus: | |
715 | result = second - first; | |
716 | break; | |
717 | case DW_OP_mod: | |
718 | result = (_Unwind_Sword) second % (_Unwind_Sword) first; | |
719 | break; | |
720 | case DW_OP_mul: | |
721 | result = second * first; | |
722 | break; | |
723 | case DW_OP_or: | |
724 | result = second | first; | |
725 | break; | |
726 | case DW_OP_plus: | |
727 | result = second + first; | |
728 | break; | |
729 | case DW_OP_shl: | |
730 | result = second << first; | |
731 | break; | |
732 | case DW_OP_shr: | |
733 | result = second >> first; | |
734 | break; | |
735 | case DW_OP_shra: | |
736 | result = (_Unwind_Sword) second >> first; | |
737 | break; | |
738 | case DW_OP_xor: | |
739 | result = second ^ first; | |
740 | break; | |
741 | case DW_OP_le: | |
742 | result = (_Unwind_Sword) first <= (_Unwind_Sword) second; | |
743 | break; | |
744 | case DW_OP_ge: | |
745 | result = (_Unwind_Sword) first >= (_Unwind_Sword) second; | |
746 | break; | |
747 | case DW_OP_eq: | |
748 | result = (_Unwind_Sword) first == (_Unwind_Sword) second; | |
749 | break; | |
750 | case DW_OP_lt: | |
751 | result = (_Unwind_Sword) first < (_Unwind_Sword) second; | |
752 | break; | |
753 | case DW_OP_gt: | |
754 | result = (_Unwind_Sword) first > (_Unwind_Sword) second; | |
755 | break; | |
756 | case DW_OP_ne: | |
757 | result = (_Unwind_Sword) first != (_Unwind_Sword) second; | |
758 | break; | |
759 | ||
760 | default: | |
51536141 | 761 | gcc_unreachable (); |
6c34d0c2 | 762 | } |
df4b504c | 763 | } |
764 | break; | |
765 | ||
766 | case DW_OP_skip: | |
767 | offset = read_2s (op_ptr); | |
768 | op_ptr += 2; | |
769 | op_ptr += offset; | |
770 | goto no_push; | |
771 | ||
772 | case DW_OP_bra: | |
51536141 | 773 | gcc_assert (stack_elt); |
774 | stack_elt -= 1; | |
775 | ||
df4b504c | 776 | offset = read_2s (op_ptr); |
777 | op_ptr += 2; | |
778 | if (stack[stack_elt] != 0) | |
779 | op_ptr += offset; | |
780 | goto no_push; | |
781 | ||
782 | case DW_OP_nop: | |
783 | goto no_push; | |
784 | ||
785 | default: | |
51536141 | 786 | gcc_unreachable (); |
df4b504c | 787 | } |
788 | ||
789 | /* Most things push a result value. */ | |
51536141 | 790 | gcc_assert ((size_t) stack_elt < sizeof(stack)/sizeof(*stack)); |
f8f023a5 | 791 | stack[stack_elt++] = result; |
df4b504c | 792 | no_push:; |
793 | } | |
794 | ||
795 | /* We were executing this program to get a value. It should be | |
796 | at top of stack. */ | |
51536141 | 797 | gcc_assert (stack_elt); |
798 | stack_elt -= 1; | |
df4b504c | 799 | return stack[stack_elt]; |
800 | } | |
801 | ||
802 | ||
803 | /* Decode DWARF 2 call frame information. Takes pointers the | |
804 | instruction sequence to decode, current register information and | |
805 | CIE info, and the PC range to evaluate. */ | |
806 | ||
807 | static void | |
9b84bf7d | 808 | execute_cfa_program (const unsigned char *insn_ptr, |
809 | const unsigned char *insn_end, | |
810 | struct _Unwind_Context *context, | |
811 | _Unwind_FrameState *fs) | |
df4b504c | 812 | { |
813 | struct frame_state_reg_info *unused_rs = NULL; | |
814 | ||
815 | /* Don't allow remember/restore between CIE and FDE programs. */ | |
816 | fs->regs.prev = NULL; | |
817 | ||
f2c8b8e7 | 818 | /* The comparison with the return address uses < rather than <= because |
819 | we are only interested in the effects of code before the call; for a | |
820 | noreturn function, the return address may point to unrelated code with | |
821 | a different stack configuration that we are not interested in. We | |
822 | assume that the call itself is unwind info-neutral; if not, or if | |
823 | there are delay instructions that adjust the stack, these must be | |
15c73eb7 | 824 | reflected at the point immediately before the call insn. |
825 | In signal frames, return address is after last completed instruction, | |
826 | so we add 1 to return address to make the comparison <=. */ | |
827 | while (insn_ptr < insn_end && fs->pc < context->ra + context->signal_frame) | |
df4b504c | 828 | { |
829 | unsigned char insn = *insn_ptr++; | |
a6398abe | 830 | _Unwind_Word reg, utmp; |
831 | _Unwind_Sword offset, stmp; | |
df4b504c | 832 | |
fc8b707b | 833 | if ((insn & 0xc0) == DW_CFA_advance_loc) |
df4b504c | 834 | fs->pc += (insn & 0x3f) * fs->code_align; |
fc8b707b | 835 | else if ((insn & 0xc0) == DW_CFA_offset) |
df4b504c | 836 | { |
837 | reg = insn & 0x3f; | |
a6398abe | 838 | insn_ptr = read_uleb128 (insn_ptr, &utmp); |
188879e7 | 839 | offset = (_Unwind_Sword) utmp * fs->data_align; |
e92aec9e | 840 | fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how |
841 | = REG_SAVED_OFFSET; | |
842 | fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = offset; | |
df4b504c | 843 | } |
fc8b707b | 844 | else if ((insn & 0xc0) == DW_CFA_restore) |
df4b504c | 845 | { |
846 | reg = insn & 0x3f; | |
e92aec9e | 847 | fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how = REG_UNSAVED; |
df4b504c | 848 | } |
849 | else switch (insn) | |
850 | { | |
851 | case DW_CFA_set_loc: | |
fa29d733 | 852 | { |
853 | _Unwind_Ptr pc; | |
854 | ||
855 | insn_ptr = read_encoded_value (context, fs->fde_encoding, | |
856 | insn_ptr, &pc); | |
857 | fs->pc = (void *) pc; | |
858 | } | |
df4b504c | 859 | break; |
860 | ||
861 | case DW_CFA_advance_loc1: | |
b92c85dc | 862 | fs->pc += read_1u (insn_ptr) * fs->code_align; |
df4b504c | 863 | insn_ptr += 1; |
864 | break; | |
865 | case DW_CFA_advance_loc2: | |
b92c85dc | 866 | fs->pc += read_2u (insn_ptr) * fs->code_align; |
df4b504c | 867 | insn_ptr += 2; |
868 | break; | |
869 | case DW_CFA_advance_loc4: | |
b92c85dc | 870 | fs->pc += read_4u (insn_ptr) * fs->code_align; |
df4b504c | 871 | insn_ptr += 4; |
872 | break; | |
873 | ||
874 | case DW_CFA_offset_extended: | |
a6398abe | 875 | insn_ptr = read_uleb128 (insn_ptr, ®); |
876 | insn_ptr = read_uleb128 (insn_ptr, &utmp); | |
188879e7 | 877 | offset = (_Unwind_Sword) utmp * fs->data_align; |
e92aec9e | 878 | fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how |
879 | = REG_SAVED_OFFSET; | |
880 | fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = offset; | |
df4b504c | 881 | break; |
882 | ||
883 | case DW_CFA_restore_extended: | |
a6398abe | 884 | insn_ptr = read_uleb128 (insn_ptr, ®); |
60ea93bb | 885 | /* FIXME, this is wrong; the CIE might have said that the |
886 | register was saved somewhere. */ | |
e92aec9e | 887 | fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN(reg)].how = REG_UNSAVED; |
df4b504c | 888 | break; |
889 | ||
890 | case DW_CFA_undefined: | |
891 | case DW_CFA_same_value: | |
3a258605 | 892 | insn_ptr = read_uleb128 (insn_ptr, ®); |
60ea93bb | 893 | fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN(reg)].how = REG_UNSAVED; |
3a258605 | 894 | break; |
895 | ||
df4b504c | 896 | case DW_CFA_nop: |
897 | break; | |
898 | ||
899 | case DW_CFA_register: | |
900 | { | |
901 | _Unwind_Word reg2; | |
a6398abe | 902 | insn_ptr = read_uleb128 (insn_ptr, ®); |
903 | insn_ptr = read_uleb128 (insn_ptr, ®2); | |
e92aec9e | 904 | fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how = REG_SAVED_REG; |
905 | fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.reg = reg2; | |
df4b504c | 906 | } |
907 | break; | |
6c34d0c2 | 908 | |
df4b504c | 909 | case DW_CFA_remember_state: |
910 | { | |
911 | struct frame_state_reg_info *new_rs; | |
912 | if (unused_rs) | |
913 | { | |
914 | new_rs = unused_rs; | |
915 | unused_rs = unused_rs->prev; | |
916 | } | |
917 | else | |
14f9c168 | 918 | new_rs = alloca (sizeof (struct frame_state_reg_info)); |
df4b504c | 919 | |
920 | *new_rs = fs->regs; | |
921 | fs->regs.prev = new_rs; | |
922 | } | |
923 | break; | |
924 | ||
925 | case DW_CFA_restore_state: | |
926 | { | |
927 | struct frame_state_reg_info *old_rs = fs->regs.prev; | |
928 | fs->regs = *old_rs; | |
929 | old_rs->prev = unused_rs; | |
930 | unused_rs = old_rs; | |
931 | } | |
932 | break; | |
933 | ||
934 | case DW_CFA_def_cfa: | |
ad430e37 | 935 | insn_ptr = read_uleb128 (insn_ptr, &fs->regs.cfa_reg); |
a6398abe | 936 | insn_ptr = read_uleb128 (insn_ptr, &utmp); |
ad430e37 | 937 | fs->regs.cfa_offset = utmp; |
938 | fs->regs.cfa_how = CFA_REG_OFFSET; | |
df4b504c | 939 | break; |
940 | ||
941 | case DW_CFA_def_cfa_register: | |
ad430e37 | 942 | insn_ptr = read_uleb128 (insn_ptr, &fs->regs.cfa_reg); |
943 | fs->regs.cfa_how = CFA_REG_OFFSET; | |
df4b504c | 944 | break; |
945 | ||
946 | case DW_CFA_def_cfa_offset: | |
a6398abe | 947 | insn_ptr = read_uleb128 (insn_ptr, &utmp); |
ad430e37 | 948 | fs->regs.cfa_offset = utmp; |
df4b504c | 949 | /* cfa_how deliberately not set. */ |
950 | break; | |
951 | ||
952 | case DW_CFA_def_cfa_expression: | |
ad430e37 | 953 | fs->regs.cfa_exp = insn_ptr; |
954 | fs->regs.cfa_how = CFA_EXP; | |
f8f023a5 | 955 | insn_ptr = read_uleb128 (insn_ptr, &utmp); |
a6398abe | 956 | insn_ptr += utmp; |
df4b504c | 957 | break; |
958 | ||
959 | case DW_CFA_expression: | |
a6398abe | 960 | insn_ptr = read_uleb128 (insn_ptr, ®); |
e92aec9e | 961 | fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how = REG_SAVED_EXP; |
962 | fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.exp = insn_ptr; | |
f8f023a5 | 963 | insn_ptr = read_uleb128 (insn_ptr, &utmp); |
a6398abe | 964 | insn_ptr += utmp; |
df4b504c | 965 | break; |
966 | ||
706f0818 | 967 | /* Dwarf3. */ |
df4b504c | 968 | case DW_CFA_offset_extended_sf: |
a6398abe | 969 | insn_ptr = read_uleb128 (insn_ptr, ®); |
970 | insn_ptr = read_sleb128 (insn_ptr, &stmp); | |
971 | offset = stmp * fs->data_align; | |
e92aec9e | 972 | fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how |
973 | = REG_SAVED_OFFSET; | |
974 | fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = offset; | |
df4b504c | 975 | break; |
6c34d0c2 | 976 | |
df4b504c | 977 | case DW_CFA_def_cfa_sf: |
ad430e37 | 978 | insn_ptr = read_uleb128 (insn_ptr, &fs->regs.cfa_reg); |
979 | insn_ptr = read_sleb128 (insn_ptr, &fs->regs.cfa_offset); | |
980 | fs->regs.cfa_how = CFA_REG_OFFSET; | |
981 | fs->regs.cfa_offset *= fs->data_align; | |
df4b504c | 982 | break; |
983 | ||
984 | case DW_CFA_def_cfa_offset_sf: | |
ad430e37 | 985 | insn_ptr = read_sleb128 (insn_ptr, &fs->regs.cfa_offset); |
986 | fs->regs.cfa_offset *= fs->data_align; | |
df4b504c | 987 | /* cfa_how deliberately not set. */ |
988 | break; | |
989 | ||
706f0818 | 990 | case DW_CFA_val_offset: |
991 | insn_ptr = read_uleb128 (insn_ptr, ®); | |
992 | insn_ptr = read_uleb128 (insn_ptr, &utmp); | |
993 | offset = (_Unwind_Sword) utmp * fs->data_align; | |
994 | fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how | |
995 | = REG_SAVED_VAL_OFFSET; | |
996 | fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = offset; | |
997 | break; | |
998 | ||
999 | case DW_CFA_val_offset_sf: | |
1000 | insn_ptr = read_uleb128 (insn_ptr, ®); | |
1001 | insn_ptr = read_sleb128 (insn_ptr, &stmp); | |
1002 | offset = stmp * fs->data_align; | |
1003 | fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how | |
1004 | = REG_SAVED_VAL_OFFSET; | |
1005 | fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = offset; | |
1006 | break; | |
1007 | ||
1008 | case DW_CFA_val_expression: | |
1009 | insn_ptr = read_uleb128 (insn_ptr, ®); | |
1010 | fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how | |
1011 | = REG_SAVED_VAL_EXP; | |
1012 | fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.exp = insn_ptr; | |
1013 | insn_ptr = read_uleb128 (insn_ptr, &utmp); | |
1014 | insn_ptr += utmp; | |
1015 | break; | |
1016 | ||
df4b504c | 1017 | case DW_CFA_GNU_window_save: |
1018 | /* ??? Hardcoded for SPARC register window configuration. */ | |
1019 | for (reg = 16; reg < 32; ++reg) | |
1020 | { | |
1021 | fs->regs.reg[reg].how = REG_SAVED_OFFSET; | |
1022 | fs->regs.reg[reg].loc.offset = (reg - 16) * sizeof (void *); | |
1023 | } | |
1024 | break; | |
1025 | ||
1026 | case DW_CFA_GNU_args_size: | |
a6398abe | 1027 | insn_ptr = read_uleb128 (insn_ptr, &context->args_size); |
df4b504c | 1028 | break; |
1029 | ||
1030 | case DW_CFA_GNU_negative_offset_extended: | |
1031 | /* Obsoleted by DW_CFA_offset_extended_sf, but used by | |
1032 | older PowerPC code. */ | |
a6398abe | 1033 | insn_ptr = read_uleb128 (insn_ptr, ®); |
1034 | insn_ptr = read_uleb128 (insn_ptr, &utmp); | |
188879e7 | 1035 | offset = (_Unwind_Word) utmp * fs->data_align; |
e92aec9e | 1036 | fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how |
1037 | = REG_SAVED_OFFSET; | |
1038 | fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = -offset; | |
df4b504c | 1039 | break; |
1040 | ||
1041 | default: | |
51536141 | 1042 | gcc_unreachable (); |
df4b504c | 1043 | } |
1044 | } | |
1045 | } | |
1046 | \f | |
9081a51e | 1047 | /* Given the _Unwind_Context CONTEXT for a stack frame, look up the FDE for |
1048 | its caller and decode it into FS. This function also sets the | |
1049 | args_size and lsda members of CONTEXT, as they are really information | |
1050 | about the caller's frame. */ | |
1051 | ||
df4b504c | 1052 | static _Unwind_Reason_Code |
1053 | uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs) | |
1054 | { | |
358738f4 | 1055 | const struct dwarf_fde *fde; |
1056 | const struct dwarf_cie *cie; | |
9b84bf7d | 1057 | const unsigned char *aug, *insn, *end; |
df4b504c | 1058 | |
1059 | memset (fs, 0, sizeof (*fs)); | |
1060 | context->args_size = 0; | |
1061 | context->lsda = 0; | |
1062 | ||
c49ad9ef | 1063 | if (context->ra == 0) |
1064 | return _URC_END_OF_STACK; | |
1065 | ||
15c73eb7 | 1066 | fde = _Unwind_Find_FDE (context->ra + context->signal_frame - 1, |
1067 | &context->bases); | |
df4b504c | 1068 | if (fde == NULL) |
1069 | { | |
aebd6cb6 | 1070 | #ifdef MD_FALLBACK_FRAME_STATE_FOR |
df4b504c | 1071 | /* Couldn't find frame unwind info for this function. Try a |
1072 | target-specific fallback mechanism. This will necessarily | |
b9fe4edd | 1073 | not provide a personality routine or LSDA. */ |
aebd6cb6 | 1074 | return MD_FALLBACK_FRAME_STATE_FOR (context, fs); |
df4b504c | 1075 | #else |
1076 | return _URC_END_OF_STACK; | |
1077 | #endif | |
1078 | } | |
1079 | ||
9b84bf7d | 1080 | fs->pc = context->bases.func; |
df4b504c | 1081 | |
1082 | cie = get_cie (fde); | |
1083 | insn = extract_cie_info (cie, context, fs); | |
1084 | if (insn == NULL) | |
1085 | /* CIE contained unknown augmentation. */ | |
1086 | return _URC_FATAL_PHASE1_ERROR; | |
1087 | ||
1088 | /* First decode all the insns in the CIE. */ | |
1089 | end = (unsigned char *) next_fde ((struct dwarf_fde *) cie); | |
1090 | execute_cfa_program (insn, end, context, fs); | |
1091 | ||
1092 | /* Locate augmentation for the fde. */ | |
188879e7 | 1093 | aug = (unsigned char *) fde + sizeof (*fde); |
9b84bf7d | 1094 | aug += 2 * size_of_encoded_value (fs->fde_encoding); |
df4b504c | 1095 | insn = NULL; |
1096 | if (fs->saw_z) | |
1097 | { | |
a6398abe | 1098 | _Unwind_Word i; |
df4b504c | 1099 | aug = read_uleb128 (aug, &i); |
1100 | insn = aug + i; | |
1101 | } | |
9b84bf7d | 1102 | if (fs->lsda_encoding != DW_EH_PE_omit) |
fa29d733 | 1103 | { |
1104 | _Unwind_Ptr lsda; | |
1105 | ||
1106 | aug = read_encoded_value (context, fs->lsda_encoding, aug, &lsda); | |
1107 | context->lsda = (void *) lsda; | |
1108 | } | |
df4b504c | 1109 | |
1110 | /* Then the insns in the FDE up to our target PC. */ | |
1111 | if (insn == NULL) | |
1112 | insn = aug; | |
1113 | end = (unsigned char *) next_fde (fde); | |
1114 | execute_cfa_program (insn, end, context, fs); | |
1115 | ||
1116 | return _URC_NO_REASON; | |
1117 | } | |
44b157cf | 1118 | \f |
1119 | typedef struct frame_state | |
1120 | { | |
1121 | void *cfa; | |
1122 | void *eh_ptr; | |
1123 | long cfa_offset; | |
1124 | long args_size; | |
ba7065a9 | 1125 | long reg_or_offset[PRE_GCC3_DWARF_FRAME_REGISTERS+1]; |
44b157cf | 1126 | unsigned short cfa_reg; |
1127 | unsigned short retaddr_column; | |
ba7065a9 | 1128 | char saved[PRE_GCC3_DWARF_FRAME_REGISTERS+1]; |
44b157cf | 1129 | } frame_state; |
1130 | ||
1131 | struct frame_state * __frame_state_for (void *, struct frame_state *); | |
1132 | ||
1133 | /* Called from pre-G++ 3.0 __throw to find the registers to restore for | |
1134 | a given PC_TARGET. The caller should allocate a local variable of | |
1135 | `struct frame_state' and pass its address to STATE_IN. */ | |
1136 | ||
1137 | struct frame_state * | |
1138 | __frame_state_for (void *pc_target, struct frame_state *state_in) | |
1139 | { | |
1140 | struct _Unwind_Context context; | |
1141 | _Unwind_FrameState fs; | |
1142 | int reg; | |
1143 | ||
1144 | memset (&context, 0, sizeof (struct _Unwind_Context)); | |
1145 | context.ra = pc_target + 1; | |
1146 | ||
1147 | if (uw_frame_state_for (&context, &fs) != _URC_NO_REASON) | |
1148 | return 0; | |
df4b504c | 1149 | |
44b157cf | 1150 | /* We have no way to pass a location expression for the CFA to our |
1151 | caller. It wouldn't understand it anyway. */ | |
ad430e37 | 1152 | if (fs.regs.cfa_how == CFA_EXP) |
44b157cf | 1153 | return 0; |
df4b504c | 1154 | |
ba7065a9 | 1155 | for (reg = 0; reg < PRE_GCC3_DWARF_FRAME_REGISTERS + 1; reg++) |
44b157cf | 1156 | { |
1157 | state_in->saved[reg] = fs.regs.reg[reg].how; | |
1158 | switch (state_in->saved[reg]) | |
1159 | { | |
1160 | case REG_SAVED_REG: | |
1161 | state_in->reg_or_offset[reg] = fs.regs.reg[reg].loc.reg; | |
1162 | break; | |
1163 | case REG_SAVED_OFFSET: | |
1164 | state_in->reg_or_offset[reg] = fs.regs.reg[reg].loc.offset; | |
1165 | break; | |
1166 | default: | |
1167 | state_in->reg_or_offset[reg] = 0; | |
1168 | break; | |
1169 | } | |
1170 | } | |
1171 | ||
ad430e37 | 1172 | state_in->cfa_offset = fs.regs.cfa_offset; |
1173 | state_in->cfa_reg = fs.regs.cfa_reg; | |
44b157cf | 1174 | state_in->retaddr_column = fs.retaddr_column; |
1175 | state_in->args_size = context.args_size; | |
1176 | state_in->eh_ptr = fs.eh_ptr; | |
1177 | ||
1178 | return state_in; | |
1179 | } | |
1180 | \f | |
5fec5f34 | 1181 | typedef union { _Unwind_Ptr ptr; _Unwind_Word word; } _Unwind_SpTmp; |
1182 | ||
1183 | static inline void | |
1184 | _Unwind_SetSpColumn (struct _Unwind_Context *context, void *cfa, | |
706f0818 | 1185 | _Unwind_SpTmp *tmp_sp) |
5fec5f34 | 1186 | { |
1187 | int size = dwarf_reg_size_table[__builtin_dwarf_sp_column ()]; | |
1188 | ||
1189 | if (size == sizeof(_Unwind_Ptr)) | |
1190 | tmp_sp->ptr = (_Unwind_Ptr) cfa; | |
5fec5f34 | 1191 | else |
51536141 | 1192 | { |
1193 | gcc_assert (size == sizeof(_Unwind_Word)); | |
1194 | tmp_sp->word = (_Unwind_Ptr) cfa; | |
1195 | } | |
5fec5f34 | 1196 | _Unwind_SetGRPtr (context, __builtin_dwarf_sp_column (), tmp_sp); |
1197 | } | |
1198 | ||
df4b504c | 1199 | static void |
1200 | uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs) | |
1201 | { | |
1202 | struct _Unwind_Context orig_context = *context; | |
1203 | void *cfa; | |
1204 | long i; | |
1205 | ||
cd4e2223 | 1206 | #ifdef EH_RETURN_STACKADJ_RTX |
f8f023a5 | 1207 | /* Special handling here: Many machines do not use a frame pointer, |
1208 | and track the CFA only through offsets from the stack pointer from | |
1209 | one frame to the next. In this case, the stack pointer is never | |
1210 | stored, so it has no saved address in the context. What we do | |
1211 | have is the CFA from the previous stack frame. | |
1212 | ||
1213 | In very special situations (such as unwind info for signal return), | |
1214 | there may be location expressions that use the stack pointer as well. | |
1215 | ||
5f60ad01 | 1216 | Do this conditionally for one frame. This allows the unwind info |
1217 | for one frame to save a copy of the stack pointer from the previous | |
1218 | frame, and be able to use much easier CFA mechanisms to do it. | |
1219 | Always zap the saved stack pointer value for the next frame; carrying | |
1220 | the value over from one frame to another doesn't make sense. */ | |
cd4e2223 | 1221 | |
5fec5f34 | 1222 | _Unwind_SpTmp tmp_sp; |
cd4e2223 | 1223 | |
5f60ad01 | 1224 | if (!_Unwind_GetGRPtr (&orig_context, __builtin_dwarf_sp_column ())) |
5fec5f34 | 1225 | _Unwind_SetSpColumn (&orig_context, context->cfa, &tmp_sp); |
5f60ad01 | 1226 | _Unwind_SetGRPtr (context, __builtin_dwarf_sp_column (), NULL); |
cd4e2223 | 1227 | #endif |
f8f023a5 | 1228 | |
df4b504c | 1229 | /* Compute this frame's CFA. */ |
ad430e37 | 1230 | switch (fs->regs.cfa_how) |
df4b504c | 1231 | { |
1232 | case CFA_REG_OFFSET: | |
ad430e37 | 1233 | cfa = _Unwind_GetPtr (&orig_context, fs->regs.cfa_reg); |
1234 | cfa += fs->regs.cfa_offset; | |
df4b504c | 1235 | break; |
1236 | ||
1237 | case CFA_EXP: | |
df4b504c | 1238 | { |
ad430e37 | 1239 | const unsigned char *exp = fs->regs.cfa_exp; |
a6398abe | 1240 | _Unwind_Word len; |
df4b504c | 1241 | |
1242 | exp = read_uleb128 (exp, &len); | |
1243 | cfa = (void *) (_Unwind_Ptr) | |
f8f023a5 | 1244 | execute_stack_op (exp, exp + len, &orig_context, 0); |
df4b504c | 1245 | break; |
1246 | } | |
1247 | ||
1248 | default: | |
51536141 | 1249 | gcc_unreachable (); |
df4b504c | 1250 | } |
1251 | context->cfa = cfa; | |
1252 | ||
1253 | /* Compute the addresses of all registers saved in this frame. */ | |
1254 | for (i = 0; i < DWARF_FRAME_REGISTERS + 1; ++i) | |
1255 | switch (fs->regs.reg[i].how) | |
1256 | { | |
1257 | case REG_UNSAVED: | |
1258 | break; | |
f8f023a5 | 1259 | |
df4b504c | 1260 | case REG_SAVED_OFFSET: |
f8f023a5 | 1261 | _Unwind_SetGRPtr (context, i, |
1262 | (void *) (cfa + fs->regs.reg[i].loc.offset)); | |
df4b504c | 1263 | break; |
f8f023a5 | 1264 | |
df4b504c | 1265 | case REG_SAVED_REG: |
706f0818 | 1266 | if (_Unwind_GRByValue (&orig_context, fs->regs.reg[i].loc.reg)) |
1267 | _Unwind_SetGRValue (context, i, | |
1268 | _Unwind_GetGR (&orig_context, | |
1269 | fs->regs.reg[i].loc.reg)); | |
1270 | else | |
1271 | _Unwind_SetGRPtr (context, i, | |
1272 | _Unwind_GetGRPtr (&orig_context, | |
1273 | fs->regs.reg[i].loc.reg)); | |
df4b504c | 1274 | break; |
f8f023a5 | 1275 | |
df4b504c | 1276 | case REG_SAVED_EXP: |
1277 | { | |
9b84bf7d | 1278 | const unsigned char *exp = fs->regs.reg[i].loc.exp; |
a6398abe | 1279 | _Unwind_Word len; |
df4b504c | 1280 | _Unwind_Ptr val; |
1281 | ||
1282 | exp = read_uleb128 (exp, &len); | |
1283 | val = execute_stack_op (exp, exp + len, &orig_context, | |
1284 | (_Unwind_Ptr) cfa); | |
e92aec9e | 1285 | _Unwind_SetGRPtr (context, i, (void *) val); |
df4b504c | 1286 | } |
1287 | break; | |
706f0818 | 1288 | |
1289 | case REG_SAVED_VAL_OFFSET: | |
1290 | _Unwind_SetGRValue (context, i, | |
1291 | (_Unwind_Internal_Ptr) | |
1292 | (cfa + fs->regs.reg[i].loc.offset)); | |
1293 | break; | |
1294 | ||
1295 | case REG_SAVED_VAL_EXP: | |
1296 | { | |
1297 | const unsigned char *exp = fs->regs.reg[i].loc.exp; | |
1298 | _Unwind_Word len; | |
1299 | _Unwind_Ptr val; | |
1300 | ||
1301 | exp = read_uleb128 (exp, &len); | |
1302 | val = execute_stack_op (exp, exp + len, &orig_context, | |
1303 | (_Unwind_Ptr) cfa); | |
1304 | _Unwind_SetGRValue (context, i, val); | |
1305 | } | |
1306 | break; | |
df4b504c | 1307 | } |
31933f89 | 1308 | |
15c73eb7 | 1309 | context->signal_frame = fs->signal_frame; |
1310 | ||
aebd6cb6 | 1311 | #ifdef MD_FROB_UPDATE_CONTEXT |
31933f89 | 1312 | MD_FROB_UPDATE_CONTEXT (context, fs); |
aebd6cb6 | 1313 | #endif |
df4b504c | 1314 | } |
1315 | ||
9081a51e | 1316 | /* CONTEXT describes the unwind state for a frame, and FS describes the FDE |
1317 | of its caller. Update CONTEXT to refer to the caller as well. Note | |
1318 | that the args_size and lsda members are not updated here, but later in | |
1319 | uw_frame_state_for. */ | |
1320 | ||
df4b504c | 1321 | static void |
1322 | uw_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs) | |
1323 | { | |
1324 | uw_update_context_1 (context, fs); | |
1325 | ||
1326 | /* Compute the return address now, since the return address column | |
1327 | can change from frame to frame. */ | |
1328 | context->ra = __builtin_extract_return_addr | |
5fec5f34 | 1329 | (_Unwind_GetPtr (context, fs->retaddr_column)); |
df4b504c | 1330 | } |
3dd1860b | 1331 | |
1332 | static void | |
1333 | uw_advance_context (struct _Unwind_Context *context, _Unwind_FrameState *fs) | |
1334 | { | |
1335 | uw_update_context (context, fs); | |
1336 | } | |
df4b504c | 1337 | \f |
1338 | /* Fill in CONTEXT for top-of-stack. The only valid registers at this | |
1339 | level will be the return address and the CFA. */ | |
6c34d0c2 | 1340 | |
ac0c7fb1 | 1341 | #define uw_init_context(CONTEXT) \ |
1342 | do \ | |
1343 | { \ | |
1344 | /* Do any necessary initialization to access arbitrary stack frames. \ | |
1345 | On the SPARC, this means flushing the register windows. */ \ | |
1346 | __builtin_unwind_init (); \ | |
1347 | uw_init_context_1 (CONTEXT, __builtin_dwarf_cfa (), \ | |
1348 | __builtin_return_address (0)); \ | |
1349 | } \ | |
1350 | while (0) | |
df4b504c | 1351 | |
5fec5f34 | 1352 | static inline void |
1353 | init_dwarf_reg_size_table (void) | |
1354 | { | |
1355 | __builtin_init_dwarf_reg_size_table (dwarf_reg_size_table); | |
1356 | } | |
1357 | ||
df4b504c | 1358 | static void |
1359 | uw_init_context_1 (struct _Unwind_Context *context, | |
1360 | void *outer_cfa, void *outer_ra) | |
1361 | { | |
1362 | void *ra = __builtin_extract_return_addr (__builtin_return_address (0)); | |
1363 | _Unwind_FrameState fs; | |
5fec5f34 | 1364 | _Unwind_SpTmp sp_slot; |
51536141 | 1365 | _Unwind_Reason_Code code; |
df4b504c | 1366 | |
1367 | memset (context, 0, sizeof (struct _Unwind_Context)); | |
1368 | context->ra = ra; | |
1369 | ||
51536141 | 1370 | code = uw_frame_state_for (context, &fs); |
1371 | gcc_assert (code == _URC_NO_REASON); | |
df4b504c | 1372 | |
5fec5f34 | 1373 | #if __GTHREADS |
1374 | { | |
1375 | static __gthread_once_t once_regsizes = __GTHREAD_ONCE_INIT; | |
1376 | if (__gthread_once (&once_regsizes, init_dwarf_reg_size_table) != 0 | |
1377 | || dwarf_reg_size_table[0] == 0) | |
1378 | init_dwarf_reg_size_table (); | |
1379 | } | |
1380 | #else | |
1381 | if (dwarf_reg_size_table[0] == 0) | |
1382 | init_dwarf_reg_size_table (); | |
1383 | #endif | |
1384 | ||
df4b504c | 1385 | /* Force the frame state to use the known cfa value. */ |
5fec5f34 | 1386 | _Unwind_SetSpColumn (context, outer_cfa, &sp_slot); |
ad430e37 | 1387 | fs.regs.cfa_how = CFA_REG_OFFSET; |
1388 | fs.regs.cfa_reg = __builtin_dwarf_sp_column (); | |
1389 | fs.regs.cfa_offset = 0; | |
df4b504c | 1390 | |
1391 | uw_update_context_1 (context, &fs); | |
1392 | ||
1393 | /* If the return address column was saved in a register in the | |
1394 | initialization context, then we can't see it in the given | |
1395 | call frame data. So have the initialization context tell us. */ | |
1396 | context->ra = __builtin_extract_return_addr (outer_ra); | |
1397 | } | |
1398 | ||
1399 | ||
1400 | /* Install TARGET into CURRENT so that we can return to it. This is a | |
1401 | macro because __builtin_eh_return must be invoked in the context of | |
1402 | our caller. */ | |
1403 | ||
ac0c7fb1 | 1404 | #define uw_install_context(CURRENT, TARGET) \ |
1405 | do \ | |
1406 | { \ | |
1407 | long offset = uw_install_context_1 ((CURRENT), (TARGET)); \ | |
1408 | void *handler = __builtin_frob_return_addr ((TARGET)->ra); \ | |
1409 | __builtin_eh_return (offset, handler); \ | |
1410 | } \ | |
1411 | while (0) | |
df4b504c | 1412 | |
df4b504c | 1413 | static long |
1414 | uw_install_context_1 (struct _Unwind_Context *current, | |
1415 | struct _Unwind_Context *target) | |
1416 | { | |
1417 | long i; | |
34b963d5 | 1418 | _Unwind_SpTmp sp_slot; |
1419 | ||
1420 | /* If the target frame does not have a saved stack pointer, | |
1421 | then set up the target's CFA. */ | |
1422 | if (!_Unwind_GetGRPtr (target, __builtin_dwarf_sp_column ())) | |
706f0818 | 1423 | _Unwind_SetSpColumn (target, target->cfa, &sp_slot); |
df4b504c | 1424 | |
df4b504c | 1425 | for (i = 0; i < DWARF_FRAME_REGISTERS; ++i) |
1426 | { | |
1427 | void *c = current->reg[i]; | |
1428 | void *t = target->reg[i]; | |
e92aec9e | 1429 | |
706f0818 | 1430 | gcc_assert (current->by_value[i] == 0); |
1431 | if (target->by_value[i] && c) | |
1432 | { | |
1433 | _Unwind_Word w; | |
1434 | _Unwind_Ptr p; | |
1435 | if (dwarf_reg_size_table[i] == sizeof (_Unwind_Word)) | |
1436 | { | |
1437 | w = (_Unwind_Internal_Ptr) t; | |
1438 | memcpy (c, &w, sizeof (_Unwind_Word)); | |
1439 | } | |
1440 | else | |
1441 | { | |
1442 | gcc_assert (dwarf_reg_size_table[i] == sizeof (_Unwind_Ptr)); | |
1443 | p = (_Unwind_Internal_Ptr) t; | |
1444 | memcpy (c, &p, sizeof (_Unwind_Ptr)); | |
1445 | } | |
1446 | } | |
1447 | else if (t && c && t != c) | |
df4b504c | 1448 | memcpy (c, t, dwarf_reg_size_table[i]); |
1449 | } | |
1450 | ||
34b963d5 | 1451 | /* If the current frame doesn't have a saved stack pointer, then we |
1452 | need to rely on EH_RETURN_STACKADJ_RTX to get our target stack | |
1453 | pointer value reloaded. */ | |
1454 | if (!_Unwind_GetGRPtr (current, __builtin_dwarf_sp_column ())) | |
1455 | { | |
1456 | void *target_cfa; | |
cd4e2223 | 1457 | |
5fec5f34 | 1458 | target_cfa = _Unwind_GetPtr (target, __builtin_dwarf_sp_column ()); |
34b963d5 | 1459 | |
1460 | /* We adjust SP by the difference between CURRENT and TARGET's CFA. */ | |
1461 | if (STACK_GROWS_DOWNWARD) | |
1462 | return target_cfa - current->cfa + target->args_size; | |
1463 | else | |
1464 | return current->cfa - target_cfa - target->args_size; | |
1465 | } | |
cd4e2223 | 1466 | return 0; |
df4b504c | 1467 | } |
1468 | ||
1469 | static inline _Unwind_Ptr | |
1470 | uw_identify_context (struct _Unwind_Context *context) | |
1471 | { | |
1472 | return _Unwind_GetIP (context); | |
1473 | } | |
1474 | ||
1475 | ||
1476 | #include "unwind.inc" | |
1477 | ||
8bdf23ae | 1478 | #if defined (USE_GAS_SYMVER) && defined (SHARED) && defined (USE_LIBUNWIND_EXCEPTIONS) |
1479 | alias (_Unwind_Backtrace); | |
1480 | alias (_Unwind_DeleteException); | |
1481 | alias (_Unwind_FindEnclosingFunction); | |
8bdf23ae | 1482 | alias (_Unwind_ForcedUnwind); |
1483 | alias (_Unwind_GetDataRelBase); | |
1484 | alias (_Unwind_GetTextRelBase); | |
1485 | alias (_Unwind_GetCFA); | |
1486 | alias (_Unwind_GetGR); | |
1487 | alias (_Unwind_GetIP); | |
1488 | alias (_Unwind_GetLanguageSpecificData); | |
1489 | alias (_Unwind_GetRegionStart); | |
1490 | alias (_Unwind_RaiseException); | |
1491 | alias (_Unwind_Resume); | |
1492 | alias (_Unwind_Resume_or_Rethrow); | |
1493 | alias (_Unwind_SetGR); | |
1494 | alias (_Unwind_SetIP); | |
1495 | #endif | |
1496 | ||
df4b504c | 1497 | #endif /* !USING_SJLJ_EXCEPTIONS */ |