From: Ulrich Drepper Date: Tue, 6 Jan 2009 08:30:01 +0000 (-0800) Subject: Implement call frame information dumping. X-Git-Tag: elfutils-0.139~36 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ac194d052517be32d1e3dab62782d5f734994dca;p=thirdparty%2Felfutils.git Implement call frame information dumping. --- diff --git a/NEWS b/NEWS index 544887478..30fcbc0a6 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,8 @@ Version 0.139: libcpu: Add Intel SSE4 disassembler support +readelf: Implement call frame information dumping. + Version 0.138: Install header file for applications to use in source diff --git a/libdw/ChangeLog b/libdw/ChangeLog index 235fac013..eaaab2dda 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,3 +1,10 @@ +2009-01-06 Ulrich Drepper + + * libdw.h: Add definition for unwind and call frame information. + + * memory-access.h: Define read_ubyte_unaligned, read_sbyte_unaligned, + read_ubyte_unaligned_inc, and read_sbyte_unaligned_inc. + 2008-08-15 Roland McGrath * libdw.map (ELFUTILS_0.136): New version set, inherits from diff --git a/libdw/dwarf.h b/libdw/dwarf.h index f1261c361..091519c56 100644 --- a/libdw/dwarf.h +++ b/libdw/dwarf.h @@ -668,6 +668,40 @@ enum DW_CFA_high_user = 0x3f }; +/* ID indicating CIE as opposed to FDE in .debug_frame. */ +enum + { + DW_CIE_ID = 0xffffffff + }; + + +/* Information for GNU unwind information. */ +enum + { + DW_EH_PE_absptr = 0x00, + DW_EH_PE_omit = 0xff, + + /* FDE data encoding. */ + DW_EH_PE_uleb128 = 0x01, + DW_EH_PE_udata2 = 0x02, + DW_EH_PE_udata4 = 0x03, + DW_EH_PE_udata8 = 0x04, + DW_EH_PE_sleb128 = 0x09, + DW_EH_PE_sdata2 = 0x0a, + DW_EH_PE_sdata4 = 0x0b, + DW_EH_PE_sdata8 = 0x0c, + DW_EH_PE_signed = 0x08, + + /* FDE flags. */ + DW_EH_PE_pcrel = 0x10, + DW_EH_PE_textrel = 0x20, + DW_EH_PE_datarel = 0x30, + DW_EH_PE_funcrel = 0x40, + DW_EH_PE_aligned = 0x50, + + DW_EH_PE_indirect = 0x80 + }; + /* DWARF XXX. */ #define DW_ADDR_none 0 diff --git a/libdw/memory-access.h b/libdw/memory-access.h index 52b41b5b0..74054f952 100644 --- a/libdw/memory-access.h +++ b/libdw/memory-access.h @@ -1,5 +1,5 @@ /* Unaligned memory access functionality. - Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc. + Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2009 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper , 2001. @@ -246,6 +246,17 @@ read_8sbyte_unaligned (Dwarf *dbg, const void *p) #endif /* allow unaligned */ +#define read_ubyte_unaligned(Nbytes, Dbg, Addr) \ + ((Nbytes) == 2 ? read_2ubyte_unaligned (Dbg, Addr) \ + : (Nbytes) == 4 ? read_4ubyte_unaligned (Dbg, Addr) \ + : read_8ubyte_unaligned (Dbg, Addr)) + +#define read_sbyte_unaligned(Nbytes, Dbg, Addr) \ + ((Nbytes) == 2 ? read_2sbyte_unaligned (Dbg, Addr) \ + : (Nbytes) == 4 ? read_4sbyte_unaligned (Dbg, Addr) \ + : read_8sbyte_unaligned (Dbg, Addr)) + + #define read_2ubyte_unaligned_inc(Dbg, Addr) \ ({ uint16_t t_ = read_2ubyte_unaligned (Dbg, Addr); \ Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 2); \ @@ -273,4 +284,15 @@ read_8sbyte_unaligned (Dwarf *dbg, const void *p) Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 8); \ t_; }) + +#define read_ubyte_unaligned_inc(Nbytes, Dbg, Addr) \ + ((Nbytes) == 2 ? read_2ubyte_unaligned_inc (Dbg, Addr) \ + : (Nbytes) == 4 ? read_4ubyte_unaligned_inc (Dbg, Addr) \ + : read_8ubyte_unaligned_inc (Dbg, Addr)) + +#define read_sbyte_unaligned_inc(Nbytes, Dbg, Addr) \ + ((Nbytes) == 2 ? read_2sbyte_unaligned_inc (Dbg, Addr) \ + : (Nbytes) == 4 ? read_4sbyte_unaligned_inc (Dbg, Addr) \ + : read_8sbyte_unaligned_inc (Dbg, Addr)) + #endif /* memory-access.h */ diff --git a/src/ChangeLog b/src/ChangeLog index e4300be99..2e17b5440 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,7 @@ +2009-01-06 Ulrich Drepper + + * readelf.c: Implement call frame debug section dumping. + 2009-01-01 Ulrich Drepper * addr2line.c: Update copyright year. diff --git a/src/readelf.c b/src/readelf.c index e9d4f0da2..2041983dd 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -344,7 +344,7 @@ parse_opt (int key, char *arg, print_debug_sections |= section_aranges; else if (strcmp (arg, "ranges") == 0) print_debug_sections |= section_ranges; - else if (strcmp (arg, "frame") == 0) + else if (strcmp (arg, "frame") == 0 || strcmp (arg, "frames") == 0) print_debug_sections |= section_frame; else if (strcmp (arg, "info") == 0) print_debug_sections |= section_info; @@ -3790,14 +3790,13 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest, { char *a = format_dwarf_addr (dwflmod, 0, addr); printf ("%*s[%4" PRIuMAX "] %s %s\n", - indent, "", (uintmax_t) offset, - known[op] ?: "???", a); + indent, "", (uintmax_t) offset, known[op], a); free (a); } else printf ("%*s[%4" PRIuMAX "] %s %#" PRIxMAX "\n", indent, "", (uintmax_t) offset, - known[op] ?: "???", (uintmax_t) addr); + known[op], (uintmax_t) addr); offset += 1 + addrsize; break; @@ -3805,72 +3804,80 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest, case DW_OP_xderef_size: case DW_OP_pick: case DW_OP_const1u: + // XXX value might be modified by relocation printf ("%*s[%4" PRIuMAX "] %s %" PRIu8 "\n", indent, "", (uintmax_t) offset, - known[op] ?: "???", *((uint8_t *) data)); + known[op], *((uint8_t *) data)); ++data; --len; offset += 2; break; case DW_OP_const2u: + // XXX value might be modified by relocation printf ("%*s[%4" PRIuMAX "] %s %" PRIu16 "\n", indent, "", (uintmax_t) offset, - known[op] ?: "???", read_2ubyte_unaligned (dbg, data)); + known[op], read_2ubyte_unaligned (dbg, data)); len -= 2; data += 2; offset += 3; break; case DW_OP_const4u: + // XXX value might be modified by relocation printf ("%*s[%4" PRIuMAX "] %s %" PRIu32 "\n", indent, "", (uintmax_t) offset, - known[op] ?: "???", read_4ubyte_unaligned (dbg, data)); + known[op], read_4ubyte_unaligned (dbg, data)); len -= 4; data += 4; offset += 5; break; case DW_OP_const8u: + // XXX value might be modified by relocation printf ("%*s[%4" PRIuMAX "] %s %" PRIu64 "\n", indent, "", (uintmax_t) offset, - known[op] ?: "???", read_8ubyte_unaligned (dbg, data)); + known[op], read_8ubyte_unaligned (dbg, data)); len -= 8; data += 8; offset += 9; break; case DW_OP_const1s: + // XXX value might be modified by relocation printf ("%*s[%4" PRIuMAX "] %s %" PRId8 "\n", indent, "", (uintmax_t) offset, - known[op] ?: "???", *((int8_t *) data)); + known[op], *((int8_t *) data)); ++data; --len; offset += 2; break; case DW_OP_const2s: + // XXX value might be modified by relocation printf ("%*s[%4" PRIuMAX "] %s %" PRId16 "\n", indent, "", (uintmax_t) offset, - known[op] ?: "???", read_2sbyte_unaligned (dbg, data)); + known[op], read_2sbyte_unaligned (dbg, data)); len -= 2; data += 2; offset += 3; break; case DW_OP_const4s: + // XXX value might be modified by relocation printf ("%*s[%4" PRIuMAX "] %s %" PRId32 "\n", indent, "", (uintmax_t) offset, - known[op] ?: "???", read_4sbyte_unaligned (dbg, data)); + known[op], read_4sbyte_unaligned (dbg, data)); len -= 4; data += 4; offset += 5; break; case DW_OP_const8s: + // XXX value might be modified by relocation printf ("%*s[%4" PRIuMAX "] %s %" PRId64 "\n", indent, "", (uintmax_t) offset, - known[op] ?: "???", read_8sbyte_unaligned (dbg, data)); + known[op], read_8sbyte_unaligned (dbg, data)); len -= 8; data += 8; offset += 9; @@ -3884,8 +3891,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest, unsigned int uleb; get_uleb128 (uleb, data); printf ("%*s[%4" PRIuMAX "] %s %u\n", - indent, "", (uintmax_t) offset, - known[op] ?: "???", uleb); + indent, "", (uintmax_t) offset, known[op], uleb); len -= data - start; offset += 1 + (data - start); break; @@ -3896,8 +3902,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest, get_uleb128 (uleb, data); get_uleb128 (uleb2, data); printf ("%*s[%4" PRIuMAX "] %s %u, %u\n", - indent, "", (uintmax_t) offset, - known[op] ?: "???", uleb, uleb2); + indent, "", (uintmax_t) offset, known[op], uleb, uleb2); len -= data - start; offset += 1 + (data - start); break; @@ -3909,8 +3914,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest, unsigned int sleb; get_sleb128 (sleb, data); printf ("%*s[%4" PRIuMAX "] %s %d\n", - indent, "", (uintmax_t) offset, - known[op] ?: "???", sleb); + indent, "", (uintmax_t) offset, known[op], sleb); len -= data - start; offset += 1 + (data - start); break; @@ -3920,8 +3924,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest, get_uleb128 (uleb, data); get_sleb128 (sleb, data); printf ("%*s[%4" PRIuMAX "] %s %u %d\n", - indent, "", (uintmax_t) offset, - known[op] ?: "???", uleb, sleb); + indent, "", (uintmax_t) offset, known[op], uleb, sleb); len -= data - start; offset += 1 + (data - start); break; @@ -3931,8 +3934,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest, case DW_OP_skip: case DW_OP_bra: printf ("%*s[%4" PRIuMAX "] %s %" PRIuMAX "\n", - indent, "", (uintmax_t) offset, - known[op] ?: "???", + indent, "", (uintmax_t) offset, known[op], (uintmax_t) (offset + read_2sbyte_unaligned (dbg, data))); len -= 2; data += 2; @@ -4160,13 +4162,569 @@ print_debug_ranges_section (Dwfl_Module *dwflmod, static void -print_debug_frame_section (Dwfl_Module *dwflmod __attribute__ ((unused)), - Ebl *ebl __attribute__ ((unused)), - GElf_Ehdr *ehdr __attribute__ ((unused)), - Elf_Scn *scn __attribute__ ((unused)), - GElf_Shdr *shdr __attribute__ ((unused)), - Dwarf *dbg __attribute__ ((unused))) +print_cfa_program (const unsigned char *readp, const unsigned char *const endp, + Dwarf_Word vma_base, unsigned int code_align, + int data_align, unsigned int ptr_size, Dwfl_Module *dwflmod, + Ebl *ebl, Dwarf *dbg) { + char regnamebuf[16]; + const char *regname (unsigned int regno) + { + const char *str; + int i; + return (ebl_register_info (ebl, regno, regnamebuf, sizeof (regnamebuf), + &str, &str, &i, &i) < 0 + ? "???" : regnamebuf); + } + + puts ("\n Program:"); + Dwarf_Word pc = vma_base; + while (readp < endp) + { + unsigned int opcode = *readp++; + + if (opcode < DW_CFA_advance_loc) + /* Extended opcode. */ + switch (opcode) + { + uint64_t op1; + int64_t sop1; + uint64_t op2; + int64_t sop2; + + case DW_CFA_nop: + puts (" nop"); + break; + case DW_CFA_set_loc: + // XXX overflow check + get_uleb128 (op1, readp); + op1 += vma_base; + printf (" set_loc %" PRIu64 "\n", op1 * code_align); + break; + case DW_CFA_advance_loc1: + printf (" advance_loc1 %u to %#" PRIx64 "\n", + *readp, pc += *readp * code_align); + ++readp; + break; + case DW_CFA_advance_loc2: + op1 = read_2ubyte_unaligned_inc (dbg, readp); + printf (" advance_loc2 %" PRIu64 " to %#" PRIx64 "\n", + op1, pc += op1 * code_align); + break; + case DW_CFA_advance_loc4: + op1 = read_4ubyte_unaligned_inc (dbg, readp); + printf (" advance_loc4 %" PRIu64 " to %#" PRIx64 "\n", + op1, pc += op1 * code_align); + break; + case DW_CFA_offset_extended: + // XXX overflow check + get_uleb128 (op1, readp); + get_uleb128 (op2, readp); + printf (" offset_extended r%" PRIu64 " (%s) at cfa%+" PRId64 + "\n", + op1, regname (op1), op2 * data_align); + break; + case DW_CFA_restore_extended: + // XXX overflow check + get_uleb128 (op1, readp); + printf (" restore_extended r%" PRIu64 " (%s)\n", + op1, regname (op1)); + break; + case DW_CFA_undefined: + // XXX overflow check + get_uleb128 (op1, readp); + printf (" undefined r%" PRIu64 " (%s)\n", op1, regname (op1)); + break; + case DW_CFA_same_value: + // XXX overflow check + get_uleb128 (op1, readp); + printf (" same_value r%" PRIu64 " (%s)\n", op1, regname (op1)); + break; + case DW_CFA_register: + // XXX overflow check + get_uleb128 (op1, readp); + get_uleb128 (op2, readp); + printf (" same_value r%" PRIu64 " (%s) in r%" PRIu64 " (%s)\n", + op1, regname (op1), op2, regname (op2)); + break; + case DW_CFA_remember_state: + puts (" remember_state"); + break; + case DW_CFA_restore_state: + puts (" restore_state"); + break; + case DW_CFA_def_cfa: + // XXX overflow check + get_uleb128 (op1, readp); + get_uleb128 (op2, readp); + printf (" def_cfa r%" PRIu64 " (%s) at offset %" PRIu64 "\n", + op1, regname (op1), op2); + break; + case DW_CFA_def_cfa_register: + // XXX overflow check + get_uleb128 (op1, readp); + printf (" def_cfa_register r%" PRIu64 " (%s)\n", + op1, regname (op1)); + break; + case DW_CFA_def_cfa_offset: + // XXX overflow check + get_uleb128 (op1, readp); + printf (" def_cfa_offset %" PRIu64 "\n", op1); + break; + case DW_CFA_def_cfa_expression: + // XXX overflow check + get_uleb128 (op1, readp); /* Length of DW_FORM_block. */ + printf (" val_expression %" PRIu64 "\n", op1); + print_ops (dwflmod, dbg, 10, 10, ptr_size, op1, readp); + readp += op1; + error (1,0,"need to implement BLOCK reading"); + break; + case DW_CFA_expression: + // XXX overflow check + get_uleb128 (op1, readp); + get_uleb128 (op2, readp); /* Length of DW_FORM_block. */ + printf (" val_expression %" PRIu64 "\n", op1); + print_ops (dwflmod, dbg, 10, 10, ptr_size, op2, readp); + readp += op2; + break; + case DW_CFA_offset_extended_sf: + // XXX overflow check + get_uleb128 (op1, readp); + get_sleb128 (sop2, readp); + printf (" offset_extended_sf r%" PRIu64 " (%s) at cfa%+" + PRId64 "\n", + op1, regname (op1), sop2 * data_align); + break; + case DW_CFA_def_cfa_sf: + // XXX overflow check + get_uleb128 (op1, readp); + get_sleb128 (sop2, readp); + printf (" def_cfa_sf r%" PRIu64 " (%s) at offset %" PRId64 "\n", + op1, regname (op1), sop2 * data_align); + break; + case DW_CFA_def_cfa_offset_sf: + // XXX overflow check + get_sleb128 (sop1, readp); + printf (" def_cfa_offset_sf %" PRId64 "\n", sop1 * data_align); + break; + case DW_CFA_val_offset: + // XXX overflow check + get_uleb128 (op1, readp); + get_uleb128 (op2, readp); + printf (" val_offset %" PRIu64 " at offset %" PRIu64 "\n", + op1, op2 * data_align); + break; + case DW_CFA_val_offset_sf: + // XXX overflow check + get_uleb128 (op1, readp); + get_sleb128 (sop2, readp); + printf (" val_offset %" PRIu64 " at offset %" PRId64 "\n", + op1, sop2 * data_align); + break; + case DW_CFA_val_expression: + // XXX overflow check + get_uleb128 (op1, readp); + get_uleb128 (op2, readp); /* Length of DW_FORM_block. */ + printf (" val_expression %" PRIu64 "\n", op1); + print_ops (dwflmod, dbg, 10, 10, ptr_size, op2, readp); + readp += op2; + break; + case DW_CFA_MIPS_advance_loc8: + op1 = read_8ubyte_unaligned_inc (dbg, readp); + printf (" advance_loc2 %" PRIu64 " to %#" PRIx64 "\n", + op1, pc += op1 * code_align); + break; + case DW_CFA_GNU_window_save: + puts (" window_save"); + break; + case DW_CFA_GNU_args_size: + // XXX overflow check + get_uleb128 (op1, readp); + printf (" args_size %" PRIu64 "\n", op1); + break; + default: + printf (" ??? (%u)\n", opcode); + break; + } + else if (opcode < DW_CFA_offset) + printf (" advance_loc %u to %#" PRIx64 "\n", + opcode & 0x3f, pc += (opcode & 0x3f) * code_align); + else if (opcode < DW_CFA_restore) + { + unsigned int offset; + // XXX overflow check + get_uleb128 (offset, readp); + printf (" offset r%u (%s) at cfa%+d\n", + opcode & 0x3f, regname (opcode & 0x3f), offset * data_align); + } + else + printf (" restore r%u (%s)\n", + opcode & 0x3f, regname (opcode & 0x3f)); + } +} + + +static unsigned int +encoded_ptr_size (int encoding, unsigned int ptr_size) +{ + switch (encoding & 7) + { + case 2: + return 2; + case 3: + return 4; + case 4: + return 8; + default: + return ptr_size; + } +} + + +static void +print_debug_frame_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, + Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg) +{ + size_t shstrndx; + /* We know this call will succeed since it did in the caller. */ + (void) elf_getshstrndx (ebl->elf, &shstrndx); + const char *scnname = elf_strptr (ebl->elf, shstrndx, shdr->sh_name); + + Elf_Data *data = elf_rawdata (scn, NULL); + + if (unlikely (data == NULL)) + { + error (0, 0, gettext ("cannot get %s content: %s"), + scnname, elf_errmsg (-1)); + return; + } + + printf (gettext ("\ +\nDWARF section '%s' at offset %#" PRIx64 ":\n"), + scnname, (uint64_t) shdr->sh_offset); + + struct cieinfo + { + ptrdiff_t cie_offset; + const char *augmentation; + unsigned int code_alignment_factor; + unsigned int data_alignment_factor; + unsigned int fde_encoding; + struct cieinfo *next; + } *cies = NULL; + + const unsigned char *readp = data->d_buf; + const unsigned char *const dataend = ((unsigned char *) data->d_buf + + data->d_size); + bool is_eh_frame = strcmp (scnname, ".eh_frame") == 0; + while (readp < dataend) + { + /* At the beginning there must be a CIE. There can be multiple, + hence we test tis in a loop. */ + ptrdiff_t offset = readp - (unsigned char *) data->d_buf; + + if (unlikely (readp + 12 > dataend)) + { + invalid_data: + error (0, 0, gettext ("invalid data in section [%zu] '%s'"), + elf_ndxscn (scn), scnname); + return; + } + + unsigned int ptr_size = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8; + + Dwarf_Word unit_length = read_4ubyte_unaligned_inc (dbg, readp); + unsigned int length = 4; + if (unlikely (unit_length == 0xffffffff)) + { + unit_length = read_8ubyte_unaligned_inc (dbg, readp); + length = 8; + + if (unlikely (readp + 12 > dataend)) + goto invalid_data; + } + ptrdiff_t start = readp - (unsigned char *) data->d_buf; + const unsigned char *const cieend = readp + unit_length; + if (unlikely (cieend > dataend)) + goto invalid_data; + + Dwarf_Word cie_id; + if (length == 4) + cie_id = read_4ubyte_unaligned_inc (dbg, readp); + else + cie_id = read_8ubyte_unaligned_inc (dbg, readp); + + unsigned int code_alignment_factor; + int data_alignment_factor; + unsigned int fde_encoding = 0; + Dwarf_Word initial_location = 0; + + if ((is_eh_frame && cie_id == 0) + || (! is_eh_frame && cie_id == DW_CIE_ID)) + { + uint_fast8_t version = *readp++; + const char *const augmentation = (const char *) readp; + readp = memchr (readp, '\0', cieend - readp); + if (unlikely (readp == NULL)) + goto invalid_data; + ++readp; + // XXX Check overflow + get_uleb128 (code_alignment_factor, readp); + // XXX Check overflow + get_sleb128 (data_alignment_factor, readp); + + /* In some variant for unwind data there is another field. */ + if (strcmp (augmentation, "eh") == 0) + readp += ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8; + + unsigned int return_address_register; + if (unlikely (version == 1)) + return_address_register = *readp++; + else + // XXX Check overflow + get_uleb128 (return_address_register, readp); + + printf (" [%6jx] CIE length=%" PRIu64 "\n" + " CIE_id: %" PRIu64 "\n" + " version: %u\n" + " augmentation: \"%s\"\n" + " code_alignment_factor: %u\n" + " data_alignment_factor: %d\n" + " return_address_register: %u\n", + offset, (uint64_t) unit_length, (uint64_t) cie_id, + version, augmentation, code_alignment_factor, + data_alignment_factor, return_address_register); + + if (augmentation[0] == 'z') + { + unsigned int print_encoding (unsigned int val) + { + switch (val & 0xf) + { + case DW_EH_PE_absptr: + fputs ("absptr", stdout); + break; + case DW_EH_PE_uleb128: + fputs ("uleb128", stdout); + break; + case DW_EH_PE_udata2: + fputs ("udata2", stdout); + break; + case DW_EH_PE_udata4: + fputs ("udata4", stdout); + break; + case DW_EH_PE_udata8: + fputs ("udata8", stdout); + break; + case DW_EH_PE_sleb128: + fputs ("sleb128", stdout); + break; + case DW_EH_PE_sdata2: + fputs ("sdata2", stdout); + break; + case DW_EH_PE_sdata4: + fputs ("sdata4", stdout); + break; + case DW_EH_PE_sdata8: + fputs ("sdata8", stdout); + break; + default: + /* We did not use any of the bits after all. */ + return val; + } + + return val & ~0xf; + } + + unsigned int print_relinfo (unsigned int val) + { + switch (val & 0x70) + { + case DW_EH_PE_pcrel: + fputs ("pcrel", stdout); + break; + case DW_EH_PE_textrel: + fputs ("textrel", stdout); + break; + case DW_EH_PE_datarel: + fputs ("datarel", stdout); + break; + case DW_EH_PE_funcrel: + fputs ("funcrel", stdout); + break; + case DW_EH_PE_aligned: + fputs ("aligned", stdout); + break; + default: + return val; + } + + return val & ~0x70; + } + + unsigned int augmentationlen; + get_uleb128 (augmentationlen, readp); + + const char *hdr = "Augmentation data:"; + const char *cp = augmentation + 1; + while (*cp != '\0') + { + printf (" %-26s%#x ", hdr, *readp); + hdr = ""; + + if (*cp == 'R') + { + putchar_unlocked ('('); + + unsigned int w = fde_encoding = *readp++; + + if (w & 0xf) + w = print_encoding (w); + + if (w & 0x70) + { + if (w != fde_encoding) + fputc_unlocked (' ', stdout); + + w = print_relinfo (w); + } + + if (w != 0) + printf ("(%s%x", w != fde_encoding ? " " : "", w); + + puts (")"); + } + else if (*cp == 'P') + { + const unsigned char *startp = readp; + unsigned int encoding = *readp++; + uint64_t val = 0; + int64_t sval = 0; + bool is_signed; + + switch (encoding & 0xf) + { + case DW_EH_PE_uleb128: + get_uleb128 (val, readp); + is_signed = false; + break; + case DW_EH_PE_sleb128: + get_sleb128 (sval, readp); + is_signed = true; + break; + case DW_EH_PE_udata2: + val = read_2ubyte_unaligned_inc (dbg, readp); + is_signed = false; + break; + case DW_EH_PE_udata4: + val = read_4ubyte_unaligned_inc (dbg, readp); + is_signed = false; + break; + case DW_EH_PE_udata8: + val = read_8ubyte_unaligned_inc (dbg, readp); + is_signed = false; + break; + case DW_EH_PE_sdata2: + val = read_2sbyte_unaligned_inc (dbg, readp); + is_signed = true; + break; + case DW_EH_PE_sdata4: + val = read_4sbyte_unaligned_inc (dbg, readp); + is_signed = true; + break; + case DW_EH_PE_sdata8: + val = read_8sbyte_unaligned_inc (dbg, readp); + is_signed = true; + break; + default: + error (1, 0, + gettext ("invalid augmentation encoding")); + } + + while (++startp < readp) + printf ("%#x ", *startp); + + if (is_signed) + printf ("(%" PRId64 ")\n", sval); + else + printf ("(%" PRIu64 ")\n", val); + } + else + printf ("(%x)\n", *readp++); + + ++cp; + } + readp += augmentationlen; + } + + struct cieinfo *newp = alloca (sizeof (*newp)); + newp->cie_offset = offset; + newp->augmentation = augmentation; + newp->fde_encoding = fde_encoding; + newp->code_alignment_factor = code_alignment_factor; + newp->data_alignment_factor = data_alignment_factor; + newp->next = cies; + cies = newp; + } + else + { + struct cieinfo *cie = cies; + while (cie != NULL) + if (start - (ptrdiff_t) cie_id == cie->cie_offset) + break; + else + cie = cie->next; + if (unlikely (cie == NULL)) + { + puts ("invalid CIE reference in FDE"); + return; + } + + /* Initialize from CIE data. */ + ptr_size = encoded_ptr_size (cie->fde_encoding, ptr_size); + code_alignment_factor = cie->code_alignment_factor; + data_alignment_factor = cie->data_alignment_factor; + fde_encoding = cie->fde_encoding; + + initial_location = read_ubyte_unaligned_inc (ptr_size, dbg, readp); + Dwarf_Word address_range + = read_ubyte_unaligned_inc (ptr_size, dbg, readp); + + printf ("\n [%6jx] FDE length=%" PRIu64 " cie=[%6jx]\n" + " CIE_pointer: %" PRIu64 "\n" + " initial_location: %#" PRIx64 "\n" + " address_range: %#" PRIx64 "\n", + offset, (uint64_t) unit_length, + cie->cie_offset, (uint64_t) cie_id, + (uint64_t) initial_location, (uint64_t) address_range); + + if (cie->augmentation[0] == 'z') + { + unsigned int augmentationlen; + get_uleb128 (augmentationlen, readp); + + const char *hdr = "Augmentation data:"; + const char *cp = cie->augmentation + 1; + for (unsigned int u = 0; u < augmentationlen; ++cp, ++u) + { + printf (" %-26s%#x (", hdr, readp[u]); + hdr = ""; + } + } + } + + /* To print correct addresses compute the base address. */ + Dwarf_Word vma_base; + if ((fde_encoding & 0x70) == DW_EH_PE_pcrel && ehdr->e_type != ET_REL) + vma_base = shdr->sh_addr + initial_location; + else + vma_base = 0; + + /* Handle the initialization instructions. */ + print_cfa_program (readp, cieend, vma_base, code_alignment_factor, + data_alignment_factor, ptr_size, dwflmod, ebl, dbg); + readp = cieend; + } }