summaryrefslogtreecommitdiffstats
path: root/dwarf-extract-struct.c
diff options
context:
space:
mode:
authorDominique Martinet <asmadeus@codewreck.org>2017-10-03 16:23:38 +0900
committerDominique Martinet <asmadeus@codewreck.org>2017-10-03 16:23:38 +0900
commit745feb05f35dd35fea386f7008c82edadd3166a3 (patch)
tree0f5b841b045e9c2397edd670fbff7b44fb64b5f0 /dwarf-extract-struct.c
parent8b079fca9d7726ebc860434350240d3a8d91a43a (diff)
Add gitignore, makefile, license header
Diffstat (limited to 'dwarf-extract-struct.c')
-rw-r--r--dwarf-extract-struct.c413
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);
+}