|
|
|
@ -967,8 +967,8 @@ read_die_structure_type(u8 *file, u64 debug_str_offset, u64 *schema_offset, u64
@@ -967,8 +967,8 @@ read_die_structure_type(u8 *file, u64 debug_str_offset, u64 *schema_offset, u64
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
read_die_member(u8 *file, u64 debug_str_offset, u64 *schema_offset, u64 *data_offset, |
|
|
|
|
u8 address_size, struct dwarf_die_type *dest) |
|
|
|
|
read_die_structure_member(u8 *file, u64 debug_str_offset, u64 *schema_offset, u64 *data_offset, |
|
|
|
|
u8 address_size, struct dwarf_die_type *dest) |
|
|
|
|
{ |
|
|
|
|
u64 data = *data_offset; |
|
|
|
|
u64 schema = *schema_offset; |
|
|
|
@ -979,6 +979,18 @@ read_die_member(u8 *file, u64 debug_str_offset, u64 *schema_offset, u64 *data_of
@@ -979,6 +979,18 @@ read_die_member(u8 *file, u64 debug_str_offset, u64 *schema_offset, u64 *data_of
|
|
|
|
|
schema += decode_leb128(file + schema, &attribute); |
|
|
|
|
schema += decode_leb128(file + schema, &form); |
|
|
|
|
data += read_actual_debug_data(file, debug_str_offset, address_size, form, data, &value); |
|
|
|
|
|
|
|
|
|
switch (attribute) { |
|
|
|
|
case DW_AT_name: { |
|
|
|
|
dest->name = (char *) value; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
case DW_AT_type: { |
|
|
|
|
dest->pointer = value; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} while (attribute != 0 || form != 0); |
|
|
|
|
|
|
|
|
|
*data_offset = data; |
|
|
|
@ -986,53 +998,155 @@ read_die_member(u8 *file, u64 debug_str_offset, u64 *schema_offset, u64 *data_of
@@ -986,53 +998,155 @@ read_die_member(u8 *file, u64 debug_str_offset, u64 *schema_offset, u64 *data_of
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
read_one_die(u8 *file, u64 debug_info_offset, u64 debug_str_offset, u64 *schema_offset, u64 *data_offset, |
|
|
|
|
enum dwarf_die_tag tag, u8 address_size, struct dwarf_die *dest) |
|
|
|
|
read_die_pointer_type(u8 *file, u64 debug_str_offset, u64 *schema_offset, u64 *data_offset, |
|
|
|
|
u8 address_size, struct dwarf_die_type *dest) |
|
|
|
|
{ |
|
|
|
|
u64 data = *data_offset; |
|
|
|
|
u64 schema = *schema_offset; |
|
|
|
|
|
|
|
|
|
u32 attribute, form; |
|
|
|
|
do { |
|
|
|
|
u64 value; |
|
|
|
|
schema += decode_leb128(file + schema, &attribute); |
|
|
|
|
schema += decode_leb128(file + schema, &form); |
|
|
|
|
data += read_actual_debug_data(file, debug_str_offset, address_size, form, data, &value); |
|
|
|
|
|
|
|
|
|
switch (attribute) { |
|
|
|
|
case DW_AT_byte_size: { |
|
|
|
|
dest->size = value; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
case DW_AT_type: { |
|
|
|
|
dest->pointer = value; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} while (attribute != 0 || form != 0); |
|
|
|
|
|
|
|
|
|
*data_offset = data; |
|
|
|
|
*schema_offset = schema; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
read_die_const_type(u8 *file, u64 debug_str_offset, u64 *schema_offset, u64 *data_offset, |
|
|
|
|
u8 address_size, struct dwarf_die_type *dest) |
|
|
|
|
{ |
|
|
|
|
u64 data = *data_offset; |
|
|
|
|
u64 schema = *schema_offset; |
|
|
|
|
|
|
|
|
|
dest->offset = data - debug_info_offset; |
|
|
|
|
dest->tag = tag; |
|
|
|
|
u32 attribute, form; |
|
|
|
|
do { |
|
|
|
|
u64 value; |
|
|
|
|
schema += decode_leb128(file + schema, &attribute); |
|
|
|
|
schema += decode_leb128(file + schema, &form); |
|
|
|
|
data += read_actual_debug_data(file, debug_str_offset, address_size, form, data, &value); |
|
|
|
|
|
|
|
|
|
switch (attribute) { |
|
|
|
|
case DW_AT_type: { |
|
|
|
|
dest->pointer = value; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} while (attribute != 0 || form != 0); |
|
|
|
|
|
|
|
|
|
*data_offset = data; |
|
|
|
|
*schema_offset = schema; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 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) |
|
|
|
|
{ |
|
|
|
|
u64 data = *data_offset; |
|
|
|
|
u64 record_offset = data - info_offset; |
|
|
|
|
|
|
|
|
|
u32 code; |
|
|
|
|
u32 tag; |
|
|
|
|
|
|
|
|
|
data += decode_leb128(file + data, &code); |
|
|
|
|
|
|
|
|
|
if (code == 0) { |
|
|
|
|
*data_offset = data; |
|
|
|
|
return(0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// TODO: use a custom allocator / preallocated memory for this
|
|
|
|
|
struct dwarf_die *die = calloc(1, sizeof(struct dwarf_die)); |
|
|
|
|
|
|
|
|
|
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); |
|
|
|
|
|
|
|
|
|
u8 has_children = file[schema_offset++]; |
|
|
|
|
|
|
|
|
|
die->tag = tag; |
|
|
|
|
die->offset = record_offset; |
|
|
|
|
|
|
|
|
|
// TODO: remove code duplication for prologue/epilogue of all these functions
|
|
|
|
|
switch (tag) { |
|
|
|
|
case DW_TAG_compile_unit: { |
|
|
|
|
read_die_compilation_unit(file, debug_str_offset, &schema, &data, address_size, &dest->compilation_unit); |
|
|
|
|
read_die_compilation_unit(file, string_offset, &schema_offset, &data, address_size, &die->compilation_unit); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
case DW_TAG_subprogram: { |
|
|
|
|
read_die_subprogram(file, debug_str_offset, &schema, &data, address_size, &dest->subprogram); |
|
|
|
|
read_die_subprogram(file, string_offset, &schema_offset, &data, address_size, &die->subprogram); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
case DW_TAG_variable: { |
|
|
|
|
read_die_variable(file, debug_str_offset, &schema, &data, address_size, &dest->variable); |
|
|
|
|
read_die_variable(file, string_offset, &schema_offset, &data, address_size, &die->variable); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
case DW_TAG_base_type: { |
|
|
|
|
read_die_base_type(file, debug_str_offset, &schema, &data, address_size, &dest->type); |
|
|
|
|
read_die_base_type(file, string_offset, &schema_offset, &data, address_size, &die->type); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
case DW_TAG_structure_type: { |
|
|
|
|
read_die_structure_type(file, debug_str_offset, &schema, &data, address_size, &dest->type); |
|
|
|
|
read_die_structure_type(file, string_offset, &schema_offset, &data, address_size, &die->type); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
case DW_TAG_member: { |
|
|
|
|
read_die_member(file, debug_str_offset, &schema, &data, address_size, &dest->type); |
|
|
|
|
read_die_structure_member(file, string_offset, &schema_offset, &data, address_size, &die->type); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
case DW_TAG_pointer_type: { |
|
|
|
|
read_die_pointer_type(file, string_offset, &schema_offset, &data, address_size, &die->type); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
case DW_TAG_const_type: { |
|
|
|
|
read_die_const_type(file, string_offset, &schema_offset, &data, address_size, &die->type); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
default: { |
|
|
|
|
read_die_nop(file, debug_str_offset, &schema, &data, address_size); |
|
|
|
|
read_die_nop(file, string_offset, &schema_offset, &data, address_size); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (has_children) { |
|
|
|
|
die->first_child = read_one_die(file, string_offset, info_offset, abbrev_offset, address_size, &data, depth + 1); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (depth > 0) { |
|
|
|
|
die->next = read_one_die(file, string_offset, info_offset, abbrev_offset, address_size, &data, depth); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
*schema_offset = schema; |
|
|
|
|
*data_offset = data; |
|
|
|
|
|
|
|
|
|
return(die); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
decrap_die_tree(struct mi_debuginfo *dest, struct dwarf_die *die_root) |
|
|
|
|
{ |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static u64 |
|
|
|
@ -1045,49 +1159,11 @@ read_debug_info_for_compilation_unit(u8 *file, struct mi_debuginfo *dest,
@@ -1045,49 +1159,11 @@ read_debug_info_for_compilation_unit(u8 *file, struct mi_debuginfo *dest,
|
|
|
|
|
|
|
|
|
|
u64 abbrev_offset = debug_abbrev_offset + di_header.debug_abbrev_offset; |
|
|
|
|
u64 data_offset = debug_info_offset + header_size; |
|
|
|
|
u8 address_size = di_header.address_size; |
|
|
|
|
|
|
|
|
|
u32 code, tag; |
|
|
|
|
u64 schema_offset; |
|
|
|
|
u32 depth = 0; |
|
|
|
|
//u64 base_data_offset = data_offset - header_size;
|
|
|
|
|
|
|
|
|
|
int vars_from = dest->var_count; |
|
|
|
|
int types_from = dest->type_count; |
|
|
|
|
|
|
|
|
|
struct mi_compunit *comp_unit = dest->compilation_units + dest->cu_count; |
|
|
|
|
struct mi_function *func = dest->functions + dest->func_count; |
|
|
|
|
struct mi_variable *variable = dest->variables + dest->var_count; |
|
|
|
|
struct mi_type *type = dest->types + dest->type_count; |
|
|
|
|
|
|
|
|
|
struct dwarf_die d_die = { 0 }; |
|
|
|
|
struct dwarf_die *die = &d_die; |
|
|
|
|
u8 address_size = di_header.address_size; |
|
|
|
|
|
|
|
|
|
comp_unit->functions_from = dest->func_count; |
|
|
|
|
struct dwarf_die *root_die = read_one_die(file, debug_str_offset, debug_info_offset, abbrev_offset, address_size, &data_offset, 0); |
|
|
|
|
|
|
|
|
|
for (;;) { |
|
|
|
|
data_offset += decode_leb128(file + data_offset, &code); |
|
|
|
|
|
|
|
|
|
if (code == 0) { |
|
|
|
|
if (depth > 1) { |
|
|
|
|
--depth; |
|
|
|
|
continue; |
|
|
|
|
} else { |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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); |
|
|
|
|
|
|
|
|
|
u32 has_children = file[schema_offset++]; |
|
|
|
|
if (has_children) { |
|
|
|
|
++depth; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
read_one_die(file, debug_info_offset, debug_str_offset, &schema_offset, &data_offset, tag, address_size, die); |
|
|
|
|
} |
|
|
|
|
decrap_die_tree(dest, root_die); |
|
|
|
|
|
|
|
|
|
return(di_header.length + 4); |
|
|
|
|
} |
|
|
|
|