dbghelp/dwarf: Add a helper to jump into another debug_info.

This helper takes into account that source and destination debug_info
can be in different dwarf units, and even different debug files (DWZ).

Signed-off-by: Eric Pouech <eric.pouech@gmail.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Eric Pouech 2021-09-16 11:10:41 +02:00 committed by Alexandre Julliard
parent def87b2aef
commit d832d51c2c
1 changed files with 52 additions and 25 deletions

View File

@ -134,6 +134,7 @@ struct attribute
const char* string;
struct dwarf2_block block;
} u;
const struct dwarf2_debug_info_s* debug_info;
};
typedef struct dwarf2_debug_info_s
@ -711,6 +712,8 @@ static BOOL dwarf2_fill_attr(const dwarf2_parse_context_t* ctx,
return TRUE;
}
static dwarf2_debug_info_t* dwarf2_jump_to_debug_info(struct attribute* attr);
static BOOL dwarf2_find_attribute(const dwarf2_debug_info_t* di,
unsigned at, struct attribute* attr)
{
@ -722,6 +725,7 @@ static BOOL dwarf2_find_attribute(const dwarf2_debug_info_t* di,
while (di)
{
ref_abbrev_attr = NULL;
attr->debug_info = di;
for (i = 0, abbrev_attr = di->abbrev->attrs; abbrev_attr; i++, abbrev_attr = abbrev_attr->next)
{
if (abbrev_attr->attribute == at)
@ -743,12 +747,49 @@ static BOOL dwarf2_find_attribute(const dwarf2_debug_info_t* di,
/* do we have either an abstract origin or a specification debug entry to look into ? */
if (!ref_abbrev_attr || !dwarf2_fill_attr(di->unit_ctx, ref_abbrev_attr, di->data[refidx], attr))
break;
if (!(di = sparse_array_find(&di->unit_ctx->debug_info_table, attr->u.uvalue)))
if (!(di = dwarf2_jump_to_debug_info(attr)))
{
FIXME("Should have found the debug info entry\n");
break;
}
}
return FALSE;
}
static dwarf2_debug_info_t* dwarf2_jump_to_debug_info(struct attribute* attr)
{
dwarf2_parse_context_t* ref_ctx = NULL;
BOOL with_other = TRUE;
dwarf2_debug_info_t* ret;
switch (attr->form)
{
case DW_FORM_ref_addr:
ref_ctx = dwarf2_locate_cu(attr->debug_info->unit_ctx->module_ctx, attr->u.uvalue);
break;
default:
with_other = FALSE;
ref_ctx = attr->debug_info->unit_ctx;
break;
}
if (!ref_ctx) return FALSE;
/* There are cases where we end up with a circular reference between two (or more)
* compilation units. Before this happens, try to see if we can refer to an already
* loaded debug_info in the target compilation unit (even if all the debug_info
* haven't been loaded yet).
*/
if (ref_ctx->status == UNIT_BEINGLOADED &&
(ret = sparse_array_find(&ref_ctx->debug_info_table, attr->u.uvalue)))
return ret;
if (with_other)
{
/* ensure CU is fully loaded */
if (ref_ctx != attr->debug_info->unit_ctx && !dwarf2_parse_compilation_unit(ref_ctx))
return NULL;
}
return sparse_array_find(&ref_ctx->debug_info_table, attr->u.uvalue);
}
static void dwarf2_load_one_entry(dwarf2_debug_info_t*);
#define Wine_DW_no_register 0x7FFFFFFF
@ -1069,24 +1110,9 @@ static struct symt* dwarf2_lookup_type(const dwarf2_debug_info_t* di)
if (!dwarf2_find_attribute(di, DW_AT_type, &attr))
/* this is only valid if current language of CU is C or C++ */
return di->unit_ctx->module_ctx->symt_cache[sc_void];
if (!(type = sparse_array_find(&di->unit_ctx->debug_info_table, attr.u.uvalue)))
{
if (attr.form == DW_FORM_ref_addr)
{
dwarf2_parse_context_t* ref_ctx = dwarf2_locate_cu(di->unit_ctx->module_ctx, attr.u.uvalue);
/* ensure CU is fully loaded */
if (ref_ctx && dwarf2_parse_compilation_unit(ref_ctx))
{
type = sparse_array_find(&ref_ctx->debug_info_table, attr.u.uvalue);
if (type) TRACE("Found type ref %lx in another CU %s\n", attr.u.uvalue, dwarf2_debug_unit_ctx(ref_ctx));
}
}
if (!type)
{
FIXME("Unable to find back reference to type 0x%lx (form=0x%lx)\n", attr.u.uvalue, attr.form);
return di->unit_ctx->module_ctx->symt_cache[sc_unknown];
}
}
if (!(type = dwarf2_jump_to_debug_info(&attr)))
return di->unit_ctx->module_ctx->symt_cache[sc_unknown];
if (type == di)
{
FIXME("Reference to itself\n");
@ -1112,17 +1138,13 @@ static const char* dwarf2_get_cpp_name(dwarf2_debug_info_t* di, const char* name
struct attribute spec;
if (di->abbrev->tag == DW_TAG_compile_unit) return name;
if (!di->unit_ctx->cpp_name)
di->unit_ctx->cpp_name = pool_alloc(&di->unit_ctx->pool, MAX_SYM_NAME);
last = di->unit_ctx->cpp_name + MAX_SYM_NAME - strlen(name) - 1;
strcpy(last, name);
/* if the di is a definition, but has also a (previous) declaration, then scope must
* be gotten from declaration not definition
*/
if (dwarf2_find_attribute(di, DW_AT_specification, &spec) && spec.gotten_from == attr_direct)
{
di = sparse_array_find(&di->unit_ctx->debug_info_table, spec.u.uvalue);
di = dwarf2_jump_to_debug_info(&spec);
if (!di)
{
FIXME("Should have found the debug info entry\n");
@ -1130,6 +1152,11 @@ static const char* dwarf2_get_cpp_name(dwarf2_debug_info_t* di, const char* name
}
}
if (!di->unit_ctx->cpp_name)
di->unit_ctx->cpp_name = pool_alloc(&di->unit_ctx->pool, MAX_SYM_NAME);
last = di->unit_ctx->cpp_name + MAX_SYM_NAME - strlen(name) - 1;
strcpy(last, name);
for (di = di->parent; di; di = di->parent)
{
switch (di->abbrev->tag)
@ -1295,7 +1322,7 @@ static struct vector* dwarf2_get_di_children(dwarf2_debug_info_t* di)
if (di->abbrev->have_child)
return &di->children;
if (!dwarf2_find_attribute(di, DW_AT_specification, &spec)) break;
if (!(di = sparse_array_find(&di->unit_ctx->debug_info_table, spec.u.uvalue)))
if (!(di = dwarf2_jump_to_debug_info(&spec)))
FIXME("Should have found the debug info entry\n");
}
return NULL;