Browse Source

Experiments with new DIE parsing (broken)

master
aolo2 3 years ago
parent
commit
a83b2346a1
  1. 395
      src/dwarf.c
  2. 46
      src/elf_dwarf.h

395
src/dwarf.c

@ -753,214 +753,341 @@ read_actual_debug_data(u8 *file, u64 string_offset, u32 address_size, u32 form, @@ -753,214 +753,341 @@ read_actual_debug_data(u8 *file, u64 string_offset, u32 address_size, u32 form,
return(increment);
}
static u64
read_debug_info_for_compilation_unit(u8 *file, struct mi_debuginfo *dest,
u64 debug_info_offset, u64 debug_abbrev_offset, u64 debug_str_offset)
static void
read_die_compilation_unit(u8 *file, u64 debug_str_offset, u64 *schema_offset, u64 *data_offset,
u8 address_size, struct dwarf_die_compilation_unit *dest)
{
struct dwarf_debug_info_header_x32 di_header = { 0 };
u32 header_size = sizeof(di_header);
memcpy(&di_header, file + debug_info_offset, header_size);
u64 abbrev_offset = debug_abbrev_offset + di_header.debug_abbrev_offset;
u64 data_offset = debug_info_offset + header_size;
u32 code, tag;
u64 schema_offset;
u32 depth = 0;
//u64 base_data_offset = data_offset - header_size;
u64 schema = *schema_offset;
u64 data = *data_offset;
int vars_from = dest->var_count;
int types_from = dest->type_count;
u32 attribute, form;
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;
do {
u64 value;
struct mi_type *parent_type = 0;
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);
comp_unit->functions_from = dest->func_count;
switch (attribute) {
case DW_AT_name: {
dest->name = (char *) value;
break;
}
for (;;) {
s64 record_offset = data_offset - debug_info_offset;
case DW_AT_comp_dir: {
dest->comp_dir = (char *) value;
break;
}
data_offset += decode_leb128(file + data_offset, &code);
case DW_AT_low_pc: {
dest->low_pc = value;
break;
}
if (code == 0) {
if (depth > 1) {
--depth;
continue;
} else {
case DW_AT_high_pc: {
dest->high_pc = value;
break;
}
}
} while (attribute != 0 || form != 0);
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);
dest->high_pc = dest->low_pc + dest->high_pc;
//printf("%d %s\n", code, tag_to_str(tag));
*schema_offset = schema;
*data_offset = data;
}
u32 has_children = file[schema_offset++];
if (has_children) {
++depth;
}
switch (tag) {
case DW_TAG_compile_unit: {
static void
read_die_subprogram(u8 *file, u64 debug_str_offset, u64 *schema_offset, u64 *data_offset,
u8 address_size, struct dwarf_die_subprogram *dest)
{
u64 schema = *schema_offset;
u64 data = *data_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_name: {
dest->name = (char *) value;
break;
}
case DW_TAG_subprogram: {
case DW_AT_low_pc: {
dest->low_pc = value;
break;
}
case DW_TAG_variable: {
case DW_AT_high_pc: {
dest->high_pc = value;
break;
}
}
} while (attribute != 0 || form != 0);
case DW_TAG_structure_type: {
dest->high_pc = dest->low_pc + dest->high_pc;
*schema_offset = schema;
*data_offset = data;
}
static void
read_die_variable(u8 *file, u64 debug_str_offset, u64 *schema_offset, u64 *data_offset,
u8 address_size, struct dwarf_die_variable *dest)
{
u64 schema = *schema_offset;
u64 data = *data_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_name: {
dest->name = (char *) value;
break;
}
case DW_TAG_member: {
case DW_AT_location: {
dest->location = value;
break;
}
case DW_TAG_base_type: {
case DW_AT_type: {
dest->type = (void * ) value; // TODO TODO TODO
break;
}
}
#if 0
} while (attribute != 0 || form != 0);
*schema_offset = schema;
*data_offset = data;
}
static void
read_die_base_type(u8 *file, u64 debug_str_offset, u64 *schema_offset, u64 *data_offset,
u8 address_size, struct dwarf_die_type *dest)
{
u64 schema = *schema_offset;
u64 data = *data_offset;
u32 attribute, form;
do {
schema_offset += decode_leb128(file + schema_offset, &attribute);
schema_offset += decode_leb128(file + schema_offset, &form);
u64 value;
data_offset += read_actual_debug_data(file, debug_str_offset, di_header.address_size, form, data_offset, &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);
if (tag == DW_TAG_compile_unit) {
if (attribute == DW_AT_low_pc) {
comp_unit->low_pc = value;
} else if (attribute == DW_AT_high_pc) {
comp_unit->high_pc = value;
} else if (attribute == DW_AT_comp_dir) {
comp_unit->source.comp_dir = (char *) value;
switch (attribute) {
case DW_AT_name: {
dest->name = (char *) value;
break;
}
} else if (tag == DW_TAG_subprogram) {
if (attribute == DW_AT_name) {
func->name = (char *) value;
} else if (attribute == DW_AT_low_pc) {
func->low_pc = value;
} else if (attribute == DW_AT_high_pc) {
func->high_pc = value;
case DW_AT_byte_size: {
dest->size = value;
break;
}
} else if (tag == DW_TAG_variable) {
if (attribute == DW_AT_name) {
variable->name = (char *) value;
} else if (attribute == DW_AT_location) {
variable->location = value;
} else if (attribute == DW_AT_type) {
variable->type = value;
case DW_AT_encoding: {
dest->encoding = value;
break;
}
} else if (tag == DW_TAG_structure_type) {
type->_offset = record_offset;
if (attribute == DW_AT_name) {
type->name = (char *) value;
} else if (attribute == DW_AT_byte_size) {
type->size = value;
}
} else if (tag == DW_TAG_member) {
} while (attribute != 0 || form != 0);
} else if (tag == DW_TAG_base_type) {
type->_offset = record_offset;
if (attribute == DW_AT_name) {
type->name = (char *) value;
} else if (attribute == DW_AT_byte_size) {
type->size = value;
} else if (attribute == DW_AT_encoding) {
enum dwarf_type_encoding encoding = value;
switch (encoding) {
case DW_ATE_address: {
type->encoding = MI_ADDRESS;
*schema_offset = schema;
*data_offset = data;
}
static void
read_die_nop(u8 *file, u64 debug_str_offset, u64 *schema_offset, u64 *data_offset,
u8 address_size)
{
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);
} while (attribute != 0 || form != 0);
*data_offset = data;
*schema_offset = schema;
}
static void
read_die_structure_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_name: {
dest->name = (char *) value;
break;
}
case DW_ATE_boolean: {
type->encoding = MI_BOOLEAN;
case DW_AT_byte_size: {
dest->size = value;
break;
}
}
} while (attribute != 0 || form != 0);
case DW_ATE_float: {
type->encoding = MI_FLOAT;
*data_offset = data;
*schema_offset = schema;
}
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)
{
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);
} while (attribute != 0 || form != 0);
*data_offset = data;
*schema_offset = schema;
}
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)
{
u64 schema = *schema_offset;
u64 data = *data_offset;
dest->offset = data - debug_info_offset;
dest->tag = tag;
switch (tag) {
case DW_TAG_compile_unit: {
read_die_compilation_unit(file, debug_str_offset, &schema, &data, address_size, &dest->compilation_unit);
break;
}
case DW_ATE_signed_char:
case DW_ATE_signed: {
type->encoding = MI_SIGNED;
case DW_TAG_subprogram: {
read_die_subprogram(file, debug_str_offset, &schema, &data, address_size, &dest->subprogram);
break;
}
case DW_ATE_unsigned_char:
case DW_ATE_unsigned: {
type->encoding = MI_UNSIGNED;
case DW_TAG_variable: {
read_die_variable(file, debug_str_offset, &schema, &data, address_size, &dest->variable);
break;
}
default: {
DIE("unexpected type encoding!\n");
}
case DW_TAG_base_type: {
read_die_base_type(file, debug_str_offset, &schema, &data, address_size, &dest->type);
break;
}
case DW_TAG_structure_type: {
read_die_structure_type(file, debug_str_offset, &schema, &data, address_size, &dest->type);
break;
}
case DW_TAG_member: {
read_die_member(file, debug_str_offset, &schema, &data, address_size, &dest->type);
break;
}
} while (attribute != 0 || form != 0);
// NOTE(aolo2): DIE completely processed, finish it ??uploads??
if (tag == DW_TAG_subprogram) {
func->high_pc = func->low_pc + func->high_pc;
func->variables_from = dest->var_count;
++comp_unit->functions_count;
++dest->func_count;
++func;
} else if (tag == DW_TAG_variable) {
struct mi_function *parent = func - 1;
++parent->variables_count;
++dest->var_count;
++variable;
} else if (tag == DW_TAG_base_type) {
++parent_type->children_count;
++dest->type_count;
++type;
} else if (tag == DW_TAG_structure_type) {
parent_type = type;
parent_type->children_from = dest->type_count;
++type;
default: {
read_die_nop(file, debug_str_offset, &schema, &data, address_size);
}
}
#endif
*schema_offset = schema;
*data_offset = data;
}
}
static u64
read_debug_info_for_compilation_unit(u8 *file, struct mi_debuginfo *dest,
u64 debug_info_offset, u64 debug_abbrev_offset, u64 debug_str_offset)
{
struct dwarf_debug_info_header_x32 di_header = { 0 };
u32 header_size = sizeof(di_header);
memcpy(&di_header, file + debug_info_offset, header_size);
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;
// Resolve types
for (int v = vars_from; v < dest->var_count; ++v) {
struct mi_variable *variable = dest->variables + v;
u32 code, tag;
u64 schema_offset;
u32 depth = 0;
//u64 base_data_offset = data_offset - header_size;
for (int t = types_from; t < dest->type_count; ++t) {
struct mi_type *type = dest->types + t;
int vars_from = dest->var_count;
int types_from = dest->type_count;
if (type->_offset == variable->type) {
variable->type = t;
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;
comp_unit->functions_from = dest->func_count;
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;
}
comp_unit->high_pc = comp_unit->low_pc + comp_unit->high_pc;
++dest->cu_count;
read_one_die(file, debug_info_offset, debug_str_offset, &schema_offset, &data_offset, tag, address_size, die);
}
return(di_header.length + 4);
}

46
src/elf_dwarf.h

@ -722,3 +722,49 @@ struct dwarf_regset { @@ -722,3 +722,49 @@ struct dwarf_regset {
enum dwarf_regset_register cfa_register;
u32 cfa_offset;
};
struct dwarf_die_compilation_unit {
u64 low_pc;
u64 high_pc;
char *name;
char *comp_dir;
};
struct dwarf_die_subprogram {
u64 low_pc;
u64 high_pc;
char *name;
// TODO: frame base (might be NOT cfa)
// TODO: type
};
struct dwarf_die_variable {
char *name;
int location;
struct dwarf_die_type *type;
};
struct dwarf_die_type {
char *name;
int size;
int encoding;
int is_const;
int is_pointer;
int is_restrict;
struct dwarf_die_type *next;
struct dwarf_die_type *first_child;
};
struct dwarf_die {
u64 offset;
struct dwarf_die *parent;
enum dwarf_die_tag tag;
union {
struct dwarf_die_compilation_unit compilation_unit;
struct dwarf_die_subprogram subprogram;
struct dwarf_die_variable variable;
struct dwarf_die_type type;
};
};
Loading…
Cancel
Save