diff options
author | Dominique Martinet <asmadeus@codewreck.org> | 2017-10-03 15:17:36 +0900 |
---|---|---|
committer | Dominique Martinet <asmadeus@codewreck.org> | 2017-10-03 15:17:36 +0900 |
commit | a717094e06962b4694e9298cdde52af53f99321a (patch) | |
tree | 9c84fb9642ef4a5d0af6e547bdfa7f41c51b723c | |
parent | 7f287e650e470c131c4b6c726e0d09d4ac5433e8 (diff) |
find one element and its offset
-rw-r--r-- | dwarf.c | 182 |
1 files changed, 172 insertions, 10 deletions
@@ -10,7 +10,11 @@ static void parse_dwarf(Dwarf_Debug dbg, const char *struct_name, const char *field_name); -static void parse_level(Dwarf_Debug dbg, Dwarf_Die die, const char *struct_name, const char *field_name, int level); +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]); @@ -93,18 +97,21 @@ static void parse_dwarf(Dwarf_Debug dbg, const char *struct_name, exit(1); } - parse_level(dbg, die, struct_name, field_name, 0); + find_struct(dbg, die, struct_name, field_name, 0); } - printf("struct %s / member %s not found\n", struct_name, field_name); + printf("struct %s not found\n", struct_name, field_name); exit(2); } -static void parse_level(Dwarf_Debug dbg, Dwarf_Die die, const char *struct_name, const char *field_name, int level) { +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; @@ -112,10 +119,75 @@ static void parse_level(Dwarf_Debug dbg, Dwarf_Die die, const char *struct_name, rc = dwarf_diename(die, &name, &err); if (rc == DW_DLV_NO_ENTRY) { - printf("no diename for %p?\n", die); - break; + 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 : "<no 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); } @@ -126,17 +198,107 @@ static void parse_level(Dwarf_Debug dbg, Dwarf_Die die, const char *struct_name, exit(1); } - rc = dwarf_get_TAG_name(tag, &tag_name); - if (rc != DW_DLV_OK) { - printf("dwarf_get_TAG_name error: %d\n", rc); + 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 : "<no 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); + } - printf("<%d> %p <%d> %s: %s\n", level, die, tag, tag_name, name); 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); +} |