diff options
-rw-r--r-- | dwarf-extract-struct.c | 321 |
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); } |