diff options
author | Dominique Martinet <asmadeus@codewreck.org> | 2017-10-03 16:23:38 +0900 |
---|---|---|
committer | Dominique Martinet <asmadeus@codewreck.org> | 2017-10-03 16:23:38 +0900 |
commit | 745feb05f35dd35fea386f7008c82edadd3166a3 (patch) | |
tree | 0f5b841b045e9c2397edd670fbff7b44fb64b5f0 /dwarf-extract-struct.c | |
parent | 8b079fca9d7726ebc860434350240d3a8d91a43a (diff) |
Add gitignore, makefile, license header
Diffstat (limited to 'dwarf-extract-struct.c')
-rw-r--r-- | dwarf-extract-struct.c | 413 |
1 files changed, 413 insertions, 0 deletions
diff --git a/dwarf-extract-struct.c b/dwarf-extract-struct.c new file mode 100644 index 0000000..b6ef87f --- /dev/null +++ b/dwarf-extract-struct.c @@ -0,0 +1,413 @@ +/* + * Trivial dwarf parser to extract part of a struct from debug infos + * + * Author: Dominique Martinet <dominique.martinet@cea.fr> + * License: WTFPLv2 + * + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdlib.h> +#include <unistd.h> +#include <stdio.h> +#include <strings.h> +#include <errno.h> +#include "dwarf.h" +#include "libdwarf.h" + + +static void parse_dwarf(Dwarf_Debug dbg, const char *struct_name, const char *field_names[], int field_count); +static void find_struct(Dwarf_Debug dbg, Dwarf_Die die, const char *struct_name, const char *field_names[], int field_count, int level); +static void find_fields(Dwarf_Debug dbg, Dwarf_Die die, const char *struct_name, const char *field_names[], int field_count, int level); +static void print_field(Dwarf_Debug dbg, Dwarf_Die die, const char *field_name, int pad_num); + +int debug = 0; + +void usage(char *argv[]) { + printf("%s debug_file struct_name field [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_names; + 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_names = 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_names, argc - 3); + + 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_names[], int field_count) { + 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; + + 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_names, field_count, 0); + } + + printf("struct %s not found\n", struct_name); + exit(2); +} + +static void find_struct(Dwarf_Debug dbg, Dwarf_Die die, const char *struct_name, const char *field_names[], int field_count, 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 : "<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_fields(dbg, next, struct_name, field_names, field_count, level + 1); + printf("Found struct %s but it did not have all members given!\nMissing:\n", + struct_name); + for (rc = 0; rc < field_count; rc++) { + if (field_names[rc]) + printf("%s\n", field_names[rc]); + } + exit(3); + } + find_struct(dbg, next, struct_name, field_names, field_count, 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_fields(Dwarf_Debug dbg, Dwarf_Die die, const char *struct_name, const char *field_names[], int field_count, int level) { + Dwarf_Die next; + Dwarf_Error err; + int rc, i, printed_count = 0; + + printf("struct %s {\n\tunion {\n", + struct_name); + + 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 : "<no name>"); + } + + if (tag == DW_TAG_member && name) { + for (i = 0; i < field_count; i++) { + if (!field_names[i]) + continue; + if (strcasecmp(name, field_names[i]) == 0) { + print_field(dbg, die, field_names[i], printed_count); + field_names[i] = NULL; + printed_count++; + break; + } + } + if (printed_count == field_count) { + printf("\t};\n};\n"); + exit(0); + } + } + + 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, int padnum) { + Dwarf_Attribute attr; + Dwarf_Error err; + Dwarf_Unsigned offset = 0; + char type_buf[1024]; + int rc; + + rc = dwarf_attr(die, DW_AT_data_member_location, &attr, &err); + if (rc == DW_DLV_NO_ENTRY) { + printf("Found %s but no offset, assuming 0\n", field_name); + } else if (rc != DW_DLV_OK) { + printf("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) { + 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(attr, &offset, 0); + } else if (form == DW_FORM_sdata) { + Dwarf_Signed soffset; + dwarf_formsdata(attr, &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(attr, &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; + } + dwarf_dealloc(dbg, attr, DW_DLA_ATTR); + } + + rc = dwarf_attr(die, DW_AT_type, &attr, &err); + if (rc == DW_DLV_NO_ENTRY) { + printf("Found %s but no type, can't assume that one out..\n", field_name); + exit(6); + } else if (rc != DW_DLV_OK) { + printf("Error getting dwarf attrlist: %s\n", dwarf_errmsg(err)); + exit(6); + } else { + Dwarf_Die type_die; + Dwarf_Off type_off; + Dwarf_Half type_tag; + char *type_name; + int pointer = 0; + + rc = dwarf_global_formref(attr, &type_off, &err); + if (rc != DW_DLV_OK) { + printf("Error getting ref offset for type: %s\n", dwarf_errmsg(err)); + exit(7); + } + + rc = dwarf_offdie_b(dbg, type_off, 1, &type_die, &err); + if (rc != DW_DLV_OK) { + printf("Error getting die from offset for type: %s\n", dwarf_errmsg(err)); + exit(7); + } + + rc = dwarf_tag(type_die, &type_tag, &err); + if (rc != DW_DLV_OK) { + printf("dwarf_tag error: %d %s\n", rc, dwarf_errmsg(err)); + exit(7); + } + + if (type_tag == DW_TAG_pointer_type) { + Dwarf_Attribute pointer_attr; + Dwarf_Off pointer_off; + Dwarf_Die pointer_die; + + rc = dwarf_attr(type_die, DW_AT_type, &pointer_attr, &err); + if (rc != DW_DLV_OK) { + printf("Error getting pointer attr for type: %s\n", dwarf_errmsg(err)); + exit(7); + } + + rc = dwarf_global_formref(pointer_attr, &pointer_off, &err); + if (rc != DW_DLV_OK) { + printf("Error getting pointer ref offset for type: %s\n", dwarf_errmsg(err)); + exit(7); + } + + rc = dwarf_offdie_b(dbg, pointer_off, 1, &pointer_die, &err); + if (rc != DW_DLV_OK) { + printf("Error getting pointer die from offset for type: %s\n", dwarf_errmsg(err)); + exit(7); + } + + 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); + if (rc != DW_DLV_OK) { + printf("dwarf_tag error: %d %s\n", rc, dwarf_errmsg(err)); + exit(7); + } + } + + rc = dwarf_diename(type_die, &type_name, &err); + if (rc != DW_DLV_OK) { + printf("dwarf_diename error: %d %s\n", rc, dwarf_errmsg(err)); + const char *tag_name; + + rc = dwarf_get_TAG_name(type_tag, &tag_name); + if (rc != DW_DLV_OK) { + printf("dwarf_get_TAG_name error: %d\n", rc); + } + + printf("Bad tag %s (%d)?\n", tag_name, type_tag); + exit(7); + } + + if (type_tag == DW_TAG_structure_type) { + snprintf(type_buf, 1024, "struct %s%s", pointer ? "*" : "", + type_name); + } else if (type_tag == DW_TAG_base_type || type_tag == DW_TAG_typedef) { + snprintf(type_buf, 1024, "%s%s", pointer ? "*" : "", + type_name); + } else { + const char *tag_name; + + rc = dwarf_get_TAG_name(type_tag, &tag_name); + if (rc != DW_DLV_OK) { + printf("dwarf_get_TAG_name error: %d\n", rc); + } + + printf("Type tag %s (%d) is not implemented, please add it\n", + tag_name, type_tag); + exit(7); + } + + dwarf_dealloc(dbg, type_name, DW_DLA_STRING); + dwarf_dealloc(dbg, attr, DW_DLA_ATTR); + 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); +} |