blob: 2be30b94151c11a769fd329e34ecb1ac768e5416 [file] [log] [blame]
homeip.net!davidm88160e02004-08-17 15:34:28 +00001/* libunwind - a platform-independent unwind library
2 Copyright (c) 2003 Hewlett-Packard Development Company, L.P.
3 Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
4
5This file is part of libunwind.
6
7Permission is hereby granted, free of charge, to any person obtaining
8a copy of this software and associated documentation files (the
9"Software"), to deal in the Software without restriction, including
10without limitation the rights to use, copy, modify, merge, publish,
11distribute, sublicense, and/or sell copies of the Software, and to
12permit persons to whom the Software is furnished to do so, subject to
13the following conditions:
14
15The above copyright notice and this permission notice shall be
16included in all copies or substantial portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
25
26#include <string.h>
27
28#include "dwarf_i.h"
29#include "tdep.h"
30
31#define alloc_reg_state() (mempool_alloc (&dwarf_reg_state_pool))
32#define free_reg_state(rs) (mempool_free (&dwarf_reg_state_pool, rs))
33
34static inline int
35read_regnum (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
36 unw_word_t *valp, void *arg)
37{
38 int ret;
39
40 if ((ret = dwarf_read_uleb128 (as, a, addr, valp, arg)) < 0)
41 return ret;
42
43 if (*valp >= DWARF_NUM_PRESERVED_REGS)
44 {
45 Debug (1, "Invalid register number %u\n", *valp);
46 return -UNW_EBADREG;
47 }
48 return 0;
49}
50
51static inline void
52set_reg (dwarf_state_record_t *sr, unw_word_t regnum, dwarf_where_t where,
53 unw_word_t val)
54{
55 sr->rs_current.reg[regnum].where = where;
56 sr->rs_current.reg[regnum].val = val;
57}
58
59/* Run a CFI program to update the register state. */
60static int
61run_cfi_program (struct dwarf_cursor *c, dwarf_state_record_t *sr,
62 unw_word_t ip, unw_word_t *addr, unw_word_t end_addr,
63 unw_dyn_dwarf_fde_info_t *dfi)
64{
65 unw_word_t curr_ip, operand = 0, regnum, val, len, fde_encoding;
66 dwarf_reg_state_t *rs_stack = NULL, *new_rs, *old_rs;
67 unw_addr_space_t as;
68 unw_accessors_t *a;
69 uint8_t u8, op;
70 uint16_t u16;
71 uint32_t u32;
72 void *arg;
73 int ret;
74
75 as = c->as;
76 arg = c->as_arg;
77 a = unw_get_accessors (as);
78 curr_ip = c->pi.start_ip;
79
80 while (curr_ip < ip && *addr < end_addr)
81 {
82 if ((ret = dwarf_readu8 (as, a, addr, &op, arg)) < 0)
83 return ret;
84
85 if (op & DWARF_CFA_OPCODE_MASK)
86 {
87 operand = op & DWARF_CFA_OPERAND_MASK;
88 op &= ~DWARF_CFA_OPERAND_MASK;
89 }
90 switch ((dwarf_cfa_t) op)
91 {
92 case DW_CFA_advance_loc:
93 curr_ip += operand * dfi->code_align;
94 Debug (16, "CFA_advance_loc to 0x%lx\n", (long) curr_ip);
95 break;
96
97 case DW_CFA_advance_loc1:
98 if ((ret = dwarf_readu8 (as, a, addr, &u8, arg)) < 0)
99 goto fail;
100 curr_ip += u8 * dfi->code_align;
101 Debug (16, "CFA_advance_loc1 to 0x%lx\n", (long) curr_ip);
102 break;
103
104 case DW_CFA_advance_loc2:
105 if ((ret = dwarf_readu16 (as, a, addr, &u16, arg)) < 0)
106 goto fail;
107 curr_ip += u16 * dfi->code_align;
108 Debug (16, "CFA_advance_loc2 to 0x%lx\n", (long) curr_ip);
109 break;
110
111 case DW_CFA_advance_loc4:
112 if ((ret = dwarf_readu32 (as, a, addr, &u32, arg)) < 0)
113 goto fail;
114 curr_ip += u32 * dfi->code_align;
115 Debug (16, "CFA_advance_loc4 to 0x%lx\n", (long) curr_ip);
116 break;
117
118 case DW_CFA_MIPS_advance_loc8:
119#ifdef UNW_TARGET_MIPS
120 {
121 uint64_t u64;
122
123 if ((ret = dwarf_readu64 (as, a, addr, &u64, arg)) < 0)
124 goto fail;
125 curr_ip += u64 * dfi->code_align;
126 Debug (16, "CFA_MIPS_advance_loc8\n");
127 break;
128 }
129#else
130 Debug (1, "DW_CFA_MIPS_advance_loc8 on non-MIPS target\n");
131 ret = -UNW_EINVAL;
132 goto fail;
133#endif
134
135 case DW_CFA_offset:
136 regnum = operand;
137 if (regnum >= DWARF_NUM_PRESERVED_REGS)
138 {
139 Debug (1, "Invalid register number %u in DW_cfa_OFFSET\n",
140 regnum);
141 ret = -UNW_EBADREG;
142 goto fail;
143 }
144 if ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0)
145 goto fail;
146 set_reg (sr, regnum, DWARF_WHERE_CFAREL, val * dfi->data_align);
147 Debug (16, "CFA_offset r%lu at cfa+0x%lx\n",
148 (long) regnum, (long) (val * dfi->data_align));
149 break;
150
151 case DW_CFA_offset_extended:
152 if (((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
153 || ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0))
154 goto fail;
155 set_reg (sr, regnum, DWARF_WHERE_CFAREL, val * dfi->data_align);
156 Debug (16, "CFA_offset_extended r%lu at cf+0x%lx\n",
157 (long) regnum, (long) (val * dfi->data_align));
158 break;
159
160 case DW_CFA_offset_extended_sf:
161 if (((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
162 || ((ret = dwarf_read_sleb128 (as, a, addr, &val, arg)) < 0))
163 goto fail;
164 set_reg (sr, regnum, DWARF_WHERE_CFAREL, val * dfi->data_align);
165 Debug (16, "CFA_offset_extended_sf r%lu at cf+0x%lx\n",
166 (long) regnum, (long) (val * dfi->data_align));
167 break;
168
169 case DW_CFA_restore:
170 regnum = operand;
171 if (regnum >= DWARF_NUM_PRESERVED_REGS)
172 {
173 Debug (1, "Invalid register number %u in DW_CFA_restore\n",
174 regnum);
175 ret = -UNW_EINVAL;
176 goto fail;
177 }
178 sr->rs_current.reg[regnum] = sr->rs_initial.reg[regnum];
179 Debug (16, "CFA_restore r%lu\n", (long) regnum);
180 break;
181
182 case DW_CFA_restore_extended:
183 if ((ret = dwarf_read_uleb128 (as, a, addr, &regnum, arg)) < 0)
184 goto fail;
185 if (regnum >= DWARF_NUM_PRESERVED_REGS)
186 {
187 Debug (1, "Invalid register number %u in "
188 "DW_CFA_restore_extended\n", regnum);
189 ret = -UNW_EINVAL;
190 goto fail;
191 }
192 sr->rs_current.reg[regnum] = sr->rs_initial.reg[regnum];
193 Debug (16, "CFA_restore_extended r%lu\n", (long) regnum);
194 break;
195
196 case DW_CFA_nop:
197 break;
198
199 case DW_CFA_set_loc:
200 fde_encoding = dfi->flags & UNW_DYN_DFI_FLAG_FDE_PE_MASK;
201 if ((ret = dwarf_read_encoded_pointer (as, a, addr, fde_encoding,
202 &c->pi, &curr_ip,
203 arg)) < 0)
204 goto fail;
205 Debug (16, "CFA_set_loc to 0x%lx\n", (long) curr_ip);
206 break;
207
208 case DW_CFA_undefined:
209 if ((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
210 goto fail;
211 set_reg (sr, regnum, DWARF_WHERE_UNDEF, 0);
212 Debug (16, "CFA_undefined r%lu\n", (long) regnum);
213 break;
214
215 case DW_CFA_same_value:
216 if ((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
217 goto fail;
218 set_reg (sr, regnum, DWARF_WHERE_SAME, 0);
219 Debug (16, "CFA_same_value r%lu\n", (long) regnum);
220 break;
221
222 case DW_CFA_register:
223 if (((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
224 || ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0))
225 goto fail;
226 set_reg (sr, regnum, DWARF_WHERE_REG, val);
227 Debug (16, "CFA_register r%lu to r%lu\n", (long) regnum, (long) val);
228 break;
229
230 case DW_CFA_remember_state:
231 new_rs = alloc_reg_state ();
232 if (!new_rs)
233 {
234 Debug (1, "Out of memory in DW_CFA_remember_state\n");
235 ret = -UNW_ENOMEM;
236 goto fail;
237 }
238
239 memcpy (new_rs->reg, sr->rs_current.reg, sizeof (new_rs->reg));
240 new_rs->next = rs_stack;
241 rs_stack = new_rs;
242 Debug (16, "CFA_remember_state\n");
243 break;
244
245 case DW_CFA_restore_state:
246 if (!rs_stack)
247 {
248 Debug (1, "register-state stack underflow\n");
249 ret = -UNW_EINVAL;
250 goto fail;
251 }
252 memcpy (&sr->rs_current.reg, &rs_stack->reg, sizeof (rs_stack->reg));
253 old_rs = rs_stack;
254 rs_stack = rs_stack->next;
255 free_reg_state (old_rs);
256 Debug (16, "CFA_restore_state\n");
257 break;
258
259 case DW_CFA_def_cfa:
260 if (((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
261 || ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0))
262 goto fail;
263 set_reg (sr, DWARF_CFA_REG_COLUMN, DWARF_WHERE_REG, regnum);
264 set_reg (sr, DWARF_CFA_OFF_COLUMN, 0, val); /* NOT factored! */
265 Debug (16, "CFA_def_cfa r%lu+0x%lx\n", (long) regnum, (long) val);
266 break;
267
268 case DW_CFA_def_cfa_sf:
269 if (((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
270 || ((ret = dwarf_read_sleb128 (as, a, addr, &val, arg)) < 0))
271 goto fail;
272 set_reg (sr, DWARF_CFA_REG_COLUMN, DWARF_WHERE_REG, regnum);
273 set_reg (sr, DWARF_CFA_OFF_COLUMN, 0,
274 val * dfi->data_align); /* factored! */
275 Debug (16, "CFA_def_cfa_sf r%lu+0x%lx\n",
276 (long) regnum, (long) (val * dfi->data_align));
277 break;
278
279 case DW_CFA_def_cfa_register:
280 if ((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
281 goto fail;
282 set_reg (sr, DWARF_CFA_REG_COLUMN, DWARF_WHERE_REG, regnum);
283 Debug (16, "CFA_def_cfa_register r%lu\n", (long) regnum);
284 break;
285
286 case DW_CFA_def_cfa_offset:
287 if ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0)
288 goto fail;
289 set_reg (sr, DWARF_CFA_OFF_COLUMN, 0, val); /* NOT factored! */
290 Debug (16, "CFA_def_cfa_offsets 0x%lx\n", (long) val);
291 break;
292
293 case DW_CFA_def_cfa_offset_sf:
294 if ((ret = dwarf_read_sleb128 (as, a, addr, &val, arg)) < 0)
295 goto fail;
296 set_reg (sr, DWARF_CFA_OFF_COLUMN, 0,
297 val * dfi->data_align); /* factored! */
298 Debug (16, "CFA_def_cfa_offsets_sf 0x%lx\n",
299 (long) (val * dfi->data_align));
300 break;
301
302 case DW_CFA_def_cfa_expression:
303 /* Save the address of the DW_FORM_block for later evaluation. */
304 set_reg (sr, DWARF_CFA_REG_COLUMN, DWARF_WHERE_EXPR, *addr);
305
306 if ((ret = dwarf_read_uleb128 (as, a, addr, &len, arg)) < 0)
307 goto fail;
308
309 Debug (16, "CFA_def_cfa_expr @ 0x%lx [%lu bytes]\n",
310 (long) *addr, (long) len);
311 *addr += len;
312 break;
313
314 case DW_CFA_CFA_expression:
315 if ((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
316 goto fail;
317
318 /* Save the address of the DW_FORM_block for later evaluation. */
319 set_reg (sr, regnum, DWARF_WHERE_EXPR, *addr);
320
321 if ((ret = dwarf_read_uleb128 (as, a, addr, &len, arg)) < 0)
322 goto fail;
323
324 Debug (16, "CFA_expression r%lu @ 0x%lx [%lu bytes]\n",
325 (long) regnum, (long) addr, (long) len);
326 *addr += len;
327 break;
328
329 case DW_CFA_GNU_args_size:
330 if ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0)
331 goto fail;
332 sr->args_size = val;
333 Debug (16, "CFA_GNU_args_size %lu\n", (long) val);
334 break;
335
336 case DW_CFA_GNU_negative_offset_extended:
337 /* A comment in GCC says that this is obsoleted by
338 DW_CFA_offset_extended_sf, but that it's used by older
339 PowerPC code. */
340 if (((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
341 || ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0))
342 goto fail;
343 set_reg (sr, regnum, DWARF_WHERE_CFAREL, -(val * dfi->data_align));
344 Debug (16, "CFA_GNU_negative_offsets_extended cfa+0x%lx\n",
345 (long) -(val * dfi->data_align));
346 break;
347
348 case DW_CFA_GNU_window_save:
349#ifdef UNW_TARGET_SPARC
350 /* This is a special CFA to handle all 16 windowed registers
351 on SPARC. */
352 for (regnum = 16; regnum < 32; ++regnum)
353 set_reg (sr, regnum, DWARF_WHERE_CFAREL,
354 (regnum - 16) * sizeof (unw_word_t));
355 Debug (16, "CFA_GNU_window_save\n");
356 break;
357#else
358 /* FALL THROUGH */
359#endif
360 case DW_CFA_lo_user:
361 case DW_CFA_hi_user:
362 Debug (1, "Unexpected CFA opcode 0x%x", op);
363 ret = -UNW_EINVAL;
364 goto fail;
365 }
366 }
367 ret = 0;
368
369 fail:
370 /* Free the register-state stack, if not empty already. */
371 while (rs_stack)
372 {
373 old_rs = rs_stack;
374 rs_stack = rs_stack->next;
375 free_reg_state (old_rs);
376 }
377 return ret;
378}
379
380static int
381fetch_proc_info (struct dwarf_cursor *c, unw_word_t ip, int need_unwind_info)
382{
383 int ret, dynamic = 1;
384
385 if (c->pi_valid && !need_unwind_info)
386 return 0;
387
388 /* check dynamic info first --- it overrides everything else */
389 ret = unwi_find_dynamic_proc_info (c->as, ip, &c->pi, need_unwind_info,
390 c->as_arg);
391 if (ret == -UNW_ENOINFO)
392 {
393 dynamic = 0;
394 if ((ret = tdep_find_proc_info (c, ip, need_unwind_info)) < 0)
395 return ret;
396 }
397
398 c->pi_valid = 1;
399 c->pi_is_dynamic = dynamic;
400 return ret;
401}
402
403static int
404parse_dynamic (struct dwarf_cursor *c, unw_word_t ip, dwarf_state_record_t *sr)
405{
406 Debug (1, "Not yet implemented\n");
407#if 0
408 /* Don't forget to set the ret_addr_column! */
409 c->ret_addr_column = XXX;
410#endif
411 return -UNW_ENOINFO;
412}
413
414static inline void
415put_unwind_info (struct dwarf_cursor *c, unw_proc_info_t *pi)
416{
417 if (!c->pi_valid)
418 return;
419
420 if (c->pi_is_dynamic)
421 unwi_put_dynamic_unwind_info (c->as, pi, c->as_arg);
422}
423
424static inline int
425parse_fde (struct dwarf_cursor *c, unw_word_t ip, dwarf_state_record_t *sr)
426{
427 unw_dyn_dwarf_fde_info_t *dfi;
428 unw_word_t addr;
429 int ret;
430
431 dfi = c->pi.unwind_info;
432 c->ret_addr_column = dfi->ret_addr_column;
433
434 addr = dfi->cie_instr_start;
435 if ((ret = run_cfi_program (c, sr, ~(unw_word_t) 0, &addr,
436 dfi->cie_instr_end, dfi)) < 0)
437 return ret;
438
439 memcpy (&sr->rs_initial, &sr->rs_current, sizeof (sr->rs_initial));
440
441 addr = dfi->fde_instr_start;
442 if ((ret = run_cfi_program (c, sr, ip, &addr, dfi->fde_instr_end, dfi)) < 0)
443 return ret;
444
445 return 0;
446}
447
448static int
449create_state_record_for (struct dwarf_cursor *c, dwarf_state_record_t *sr,
450 unw_word_t ip)
451{
452 int i, ret;
453
454 assert (c->pi_valid);
455
456 for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
457 set_reg (sr, i, DWARF_WHERE_SAME, 0);
458
459 switch (c->pi.format)
460 {
461 case UNW_INFO_FORMAT_DWARF_FDE:
462 ret = parse_fde (c, ip, sr);
463 break;
464
465 case UNW_INFO_FORMAT_DYNAMIC:
466 ret = parse_dynamic (c, ip, sr);
467 break;
468
469 case UNW_INFO_FORMAT_REMOTE_TABLE:
470 case UNW_INFO_FORMAT_TABLE:
471 default:
472 Debug (1, "Unexpected unwind-info format %d\n", c->pi.format);
473 ret = -UNW_EINVAL;
474 }
475 return ret;
476}
477
478static inline int
479eval_location_expr (struct dwarf_cursor *c, unw_addr_space_t as,
480 unw_accessors_t *a, unw_word_t addr,
481 dwarf_loc_t *locp, void *arg)
482{
483 int ret, is_register;
484 unw_word_t len, val;
485
486 /* read the length of the expression: */
487 if ((ret = dwarf_read_uleb128 (as, a, &addr, &len, arg)) < 0)
488 return ret;
489
490 /* evaluate the expression: */
491 if ((ret = dwarf_eval_expr (c, &addr, len, &val, &is_register)) < 0)
492 return ret;
493
494 if (is_register)
495 *locp = DWARF_REG_LOC (c, dwarf_to_unw_regnum (val));
496 else
497 *locp = DWARF_MEM_LOC (c, val);
498
499 return 0;
500}
501
502static int
503apply_reg_state (struct dwarf_cursor *c, struct dwarf_reg_state *rs)
504{
505 unw_word_t regnum, addr, cfa;
506 unw_addr_space_t as;
507 dwarf_loc_t cfa_loc;
508 unw_accessors_t *a;
509 int i, ret;
510 void *arg;
511
512 as = c->as;
513 arg = c->as_arg;
514 a = unw_get_accessors (as);
515
516 /* Evaluate the CFA first, because it may be referred to be other
517 expressions. */
518
519 if (rs->reg[DWARF_CFA_REG_COLUMN].where == DWARF_WHERE_REG)
520 {
521 /* CFA is equal to [reg] + offset: */
522
523 regnum = dwarf_to_unw_regnum (rs->reg[DWARF_CFA_REG_COLUMN].val);
524 if ((ret = unw_get_reg ((unw_cursor_t *) c, regnum, &cfa)) < 0)
525 return ret;
526
527 cfa += rs->reg[DWARF_CFA_OFF_COLUMN].val;
528 }
529 else
530 {
531 /* CFA is equal to EXPR: */
532
533 assert (rs->reg[DWARF_CFA_REG_COLUMN].where == DWARF_WHERE_EXPR);
534
535 addr = rs->reg[DWARF_CFA_REG_COLUMN].val;
536 if ((ret = eval_location_expr (c, as, a, addr, &cfa_loc, arg)) < 0)
537 return ret;
538 if ((ret = dwarf_get (c, cfa_loc, &cfa)) < 0)
539 return ret;
540 }
541 c->cfa = cfa;
542
543 for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
544 {
545 switch ((dwarf_where_t) rs->reg[i].where)
546 {
547 case DWARF_WHERE_UNDEF:
548 c->loc[i] = DWARF_NULL_LOC;
549 break;
550
551 case DWARF_WHERE_SAME:
552 break;
553
554 case DWARF_WHERE_CFAREL:
555 c->loc[i] = DWARF_MEM_LOC (c, cfa + rs->reg[i].val);
556 break;
557
558 case DWARF_WHERE_REG:
559 c->loc[i] = DWARF_REG_LOC (c, dwarf_to_unw_regnum (rs->reg[i].val));
560 break;
561
562 case DWARF_WHERE_EXPR:
563 addr = rs->reg[i].val;
564 if ((ret = eval_location_expr (c, as, a, addr, c->loc + i, arg)) , 0)
565 return ret;
566 break;
567 }
568 }
569 return 0;
570}
571
572HIDDEN int
573dwarf_find_save_locs (struct dwarf_cursor *c)
574{
575 dwarf_state_record_t sr;
576 int ret;
577
578 if ((ret = fetch_proc_info (c, c->ip, 1)) < 0)
579 return ret;
580
581 if ((ret = create_state_record_for (c, &sr, c->ip)) < 0)
582 return ret;
583
584 if ((ret = apply_reg_state (c, &sr.rs_current)) < 0)
585 return ret;
586
587 put_unwind_info (c, &c->pi);
588 return 0;
589}
590
591/* The proc-info must be valid for IP before this routine can be
592 called. */
593HIDDEN int
594dwarf_create_state_record (struct dwarf_cursor *c, dwarf_state_record_t *sr)
595{
596 return create_state_record_for (c, sr, c->ip);
597}
598
599HIDDEN int
600dwarf_make_proc_info (struct dwarf_cursor *c)
601{
602#if 0
603 if (c->as->caching_policy == UNW_CACHE_NONE
604 || get_cached_proc_info (c) < 0)
605#endif
606 /* Lookup it up the slow way... */
607 return fetch_proc_info (c, c->ip, 0);
608 return 0;
609}