void handle (Dwarf *dbg, Dwarf_Die *die, int n) { Dwarf_Die child; unsigned int tag; const char *str; char buf[30]; const char *name; Dwarf_Off off; Dwarf_Off cuoff; size_t cnt; Dwarf_Addr addr; int i; tag = dwarf_tag (die); if (tag != DW_TAG_invalid) { if (tag < ntagnames) str = tagnames[tag]; else { snprintf (buf, sizeof buf, "%#x", tag); str = buf; } } else str = "* NO TAG *"; name = dwarf_diename (die); if (name == 0) name = "* NO NAME *"; off = dwarf_dieoffset (die); cuoff = dwarf_cuoffset (die); printf ("%*s%s\n", n * 5, "", str); printf ("%*s Name : %s\n", n * 5, "", name); printf ("%*s Offset : %lld\n", n * 5, "", (long long int) off); printf ("%*s CU offset : %lld\n", n * 5, "", (long long int) cuoff); printf ("%*s Attrs :", n * 5, ""); for (cnt = 0; cnt < nattrs; ++cnt) if (dwarf_hasattr (die, attrs[cnt].code)) printf (" %s", attrs[cnt].name); puts (""); if (dwarf_hasattr (die, DW_AT_low_pc) && dwarf_lowpc (die, &addr) == 0) { Dwarf_Attribute attr; Dwarf_Addr addr2; printf ("%*s low PC : %#llx\n", n * 5, "", (unsigned long long int) addr); if (dwarf_attr (die, DW_AT_low_pc, &attr) == NULL || dwarf_formaddr (&attr, &addr2) != 0 || addr != addr2) puts ("************* DW_AT_low_pc verify failed ************"); else if (! dwarf_hasform (&attr, DW_FORM_addr)) puts ("************* DW_AT_low_pc form failed ************"); else if (dwarf_whatform (&attr) != DW_FORM_addr) puts ("************* DW_AT_low_pc form (2) failed ************"); else if (dwarf_whatattr (&attr) != DW_AT_low_pc) puts ("************* DW_AT_low_pc attr failed ************"); } if (dwarf_hasattr (die, DW_AT_high_pc) && dwarf_highpc (die, &addr) == 0) { Dwarf_Attribute attr; Dwarf_Addr addr2; printf ("%*s high PC : %#llx\n", n * 5, "", (unsigned long long int) addr); if (dwarf_attr (die, DW_AT_high_pc, &attr) == NULL || dwarf_formaddr (&attr, &addr2) != 0 || addr != addr2) puts ("************* DW_AT_high_pc verify failed ************"); else if (! dwarf_hasform (&attr, DW_FORM_addr)) puts ("************* DW_AT_high_pc form failed ************"); else if (dwarf_whatform (&attr) != DW_FORM_addr) puts ("************* DW_AT_high_pc form (2) failed ************"); else if (dwarf_whatattr (&attr) != DW_AT_high_pc) puts ("************* DW_AT_high_pc attr failed ************"); } if (dwarf_hasattr (die, DW_AT_byte_size) && (i = dwarf_bytesize (die)) != -1) { Dwarf_Attribute attr; Dwarf_Word u2; unsigned int u; printf ("%*s byte size : %d\n", n * 5, "", i); if (dwarf_attr (die, DW_AT_byte_size, &attr) == NULL || dwarf_formudata (&attr, &u2) != 0 || i != (int) u2) puts ("************* DW_AT_byte_size verify failed ************"); else if (! dwarf_hasform (&attr, DW_FORM_data1) && ! dwarf_hasform (&attr, DW_FORM_data2) && ! dwarf_hasform (&attr, DW_FORM_data4) && ! dwarf_hasform (&attr, DW_FORM_data8) && ! dwarf_hasform (&attr, DW_FORM_sdata) && ! dwarf_hasform (&attr, DW_FORM_udata)) puts ("************* DW_AT_byte_size form failed ************"); else if ((u = dwarf_whatform (&attr)) == 0 || (u != DW_FORM_data1 && u != DW_FORM_data2 && u != DW_FORM_data4 && u != DW_FORM_data8 && u != DW_FORM_sdata && u != DW_FORM_udata)) puts ("************* DW_AT_byte_size form (2) failed ************"); else if (dwarf_whatattr (&attr) != DW_AT_byte_size) puts ("************* DW_AT_byte_size attr failed ************"); } if (dwarf_hasattr (die, DW_AT_bit_size) && (i = dwarf_bitsize (die)) != -1) { Dwarf_Attribute attr; Dwarf_Word u2; unsigned int u; printf ("%*s bit size : %d\n", n * 5, "", i); if (dwarf_attr (die, DW_AT_bit_size, &attr) == NULL || dwarf_formudata (&attr, &u2) != 0 || i != (int) u2) puts ("************* DW_AT_bit_size test failed ************"); else if (! dwarf_hasform (&attr, DW_FORM_data1) && ! dwarf_hasform (&attr, DW_FORM_data2) && ! dwarf_hasform (&attr, DW_FORM_data4) && ! dwarf_hasform (&attr, DW_FORM_data8) && ! dwarf_hasform (&attr, DW_FORM_sdata) && ! dwarf_hasform (&attr, DW_FORM_udata)) puts ("************* DW_AT_bit_size form failed ************"); else if ((u = dwarf_whatform (&attr)) == 0 || (u != DW_FORM_data1 && u != DW_FORM_data2 && u != DW_FORM_data4 && u != DW_FORM_data8 && u != DW_FORM_sdata && u != DW_FORM_udata)) puts ("************* DW_AT_bit_size form (2) failed ************"); else if (dwarf_whatattr (&attr) != DW_AT_bit_size) puts ("************* DW_AT_bit_size attr failed ************"); } if (dwarf_hasattr (die, DW_AT_bit_offset) && (i = dwarf_bitoffset (die)) != -1) { Dwarf_Attribute attr; Dwarf_Word u2; unsigned int u; printf ("%*s bit offset: %d\n", n * 5, "", i); if (dwarf_attr (die, DW_AT_bit_offset, &attr) == NULL || dwarf_formudata (&attr, &u2) != 0 || i != (int) u2) puts ("************* DW_AT_bit_offset test failed ************"); else if (! dwarf_hasform (&attr, DW_FORM_data1) && ! dwarf_hasform (&attr, DW_FORM_data2) && ! dwarf_hasform (&attr, DW_FORM_data4) && ! dwarf_hasform (&attr, DW_FORM_data8) && ! dwarf_hasform (&attr, DW_FORM_sdata) && ! dwarf_hasform (&attr, DW_FORM_udata)) puts ("************* DW_AT_bit_offset form failed ************"); else if ((u = dwarf_whatform (&attr)) == 0 || (u != DW_FORM_data1 && u != DW_FORM_data2 && u != DW_FORM_data4 && u != DW_FORM_data8 && u != DW_FORM_sdata && u != DW_FORM_udata)) puts ("************* DW_AT_bit_offset form (2) failed ************"); else if (dwarf_whatattr (&attr) != DW_AT_bit_offset) puts ("************* DW_AT_bit_offset attr failed ************"); } if (dwarf_hasattr (die, DW_AT_language) && (i = dwarf_srclang (die)) != -1) { Dwarf_Attribute attr; Dwarf_Word u2; unsigned int u; printf ("%*s language : %d\n", n * 5, "", i); if (dwarf_attr (die, DW_AT_language, &attr) == NULL || dwarf_formudata (&attr, &u2) != 0 || i != (int) u2) puts ("************* DW_AT_language test failed ************"); else if (! dwarf_hasform (&attr, DW_FORM_data1) && ! dwarf_hasform (&attr, DW_FORM_data2) && ! dwarf_hasform (&attr, DW_FORM_data4) && ! dwarf_hasform (&attr, DW_FORM_data8) && ! dwarf_hasform (&attr, DW_FORM_sdata) && ! dwarf_hasform (&attr, DW_FORM_udata)) puts ("************* DW_AT_language form failed ************"); else if ((u = dwarf_whatform (&attr)) == 0 || (u != DW_FORM_data1 && u != DW_FORM_data2 && u != DW_FORM_data4 && u != DW_FORM_data8 && u != DW_FORM_sdata && u != DW_FORM_udata)) puts ("************* DW_AT_language form (2) failed ************"); else if (dwarf_whatattr (&attr) != DW_AT_language) puts ("************* DW_AT_language attr failed ************"); } if (dwarf_hasattr (die, DW_AT_ordering) && (i = dwarf_arrayorder (die)) != -1) { Dwarf_Attribute attr; Dwarf_Word u2; unsigned int u; printf ("%*s ordering : %d\n", n * 5, "", i); if (dwarf_attr (die, DW_AT_ordering, &attr) == NULL || dwarf_formudata (&attr, &u2) != 0 || i != (int) u2) puts ("************* DW_AT_ordering test failed ************"); else if (! dwarf_hasform (&attr, DW_FORM_data1) && ! dwarf_hasform (&attr, DW_FORM_data2) && ! dwarf_hasform (&attr, DW_FORM_data4) && ! dwarf_hasform (&attr, DW_FORM_data8) && ! dwarf_hasform (&attr, DW_FORM_sdata) && ! dwarf_hasform (&attr, DW_FORM_udata)) puts ("************* DW_AT_ordering failed ************"); else if ((u = dwarf_whatform (&attr)) == 0 || (u != DW_FORM_data1 && u != DW_FORM_data2 && u != DW_FORM_data4 && u != DW_FORM_data8 && u != DW_FORM_sdata && u != DW_FORM_udata)) puts ("************* DW_AT_ordering form (2) failed ************"); else if (dwarf_whatattr (&attr) != DW_AT_ordering) puts ("************* DW_AT_ordering attr failed ************"); } if (dwarf_hasattr (die, DW_AT_comp_dir)) { Dwarf_Attribute attr; if (dwarf_attr (die, DW_AT_comp_dir, &attr) == NULL || (name = dwarf_formstring (&attr)) == NULL) puts ("************* DW_AT_comp_dir attr failed ************"); else printf ("%*s directory : %s\n", n * 5, "", name); } if (dwarf_hasattr (die, DW_AT_producer)) { Dwarf_Attribute attr; if (dwarf_attr (die, DW_AT_producer, &attr) == NULL || (name = dwarf_formstring (&attr)) == NULL) puts ("************* DW_AT_comp_dir attr failed ************"); else printf ("%*s producer : %s\n", n * 5, "", name); } if (dwarf_haschildren (die) != 0 && dwarf_child (die, &child) == 0) handle (dbg, &child, n + 1); if (dwarf_siblingof (die, die) == 0) handle (dbg, die, n); }
int main(int argc, char **argv) { Dwarf_Off off, lastoff; Dwarf *dw; size_t hdr_size; int cufd, error; argv0 = argv[0]; if (argc < 3) usage(); structname = argv[1]; binary = argv[2]; elf_version(EV_CURRENT); cufd = open(binary, O_RDONLY); if (cufd == -1) err(EX_USAGE, "open"); dw = dwarf_begin(cufd, DWARF_C_READ); if (dw == NULL) { error = dwarf_errno(); if (error == DWARF_E_NO_REGFILE) errx(EX_USAGE, "%s: Not a regular file", binary); dwarf_err_errno(EX_DATAERR, error, "dwarf_begin"); } get_elf_pointer_size(dw); /* XXX worry about .debug_types sections later. */ lastoff = off = 0; while (dwarf_nextcu(dw, off, &off, &hdr_size, NULL, NULL, NULL) == 0) { Dwarf_Die cu_die, die; int x; if (dwarf_offdie(dw, lastoff + hdr_size, &cu_die) == NULL) continue; lastoff = off; /* * A CU may be empty because e.g. an empty (or fully #if0'd) * file is compiled. */ if (dwarf_child(&cu_die, &die)) continue; /* Loop through all DIEs in the CU. */ do { if (isstruct(dwarf_tag(&die)) && dwarf_haschildren(&die) && dwarf_diename(&die) && strcmp(dwarf_diename(&die), structname) == 0) { structprobe(dw, &die); goto out; } } while ((x = dwarf_siblingof(&die, &die)) == 0); if (x == -1) dwarf_err(EX_DATAERR, "dwarf_siblingof"); } out: if (dwarf_end(dw)) dwarf_err(EX_SOFTWARE, "dwarf_end"); return (EX_OK); }
/* Get all variables and print their value expressions. */ static void print_varlocs (Dwarf_Die *funcdie) { // Display frame base for function if it exists. // Should be used for DW_OP_fbreg. has_frame_base = dwarf_hasattr (funcdie, DW_AT_frame_base); if (has_frame_base) { Dwarf_Attribute fb_attr; if (dwarf_attr (funcdie, DW_AT_frame_base, &fb_attr) == NULL) error (EXIT_FAILURE, 0, "dwarf_attr fb: %s", dwarf_errmsg (-1)); Dwarf_Op *fb_expr; size_t fb_exprlen; if (dwarf_getlocation (&fb_attr, &fb_expr, &fb_exprlen) == 0) { // Covers all of function. Dwarf_Addr entrypc; if (dwarf_entrypc (funcdie, &entrypc) != 0) error (EXIT_FAILURE, 0, "dwarf_entrypc: %s", dwarf_errmsg (-1)); printf (" frame_base: "); if (entrypc == 0) printf ("XXX zero address"); // XXX bad DWARF? else print_expr_block (&fb_attr, fb_expr, fb_exprlen, entrypc); printf ("\n"); } else { Dwarf_Addr base, start, end; ptrdiff_t off = 0; printf (" frame_base:\n"); while ((off = dwarf_getlocations (&fb_attr, off, &base, &start, &end, &fb_expr, &fb_exprlen)) > 0) { printf (" (%" PRIx64 ",%" PRIx64 ") ", start, end); print_expr_block (&fb_attr, fb_expr, fb_exprlen, start); printf ("\n"); } if (off < 0) error (EXIT_FAILURE, 0, "dwarf_getlocations fb: %s", dwarf_errmsg (-1)); } } else if (dwarf_tag (funcdie) == DW_TAG_inlined_subroutine) { // See whether the subprogram we are inlined into has a frame // base we should use. Dwarf_Die *scopes; int n = dwarf_getscopes_die (funcdie, &scopes); if (n <= 0) error (EXIT_FAILURE, 0, "dwarf_getscopes_die: %s", dwarf_errmsg (-1)); while (n-- > 0) if (dwarf_tag (&scopes[n]) == DW_TAG_subprogram && dwarf_hasattr (&scopes[n], DW_AT_frame_base)) { has_frame_base = true; break; } free (scopes); } if (! dwarf_haschildren (funcdie)) return; Dwarf_Die child; int res = dwarf_child (funcdie, &child); if (res < 0) error (EXIT_FAILURE, 0, "dwarf_child: %s", dwarf_errmsg (-1)); /* We thought there was a child, but the child list was actually empty. This isn't technically an error in the DWARF, but it is certainly non-optimimal. */ if (res == 1) return; do { int tag = dwarf_tag (&child); if (tag == DW_TAG_variable || tag == DW_TAG_formal_parameter) { const char *what = tag == DW_TAG_variable ? "variable" : "parameter"; print_die (&child, what, 2); if (dwarf_hasattr (&child, DW_AT_location)) { Dwarf_Attribute attr; if (dwarf_attr (&child, DW_AT_location, &attr) == NULL) error (EXIT_FAILURE, 0, "dwarf_attr: %s", dwarf_errmsg (-1)); Dwarf_Op *expr; size_t exprlen; if (dwarf_getlocation (&attr, &expr, &exprlen) == 0) { // Covers all ranges of the function. // Evaluate the expression block for each range. ptrdiff_t offset = 0; Dwarf_Addr base, begin, end; do { offset = dwarf_ranges (funcdie, offset, &base, &begin, &end); if (offset < 0) error (EXIT_FAILURE, 0, "dwarf_ranges: %s", dwarf_errmsg (-1)); if (offset > 0) { if (exprlen == 0) printf (" (%" PRIx64 ",%" PRIx64 ") <empty expression>\n", begin, end); else print_expr_block_addrs (&attr, begin, end, expr, exprlen); } } while (offset > 0); if (offset < 0) error (EXIT_FAILURE, 0, "dwarf_ranges: %s", dwarf_errmsg (-1)); } else { Dwarf_Addr base, begin, end; ptrdiff_t offset = 0; while ((offset = dwarf_getlocations (&attr, offset, &base, &begin, &end, &expr, &exprlen)) > 0) if (begin >= end) printf (" (%" PRIx64 ",%" PRIx64 ") <empty range>\n", begin, end); // XXX report? else { print_expr_block_addrs (&attr, begin, end, expr, exprlen); // Extra sanity check for dwarf_getlocation_addr // Must at least find one range for begin and end-1. Dwarf_Op *expraddr; size_t expraddr_len; int locs = dwarf_getlocation_addr (&attr, begin, &expraddr, &expraddr_len, 1); assert (locs == 1); locs = dwarf_getlocation_addr (&attr, end - 1, &expraddr, &expraddr_len, 1); assert (locs == 1); } if (offset < 0) error (EXIT_FAILURE, 0, "dwarf_getlocations: %s", dwarf_errmsg (-1)); } } else if (dwarf_hasattr (&child, DW_AT_const_value)) { printf (" <constant value>\n"); // Lookup type and print. } else { printf (" <no value>\n"); } } } while (dwarf_siblingof (&child, &child) == 0); }