]>
Commit | Line | Data |
---|---|---|
0021b564 JM |
1 | /* Subroutines needed for unwinding stack frames for exception handling. */ |
2 | /* Compile this one with gcc. */ | |
3e2a2957 | 3 | /* Copyright (C) 1997, 1998 Free Software Foundation, Inc. |
0021b564 JM |
4 | Contributed by Jason Merrill <jason@cygnus.com>. |
5 | ||
6 | This file is part of GNU CC. | |
7 | ||
8 | GNU CC is free software; you can redistribute it and/or modify | |
9 | it under the terms of the GNU General Public License as published by | |
10 | the Free Software Foundation; either version 2, or (at your option) | |
11 | any later version. | |
12 | ||
13 | GNU CC is distributed in the hope that it will be useful, | |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | GNU General Public License for more details. | |
17 | ||
18 | You should have received a copy of the GNU General Public License | |
19 | along with GNU CC; see the file COPYING. If not, write to | |
20 | the Free Software Foundation, 59 Temple Place - Suite 330, | |
21 | Boston, MA 02111-1307, USA. */ | |
22 | ||
23 | /* As a special exception, if you link this library with other files, | |
24 | some of which are compiled with GCC, to produce an executable, | |
25 | this library does not by itself cause the resulting executable | |
26 | to be covered by the GNU General Public License. | |
27 | This exception does not however invalidate any other reasons why | |
28 | the executable file might be covered by the GNU General Public License. */ | |
29 | ||
30 | /* It is incorrect to include config.h here, because this file is being | |
31 | compiled for the target, and hence definitions concerning only the host | |
32 | do not apply. */ | |
33 | ||
34 | #include "tconfig.h" | |
2467749d | 35 | |
f1f53f0b JW |
36 | /* We disable this when inhibit_libc, so that gcc can still be built without |
37 | needing header files first. */ | |
38 | /* ??? This is not a good solution, since prototypes may be required in | |
39 | some cases for correct code. See also libgcc2.c. */ | |
40 | #ifndef inhibit_libc | |
2467749d KG |
41 | /* fixproto guarantees these system headers exist. */ |
42 | #include <stdlib.h> | |
43 | #include <unistd.h> | |
f1f53f0b | 44 | #endif |
2467749d | 45 | |
0021b564 JM |
46 | #include "defaults.h" |
47 | ||
48 | #ifdef DWARF2_UNWIND_INFO | |
49 | #include "dwarf2.h" | |
0021b564 | 50 | #include <stddef.h> |
956d6950 | 51 | #include "frame.h" |
f24af81b | 52 | #include "gthr.h" |
154bba13 TT |
53 | |
54 | #ifdef __GTHREAD_MUTEX_INIT | |
55 | static __gthread_mutex_t object_mutex = __GTHREAD_MUTEX_INIT; | |
56 | #else | |
57 | static __gthread_mutex_t object_mutex; | |
58 | #endif | |
0021b564 JM |
59 | |
60 | /* Don't use `fancy_abort' here even if config.h says to use it. */ | |
61 | #ifdef abort | |
62 | #undef abort | |
63 | #endif | |
64 | ||
65 | /* Some types used by the DWARF 2 spec. */ | |
66 | ||
d84e64d4 JM |
67 | typedef int sword __attribute__ ((mode (SI))); |
68 | typedef unsigned int uword __attribute__ ((mode (SI))); | |
69 | typedef unsigned int uaddr __attribute__ ((mode (pointer))); | |
70 | typedef int saddr __attribute__ ((mode (pointer))); | |
0021b564 JM |
71 | typedef unsigned char ubyte; |
72 | ||
ccb5954f ML |
73 | /* Terminology: |
74 | CIE - Common Information Element | |
75 | FDE - Frame Descriptor Element | |
76 | ||
77 | There is one per function, and it describes where the function code | |
78 | is located, and what the register lifetimes and stack layout are | |
79 | within the function. | |
80 | ||
81 | The data structures are defined in the DWARF specfication, although | |
82 | not in a very readable way (see LITERATURE). | |
83 | ||
84 | Every time an exception is thrown, the code needs to locate the FDE | |
85 | for the current function, and starts to look for exception regions | |
86 | from that FDE. This works in a two-level search: | |
87 | a) in a linear search, find the shared image (i.e. DLL) containing | |
88 | the PC | |
89 | b) using the FDE table for that shared object, locate the FDE using | |
90 | binary search (which requires the sorting). */ | |
91 | ||
9605fb44 | 92 | /* The first few fields of a CIE. The CIE_id field is 0 for a CIE, |
0021b564 JM |
93 | to distinguish it from a valid FDE. FDEs are aligned to an addressing |
94 | unit boundary, but the fields within are unaligned. */ | |
95 | ||
96 | struct dwarf_cie { | |
97 | uword length; | |
d84e64d4 | 98 | sword CIE_id; |
0021b564 JM |
99 | ubyte version; |
100 | char augmentation[0]; | |
101 | } __attribute__ ((packed, aligned (__alignof__ (void *)))); | |
102 | ||
103 | /* The first few fields of an FDE. */ | |
104 | ||
105 | struct dwarf_fde { | |
106 | uword length; | |
d84e64d4 | 107 | sword CIE_delta; |
0021b564 JM |
108 | void* pc_begin; |
109 | uaddr pc_range; | |
110 | } __attribute__ ((packed, aligned (__alignof__ (void *)))); | |
111 | ||
112 | typedef struct dwarf_fde fde; | |
113 | ||
956d6950 | 114 | /* Objects to be searched for frame unwind info. */ |
0021b564 JM |
115 | |
116 | static struct object *objects; | |
117 | ||
118 | /* The information we care about from a CIE. */ | |
119 | ||
120 | struct cie_info { | |
121 | char *augmentation; | |
d84e64d4 | 122 | void *eh_ptr; |
0021b564 JM |
123 | int code_align; |
124 | int data_align; | |
125 | unsigned ra_regno; | |
126 | }; | |
127 | ||
128 | /* The current unwind state, plus a saved copy for DW_CFA_remember_state. */ | |
129 | ||
130 | struct frame_state_internal | |
131 | { | |
132 | struct frame_state s; | |
133 | struct frame_state_internal *saved_state; | |
134 | }; | |
3e2a2957 TT |
135 | \f |
136 | /* This is undefined below if we need it to be an actual function. */ | |
137 | #define init_object_mutex_once() | |
138 | ||
139 | #if __GTHREADS | |
140 | #ifdef __GTHREAD_MUTEX_INIT_FUNCTION | |
141 | ||
142 | /* Helper for init_object_mutex_once. */ | |
143 | ||
144 | static void | |
145 | init_object_mutex (void) | |
146 | { | |
147 | __GTHREAD_MUTEX_INIT_FUNCTION (&object_mutex); | |
148 | } | |
149 | ||
150 | /* Call this to arrange to initialize the object mutex. */ | |
151 | ||
152 | #undef init_object_mutex_once | |
153 | static void | |
154 | init_object_mutex_once (void) | |
155 | { | |
156 | static __gthread_once_t once = __GTHREAD_ONCE_INIT; | |
157 | __gthread_once (&once, init_object_mutex); | |
158 | } | |
159 | ||
160 | #endif /* __GTHREAD_MUTEX_INIT_FUNCTION */ | |
161 | #endif /* __GTHREADS */ | |
0021b564 JM |
162 | \f |
163 | /* Decode the unsigned LEB128 constant at BUF into the variable pointed to | |
164 | by R, and return the new value of BUF. */ | |
165 | ||
166 | static void * | |
167 | decode_uleb128 (unsigned char *buf, unsigned *r) | |
168 | { | |
169 | unsigned shift = 0; | |
170 | unsigned result = 0; | |
171 | ||
172 | while (1) | |
173 | { | |
174 | unsigned byte = *buf++; | |
175 | result |= (byte & 0x7f) << shift; | |
176 | if ((byte & 0x80) == 0) | |
177 | break; | |
178 | shift += 7; | |
179 | } | |
180 | *r = result; | |
181 | return buf; | |
182 | } | |
183 | ||
184 | /* Decode the signed LEB128 constant at BUF into the variable pointed to | |
185 | by R, and return the new value of BUF. */ | |
186 | ||
187 | static void * | |
188 | decode_sleb128 (unsigned char *buf, int *r) | |
189 | { | |
190 | unsigned shift = 0; | |
191 | unsigned result = 0; | |
192 | unsigned byte; | |
193 | ||
194 | while (1) | |
195 | { | |
196 | byte = *buf++; | |
197 | result |= (byte & 0x7f) << shift; | |
198 | shift += 7; | |
199 | if ((byte & 0x80) == 0) | |
200 | break; | |
201 | } | |
202 | if (shift < (sizeof (*r) * 8) && (byte & 0x40) != 0) | |
203 | result |= - (1 << shift); | |
204 | ||
205 | *r = result; | |
206 | return buf; | |
207 | } | |
208 | ||
209 | /* Read unaligned data from the instruction buffer. */ | |
210 | ||
211 | union unaligned { | |
212 | void *p; | |
213 | unsigned b2 __attribute__ ((mode (HI))); | |
214 | unsigned b4 __attribute__ ((mode (SI))); | |
215 | unsigned b8 __attribute__ ((mode (DI))); | |
216 | } __attribute__ ((packed)); | |
217 | static inline void * | |
218 | read_pointer (void *p) | |
219 | { union unaligned *up = p; return up->p; } | |
220 | static inline unsigned | |
221 | read_1byte (void *p) | |
222 | { return *(unsigned char *)p; } | |
223 | static inline unsigned | |
224 | read_2byte (void *p) | |
225 | { union unaligned *up = p; return up->b2; } | |
226 | static inline unsigned | |
227 | read_4byte (void *p) | |
228 | { union unaligned *up = p; return up->b4; } | |
229 | static inline unsigned long | |
230 | read_8byte (void *p) | |
231 | { union unaligned *up = p; return up->b8; } | |
232 | \f | |
233 | /* Ordering function for FDEs. Functions can't overlap, so we just compare | |
234 | their starting addresses. */ | |
235 | ||
236 | static inline saddr | |
237 | fde_compare (fde *x, fde *y) | |
238 | { | |
239 | return (saddr)x->pc_begin - (saddr)y->pc_begin; | |
240 | } | |
241 | ||
242 | /* Return the address of the FDE after P. */ | |
243 | ||
244 | static inline fde * | |
245 | next_fde (fde *p) | |
246 | { | |
247 | return (fde *)(((char *)p) + p->length + sizeof (p->length)); | |
248 | } | |
249 | ||
72dd050a BH |
250 | /* Sorting an array of FDEs by address. |
251 | (Ideally we would have the linker sort the FDEs so we don't have to do | |
252 | it at run time. But the linkers are not yet prepared for this.) */ | |
253 | ||
254 | /* This is a special mix of insertion sort and heap sort, optimized for | |
255 | the data sets that actually occur. They look like | |
256 | 101 102 103 127 128 105 108 110 190 111 115 119 125 160 126 129 130. | |
257 | I.e. a linearly increasing sequence (coming from functions in the text | |
258 | section), with additionally a few unordered elements (coming from functions | |
259 | in gnu_linkonce sections) whose values are higher than the values in the | |
260 | surrounding linear sequence (but not necessarily higher than the values | |
261 | at the end of the linear sequence!). | |
262 | The worst-case total run time is O(N) + O(n log (n)), where N is the | |
263 | total number of FDEs and n is the number of erratic ones. */ | |
264 | ||
265 | typedef struct fde_vector | |
266 | { | |
267 | fde **array; | |
268 | size_t count; | |
269 | } fde_vector; | |
270 | ||
271 | typedef struct fde_accumulator | |
272 | { | |
273 | fde_vector linear; | |
274 | fde_vector erratic; | |
275 | } fde_accumulator; | |
276 | ||
277 | static inline void | |
278 | start_fde_sort (fde_accumulator *accu, size_t count) | |
279 | { | |
280 | accu->linear.array = (fde **) malloc (sizeof (fde *) * count); | |
281 | accu->erratic.array = (fde **) malloc (sizeof (fde *) * count); | |
282 | accu->linear.count = 0; | |
283 | accu->erratic.count = 0; | |
284 | } | |
0021b564 | 285 | |
72dd050a BH |
286 | static inline void |
287 | fde_insert (fde_accumulator *accu, fde *this_fde) | |
288 | { | |
289 | accu->linear.array[accu->linear.count++] = this_fde; | |
290 | } | |
291 | ||
292 | /* Split LINEAR into a linear sequence with low values and an erratic | |
293 | sequence with high values, put the linear one (of longest possible | |
294 | length) into LINEAR and the erratic one into ERRATIC. This is O(N). */ | |
295 | static inline void | |
296 | fde_split (fde_vector *linear, fde_vector *erratic) | |
297 | { | |
298 | size_t count = linear->count; | |
299 | size_t linear_max = (size_t) -1; | |
300 | size_t previous_max[count]; | |
301 | size_t i, j; | |
302 | ||
303 | for (i = 0; i < count; i++) | |
304 | { | |
305 | for (j = linear_max; | |
306 | j != (size_t) -1 | |
307 | && fde_compare (linear->array[i], linear->array[j]) < 0; | |
308 | j = previous_max[j]) | |
309 | { | |
310 | erratic->array[erratic->count++] = linear->array[j]; | |
311 | linear->array[j] = (fde *) NULL; | |
312 | } | |
313 | previous_max[i] = j; | |
314 | linear_max = i; | |
315 | } | |
316 | ||
317 | for (i = 0, j = 0; i < count; i++) | |
318 | if (linear->array[i] != (fde *) NULL) | |
319 | linear->array[j++] = linear->array[i]; | |
320 | linear->count = j; | |
321 | } | |
322 | ||
99b13ed3 JW |
323 | /* This is O(n log(n)). BSD/OS defines heapsort in stdlib.h, so we must |
324 | use a name that does not conflict. */ | |
72dd050a | 325 | static inline void |
99b13ed3 | 326 | frame_heapsort (fde_vector *erratic) |
72dd050a BH |
327 | { |
328 | /* For a description of this algorithm, see: | |
329 | Samuel P. Harbison, Guy L. Steele Jr.: C, a reference manual, 2nd ed., | |
330 | p. 60-61. */ | |
331 | fde ** a = erratic->array; | |
332 | /* A portion of the array is called a "heap" if for all i>=0: | |
333 | If i and 2i+1 are valid indices, then a[i] >= a[2i+1]. | |
334 | If i and 2i+2 are valid indices, then a[i] >= a[2i+2]. */ | |
335 | #define SWAP(x,y) do { fde * tmp = x; x = y; y = tmp; } while (0) | |
336 | size_t n = erratic->count; | |
337 | size_t m = n; | |
338 | size_t i; | |
339 | ||
340 | while (m > 0) | |
341 | { | |
342 | /* Invariant: a[m..n-1] is a heap. */ | |
343 | m--; | |
344 | for (i = m; 2*i+1 < n; ) | |
345 | { | |
346 | if (2*i+2 < n | |
347 | && fde_compare (a[2*i+2], a[2*i+1]) > 0 | |
348 | && fde_compare (a[2*i+2], a[i]) > 0) | |
349 | { | |
350 | SWAP (a[i], a[2*i+2]); | |
351 | i = 2*i+2; | |
352 | } | |
353 | else if (fde_compare (a[2*i+1], a[i]) > 0) | |
354 | { | |
355 | SWAP (a[i], a[2*i+1]); | |
356 | i = 2*i+1; | |
357 | } | |
358 | else | |
359 | break; | |
360 | } | |
361 | } | |
362 | while (n > 1) | |
363 | { | |
364 | /* Invariant: a[0..n-1] is a heap. */ | |
365 | n--; | |
366 | SWAP (a[0], a[n]); | |
367 | for (i = 0; 2*i+1 < n; ) | |
368 | { | |
369 | if (2*i+2 < n | |
370 | && fde_compare (a[2*i+2], a[2*i+1]) > 0 | |
371 | && fde_compare (a[2*i+2], a[i]) > 0) | |
372 | { | |
373 | SWAP (a[i], a[2*i+2]); | |
374 | i = 2*i+2; | |
375 | } | |
376 | else if (fde_compare (a[2*i+1], a[i]) > 0) | |
377 | { | |
378 | SWAP (a[i], a[2*i+1]); | |
379 | i = 2*i+1; | |
380 | } | |
381 | else | |
382 | break; | |
383 | } | |
384 | } | |
385 | #undef SWAP | |
386 | } | |
387 | ||
388 | /* Merge V1 and V2, both sorted, and put the result into V1. */ | |
0021b564 | 389 | static void |
72dd050a | 390 | fde_merge (fde_vector *v1, const fde_vector *v2) |
0021b564 | 391 | { |
72dd050a BH |
392 | size_t i1, i2; |
393 | fde * fde2; | |
0021b564 | 394 | |
72dd050a BH |
395 | i2 = v2->count; |
396 | if (i2 > 0) | |
0021b564 | 397 | { |
72dd050a BH |
398 | i1 = v1->count; |
399 | do { | |
400 | i2--; | |
401 | fde2 = v2->array[i2]; | |
402 | while (i1 > 0 && fde_compare (v1->array[i1-1], fde2) > 0) | |
403 | { | |
404 | v1->array[i1+i2] = v1->array[i1-1]; | |
405 | i1--; | |
406 | } | |
407 | v1->array[i1+i2] = fde2; | |
408 | } while (i2 > 0); | |
409 | v1->count += v2->count; | |
0021b564 JM |
410 | } |
411 | } | |
412 | ||
72dd050a BH |
413 | static fde ** |
414 | end_fde_sort (fde_accumulator *accu, size_t count) | |
415 | { | |
416 | if (accu->linear.count != count) | |
417 | abort (); | |
418 | fde_split (&accu->linear, &accu->erratic); | |
419 | if (accu->linear.count + accu->erratic.count != count) | |
420 | abort (); | |
99b13ed3 | 421 | frame_heapsort (&accu->erratic); |
72dd050a BH |
422 | fde_merge (&accu->linear, &accu->erratic); |
423 | free (accu->erratic.array); | |
424 | return accu->linear.array; | |
425 | } | |
426 | ||
0021b564 JM |
427 | static size_t |
428 | count_fdes (fde *this_fde) | |
429 | { | |
430 | size_t count; | |
431 | ||
432 | for (count = 0; this_fde->length != 0; this_fde = next_fde (this_fde)) | |
433 | { | |
d84e64d4 | 434 | /* Skip CIEs and linked once FDE entries. */ |
97991933 | 435 | if (this_fde->CIE_delta == 0 || this_fde->pc_begin == 0) |
0021b564 JM |
436 | continue; |
437 | ||
438 | ++count; | |
439 | } | |
440 | ||
441 | return count; | |
442 | } | |
443 | ||
444 | static void | |
72dd050a | 445 | add_fdes (fde *this_fde, fde_accumulator *accu, void **beg_ptr, void **end_ptr) |
0021b564 | 446 | { |
0021b564 JM |
447 | void *pc_begin = *beg_ptr; |
448 | void *pc_end = *end_ptr; | |
449 | ||
450 | for (; this_fde->length != 0; this_fde = next_fde (this_fde)) | |
451 | { | |
d84e64d4 | 452 | /* Skip CIEs and linked once FDE entries. */ |
97991933 | 453 | if (this_fde->CIE_delta == 0 || this_fde->pc_begin == 0) |
0021b564 JM |
454 | continue; |
455 | ||
72dd050a | 456 | fde_insert (accu, this_fde); |
0021b564 JM |
457 | |
458 | if (this_fde->pc_begin < pc_begin) | |
459 | pc_begin = this_fde->pc_begin; | |
460 | if (this_fde->pc_begin + this_fde->pc_range > pc_end) | |
461 | pc_end = this_fde->pc_begin + this_fde->pc_range; | |
462 | } | |
463 | ||
0021b564 JM |
464 | *beg_ptr = pc_begin; |
465 | *end_ptr = pc_end; | |
466 | } | |
467 | ||
468 | /* Set up a sorted array of pointers to FDEs for a loaded object. We | |
469 | count up the entries before allocating the array because it's likely to | |
470 | be faster. */ | |
471 | ||
472 | static void | |
473 | frame_init (struct object* ob) | |
474 | { | |
0021b564 | 475 | size_t count; |
72dd050a | 476 | fde_accumulator accu; |
0021b564 JM |
477 | void *pc_begin, *pc_end; |
478 | ||
479 | if (ob->fde_array) | |
480 | { | |
481 | fde **p = ob->fde_array; | |
482 | for (count = 0; *p; ++p) | |
483 | count += count_fdes (*p); | |
484 | } | |
485 | else | |
486 | count = count_fdes (ob->fde_begin); | |
487 | ||
488 | ob->count = count; | |
0021b564 | 489 | |
72dd050a | 490 | start_fde_sort (&accu, count); |
0021b564 JM |
491 | pc_begin = (void*)(uaddr)-1; |
492 | pc_end = 0; | |
0021b564 JM |
493 | |
494 | if (ob->fde_array) | |
495 | { | |
496 | fde **p = ob->fde_array; | |
497 | for (; *p; ++p) | |
72dd050a | 498 | add_fdes (*p, &accu, &pc_begin, &pc_end); |
0021b564 JM |
499 | } |
500 | else | |
72dd050a | 501 | add_fdes (ob->fde_begin, &accu, &pc_begin, &pc_end); |
0021b564 | 502 | |
72dd050a | 503 | ob->fde_array = end_fde_sort (&accu, count); |
0021b564 JM |
504 | ob->pc_begin = pc_begin; |
505 | ob->pc_end = pc_end; | |
506 | } | |
507 | ||
508 | /* Return a pointer to the FDE for the function containing PC. */ | |
509 | ||
510 | static fde * | |
511 | find_fde (void *pc) | |
512 | { | |
513 | struct object *ob; | |
514 | size_t lo, hi; | |
515 | ||
3e2a2957 | 516 | init_object_mutex_once (); |
154bba13 TT |
517 | __gthread_mutex_lock (&object_mutex); |
518 | ||
0021b564 JM |
519 | for (ob = objects; ob; ob = ob->next) |
520 | { | |
521 | if (ob->pc_begin == 0) | |
522 | frame_init (ob); | |
523 | if (pc >= ob->pc_begin && pc < ob->pc_end) | |
524 | break; | |
525 | } | |
526 | ||
154bba13 TT |
527 | __gthread_mutex_unlock (&object_mutex); |
528 | ||
0021b564 JM |
529 | if (ob == 0) |
530 | return 0; | |
531 | ||
532 | /* Standard binary search algorithm. */ | |
533 | for (lo = 0, hi = ob->count; lo < hi; ) | |
534 | { | |
535 | size_t i = (lo + hi) / 2; | |
536 | fde *f = ob->fde_array[i]; | |
537 | ||
538 | if (pc < f->pc_begin) | |
539 | hi = i; | |
db8abea3 | 540 | else if (pc >= f->pc_begin + f->pc_range) |
0021b564 JM |
541 | lo = i + 1; |
542 | else | |
543 | return f; | |
544 | } | |
545 | ||
546 | return 0; | |
547 | } | |
548 | \f | |
d84e64d4 JM |
549 | static inline struct dwarf_cie * |
550 | get_cie (fde *f) | |
551 | { | |
552 | return ((void *)&f->CIE_delta) - f->CIE_delta; | |
553 | } | |
554 | ||
0021b564 JM |
555 | /* Extract any interesting information from the CIE for the translation |
556 | unit F belongs to. */ | |
557 | ||
558 | static void * | |
559 | extract_cie_info (fde *f, struct cie_info *c) | |
560 | { | |
561 | void *p; | |
562 | int i; | |
563 | ||
d84e64d4 | 564 | c->augmentation = get_cie (f)->augmentation; |
0021b564 JM |
565 | |
566 | if (strcmp (c->augmentation, "") != 0 | |
d84e64d4 | 567 | && strcmp (c->augmentation, "eh") != 0 |
0021b564 JM |
568 | && c->augmentation[0] != 'z') |
569 | return 0; | |
570 | ||
571 | p = c->augmentation + strlen (c->augmentation) + 1; | |
572 | ||
d84e64d4 JM |
573 | if (strcmp (c->augmentation, "eh") == 0) |
574 | { | |
575 | c->eh_ptr = read_pointer (p); | |
576 | p += sizeof (void *); | |
577 | } | |
578 | else | |
579 | c->eh_ptr = 0; | |
580 | ||
0021b564 JM |
581 | p = decode_uleb128 (p, &c->code_align); |
582 | p = decode_sleb128 (p, &c->data_align); | |
583 | c->ra_regno = *(unsigned char *)p++; | |
584 | ||
585 | /* If the augmentation starts with 'z', we now see the length of the | |
586 | augmentation fields. */ | |
587 | if (c->augmentation[0] == 'z') | |
588 | { | |
589 | p = decode_uleb128 (p, &i); | |
590 | p += i; | |
591 | } | |
592 | ||
593 | return p; | |
594 | } | |
595 | ||
38e01259 | 596 | /* Decode one instruction's worth of DWARF 2 call frame information. |
0021b564 JM |
597 | Used by __frame_state_for. Takes pointers P to the instruction to |
598 | decode, STATE to the current register unwind information, INFO to the | |
599 | current CIE information, and PC to the current PC value. Returns a | |
600 | pointer to the next instruction. */ | |
601 | ||
602 | static void * | |
603 | execute_cfa_insn (void *p, struct frame_state_internal *state, | |
604 | struct cie_info *info, void **pc) | |
605 | { | |
606 | unsigned insn = *(unsigned char *)p++; | |
607 | unsigned reg; | |
608 | int offset; | |
609 | ||
610 | if (insn & DW_CFA_advance_loc) | |
611 | *pc += ((insn & 0x3f) * info->code_align); | |
612 | else if (insn & DW_CFA_offset) | |
613 | { | |
614 | reg = (insn & 0x3f); | |
615 | p = decode_uleb128 (p, &offset); | |
616 | offset *= info->data_align; | |
617 | state->s.saved[reg] = REG_SAVED_OFFSET; | |
618 | state->s.reg_or_offset[reg] = offset; | |
619 | } | |
620 | else if (insn & DW_CFA_restore) | |
621 | { | |
622 | reg = (insn & 0x3f); | |
623 | state->s.saved[reg] = REG_UNSAVED; | |
624 | } | |
625 | else switch (insn) | |
626 | { | |
627 | case DW_CFA_set_loc: | |
628 | *pc = read_pointer (p); | |
629 | p += sizeof (void *); | |
630 | break; | |
631 | case DW_CFA_advance_loc1: | |
632 | *pc += read_1byte (p); | |
633 | p += 1; | |
634 | break; | |
635 | case DW_CFA_advance_loc2: | |
636 | *pc += read_2byte (p); | |
637 | p += 2; | |
638 | break; | |
639 | case DW_CFA_advance_loc4: | |
640 | *pc += read_4byte (p); | |
641 | p += 4; | |
642 | break; | |
643 | ||
644 | case DW_CFA_offset_extended: | |
645 | p = decode_uleb128 (p, ®); | |
646 | p = decode_uleb128 (p, &offset); | |
647 | offset *= info->data_align; | |
648 | state->s.saved[reg] = REG_SAVED_OFFSET; | |
649 | state->s.reg_or_offset[reg] = offset; | |
650 | break; | |
651 | case DW_CFA_restore_extended: | |
652 | p = decode_uleb128 (p, ®); | |
653 | state->s.saved[reg] = REG_UNSAVED; | |
654 | break; | |
655 | ||
656 | case DW_CFA_undefined: | |
657 | case DW_CFA_same_value: | |
658 | case DW_CFA_nop: | |
659 | break; | |
660 | ||
661 | case DW_CFA_register: | |
662 | { | |
663 | unsigned reg2; | |
664 | p = decode_uleb128 (p, ®); | |
665 | p = decode_uleb128 (p, ®2); | |
666 | state->s.saved[reg] = REG_SAVED_REG; | |
667 | state->s.reg_or_offset[reg] = reg2; | |
668 | } | |
669 | break; | |
670 | ||
671 | case DW_CFA_def_cfa: | |
672 | p = decode_uleb128 (p, ®); | |
673 | p = decode_uleb128 (p, &offset); | |
674 | state->s.cfa_reg = reg; | |
675 | state->s.cfa_offset = offset; | |
676 | break; | |
677 | case DW_CFA_def_cfa_register: | |
678 | p = decode_uleb128 (p, ®); | |
679 | state->s.cfa_reg = reg; | |
680 | break; | |
681 | case DW_CFA_def_cfa_offset: | |
682 | p = decode_uleb128 (p, &offset); | |
683 | state->s.cfa_offset = offset; | |
684 | break; | |
685 | ||
686 | case DW_CFA_remember_state: | |
687 | { | |
688 | struct frame_state_internal *save = | |
689 | (struct frame_state_internal *) | |
690 | malloc (sizeof (struct frame_state_internal)); | |
691 | memcpy (save, state, sizeof (struct frame_state_internal)); | |
692 | state->saved_state = save; | |
693 | } | |
694 | break; | |
695 | case DW_CFA_restore_state: | |
696 | { | |
697 | struct frame_state_internal *save = state->saved_state; | |
698 | memcpy (state, save, sizeof (struct frame_state_internal)); | |
699 | free (save); | |
700 | } | |
701 | break; | |
702 | ||
703 | /* FIXME: Hardcoded for SPARC register window configuration. */ | |
704 | case DW_CFA_GNU_window_save: | |
705 | for (reg = 16; reg < 32; ++reg) | |
706 | { | |
707 | state->s.saved[reg] = REG_SAVED_OFFSET; | |
708 | state->s.reg_or_offset[reg] = (reg - 16) * sizeof (void *); | |
709 | } | |
710 | break; | |
711 | ||
712 | case DW_CFA_GNU_args_size: | |
713 | p = decode_uleb128 (p, &offset); | |
714 | state->s.args_size = offset; | |
715 | break; | |
716 | ||
717 | default: | |
718 | abort (); | |
719 | } | |
720 | return p; | |
721 | } | |
722 | \f | |
723 | /* Called from crtbegin.o to register the unwind info for an object. */ | |
724 | ||
725 | void | |
6d8ccdbb | 726 | __register_frame_info (void *begin, struct object *ob) |
0021b564 | 727 | { |
0021b564 JM |
728 | ob->fde_begin = begin; |
729 | ||
730 | ob->pc_begin = ob->pc_end = 0; | |
731 | ob->fde_array = 0; | |
732 | ob->count = 0; | |
733 | ||
3e2a2957 | 734 | init_object_mutex_once (); |
154bba13 TT |
735 | __gthread_mutex_lock (&object_mutex); |
736 | ||
0021b564 JM |
737 | ob->next = objects; |
738 | objects = ob; | |
154bba13 TT |
739 | |
740 | __gthread_mutex_unlock (&object_mutex); | |
0021b564 JM |
741 | } |
742 | ||
a3fd4e75 JL |
743 | void |
744 | __register_frame (void *begin) | |
745 | { | |
746 | struct object *ob = (struct object *) malloc (sizeof (struct object)); | |
747 | __register_frame_info (begin, ob); | |
748 | } | |
749 | ||
0021b564 JM |
750 | /* Similar, but BEGIN is actually a pointer to a table of unwind entries |
751 | for different translation units. Called from the file generated by | |
752 | collect2. */ | |
753 | ||
754 | void | |
6d8ccdbb | 755 | __register_frame_info_table (void *begin, struct object *ob) |
0021b564 | 756 | { |
0021b564 JM |
757 | ob->fde_begin = begin; |
758 | ob->fde_array = begin; | |
759 | ||
760 | ob->pc_begin = ob->pc_end = 0; | |
761 | ob->count = 0; | |
762 | ||
3e2a2957 | 763 | init_object_mutex_once (); |
154bba13 TT |
764 | __gthread_mutex_lock (&object_mutex); |
765 | ||
0021b564 JM |
766 | ob->next = objects; |
767 | objects = ob; | |
154bba13 TT |
768 | |
769 | __gthread_mutex_unlock (&object_mutex); | |
0021b564 JM |
770 | } |
771 | ||
a3fd4e75 JL |
772 | void |
773 | __register_frame_table (void *begin) | |
774 | { | |
775 | struct object *ob = (struct object *) malloc (sizeof (struct object)); | |
776 | __register_frame_info_table (begin, ob); | |
777 | } | |
778 | ||
9605fb44 | 779 | /* Called from crtbegin.o to deregister the unwind info for an object. */ |
0021b564 | 780 | |
a3fd4e75 | 781 | void * |
6d8ccdbb | 782 | __deregister_frame_info (void *begin) |
0021b564 | 783 | { |
154bba13 | 784 | struct object **p; |
0021b564 | 785 | |
3e2a2957 | 786 | init_object_mutex_once (); |
154bba13 TT |
787 | __gthread_mutex_lock (&object_mutex); |
788 | ||
789 | p = &objects; | |
0021b564 JM |
790 | while (*p) |
791 | { | |
792 | if ((*p)->fde_begin == begin) | |
793 | { | |
794 | struct object *ob = *p; | |
795 | *p = (*p)->next; | |
796 | ||
6d53d7c2 JM |
797 | /* If we've run init_frame for this object, free the FDE array. */ |
798 | if (ob->pc_begin) | |
0021b564 | 799 | free (ob->fde_array); |
0021b564 | 800 | |
154bba13 | 801 | __gthread_mutex_unlock (&object_mutex); |
a3fd4e75 | 802 | return (void *) ob; |
0021b564 JM |
803 | } |
804 | p = &((*p)->next); | |
805 | } | |
154bba13 TT |
806 | |
807 | __gthread_mutex_unlock (&object_mutex); | |
0021b564 JM |
808 | abort (); |
809 | } | |
810 | ||
a3fd4e75 JL |
811 | void |
812 | __deregister_frame (void *begin) | |
813 | { | |
814 | free (__deregister_frame_info (begin)); | |
815 | } | |
816 | ||
0021b564 JM |
817 | /* Called from __throw to find the registers to restore for a given |
818 | PC_TARGET. The caller should allocate a local variable of `struct | |
819 | frame_state' (declared in frame.h) and pass its address to STATE_IN. */ | |
820 | ||
821 | struct frame_state * | |
822 | __frame_state_for (void *pc_target, struct frame_state *state_in) | |
823 | { | |
824 | fde *f; | |
825 | void *insn, *end, *pc; | |
826 | struct cie_info info; | |
827 | struct frame_state_internal state; | |
828 | ||
829 | f = find_fde (pc_target); | |
830 | if (f == 0) | |
831 | return 0; | |
832 | ||
833 | insn = extract_cie_info (f, &info); | |
834 | if (insn == 0) | |
835 | return 0; | |
836 | ||
837 | memset (&state, 0, sizeof (state)); | |
838 | state.s.retaddr_column = info.ra_regno; | |
d84e64d4 | 839 | state.s.eh_ptr = info.eh_ptr; |
0021b564 JM |
840 | |
841 | /* First decode all the insns in the CIE. */ | |
d84e64d4 | 842 | end = next_fde ((fde*) get_cie (f)); |
0021b564 JM |
843 | while (insn < end) |
844 | insn = execute_cfa_insn (insn, &state, &info, 0); | |
845 | ||
846 | insn = ((fde *)f) + 1; | |
847 | ||
848 | if (info.augmentation[0] == 'z') | |
849 | { | |
850 | int i; | |
851 | insn = decode_uleb128 (insn, &i); | |
852 | insn += i; | |
853 | } | |
0021b564 JM |
854 | |
855 | /* Then the insns in the FDE up to our target PC. */ | |
856 | end = next_fde (f); | |
857 | pc = f->pc_begin; | |
13ab2b83 | 858 | while (insn < end && pc <= pc_target) |
0021b564 JM |
859 | insn = execute_cfa_insn (insn, &state, &info, &pc); |
860 | ||
861 | memcpy (state_in, &state.s, sizeof (state.s)); | |
862 | return state_in; | |
863 | } | |
864 | #endif /* DWARF2_UNWIND_INFO */ |