#include #include #include #include #include #include #include #include "dwarf.h" #include "libdwarf.h" static void parse_dwarf(Dwarf_Debug dbg, const char *struct_name, const char *field_name); static void find_struct(Dwarf_Debug dbg, Dwarf_Die die, const char *struct_name, const char *field_name, int level); static void find_field(Dwarf_Debug dbg, Dwarf_Die die, const char *field_name, int level); static void print_field(Dwarf_Debug dbg, Dwarf_Die die, const char *field_name); int debug = 0; void usage(char *argv[]) { printf("%s file struct field\n", argv[0]); } int main(int argc, char *argv[]) { Dwarf_Debug dbg = 0; int fd = -1; const char *filepath; const char *struct_name, *field_name; int res = DW_DLV_ERROR; Dwarf_Error error; Dwarf_Handler errhand = 0; Dwarf_Ptr errarg = 0; if(argc < 4) { usage(argv); exit(1); } filepath = argv[1]; struct_name = argv[2]; field_name = argv[3]; fd = open(filepath,O_RDONLY); if(fd < 0) { printf("Failure attempting to open %s\n",filepath); } res = dwarf_init(fd,DW_DLC_READ,errhand,errarg, &dbg,&error); if(res != DW_DLV_OK) { printf("Giving up, cannot do DWARF processing\n"); exit(1); } parse_dwarf(dbg, struct_name, field_name); res = dwarf_finish(dbg,&error); if(res != DW_DLV_OK) { printf("dwarf_finish failed!\n"); } close(fd); return 0; } static void parse_dwarf(Dwarf_Debug dbg, const char *struct_name, const char *field_name) { Dwarf_Bool is_info = 1; Dwarf_Unsigned cu_length; Dwarf_Half cu_version; Dwarf_Off cu_abbrev_offset; Dwarf_Half cu_pointer_size; Dwarf_Half cu_offset_size; Dwarf_Half cu_extension_size; Dwarf_Sig8 type_signature; Dwarf_Unsigned type_offset; Dwarf_Unsigned cu_next_offset; Dwarf_Error err; int rc; while (1) { Dwarf_Die die, next; rc = dwarf_next_cu_header_c(dbg, is_info, &cu_length, &cu_version, &cu_abbrev_offset, &cu_pointer_size, &cu_offset_size, &cu_extension_size, &type_signature, &type_offset, &cu_next_offset, &err); if (rc == DW_DLV_NO_ENTRY) break; if (rc != DW_DLV_OK) { printf("error dwarf_next_cu_header_c: %d %s\n", rc, dwarf_errmsg(err)); exit(1); } rc = dwarf_siblingof(dbg, NULL, &die, &err); if (rc != DW_DLV_OK) { printf("first dwarf_siblingof failed: %d %s\n", rc, dwarf_errmsg(err)); exit(1); } find_struct(dbg, die, struct_name, field_name, 0); } printf("struct %s not found\n", struct_name, field_name); exit(2); } static void find_struct(Dwarf_Debug dbg, Dwarf_Die die, const char *struct_name, const char *field_name, int level) { Dwarf_Die next; Dwarf_Error err; int rc; if (level > 1) return; do { char *name; const char *tag_name; Dwarf_Half tag; rc = dwarf_diename(die, &name, &err); if (rc == DW_DLV_NO_ENTRY) { name = NULL; } else if (rc != DW_DLV_OK) { printf("dwarf_diename error: %d %s\n", rc, dwarf_errmsg(err)); exit(1); } rc = dwarf_tag(die, &tag, &err); if (rc != DW_DLV_OK) { printf("dwarf_tag error: %d %s\n", rc, dwarf_errmsg(err)); exit(1); } if (debug) { rc = dwarf_get_TAG_name(tag, &tag_name); if (rc != DW_DLV_OK) { printf("dwarf_get_TAG_name error: %d\n", rc); exit(1); } printf("<%d> %p <%d> %s: %s\n", level, die, tag, tag_name, name ? name : ""); } rc = dwarf_child(die, &next, &err); if (rc == DW_DLV_ERROR) { printf("dwarf_child error: %d %s\n", rc, dwarf_errmsg(err)); exit(1); } if (rc == DW_DLV_OK) { if (tag == DW_TAG_structure_type && name && strcasecmp(name, struct_name) == 0) { find_field(dbg, next, field_name, level + 1); printf("Found struct %s but it had no member %s!\n", struct_name, field_name); exit(3); } find_struct(dbg, next, struct_name, field_name, level + 1); dwarf_dealloc(dbg, next, DW_DLA_DIE); } rc = dwarf_siblingof(dbg, die, &next, &err); dwarf_dealloc(dbg, die, DW_DLA_DIE); if (name) dwarf_dealloc(dbg, name, DW_DLA_STRING); if (rc != DW_DLV_OK) break; die = next; } while (die); } static void find_field(Dwarf_Debug dbg, Dwarf_Die die, const char *field_name, int level) { Dwarf_Die next; Dwarf_Error err; int rc; if (level > 2) return; do { char *name; const char *tag_name; Dwarf_Half tag; rc = dwarf_diename(die, &name, &err); if (rc == DW_DLV_NO_ENTRY) { name = NULL; } else if (rc != DW_DLV_OK) { printf("dwarf_diename error: %d %s\n", rc, dwarf_errmsg(err)); exit(1); } rc = dwarf_tag(die, &tag, &err); if (rc != DW_DLV_OK) { printf("dwarf_tag error: %d %s\n", rc, dwarf_errmsg(err)); exit(1); } if (debug) { rc = dwarf_get_TAG_name(tag, &tag_name); if (rc != DW_DLV_OK) { printf("dwarf_get_TAG_name error: %d\n", rc); exit(1); } printf("<%d> %p <%d> %s: %s\n", level, die, tag, tag_name, name ? name : ""); } if (tag == DW_TAG_member && name && strcasecmp(name, field_name) == 0) { print_field(dbg, die, field_name); exit(0); } rc = dwarf_child(die, &next, &err); if (rc == DW_DLV_ERROR) { printf("dwarf_child error: %d %s\n", rc, dwarf_errmsg(err)); exit(1); } if (rc == DW_DLV_OK) { find_field(dbg, next, field_name, level + 1); dwarf_dealloc(dbg, next, DW_DLA_DIE); } rc = dwarf_siblingof(dbg, die, &next, &err); dwarf_dealloc(dbg, die, DW_DLA_DIE); if (name) dwarf_dealloc(dbg, name, DW_DLA_STRING); if (rc != DW_DLV_OK) break; die = next; } while (die); } static void print_field(Dwarf_Debug dbg, Dwarf_Die die, const char *field_name) { Dwarf_Attribute *attrs; Dwarf_Signed attrcount = 0; Dwarf_Error err; Dwarf_Unsigned offset = 0; int rc, i; printf("Found %s\n", field_name); rc = dwarf_attrlist(die, &attrs, &attrcount, &err); if (rc == DW_DLV_NO_ENTRY) { printf("Found %s but no attribute\n", field_name); exit(4); } if (rc != DW_DLV_OK) { printf("Error getting dwarf attrlist: %s\n", dwarf_errmsg(err)); exit(4); } for (i = 0; i < attrcount; i++) { Dwarf_Half aform; rc = dwarf_whatattr(attrs[i], &aform, &err); if (rc != DW_DLV_OK) { printf("Error getting attr %d: %s\n", i, dwarf_errmsg(err)); exit(5); } if (aform == DW_AT_data_member_location) { Dwarf_Half form; rc = dwarf_whatform(attrs[i], &form, &err); if (rc != DW_DLV_OK) { printf("Error getting whatform: %s\n", dwarf_errmsg(err)); exit(5); } if (form == DW_FORM_data1 || form == DW_FORM_data2 || form == DW_FORM_data2 || form == DW_FORM_data4 || form == DW_FORM_data8 || form == DW_FORM_udata) { dwarf_formudata(attrs[i], &offset, 0); } else if (form == DW_FORM_sdata) { Dwarf_Signed soffset; dwarf_formsdata(attrs[i], &soffset, 0); if (soffset < 0) { printf("unsupported negative offset\n"); /* FAIL */ } offset = (Dwarf_Unsigned) soffset; } else { Dwarf_Locdesc **locdescs; Dwarf_Signed len; if (dwarf_loclist_n(attrs[i], &locdescs, &len, &err) == DW_DLV_ERROR) { printf("unsupported member offset\n"); /* FAIL */ } if (len != 1 || locdescs[0]->ld_cents != 1 || (locdescs[0]->ld_s[0]).lr_atom != DW_OP_plus_uconst) { printf("unsupported location expression\n"); /* FAIL */ } offset = (locdescs[0]->ld_s[0]).lr_number; } } else if (aform == DW_AT_type) { } } printf("offset %u\n", offset); }