23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include <_libelf.h>
28 #include <dwarf.h>
29 #include <stdio.h>
30 #include <unistd.h>
31 #include <errno.h>
32 #include <strings.h>
33 #include <debug.h>
34 #include <conv.h>
35 #include <msg.h>
36 #include <_elfdump.h>
37
38
39 /*
40 * Data from eh_frame section used by dump_cfi()
41 */
42 typedef struct {
43 Half e_machine; /* ehdr->e_machine */
44 uchar_t *e_ident; /* ehdr->e_ident */
45 uint64_t sh_addr; /* Address of eh_frame section */
46 int do_swap; /* True if object and system byte */
47 /* order differs */
48 int cieRflag; /* R flag from current CIE */
49 uint64_t ciecalign; /* CIE code align factor */
50 int64_t ciedalign; /* CIE data align factor */
51 uint64_t fdeinitloc; /* FDE initial location */
52 uint64_t gotaddr; /* Address of the GOT */
53 } dump_cfi_state_t;
54
55
56 /*
57 * Extract an unsigned integer value from an .eh_frame section, converting it
58 * from its native byte order to that of the running machine if necessary.
59 *
60 * entry:
61 * data - Base address from which to extract datum
62 * ndx - Address of variable giving index to start byte in data.
63 * size - # of bytes in datum. Must be one of: 1, 2, 4, 8
64 * do_swap - True if the data is in a different byte order than that
65 * of the host system.
66 *
67 * exit:
68 * *ndx is incremented by the size of the extracted datum.
69 *
70 * The requested datum is extracted, byte swapped if necessary,
71 * and returned.
72 */
73 static uint64_t
74 dwarf_extract_uint(uchar_t *data, uint64_t *ndx, int size, int do_swap)
75 {
76 switch (size) {
77 case 1:
78 return (data[(*ndx)++]);
79 case 2:
80 {
81 Half r;
82 uchar_t *p = (uchar_t *)&r;
83
84 data += *ndx;
85 if (do_swap)
86 UL_ASSIGN_BSWAP_HALF(p, data);
87 else
88 UL_ASSIGN_HALF(p, data);
89
90 (*ndx) += 2;
91 return (r);
92 }
93 case 4:
94 {
95 Word r;
96 uchar_t *p = (uchar_t *)&r;
97
98 data += *ndx;
99 if (do_swap)
100 UL_ASSIGN_BSWAP_WORD(p, data);
101 else
102 UL_ASSIGN_WORD(p, data);
103
104 (*ndx) += 4;
105 return (r);
106 }
107
108 case 8:
109 {
110 uint64_t r;
111 uchar_t *p = (uchar_t *)&r;
112
113 data += *ndx;
114 if (do_swap)
115 UL_ASSIGN_BSWAP_LWORD(p, data);
116 else
117 UL_ASSIGN_LWORD(p, data);
118
119 (*ndx) += 8;
120 return (r);
121 }
122 }
123
124 /* If here, an invalid size was specified */
125 assert(0);
126 return (0);
127 }
128
129 /*
130 * Map a DWARF register constant to the machine register name it
131 * corresponds to, formatting the result into buf.
132 *
133 * The assignment of DWARF register numbers is part of the system
134 * specific ABI for each platform.
135 *
136 * entry:
137 * regno - DWARF register number
138 * mach - ELF machine code for platform
139 * buf, bufsize - Buffer to receive the formatted result string
140 *
141 * exit:
142 * The results are formatted into buf, and buf is returned.
143 * If the generated output would exceed the size of the buffer
144 * provided, it will be clipped to fit.
145 */
146 static const char *
159 */
160 if (good_name)
161 (void) snprintf(buf, bufsize, MSG_ORIG(MSG_REG_FMT_NAME),
162 regno, name);
163 else
164 (void) snprintf(buf, bufsize, MSG_ORIG(MSG_REG_FMT_BASIC),
165 regno);
166
167 return (buf);
168 }
169
170
171 /*
172 * Decode eh_frame Call Frame Instructions, printing each one on a
173 * separate line.
174 *
175 * entry:
176 * data - Address of base of eh_frame section being processed
177 * off - Offset of current FDE within eh_frame
178 * ndx - Index of current position within current FDE
179 * len - Length of eh_frame section
180 * state - Object, CIE, and FDE state for current request
181 * msg - Header message to issue before producing output.
182 * indent - # of indentation characters issued for each line of output.
183 *
184 * exit:
185 * The Call Frame Instructions have been decoded and printed.
186 *
187 * *ndx has been incremented to contain the index of the next
188 * byte of data to be processed in eh_frame.
189 *
190 * note:
191 * The format of Call Frame Instructions in .eh_frame sections is based
192 * on the DWARF specification.
193 */
194 static void
195 dump_cfi(uchar_t *data, uint64_t off, uint64_t *ndx, uint_t len,
196 dump_cfi_state_t *state, const char *msg, int indent)
197 {
198 /*
199 * We use %*s%s to insert leading whitespace and the op name.
246 * 0 uses the lower 6 bits to specify a sub-opcode, allowing
247 * for 64 of them. The other 3 primary op codes use the
248 * lower 6 bits to hold an operand (a register #, or value).
249 *
250 * Check the primary OP code. If it's 1-3, handle it
251 * and move to the next loop iteration. For OP code 0,
252 * fall through to decode the sub-code.
253 */
254 op = data[off + (*ndx)++];
255 opname = conv_dwarf_cfa(op, 0, &inv_buf);
256 switch (op >> 6) {
257 case 0x1: /* v2: DW_CFA_advance_loc, delta */
258 oper1 = state->ciecalign * LOW_OP(op);
259 cur_pc += oper1;
260 dbg_print(0, MSG_ORIG(MSG_CFA_ADV_LOC), PREFIX,
261 loc_str, EC_XWORD(oper1), EC_XWORD(cur_pc));
262 loc_str = MSG_ORIG(MSG_STR_LOC);
263 continue;
264
265 case 0x2: /* v2: DW_CFA_offset, reg, offset */
266 soper = uleb_extract(&data[off], ndx) *
267 state->ciedalign;
268 dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX,
269 REGNAME(LOW_OP(op), rbuf1), EC_SXWORD(soper));
270 continue;
271
272 case 0x3: /* v2: DW_CFA_restore, reg */
273 dbg_print(0, MSG_ORIG(MSG_CFA_REG), PREFIX,
274 REGNAME(LOW_OP(op), rbuf1));
275 continue;
276 }
277
278 /*
279 * If we're here, the high order 2 bits are 0. The low 6 bits
280 * specify a sub-opcode defining the operation.
281 */
282 switch (op) {
283 case 0x00: /* v2: DW_CFA_nop */
284 /*
285 * No-ops are used to fill unused space required
286 * for alignment. It is common for there to be
287 * multiple adjacent nops. It saves space to report
288 * them all with a single line of output.
289 */
290 for (i = 1;
291 (*ndx < len) && (data[off + *ndx] == 0);
292 i++, (*ndx)++)
293 ;
294 dbg_print(0, MSG_ORIG(MSG_CFA_SIMPLEREP), PREFIX, i);
295 break;
296
297 case 0x0a: /* v2: DW_CFA_remember_state */
298 case 0x0b: /* v2: DW_CFA_restore_state */
299 case 0x2d: /* GNU: DW_CFA_GNU_window_save */
300 dbg_print(0, MSG_ORIG(MSG_CFA_SIMPLE), PREFIX);
301 break;
302
303 case 0x01: /* v2: DW_CFA_set_loc, address */
304 cur_pc = dwarf_ehe_extract(&data[off], ndx,
305 state->cieRflag, state->e_ident, B_FALSE,
306 state->sh_addr, off + *ndx, state->gotaddr);
307 dbg_print(0, MSG_ORIG(MSG_CFA_CFASET), PREFIX,
308 EC_XWORD(cur_pc));
309 break;
310
311 case 0x02: /* v2: DW_CFA_advance_loc_1, 1-byte delta */
312 case 0x03: /* v2: DW_CFA_advance_loc_2, 2-byte delta */
313 case 0x04: /* v2: DW_CFA_advance_loc_4, 4-byte delta */
314 /*
315 * Since the codes are contiguous, and the sizes are
316 * powers of 2, we can compute the word width from
317 * the code.
318 */
319 i = 1 << (op - 0x02);
320 oper1 = dwarf_extract_uint(data + off, ndx, i,
321 state->do_swap) * state->ciecalign;
322 cur_pc += oper1;
323 dbg_print(0, MSG_ORIG(MSG_CFA_ADV_LOC), PREFIX,
324 loc_str, EC_XWORD(oper1), EC_XWORD(cur_pc));
325 loc_str = MSG_ORIG(MSG_STR_LOC);
326 break;
327
328 case 0x05: /* v2: DW_CFA_offset_extended,reg,off */
329 oper1 = uleb_extract(&data[off], ndx);
330 soper = uleb_extract(&data[off], ndx) *
331 state->ciedalign;
332 dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX,
333 REGNAME(oper1, rbuf1), EC_SXWORD(soper));
334 break;
335
336 case 0x06: /* v2: DW_CFA_restore_extended, reg */
337 case 0x0d: /* v2: DW_CFA_def_cfa_register, reg */
338 case 0x08: /* v2: DW_CFA_same_value, reg */
339 case 0x07: /* v2: DW_CFA_undefined, reg */
340 oper1 = uleb_extract(&data[off], ndx);
341 dbg_print(0, MSG_ORIG(MSG_CFA_REG), PREFIX,
342 REGNAME(oper1, rbuf1));
343 break;
344
345
346 case 0x09: /* v2: DW_CFA_register, reg, reg */
347 oper1 = uleb_extract(&data[off], ndx);
348 oper2 = uleb_extract(&data[off], ndx);
349 dbg_print(0, MSG_ORIG(MSG_CFA_REG_REG), PREFIX,
350 REGNAME(oper1, rbuf1), REGNAME(oper2, rbuf2));
351 break;
352
353 case 0x0c: /* v2: DW_CFA_def_cfa, reg, offset */
354 oper1 = uleb_extract(&data[off], ndx);
355 oper2 = uleb_extract(&data[off], ndx);
356 dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLU), PREFIX,
357 REGNAME(oper1, rbuf1), EC_XWORD(oper2));
358 break;
359
360 case 0x0e: /* v2: DW_CFA_def_cfa_offset, offset */
361 oper1 = uleb_extract(&data[off], ndx);
362 dbg_print(0, MSG_ORIG(MSG_CFA_LLU), PREFIX,
363 EC_XWORD(oper1));
364 break;
365
366 case 0x0f: /* v3: DW_CFA_def_cfa_expression, blk */
367 oper1 = uleb_extract(&data[off], ndx);
368 dbg_print(0, MSG_ORIG(MSG_CFA_EBLK), PREFIX,
369 EC_XWORD(oper1));
370 /* We currently do not decode the expression block */
371 *ndx += oper1;
372 break;
373
374 case 0x10: /* v3: DW_CFA_expression, reg, blk */
375 case 0x16: /* v3: DW_CFA_val_expression,reg,blk */
376 oper1 = uleb_extract(&data[off], ndx);
377 oper2 = uleb_extract(&data[off], ndx);
378 dbg_print(0, MSG_ORIG(MSG_CFA_REG_EBLK), PREFIX,
379 REGNAME(oper1, rbuf1), EC_XWORD(oper2));
380 /* We currently do not decode the expression block */
381 *ndx += oper2;
382 break;
383
384 case 0x11: /* v3: DW_CFA_offset_extended_sf, reg, off */
385 oper1 = uleb_extract(&data[off], ndx);
386 soper = sleb_extract(&data[off], ndx) *
387 state->ciedalign;
388 dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX,
389 REGNAME(oper1, rbuf1), EC_SXWORD(soper));
390 break;
391
392 case 0x12: /* v3: DW_CFA_def_cfa_sf, reg, offset */
393 oper1 = uleb_extract(&data[off], ndx);
394 soper = sleb_extract(&data[off], ndx) *
395 state->ciedalign;
396 dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLD), PREFIX,
397 REGNAME(oper1, rbuf1), EC_SXWORD(soper));
398 break;
399
400 case 0x13: /* DW_CFA_def_cfa_offset_sf, offset */
401 soper = sleb_extract(&data[off], ndx) *
402 state->ciedalign;
403 dbg_print(0, MSG_ORIG(MSG_CFA_LLD), PREFIX,
404 EC_SXWORD(soper));
405 break;
406
407 case 0x14: /* v3: DW_CFA_val_offset, reg, offset */
408 oper1 = uleb_extract(&data[off], ndx);
409 soper = uleb_extract(&data[off], ndx) *
410 state->ciedalign;
411 dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLD), PREFIX,
412 REGNAME(oper1, rbuf1), EC_SXWORD(soper));
413 break;
414
415 case 0x15: /* v3: DW_CFA_val_offset_sf, reg, offset */
416 oper1 = uleb_extract(&data[off], ndx);
417 soper = sleb_extract(&data[off], ndx) *
418 state->ciedalign;
419 dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLD), PREFIX,
420 REGNAME(oper1, rbuf1), EC_SXWORD(soper));
421 break;
422
423 case 0x1d: /* GNU: DW_CFA_MIPS_advance_loc8, delta */
424 oper1 = dwarf_extract_uint(data + off, ndx, i,
425 state->do_swap) * state->ciecalign;
426 cur_pc += oper1;
427 dbg_print(0, MSG_ORIG(MSG_CFA_ADV_LOC), PREFIX,
428 loc_str, EC_XWORD(oper1), EC_XWORD(cur_pc));
429 loc_str = MSG_ORIG(MSG_STR_LOC);
430 break;
431
432 case 0x2e: /* GNU: DW_CFA_GNU_args_size, size */
433 oper1 = uleb_extract(&data[off], ndx);
434 dbg_print(0, MSG_ORIG(MSG_CFA_LLU), PREFIX,
435 EC_XWORD(oper1));
436
437 break;
438
439 case 0x2f: /* GNU:DW_CFA_GNU_negative_offset_extended,reg,off */
440 oper1 = uleb_extract(&data[off], ndx);
441 soper = -uleb_extract(&data[off], ndx) *
442 state->ciedalign;
443 dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX,
444 REGNAME(oper1, rbuf1), EC_SXWORD(soper));
445 break;
446
447 default:
448 /*
449 * Unrecognized OP code: DWARF data is variable length,
450 * so we don't know how many bytes to skip in order to
451 * advance to the next item. We cannot decode beyond
452 * this point, so dump the remainder in hex.
453 */
454 (*ndx)--; /* Back up to unrecognized opcode */
455 dump_hex_bytes(data + off + *ndx, len - *ndx,
456 indent, 8, 1);
457 (*ndx) = len;
458 break;
459 }
460 }
461
462 #undef PREFIX
463 #undef REGNAME
464 #undef LOW_OP
465 }
466
467 void
468 dump_eh_frame(uchar_t *data, size_t datasize, uint64_t sh_addr,
469 Half e_machine, uchar_t *e_ident, uint64_t gotaddr)
470 {
471 Conv_dwarf_ehe_buf_t dwarf_ehe_buf;
472 dump_cfi_state_t cfi_state;
473 uint64_t off, ndx;
474 uint_t cieid, cielength, cieversion, cieretaddr;
475 int ciePflag, cieZflag, cieLflag, cieLflag_present;
476 uint_t cieaugndx, length, id;
477 char *cieaugstr;
478
479 cfi_state.e_machine = e_machine;
480 cfi_state.e_ident = e_ident;
481 cfi_state.sh_addr = sh_addr;
482 cfi_state.do_swap = _elf_sys_encoding() != e_ident[EI_DATA];
483 cfi_state.gotaddr = gotaddr;
484
485 off = 0;
486 while (off < datasize) {
487 ndx = 0;
488
489 /*
490 * Extract length in native format. A zero length indicates
491 * that this CIE is a terminator and that processing for this
492 * unwind information should end. However, skip this entry and
493 * keep processing, just in case there is any other information
494 * remaining in this section. Note, ld(1) will terminate the
495 * processing of the .eh_frame contents for this file after a
496 * zero length CIE, thus any information that does follow is
497 * ignored by ld(1), and is therefore questionable.
498 */
499 length = (uint_t)dwarf_extract_uint(data + off, &ndx,
500 4, cfi_state.do_swap);
501 if (length == 0) {
502 dbg_print(0, MSG_ORIG(MSG_UNW_ZEROTERM));
503 off += 4;
504 continue;
505 }
506
507 /*
508 * extract CIE id in native format
509 */
510 id = (uint_t)dwarf_extract_uint(data + off, &ndx,
511 4, cfi_state.do_swap);
512
513 /*
514 * A CIE record has an id of '0', otherwise this is a
515 * FDE entry and the 'id' is the CIE pointer.
516 */
517 if (id == 0) {
518 uint64_t persVal, ndx_save;
519 uint_t axsize;
520
521 cielength = length;
522 cieid = id;
523 ciePflag = cfi_state.cieRflag = cieZflag = 0;
524 cieLflag = cieLflag_present = 0;
525
526 dbg_print(0, MSG_ORIG(MSG_UNW_CIE),
527 EC_XWORD(sh_addr + off));
528 dbg_print(0, MSG_ORIG(MSG_UNW_CIELNGTH),
529 cielength, cieid);
530
531 cieversion = data[off + ndx];
532 ndx += 1;
533 cieaugstr = (char *)(&data[off + ndx]);
534 ndx += strlen(cieaugstr) + 1;
535
536 dbg_print(0, MSG_ORIG(MSG_UNW_CIEVERS),
537 cieversion, cieaugstr);
538
539 cfi_state.ciecalign = uleb_extract(&data[off], &ndx);
540 cfi_state.ciedalign = sleb_extract(&data[off], &ndx);
541 cieretaddr = data[off + ndx];
542 ndx += 1;
543
544 dbg_print(0, MSG_ORIG(MSG_UNW_CIECALGN),
545 EC_XWORD(cfi_state.ciecalign),
546 EC_XWORD(cfi_state.ciedalign), cieretaddr);
547
548 if (cieaugstr[0])
549 dbg_print(0, MSG_ORIG(MSG_UNW_CIEAXVAL));
550
551 for (cieaugndx = 0; cieaugstr[cieaugndx]; cieaugndx++) {
552 switch (cieaugstr[cieaugndx]) {
553 case 'z':
554 axsize = uleb_extract(&data[off], &ndx);
555 dbg_print(0, MSG_ORIG(MSG_UNW_CIEAXSIZ),
556 axsize);
557 cieZflag = 1;
558 /*
559 * The auxiliary section can contain
560 * unused padding bytes at the end, so
561 * save the current index. Along with
562 * axsize, we will use it to set ndx to
563 * the proper continuation index after
564 * the aux data has been processed.
565 */
566 ndx_save = ndx;
567 break;
568 case 'P':
569 ciePflag = data[off + ndx];
570 ndx += 1;
571
572 persVal = dwarf_ehe_extract(&data[off],
573 &ndx, ciePflag, e_ident, B_FALSE,
574 sh_addr, off + ndx, gotaddr);
575 dbg_print(0,
576 MSG_ORIG(MSG_UNW_CIEAXPERS));
577 dbg_print(0,
578 MSG_ORIG(MSG_UNW_CIEAXPERSENC),
579 ciePflag, conv_dwarf_ehe(ciePflag,
580 &dwarf_ehe_buf));
581 dbg_print(0,
582 MSG_ORIG(MSG_UNW_CIEAXPERSRTN),
583 EC_XWORD(persVal));
584 break;
585 case 'R':
586 cfi_state.cieRflag = data[off + ndx];
587 ndx += 1;
588 dbg_print(0,
589 MSG_ORIG(MSG_UNW_CIEAXCENC),
590 cfi_state.cieRflag,
591 conv_dwarf_ehe(cfi_state.cieRflag,
592 &dwarf_ehe_buf));
593 break;
594 case 'L':
612 * If the z flag was present, reposition ndx using the
613 * length given. This will safely move us past any
614 * unaccessed padding bytes in the auxiliary section.
615 */
616 if (cieZflag)
617 ndx = ndx_save + axsize;
618
619 /*
620 * Any remaining data are Call Frame Instructions
621 */
622 if ((cielength + 4) > ndx)
623 dump_cfi(data, off, &ndx, cielength, &cfi_state,
624 MSG_ORIG(MSG_UNW_CIECFI), 3);
625 off += cielength + 4;
626
627 } else {
628 uint_t fdelength = length;
629 int fdecieptr = id;
630 uint64_t fdeaddrrange;
631
632 dbg_print(0, MSG_ORIG(MSG_UNW_FDE),
633 EC_XWORD(sh_addr + off));
634 dbg_print(0, MSG_ORIG(MSG_UNW_FDELNGTH),
635 fdelength, fdecieptr);
636
637 cfi_state.fdeinitloc = dwarf_ehe_extract(&data[off],
638 &ndx, cfi_state.cieRflag, e_ident, B_FALSE,
639 sh_addr, off + ndx, gotaddr);
640 fdeaddrrange = dwarf_ehe_extract(&data[off], &ndx,
641 (cfi_state.cieRflag & ~DW_EH_PE_pcrel),
642 e_ident, B_FALSE, sh_addr, off + ndx, gotaddr);
643
644 dbg_print(0, MSG_ORIG(MSG_UNW_FDEINITLOC),
645 EC_XWORD(cfi_state.fdeinitloc),
646 EC_XWORD(fdeaddrrange),
647 EC_XWORD(cfi_state.fdeinitloc + fdeaddrrange - 1));
648
649 if (cieaugstr[0])
650 dbg_print(0, MSG_ORIG(MSG_UNW_FDEAXVAL));
651 if (cieZflag) {
652 uint64_t val;
653 uint64_t lndx;
654
655 val = uleb_extract(&data[off], &ndx);
656 lndx = ndx;
657 ndx += val;
658 dbg_print(0, MSG_ORIG(MSG_UNW_FDEAXSIZE),
659 EC_XWORD(val));
660 if (val && cieLflag_present) {
661 uint64_t lsda;
662
663 lsda = dwarf_ehe_extract(&data[off],
664 &lndx, cieLflag, e_ident,
665 B_FALSE, sh_addr, off + lndx,
666 gotaddr);
667 dbg_print(0,
668 MSG_ORIG(MSG_UNW_FDEAXLSDA),
669 EC_XWORD(lsda));
670 }
671 }
672 if ((fdelength + 4) > ndx)
673 dump_cfi(data, off, &ndx, fdelength, &cfi_state,
674 MSG_ORIG(MSG_UNW_FDECFI), 6);
675 off += fdelength + 4;
676 }
677 }
678 }
|
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include <_libelf.h>
28 #include <dwarf.h>
29 #include <stdio.h>
30 #include <unistd.h>
31 #include <errno.h>
32 #include <strings.h>
33 #include <debug.h>
34 #include <conv.h>
35 #include <msg.h>
36 #include <_elfdump.h>
37
38
39 /*
40 * Data from eh_frame section used by dump_cfi()
41 */
42 typedef struct {
43 const char *file;
44 const char *sh_name;
45 Half e_machine; /* ehdr->e_machine */
46 uchar_t *e_ident; /* ehdr->e_ident */
47 uint64_t sh_addr; /* Address of eh_frame section */
48 int do_swap; /* True if object and system byte */
49 /* order differs */
50 int cieRflag; /* R flag from current CIE */
51 uint64_t ciecalign; /* CIE code align factor */
52 int64_t ciedalign; /* CIE data align factor */
53 uint64_t fdeinitloc; /* FDE initial location */
54 uint64_t gotaddr; /* Address of the GOT */
55 } dump_cfi_state_t;
56
57
58 /*
59 * Extract an unsigned integer value from an .eh_frame section, converting it
60 * from its native byte order to that of the running machine if necessary.
61 *
62 * entry:
63 * data - Base address from which to extract datum
64 * ndx - Address of variable giving index to start byte in data.
65 * size - # of bytes in datum. Must be one of: 1, 2, 4, 8
66 * do_swap - True if the data is in a different byte order than that
67 * of the host system.
68 *
69 * exit:
70 * *ndx is incremented by the size of the extracted datum.
71 *
72 * The requested datum is extracted, byte swapped if necessary,
73 * and returned.
74 */
75 static dwarf_error_t
76 dwarf_extract_uint(uchar_t *data, size_t len, uint64_t *ndx, int size,
77 int do_swap, uint64_t *ret)
78 {
79 if (((*ndx + size) > len) ||
80 ((*ndx + size) < *ndx))
81 return (DW_OVERFLOW);
82
83 switch (size) {
84 case 1:
85 *ret = (data[(*ndx)++]);
86 return (DW_SUCCESS);
87 case 2:
88 {
89 Half r;
90 uchar_t *p = (uchar_t *)&r;
91
92 data += *ndx;
93 if (do_swap)
94 UL_ASSIGN_BSWAP_HALF(p, data);
95 else
96 UL_ASSIGN_HALF(p, data);
97
98 (*ndx) += 2;
99 *ret = r;
100 return (DW_SUCCESS);
101 }
102 case 4:
103 {
104 Word r;
105 uchar_t *p = (uchar_t *)&r;
106
107 data += *ndx;
108 if (do_swap)
109 UL_ASSIGN_BSWAP_WORD(p, data);
110 else
111 UL_ASSIGN_WORD(p, data);
112
113 (*ndx) += 4;
114 *ret = r;
115 return (DW_SUCCESS);
116 }
117
118 case 8:
119 {
120 uint64_t r;
121 uchar_t *p = (uchar_t *)&r;
122
123 data += *ndx;
124 if (do_swap)
125 UL_ASSIGN_BSWAP_LWORD(p, data);
126 else
127 UL_ASSIGN_LWORD(p, data);
128
129 (*ndx) += 8;
130 *ret = r;
131 return (DW_SUCCESS);
132 }
133 default:
134 return (DW_BAD_ENCODING);
135 }
136
137 /* NOTREACHED */
138 }
139
140 /*
141 * Map a DWARF register constant to the machine register name it
142 * corresponds to, formatting the result into buf.
143 *
144 * The assignment of DWARF register numbers is part of the system
145 * specific ABI for each platform.
146 *
147 * entry:
148 * regno - DWARF register number
149 * mach - ELF machine code for platform
150 * buf, bufsize - Buffer to receive the formatted result string
151 *
152 * exit:
153 * The results are formatted into buf, and buf is returned.
154 * If the generated output would exceed the size of the buffer
155 * provided, it will be clipped to fit.
156 */
157 static const char *
170 */
171 if (good_name)
172 (void) snprintf(buf, bufsize, MSG_ORIG(MSG_REG_FMT_NAME),
173 regno, name);
174 else
175 (void) snprintf(buf, bufsize, MSG_ORIG(MSG_REG_FMT_BASIC),
176 regno);
177
178 return (buf);
179 }
180
181
182 /*
183 * Decode eh_frame Call Frame Instructions, printing each one on a
184 * separate line.
185 *
186 * entry:
187 * data - Address of base of eh_frame section being processed
188 * off - Offset of current FDE within eh_frame
189 * ndx - Index of current position within current FDE
190 * len - Length of FDE
191 * state - Object, CIE, and FDE state for current request
192 * msg - Header message to issue before producing output.
193 * indent - # of indentation characters issued for each line of output.
194 *
195 * exit:
196 * The Call Frame Instructions have been decoded and printed.
197 *
198 * *ndx has been incremented to contain the index of the next
199 * byte of data to be processed in eh_frame.
200 *
201 * note:
202 * The format of Call Frame Instructions in .eh_frame sections is based
203 * on the DWARF specification.
204 */
205 static void
206 dump_cfi(uchar_t *data, uint64_t off, uint64_t *ndx, uint_t len,
207 dump_cfi_state_t *state, const char *msg, int indent)
208 {
209 /*
210 * We use %*s%s to insert leading whitespace and the op name.
257 * 0 uses the lower 6 bits to specify a sub-opcode, allowing
258 * for 64 of them. The other 3 primary op codes use the
259 * lower 6 bits to hold an operand (a register #, or value).
260 *
261 * Check the primary OP code. If it's 1-3, handle it
262 * and move to the next loop iteration. For OP code 0,
263 * fall through to decode the sub-code.
264 */
265 op = data[off + (*ndx)++];
266 opname = conv_dwarf_cfa(op, 0, &inv_buf);
267 switch (op >> 6) {
268 case 0x1: /* v2: DW_CFA_advance_loc, delta */
269 oper1 = state->ciecalign * LOW_OP(op);
270 cur_pc += oper1;
271 dbg_print(0, MSG_ORIG(MSG_CFA_ADV_LOC), PREFIX,
272 loc_str, EC_XWORD(oper1), EC_XWORD(cur_pc));
273 loc_str = MSG_ORIG(MSG_STR_LOC);
274 continue;
275
276 case 0x2: /* v2: DW_CFA_offset, reg, offset */
277 if (uleb_extract(&data[off], ndx, len, &oper1) ==
278 DW_OVERFLOW) {
279 (void) fprintf(stderr,
280 MSG_INTL(MSG_ERR_DWOVRFLW),
281 state->file, state->sh_name);
282 return;
283 }
284
285 oper1 *= state->ciedalign;
286 dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX,
287 REGNAME(LOW_OP(op), rbuf1), EC_XWORD(oper1));
288 continue;
289
290 case 0x3: /* v2: DW_CFA_restore, reg */
291 dbg_print(0, MSG_ORIG(MSG_CFA_REG), PREFIX,
292 REGNAME(LOW_OP(op), rbuf1));
293 continue;
294 }
295
296 /*
297 * If we're here, the high order 2 bits are 0. The low 6 bits
298 * specify a sub-opcode defining the operation.
299 */
300 switch (op) {
301 case 0x00: /* v2: DW_CFA_nop */
302 /*
303 * No-ops are used to fill unused space required
304 * for alignment. It is common for there to be
305 * multiple adjacent nops. It saves space to report
306 * them all with a single line of output.
307 */
308 for (i = 1;
309 (*ndx < len) && (data[off + *ndx] == 0);
310 i++, (*ndx)++)
311 ;
312 dbg_print(0, MSG_ORIG(MSG_CFA_SIMPLEREP), PREFIX, i);
313 break;
314
315 case 0x0a: /* v2: DW_CFA_remember_state */
316 case 0x0b: /* v2: DW_CFA_restore_state */
317 case 0x2d: /* GNU: DW_CFA_GNU_window_save */
318 dbg_print(0, MSG_ORIG(MSG_CFA_SIMPLE), PREFIX);
319 break;
320
321 case 0x01: /* v2: DW_CFA_set_loc, address */
322 switch (dwarf_ehe_extract(&data[off], len, ndx,
323 &cur_pc, state->cieRflag, state->e_ident, B_FALSE,
324 state->sh_addr, off + *ndx, state->gotaddr)) {
325 case DW_OVERFLOW:
326 (void) fprintf(stderr,
327 MSG_INTL(MSG_ERR_DWOVRFLW),
328 state->file, state->sh_name);
329 return;
330 case DW_BAD_ENCODING:
331 (void) fprintf(stderr,
332 MSG_INTL(MSG_ERR_DWBADENC),
333 state->file, state->sh_name,
334 state->cieRflag);
335 return;
336 case DW_SUCCESS:
337 break;
338 }
339 dbg_print(0, MSG_ORIG(MSG_CFA_CFASET), PREFIX,
340 EC_XWORD(cur_pc));
341 break;
342
343 case 0x02: /* v2: DW_CFA_advance_loc_1, 1-byte delta */
344 case 0x03: /* v2: DW_CFA_advance_loc_2, 2-byte delta */
345 case 0x04: /* v2: DW_CFA_advance_loc_4, 4-byte delta */
346 /*
347 * Since the codes are contiguous, and the sizes are
348 * powers of 2, we can compute the word width from
349 * the code.
350 */
351 i = 1 << (op - 0x02);
352 switch (dwarf_extract_uint(data + off, len,
353 ndx, i, state->do_swap, &oper1)) {
354 case DW_BAD_ENCODING:
355 (void) fprintf(stderr,
356 MSG_INTL(MSG_ERR_DWBADENC),
357 state->file, state->sh_name,
358 i);
359 return;
360 case DW_OVERFLOW:
361 (void) fprintf(stderr,
362 MSG_INTL(MSG_ERR_DWOVRFLW),
363 state->file, state->sh_name);
364 return;
365 case DW_SUCCESS:
366 break;
367 }
368 oper1 *= state->ciecalign;
369 cur_pc += oper1;
370 dbg_print(0, MSG_ORIG(MSG_CFA_ADV_LOC), PREFIX,
371 loc_str, EC_XWORD(oper1), EC_XWORD(cur_pc));
372 loc_str = MSG_ORIG(MSG_STR_LOC);
373 break;
374
375 case 0x05: /* v2: DW_CFA_offset_extended,reg,off */
376 if (uleb_extract(&data[off], ndx, len, &oper1) ==
377 DW_OVERFLOW) {
378 (void) fprintf(stderr,
379 MSG_INTL(MSG_ERR_DWOVRFLW),
380 state->file, state->sh_name);
381 return;
382 }
383
384 if (sleb_extract(&data[off], ndx, len, &soper) ==
385 DW_OVERFLOW) {
386 (void) fprintf(stderr,
387 MSG_INTL(MSG_ERR_DWOVRFLW),
388 state->file, state->sh_name);
389 return;
390 }
391
392 soper *= state->ciedalign;
393 dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX,
394 REGNAME(oper1, rbuf1), EC_SXWORD(soper));
395 break;
396
397 case 0x06: /* v2: DW_CFA_restore_extended, reg */
398 case 0x0d: /* v2: DW_CFA_def_cfa_register, reg */
399 case 0x08: /* v2: DW_CFA_same_value, reg */
400 case 0x07: /* v2: DW_CFA_undefined, reg */
401 if (uleb_extract(&data[off], ndx, len, &oper1) ==
402 DW_OVERFLOW) {
403 (void) fprintf(stderr,
404 MSG_INTL(MSG_ERR_DWOVRFLW),
405 state->file, state->sh_name);
406 return;
407 }
408
409 dbg_print(0, MSG_ORIG(MSG_CFA_REG), PREFIX,
410 REGNAME(oper1, rbuf1));
411 break;
412
413
414 case 0x09: /* v2: DW_CFA_register, reg, reg */
415 if (uleb_extract(&data[off], ndx, len, &oper1) ==
416 DW_OVERFLOW) {
417 (void) fprintf(stderr,
418 MSG_INTL(MSG_ERR_DWOVRFLW),
419 state->file, state->sh_name);
420 return;
421 }
422
423 if (uleb_extract(&data[off], ndx, len, &oper2) ==
424 DW_OVERFLOW) {
425 (void) fprintf(stderr,
426 MSG_INTL(MSG_ERR_DWOVRFLW),
427 state->file, state->sh_name);
428 return;
429 }
430 dbg_print(0, MSG_ORIG(MSG_CFA_REG_REG), PREFIX,
431 REGNAME(oper1, rbuf1), REGNAME(oper2, rbuf2));
432 break;
433
434 case 0x0c: /* v2: DW_CFA_def_cfa, reg, offset */
435 if (uleb_extract(&data[off], ndx, len, &oper1) ==
436 DW_OVERFLOW) {
437 (void) fprintf(stderr,
438 MSG_INTL(MSG_ERR_DWOVRFLW),
439 state->file, state->sh_name);
440 return;
441 }
442
443 if (uleb_extract(&data[off], ndx, len, &oper2) ==
444 DW_OVERFLOW) {
445 (void) fprintf(stderr,
446 MSG_INTL(MSG_ERR_DWOVRFLW),
447 state->file, state->sh_name);
448 return;
449 }
450 dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLU), PREFIX,
451 REGNAME(oper1, rbuf1), EC_XWORD(oper2));
452 break;
453
454 case 0x0e: /* v2: DW_CFA_def_cfa_offset, offset */
455 if (uleb_extract(&data[off], ndx, len, &oper1) ==
456 DW_OVERFLOW) {
457 (void) fprintf(stderr,
458 MSG_INTL(MSG_ERR_DWOVRFLW),
459 state->file, state->sh_name);
460 return;
461 }
462 dbg_print(0, MSG_ORIG(MSG_CFA_LLU), PREFIX,
463 EC_XWORD(oper1));
464 break;
465
466 case 0x0f: /* v3: DW_CFA_def_cfa_expression, blk */
467 if (uleb_extract(&data[off], ndx, len, &oper1) ==
468 DW_OVERFLOW) {
469 (void) fprintf(stderr,
470 MSG_INTL(MSG_ERR_DWOVRFLW),
471 state->file, state->sh_name);
472 return;
473 }
474 dbg_print(0, MSG_ORIG(MSG_CFA_EBLK), PREFIX,
475 EC_XWORD(oper1));
476 /* We currently do not decode the expression block */
477 *ndx += oper1;
478 break;
479
480 case 0x10: /* v3: DW_CFA_expression, reg, blk */
481 case 0x16: /* v3: DW_CFA_val_expression,reg,blk */
482 if (uleb_extract(&data[off], ndx, len, &oper1) ==
483 DW_OVERFLOW) {
484 (void) fprintf(stderr,
485 MSG_INTL(MSG_ERR_DWOVRFLW),
486 state->file, state->sh_name);
487 return;
488 }
489
490 if (uleb_extract(&data[off], ndx, len, &oper2) ==
491 DW_OVERFLOW) {
492 (void) fprintf(stderr,
493 MSG_INTL(MSG_ERR_DWOVRFLW),
494 state->file, state->sh_name);
495 return;
496 }
497 dbg_print(0, MSG_ORIG(MSG_CFA_REG_EBLK), PREFIX,
498 REGNAME(oper1, rbuf1), EC_XWORD(oper2));
499 /* We currently do not decode the expression block */
500 *ndx += oper2;
501 break;
502
503 case 0x11: /* v3: DW_CFA_offset_extended_sf, reg, off */
504 if (uleb_extract(&data[off], ndx, len, &oper1) ==
505 DW_OVERFLOW) {
506 (void) fprintf(stderr,
507 MSG_INTL(MSG_ERR_DWOVRFLW),
508 state->file, state->sh_name);
509 return;
510 }
511
512 if (sleb_extract(&data[off], ndx, len, &soper) ==
513 DW_OVERFLOW) {
514 (void) fprintf(stderr,
515 MSG_INTL(MSG_ERR_DWOVRFLW),
516 state->file, state->sh_name);
517 return;
518 }
519
520 soper *= state->ciedalign;
521 dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX,
522 REGNAME(oper1, rbuf1), EC_SXWORD(soper));
523 break;
524
525 case 0x12: /* v3: DW_CFA_def_cfa_sf, reg, offset */
526 if (uleb_extract(&data[off], ndx, len, &oper1) ==
527 DW_OVERFLOW) {
528 (void) fprintf(stderr,
529 MSG_INTL(MSG_ERR_DWOVRFLW),
530 state->file, state->sh_name);
531 return;
532 }
533
534 if (sleb_extract(&data[off], ndx, len, &soper) ==
535 DW_OVERFLOW) {
536 (void) fprintf(stderr,
537 MSG_INTL(MSG_ERR_DWOVRFLW),
538 state->file, state->sh_name);
539 return;
540 }
541
542 soper *= state->ciedalign;
543 dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLD), PREFIX,
544 REGNAME(oper1, rbuf1), EC_SXWORD(soper));
545 break;
546
547 case 0x13: /* DW_CFA_def_cfa_offset_sf, offset */
548 if (sleb_extract(&data[off], ndx, len, &soper) ==
549 DW_OVERFLOW) {
550 (void) fprintf(stderr,
551 MSG_INTL(MSG_ERR_DWOVRFLW),
552 state->file, state->sh_name);
553 return;
554 }
555
556 soper *= state->ciedalign;
557 dbg_print(0, MSG_ORIG(MSG_CFA_LLD), PREFIX,
558 EC_SXWORD(soper));
559 break;
560
561 case 0x14: /* v3: DW_CFA_val_offset, reg, offset */
562 if (uleb_extract(&data[off], ndx, len, &oper1) ==
563 DW_OVERFLOW) {
564 (void) fprintf(stderr,
565 MSG_INTL(MSG_ERR_DWOVRFLW),
566 state->file, state->sh_name);
567 return;
568 }
569
570 if (sleb_extract(&data[off], ndx, len, &soper) ==
571 DW_OVERFLOW) {
572 (void) fprintf(stderr,
573 MSG_INTL(MSG_ERR_DWOVRFLW),
574 state->file, state->sh_name);
575 return;
576 }
577
578 soper *= state->ciedalign;
579 dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLD), PREFIX,
580 REGNAME(oper1, rbuf1), EC_SXWORD(soper));
581 break;
582
583 case 0x15: /* v3: DW_CFA_val_offset_sf, reg, offset */
584 if (uleb_extract(&data[off], ndx, len, &oper1) ==
585 DW_OVERFLOW) {
586 (void) fprintf(stderr,
587 MSG_INTL(MSG_ERR_DWOVRFLW),
588 state->file, state->sh_name);
589 return;
590 }
591
592 if (sleb_extract(&data[off], ndx, len, &soper) ==
593 DW_OVERFLOW) {
594 (void) fprintf(stderr,
595 MSG_INTL(MSG_ERR_DWOVRFLW),
596 state->file, state->sh_name);
597 return;
598 }
599
600 soper *= state->ciedalign;
601 dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLD), PREFIX,
602 REGNAME(oper1, rbuf1), EC_SXWORD(soper));
603 break;
604
605 case 0x1d: /* GNU: DW_CFA_MIPS_advance_loc8, delta */
606 switch (dwarf_extract_uint(data + off, len,
607 ndx, 8, state->do_swap, &oper1)) {
608 case DW_BAD_ENCODING:
609 (void) fprintf(stderr,
610 MSG_INTL(MSG_ERR_DWBADENC),
611 state->file, state->sh_name,
612 8);
613 return;
614 case DW_OVERFLOW:
615 (void) fprintf(stderr,
616 MSG_INTL(MSG_ERR_DWOVRFLW),
617 state->file, state->sh_name);
618 return;
619 case DW_SUCCESS:
620 break;
621 }
622 oper1 *= state->ciecalign;
623 cur_pc += oper1;
624 dbg_print(0, MSG_ORIG(MSG_CFA_ADV_LOC), PREFIX,
625 loc_str, EC_XWORD(oper1), EC_XWORD(cur_pc));
626 loc_str = MSG_ORIG(MSG_STR_LOC);
627 break;
628
629 case 0x2e: /* GNU: DW_CFA_GNU_args_size, size */
630 if (uleb_extract(&data[off], ndx, len, &oper1) ==
631 DW_OVERFLOW) {
632 (void) fprintf(stderr,
633 MSG_INTL(MSG_ERR_DWOVRFLW),
634 state->file, state->sh_name);
635 return;
636 }
637
638 dbg_print(0, MSG_ORIG(MSG_CFA_LLU), PREFIX,
639 EC_XWORD(oper1));
640
641 break;
642
643 case 0x2f: /* GNU:DW_CFA_GNU_negative_offset_extended,reg,off */
644 if (uleb_extract(&data[off], ndx, len, &oper1) ==
645 DW_OVERFLOW) {
646 (void) fprintf(stderr,
647 MSG_INTL(MSG_ERR_DWOVRFLW),
648 state->file, state->sh_name);
649 return;
650 }
651
652 if (sleb_extract(&data[off], ndx, len, &soper) ==
653 DW_OVERFLOW) {
654 (void) fprintf(stderr,
655 MSG_INTL(MSG_ERR_DWOVRFLW),
656 state->file, state->sh_name);
657 return;
658 }
659 soper = -soper * state->ciedalign;
660 soper *= state->ciedalign;
661 dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX,
662 REGNAME(oper1, rbuf1), EC_SXWORD(soper));
663 break;
664
665 default:
666 /*
667 * Unrecognized OP code: DWARF data is variable length,
668 * so we don't know how many bytes to skip in order to
669 * advance to the next item. We cannot decode beyond
670 * this point, so dump the remainder in hex.
671 */
672 (*ndx)--; /* Back up to unrecognized opcode */
673 dump_hex_bytes(data + off + *ndx, len - *ndx,
674 indent, 8, 1);
675 (*ndx) = len;
676 break;
677 }
678 }
679
680 #undef PREFIX
681 #undef REGNAME
682 #undef LOW_OP
683 }
684
685 void
686 dump_eh_frame(const char *file, char *sh_name, uchar_t *data, size_t datasize,
687 uint64_t sh_addr, Half e_machine, uchar_t *e_ident, uint64_t gotaddr)
688 {
689 Conv_dwarf_ehe_buf_t dwarf_ehe_buf;
690 dump_cfi_state_t cfi_state;
691 uint64_t off, ndx, length, id;
692 uint_t cieid, cielength, cieversion, cieretaddr;
693 int ciePflag = 0, cieZflag = 0, cieLflag = 0;
694 int cieLflag_present = 0;
695 uint_t cieaugndx;
696 char *cieaugstr = NULL;
697 boolean_t have_cie = B_FALSE;
698
699 cfi_state.file = file;
700 cfi_state.sh_name = sh_name;
701 cfi_state.e_machine = e_machine;
702 cfi_state.e_ident = e_ident;
703 cfi_state.sh_addr = sh_addr;
704 cfi_state.do_swap = _elf_sys_encoding() != e_ident[EI_DATA];
705 cfi_state.gotaddr = gotaddr;
706
707 off = 0;
708 while (off < datasize) {
709 ndx = 0;
710
711 /*
712 * Extract length in native format. A zero length indicates
713 * that this CIE is a terminator and that processing for this
714 * unwind information should end. However, skip this entry and
715 * keep processing, just in case there is any other information
716 * remaining in this section. Note, ld(1) will terminate the
717 * processing of the .eh_frame contents for this file after a
718 * zero length CIE, thus any information that does follow is
719 * ignored by ld(1), and is therefore questionable.
720 */
721 if (dwarf_extract_uint(data + off, datasize - off,
722 &ndx, 4, cfi_state.do_swap, &length) == DW_OVERFLOW) {
723 (void) fprintf(stderr,
724 MSG_INTL(MSG_ERR_DWOVRFLW),
725 file, sh_name);
726 return;
727 }
728
729 if (length == 0) {
730 dbg_print(0, MSG_ORIG(MSG_UNW_ZEROTERM));
731 off += 4;
732 continue;
733 }
734
735 if (length > (datasize - off)) {
736 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADCIEFDELEN),
737 file, sh_name, EC_XWORD(length),
738 EC_XWORD(sh_addr + off));
739 /*
740 * If length is wrong, we have no means to find the
741 * next entry, just give up
742 */
743 return;
744 }
745
746 /*
747 * extract CIE id in native format
748 */
749 if (dwarf_extract_uint(data + off, datasize - off, &ndx,
750 4, cfi_state.do_swap, &id) == DW_OVERFLOW) {
751 (void) fprintf(stderr,
752 MSG_INTL(MSG_ERR_DWOVRFLW),
753 file, sh_name);
754 return;
755 }
756
757 /*
758 * A CIE record has an id of '0', otherwise this is a
759 * FDE entry and the 'id' is the CIE pointer.
760 */
761 if (id == 0) {
762 uint64_t persVal, ndx_save = 0;
763 uint64_t axsize;
764
765
766 have_cie = B_TRUE;
767 cielength = length;
768 cieid = id;
769 ciePflag = cfi_state.cieRflag = cieZflag = 0;
770 cieLflag = cieLflag_present = 0;
771
772 dbg_print(0, MSG_ORIG(MSG_UNW_CIE),
773 EC_XWORD(sh_addr + off));
774 dbg_print(0, MSG_ORIG(MSG_UNW_CIELNGTH),
775 cielength, cieid);
776
777 cieversion = data[off + ndx];
778 ndx += 1;
779 cieaugstr = (char *)(&data[off + ndx]);
780 ndx += strlen(cieaugstr) + 1;
781
782 dbg_print(0, MSG_ORIG(MSG_UNW_CIEVERS),
783 cieversion, cieaugstr);
784
785 if (uleb_extract(&data[off], &ndx, datasize - off,
786 &cfi_state.ciecalign) == DW_OVERFLOW) {
787 (void) fprintf(stderr,
788 MSG_INTL(MSG_ERR_DWOVRFLW),
789 file, sh_name);
790 return;
791 }
792
793 if (sleb_extract(&data[off], &ndx, datasize - off,
794 &cfi_state.ciedalign) == DW_OVERFLOW) {
795 (void) fprintf(stderr,
796 MSG_INTL(MSG_ERR_DWOVRFLW),
797 file, sh_name);
798 return;
799 }
800 cieretaddr = data[off + ndx];
801 ndx += 1;
802
803 dbg_print(0, MSG_ORIG(MSG_UNW_CIECALGN),
804 EC_XWORD(cfi_state.ciecalign),
805 EC_XWORD(cfi_state.ciedalign), cieretaddr);
806
807 if (cieaugstr[0])
808 dbg_print(0, MSG_ORIG(MSG_UNW_CIEAXVAL));
809
810 for (cieaugndx = 0; cieaugstr[cieaugndx]; cieaugndx++) {
811 switch (cieaugstr[cieaugndx]) {
812 case 'z':
813 if (uleb_extract(&data[off], &ndx,
814 datasize - off, &axsize) ==
815 DW_OVERFLOW) {
816 (void) fprintf(stderr,
817 MSG_INTL(MSG_ERR_DWOVRFLW),
818 file, sh_name);
819 return;
820 }
821
822 dbg_print(0, MSG_ORIG(MSG_UNW_CIEAXSIZ),
823 EC_XWORD(axsize));
824 cieZflag = 1;
825 /*
826 * The auxiliary section can contain
827 * unused padding bytes at the end, so
828 * save the current index. Along with
829 * axsize, we will use it to set ndx to
830 * the proper continuation index after
831 * the aux data has been processed.
832 */
833 ndx_save = ndx;
834 break;
835 case 'P':
836 ciePflag = data[off + ndx];
837 ndx += 1;
838
839 switch (dwarf_ehe_extract(&data[off],
840 datasize - off, &ndx, &persVal,
841 ciePflag, e_ident, B_FALSE, sh_addr,
842 off + ndx, gotaddr)) {
843 case DW_OVERFLOW:
844 (void) fprintf(stderr,
845 MSG_INTL(MSG_ERR_DWOVRFLW),
846 file, sh_name);
847 return;
848 case DW_BAD_ENCODING:
849 (void) fprintf(stderr,
850 MSG_INTL(MSG_ERR_DWBADENC),
851 file, sh_name, ciePflag);
852 return;
853 case DW_SUCCESS:
854 break;
855 }
856 dbg_print(0,
857 MSG_ORIG(MSG_UNW_CIEAXPERS));
858 dbg_print(0,
859 MSG_ORIG(MSG_UNW_CIEAXPERSENC),
860 ciePflag, conv_dwarf_ehe(ciePflag,
861 &dwarf_ehe_buf));
862 dbg_print(0,
863 MSG_ORIG(MSG_UNW_CIEAXPERSRTN),
864 EC_XWORD(persVal));
865 break;
866 case 'R':
867 cfi_state.cieRflag = data[off + ndx];
868 ndx += 1;
869 dbg_print(0,
870 MSG_ORIG(MSG_UNW_CIEAXCENC),
871 cfi_state.cieRflag,
872 conv_dwarf_ehe(cfi_state.cieRflag,
873 &dwarf_ehe_buf));
874 break;
875 case 'L':
893 * If the z flag was present, reposition ndx using the
894 * length given. This will safely move us past any
895 * unaccessed padding bytes in the auxiliary section.
896 */
897 if (cieZflag)
898 ndx = ndx_save + axsize;
899
900 /*
901 * Any remaining data are Call Frame Instructions
902 */
903 if ((cielength + 4) > ndx)
904 dump_cfi(data, off, &ndx, cielength, &cfi_state,
905 MSG_ORIG(MSG_UNW_CIECFI), 3);
906 off += cielength + 4;
907
908 } else {
909 uint_t fdelength = length;
910 int fdecieptr = id;
911 uint64_t fdeaddrrange;
912
913 if (!have_cie) {
914 (void) fprintf(stderr,
915 MSG_INTL(MSG_ERR_DWNOCIE), file, sh_name);
916 return;
917 }
918
919 dbg_print(0, MSG_ORIG(MSG_UNW_FDE),
920 EC_XWORD(sh_addr + off));
921 dbg_print(0, MSG_ORIG(MSG_UNW_FDELNGTH),
922 fdelength, fdecieptr);
923
924 switch (dwarf_ehe_extract(&data[off], datasize - off,
925 &ndx, &cfi_state.fdeinitloc, cfi_state.cieRflag,
926 e_ident, B_FALSE, sh_addr, off + ndx, gotaddr)) {
927 case DW_OVERFLOW:
928 (void) fprintf(stderr,
929 MSG_INTL(MSG_ERR_DWOVRFLW), file, sh_name);
930 return;
931 case DW_BAD_ENCODING:
932 (void) fprintf(stderr,
933 MSG_INTL(MSG_ERR_DWBADENC), file, sh_name,
934 cfi_state.cieRflag);
935 return;
936 case DW_SUCCESS:
937 break;
938 }
939
940 switch (dwarf_ehe_extract(&data[off], datasize - off,
941 &ndx, &fdeaddrrange,
942 (cfi_state.cieRflag & ~DW_EH_PE_pcrel), e_ident,
943 B_FALSE, sh_addr, off + ndx, gotaddr)) {
944 case DW_OVERFLOW:
945 (void) fprintf(stderr,
946 MSG_INTL(MSG_ERR_DWOVRFLW), file, sh_name);
947 return;
948 case DW_BAD_ENCODING:
949 (void) fprintf(stderr,
950 MSG_INTL(MSG_ERR_DWBADENC), file, sh_name,
951 (cfi_state.cieRflag & ~DW_EH_PE_pcrel));
952 return;
953 case DW_SUCCESS:
954 break;
955 }
956
957 dbg_print(0, MSG_ORIG(MSG_UNW_FDEINITLOC),
958 EC_XWORD(cfi_state.fdeinitloc),
959 EC_XWORD(fdeaddrrange),
960 EC_XWORD(cfi_state.fdeinitloc + fdeaddrrange - 1));
961
962 if ((cieaugstr != NULL) && (cieaugstr[0] != '\0'))
963 dbg_print(0, MSG_ORIG(MSG_UNW_FDEAXVAL));
964 if (cieZflag) {
965 uint64_t val;
966 uint64_t lndx;
967
968 if (uleb_extract(&data[off], &ndx,
969 datasize - off, &val) == DW_OVERFLOW) {
970 (void) fprintf(stderr,
971 MSG_INTL(MSG_ERR_DWOVRFLW),
972 file, sh_name);
973 return;
974 }
975 lndx = ndx;
976 ndx += val;
977 dbg_print(0, MSG_ORIG(MSG_UNW_FDEAXSIZE),
978 EC_XWORD(val));
979 if (val && cieLflag_present) {
980 uint64_t lsda;
981
982 switch (dwarf_ehe_extract(&data[off],
983 datasize - off, &lndx, &lsda,
984 cieLflag, e_ident, B_FALSE, sh_addr,
985 off + lndx, gotaddr)) {
986 case DW_OVERFLOW:
987 (void) fprintf(stderr,
988 MSG_INTL(MSG_ERR_DWOVRFLW),
989 file, sh_name);
990 return;
991 case DW_BAD_ENCODING:
992 (void) fprintf(stderr,
993 MSG_INTL(MSG_ERR_DWBADENC),
994 file, sh_name, cieLflag);
995 return;
996 case DW_SUCCESS:
997 break;
998 }
999 dbg_print(0,
1000 MSG_ORIG(MSG_UNW_FDEAXLSDA),
1001 EC_XWORD(lsda));
1002 }
1003 }
1004 if ((fdelength + 4) > ndx)
1005 dump_cfi(data, off, &ndx, fdelength, &cfi_state,
1006 MSG_ORIG(MSG_UNW_FDECFI), 6);
1007 off += fdelength + 4;
1008 }
1009 }
1010 }
|