The following series implements the stack walking and symbol functions for inlined frames for dwarf.
v3: - reorder to avoid dead code - remaimaing of the inlined frames support
---
Eric Pouech (7): dbghelp: introduce symt_inlinesite (SymTagInlineSite) to support inline sites dbghelp/dwarf: add current block as a field in dwarf2_subprogram_t dbghelp/dwarf: generate proper inline function dbghelp/dwarf: store each subrange for an inlined function dbghelp: implement StackWalkEx for inlined frames dbghelp: implement SymFromInlineContext when frame is inlined dbghelp: implement the SymSetScopeFromInlineContex() for inlined frame
dlls/dbghelp/dbghelp.c | 12 ++ dlls/dbghelp/dbghelp_private.h | 88 +++++++++++++- dlls/dbghelp/dwarf.c | 185 ++++++++++++++++++++-------- dlls/dbghelp/msc.c | 4 +- dlls/dbghelp/stack.c | 38 ++++-- dlls/dbghelp/symbol.c | 213 +++++++++++++++++++++++++++++---- dlls/dbghelp/type.c | 16 +++ 7 files changed, 466 insertions(+), 90 deletions(-)
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/dbghelp_private.h | 51 ++++++++++++++++++++++++++++++++++++++-- dlls/dbghelp/dwarf.c | 2 +- dlls/dbghelp/msc.c | 4 ++- dlls/dbghelp/symbol.c | 16 +++++-------- dlls/dbghelp/type.c | 16 +++++++++++++ 5 files changed, 75 insertions(+), 14 deletions(-)
diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h index 7ab7d1b7fc3..7dfb7a7c6dd 100644 --- a/dlls/dbghelp/dbghelp_private.h +++ b/dlls/dbghelp/dbghelp_private.h @@ -216,16 +216,63 @@ struct symt_data } u; };
+/* We must take into account that most debug formats (dwarf and pdb) report for + * code (esp. inlined functions) inside functions the following way: + * - block + * + is represented by a contiguous area of memory, + * or at least have lo/hi addresses to encompass it's contents + * + but most importantly, block A's lo/hi range is always embedded within + * its parent (block or function) + * - inline site: + * + is most of the times represented by a set of ranges (instead of a + * contiguous block) + * + native dbghelp only exports the start address, not its size + * + the set of ranges isn't always embedded in enclosing block (if any) + * + the set of ranges is always embedded in top function + * - (top) function + * + is described as a contiguous block of memory + * + * On top of the items above (taken as assumptions), we also assume that: + * - a range in inline site A, is disjoint from all the other ranges in + * inline site A + * - a range in inline site A, is either disjoint or embedded into any of + * the ranges of inline sites parent of A + * + * Therefore, we also store all inline sites inside a function: + * - available as a linked list to simplify the walk among them + * - this linked list shall preserve the weak order of the lexical-parent + * relationship (eg for any inline site A, which has inline site B + * as lexical parent, then A is present before B in the linked list) + * - hence (from the assumptions above), when looking up which inline site + * contains a given address, the first range containing that address found + * while walking the list of inline sites is the right one. + */ + struct symt_function { - struct symt symt; + struct symt symt; /* SymTagFunction (or SymTagInlineSite when embedded in symt_inlinesite) */ struct hash_table_elt hash_elt; /* if global symbol */ ULONG_PTR address; struct symt* container; /* compiland */ struct symt* type; /* points to function_signature */ ULONG_PTR size; struct vector vlines; - struct vector vchildren; /* locals, params, blocks, start/end, labels */ + struct vector vchildren; /* locals, params, blocks, start/end, labels, inline sites */ + struct symt_inlinesite* next_inlinesite;/* linked list of inline sites in this function */ +}; + +/* FIXME: this could be optimized later on by using relative offsets and smaller integral sizes */ +struct addr_range +{ + DWORD64 low; /* absolute address of first byte of the range */ + DWORD64 high; /* absolute address of first byte after the range */ +}; + +/* a symt_inlinesite* can be casted to a symt_function* to access all function bits */ +struct symt_inlinesite +{ + struct symt_function func; + struct vector vranges; /* of addr_range: where the inline site is actually defined */ };
struct symt_hierarchy_point diff --git a/dlls/dbghelp/dwarf.c b/dlls/dbghelp/dwarf.c index c503be4dcc1..86650e991a8 100644 --- a/dlls/dbghelp/dwarf.c +++ b/dlls/dbghelp/dwarf.c @@ -2438,7 +2438,7 @@ static void dwarf2_set_line_number(struct module* module, ULONG_PTR address, TRACE("%s %lx %s %u\n", debugstr_w(module->modulename), address, debugstr_a(source_get(module, *psrc)), line); symt = symt_find_nearest(module, address); - if (symt && symt_check_tag(&symt->symt, SymTagFunction)) + if (symt_check_tag(&symt->symt, SymTagFunction)) { func = (struct symt_function*)symt; symt_add_func_line(module, func, *psrc, line, address - func->address); diff --git a/dlls/dbghelp/msc.c b/dlls/dbghelp/msc.c index 2468051acc7..c557cb24636 100644 --- a/dlls/dbghelp/msc.c +++ b/dlls/dbghelp/msc.c @@ -1446,7 +1446,7 @@ static void codeview_snarf_linetab(const struct msc_debug_info* msc_dbg, const B { func = (struct symt_function*)symt_find_nearest(msc_dbg->module, addr); /* FIXME: at least labels support line numbers */ - if (!func || func->symt.tag != SymTagFunction) + if (!symt_check_tag(&func->symt, SymTagFunction) && !symt_check_tag(&func->symt, SymTagInlineSite)) { WARN("--not a func at %04x:%08x %lx tag=%d\n", ltb->seg, ltb->offsets[k], addr, func ? func->symt.tag : -1); @@ -1509,7 +1509,7 @@ static void codeview_snarf_linetab2(const struct msc_debug_info* msc_dbg, const source = source_new(msc_dbg->module, NULL, strimage + fd->offset); func = (struct symt_function*)symt_find_nearest(msc_dbg->module, addr); /* FIXME: at least labels support line numbers */ - if (!func || func->symt.tag != SymTagFunction) + if (!symt_check_tag(&func->symt, SymTagFunction) && !symt_check_tag(&func->symt, SymTagInlineSite)) { WARN("--not a func at %04x:%08x %lx tag=%d\n", lines_blk->seg, lines_blk->start, addr, func ? func->symt.tag : -1); diff --git a/dlls/dbghelp/symbol.c b/dlls/dbghelp/symbol.c index 0f53bcd023c..95cacc057a7 100644 --- a/dlls/dbghelp/symbol.c +++ b/dlls/dbghelp/symbol.c @@ -366,7 +366,7 @@ void symt_add_func_line(struct module* module, struct symt_function* func, func, func->hash_elt.name, offset, source_get(module, source_idx), line_num);
- assert(func->symt.tag == SymTagFunction); + assert(func->symt.tag == SymTagFunction || func->symt.tag == SymTagInlineSite);
for (i=vector_length(&func->vlines)-1; i>=0; i--) { @@ -424,8 +424,7 @@ struct symt_data* symt_add_func_local(struct module* module, debugstr_w(module->modulename), func->hash_elt.name, name, type);
- assert(func); - assert(func->symt.tag == SymTagFunction); + assert(symt_check_tag(&func->symt, SymTagFunction) || symt_check_tag(&func->symt, SymTagInlineSite)); assert(dt == DataIsParam || dt == DataIsLocal);
locsym = pool_alloc(&module->pool, sizeof(*locsym)); @@ -462,8 +461,7 @@ struct symt_data* symt_add_func_constant(struct module* module, debugstr_w(module->modulename), func->hash_elt.name, name, type);
- assert(func); - assert(func->symt.tag == SymTagFunction); + assert(symt_check_tag(&func->symt, SymTagFunction) || symt_check_tag(&func->symt, SymTagInlineSite));
locsym = pool_alloc(&module->pool, sizeof(*locsym)); locsym->symt.tag = SymTagData; @@ -489,8 +487,7 @@ struct symt_block* symt_open_func_block(struct module* module, struct symt_block* block; struct symt** p;
- assert(func); - assert(func->symt.tag == SymTagFunction); + assert(symt_check_tag(&func->symt, SymTagFunction) || symt_check_tag(&func->symt, SymTagInlineSite));
assert(!parent_block || parent_block->symt.tag == SymTagBlock); block = pool_alloc(&module->pool, sizeof(*block)); @@ -512,8 +509,7 @@ struct symt_block* symt_close_func_block(struct module* module, const struct symt_function* func, struct symt_block* block, unsigned pc) { - assert(func); - assert(func->symt.tag == SymTagFunction); + assert(symt_check_tag(&func->symt, SymTagFunction) || symt_check_tag(&func->symt, SymTagInlineSite));
if (pc) block->size = func->address + pc - block->address; return (block->container->tag == SymTagBlock) ? @@ -781,6 +777,7 @@ static void symt_fill_sym_info(struct module_pair* pair, } break; case SymTagFunction: + case SymTagInlineSite: symt_get_address(sym, &sym_info->Address); break; case SymTagThunk: @@ -1061,6 +1058,7 @@ static BOOL symt_enum_locals_helper(struct module_pair* pair, case SymTagFuncDebugStart: case SymTagFuncDebugEnd: case SymTagCustom: + case SymTagInlineSite: break; default: FIXME("Unknown type: %u (%x)\n", lsym->tag, lsym->tag); diff --git a/dlls/dbghelp/type.c b/dlls/dbghelp/type.c index 80f8eca768e..3a7ebfb6a0a 100644 --- a/dlls/dbghelp/type.c +++ b/dlls/dbghelp/type.c @@ -95,6 +95,7 @@ const char* symt_get_name(const struct symt* sym) /* lexical tree */ case SymTagData: return ((const struct symt_data*)sym)->hash_elt.name; case SymTagFunction: return ((const struct symt_function*)sym)->hash_elt.name; + case SymTagInlineSite: return ((const struct symt_inlinesite*)sym)->func.hash_elt.name; case SymTagPublicSymbol: return ((const struct symt_public*)sym)->hash_elt.name; case SymTagBaseType: return ((const struct symt_basic*)sym)->hash_elt.name; case SymTagLabel: return ((const struct symt_hierarchy_point*)sym)->hash_elt.name; @@ -153,6 +154,9 @@ BOOL symt_get_address(const struct symt* type, ULONG64* addr) case SymTagFunction: *addr = ((const struct symt_function*)type)->address; break; + case SymTagInlineSite: + *addr = ((const struct symt_inlinesite*)type)->func.address; + break; case SymTagPublicSymbol: *addr = ((const struct symt_public*)type)->address; break; @@ -572,6 +576,7 @@ BOOL symt_get_info(struct module* module, const struct symt* type, case SymTagEnum: v = &((const struct symt_enum*)type)->vchildren; break; case SymTagFunctionType: v = &((const struct symt_function_signature*)type)->vchildren; break; case SymTagFunction: v = &((const struct symt_function*)type)->vchildren; break; + case SymTagInlineSite: v = &((const struct symt_inlinesite*)type)->func.vchildren; break; case SymTagBlock: v = &((const struct symt_block*)type)->vchildren; break; case SymTagPointerType: case SymTagArrayType: @@ -644,6 +649,9 @@ BOOL symt_get_info(struct module* module, const struct symt* type, case SymTagFunction: X(DWORD) = vector_length(&((const struct symt_function*)type)->vchildren); break; + case SymTagInlineSite: + X(DWORD) = vector_length(&((const struct symt_inlinesite*)type)->func.vchildren); + break; case SymTagBlock: X(DWORD) = vector_length(&((const struct symt_block*)type)->vchildren); break; @@ -745,6 +753,7 @@ BOOL symt_get_info(struct module* module, const struct symt* type, case SymTagCompiland: case SymTagFunctionType: case SymTagFunctionArgType: + case SymTagInlineSite: /* native doesn't expose it, perhaps because of non-contiguous range */ case SymTagLabel: case SymTagFuncDebugStart: case SymTagFuncDebugEnd: @@ -767,6 +776,9 @@ BOOL symt_get_info(struct module* module, const struct symt* type, case SymTagFunction: X(DWORD) = symt_ptr2index(module, ((const struct symt_function*)type)->container); break; + case SymTagInlineSite: + X(DWORD) = symt_ptr2index(module, ((const struct symt_inlinesite*)type)->func.container); + break; case SymTagThunk: X(DWORD) = symt_ptr2index(module, ((const struct symt_thunk*)type)->container); break; @@ -846,6 +858,7 @@ BOOL symt_get_info(struct module* module, const struct symt* type, case SymTagFuncDebugStart: case SymTagFuncDebugEnd: case SymTagLabel: + case SymTagInlineSite: case SymTagCustom: return FALSE; } @@ -899,6 +912,9 @@ BOOL symt_get_info(struct module* module, const struct symt* type, case SymTagFunction: X(DWORD) = symt_ptr2index(module, ((const struct symt_function*)type)->type); break; + case SymTagInlineSite: + X(DWORD) = symt_ptr2index(module, ((const struct symt_inlinesite*)type)->func.type); + break; case SymTagEnum: X(DWORD) = symt_ptr2index(module, ((const struct symt_enum*)type)->base_type); break;
(instead of passing it as a parameter in various subprogram related functions)
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/dwarf.c | 59 +++++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 29 deletions(-)
diff --git a/dlls/dbghelp/dwarf.c b/dlls/dbghelp/dwarf.c index 86650e991a8..ef86e6bffe0 100644 --- a/dlls/dbghelp/dwarf.c +++ b/dlls/dbghelp/dwarf.c @@ -1812,6 +1812,7 @@ typedef struct dwarf2_subprogram_s { dwarf2_parse_context_t* ctx; struct symt_function* func; + struct symt_block* current_block; BOOL non_computed_variable; struct location frame; } dwarf2_subprogram_t; @@ -1822,7 +1823,6 @@ typedef struct dwarf2_subprogram_s * Parses any variable (parameter, local/global variable) */ static void dwarf2_parse_variable(dwarf2_subprogram_t* subpgm, - struct symt_block* block, dwarf2_debug_info_t* di) { struct symt* param_type; @@ -1832,7 +1832,7 @@ static void dwarf2_parse_variable(dwarf2_subprogram_t* subpgm,
TRACE("%s\n", dwarf2_debug_di(di));
- is_pmt = !block && di->abbrev->tag == DW_TAG_formal_parameter; + is_pmt = !subpgm->current_block && di->abbrev->tag == DW_TAG_formal_parameter; param_type = dwarf2_lookup_type(di);
if (!dwarf2_find_attribute(di, DW_AT_name, &name)) { @@ -1873,7 +1873,7 @@ static void dwarf2_parse_variable(dwarf2_subprogram_t* subpgm, if (subpgm->func) symt_add_func_local(subpgm->ctx->module_ctx->module, subpgm->func, is_pmt ? DataIsParam : DataIsLocal, - &loc, block, param_type, name.u.string); + &loc, subpgm->current_block, param_type, name.u.string); break; } } @@ -1939,7 +1939,7 @@ static void dwarf2_parse_variable(dwarf2_subprogram_t* subpgm, { if (is_pmt) FIXME("Unsupported constant (parameter) %s in function '%s'\n", debugstr_a(name.u.string), subpgm->func->hash_elt.name); di->symt = &symt_add_func_constant(subpgm->ctx->module_ctx->module, - subpgm->func, block, + subpgm->func, subpgm->current_block, param_type, name.u.string, &v)->symt; } else @@ -1955,7 +1955,7 @@ static void dwarf2_parse_variable(dwarf2_subprogram_t* subpgm, loc.reg = loc_err_no_location; symt_add_func_local(subpgm->ctx->module_ctx->module, subpgm->func, is_pmt ? DataIsParam : DataIsLocal, - &loc, block, param_type, name.u.string); + &loc, subpgm->current_block, param_type, name.u.string); } else { @@ -1994,16 +1994,13 @@ static void dwarf2_parse_subprogram_label(dwarf2_subprogram_t* subpgm, }
static void dwarf2_parse_subprogram_block(dwarf2_subprogram_t* subpgm, - struct symt_block* parent_block, - dwarf2_debug_info_t* di); + dwarf2_debug_info_t* di);
static struct symt* dwarf2_parse_subroutine_type(dwarf2_debug_info_t* di);
static void dwarf2_parse_inlined_subroutine(dwarf2_subprogram_t* subpgm, - struct symt_block* parent_block, dwarf2_debug_info_t* di) { - struct symt_block* block; ULONG_PTR low_pc, high_pc; struct vector* children; dwarf2_debug_info_t*child; @@ -2017,9 +2014,9 @@ static void dwarf2_parse_inlined_subroutine(dwarf2_subprogram_t* subpgm, return; }
- block = symt_open_func_block(subpgm->ctx->module_ctx->module, subpgm->func, parent_block, - subpgm->ctx->module_ctx->load_offset + low_pc - subpgm->func->address, - high_pc - low_pc); + subpgm->current_block = symt_open_func_block(subpgm->ctx->module_ctx->module, subpgm->func, subpgm->current_block, + subpgm->ctx->module_ctx->load_offset + low_pc - subpgm->func->address, + high_pc - low_pc);
children = dwarf2_get_di_children(di); if (children) for (i = 0; i < vector_length(children); i++) @@ -2030,13 +2027,13 @@ static void dwarf2_parse_inlined_subroutine(dwarf2_subprogram_t* subpgm, { case DW_TAG_formal_parameter: case DW_TAG_variable: - dwarf2_parse_variable(subpgm, block, child); + dwarf2_parse_variable(subpgm, child); break; case DW_TAG_lexical_block: - dwarf2_parse_subprogram_block(subpgm, block, child); + dwarf2_parse_subprogram_block(subpgm, child); break; case DW_TAG_inlined_subroutine: - dwarf2_parse_inlined_subroutine(subpgm, block, child); + dwarf2_parse_inlined_subroutine(subpgm, child); break; case DW_TAG_label: dwarf2_parse_subprogram_label(subpgm, child); @@ -2049,14 +2046,14 @@ static void dwarf2_parse_inlined_subroutine(dwarf2_subprogram_t* subpgm, child->abbrev->tag, dwarf2_debug_di(di)); } } - symt_close_func_block(subpgm->ctx->module_ctx->module, subpgm->func, block, 0); + symt_close_func_block(subpgm->ctx->module_ctx->module, subpgm->func, subpgm->current_block, 0); + subpgm->current_block = symt_check_tag(subpgm->current_block->container, SymTagBlock) ? + (struct symt_block*)subpgm->current_block->container : NULL; }
static void dwarf2_parse_subprogram_block(dwarf2_subprogram_t* subpgm, - struct symt_block* parent_block, dwarf2_debug_info_t* di) { - struct symt_block* block; ULONG_PTR low_pc, high_pc; struct vector* children; dwarf2_debug_info_t*child; @@ -2070,9 +2067,9 @@ static void dwarf2_parse_subprogram_block(dwarf2_subprogram_t* subpgm, return; }
- block = symt_open_func_block(subpgm->ctx->module_ctx->module, subpgm->func, parent_block, - subpgm->ctx->module_ctx->load_offset + low_pc - subpgm->func->address, - high_pc - low_pc); + subpgm->current_block = symt_open_func_block(subpgm->ctx->module_ctx->module, subpgm->func, subpgm->current_block, + subpgm->ctx->module_ctx->load_offset + low_pc - subpgm->func->address, + high_pc - low_pc);
children = dwarf2_get_di_children(di); if (children) for (i = 0; i < vector_length(children); i++) @@ -2082,10 +2079,10 @@ static void dwarf2_parse_subprogram_block(dwarf2_subprogram_t* subpgm, switch (child->abbrev->tag) { case DW_TAG_inlined_subroutine: - dwarf2_parse_inlined_subroutine(subpgm, block, child); + dwarf2_parse_inlined_subroutine(subpgm, child); break; case DW_TAG_variable: - dwarf2_parse_variable(subpgm, block, child); + dwarf2_parse_variable(subpgm, child); break; case DW_TAG_pointer_type: dwarf2_parse_pointer_type(child); @@ -2097,7 +2094,7 @@ static void dwarf2_parse_subprogram_block(dwarf2_subprogram_t* subpgm, dwarf2_parse_const_type(child); break; case DW_TAG_lexical_block: - dwarf2_parse_subprogram_block(subpgm, block, child); + dwarf2_parse_subprogram_block(subpgm, child); break; case DW_TAG_subprogram: /* FIXME: likely a declaration (to be checked) @@ -2131,7 +2128,9 @@ static void dwarf2_parse_subprogram_block(dwarf2_subprogram_t* subpgm, } }
- symt_close_func_block(subpgm->ctx->module_ctx->module, subpgm->func, block, 0); + symt_close_func_block(subpgm->ctx->module_ctx->module, subpgm->func, subpgm->current_block, 0); + subpgm->current_block = symt_check_tag(subpgm->current_block->container, SymTagBlock) ? + (struct symt_block*)subpgm->current_block->container : NULL; }
static struct symt* dwarf2_parse_subprogram(dwarf2_debug_info_t* di) @@ -2203,6 +2202,7 @@ static struct symt* dwarf2_parse_subprogram(dwarf2_debug_info_t* di) subpgm.frame.offset = 0; } subpgm.non_computed_variable = FALSE; + subpgm.current_block = NULL;
children = dwarf2_get_di_children(di); if (children) for (i = 0; i < vector_length(children); i++) @@ -2213,13 +2213,13 @@ static struct symt* dwarf2_parse_subprogram(dwarf2_debug_info_t* di) { case DW_TAG_variable: case DW_TAG_formal_parameter: - dwarf2_parse_variable(&subpgm, NULL, child); + dwarf2_parse_variable(&subpgm, child); break; case DW_TAG_lexical_block: - dwarf2_parse_subprogram_block(&subpgm, NULL, child); + dwarf2_parse_subprogram_block(&subpgm, child); break; case DW_TAG_inlined_subroutine: - dwarf2_parse_inlined_subroutine(&subpgm, NULL, child); + dwarf2_parse_inlined_subroutine(&subpgm, child); break; case DW_TAG_pointer_type: dwarf2_parse_pointer_type(child); @@ -2396,10 +2396,11 @@ static void dwarf2_load_one_entry(dwarf2_debug_info_t* di)
subpgm.ctx = di->unit_ctx; subpgm.func = NULL; + subpgm.current_block = NULL; subpgm.frame.kind = loc_absolute; subpgm.frame.offset = 0; subpgm.frame.reg = Wine_DW_no_register; - dwarf2_parse_variable(&subpgm, NULL, di); + dwarf2_parse_variable(&subpgm, di); } break; case DW_TAG_namespace:
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/dbghelp_private.h | 16 +++++++ dlls/dbghelp/dwarf.c | 81 +++++++++++++++++++++++------------- dlls/dbghelp/symbol.c | 90 ++++++++++++++++++++++++++++++++-------- 3 files changed, 141 insertions(+), 46 deletions(-)
diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h index 7dfb7a7c6dd..34f51c28608 100644 --- a/dlls/dbghelp/dbghelp_private.h +++ b/dlls/dbghelp/dbghelp_private.h @@ -805,6 +805,13 @@ extern struct symt_function* const char* name, ULONG_PTR addr, ULONG_PTR size, struct symt* type) DECLSPEC_HIDDEN; +extern struct symt_inlinesite* + symt_new_inlinesite(struct module* module, + struct symt_function* func, + struct symt* parent, + const char* name, + ULONG_PTR addr, + struct symt* type) DECLSPEC_HIDDEN; extern void symt_add_func_line(struct module* module, struct symt_function* func, unsigned source_idx, int line_num, @@ -894,6 +901,15 @@ extern struct symt_pointer* extern struct symt_typedef* symt_new_typedef(struct module* module, struct symt* ref, const char* name) DECLSPEC_HIDDEN; +extern struct symt* + symt_get_upper_inlined(struct symt_inlinesite* inlined) DECLSPEC_HIDDEN; +static inline struct symt_function* + symt_get_function_from_inlined(struct symt_inlinesite* inlined) +{ + while (!symt_check_tag(&inlined->func.symt, SymTagFunction)) + inlined = (struct symt_inlinesite*)symt_get_upper_inlined(inlined); + return &inlined->func; +}
/* Inline context encoding (different from what native does): * bits 31:30: 3 ignore (includes INLINE_FRAME_CONTEXT_IGNORE=0xFFFFFFFF) diff --git a/dlls/dbghelp/dwarf.c b/dlls/dbghelp/dwarf.c index ef86e6bffe0..a01b72c4fc8 100644 --- a/dlls/dbghelp/dwarf.c +++ b/dlls/dbghelp/dwarf.c @@ -1811,7 +1811,8 @@ static struct symt* dwarf2_parse_enumeration_type(dwarf2_debug_info_t* di) typedef struct dwarf2_subprogram_s { dwarf2_parse_context_t* ctx; - struct symt_function* func; + struct symt_function* top_func; + struct symt_function* current_func; /* either symt_function* or symt_inlinesite* */ struct symt_block* current_block; BOOL non_computed_variable; struct location frame; @@ -1870,8 +1871,8 @@ static void dwarf2_parse_variable(dwarf2_subprogram_t* subpgm, /* either a pmt/variable relative to frame pointer or * pmt/variable in a register */ - if (subpgm->func) - symt_add_func_local(subpgm->ctx->module_ctx->module, subpgm->func, + if (subpgm->current_func) + symt_add_func_local(subpgm->ctx->module_ctx->module, subpgm->current_func, is_pmt ? DataIsParam : DataIsLocal, &loc, subpgm->current_block, param_type, name.u.string); break; @@ -1935,11 +1936,12 @@ static void dwarf2_parse_variable(dwarf2_subprogram_t* subpgm, debugstr_a(name.u.string), value.form); V_VT(&v) = VT_EMPTY; } - if (subpgm->func) + if (subpgm->current_func) { - if (is_pmt) FIXME("Unsupported constant (parameter) %s in function '%s'\n", debugstr_a(name.u.string), subpgm->func->hash_elt.name); + if (is_pmt) WARN("Constant parameter %s reported as local variable in function '%s'\n", + debugstr_a(name.u.string), subpgm->current_func->hash_elt.name); di->symt = &symt_add_func_constant(subpgm->ctx->module_ctx->module, - subpgm->func, subpgm->current_block, + subpgm->current_func, subpgm->current_block, param_type, name.u.string, &v)->symt; } else @@ -1948,12 +1950,12 @@ static void dwarf2_parse_variable(dwarf2_subprogram_t* subpgm, } else { - if (subpgm->func) + if (subpgm->current_func) { /* local variable has been optimized away... report anyway */ loc.kind = loc_error; loc.reg = loc_err_no_location; - symt_add_func_local(subpgm->ctx->module_ctx->module, subpgm->func, + symt_add_func_local(subpgm->ctx->module_ctx->module, subpgm->current_func, is_pmt ? DataIsParam : DataIsLocal, &loc, subpgm->current_block, param_type, name.u.string); } @@ -1966,9 +1968,9 @@ static void dwarf2_parse_variable(dwarf2_subprogram_t* subpgm, WARN("dropping global variable %s which has been optimized away\n", debugstr_a(name.u.string)); } } - if (is_pmt && subpgm->func && symt_check_tag(subpgm->func->type, SymTagFunctionType)) + if (is_pmt && subpgm->current_func && symt_check_tag(subpgm->current_func->type, SymTagFunctionType)) symt_add_function_signature_parameter(subpgm->ctx->module_ctx->module, - (struct symt_function_signature*)subpgm->func->type, + (struct symt_function_signature*)subpgm->current_func->type, param_type);
if (dwarf2_get_di_children(di)) FIXME("Unsupported children\n"); @@ -1988,8 +1990,8 @@ static void dwarf2_parse_subprogram_label(dwarf2_subprogram_t* subpgm, name.u.string = NULL;
loc.kind = loc_absolute; - loc.offset = subpgm->ctx->module_ctx->load_offset + low_pc.u.uvalue - subpgm->func->address; - symt_add_function_point(subpgm->ctx->module_ctx->module, subpgm->func, SymTagLabel, + loc.offset = subpgm->ctx->module_ctx->load_offset + low_pc.u.uvalue - subpgm->top_func->address; + symt_add_function_point(subpgm->ctx->module_ctx->module, subpgm->top_func, SymTagLabel, &loc, name.u.string); }
@@ -2001,7 +2003,11 @@ static struct symt* dwarf2_parse_subroutine_type(dwarf2_debug_info_t* di); static void dwarf2_parse_inlined_subroutine(dwarf2_subprogram_t* subpgm, dwarf2_debug_info_t* di) { + struct attribute name; ULONG_PTR low_pc, high_pc; + struct symt* ret_type; + struct symt_function_signature* sig_type; + struct symt_inlinesite* inlined; struct vector* children; dwarf2_debug_info_t*child; unsigned int i; @@ -2013,10 +2019,24 @@ static void dwarf2_parse_inlined_subroutine(dwarf2_subprogram_t* subpgm, WARN("cannot read range\n"); return; } + if (!dwarf2_find_attribute(di, DW_AT_name, &name)) + { + FIXME("No name for function... dropping function\n"); + return; + } + ret_type = dwarf2_lookup_type(di);
- subpgm->current_block = symt_open_func_block(subpgm->ctx->module_ctx->module, subpgm->func, subpgm->current_block, - subpgm->ctx->module_ctx->load_offset + low_pc - subpgm->func->address, - high_pc - low_pc); + /* FIXME: assuming C source code */ + sig_type = symt_new_function_signature(subpgm->ctx->module_ctx->module, ret_type, CV_CALL_FAR_C); + + inlined = symt_new_inlinesite(subpgm->ctx->module_ctx->module, + subpgm->top_func, + subpgm->current_block ? &subpgm->current_block->symt : &subpgm->current_func->symt, + dwarf2_get_cpp_name(di, name.u.string), + subpgm->ctx->module_ctx->load_offset + low_pc, + &sig_type->symt); + subpgm->current_func = (struct symt_function*)inlined; + subpgm->current_block = NULL;
children = dwarf2_get_di_children(di); if (children) for (i = 0; i < vector_length(children); i++) @@ -2046,9 +2066,9 @@ static void dwarf2_parse_inlined_subroutine(dwarf2_subprogram_t* subpgm, child->abbrev->tag, dwarf2_debug_di(di)); } } - symt_close_func_block(subpgm->ctx->module_ctx->module, subpgm->func, subpgm->current_block, 0); - subpgm->current_block = symt_check_tag(subpgm->current_block->container, SymTagBlock) ? - (struct symt_block*)subpgm->current_block->container : NULL; + subpgm->current_block = symt_check_tag(subpgm->current_func->container, SymTagBlock) ? + (struct symt_block*)subpgm->current_func->container : NULL; + subpgm->current_func = (struct symt_function*)symt_get_upper_inlined((struct symt_inlinesite*)subpgm->current_func); }
static void dwarf2_parse_subprogram_block(dwarf2_subprogram_t* subpgm, @@ -2067,8 +2087,8 @@ static void dwarf2_parse_subprogram_block(dwarf2_subprogram_t* subpgm, return; }
- subpgm->current_block = symt_open_func_block(subpgm->ctx->module_ctx->module, subpgm->func, subpgm->current_block, - subpgm->ctx->module_ctx->load_offset + low_pc - subpgm->func->address, + subpgm->current_block = symt_open_func_block(subpgm->ctx->module_ctx->module, subpgm->current_func, subpgm->current_block, + subpgm->ctx->module_ctx->load_offset + low_pc - subpgm->current_func->address, high_pc - low_pc);
children = dwarf2_get_di_children(di); @@ -2128,7 +2148,7 @@ static void dwarf2_parse_subprogram_block(dwarf2_subprogram_t* subpgm, } }
- symt_close_func_block(subpgm->ctx->module_ctx->module, subpgm->func, subpgm->current_block, 0); + symt_close_func_block(subpgm->ctx->module_ctx->module, subpgm->current_func, subpgm->current_block, 0); subpgm->current_block = symt_check_tag(subpgm->current_block->container, SymTagBlock) ? (struct symt_block*)subpgm->current_block->container : NULL; } @@ -2187,11 +2207,12 @@ static struct symt* dwarf2_parse_subprogram(dwarf2_debug_info_t* di)
/* FIXME: assuming C source code */ sig_type = symt_new_function_signature(di->unit_ctx->module_ctx->module, ret_type, CV_CALL_FAR_C); - subpgm.func = symt_new_function(di->unit_ctx->module_ctx->module, di->unit_ctx->compiland, - dwarf2_get_cpp_name(di, name.u.string), - di->unit_ctx->module_ctx->load_offset + low_pc, high_pc - low_pc, - &sig_type->symt); - di->symt = &subpgm.func->symt; + subpgm.top_func = symt_new_function(di->unit_ctx->module_ctx->module, di->unit_ctx->compiland, + dwarf2_get_cpp_name(di, name.u.string), + di->unit_ctx->module_ctx->load_offset + low_pc, high_pc - low_pc, + &sig_type->symt); + subpgm.current_func = subpgm.top_func; + di->symt = &subpgm.top_func->symt; subpgm.ctx = di->unit_ctx; if (!dwarf2_compute_location_attr(di->unit_ctx, di, DW_AT_frame_base, &subpgm.frame, NULL)) @@ -2258,7 +2279,7 @@ static struct symt* dwarf2_parse_subprogram(dwarf2_debug_info_t* di)
if (subpgm.non_computed_variable || subpgm.frame.kind >= loc_user) { - symt_add_function_point(di->unit_ctx->module_ctx->module, subpgm.func, SymTagCustom, + symt_add_function_point(di->unit_ctx->module_ctx->module, subpgm.top_func, SymTagCustom, &subpgm.frame, NULL); }
@@ -2395,7 +2416,7 @@ static void dwarf2_load_one_entry(dwarf2_debug_info_t* di) dwarf2_subprogram_t subpgm;
subpgm.ctx = di->unit_ctx; - subpgm.func = NULL; + subpgm.top_func = subpgm.current_func = NULL; subpgm.current_block = NULL; subpgm.frame.kind = loc_absolute; subpgm.frame.offset = 0; @@ -2827,7 +2848,9 @@ static BOOL dwarf2_lookup_loclist(const struct module_format* modfmt, const dwar
static const dwarf2_cuhead_t* get_cuhead_from_func(const struct symt_function* func) { - if (func && symt_check_tag(func->container, SymTagCompiland)) + if (symt_check_tag(&func->symt, SymTagInlineSite)) + func = symt_get_function_from_inlined((struct symt_inlinesite*)func); + if (symt_check_tag(&func->symt, SymTagFunction) && symt_check_tag(func->container, SymTagCompiland)) { struct symt_compiland* c = (struct symt_compiland*)func->container; return (const dwarf2_cuhead_t*)c->user; diff --git a/dlls/dbghelp/symbol.c b/dlls/dbghelp/symbol.c index 95cacc057a7..aebe5fee098 100644 --- a/dlls/dbghelp/symbol.c +++ b/dlls/dbghelp/symbol.c @@ -318,35 +318,74 @@ struct symt_data* symt_new_global_variable(struct module* module, return sym; }
-struct symt_function* symt_new_function(struct module* module, - struct symt_compiland* compiland, +static void init_function_or_inlinesite(struct symt_function* sym, + struct module* module, + DWORD tag, + struct symt* container, const char* name, ULONG_PTR addr, ULONG_PTR size, struct symt* sig_type) { - struct symt_function* sym; - struct symt** p; + assert(!sig_type || sig_type->tag == SymTagFunctionType); + sym->symt.tag = tag; + sym->hash_elt.name = pool_strdup(&module->pool, name); + sym->container = container; + sym->address = addr; + sym->type = sig_type; + sym->size = size; + vector_init(&sym->vlines, sizeof(struct line_info), 64); + vector_init(&sym->vchildren, sizeof(struct symt*), 8); +} + +struct symt_function* symt_new_function(struct module* module, + struct symt_compiland* compiland, + const char* name, + ULONG_PTR addr, ULONG_PTR size, + struct symt* sig_type) +{ + struct symt_function* sym;
TRACE_(dbghelp_symt)("Adding global function %s:%s @%lx-%lx\n", debugstr_w(module->modulename), name, addr, addr + size - 1); - - assert(!sig_type || sig_type->tag == SymTagFunctionType); if ((sym = pool_alloc(&module->pool, sizeof(*sym)))) { - sym->symt.tag = SymTagFunction; - sym->hash_elt.name = pool_strdup(&module->pool, name); - sym->container = &compiland->symt; - sym->address = addr; - sym->type = sig_type; - sym->size = size; - vector_init(&sym->vlines, sizeof(struct line_info), 64); - vector_init(&sym->vchildren, sizeof(struct symt*), 8); + struct symt** p; + init_function_or_inlinesite(sym, module, SymTagFunction, &compiland->symt, name, addr, size, sig_type); + sym->next_inlinesite = NULL; /* first of list */ symt_add_module_ht(module, (struct symt_ht*)sym); - if (compiland) + p = vector_add(&compiland->vchildren, &module->pool); + *p = &sym->symt; + } + return sym; +} + +struct symt_inlinesite* symt_new_inlinesite(struct module* module, + struct symt_function* func, + struct symt* container, + const char* name, + ULONG_PTR addr, + struct symt* sig_type) +{ + struct symt_inlinesite* sym; + + TRACE_(dbghelp_symt)("Adding inline site %s @%lx\n", name, addr); + if ((sym = pool_alloc(&module->pool, sizeof(*sym)))) + { + struct symt** p; + assert(container); + init_function_or_inlinesite(&sym->func, module, SymTagInlineSite, container, name, addr, 0, sig_type); + vector_init(&sym->vranges, sizeof(struct addr_range), 2); /* FIXME: number of elts => to be set on input */ + /* chain inline sites */ + sym->func.next_inlinesite = func->next_inlinesite; + func->next_inlinesite = sym; + if (container->tag == SymTagFunction || container->tag == SymTagInlineSite) + p = vector_add(&((struct symt_function*)container)->vchildren, &module->pool); + else { - p = vector_add(&compiland->vchildren, &module->pool); - *p = &sym->symt; + assert(container->tag == SymTagBlock); + p = vector_add(&((struct symt_block*)container)->vchildren, &module->pool); } + *p = &sym->func.symt; } return sym; } @@ -1138,6 +1177,23 @@ void copy_symbolW(SYMBOL_INFOW* siw, const SYMBOL_INFO* si) MultiByteToWideChar(CP_ACP, 0, si->Name, -1, siw->Name, siw->MaxNameLen); }
+/* from an inline function, get either the enclosing inlined function, or the top function when no inlined */ +struct symt* symt_get_upper_inlined(struct symt_inlinesite* inlined) +{ + struct symt* symt = &inlined->func.symt; + + do + { + assert(symt); + if (symt->tag == SymTagBlock) + symt = ((struct symt_block*)symt)->container; + else + symt = ((struct symt_function*)symt)->container; + } while (symt->tag == SymTagBlock); + assert(symt->tag == SymTagFunction || symt->tag == SymTagInlineSite); + return symt; +} + /****************************************************************** * sym_enum *
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/dbghelp_private.h | 15 ++++++++++ dlls/dbghelp/dwarf.c | 63 ++++++++++++++++++++++++++++++++++++++++ dlls/dbghelp/symbol.c | 36 +++++++++++++++++++++++ 3 files changed, 114 insertions(+)
diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h index 34f51c28608..c5d637e2f8c 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 <= ar2->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,
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/dbghelp_private.h | 3 +++ dlls/dbghelp/stack.c | 38 ++++++++++++++++++++++++++----------- dlls/dbghelp/symbol.c | 41 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 11 deletions(-)
diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h index c5d637e2f8c..074685b7173 100644 --- a/dlls/dbghelp/dbghelp_private.h +++ b/dlls/dbghelp/dbghelp_private.h @@ -916,6 +916,8 @@ extern struct symt_pointer* extern struct symt_typedef* symt_new_typedef(struct module* module, struct symt* ref, const char* name) DECLSPEC_HIDDEN; +extern struct symt_inlinesite* + symt_find_lowest_inlined(struct symt_function* func, DWORD64 addr) DECLSPEC_HIDDEN; extern struct symt* symt_get_upper_inlined(struct symt_inlinesite* inlined) DECLSPEC_HIDDEN; static inline struct symt_function* @@ -925,6 +927,7 @@ static inline struct symt_function* inlined = (struct symt_inlinesite*)symt_get_upper_inlined(inlined); return &inlined->func; } +extern DWORD symt_get_inlinesite_depth(HANDLE hProcess, DWORD64 addr) DECLSPEC_HIDDEN;
/* Inline context encoding (different from what native does): * bits 31:30: 3 ignore (includes INLINE_FRAME_CONTEXT_IGNORE=0xFFFFFFFF) diff --git a/dlls/dbghelp/stack.c b/dlls/dbghelp/stack.c index a93c454036c..2271612bdd1 100644 --- a/dlls/dbghelp/stack.c +++ b/dlls/dbghelp/stack.c @@ -274,6 +274,7 @@ BOOL WINAPI StackWalkEx(DWORD MachineType, HANDLE hProcess, HANDLE hThread, { struct cpu_stack_walk csw; struct cpu* cpu; + DWORD64 addr;
TRACE("(%d, %p, %p, %p, %p, %p, %p, %p, %p, 0x%x)\n", MachineType, hProcess, hThread, frame, ctx, @@ -296,16 +297,6 @@ BOOL WINAPI StackWalkEx(DWORD MachineType, HANDLE hProcess, HANDLE hThread, SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } - if (frame->InlineFrameContext != INLINE_FRAME_CONTEXT_IGNORE) - { - static BOOL once; - if (!once) - { - FIXME("Inlined contexts are not supported yet\n"); - once = TRUE; - } - frame->InlineFrameContext = INLINE_FRAME_CONTEXT_IGNORE; - }
csw.hProcess = hProcess; csw.hThread = hThread; @@ -317,7 +308,32 @@ BOOL WINAPI StackWalkEx(DWORD MachineType, HANDLE hProcess, HANDLE hThread, csw.u.s64.f_tabl_acs = (FunctionTableAccessRoutine) ? FunctionTableAccessRoutine : SymFunctionTableAccess64; csw.u.s64.f_modl_bas = (GetModuleBaseRoutine) ? GetModuleBaseRoutine : SymGetModuleBase64;
- if (!cpu->stack_walk(&csw, (STACKFRAME64*)frame, ctx)) return FALSE; + addr = sw_xlat_addr(&csw, &frame->AddrPC); + + if (IFC_MODE(frame->InlineFrameContext) == IFC_MODE_INLINE) + { + DWORD depth = symt_get_inlinesite_depth(hProcess, addr); + if (IFC_DEPTH(frame->InlineFrameContext) + 1 < depth) /* move to next inlined function? */ + { + TRACE("found inline ctx: depth=%u current=%u++\n", + depth, frame->InlineFrameContext); + frame->InlineFrameContext++; /* just increase index, FIXME detect overflow */ + } + else + { + frame->InlineFrameContext = IFC_MODE_REGULAR; /* move to next top level function */ + } + } + else + { + if (!cpu->stack_walk(&csw, (STACKFRAME64*)frame, ctx)) return FALSE; + if (frame->InlineFrameContext != INLINE_FRAME_CONTEXT_IGNORE) + { + addr = sw_xlat_addr(&csw, &frame->AddrPC); + frame->InlineFrameContext = symt_get_inlinesite_depth(hProcess, addr) == 0 ? IFC_MODE_REGULAR : IFC_MODE_INLINE; + TRACE("setting IFC mode to %x\n", frame->InlineFrameContext); + } + }
/* we don't handle KdHelp */
diff --git a/dlls/dbghelp/symbol.c b/dlls/dbghelp/symbol.c index 9b7c5f3078e..5dd989b5489 100644 --- a/dlls/dbghelp/symbol.c +++ b/dlls/dbghelp/symbol.c @@ -1213,6 +1213,26 @@ void copy_symbolW(SYMBOL_INFOW* siw, const SYMBOL_INFO* si) MultiByteToWideChar(CP_ACP, 0, si->Name, -1, siw->Name, siw->MaxNameLen); }
+/* return the lowest inline site inside a function */ +struct symt_inlinesite* symt_find_lowest_inlined(struct symt_function* func, DWORD64 addr) +{ + struct symt_inlinesite* current; + int i; + + assert(func->symt.tag == SymTagFunction); + for (current = func->next_inlinesite; current; current = current->func.next_inlinesite) + { + for (i = 0; i < current->vranges.num_elts; ++i) + { + struct addr_range* ar = (struct addr_range*)vector_at(¤t->vranges, i); + /* first matching range gives the lowest inline site; see dbghelp_private.h for details */ + if (ar->low <= addr && addr < ar->high) + return current; + } + } + return NULL; +} + /* from an inline function, get either the enclosing inlined function, or the top function when no inlined */ struct symt* symt_get_upper_inlined(struct symt_inlinesite* inlined) { @@ -1230,6 +1250,27 @@ struct symt* symt_get_upper_inlined(struct symt_inlinesite* inlined) return symt; }
+DWORD symt_get_inlinesite_depth(HANDLE hProcess, DWORD64 addr) +{ + struct module_pair pair; + DWORD depth = 0; + + if (module_init_pair(&pair, hProcess, addr)) + { + struct symt_ht* symt = symt_find_nearest(pair.effective, addr); + if (symt_check_tag(&symt->symt, SymTagFunction)) + { + struct symt_inlinesite* inlined = symt_find_lowest_inlined((struct symt_function*)symt, addr); + if (inlined) + { + for ( ; &inlined->func.symt != &symt->symt; inlined = (struct symt_inlinesite*)symt_get_upper_inlined(inlined)) + ++depth; + } + } + } + return depth; +} + /****************************************************************** * sym_enum *
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/dbghelp_private.h | 3 +++ dlls/dbghelp/symbol.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+)
diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h index 074685b7173..843c05c27a6 100644 --- a/dlls/dbghelp/dbghelp_private.h +++ b/dlls/dbghelp/dbghelp_private.h @@ -927,6 +927,9 @@ static inline struct symt_function* inlined = (struct symt_inlinesite*)symt_get_upper_inlined(inlined); return &inlined->func; } +extern struct symt_inlinesite* + symt_find_inlined_site(struct module* module, + DWORD64 addr, DWORD inline_ctx) DECLSPEC_HIDDEN; extern DWORD symt_get_inlinesite_depth(HANDLE hProcess, DWORD64 addr) DECLSPEC_HIDDEN;
/* Inline context encoding (different from what native does): diff --git a/dlls/dbghelp/symbol.c b/dlls/dbghelp/symbol.c index 5dd989b5489..503432e461f 100644 --- a/dlls/dbghelp/symbol.c +++ b/dlls/dbghelp/symbol.c @@ -1250,6 +1250,24 @@ struct symt* symt_get_upper_inlined(struct symt_inlinesite* inlined) return symt; }
+/* lookup in module for an inline site (from addr and inline_ctx) */ +struct symt_inlinesite* symt_find_inlined_site(struct module* module, DWORD64 addr, DWORD inline_ctx) +{ + struct symt_ht* symt = symt_find_nearest(module, addr); + + if (symt_check_tag(&symt->symt, SymTagFunction)) + { + struct symt_function* func = (struct symt_function*)symt; + struct symt_inlinesite* curr = symt_find_lowest_inlined(func, addr); + DWORD depth = IFC_DEPTH(inline_ctx); + + if (curr) + for ( ; &curr->func != func; curr = (struct symt_inlinesite*)symt_get_upper_inlined(curr)) + if (depth-- == 0) return curr; + } + return NULL; +} + DWORD symt_get_inlinesite_depth(HANDLE hProcess, DWORD64 addr) { struct module_pair pair; @@ -2626,6 +2644,9 @@ PWSTR WINAPI SymSetHomeDirectoryW(HANDLE hProcess, PCWSTR dir) */ BOOL WINAPI SymFromInlineContext(HANDLE hProcess, DWORD64 addr, ULONG inline_ctx, PDWORD64 disp, PSYMBOL_INFO si) { + struct module_pair pair; + struct symt_inlinesite* inlined; + TRACE("(%p, %#I64x, 0x%x, %p, %p)\n", hProcess, addr, inline_ctx, disp, si);
switch (IFC_MODE(inline_ctx)) @@ -2634,6 +2655,15 @@ BOOL WINAPI SymFromInlineContext(HANDLE hProcess, DWORD64 addr, ULONG inline_ctx case IFC_MODE_REGULAR: return SymFromAddr(hProcess, addr, disp, si); case IFC_MODE_INLINE: + if (!module_init_pair(&pair, hProcess, addr)) return FALSE; + inlined = symt_find_inlined_site(pair.effective, addr, inline_ctx); + if (inlined) + { + symt_fill_sym_info(&pair, NULL, &inlined->func.symt, si); + *disp = addr - inlined->func.address; + return TRUE; + } + /* fall through */ default: SetLastError(ERROR_INVALID_PARAMETER); return FALSE;
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/dbghelp.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
diff --git a/dlls/dbghelp/dbghelp.c b/dlls/dbghelp/dbghelp.c index 0b1e20e93c0..844ef00b8e9 100644 --- a/dlls/dbghelp/dbghelp.c +++ b/dlls/dbghelp/dbghelp.c @@ -677,6 +677,9 @@ BOOL WINAPI SymSetScopeFromIndex(HANDLE hProcess, ULONG64 addr, DWORD index) */ BOOL WINAPI SymSetScopeFromInlineContext(HANDLE hProcess, ULONG64 addr, DWORD inlinectx) { + struct module_pair pair; + struct symt_inlinesite* inlined; + TRACE("(%p %I64x %x)\n", hProcess, addr, inlinectx);
switch (IFC_MODE(inlinectx)) @@ -684,6 +687,15 @@ BOOL WINAPI SymSetScopeFromInlineContext(HANDLE hProcess, ULONG64 addr, DWORD in case IFC_MODE_IGNORE: case IFC_MODE_REGULAR: return SymSetScopeFromAddr(hProcess, addr); case IFC_MODE_INLINE: + if (!module_init_pair(&pair, hProcess, addr)) return FALSE; + inlined = symt_find_inlined_site(pair.effective, addr, inlinectx); + if (inlined) + { + pair.pcs->localscope_pc = addr; + pair.pcs->localscope_symt = &inlined->func.symt; + return TRUE; + } + return FALSE; default: SetLastError(ERROR_INVALID_PARAMETER); return FALSE;