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 @@ -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

4
src/common.h

@ -80,13 +80,13 @@ struct mi_type { @@ -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 {

96
src/dwarf.c

@ -868,7 +868,7 @@ read_die_variable(u8 *file, u64 debug_str_offset, u64 *schema_offset, u64 *data_ @@ -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 @@ -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 @@ -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 @@ -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 @@ -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, @@ -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);

3
src/elf_dwarf.h

@ -741,7 +741,7 @@ struct dwarf_die_subprogram { @@ -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 { @@ -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 {

5
test/test_main.c

@ -6,11 +6,12 @@ @@ -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)

Loading…
Cancel
Save