summaryrefslogtreecommitdiffstats
path: root/dwarf.c
diff options
context:
space:
mode:
authorDominique Martinet <asmadeus@codewreck.org>2017-10-03 15:17:36 +0900
committerDominique Martinet <asmadeus@codewreck.org>2017-10-03 15:17:36 +0900
commita717094e06962b4694e9298cdde52af53f99321a (patch)
tree9c84fb9642ef4a5d0af6e547bdfa7f41c51b723c /dwarf.c
parent7f287e650e470c131c4b6c726e0d09d4ac5433e8 (diff)
find one element and its offset
Diffstat (limited to 'dwarf.c')
-rw-r--r--dwarf.c182
1 files changed, 172 insertions, 10 deletions
diff --git a/dwarf.c b/dwarf.c
index 637d710..b116cf5 100644
--- a/dwarf.c
+++ b/dwarf.c
@@ -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);
+}