From f01875f49802c56e4f39654e273e3383d928498f Mon Sep 17 00:00:00 2001 From: "A.Olokhtonov" Date: Mon, 2 Aug 2021 22:34:27 +0300 Subject: [PATCH] Iterate the new DIE tree, getting useful info out. Tests pass. This step is probably not needed (as the DIE tree can be traversed as-is), and will be removed at a later stage --- build.sh | 2 +- src/common.h | 4 +- src/dwarf.c | 96 +++++++++++++++++++++++++++++++++++++++++++++--- src/elf_dwarf.h | 3 +- test/test_main.c | 5 ++- 5 files changed, 99 insertions(+), 11 deletions(-) diff --git a/build.sh b/build.sh index 9ab8fac..9f51561 100755 --- a/build.sh +++ b/build.sh @@ -32,7 +32,7 @@ elif [[ $1 = "tests" ]]; then echo "Entering directory: test" pushd test >/dev/null echo -n "Compiling test_main.c..." - gcc test_main.c -g -o ../build/test -Wall -Wextra -Wno-unused-function -Wno-unused-variable + gcc test_main.c -g -o ../build/test -Wall -Wextra -Wno-unused-function -Wno-unused-variable -Wno-switch # -fsanitize=address echo " Done. Built ../build/test" echo "Leaving directory: test" popd >/dev/null diff --git a/src/common.h b/src/common.h index 8999e63..2865376 100644 --- a/src/common.h +++ b/src/common.h @@ -80,13 +80,13 @@ struct mi_type { // used during parsing so that variables (which only have offsets) could find their // corresponding parsed type record - s64 _offset; + u64 _offset; }; struct mi_variable { char *name; s64 location; - int type; + u64 type; }; struct mi_function { diff --git a/src/dwarf.c b/src/dwarf.c index 3eeb717..f56a2a6 100644 --- a/src/dwarf.c +++ b/src/dwarf.c @@ -868,7 +868,7 @@ read_die_variable(u8 *file, u64 debug_str_offset, u64 *schema_offset, u64 *data_ } case DW_AT_type: { - dest->type = (void * ) value; // TODO TODO TODO + dest->type = value; break; } } @@ -1056,7 +1056,7 @@ read_die_const_type(u8 *file, u64 debug_str_offset, u64 *schema_offset, u64 *dat // NOTE(aolo2): parse one DIE and all of its children static struct dwarf_die * -read_one_die(u8 *file, u64 string_offset, u64 info_offset, u64 abbrev_offset, u8 address_size, u64 *data_offset, u32 depth) +read_one_die(u8 *file, u64 string_offset, u64 info_offset, u64 abbrev_offset, u8 address_size, u64 *data_offset, struct dwarf_die *parent, u32 depth) { u64 data = *data_offset; u64 record_offset = data - info_offset; @@ -1074,6 +1074,8 @@ read_one_die(u8 *file, u64 string_offset, u64 info_offset, u64 abbrev_offset, u8 // TODO: use a custom allocator / preallocated memory for this struct dwarf_die *die = calloc(1, sizeof(struct dwarf_die)); + die->parent = parent; + u64 schema_offset = abbrev_entry_offset(file, abbrev_offset, code); schema_offset += decode_leb128(file + schema_offset, NULL); schema_offset += decode_leb128(file + schema_offset, &tag); @@ -1131,11 +1133,11 @@ read_one_die(u8 *file, u64 string_offset, u64 info_offset, u64 abbrev_offset, u8 } if (has_children) { - die->first_child = read_one_die(file, string_offset, info_offset, abbrev_offset, address_size, &data, depth + 1); + die->first_child = read_one_die(file, string_offset, info_offset, abbrev_offset, address_size, &data, die, depth + 1); } if (depth > 0) { - die->next = read_one_die(file, string_offset, info_offset, abbrev_offset, address_size, &data, depth); + die->next = read_one_die(file, string_offset, info_offset, abbrev_offset, address_size, &data, parent, depth); } *data_offset = data; @@ -1143,10 +1145,94 @@ read_one_die(u8 *file, u64 string_offset, u64 info_offset, u64 abbrev_offset, u8 return(die); } +static void +traverse_die_tree_rec(struct mi_debuginfo *dest, struct dwarf_die *die) +{ + switch (die->tag) { + case DW_TAG_compile_unit: { + struct mi_compunit *comp_unit = dest->compilation_units + dest->cu_count; + + comp_unit->low_pc = die->compilation_unit.low_pc; + comp_unit->high_pc = die->compilation_unit.high_pc; + comp_unit->source.comp_dir = die->compilation_unit.comp_dir; + comp_unit->functions_from = dest->func_count; + + ++dest->cu_count; + + break; + } + + case DW_TAG_subprogram: { + struct mi_compunit *comp_unit = dest->compilation_units + dest->cu_count - 1; + struct mi_function *func = dest->functions + dest->func_count; + + func->name = die->subprogram.name; + func->low_pc = die->subprogram.low_pc; + func->high_pc = die->subprogram.high_pc; + func->variables_from = dest->var_count; + + ++comp_unit->functions_count; + + ++dest->func_count; + + break; + } + + case DW_TAG_variable: { + struct mi_function *func = dest->functions + dest->func_count - 1; + struct mi_variable *var = dest->variables + dest->var_count; + + var->name = die->variable.name; + var->location = die->variable.location; + var->type = die->variable.type; + + ++func->variables_count; + + ++dest->var_count; + + break; + } + + case DW_TAG_base_type: { + struct mi_type *type = dest->types + dest->type_count; + + type->encoding = die->type.encoding; + type->name = die->type.name; + type->size = die->type.size; + type->_offset = die->offset; + + ++dest->type_count; + + break; + } + } + + if (die->first_child) { + traverse_die_tree_rec(dest, die->first_child); + } + + if (die->next) { + traverse_die_tree_rec(dest, die->next); + } +} + +// NOTE(aolo2): turn the DIE tree into something usable static void decrap_die_tree(struct mi_debuginfo *dest, struct dwarf_die *die_root) { + traverse_die_tree_rec(dest, die_root); + // Resolve types + for (int v = 0; v < dest->var_count; ++v) { + struct mi_variable *var = dest->variables + v; + for (int t = 0; t < dest->type_count; ++t) { + struct mi_type *type = dest->types + t; + if (type->_offset == var->type) { + var->type = t; + break; + } + } + } } static u64 @@ -1161,7 +1247,7 @@ read_debug_info_for_compilation_unit(u8 *file, struct mi_debuginfo *dest, u64 data_offset = debug_info_offset + header_size; u8 address_size = di_header.address_size; - struct dwarf_die *root_die = read_one_die(file, debug_str_offset, debug_info_offset, abbrev_offset, address_size, &data_offset, 0); + struct dwarf_die *root_die = read_one_die(file, debug_str_offset, debug_info_offset, abbrev_offset, address_size, &data_offset, 0, 0); decrap_die_tree(dest, root_die); diff --git a/src/elf_dwarf.h b/src/elf_dwarf.h index 1043d7a..0ac2c23 100644 --- a/src/elf_dwarf.h +++ b/src/elf_dwarf.h @@ -741,7 +741,7 @@ struct dwarf_die_subprogram { struct dwarf_die_variable { char *name; int location; - struct dwarf_die_type *type; + int type; }; struct dwarf_die_type { @@ -761,6 +761,7 @@ struct dwarf_die { struct dwarf_die *first_child; struct dwarf_die *next; + struct dwarf_die *parent; enum dwarf_die_tag tag; union { diff --git a/test/test_main.c b/test/test_main.c index aa8e681..fbcbc71 100644 --- a/test/test_main.c +++ b/test/test_main.c @@ -6,11 +6,12 @@ #include "../src/command.c" #define DO_TEST(title, call) do { \ +fprintf(stderr, "Test '%s' ", title);\ int rt = call; \ if (rt == 0) { \ -fprintf(stderr, "Test '%s' \033[1m\033[32msuccess\033[0m...\n", title); \ +fprintf(stderr, "\033[1m\033[32msuccess\033[0m...\n"); \ } else { \ -fprintf(stderr, "Test '%s' \033[1m\033[31mfail\033[0m\n", title); \ +fprintf(stderr, "\033[1m\033[31mfail\033[0m\n"); \ exit(1); \ } \ } while(0)