diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h index 34f51c28608..2a277a14751 100644 --- a/dlls/dbghelp/dbghelp_private.h +++ b/dlls/dbghelp/dbghelp_private.h @@ -268,6 +268,18 @@ struct addr_range DWORD64 high; /* absolute address of first byte after the range */ }; +/* tests whether ar2 is inside ar1 */ +static inline BOOL addr_range_inside(const struct addr_range* ar1, const struct addr_range* ar2) +{ + return ar1->low <= ar2->low && ar2->high <= ar1->high; +} + +/* tests whether ar1 and ar2 are disjoint */ +static inline BOOL addr_range_disjoint(const struct addr_range* ar1, const struct addr_range* ar2) +{ + return ar1->high <= ar2->low || ar2->high <= ar1->low; +} + /* a symt_inlinesite* can be casted to a symt_function* to access all function bits */ struct symt_inlinesite { @@ -841,6 +853,9 @@ extern struct symt_hierarchy_point* enum SymTagEnum point, const struct location* loc, const char* name) DECLSPEC_HIDDEN; +extern BOOL symt_add_inlinesite_range(struct module* module, + struct symt_inlinesite* inlined, + ULONG_PTR low, ULONG_PTR high) DECLSPEC_HIDDEN; extern struct symt_thunk* symt_new_thunk(struct module* module, struct symt_compiland* parent, diff --git a/dlls/dbghelp/dwarf.c b/dlls/dbghelp/dwarf.c index a01b72c4fc8..1ea8d2df773 100644 --- a/dlls/dbghelp/dwarf.c +++ b/dlls/dbghelp/dwarf.c @@ -1272,6 +1272,66 @@ static BOOL dwarf2_read_range(dwarf2_parse_context_t* ctx, const dwarf2_debug_in } } +static BOOL dwarf2_feed_inlined_ranges(dwarf2_parse_context_t* ctx, const dwarf2_debug_info_t* di, + struct symt_inlinesite* inlined) +{ + struct attribute range; + + if (dwarf2_find_attribute(di, DW_AT_ranges, &range)) + { + dwarf2_traverse_context_t traverse; + + traverse.data = ctx->module_ctx->sections[section_ranges].address + range.u.uvalue; + traverse.end_data = ctx->module_ctx->sections[section_ranges].address + + ctx->module_ctx->sections[section_ranges].size; + + while (traverse.data + 2 * ctx->head.word_size < traverse.end_data) + { + ULONG_PTR low = dwarf2_parse_addr_head(&traverse, &ctx->head); + ULONG_PTR high = dwarf2_parse_addr_head(&traverse, &ctx->head); + if (low == 0 && high == 0) break; + if (low == (ctx->head.word_size == 8 ? (~(DWORD64)0u) : (DWORD64)(~0u))) + FIXME("unsupported yet (base address selection)\n"); + /* range values are relative to start of compilation unit */ + symt_add_inlinesite_range(ctx->module_ctx->module, inlined, + ctx->compiland->address + low, ctx->compiland->address + high); + } + + return TRUE; + } + else + { + struct attribute low_pc; + struct attribute high_pc; + + if (!dwarf2_find_attribute(di, DW_AT_low_pc, &low_pc) || + !dwarf2_find_attribute(di, DW_AT_high_pc, &high_pc)) + return FALSE; + if (ctx->head.version >= 4) + switch (high_pc.form) + { + case DW_FORM_addr: + break; + case DW_FORM_data1: + case DW_FORM_data2: + case DW_FORM_data4: + case DW_FORM_data8: + case DW_FORM_sdata: + case DW_FORM_udata: + /* From dwarf4 on, when FORM's class is constant, high_pc is an offset from low_pc */ + high_pc.u.uvalue += low_pc.u.uvalue; + break; + default: + FIXME("Unsupported class for high_pc\n"); + break; + } + symt_add_inlinesite_range(ctx->module_ctx->module, inlined, + ctx->module_ctx->load_offset + low_pc.u.uvalue, + ctx->module_ctx->load_offset + high_pc.u.uvalue); + return TRUE; + } +} + /****************************************************************** * dwarf2_read_one_debug_info * @@ -2038,6 +2098,9 @@ static void dwarf2_parse_inlined_subroutine(dwarf2_subprogram_t* subpgm, subpgm->current_func = (struct symt_function*)inlined; subpgm->current_block = NULL; + if (!dwarf2_feed_inlined_ranges(subpgm->ctx, di, inlined)) + WARN("cannot read ranges\n"); + children = dwarf2_get_di_children(di); if (children) for (i = 0; i < vector_length(children); i++) { diff --git a/dlls/dbghelp/symbol.c b/dlls/dbghelp/symbol.c index aebe5fee098..9b7c5f3078e 100644 --- a/dlls/dbghelp/symbol.c +++ b/dlls/dbghelp/symbol.c @@ -576,6 +576,42 @@ struct symt_hierarchy_point* symt_add_function_point(struct module* module, return sym; } +/* low and high are absolute addresses */ +BOOL symt_add_inlinesite_range(struct module* module, + struct symt_inlinesite* inlined, + ULONG_PTR low, ULONG_PTR high) +{ + struct addr_range* p; + + p = vector_add(&inlined->vranges, &module->pool); + p->low = low; + p->high = high; + if (TRUE) + { + int i; + + /* see dbghelp_private.h for the assumptions */ + for (i = 0; i < inlined->vranges.num_elts - 1; i++) + { + if (!addr_range_disjoint((struct addr_range*)vector_at(&inlined->vranges, i), p)) + { + FIXME("Added addr_range isn't disjoint from siblings\n"); + } + } + for ( ; inlined->func.symt.tag != SymTagFunction; inlined = (struct symt_inlinesite*)symt_get_upper_inlined(inlined)) + { + for (i = 0; i < inlined->vranges.num_elts; i++) + { + struct addr_range* ar = (struct addr_range*)vector_at(&inlined->vranges, i); + if (!addr_range_disjoint(ar, p) && !addr_range_inside(ar, p)) + FIXME("Added addr_range not compatible with parent\n"); + } + } + } + + return TRUE; +} + struct symt_thunk* symt_new_thunk(struct module* module, struct symt_compiland* compiland, const char* name, THUNK_ORDINAL ord,