summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dwarf-extract-struct.c321
1 files changed, 229 insertions, 92 deletions
diff --git a/dwarf-extract-struct.c b/dwarf-extract-struct.c
index 466c6ce..1ade375 100644
--- a/dwarf-extract-struct.c
+++ b/dwarf-extract-struct.c
@@ -207,7 +207,7 @@ static void find_fields(Dwarf_Debug dbg, Dwarf_Die die, const char *struct_name,
Dwarf_Error err;
int rc, i, printed_count = 0;
- printf("struct %s {\n\tunion {\n",
+ printf("struct %s {\n\tunion {\n",
struct_name);
do {
@@ -273,15 +273,155 @@ static void find_fields(Dwarf_Debug dbg, Dwarf_Die die, const char *struct_name,
} while (die);
}
+
+static int dwarf_get_offset(Dwarf_Debug dbg, Dwarf_Die die,
+ int *poffset, Dwarf_Error *perr) {
+ Dwarf_Attribute attr;
+ Dwarf_Unsigned offset;
+ int rc;
+
+ rc = dwarf_attr(die, DW_AT_data_member_location, &attr, perr);
+ if (rc != DW_DLV_OK) {
+ return rc;
+ }
+ Dwarf_Half form;
+ rc = dwarf_whatform(attr, &form, perr);
+ if (rc != DW_DLV_OK) {
+ fprintf(stderr, "Error getting whatform: %s\n",
+ dwarf_errmsg(*perr));
+ 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(attr, &offset, 0);
+ } else if (form == DW_FORM_sdata) {
+ Dwarf_Signed soffset;
+ dwarf_formsdata(attr, &soffset, 0);
+ if (soffset < 0) {
+ fprintf(stderr,
+ "unsupported negative offset\n");
+ exit(5);
+ }
+ offset = (Dwarf_Unsigned) soffset;
+ } else {
+ Dwarf_Locdesc **locdescs;
+ Dwarf_Signed len;
+ if (dwarf_loclist_n(attr, &locdescs, &len, perr)
+ == DW_DLV_ERROR) {
+ fprintf(stderr, "unsupported member offset\n");
+ exit(5);
+ }
+ if (len != 1
+ || locdescs[0]->ld_cents != 1
+ || (locdescs[0]->ld_s[0]).lr_atom
+ != DW_OP_plus_uconst) {
+ fprintf(stderr,
+ "unsupported location expression\n");
+ exit(5);
+ }
+ offset = (locdescs[0]->ld_s[0]).lr_number;
+ }
+ dwarf_dealloc(dbg, attr, DW_DLA_ATTR);
+
+ *poffset = (int) offset;
+ return DW_DLV_OK;
+}
+
+static int dwarf_get_size(Dwarf_Debug dbg, Dwarf_Die die,
+ int *psize, Dwarf_Error *perr) {
+ Dwarf_Attribute attr;
+ Dwarf_Unsigned size;
+ int rc;
+
+ rc = dwarf_attr(die, DW_AT_byte_size, &attr, perr);
+ if (rc != DW_DLV_OK) {
+ return rc;
+ }
+ Dwarf_Half form;
+ rc = dwarf_whatform(attr, &form, perr);
+ if (rc != DW_DLV_OK) {
+ fprintf(stderr, "Error getting whatform: %s\n",
+ dwarf_errmsg(*perr));
+ 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(attr, &size, 0);
+ } else if (form == DW_FORM_sdata) {
+ Dwarf_Signed ssize;
+ dwarf_formsdata(attr, &ssize, 0);
+ if (ssize < 0) {
+ fprintf(stderr,
+ "unsupported negative size\n");
+ exit(5);
+ }
+ size = (Dwarf_Unsigned) ssize;
+ } else {
+ Dwarf_Locdesc **locdescs;
+ Dwarf_Signed len;
+ if (dwarf_loclist_n(attr, &locdescs, &len, perr)
+ == DW_DLV_ERROR) {
+ fprintf(stderr, "unsupported member size\n");
+ exit(5);
+ }
+ if (len != 1
+ || locdescs[0]->ld_cents != 1
+ || (locdescs[0]->ld_s[0]).lr_atom
+ != DW_OP_plus_uconst) {
+ fprintf(stderr,
+ "unsupported location expression\n");
+ exit(5);
+ }
+ size = (locdescs[0]->ld_s[0]).lr_number;
+ }
+ dwarf_dealloc(dbg, attr, DW_DLA_ATTR);
+
+ *psize = (int) size;
+ return DW_DLV_OK;
+}
+
+static int deref_type(Dwarf_Debug dbg, Dwarf_Die type_die,
+ Dwarf_Die *new_type_die, Dwarf_Half *ptype_tag,
+ Dwarf_Error *perr) {
+ Dwarf_Attribute pointer_attr;
+ Dwarf_Off pointer_off;
+ int rc;
+
+ rc = dwarf_attr(type_die, DW_AT_type, &pointer_attr,
+ perr);
+ if (rc != DW_DLV_OK)
+ return rc;
+
+ rc = dwarf_global_formref(pointer_attr, &pointer_off,
+ perr);
+ if (rc != DW_DLV_OK)
+ return rc;
+
+ rc = dwarf_offdie_b(dbg, pointer_off, 1, new_type_die,
+ perr);
+ if (rc != DW_DLV_OK)
+ return rc;
+
+ dwarf_dealloc(dbg, pointer_attr, DW_DLA_ATTR);
+
+ if (ptype_tag)
+ rc = dwarf_tag(*new_type_die, ptype_tag, perr);
+
+ return rc;
+}
+
static void print_field(Dwarf_Debug dbg, Dwarf_Die die, const char *field_name,
int padnum) {
Dwarf_Attribute attr;
Dwarf_Error err;
- Dwarf_Unsigned offset = 0;
+ int offset = 0;
char type_buf[1024];
+ char array_buf[128] = "";
int rc;
- rc = dwarf_attr(die, DW_AT_data_member_location, &attr, &err);
+ rc = dwarf_get_offset(dbg, die, &offset, &err);
if (rc == DW_DLV_NO_ENTRY) {
fprintf(stderr, "Found %s but no offset, assuming 0\n",
field_name);
@@ -289,46 +429,6 @@ static void print_field(Dwarf_Debug dbg, Dwarf_Die die, const char *field_name,
fprintf(stderr, "Error getting dwarf attr offset: %s\n",
dwarf_errmsg(err));
exit(4);
- } else {
- Dwarf_Half form;
- rc = dwarf_whatform(attr, &form, &err);
- if (rc != DW_DLV_OK) {
- fprintf(stderr, "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(attr, &offset, 0);
- } else if (form == DW_FORM_sdata) {
- Dwarf_Signed soffset;
- dwarf_formsdata(attr, &soffset, 0);
- if (soffset < 0) {
- fprintf(stderr,
- "unsupported negative offset\n");
- exit(5);
- }
- offset = (Dwarf_Unsigned) soffset;
- } else {
- Dwarf_Locdesc **locdescs;
- Dwarf_Signed len;
- if (dwarf_loclist_n(attr, &locdescs, &len, &err)
- == DW_DLV_ERROR) {
- fprintf(stderr, "unsupported member offset\n");
- exit(5);
- }
- if (len != 1
- || locdescs[0]->ld_cents != 1
- || (locdescs[0]->ld_s[0]).lr_atom
- != DW_OP_plus_uconst) {
- fprintf(stderr,
- "unsupported location expression\n");
- exit(5);
- }
- offset = (locdescs[0]->ld_s[0]).lr_number;
- }
- dwarf_dealloc(dbg, attr, DW_DLA_ATTR);
}
rc = dwarf_attr(die, DW_AT_type, &attr, &err);
@@ -342,7 +442,7 @@ static void print_field(Dwarf_Debug dbg, Dwarf_Die die, const char *field_name,
dwarf_errmsg(err));
exit(6);
} else {
- Dwarf_Die type_die;
+ Dwarf_Die type_die, next;
Dwarf_Off type_off;
Dwarf_Half type_tag;
char *type_name;
@@ -372,75 +472,113 @@ static void print_field(Dwarf_Debug dbg, Dwarf_Die die, const char *field_name,
}
if (type_tag == DW_TAG_pointer_type) {
- Dwarf_Attribute pointer_attr;
- Dwarf_Off pointer_off;
- Dwarf_Die pointer_die;
+ rc = deref_type(dbg, type_die, &next,
+ &type_tag, &err);
+ /* No entry here means void* */
+ if (rc != DW_DLV_NO_ENTRY) {
+ if (rc != DW_DLV_OK) {
+ fprintf(stderr,
+ "Could not deref type for %s: %s\n",
+ field_name, dwarf_errmsg(err));
+ exit(7);
+ }
+
+ dwarf_dealloc(dbg, type_die, DW_DLA_DIE);
+ type_die = next;
+ }
+
+ pointer++;
+ }
+ if (type_tag == DW_TAG_array_type) {
+ int next_offset, size;
- rc = dwarf_attr(type_die, DW_AT_type, &pointer_attr,
- &err);
+ rc = deref_type(dbg, type_die, &next,
+ &type_tag, &err);
if (rc == DW_DLV_NO_ENTRY) {
- /* assume void* */
- /* XXX find better flow control than goto.. */
- goto pointer_end;
+ fprintf(stderr,
+ "Could not deref array type for %s: no entry\n",
+ field_name);
+ exit(7);
}
- if (rc == DW_DLV_ERROR) {
+ if (rc != DW_DLV_OK) {
fprintf(stderr,
- "Error getting pointer attr for type: %s\n",
- dwarf_errmsg(err));
+ "Could not deref type for %s: %s\n",
+ field_name, dwarf_errmsg(err));
exit(7);
}
- rc = dwarf_global_formref(pointer_attr, &pointer_off,
- &err);
+ dwarf_dealloc(dbg, type_die, DW_DLA_DIE);
+ type_die = next;
+
+ /* get next pos */
+ rc = dwarf_siblingof(dbg, die, &next, &err);
+ if (rc == DW_DLV_NO_ENTRY) {
+ fprintf(stderr,
+ "Need to get sibling for array size but none left, please implement through whole struct size instead. field %s\n",
+ field_name);
+ exit(7);
+ }
if (rc != DW_DLV_OK) {
fprintf(stderr,
- "Error getting pointer ref offset for type: %s\n",
- dwarf_errmsg(err));
+ "Could not get sibling of field %s: %s\n",
+ field_name, dwarf_errmsg(err));
exit(7);
}
-
- rc = dwarf_offdie_b(dbg, pointer_off, 1, &pointer_die,
- &err);
+ rc = dwarf_get_offset(dbg, next, &next_offset, &err);
if (rc != DW_DLV_OK) {
fprintf(stderr,
- "Error getting pointer die from offset for type: %s\n",
- dwarf_errmsg(err));
+ "Could not get neighbor's offset for field %s: %s\n",
+ field_name, dwarf_errmsg(err));
exit(7);
}
+ dwarf_dealloc(dbg, next, DW_DLA_DIE);
- dwarf_dealloc(dbg, attr, DW_DLA_ATTR);
- dwarf_dealloc(dbg, type_die, DW_DLA_DIE);
- attr = pointer_attr;
- type_die = pointer_die;
- pointer++;
-
- rc = dwarf_tag(type_die, &type_tag, &err);
+ /* get type size */
+ next = type_die;
+ if (type_tag == DW_TAG_typedef) {
+ rc = deref_type(dbg, type_die, &next, NULL, &err);
+ if (rc != DW_DLV_OK) {
+ fprintf(stderr,
+ "Could not deref array typedef type for %s: %s\n",
+ field_name, dwarf_errmsg(err));
+ exit(7);
+ }
+ }
+ rc = dwarf_get_size(dbg, next, &size, &err);
if (rc != DW_DLV_OK) {
- fprintf(stderr, "dwarf_tag error: %d %s\n",
- rc, dwarf_errmsg(err));
+ fprintf(stderr,
+ "Could not get size for type for %s: %s\n",
+ field_name, dwarf_errmsg(err));
exit(7);
}
- }
+ if (next != type_die)
+ dwarf_dealloc(dbg, next, DW_DLA_DIE);
- rc = dwarf_diename(type_die, &type_name, &err);
- if (rc != DW_DLV_OK) {
- fprintf(stderr, "dwarf_diename error: %d %s\n",
- rc, dwarf_errmsg(err));
- const char *tag_name;
+ snprintf(array_buf, 128, "[%d]", (next_offset - offset) / size);
+ }
- rc = dwarf_get_TAG_name(type_tag, &tag_name);
+ /* If it's still pointer at this point, it's void * */
+ if (type_tag != DW_TAG_pointer_type) {
+ rc = dwarf_diename(type_die, &type_name, &err);
if (rc != DW_DLV_OK) {
- fprintf(stderr,
- "dwarf_get_TAG_name error: %d\n",
- rc);
- }
+ fprintf(stderr, "dwarf_diename error: %s\n",
+ rc == DW_DLV_NO_ENTRY ?
+ "no name" : dwarf_errmsg(err));
+ const char *tag_name;
+
+ rc = dwarf_get_TAG_name(type_tag, &tag_name);
+ if (rc != DW_DLV_OK) {
+ fprintf(stderr,
+ "dwarf_get_TAG_name error: %d\n",
+ rc);
+ }
- fprintf(stderr, "Bad tag %s (%d)?\n",
- tag_name, type_tag);
- exit(7);
+ fprintf(stderr, "Bad tag %s (%d)?\n",
+ tag_name, type_tag);
+ exit(7);
+ }
}
-pointer_end:
if (type_tag == DW_TAG_structure_type) {
snprintf(type_buf, 1024, "struct %s %s",
type_name, pointer ? "*" : "");
@@ -470,8 +608,7 @@ pointer_end:
dwarf_dealloc(dbg, type_die, DW_DLA_DIE);
}
- printf("\t\tstruct {\n\t\t\tchar padding%i[%u];\n\t\t\t%s%s;\n\t\t};\n",
- padnum,
- (unsigned int) offset,
- type_buf, field_name);
+ printf("\t\tstruct {\n\t\t\tchar padding%i[%u];\n\t\t\t%s%s%s;\n\t\t};\n",
+ padnum, (unsigned int) offset,
+ type_buf, field_name, array_buf);
}