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 } dump_cfi_state_t;
53
54
55 /*
56 * Extract an unsigned integer value from an .eh_frame section, converting it
57 * from its native byte order to that of the running machine if necessary.
58 *
59 * entry:
60 * data - Base address from which to extract datum
61 * ndx - Address of variable giving index to start byte in data.
62 * size - # of bytes in datum. Must be one of: 1, 2, 4, 8
63 * do_swap - True if the data is in a different byte order than that
64 * of the host system.
65 *
66 * exit:
67 * *ndx is incremented by the size of the extracted datum.
68 *
69 * The requested datum is extracted, byte swapped if necessary,
70 * and returned.
71 */
284 * No-ops are used to fill unused space required
285 * for alignment. It is common for there to be
286 * multiple adjacent nops. It saves space to report
287 * them all with a single line of output.
288 */
289 for (i = 1;
290 (*ndx < len) && (data[off + *ndx] == 0);
291 i++, (*ndx)++)
292 ;
293 dbg_print(0, MSG_ORIG(MSG_CFA_SIMPLEREP), PREFIX, i);
294 break;
295
296 case 0x0a: /* v2: DW_CFA_remember_state */
297 case 0x0b: /* v2: DW_CFA_restore_state */
298 case 0x2d: /* GNU: DW_CFA_GNU_window_save */
299 dbg_print(0, MSG_ORIG(MSG_CFA_SIMPLE), PREFIX);
300 break;
301
302 case 0x01: /* v2: DW_CFA_set_loc, address */
303 cur_pc = dwarf_ehe_extract(&data[off], ndx,
304 state->cieRflag, state->e_ident,
305 state->sh_addr, off + *ndx);
306 dbg_print(0, MSG_ORIG(MSG_CFA_CFASET), PREFIX,
307 EC_XWORD(cur_pc));
308 break;
309
310 case 0x02: /* v2: DW_CFA_advance_loc_1, 1-byte delta */
311 case 0x03: /* v2: DW_CFA_advance_loc_2, 2-byte delta */
312 case 0x04: /* v2: DW_CFA_advance_loc_4, 4-byte delta */
313 /*
314 * Since the codes are contiguous, and the sizes are
315 * powers of 2, we can compute the word width from
316 * the code.
317 */
318 i = 1 << (op - 0x02);
319 oper1 = dwarf_extract_uint(data + off, ndx, i,
320 state->do_swap) * state->ciecalign;
321 cur_pc += oper1;
322 dbg_print(0, MSG_ORIG(MSG_CFA_ADV_LOC), PREFIX,
323 loc_str, EC_XWORD(oper1), EC_XWORD(cur_pc));
324 loc_str = MSG_ORIG(MSG_STR_LOC);
325 break;
448 * Unrecognized OP code: DWARF data is variable length,
449 * so we don't know how many bytes to skip in order to
450 * advance to the next item. We cannot decode beyond
451 * this point, so dump the remainder in hex.
452 */
453 (*ndx)--; /* Back up to unrecognized opcode */
454 dump_hex_bytes(data + off + *ndx, len - *ndx,
455 indent, 8, 1);
456 (*ndx) = len;
457 break;
458 }
459 }
460
461 #undef PREFIX
462 #undef REGNAME
463 #undef LOW_OP
464 }
465
466 void
467 dump_eh_frame(uchar_t *data, size_t datasize, uint64_t sh_addr,
468 Half e_machine, uchar_t *e_ident)
469 {
470 Conv_dwarf_ehe_buf_t dwarf_ehe_buf;
471 dump_cfi_state_t cfi_state;
472 uint64_t off, ndx;
473 uint_t cieid, cielength, cieversion, cieretaddr;
474 int ciePflag, cieZflag, cieLflag, cieLflag_present;
475 uint_t cieaugndx, length, id;
476 char *cieaugstr;
477
478 cfi_state.e_machine = e_machine;
479 cfi_state.e_ident = e_ident;
480 cfi_state.sh_addr = sh_addr;
481 cfi_state.do_swap = _elf_sys_encoding() != e_ident[EI_DATA];
482
483 off = 0;
484 while (off < datasize) {
485 ndx = 0;
486
487 /*
488 * Extract length in native format. A zero length indicates
489 * that this CIE is a terminator and that processing for this
490 * unwind information should end. However, skip this entry and
491 * keep processing, just in case there is any other information
492 * remaining in this section. Note, ld(1) will terminate the
493 * processing of the .eh_frame contents for this file after a
494 * zero length CIE, thus any information that does follow is
495 * ignored by ld(1), and is therefore questionable.
496 */
497 length = (uint_t)dwarf_extract_uint(data + off, &ndx,
498 4, cfi_state.do_swap);
499 if (length == 0) {
500 dbg_print(0, MSG_ORIG(MSG_UNW_ZEROTERM));
501 off += 4;
551 case 'z':
552 axsize = uleb_extract(&data[off], &ndx);
553 dbg_print(0, MSG_ORIG(MSG_UNW_CIEAXSIZ),
554 axsize);
555 cieZflag = 1;
556 /*
557 * The auxiliary section can contain
558 * unused padding bytes at the end, so
559 * save the current index. Along with
560 * axsize, we will use it to set ndx to
561 * the proper continuation index after
562 * the aux data has been processed.
563 */
564 ndx_save = ndx;
565 break;
566 case 'P':
567 ciePflag = data[off + ndx];
568 ndx += 1;
569
570 persVal = dwarf_ehe_extract(&data[off],
571 &ndx, ciePflag, e_ident,
572 sh_addr, off + ndx);
573 dbg_print(0,
574 MSG_ORIG(MSG_UNW_CIEAXPERS));
575 dbg_print(0,
576 MSG_ORIG(MSG_UNW_CIEAXPERSENC),
577 ciePflag, conv_dwarf_ehe(ciePflag,
578 &dwarf_ehe_buf));
579 dbg_print(0,
580 MSG_ORIG(MSG_UNW_CIEAXPERSRTN),
581 EC_XWORD(persVal));
582 break;
583 case 'R':
584 cfi_state.cieRflag = data[off + ndx];
585 ndx += 1;
586 dbg_print(0,
587 MSG_ORIG(MSG_UNW_CIEAXCENC),
588 cfi_state.cieRflag,
589 conv_dwarf_ehe(cfi_state.cieRflag,
590 &dwarf_ehe_buf));
591 break;
592 case 'L':
616
617 /*
618 * Any remaining data are Call Frame Instructions
619 */
620 if ((cielength + 4) > ndx)
621 dump_cfi(data, off, &ndx, cielength, &cfi_state,
622 MSG_ORIG(MSG_UNW_CIECFI), 3);
623 off += cielength + 4;
624
625 } else {
626 uint_t fdelength = length;
627 int fdecieptr = id;
628 uint64_t fdeaddrrange;
629
630 dbg_print(0, MSG_ORIG(MSG_UNW_FDE),
631 EC_XWORD(sh_addr + off));
632 dbg_print(0, MSG_ORIG(MSG_UNW_FDELNGTH),
633 fdelength, fdecieptr);
634
635 cfi_state.fdeinitloc = dwarf_ehe_extract(&data[off],
636 &ndx, cfi_state.cieRflag, e_ident,
637 sh_addr, off + ndx);
638 fdeaddrrange = dwarf_ehe_extract(&data[off], &ndx,
639 (cfi_state.cieRflag & ~DW_EH_PE_pcrel),
640 e_ident, sh_addr, off + ndx);
641
642 dbg_print(0, MSG_ORIG(MSG_UNW_FDEINITLOC),
643 EC_XWORD(cfi_state.fdeinitloc),
644 EC_XWORD(fdeaddrrange),
645 EC_XWORD(cfi_state.fdeinitloc + fdeaddrrange - 1));
646
647 if (cieaugstr[0])
648 dbg_print(0, MSG_ORIG(MSG_UNW_FDEAXVAL));
649 if (cieZflag) {
650 uint64_t val;
651 uint64_t lndx;
652
653 val = uleb_extract(&data[off], &ndx);
654 lndx = ndx;
655 ndx += val;
656 dbg_print(0, MSG_ORIG(MSG_UNW_FDEAXSIZE),
657 EC_XWORD(val));
658 if (val && cieLflag_present) {
659 uint64_t lsda;
660
661 lsda = dwarf_ehe_extract(&data[off],
662 &lndx, cieLflag, e_ident,
663 sh_addr, off + lndx);
664 dbg_print(0,
665 MSG_ORIG(MSG_UNW_FDEAXLSDA),
666 EC_XWORD(lsda));
667 }
668 }
669 if ((fdelength + 4) > ndx)
670 dump_cfi(data, off, &ndx, fdelength, &cfi_state,
671 MSG_ORIG(MSG_UNW_FDECFI), 6);
672 off += fdelength + 4;
673 }
674 }
675 }
|
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 */
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;
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;
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':
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 }
|