#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "libdwP.h"
#include <dwarf.h>
static bool
may_have_scopes (Dwarf_Die *die)
{
switch (INTUSE(dwarf_tag) (die))
{
case DW_TAG_compile_unit:
case DW_TAG_module:
case DW_TAG_lexical_block:
case DW_TAG_with_stmt:
case DW_TAG_catch_block:
case DW_TAG_try_block:
case DW_TAG_entry_point:
case DW_TAG_inlined_subroutine:
case DW_TAG_subprogram:
return true;
case DW_TAG_namespace:
case DW_TAG_class_type:
case DW_TAG_structure_type:
return true;
default:
break;
}
return false;
}
struct walk_children_state
{
unsigned int depth;
struct Dwarf_Die_Chain *imports;
int (*previsit) (unsigned int depth, struct Dwarf_Die_Chain *, void *);
int (*postvisit) (unsigned int depth, struct Dwarf_Die_Chain *, void *);
void *arg;
struct Dwarf_Die_Chain child;
};
static inline int
walk_children (struct walk_children_state *state);
int
internal_function
__libdw_visit_scopes (unsigned int depth, struct Dwarf_Die_Chain *root,
struct Dwarf_Die_Chain *imports,
int (*previsit) (unsigned int,
struct Dwarf_Die_Chain *,
void *),
int (*postvisit) (unsigned int,
struct Dwarf_Die_Chain *,
void *),
void *arg)
{
struct walk_children_state state =
{
.depth = depth,
.imports = imports,
.previsit = previsit,
.postvisit = postvisit,
.arg = arg
};
state.child.parent = root;
int ret;
if ((ret = INTUSE(dwarf_child) (&root->die, &state.child.die)) != 0)
return ret < 0 ? -1 : 0;
return walk_children (&state);
}
static inline int
walk_children (struct walk_children_state *state)
{
int ret;
do
{
while (INTUSE(dwarf_tag) (&state->child.die) == DW_TAG_imported_unit)
{
Dwarf_Die orig_child_die = state->child.die;
Dwarf_Attribute attr_mem;
Dwarf_Attribute *attr = INTUSE(dwarf_attr) (&state->child.die,
DW_AT_import,
&attr_mem);
if (INTUSE(dwarf_formref_die) (attr, &state->child.die) != NULL
&& INTUSE(dwarf_tag) (&state->child.die) != DW_TAG_compile_unit
&& (INTUSE(dwarf_child) (&state->child.die, &state->child.die)
== 0))
{
bool imported = false;
for (struct Dwarf_Die_Chain *import = state->imports; import != NULL;
import = import->parent)
if (import->die.addr == orig_child_die.addr)
{
imported = true;
break;
}
if (imported)
{
__libdw_seterrno (DWARF_E_INVALID_DWARF);
return -1;
}
struct Dwarf_Die_Chain *orig_imports = state->imports;
struct Dwarf_Die_Chain import = { .die = orig_child_die,
.parent = orig_imports };
state->imports = &import;
int result = walk_children (state);
state->imports = orig_imports;
if (result != DWARF_CB_OK)
return result;
}
if ((ret = INTUSE(dwarf_siblingof) (&orig_child_die,
&state->child.die)) != 0)
return ret < 0 ? -1 : 0;
};
state->child.prune = false;
int result = (*state->previsit) (state->depth + 1, &state->child, state->arg);
if (result != DWARF_CB_OK)
return result;
if (!state->child.prune && may_have_scopes (&state->child.die)
&& INTUSE(dwarf_haschildren) (&state->child.die))
{
result = __libdw_visit_scopes (state->depth + 1, &state->child, state->imports,
state->previsit, state->postvisit, state->arg);
if (result != DWARF_CB_OK)
return result;
}
if (state->postvisit != NULL)
{
result = (*state->postvisit) (state->depth + 1, &state->child, state->arg);
if (result != DWARF_CB_OK)
return result;
}
}
while ((ret = INTUSE(dwarf_siblingof) (&state->child.die, &state->child.die)) == 0);
return ret < 0 ? -1 : 0;
}