Browse Source

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

master
A.Olokhtonov 3 years ago
parent
commit
f01875f498
  1. 2
      build.sh
  2. 4
      src/common.h
  3. 96
      src/dwarf.c
  4. 3
      src/elf_dwarf.h
  5. 5
      test/test_main.c

2
build.sh

@ -32,7 +32,7 @@ elif [[ $1 = "tests" ]]; then
echo "Entering directory: test" echo "Entering directory: test"
pushd test >/dev/null pushd test >/dev/null
echo -n "Compiling test_main.c..." 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 " Done. Built ../build/test"
echo "Leaving directory: test" echo "Leaving directory: test"
popd >/dev/null popd >/dev/null

4
src/common.h

@ -80,13 +80,13 @@ struct mi_type {
// used during parsing so that variables (which only have offsets) could find their // used during parsing so that variables (which only have offsets) could find their
// corresponding parsed type record // corresponding parsed type record
s64 _offset; u64 _offset;
}; };
struct mi_variable { struct mi_variable {
char *name; char *name;
s64 location; s64 location;
int type; u64 type;
}; };
struct mi_function { struct mi_function {

96
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: { case DW_AT_type: {
dest->type = (void * ) value; // TODO TODO TODO dest->type = value;
break; 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 // NOTE(aolo2): parse one DIE and all of its children
static struct dwarf_die * 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 data = *data_offset;
u64 record_offset = data - info_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 // TODO: use a custom allocator / preallocated memory for this
struct dwarf_die *die = calloc(1, sizeof(struct dwarf_die)); struct dwarf_die *die = calloc(1, sizeof(struct dwarf_die));
die->parent = parent;
u64 schema_offset = abbrev_entry_offset(file, abbrev_offset, code); 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, NULL);
schema_offset += decode_leb128(file + schema_offset, &tag); 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) { 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) { 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; *data_offset = data;
@ -1143,10 +1145,94 @@ read_one_die(u8 *file, u64 string_offset, u64 info_offset, u64 abbrev_offset, u8
return(die); 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 static void
decrap_die_tree(struct mi_debuginfo *dest, struct dwarf_die *die_root) 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 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; u64 data_offset = debug_info_offset + header_size;
u8 address_size = di_header.address_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); decrap_die_tree(dest, root_die);

3
src/elf_dwarf.h

@ -741,7 +741,7 @@ struct dwarf_die_subprogram {
struct dwarf_die_variable { struct dwarf_die_variable {
char *name; char *name;
int location; int location;
struct dwarf_die_type *type; int type;
}; };
struct dwarf_die_type { struct dwarf_die_type {
@ -761,6 +761,7 @@ struct dwarf_die {
struct dwarf_die *first_child; struct dwarf_die *first_child;
struct dwarf_die *next; struct dwarf_die *next;
struct dwarf_die *parent;
enum dwarf_die_tag tag; enum dwarf_die_tag tag;
union { union {

5
test/test_main.c

@ -6,11 +6,12 @@
#include "../src/command.c" #include "../src/command.c"
#define DO_TEST(title, call) do { \ #define DO_TEST(title, call) do { \
fprintf(stderr, "Test '%s' ", title);\
int rt = call; \ int rt = call; \
if (rt == 0) { \ 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 { \ } else { \
fprintf(stderr, "Test '%s' \033[1m\033[31mfail\033[0m\n", title); \ fprintf(stderr, "\033[1m\033[31mfail\033[0m\n"); \
exit(1); \ exit(1); \
} \ } \
} while(0) } while(0)

Loading…
Cancel
Save