From: Eric Pouech Subject: [PATCH 10/12] dbghelp/dwarf! Added a new helper to jump into another debug_info Message-Id: <163178344080.542088.1477461891576729382.stgit@euterpe> Date: Thu, 16 Sep 2021 11:10:41 +0200 In-Reply-To: <163178326421.542088.17939125251680595504.stgit@euterpe> References: <163178326421.542088.17939125251680595504.stgit@euterpe> 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 --- dlls/dbghelp/dwarf.c | 77 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 52 insertions(+), 25 deletions(-) diff --git a/dlls/dbghelp/dwarf.c b/dlls/dbghelp/dwarf.c index bf4999ab0bb..c0f4afcb606 100644 --- a/dlls/dbghelp/dwarf.c +++ b/dlls/dbghelp/dwarf.c @@ -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;