Skip to content

Commit

Permalink
libdrgn: Add support for parsing member objects
Browse files Browse the repository at this point in the history
  • Loading branch information
jgkamat committed Oct 10, 2020
1 parent 018684d commit 5e6b5fd
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 18 deletions.
101 changes: 86 additions & 15 deletions libdrgn/debug_info.c
Original file line number Diff line number Diff line change
Expand Up @@ -1030,6 +1030,13 @@ struct drgn_type_from_dwarf_thunk {
uint64_t bias;
};

struct drgn_object_from_dwarf_thunk {
struct drgn_object_thunk thunk;
Dwarf_Die die;
uint64_t bias;
const char* name;
};

/**
* Return whether a DWARF DIE is little-endian.
*
Expand Down Expand Up @@ -1210,6 +1217,50 @@ drgn_lazy_type_from_dwarf(struct drgn_debug_info *dbinfo,
return NULL;
}

static struct drgn_error *
drgn_object_from_dwarf_thunk_evaluate_fn(struct drgn_object_thunk *thunk,
struct drgn_object *ret);
static void drgn_object_from_dwarf_thunk_free_fn(struct drgn_object_thunk *thunk)
{
free(container_of(thunk, struct drgn_object_from_dwarf_thunk, thunk));
}


static struct drgn_error *
drgn_lazy_object_from_dwarf(struct drgn_debug_info *dbinfo,
Dwarf_Die *die,
uint64_t bias,
const char* name,
struct drgn_lazy_parameter *ret)
{
struct drgn_object_from_dwarf_thunk *thunk = malloc(sizeof(*thunk));
if (!thunk)
return &drgn_enomem;

thunk->thunk.prog = dbinfo->prog;
thunk->thunk.evaluate_fn = drgn_object_from_dwarf_thunk_evaluate_fn;
thunk->thunk.free_fn = drgn_object_from_dwarf_thunk_free_fn;
thunk->name = name;

bool decl;
if (!dwarf_flag(die, DW_AT_declaration, &decl) && decl) {
Dwfl_Module *module;
Dwarf_Off offset;
if (drgn_dwarf_index_find_definition(&dbinfo->dindex, (uintptr_t)die->addr, &module, &offset)) {
Dwarf *dwarf = dwfl_module_getdwarf(module, &bias);
if (!dwarf)
return drgn_error_libdwfl();
if (!dwarf_offdie(dwarf, offset, die))
return drgn_error_libdw();
}
}

thunk->bias = bias;
thunk->die = *die;
drgn_lazy_parameter_init_object_thunk(ret, &thunk->thunk);
return NULL;
}

/**
* Parse a type from the @c DW_AT_type attribute of a DWARF debugging
* information entry.
Expand Down Expand Up @@ -1502,6 +1553,7 @@ parse_member(struct drgn_debug_info *dbinfo, Dwarf_Die *die,
struct drgn_compound_type_builder *builder)
{
Dwarf_Attribute attr_mem, *attr;
struct drgn_error *err = NULL;
const char *name;
if ((attr = dwarf_attr_integrate(die, DW_AT_name, &attr_mem))) {
name = dwarf_formstring(attr);
Expand All @@ -1525,28 +1577,36 @@ parse_member(struct drgn_debug_info *dbinfo, Dwarf_Die *die,
bit_field_size = 0;
}

struct drgn_lazy_parameter member_type;
struct drgn_error *err = drgn_lazy_type_from_dwarf(dbinfo, die, bias,
can_be_incomplete_array,
"DW_TAG_member",
&member_type);
if (err)
return err;
uint64_t bit_offset = 0;
struct drgn_lazy_parameter member;
if (dwarf_tag(die) == DW_TAG_subprogram) {
// Creating objects
err = drgn_lazy_object_from_dwarf(dbinfo, die, bias, name, &member);
if (err)
return err;
} else {
// Creating types
err = drgn_lazy_type_from_dwarf(dbinfo, die, bias,
can_be_incomplete_array,
"DW_TAG_member",
&member);
if (err)
return err;

uint64_t bit_offset;
err = parse_member_offset(die, &member_type, bit_field_size,
little_endian, &bit_offset);
if (err)
goto err;
err = parse_member_offset(die, &member, bit_field_size,
little_endian, &bit_offset);
if (err)
goto err;
}

err = drgn_compound_type_builder_add_member(builder, member_type, name,
err = drgn_compound_type_builder_add_member(builder, member, name,
bit_offset, bit_field_size);
if (err)
goto err;
return NULL;

err:
drgn_lazy_parameter_deinit(&member_type);
drgn_lazy_parameter_deinit(&member);
return err;
}

Expand Down Expand Up @@ -1623,7 +1683,7 @@ drgn_compound_type_from_dwarf(struct drgn_debug_info *dbinfo,
Dwarf_Die member = {}, child;
int r = dwarf_child(die, &child);
while (r == 0) {
if (dwarf_tag(&child) == DW_TAG_member) {
if (dwarf_tag(&child) == DW_TAG_member || dwarf_tag(&child) == DW_TAG_subprogram) {
if (member.addr) {
err = parse_member(dbinfo, &member, bias,
little_endian, false,
Expand Down Expand Up @@ -2363,6 +2423,17 @@ drgn_object_from_dwarf_subprogram(struct drgn_debug_info *dbinfo,
0, byte_order);
}

static struct drgn_error *
drgn_object_from_dwarf_thunk_evaluate_fn(struct drgn_object_thunk *thunk,
struct drgn_object *ret)
{
struct drgn_object_from_dwarf_thunk *t =
container_of(thunk, struct drgn_object_from_dwarf_thunk, thunk);
// TODO Support not just subprogram
return drgn_object_from_dwarf_subprogram(thunk->prog->_dbinfo, &t->die,
t->bias, t->name, ret);
}

static struct drgn_error *
drgn_object_from_dwarf_constant(struct drgn_debug_info *dbinfo, Dwarf_Die *die,
struct drgn_qualified_type qualified_type,
Expand Down
6 changes: 3 additions & 3 deletions libdrgn/dwarf_index.c
Original file line number Diff line number Diff line change
Expand Up @@ -1065,8 +1065,8 @@ void drgn_dwarf_index_read_module(struct drgn_dwarf_index_update_state *state,
drgn_dwarf_index_update_cancel(state, drgn_eof());
}

static bool find_definition(struct drgn_dwarf_index *dindex, uintptr_t die_addr,
Dwfl_Module **module_ret, size_t *offset_ret)
bool drgn_dwarf_index_find_definition(struct drgn_dwarf_index *dindex, uintptr_t die_addr,
Dwfl_Module **module_ret, size_t *offset_ret)
{
struct drgn_dwarf_index_specification_map_iterator it =
drgn_dwarf_index_specification_map_search(&dindex->specifications,
Expand Down Expand Up @@ -1388,7 +1388,7 @@ index_cu_second_pass(struct drgn_dwarf_index_namespace *ns,
*/
die_offset = depth1_offset;
} else if (declaration &&
!find_definition(ns->dindex,
!drgn_dwarf_index_find_definition(ns->dindex,
(uintptr_t)debug_info_buffer +
die_offset,
&module, &die_offset)) {
Expand Down
13 changes: 13 additions & 0 deletions libdrgn/dwarf_index.h
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,19 @@ struct drgn_error *drgn_dwarf_index_get_die(struct drgn_dwarf_index_die *die,
Dwarf_Die *die_ret,
uint64_t *bias_ret);

/**
* Look up definitions from the specifications->declarations map.
*
* Dwarf definitions contain a map to their specification, but not the other way
* around. However, the specification is used to determine the scope of an object.
*
* @param [in] dindex The dwarf index containing the lookup map to use.
* @param [in] die_addr The address of the specification die.
* @param [out] die_ret The returned declaration die.
* @param [out] bias_ret The returned bias for the above die.
*/
bool drgn_dwarf_index_find_definition(struct drgn_dwarf_index *dindex, uintptr_t die_addr,
Dwfl_Module **module_ret, size_t *offset_ret);
/** @} */

#endif /* DRGN_DWARF_INDEX_H */

0 comments on commit 5e6b5fd

Please sign in to comment.