The following series implements: - the first internal bits for inline sites - stack walking with inline sites - (local) scope management (replacement of SymSetContext) - some fixes for line number information
This serie doesn't yet provide functional improvement for inline site (as no debug format readers - aka dwarf, pdb... handle inline site properly generate inline site information).
A+ ---
Eric Pouech (11): dbghelp: introduce symt_inlinesite (SymTagInlineSite) to support inline sites dbghelp: introduce a couple of helpers to manage inline contexts dbghelp: added functions to add a range to an inline site dbghelp: implement StackWalkEx inline features dbghelp: implement SymFromInlineContext dbghelp: add local scope information in struct process dbghelp: implement the SymSetScope* functions dbghelp: renamed line_info pc_offset into address dbghelp: let symt_add_func_line() last parameter be an absolute address dbghelp: in SymGetLine* family, compute displacement relative to line_info's address dbghelp: added first implementations for SymGetLineFromInlineContext(W)
dlls/dbghelp/coff.c | 7 +- dlls/dbghelp/dbghelp.c | 71 +++++-- dlls/dbghelp/dbghelp_private.h | 108 +++++++++- dlls/dbghelp/dwarf.c | 6 +- dlls/dbghelp/module.c | 10 +- dlls/dbghelp/msc.c | 9 +- dlls/dbghelp/stabs.c | 4 +- dlls/dbghelp/stack.c | 34 +++- dlls/dbghelp/symbol.c | 360 ++++++++++++++++++++++++++------- dlls/dbghelp/type.c | 16 ++ 10 files changed, 504 insertions(+), 121 deletions(-)
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/dbghelp_private.h | 70 +++++++++++++++++++++++++++++++ dlls/dbghelp/dwarf.c | 2 - dlls/dbghelp/msc.c | 4 +- dlls/dbghelp/symbol.c | 89 ++++++++++++++++++++++++++++------------ dlls/dbghelp/type.c | 16 +++++++ 5 files changed, 150 insertions(+), 31 deletions(-)
diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h index 2ebe6699a1d..761af2ef9e1 100644 --- a/dlls/dbghelp/dbghelp_private.h +++ b/dlls/dbghelp/dbghelp_private.h @@ -216,16 +216,75 @@ 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 */ +}; + +/* tests whether ar2 in 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 +{ + struct symt_function func; + struct vector vranges; /* of addr_range: where the inline site is actually defined */ };
struct symt_hierarchy_point @@ -756,6 +815,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, diff --git a/dlls/dbghelp/dwarf.c b/dlls/dbghelp/dwarf.c index e1c77569622..bde83aca0aa 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 19374999070..cb39fd5b422 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; } @@ -366,7 +405,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 +463,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 +500,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 +526,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 +548,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 +816,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 +1097,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;
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/dbghelp_private.h | 31 ++++++++++++++++ dlls/dbghelp/symbol.c | 77 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+)
diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h index 761af2ef9e1..ed6b3a5bfa9 100644 --- a/dlls/dbghelp/dbghelp_private.h +++ b/dlls/dbghelp/dbghelp_private.h @@ -911,3 +911,34 @@ 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* + 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; +} +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): + * bits 31:30: 3 ignore (includes INLINE_FRAME_CONTEXT_IGNORE=0xFFFFFFFF) + * 2 regular frame + * 1 frame with inlined function(s). + * 0 init (includes INLINE_FRAME_CONTEXT_INIT=0) + * bits 29:00 depth of inline site (way too big!!) + * 0 being the lowest inline site + */ +#define IFC_MODE_IGNORE 0xC0000000 +#define IFC_MODE_REGULAR 0x80000000 +#define IFC_MODE_INLINE 0x40000000 +#define IFC_MODE_INIT 0x00000000 +#define IFC_DEPTH_MASK 0x3FFFFFFF +#define IFC_MODE(x) ((x) & ~IFC_DEPTH_MASK) +#define IFC_DEPTH(x) ((x) & IFC_DEPTH_MASK) diff --git a/dlls/dbghelp/symbol.c b/dlls/dbghelp/symbol.c index cb39fd5b422..b171b6c3c4f 100644 --- a/dlls/dbghelp/symbol.c +++ b/dlls/dbghelp/symbol.c @@ -1179,6 +1179,83 @@ 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) +{ + 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; +} + +/* 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; + struct symt_ht* symt; + + if (!module_init_pair(&pair, hProcess, addr)) return FALSE; + + 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) + { + DWORD depth = 0; + for ( ; &inlined->func.symt != &symt->symt; inlined = (struct symt_inlinesite*)symt_get_upper_inlined(inlined)) + ++depth; + return depth; + } + } + return 0; +} + /****************************************************************** * sym_enum *
(it mostly consists of code to validate assumptions)
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/dbghelp_private.h | 3 +++ dlls/dbghelp/symbol.c | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+)
diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h index ed6b3a5bfa9..62f723f2366 100644 --- a/dlls/dbghelp/dbghelp_private.h +++ b/dlls/dbghelp/dbghelp_private.h @@ -851,6 +851,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/symbol.c b/dlls/dbghelp/symbol.c index b171b6c3c4f..45cca5468dd 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/stack.c | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-)
diff --git a/dlls/dbghelp/stack.c b/dlls/dbghelp/stack.c index 6c70fc805cb..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,12 +297,6 @@ BOOL WINAPI StackWalkEx(DWORD MachineType, HANDLE hProcess, HANDLE hThread, SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } - if (frame->InlineFrameContext != INLINE_FRAME_CONTEXT_IGNORE) - { - FIXME("Inlined contexts are not supported yet\n"); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - }
csw.hProcess = hProcess; csw.hThread = hThread; @@ -313,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 */
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/symbol.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-)
diff --git a/dlls/dbghelp/symbol.c b/dlls/dbghelp/symbol.c index 45cca5468dd..edfeb5909f0 100644 --- a/dlls/dbghelp/symbol.c +++ b/dlls/dbghelp/symbol.c @@ -2647,9 +2647,30 @@ PWSTR WINAPI SymSetHomeDirectoryW(HANDLE hProcess, PCWSTR dir) */ BOOL WINAPI SymFromInlineContext(HANDLE hProcess, DWORD64 addr, ULONG inline_ctx, PDWORD64 disp, PSYMBOL_INFO si) { - FIXME("(%p, %#I64x, 0x%x, %p, %p): stub\n", hProcess, addr, inline_ctx, disp, si); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; + 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)) + { + case IFC_MODE_IGNORE: + 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; + } }
/******************************************************************
- made SymSetContext() generate this information - let SymEnumSymbol (in local symbol mode) use this information instead of the stack frame
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/dbghelp.c | 14 ++++++++++++-- dlls/dbghelp/dbghelp_private.h | 2 ++ dlls/dbghelp/dwarf.c | 2 +- dlls/dbghelp/symbol.c | 14 ++++++-------- 4 files changed, 21 insertions(+), 11 deletions(-)
diff --git a/dlls/dbghelp/dbghelp.c b/dlls/dbghelp/dbghelp.c index 00f02423fef..64ceb447ee9 100644 --- a/dlls/dbghelp/dbghelp.c +++ b/dlls/dbghelp/dbghelp.c @@ -606,11 +606,21 @@ BOOL WINAPI SymSetParentWindow(HWND hwnd) BOOL WINAPI SymSetContext(HANDLE hProcess, PIMAGEHLP_STACK_FRAME StackFrame, PIMAGEHLP_CONTEXT Context) { - struct process* pcs = process_find_by_handle(hProcess); + struct process* pcs; + struct module_pair pair; + struct symt_ht* sym; + + pair.pcs = pcs = process_find_by_handle(hProcess); if (!pcs) return FALSE;
- if (!module_find_by_addr(pcs, StackFrame->InstructionOffset, DMT_UNKNOWN)) + pair.requested = module_find_by_addr(pair.pcs, StackFrame->InstructionOffset, DMT_UNKNOWN); + if (!module_get_debug(&pair)) return FALSE; return FALSE; + if ((sym = symt_find_nearest(pair.effective, StackFrame->InstructionOffset)) == NULL) return FALSE; + if (sym->symt.tag != SymTagFunction) return FALSE; + pcs->localscope_pc = StackFrame->InstructionOffset; + pcs->localscope_symt = &sym->symt; + if (pcs->ctx_frame.ReturnOffset == StackFrame->ReturnOffset && pcs->ctx_frame.FrameOffset == StackFrame->FrameOffset && pcs->ctx_frame.StackOffset == StackFrame->StackOffset) diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h index 62f723f2366..1d26a1ec0d9 100644 --- a/dlls/dbghelp/dbghelp_private.h +++ b/dlls/dbghelp/dbghelp_private.h @@ -497,6 +497,8 @@ struct process ULONG_PTR dbg_hdr_addr;
IMAGEHLP_STACK_FRAME ctx_frame; + DWORD64 localscope_pc; + struct symt* localscope_symt;
unsigned buffer_size; void* buffer; diff --git a/dlls/dbghelp/dwarf.c b/dlls/dbghelp/dwarf.c index bde83aca0aa..86650e991a8 100644 --- a/dlls/dbghelp/dwarf.c +++ b/dlls/dbghelp/dwarf.c @@ -3723,7 +3723,7 @@ static void dwarf2_location_compute(struct process* pcs, else { /* instruction pointer relative to compiland's start */ - ip = pcs->ctx_frame.InstructionOffset - ((struct symt_compiland*)func->container)->address; + ip = pcs->localscope_pc - ((struct symt_compiland*)func->container)->address;
if ((err = loc_compute_frame(pcs, modfmt, func, ip, head, &frame)) == 0) { diff --git a/dlls/dbghelp/symbol.c b/dlls/dbghelp/symbol.c index edfeb5909f0..c961b3ee8e5 100644 --- a/dlls/dbghelp/symbol.c +++ b/dlls/dbghelp/symbol.c @@ -1100,7 +1100,7 @@ static BOOL symt_enum_locals_helper(struct module_pair* pair, struct symt_function* func, const struct vector* v) { struct symt* lsym = NULL; - DWORD_PTR pc = pair->pcs->ctx_frame.InstructionOffset; + DWORD_PTR pc = pair->pcs->localscope_pc; unsigned int i; WCHAR* nameW; BOOL ret; @@ -1147,21 +1147,19 @@ static BOOL symt_enum_locals(struct process* pcs, const WCHAR* mask, const struct sym_enum* se) { struct module_pair pair; - struct symt_ht* sym; - DWORD_PTR pc = pcs->ctx_frame.InstructionOffset;
se->sym_info->SizeOfStruct = sizeof(*se->sym_info); se->sym_info->MaxNameLen = sizeof(se->buffer) - sizeof(SYMBOL_INFO);
pair.pcs = pcs; - pair.requested = module_find_by_addr(pair.pcs, pc, DMT_UNKNOWN); + pair.requested = module_find_by_addr(pair.pcs, pcs->localscope_pc, DMT_UNKNOWN); if (!module_get_debug(&pair)) return FALSE; - if ((sym = symt_find_nearest(pair.effective, pc)) == NULL) return FALSE;
- if (sym->symt.tag == SymTagFunction) + if (symt_check_tag(pcs->localscope_symt, SymTagFunction) || + symt_check_tag(pcs->localscope_symt, SymTagInlineSite)) { - return symt_enum_locals_helper(&pair, mask ? mask : L"*", se, (struct symt_function*)sym, - &((struct symt_function*)sym)->vchildren); + struct symt_function* func = (struct symt_function*)pcs->localscope_symt; + return symt_enum_locals_helper(&pair, mask ? mask : L"*", se, func, &func->vchildren); } return FALSE; }
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/dbghelp.c | 75 ++++++++++++++++++++++++++++++++---------------- dlls/dbghelp/module.c | 10 ++++++ 2 files changed, 59 insertions(+), 26 deletions(-)
diff --git a/dlls/dbghelp/dbghelp.c b/dlls/dbghelp/dbghelp.c index 64ceb447ee9..6c63d6eddcd 100644 --- a/dlls/dbghelp/dbghelp.c +++ b/dlls/dbghelp/dbghelp.c @@ -607,34 +607,27 @@ BOOL WINAPI SymSetContext(HANDLE hProcess, PIMAGEHLP_STACK_FRAME StackFrame, PIMAGEHLP_CONTEXT Context) { struct process* pcs; - struct module_pair pair; - struct symt_ht* sym; + BOOL same;
- pair.pcs = pcs = process_find_by_handle(hProcess); - if (!pcs) return FALSE; + if (!(pcs = process_find_by_handle(hProcess))) return FALSE; + same = pcs->ctx_frame.ReturnOffset == StackFrame->ReturnOffset && + pcs->ctx_frame.FrameOffset == StackFrame->FrameOffset && + pcs->ctx_frame.StackOffset == StackFrame->StackOffset;
- pair.requested = module_find_by_addr(pair.pcs, StackFrame->InstructionOffset, DMT_UNKNOWN); - if (!module_get_debug(&pair)) return FALSE; + if (!SymSetScopeFromAddr(hProcess, StackFrame->InstructionOffset)) return FALSE; - if ((sym = symt_find_nearest(pair.effective, StackFrame->InstructionOffset)) == NULL) return FALSE; - if (sym->symt.tag != SymTagFunction) return FALSE; - pcs->localscope_pc = StackFrame->InstructionOffset; - pcs->localscope_symt = &sym->symt;
- if (pcs->ctx_frame.ReturnOffset == StackFrame->ReturnOffset && - pcs->ctx_frame.FrameOffset == StackFrame->FrameOffset && - pcs->ctx_frame.StackOffset == StackFrame->StackOffset) + pcs->ctx_frame = *StackFrame; + if (same) { TRACE("Setting same frame {rtn=%I64x frm=%I64x stk=%I64x}\n", pcs->ctx_frame.ReturnOffset, pcs->ctx_frame.FrameOffset, pcs->ctx_frame.StackOffset); - pcs->ctx_frame.InstructionOffset = StackFrame->InstructionOffset; SetLastError(ERROR_SUCCESS); return FALSE; }
- pcs->ctx_frame = *StackFrame; /* Context is not (no longer?) used */ return TRUE; } @@ -644,11 +637,17 @@ BOOL WINAPI SymSetContext(HANDLE hProcess, PIMAGEHLP_STACK_FRAME StackFrame, */ BOOL WINAPI SymSetScopeFromAddr(HANDLE hProcess, ULONG64 addr) { - struct process* pcs; + struct module_pair pair; + struct symt_ht* sym;
- FIXME("(%p %#I64x): stub\n", hProcess, addr); + TRACE("(%p %#I64x): stub\n", hProcess, addr);
- if (!(pcs = process_find_by_handle(hProcess))) return FALSE; + if (!module_init_pair(&pair, hProcess, addr)) return FALSE; + if ((sym = symt_find_nearest(pair.effective, addr)) == NULL) return FALSE; + if (sym->symt.tag != SymTagFunction) return FALSE; + + pair.pcs->localscope_pc = addr; + pair.pcs->localscope_symt = &sym->symt; return TRUE; }
@@ -657,11 +656,18 @@ BOOL WINAPI SymSetScopeFromAddr(HANDLE hProcess, ULONG64 addr) */ BOOL WINAPI SymSetScopeFromIndex(HANDLE hProcess, ULONG64 addr, DWORD index) { - struct process* pcs; + struct module_pair pair; + struct symt* sym;
- FIXME("(%p %#I64x %u): stub\n", hProcess, addr, index); + TRACE("(%p %#I64x %u): stub\n", hProcess, addr, index); + + if (!module_init_pair(&pair, hProcess, addr)) return FALSE; + sym = symt_index2ptr(pair.effective, index); + if (!symt_check_tag(sym, SymTagFunction)) return FALSE; + + pair.pcs->localscope_pc = ((struct symt_function*)sym)->address; /* FIXME of FuncDebugStart when it exists? */ + pair.pcs->localscope_symt = sym;
- if (!(pcs = process_find_by_handle(hProcess))) return FALSE; return TRUE; }
@@ -670,12 +676,31 @@ BOOL WINAPI SymSetScopeFromIndex(HANDLE hProcess, ULONG64 addr, DWORD index) */ BOOL WINAPI SymSetScopeFromInlineContext(HANDLE hProcess, ULONG64 addr, DWORD inlinectx) { - struct process* pcs; + TRACE("(%p %I64x %x)\n", hProcess, addr, inlinectx);
- FIXME("(%p %#I64x %u): stub\n", hProcess, addr, inlinectx); + switch (IFC_MODE(inlinectx)) + { + case IFC_MODE_IGNORE: + case IFC_MODE_REGULAR: return SymSetScopeFromAddr(hProcess, addr); + case IFC_MODE_INLINE: + { + struct module_pair pair; + struct symt_inlinesite* inlined;
- if (!(pcs = process_find_by_handle(hProcess))) return FALSE; - return TRUE; + 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; + } }
/****************************************************************** diff --git a/dlls/dbghelp/module.c b/dlls/dbghelp/module.c index f0fd2a55016..8168e727c52 100644 --- a/dlls/dbghelp/module.c +++ b/dlls/dbghelp/module.c @@ -1048,7 +1048,15 @@ BOOL WINAPI SymUnloadModule64(HANDLE hProcess, DWORD64 BaseOfDll) if (!pcs) return FALSE; module = module_find_by_addr(pcs, BaseOfDll, DMT_UNKNOWN); if (!module) return FALSE; - return module_remove(pcs, module); + if (!module_remove(pcs, module)) return FALSE; + /* remove local scope if defined inside this module */ + if (pcs->localscope_pc >= module->module.BaseOfImage && + pcs->localscope_pc < module->module.BaseOfImage + module->module.ImageSize) + { + pcs->localscope_pc = 0; + pcs->localscope_symt = NULL; + } + return TRUE; }
/******************************************************************
as it's actually an absolute address
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/dbghelp_private.h | 2 +- dlls/dbghelp/symbol.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h index 1d26a1ec0d9..2278a007b76 100644 --- a/dlls/dbghelp/dbghelp_private.h +++ b/dlls/dbghelp/dbghelp_private.h @@ -519,7 +519,7 @@ struct line_info line_number; union { - ULONG_PTR pc_offset; /* if is_source_file isn't set */ + ULONG_PTR address; /* absolute, if is_source_file isn't set */ unsigned source_file; /* if is_source_file is set */ } u; }; diff --git a/dlls/dbghelp/symbol.c b/dlls/dbghelp/symbol.c index c961b3ee8e5..93669024951 100644 --- a/dlls/dbghelp/symbol.c +++ b/dlls/dbghelp/symbol.c @@ -435,7 +435,7 @@ void symt_add_func_line(struct module* module, struct symt_function* func, dli->is_first = 0; /* only a source file can be first */ dli->is_last = 1; dli->line_number = line_num; - dli->u.pc_offset = func->address + offset; + dli->u.address = func->address + offset; }
/****************************************************************** @@ -1871,9 +1871,9 @@ static BOOL get_line_from_addr(HANDLE hProcess, DWORD64 addr, dli = vector_at(&func->vlines, i); if (!dli->is_source_file) { - if (found || dli->u.pc_offset > addr) continue; + if (found || dli->u.address > addr) continue; intl->line_number = dli->line_number; - intl->address = dli->u.pc_offset; + intl->address = dli->u.address; intl->key = dli; found = TRUE; continue; @@ -2014,7 +2014,7 @@ static BOOL symt_get_func_line_prev(HANDLE hProcess, struct internal_line_t* int if (!li->is_source_file) { intl->line_number = li->line_number; - intl->address = li->u.pc_offset; + intl->address = li->u.address; intl->key = li; /* search source file */ for (srcli = li; !srcli->is_source_file; srcli--); @@ -2093,7 +2093,7 @@ static BOOL symt_get_func_line_next(HANDLE hProcess, struct internal_line_t* int if (!li->is_source_file) { intl->line_number = li->line_number; - intl->address = li->u.pc_offset; + intl->address = li->u.address; intl->key = li; return internal_line_set_nameA(pair.pcs, intl, (char*)source_get(pair.effective, srcli->u.source_file), FALSE); } @@ -2560,7 +2560,7 @@ BOOL WINAPI SymEnumLines(HANDLE hProcess, ULONG64 base, PCSTR compiland, sci.Key = dli; sci.Obj[0] = '\0'; /* FIXME */ sci.LineNumber = dli->line_number; - sci.Address = dli->u.pc_offset; + sci.Address = dli->u.address; if (!cb(&sci, user)) break; } }
used to be an offset to the start of function, but actually stored as an absolute address this avoids unnecessary computations
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/coff.c | 7 +------ dlls/dbghelp/dwarf.c | 2 +- dlls/dbghelp/msc.c | 5 ++--- dlls/dbghelp/stabs.c | 4 ++-- dlls/dbghelp/symbol.c | 8 ++++---- 5 files changed, 10 insertions(+), 16 deletions(-)
diff --git a/dlls/dbghelp/coff.c b/dlls/dbghelp/coff.c index 8684a493310..cc005a3bbc5 100644 --- a/dlls/dbghelp/coff.c +++ b/dlls/dbghelp/coff.c @@ -421,16 +421,11 @@ DECLSPEC_HIDDEN BOOL coff_process_info(const struct msc_debug_info* msc_dbg) { if (coff_files.files[j].entries[l+1]->tag == SymTagFunction) { - /* - * Add the line number. This is always relative to the - * start of the function, so we need to subtract that offset - * first. - */ symt_add_func_line(msc_dbg->module, (struct symt_function*)coff_files.files[j].entries[l+1], coff_files.files[j].compiland->source, linepnt->Linenumber, - msc_dbg->module->module.BaseOfImage + linepnt->Type.VirtualAddress - addr); + msc_dbg->module->module.BaseOfImage + linepnt->Type.VirtualAddress); } break; } diff --git a/dlls/dbghelp/dwarf.c b/dlls/dbghelp/dwarf.c index 86650e991a8..6b0a33597b0 100644 --- a/dlls/dbghelp/dwarf.c +++ b/dlls/dbghelp/dwarf.c @@ -2441,7 +2441,7 @@ static void dwarf2_set_line_number(struct module* module, ULONG_PTR address, if (symt_check_tag(&symt->symt, SymTagFunction)) { func = (struct symt_function*)symt; - symt_add_func_line(module, func, *psrc, line, address - func->address); + symt_add_func_line(module, func, *psrc, line, address); } }
diff --git a/dlls/dbghelp/msc.c b/dlls/dbghelp/msc.c index c557cb24636..191e33e781f 100644 --- a/dlls/dbghelp/msc.c +++ b/dlls/dbghelp/msc.c @@ -1454,8 +1454,7 @@ static void codeview_snarf_linetab(const struct msc_debug_info* msc_dbg, const B break; } } - symt_add_func_line(msc_dbg->module, func, source, - linenos[k], addr - func->address); + symt_add_func_line(msc_dbg->module, func, source, linenos[k], addr); } } } @@ -1519,7 +1518,7 @@ static void codeview_snarf_linetab2(const struct msc_debug_info* msc_dbg, const { symt_add_func_line(msc_dbg->module, func, source, lines_blk->l[i].lineno ^ 0x80000000, - lines_blk->l[i].offset); + func->address + lines_blk->l[i].offset); } break; case LT2_FILES_BLOCK: /* skip */ diff --git a/dlls/dbghelp/stabs.c b/dlls/dbghelp/stabs.c index 9d7d5131fc4..647a71ec258 100644 --- a/dlls/dbghelp/stabs.c +++ b/dlls/dbghelp/stabs.c @@ -1168,7 +1168,7 @@ static void pending_flush(struct pending_list* pending, struct module* module, if (module->type == DMT_MACHO) pending->objs[i].u.line.offset -= func->address - pending->objs[i].u.line.load_offset; symt_add_func_line(module, func, pending->objs[i].u.line.source_idx, - pending->objs[i].u.line.line_num, pending->objs[i].u.line.offset); + pending->objs[i].u.line.line_num, func->address + pending->objs[i].u.line.offset); break; default: ERR("Unknown pending object tag %u\n", (unsigned)pending->objs[i].tag); @@ -1492,7 +1492,7 @@ BOOL stabs_parse(struct module* module, ULONG_PTR load_offset, if (module->type == DMT_MACHO) offset -= curr_func->address - load_offset; symt_add_func_line(module, curr_func, source_idx, - stab_ptr->n_desc, offset); + stab_ptr->n_desc, curr_func->address + offset); } else pending_add_line(&pending_func, source_idx, stab_ptr->n_desc, n_value, load_offset); diff --git a/dlls/dbghelp/symbol.c b/dlls/dbghelp/symbol.c index 93669024951..4fd9fda6619 100644 --- a/dlls/dbghelp/symbol.c +++ b/dlls/dbghelp/symbol.c @@ -391,7 +391,7 @@ struct symt_inlinesite* symt_new_inlinesite(struct module* module, }
void symt_add_func_line(struct module* module, struct symt_function* func, - unsigned source_idx, int line_num, ULONG_PTR offset) + unsigned source_idx, int line_num, ULONG_PTR addr) { struct line_info* dli; unsigned vlen; @@ -401,8 +401,8 @@ void symt_add_func_line(struct module* module, struct symt_function* func,
if (func == NULL || !(dbghelp_options & SYMOPT_LOAD_LINES)) return;
- TRACE_(dbghelp_symt)("(%p)%s:%lx %s:%u\n", - func, func->hash_elt.name, offset, + TRACE_(dbghelp_symt)("(%p)%s:%Ix %s:%u\n", + func, func->hash_elt.name, addr, source_get(module, source_idx), line_num);
assert(func->symt.tag == SymTagFunction || func->symt.tag == SymTagInlineSite); @@ -435,7 +435,7 @@ void symt_add_func_line(struct module* module, struct symt_function* func, dli->is_first = 0; /* only a source file can be first */ dli->is_last = 1; dli->line_number = line_num; - dli->u.address = func->address + offset; + dli->u.address = addr; }
/******************************************************************
(was incorrectly computed relative to start of function)
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/symbol.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/dlls/dbghelp/symbol.c b/dlls/dbghelp/symbol.c index 4fd9fda6619..459f282502a 100644 --- a/dlls/dbghelp/symbol.c +++ b/dlls/dbghelp/symbol.c @@ -1854,7 +1854,7 @@ static BOOL get_line_from_addr(HANDLE hProcess, DWORD64 addr, PDWORD pdwDisplacement, struct internal_line_t* intl) { struct line_info* dli = NULL; - BOOL found = FALSE; + struct line_info* found_dli = NULL; int i; struct module_pair pair; struct symt_ht* symt; @@ -1871,14 +1871,14 @@ static BOOL get_line_from_addr(HANDLE hProcess, DWORD64 addr, dli = vector_at(&func->vlines, i); if (!dli->is_source_file) { - if (found || dli->u.address > addr) continue; + if (found_dli || dli->u.address > addr) continue; intl->line_number = dli->line_number; intl->address = dli->u.address; intl->key = dli; - found = TRUE; + found_dli = dli; continue; } - if (found) + if (found_dli) { BOOL ret; if (dbghelp_opt_native) @@ -1892,7 +1892,7 @@ static BOOL get_line_from_addr(HANDLE hProcess, DWORD64 addr, ret = internal_line_set_nameW(pair.pcs, intl, dospath, TRUE); HeapFree( GetProcessHeap(), 0, dospath ); } - if (ret) *pdwDisplacement = intl->address - func->address; + if (ret) *pdwDisplacement = addr - found_dli->u.address; return ret; } }
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/symbol.c | 91 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 65 insertions(+), 26 deletions(-)
diff --git a/dlls/dbghelp/symbol.c b/dlls/dbghelp/symbol.c index 459f282502a..938dac2dd3c 100644 --- a/dlls/dbghelp/symbol.c +++ b/dlls/dbghelp/symbol.c @@ -1845,28 +1845,14 @@ static BOOL internal_line_set_nameW(struct process* pcs, struct internal_line_t* return TRUE; }
-/****************************************************************** - * get_line_from_addr - * - * fills source file information from an address - */ -static BOOL get_line_from_addr(HANDLE hProcess, DWORD64 addr, - PDWORD pdwDisplacement, struct internal_line_t* intl) +static BOOL get_line_from_function(struct module_pair* pair, struct symt_function* func, DWORD64 addr, + PDWORD pdwDisplacement, struct internal_line_t* intl) { struct line_info* dli = NULL; struct line_info* found_dli = NULL; int i; - struct module_pair pair; - struct symt_ht* symt; - struct symt_function* func; - - if (!module_init_pair(&pair, hProcess, addr)) return FALSE; - if ((symt = symt_find_nearest(pair.effective, addr)) == NULL) return FALSE;
- if (symt->symt.tag != SymTagFunction) return FALSE; - func = (struct symt_function*)symt; - - for (i=vector_length(&func->vlines)-1; i>=0; i--) + for (i = vector_length(&func->vlines) - 1; i >= 0; i--) { dli = vector_at(&func->vlines, i); if (!dli->is_source_file) @@ -1884,12 +1870,12 @@ static BOOL get_line_from_addr(HANDLE hProcess, DWORD64 addr, if (dbghelp_opt_native) { /* Return native file paths when using winedbg */ - ret = internal_line_set_nameA(pair.pcs, intl, (char*)source_get(pair.effective, dli->u.source_file), FALSE); + ret = internal_line_set_nameA(pair->pcs, intl, (char*)source_get(pair->effective, dli->u.source_file), FALSE); } else { - WCHAR *dospath = wine_get_dos_file_name(source_get(pair.effective, dli->u.source_file)); - ret = internal_line_set_nameW(pair.pcs, intl, dospath, TRUE); + WCHAR *dospath = wine_get_dos_file_name(source_get(pair->effective, dli->u.source_file)); + ret = internal_line_set_nameW(pair->pcs, intl, dospath, TRUE); HeapFree( GetProcessHeap(), 0, dospath ); } if (ret) *pdwDisplacement = addr - found_dli->u.address; @@ -1899,6 +1885,24 @@ static BOOL get_line_from_addr(HANDLE hProcess, DWORD64 addr, return FALSE; }
+/****************************************************************** + * get_line_from_addr + * + * fills source file information from an address + */ +static BOOL get_line_from_addr(HANDLE hProcess, DWORD64 addr, + PDWORD pdwDisplacement, struct internal_line_t* intl) +{ + struct module_pair pair; + struct symt_ht* symt; + + if (!module_init_pair(&pair, hProcess, addr)) return FALSE; + if ((symt = symt_find_nearest(pair.effective, addr)) == NULL) return FALSE; + + if (symt->symt.tag != SymTagFunction && symt->symt.tag != SymTagInlineSite) return FALSE; + return get_line_from_function(&pair, (struct symt_function*)symt, addr, pdwDisplacement, intl); +} + /*********************************************************************** * SymGetSymNext64 (DBGHELP.@) */ @@ -2697,16 +2701,45 @@ BOOL WINAPI SymFromInlineContextW(HANDLE hProcess, DWORD64 addr, ULONG inline_ct return ret; }
+static BOOL get_line_from_inline_context(HANDLE hProcess, DWORD64 addr, ULONG inline_ctx, DWORD64 mod_addr, PDWORD disp, + struct internal_line_t* intl) +{ + struct module_pair pair; + struct symt_inlinesite* inlined; + + if (!module_init_pair(&pair, hProcess, mod_addr ? mod_addr : addr)) return FALSE; + switch (IFC_MODE(inline_ctx)) + { + case IFC_MODE_INLINE: + inlined = symt_find_inlined_site(pair.effective, addr, inline_ctx); + if (inlined && get_line_from_function(&pair, &inlined->func, addr, disp, intl)) + return TRUE; + /* fall through: check if we can find line info at top function level */ + case IFC_MODE_IGNORE: + case IFC_MODE_REGULAR: + return get_line_from_addr(hProcess, addr, disp, intl); + default: + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } +} + /****************************************************************** * SymGetLineFromInlineContext (DBGHELP.@) * */ BOOL WINAPI SymGetLineFromInlineContext(HANDLE hProcess, DWORD64 addr, ULONG inline_ctx, DWORD64 mod_addr, PDWORD disp, PIMAGEHLP_LINE64 line) { - FIXME("(%p, %#I64x, 0x%x, %#I64x, %p, %p): stub!\n", + struct internal_line_t intl; + + TRACE("(%p, %#I64x, 0x%x, %#I64x, %p, %p): stub!\n", hProcess, addr, inline_ctx, mod_addr, disp, line); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; + + if (line->SizeOfStruct < sizeof(*line)) return FALSE; + init_internal_line(&intl, FALSE); + + if (!get_line_from_inline_context(hProcess, addr, inline_ctx, mod_addr, disp, &intl)) return FALSE; + return internal_line_copy_toA64(&intl, line); }
/****************************************************************** @@ -2715,8 +2748,14 @@ BOOL WINAPI SymGetLineFromInlineContext(HANDLE hProcess, DWORD64 addr, ULONG inl */ BOOL WINAPI SymGetLineFromInlineContextW(HANDLE hProcess, DWORD64 addr, ULONG inline_ctx, DWORD64 mod_addr, PDWORD disp, PIMAGEHLP_LINEW64 line) { - FIXME("(%p, %#I64x, 0x%x, %#I64x, %p, %p): stub!\n", + struct internal_line_t intl; + + TRACE("(%p, %#I64x, 0x%x, %#I64x, %p, %p): stub!\n", hProcess, addr, inline_ctx, mod_addr, disp, line); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; + + if (line->SizeOfStruct < sizeof(*line)) return FALSE; + init_internal_line(&intl, TRUE); + + if (!get_line_from_inline_context(hProcess, addr, inline_ctx, mod_addr, disp, &intl)) return FALSE; + return internal_line_copy_toW64(&intl, line); }
Eric Pouech eric.pouech@gmail.com writes:
The following series implements:
- the first internal bits for inline sites
- stack walking with inline sites
- (local) scope management (replacement of SymSetContext)
- some fixes for line number information
This serie doesn't yet provide functional improvement for inline site (as no debug format readers - aka dwarf, pdb... handle inline site properly generate inline site information).
Any chance that you could structure the series so that it doesn't add a bunch of dead code upfront, only to be called in later patches?
The following series implements inline site and (local) scope contexts
V2: - reorder patches to have full functionnalities earlier - added the dwarf backend modifications
Alexandre, if you think this is too big for once, you can decide to split between those blocks: [01/08]: stack walk and symbol info for inline contexts (+ dwarf backend support) [09/10]: (local) scope management functions [11/15]: line info for inline context (+ dwarf backend support)
I also recommend using dwarf4 (instead of dwarf2) for using these features.
A+ ---
Eric Pouech (15): dbghelp: introduce symt_inlinesite (SymTagInlineSite) to support inline sites dbghelp: introduce a couple of helpers to manage inline contexts dbghelp: added functions to add a range to an inline site dbghelp: implement StackWalkEx inline features dbghelp: implement SymFromInlineContext dbghelp/dwarf: add current block as a field in dwarf2_subprogram_t dbghelp/dwarf: generate proper inline function dbghelp/dwarf: now storing each subrange for an inlined function dbghelp: add local scope information in struct process dbghelp: implement the SymSetScope* functions dbghelp: renamed line_info pc_offset into address dbghelp: let symt_add_func_line() last parameter be an absolute address dbghelp: in SymGetLine* family, compute displacement relative to line_info's address dbghelp: added first implementations for SymGetLineFromInlineContext(W) dbghelp/dwarf: store line numbers and file info for inlined functions
dlls/dbghelp/coff.c | 7 +- dlls/dbghelp/dbghelp.c | 71 +++++-- dlls/dbghelp/dbghelp_private.h | 108 +++++++++- dlls/dbghelp/dwarf.c | 205 ++++++++++++++----- dlls/dbghelp/module.c | 10 +- dlls/dbghelp/msc.c | 9 +- dlls/dbghelp/stabs.c | 4 +- dlls/dbghelp/stack.c | 34 +++- dlls/dbghelp/symbol.c | 360 ++++++++++++++++++++++++++------- dlls/dbghelp/type.c | 16 ++ 10 files changed, 654 insertions(+), 170 deletions(-)
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/dbghelp_private.h | 70 +++++++++++++++++++++++++++++++ dlls/dbghelp/dwarf.c | 2 - dlls/dbghelp/msc.c | 4 +- dlls/dbghelp/symbol.c | 89 ++++++++++++++++++++++++++++------------ dlls/dbghelp/type.c | 16 +++++++ 5 files changed, 150 insertions(+), 31 deletions(-)
diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h index 2ebe6699a1d..761af2ef9e1 100644 --- a/dlls/dbghelp/dbghelp_private.h +++ b/dlls/dbghelp/dbghelp_private.h @@ -216,16 +216,75 @@ 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 */ +}; + +/* tests whether ar2 in 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 +{ + struct symt_function func; + struct vector vranges; /* of addr_range: where the inline site is actually defined */ };
struct symt_hierarchy_point @@ -756,6 +815,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, diff --git a/dlls/dbghelp/dwarf.c b/dlls/dbghelp/dwarf.c index e1c77569622..bde83aca0aa 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 19374999070..cb39fd5b422 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; } @@ -366,7 +405,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 +463,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 +500,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 +526,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 +548,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 +816,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 +1097,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;
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/dbghelp_private.h | 31 ++++++++++++++++ dlls/dbghelp/symbol.c | 77 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+)
diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h index 761af2ef9e1..ed6b3a5bfa9 100644 --- a/dlls/dbghelp/dbghelp_private.h +++ b/dlls/dbghelp/dbghelp_private.h @@ -911,3 +911,34 @@ 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* + 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; +} +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): + * bits 31:30: 3 ignore (includes INLINE_FRAME_CONTEXT_IGNORE=0xFFFFFFFF) + * 2 regular frame + * 1 frame with inlined function(s). + * 0 init (includes INLINE_FRAME_CONTEXT_INIT=0) + * bits 29:00 depth of inline site (way too big!!) + * 0 being the lowest inline site + */ +#define IFC_MODE_IGNORE 0xC0000000 +#define IFC_MODE_REGULAR 0x80000000 +#define IFC_MODE_INLINE 0x40000000 +#define IFC_MODE_INIT 0x00000000 +#define IFC_DEPTH_MASK 0x3FFFFFFF +#define IFC_MODE(x) ((x) & ~IFC_DEPTH_MASK) +#define IFC_DEPTH(x) ((x) & IFC_DEPTH_MASK) diff --git a/dlls/dbghelp/symbol.c b/dlls/dbghelp/symbol.c index cb39fd5b422..b171b6c3c4f 100644 --- a/dlls/dbghelp/symbol.c +++ b/dlls/dbghelp/symbol.c @@ -1179,6 +1179,83 @@ 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) +{ + 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; +} + +/* 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; + struct symt_ht* symt; + + if (!module_init_pair(&pair, hProcess, addr)) return FALSE; + + 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) + { + DWORD depth = 0; + for ( ; &inlined->func.symt != &symt->symt; inlined = (struct symt_inlinesite*)symt_get_upper_inlined(inlined)) + ++depth; + return depth; + } + } + return 0; +} + /****************************************************************** * sym_enum *
(it mostly consists of code to validate assumptions)
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/dbghelp_private.h | 3 +++ dlls/dbghelp/symbol.c | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+)
diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h index ed6b3a5bfa9..62f723f2366 100644 --- a/dlls/dbghelp/dbghelp_private.h +++ b/dlls/dbghelp/dbghelp_private.h @@ -851,6 +851,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/symbol.c b/dlls/dbghelp/symbol.c index b171b6c3c4f..45cca5468dd 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/stack.c | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-)
diff --git a/dlls/dbghelp/stack.c b/dlls/dbghelp/stack.c index 6c70fc805cb..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,12 +297,6 @@ BOOL WINAPI StackWalkEx(DWORD MachineType, HANDLE hProcess, HANDLE hThread, SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } - if (frame->InlineFrameContext != INLINE_FRAME_CONTEXT_IGNORE) - { - FIXME("Inlined contexts are not supported yet\n"); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - }
csw.hProcess = hProcess; csw.hThread = hThread; @@ -313,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 */
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/symbol.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-)
diff --git a/dlls/dbghelp/symbol.c b/dlls/dbghelp/symbol.c index 45cca5468dd..edfeb5909f0 100644 --- a/dlls/dbghelp/symbol.c +++ b/dlls/dbghelp/symbol.c @@ -2647,9 +2647,30 @@ PWSTR WINAPI SymSetHomeDirectoryW(HANDLE hProcess, PCWSTR dir) */ BOOL WINAPI SymFromInlineContext(HANDLE hProcess, DWORD64 addr, ULONG inline_ctx, PDWORD64 disp, PSYMBOL_INFO si) { - FIXME("(%p, %#I64x, 0x%x, %p, %p): stub\n", hProcess, addr, inline_ctx, disp, si); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; + 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)) + { + case IFC_MODE_IGNORE: + 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; + } }
/******************************************************************
(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 bde83aca0aa..dbf28db27ea 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/dwarf.c | 83 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 53 insertions(+), 30 deletions(-)
diff --git a/dlls/dbghelp/dwarf.c b/dlls/dbghelp/dwarf.c index dbf28db27ea..641394b1d58 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,12 +2848,14 @@ 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; } - FIXME("Should have a compilation unit head\n"); + FIXME("Should have a compilation unit head %p %s\n", func, func ? func->hash_elt.name : ""); return NULL; }
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/dwarf.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+)
diff --git a/dlls/dbghelp/dwarf.c b/dlls/dbghelp/dwarf.c index 641394b1d58..afcc2628f1e 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++) {
- made SymSetContext() generate this information - let SymEnumSymbol (in local symbol mode) use this information instead of the stack frame
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/dbghelp.c | 14 ++++++++++++-- dlls/dbghelp/dbghelp_private.h | 2 ++ dlls/dbghelp/dwarf.c | 2 +- dlls/dbghelp/symbol.c | 14 ++++++-------- 4 files changed, 21 insertions(+), 11 deletions(-)
diff --git a/dlls/dbghelp/dbghelp.c b/dlls/dbghelp/dbghelp.c index 00f02423fef..64ceb447ee9 100644 --- a/dlls/dbghelp/dbghelp.c +++ b/dlls/dbghelp/dbghelp.c @@ -606,11 +606,21 @@ BOOL WINAPI SymSetParentWindow(HWND hwnd) BOOL WINAPI SymSetContext(HANDLE hProcess, PIMAGEHLP_STACK_FRAME StackFrame, PIMAGEHLP_CONTEXT Context) { - struct process* pcs = process_find_by_handle(hProcess); + struct process* pcs; + struct module_pair pair; + struct symt_ht* sym; + + pair.pcs = pcs = process_find_by_handle(hProcess); if (!pcs) return FALSE;
- if (!module_find_by_addr(pcs, StackFrame->InstructionOffset, DMT_UNKNOWN)) + pair.requested = module_find_by_addr(pair.pcs, StackFrame->InstructionOffset, DMT_UNKNOWN); + if (!module_get_debug(&pair)) return FALSE; return FALSE; + if ((sym = symt_find_nearest(pair.effective, StackFrame->InstructionOffset)) == NULL) return FALSE; + if (sym->symt.tag != SymTagFunction) return FALSE; + pcs->localscope_pc = StackFrame->InstructionOffset; + pcs->localscope_symt = &sym->symt; + if (pcs->ctx_frame.ReturnOffset == StackFrame->ReturnOffset && pcs->ctx_frame.FrameOffset == StackFrame->FrameOffset && pcs->ctx_frame.StackOffset == StackFrame->StackOffset) diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h index 62f723f2366..1d26a1ec0d9 100644 --- a/dlls/dbghelp/dbghelp_private.h +++ b/dlls/dbghelp/dbghelp_private.h @@ -497,6 +497,8 @@ struct process ULONG_PTR dbg_hdr_addr;
IMAGEHLP_STACK_FRAME ctx_frame; + DWORD64 localscope_pc; + struct symt* localscope_symt;
unsigned buffer_size; void* buffer; diff --git a/dlls/dbghelp/dwarf.c b/dlls/dbghelp/dwarf.c index afcc2628f1e..3fa2fb314ee 100644 --- a/dlls/dbghelp/dwarf.c +++ b/dlls/dbghelp/dwarf.c @@ -3810,7 +3810,7 @@ static void dwarf2_location_compute(struct process* pcs, else { /* instruction pointer relative to compiland's start */ - ip = pcs->ctx_frame.InstructionOffset - ((struct symt_compiland*)func->container)->address; + ip = pcs->localscope_pc - ((struct symt_compiland*)func->container)->address;
if ((err = loc_compute_frame(pcs, modfmt, func, ip, head, &frame)) == 0) { diff --git a/dlls/dbghelp/symbol.c b/dlls/dbghelp/symbol.c index edfeb5909f0..c961b3ee8e5 100644 --- a/dlls/dbghelp/symbol.c +++ b/dlls/dbghelp/symbol.c @@ -1100,7 +1100,7 @@ static BOOL symt_enum_locals_helper(struct module_pair* pair, struct symt_function* func, const struct vector* v) { struct symt* lsym = NULL; - DWORD_PTR pc = pair->pcs->ctx_frame.InstructionOffset; + DWORD_PTR pc = pair->pcs->localscope_pc; unsigned int i; WCHAR* nameW; BOOL ret; @@ -1147,21 +1147,19 @@ static BOOL symt_enum_locals(struct process* pcs, const WCHAR* mask, const struct sym_enum* se) { struct module_pair pair; - struct symt_ht* sym; - DWORD_PTR pc = pcs->ctx_frame.InstructionOffset;
se->sym_info->SizeOfStruct = sizeof(*se->sym_info); se->sym_info->MaxNameLen = sizeof(se->buffer) - sizeof(SYMBOL_INFO);
pair.pcs = pcs; - pair.requested = module_find_by_addr(pair.pcs, pc, DMT_UNKNOWN); + pair.requested = module_find_by_addr(pair.pcs, pcs->localscope_pc, DMT_UNKNOWN); if (!module_get_debug(&pair)) return FALSE; - if ((sym = symt_find_nearest(pair.effective, pc)) == NULL) return FALSE;
- if (sym->symt.tag == SymTagFunction) + if (symt_check_tag(pcs->localscope_symt, SymTagFunction) || + symt_check_tag(pcs->localscope_symt, SymTagInlineSite)) { - return symt_enum_locals_helper(&pair, mask ? mask : L"*", se, (struct symt_function*)sym, - &((struct symt_function*)sym)->vchildren); + struct symt_function* func = (struct symt_function*)pcs->localscope_symt; + return symt_enum_locals_helper(&pair, mask ? mask : L"*", se, func, &func->vchildren); } return FALSE; }
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/dbghelp.c | 75 ++++++++++++++++++++++++++++++++---------------- dlls/dbghelp/module.c | 10 ++++++ 2 files changed, 59 insertions(+), 26 deletions(-)
diff --git a/dlls/dbghelp/dbghelp.c b/dlls/dbghelp/dbghelp.c index 64ceb447ee9..6c63d6eddcd 100644 --- a/dlls/dbghelp/dbghelp.c +++ b/dlls/dbghelp/dbghelp.c @@ -607,34 +607,27 @@ BOOL WINAPI SymSetContext(HANDLE hProcess, PIMAGEHLP_STACK_FRAME StackFrame, PIMAGEHLP_CONTEXT Context) { struct process* pcs; - struct module_pair pair; - struct symt_ht* sym; + BOOL same;
- pair.pcs = pcs = process_find_by_handle(hProcess); - if (!pcs) return FALSE; + if (!(pcs = process_find_by_handle(hProcess))) return FALSE; + same = pcs->ctx_frame.ReturnOffset == StackFrame->ReturnOffset && + pcs->ctx_frame.FrameOffset == StackFrame->FrameOffset && + pcs->ctx_frame.StackOffset == StackFrame->StackOffset;
- pair.requested = module_find_by_addr(pair.pcs, StackFrame->InstructionOffset, DMT_UNKNOWN); - if (!module_get_debug(&pair)) return FALSE; + if (!SymSetScopeFromAddr(hProcess, StackFrame->InstructionOffset)) return FALSE; - if ((sym = symt_find_nearest(pair.effective, StackFrame->InstructionOffset)) == NULL) return FALSE; - if (sym->symt.tag != SymTagFunction) return FALSE; - pcs->localscope_pc = StackFrame->InstructionOffset; - pcs->localscope_symt = &sym->symt;
- if (pcs->ctx_frame.ReturnOffset == StackFrame->ReturnOffset && - pcs->ctx_frame.FrameOffset == StackFrame->FrameOffset && - pcs->ctx_frame.StackOffset == StackFrame->StackOffset) + pcs->ctx_frame = *StackFrame; + if (same) { TRACE("Setting same frame {rtn=%I64x frm=%I64x stk=%I64x}\n", pcs->ctx_frame.ReturnOffset, pcs->ctx_frame.FrameOffset, pcs->ctx_frame.StackOffset); - pcs->ctx_frame.InstructionOffset = StackFrame->InstructionOffset; SetLastError(ERROR_SUCCESS); return FALSE; }
- pcs->ctx_frame = *StackFrame; /* Context is not (no longer?) used */ return TRUE; } @@ -644,11 +637,17 @@ BOOL WINAPI SymSetContext(HANDLE hProcess, PIMAGEHLP_STACK_FRAME StackFrame, */ BOOL WINAPI SymSetScopeFromAddr(HANDLE hProcess, ULONG64 addr) { - struct process* pcs; + struct module_pair pair; + struct symt_ht* sym;
- FIXME("(%p %#I64x): stub\n", hProcess, addr); + TRACE("(%p %#I64x): stub\n", hProcess, addr);
- if (!(pcs = process_find_by_handle(hProcess))) return FALSE; + if (!module_init_pair(&pair, hProcess, addr)) return FALSE; + if ((sym = symt_find_nearest(pair.effective, addr)) == NULL) return FALSE; + if (sym->symt.tag != SymTagFunction) return FALSE; + + pair.pcs->localscope_pc = addr; + pair.pcs->localscope_symt = &sym->symt; return TRUE; }
@@ -657,11 +656,18 @@ BOOL WINAPI SymSetScopeFromAddr(HANDLE hProcess, ULONG64 addr) */ BOOL WINAPI SymSetScopeFromIndex(HANDLE hProcess, ULONG64 addr, DWORD index) { - struct process* pcs; + struct module_pair pair; + struct symt* sym;
- FIXME("(%p %#I64x %u): stub\n", hProcess, addr, index); + TRACE("(%p %#I64x %u): stub\n", hProcess, addr, index); + + if (!module_init_pair(&pair, hProcess, addr)) return FALSE; + sym = symt_index2ptr(pair.effective, index); + if (!symt_check_tag(sym, SymTagFunction)) return FALSE; + + pair.pcs->localscope_pc = ((struct symt_function*)sym)->address; /* FIXME of FuncDebugStart when it exists? */ + pair.pcs->localscope_symt = sym;
- if (!(pcs = process_find_by_handle(hProcess))) return FALSE; return TRUE; }
@@ -670,12 +676,31 @@ BOOL WINAPI SymSetScopeFromIndex(HANDLE hProcess, ULONG64 addr, DWORD index) */ BOOL WINAPI SymSetScopeFromInlineContext(HANDLE hProcess, ULONG64 addr, DWORD inlinectx) { - struct process* pcs; + TRACE("(%p %I64x %x)\n", hProcess, addr, inlinectx);
- FIXME("(%p %#I64x %u): stub\n", hProcess, addr, inlinectx); + switch (IFC_MODE(inlinectx)) + { + case IFC_MODE_IGNORE: + case IFC_MODE_REGULAR: return SymSetScopeFromAddr(hProcess, addr); + case IFC_MODE_INLINE: + { + struct module_pair pair; + struct symt_inlinesite* inlined;
- if (!(pcs = process_find_by_handle(hProcess))) return FALSE; - return TRUE; + 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; + } }
/****************************************************************** diff --git a/dlls/dbghelp/module.c b/dlls/dbghelp/module.c index f0fd2a55016..8168e727c52 100644 --- a/dlls/dbghelp/module.c +++ b/dlls/dbghelp/module.c @@ -1048,7 +1048,15 @@ BOOL WINAPI SymUnloadModule64(HANDLE hProcess, DWORD64 BaseOfDll) if (!pcs) return FALSE; module = module_find_by_addr(pcs, BaseOfDll, DMT_UNKNOWN); if (!module) return FALSE; - return module_remove(pcs, module); + if (!module_remove(pcs, module)) return FALSE; + /* remove local scope if defined inside this module */ + if (pcs->localscope_pc >= module->module.BaseOfImage && + pcs->localscope_pc < module->module.BaseOfImage + module->module.ImageSize) + { + pcs->localscope_pc = 0; + pcs->localscope_symt = NULL; + } + return TRUE; }
/******************************************************************
as it's actually an absolute address
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/dbghelp_private.h | 2 +- dlls/dbghelp/symbol.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h index 1d26a1ec0d9..2278a007b76 100644 --- a/dlls/dbghelp/dbghelp_private.h +++ b/dlls/dbghelp/dbghelp_private.h @@ -519,7 +519,7 @@ struct line_info line_number; union { - ULONG_PTR pc_offset; /* if is_source_file isn't set */ + ULONG_PTR address; /* absolute, if is_source_file isn't set */ unsigned source_file; /* if is_source_file is set */ } u; }; diff --git a/dlls/dbghelp/symbol.c b/dlls/dbghelp/symbol.c index c961b3ee8e5..93669024951 100644 --- a/dlls/dbghelp/symbol.c +++ b/dlls/dbghelp/symbol.c @@ -435,7 +435,7 @@ void symt_add_func_line(struct module* module, struct symt_function* func, dli->is_first = 0; /* only a source file can be first */ dli->is_last = 1; dli->line_number = line_num; - dli->u.pc_offset = func->address + offset; + dli->u.address = func->address + offset; }
/****************************************************************** @@ -1871,9 +1871,9 @@ static BOOL get_line_from_addr(HANDLE hProcess, DWORD64 addr, dli = vector_at(&func->vlines, i); if (!dli->is_source_file) { - if (found || dli->u.pc_offset > addr) continue; + if (found || dli->u.address > addr) continue; intl->line_number = dli->line_number; - intl->address = dli->u.pc_offset; + intl->address = dli->u.address; intl->key = dli; found = TRUE; continue; @@ -2014,7 +2014,7 @@ static BOOL symt_get_func_line_prev(HANDLE hProcess, struct internal_line_t* int if (!li->is_source_file) { intl->line_number = li->line_number; - intl->address = li->u.pc_offset; + intl->address = li->u.address; intl->key = li; /* search source file */ for (srcli = li; !srcli->is_source_file; srcli--); @@ -2093,7 +2093,7 @@ static BOOL symt_get_func_line_next(HANDLE hProcess, struct internal_line_t* int if (!li->is_source_file) { intl->line_number = li->line_number; - intl->address = li->u.pc_offset; + intl->address = li->u.address; intl->key = li; return internal_line_set_nameA(pair.pcs, intl, (char*)source_get(pair.effective, srcli->u.source_file), FALSE); } @@ -2560,7 +2560,7 @@ BOOL WINAPI SymEnumLines(HANDLE hProcess, ULONG64 base, PCSTR compiland, sci.Key = dli; sci.Obj[0] = '\0'; /* FIXME */ sci.LineNumber = dli->line_number; - sci.Address = dli->u.pc_offset; + sci.Address = dli->u.address; if (!cb(&sci, user)) break; } }
used to be an offset to the start of function, but actually stored as an absolute address this avoids unnecessary computations
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/coff.c | 7 +------ dlls/dbghelp/dwarf.c | 2 +- dlls/dbghelp/msc.c | 5 ++--- dlls/dbghelp/stabs.c | 4 ++-- dlls/dbghelp/symbol.c | 8 ++++---- 5 files changed, 10 insertions(+), 16 deletions(-)
diff --git a/dlls/dbghelp/coff.c b/dlls/dbghelp/coff.c index 8684a493310..cc005a3bbc5 100644 --- a/dlls/dbghelp/coff.c +++ b/dlls/dbghelp/coff.c @@ -421,16 +421,11 @@ DECLSPEC_HIDDEN BOOL coff_process_info(const struct msc_debug_info* msc_dbg) { if (coff_files.files[j].entries[l+1]->tag == SymTagFunction) { - /* - * Add the line number. This is always relative to the - * start of the function, so we need to subtract that offset - * first. - */ symt_add_func_line(msc_dbg->module, (struct symt_function*)coff_files.files[j].entries[l+1], coff_files.files[j].compiland->source, linepnt->Linenumber, - msc_dbg->module->module.BaseOfImage + linepnt->Type.VirtualAddress - addr); + msc_dbg->module->module.BaseOfImage + linepnt->Type.VirtualAddress); } break; } diff --git a/dlls/dbghelp/dwarf.c b/dlls/dbghelp/dwarf.c index 3fa2fb314ee..7251cb65630 100644 --- a/dlls/dbghelp/dwarf.c +++ b/dlls/dbghelp/dwarf.c @@ -2526,7 +2526,7 @@ static void dwarf2_set_line_number(struct module* module, ULONG_PTR address, if (symt_check_tag(&symt->symt, SymTagFunction)) { func = (struct symt_function*)symt; - symt_add_func_line(module, func, *psrc, line, address - func->address); + symt_add_func_line(module, func, *psrc, line, address); } }
diff --git a/dlls/dbghelp/msc.c b/dlls/dbghelp/msc.c index c557cb24636..191e33e781f 100644 --- a/dlls/dbghelp/msc.c +++ b/dlls/dbghelp/msc.c @@ -1454,8 +1454,7 @@ static void codeview_snarf_linetab(const struct msc_debug_info* msc_dbg, const B break; } } - symt_add_func_line(msc_dbg->module, func, source, - linenos[k], addr - func->address); + symt_add_func_line(msc_dbg->module, func, source, linenos[k], addr); } } } @@ -1519,7 +1518,7 @@ static void codeview_snarf_linetab2(const struct msc_debug_info* msc_dbg, const { symt_add_func_line(msc_dbg->module, func, source, lines_blk->l[i].lineno ^ 0x80000000, - lines_blk->l[i].offset); + func->address + lines_blk->l[i].offset); } break; case LT2_FILES_BLOCK: /* skip */ diff --git a/dlls/dbghelp/stabs.c b/dlls/dbghelp/stabs.c index 9d7d5131fc4..647a71ec258 100644 --- a/dlls/dbghelp/stabs.c +++ b/dlls/dbghelp/stabs.c @@ -1168,7 +1168,7 @@ static void pending_flush(struct pending_list* pending, struct module* module, if (module->type == DMT_MACHO) pending->objs[i].u.line.offset -= func->address - pending->objs[i].u.line.load_offset; symt_add_func_line(module, func, pending->objs[i].u.line.source_idx, - pending->objs[i].u.line.line_num, pending->objs[i].u.line.offset); + pending->objs[i].u.line.line_num, func->address + pending->objs[i].u.line.offset); break; default: ERR("Unknown pending object tag %u\n", (unsigned)pending->objs[i].tag); @@ -1492,7 +1492,7 @@ BOOL stabs_parse(struct module* module, ULONG_PTR load_offset, if (module->type == DMT_MACHO) offset -= curr_func->address - load_offset; symt_add_func_line(module, curr_func, source_idx, - stab_ptr->n_desc, offset); + stab_ptr->n_desc, curr_func->address + offset); } else pending_add_line(&pending_func, source_idx, stab_ptr->n_desc, n_value, load_offset); diff --git a/dlls/dbghelp/symbol.c b/dlls/dbghelp/symbol.c index 93669024951..4fd9fda6619 100644 --- a/dlls/dbghelp/symbol.c +++ b/dlls/dbghelp/symbol.c @@ -391,7 +391,7 @@ struct symt_inlinesite* symt_new_inlinesite(struct module* module, }
void symt_add_func_line(struct module* module, struct symt_function* func, - unsigned source_idx, int line_num, ULONG_PTR offset) + unsigned source_idx, int line_num, ULONG_PTR addr) { struct line_info* dli; unsigned vlen; @@ -401,8 +401,8 @@ void symt_add_func_line(struct module* module, struct symt_function* func,
if (func == NULL || !(dbghelp_options & SYMOPT_LOAD_LINES)) return;
- TRACE_(dbghelp_symt)("(%p)%s:%lx %s:%u\n", - func, func->hash_elt.name, offset, + TRACE_(dbghelp_symt)("(%p)%s:%Ix %s:%u\n", + func, func->hash_elt.name, addr, source_get(module, source_idx), line_num);
assert(func->symt.tag == SymTagFunction || func->symt.tag == SymTagInlineSite); @@ -435,7 +435,7 @@ void symt_add_func_line(struct module* module, struct symt_function* func, dli->is_first = 0; /* only a source file can be first */ dli->is_last = 1; dli->line_number = line_num; - dli->u.address = func->address + offset; + dli->u.address = addr; }
/******************************************************************
(was incorrectly computed relative to start of function)
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/symbol.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/dlls/dbghelp/symbol.c b/dlls/dbghelp/symbol.c index 4fd9fda6619..459f282502a 100644 --- a/dlls/dbghelp/symbol.c +++ b/dlls/dbghelp/symbol.c @@ -1854,7 +1854,7 @@ static BOOL get_line_from_addr(HANDLE hProcess, DWORD64 addr, PDWORD pdwDisplacement, struct internal_line_t* intl) { struct line_info* dli = NULL; - BOOL found = FALSE; + struct line_info* found_dli = NULL; int i; struct module_pair pair; struct symt_ht* symt; @@ -1871,14 +1871,14 @@ static BOOL get_line_from_addr(HANDLE hProcess, DWORD64 addr, dli = vector_at(&func->vlines, i); if (!dli->is_source_file) { - if (found || dli->u.address > addr) continue; + if (found_dli || dli->u.address > addr) continue; intl->line_number = dli->line_number; intl->address = dli->u.address; intl->key = dli; - found = TRUE; + found_dli = dli; continue; } - if (found) + if (found_dli) { BOOL ret; if (dbghelp_opt_native) @@ -1892,7 +1892,7 @@ static BOOL get_line_from_addr(HANDLE hProcess, DWORD64 addr, ret = internal_line_set_nameW(pair.pcs, intl, dospath, TRUE); HeapFree( GetProcessHeap(), 0, dospath ); } - if (ret) *pdwDisplacement = intl->address - func->address; + if (ret) *pdwDisplacement = addr - found_dli->u.address; return ret; } }
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/symbol.c | 91 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 65 insertions(+), 26 deletions(-)
diff --git a/dlls/dbghelp/symbol.c b/dlls/dbghelp/symbol.c index 459f282502a..938dac2dd3c 100644 --- a/dlls/dbghelp/symbol.c +++ b/dlls/dbghelp/symbol.c @@ -1845,28 +1845,14 @@ static BOOL internal_line_set_nameW(struct process* pcs, struct internal_line_t* return TRUE; }
-/****************************************************************** - * get_line_from_addr - * - * fills source file information from an address - */ -static BOOL get_line_from_addr(HANDLE hProcess, DWORD64 addr, - PDWORD pdwDisplacement, struct internal_line_t* intl) +static BOOL get_line_from_function(struct module_pair* pair, struct symt_function* func, DWORD64 addr, + PDWORD pdwDisplacement, struct internal_line_t* intl) { struct line_info* dli = NULL; struct line_info* found_dli = NULL; int i; - struct module_pair pair; - struct symt_ht* symt; - struct symt_function* func; - - if (!module_init_pair(&pair, hProcess, addr)) return FALSE; - if ((symt = symt_find_nearest(pair.effective, addr)) == NULL) return FALSE;
- if (symt->symt.tag != SymTagFunction) return FALSE; - func = (struct symt_function*)symt; - - for (i=vector_length(&func->vlines)-1; i>=0; i--) + for (i = vector_length(&func->vlines) - 1; i >= 0; i--) { dli = vector_at(&func->vlines, i); if (!dli->is_source_file) @@ -1884,12 +1870,12 @@ static BOOL get_line_from_addr(HANDLE hProcess, DWORD64 addr, if (dbghelp_opt_native) { /* Return native file paths when using winedbg */ - ret = internal_line_set_nameA(pair.pcs, intl, (char*)source_get(pair.effective, dli->u.source_file), FALSE); + ret = internal_line_set_nameA(pair->pcs, intl, (char*)source_get(pair->effective, dli->u.source_file), FALSE); } else { - WCHAR *dospath = wine_get_dos_file_name(source_get(pair.effective, dli->u.source_file)); - ret = internal_line_set_nameW(pair.pcs, intl, dospath, TRUE); + WCHAR *dospath = wine_get_dos_file_name(source_get(pair->effective, dli->u.source_file)); + ret = internal_line_set_nameW(pair->pcs, intl, dospath, TRUE); HeapFree( GetProcessHeap(), 0, dospath ); } if (ret) *pdwDisplacement = addr - found_dli->u.address; @@ -1899,6 +1885,24 @@ static BOOL get_line_from_addr(HANDLE hProcess, DWORD64 addr, return FALSE; }
+/****************************************************************** + * get_line_from_addr + * + * fills source file information from an address + */ +static BOOL get_line_from_addr(HANDLE hProcess, DWORD64 addr, + PDWORD pdwDisplacement, struct internal_line_t* intl) +{ + struct module_pair pair; + struct symt_ht* symt; + + if (!module_init_pair(&pair, hProcess, addr)) return FALSE; + if ((symt = symt_find_nearest(pair.effective, addr)) == NULL) return FALSE; + + if (symt->symt.tag != SymTagFunction && symt->symt.tag != SymTagInlineSite) return FALSE; + return get_line_from_function(&pair, (struct symt_function*)symt, addr, pdwDisplacement, intl); +} + /*********************************************************************** * SymGetSymNext64 (DBGHELP.@) */ @@ -2697,16 +2701,45 @@ BOOL WINAPI SymFromInlineContextW(HANDLE hProcess, DWORD64 addr, ULONG inline_ct return ret; }
+static BOOL get_line_from_inline_context(HANDLE hProcess, DWORD64 addr, ULONG inline_ctx, DWORD64 mod_addr, PDWORD disp, + struct internal_line_t* intl) +{ + struct module_pair pair; + struct symt_inlinesite* inlined; + + if (!module_init_pair(&pair, hProcess, mod_addr ? mod_addr : addr)) return FALSE; + switch (IFC_MODE(inline_ctx)) + { + case IFC_MODE_INLINE: + inlined = symt_find_inlined_site(pair.effective, addr, inline_ctx); + if (inlined && get_line_from_function(&pair, &inlined->func, addr, disp, intl)) + return TRUE; + /* fall through: check if we can find line info at top function level */ + case IFC_MODE_IGNORE: + case IFC_MODE_REGULAR: + return get_line_from_addr(hProcess, addr, disp, intl); + default: + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } +} + /****************************************************************** * SymGetLineFromInlineContext (DBGHELP.@) * */ BOOL WINAPI SymGetLineFromInlineContext(HANDLE hProcess, DWORD64 addr, ULONG inline_ctx, DWORD64 mod_addr, PDWORD disp, PIMAGEHLP_LINE64 line) { - FIXME("(%p, %#I64x, 0x%x, %#I64x, %p, %p): stub!\n", + struct internal_line_t intl; + + TRACE("(%p, %#I64x, 0x%x, %#I64x, %p, %p): stub!\n", hProcess, addr, inline_ctx, mod_addr, disp, line); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; + + if (line->SizeOfStruct < sizeof(*line)) return FALSE; + init_internal_line(&intl, FALSE); + + if (!get_line_from_inline_context(hProcess, addr, inline_ctx, mod_addr, disp, &intl)) return FALSE; + return internal_line_copy_toA64(&intl, line); }
/****************************************************************** @@ -2715,8 +2748,14 @@ BOOL WINAPI SymGetLineFromInlineContext(HANDLE hProcess, DWORD64 addr, ULONG inl */ BOOL WINAPI SymGetLineFromInlineContextW(HANDLE hProcess, DWORD64 addr, ULONG inline_ctx, DWORD64 mod_addr, PDWORD disp, PIMAGEHLP_LINEW64 line) { - FIXME("(%p, %#I64x, 0x%x, %#I64x, %p, %p): stub!\n", + struct internal_line_t intl; + + TRACE("(%p, %#I64x, 0x%x, %#I64x, %p, %p): stub!\n", hProcess, addr, inline_ctx, mod_addr, disp, line); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; + + if (line->SizeOfStruct < sizeof(*line)) return FALSE; + init_internal_line(&intl, TRUE); + + if (!get_line_from_inline_context(hProcess, addr, inline_ctx, mod_addr, disp, &intl)) return FALSE; + return internal_line_copy_toW64(&intl, line); }
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/dwarf.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
diff --git a/dlls/dbghelp/dwarf.c b/dlls/dbghelp/dwarf.c index 7251cb65630..bd1a433ec30 100644 --- a/dlls/dbghelp/dwarf.c +++ b/dlls/dbghelp/dwarf.c @@ -2515,6 +2515,7 @@ static void dwarf2_set_line_number(struct module* module, ULONG_PTR address, const struct vector* v, unsigned file, unsigned line) { struct symt_function* func; + struct symt_inlinesite* inlined; struct symt_ht* symt; unsigned* psrc;
@@ -2526,6 +2527,19 @@ static void dwarf2_set_line_number(struct module* module, ULONG_PTR address, if (symt_check_tag(&symt->symt, SymTagFunction)) { func = (struct symt_function*)symt; + for (inlined = func->next_inlinesite; inlined; inlined = inlined->func.next_inlinesite) + { + int i; + for (i = 0; i < inlined->vranges.num_elts; ++i) + { + struct addr_range* ar = (struct addr_range*)vector_at(&inlined->vranges, i); + if (ar->low <= address && address < ar->high) + { + symt_add_func_line(module, &inlined->func, *psrc, line, address); + return; /* only add to lowest matching inline site */ + } + } + } symt_add_func_line(module, func, *psrc, line, address); } }
Eric Pouech eric.pouech@gmail.com writes:
The following series implements inline site and (local) scope contexts
V2:
- reorder patches to have full functionnalities earlier
- added the dwarf backend modifications
Alexandre, if you think this is too big for once, you can decide to split between those blocks: [01/08]: stack walk and symbol info for inline contexts (+ dwarf backend support) [09/10]: (local) scope management functions [11/15]: line info for inline context (+ dwarf backend support)
It's still mostly dead code in the first patches. Please try to only introduce helpers in the patch that is using them. If it makes the patches too large you need to find another way to split them. Adding functions in one patch and callers in another is not a meaningful split.