The following series: - replace quite a few uses of debugger's CPU with debuggee's one (of interest for WoW64 debugging where they're different) - support more pdb entries (inline sites, new local variable information)
A+ ---
Eric Pouech (13): tools/winedump/pdb: fix computation of signed integers in codeview symbol's annotations dbghelp: check that we don't add same line number twice dbghelp: attach a struct cpu* to every module dbghelp: use module's cpu word size instead of sizeof(void*) or sizeof(DWORD_PTR) dbghelp: rather use cpu from debuggee's modules than debugger's dbghelp/pdb: added new basic type to represent char8_t introduced in C++20 dbghelp/pdb: properly handle S_LOCAL codeview entries dbghelp/pdb: implement loc_compute for pdb backend dbghelp/pdb: introduce codeview_init_type_parse() to handle init of type streams dbghelp/pdb: let codeview_snarf() handle all module debug information dbghelp/pdb: added support for inline sites dbghelp/pdb: handle when a block in DEBUG_S_LINES subsection spreads across several symbols dbghelp/pdb: add line number to inline sites
dlls/dbghelp/dbghelp_private.h | 3 + dlls/dbghelp/dwarf.c | 57 ++- dlls/dbghelp/module.c | 9 +- dlls/dbghelp/msc.c | 812 ++++++++++++++++++++++++++++----- dlls/dbghelp/stabs.c | 6 +- dlls/dbghelp/symbol.c | 5 + include/cvconst.h | 3 +- include/wine/mscvpdb.h | 13 +- tools/winedump/msc.c | 9 +- 9 files changed, 755 insertions(+), 162 deletions(-)
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- tools/winedump/msc.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/tools/winedump/msc.c b/tools/winedump/msc.c index 79dd022a088..40daf4d50d5 100644 --- a/tools/winedump/msc.c +++ b/tools/winedump/msc.c @@ -1221,6 +1221,11 @@ static unsigned binannot_uncompress(const unsigned char** pptr) return res; }
+static inline int binannot_getsigned(unsigned i) +{ + return (i & 1) ? -(int)(i >> 1) : (i >> 1); +} + static void dump_binannot(const unsigned char* ba, const char* last, const char* pfx) { while (ba < (const unsigned char*)last) @@ -1248,7 +1253,7 @@ static void dump_binannot(const unsigned char* ba, const char* last, const char* printf("%sChangeFile %u\n", pfx, binannot_uncompress(&ba)); break; case BA_OP_ChangeLineOffset: - printf("%sChangeLineOffset %d\n", pfx, binannot_uncompress(&ba)); + printf("%sChangeLineOffset %d\n", pfx, binannot_getsigned(binannot_uncompress(&ba))); break; case BA_OP_ChangeLineEndDelta: printf("%sChangeLineEndDelta %u\n", pfx, binannot_uncompress(&ba)); @@ -1265,7 +1270,7 @@ static void dump_binannot(const unsigned char* ba, const char* last, const char* case BA_OP_ChangeCodeOffsetAndLineOffset: { unsigned p1 = binannot_uncompress(&ba); - printf("%sChangeCodeOffsetAndLineOffset %u %u (0x%x)\n", pfx, p1 & 0xf, p1 >> 4, p1); + printf("%sChangeCodeOffsetAndLineOffset %u %u (0x%x)\n", pfx, p1 & 0xf, binannot_getsigned(p1 >> 4), p1); } break; case BA_OP_ChangeCodeLengthAndCodeOffset:
This happens (at least) in dwarf debug info where there could be two entries with same source file and line number, but different column numbers (and we don't store columns)
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/symbol.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/dlls/dbghelp/symbol.c b/dlls/dbghelp/symbol.c index 7747aaae2ae..435d94bc8eb 100644 --- a/dlls/dbghelp/symbol.c +++ b/dlls/dbghelp/symbol.c @@ -418,6 +418,11 @@ void symt_add_func_line(struct module* module, struct symt_function* func, } vlen = vector_length(&func->vlines); prev = vlen ? vector_at(&func->vlines, vlen - 1) : NULL; + if (last_matches && prev && addr == prev->u.address) + { + WARN("Duplicate addition of line number in %s\n", func->hash_elt.name); + return; + } if (!last_matches) { /* we shouldn't have line changes on first line of function */
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/dbghelp_private.h | 3 +++ dlls/dbghelp/module.c | 3 +++ 2 files changed, 6 insertions(+)
diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h index 61173b34b5a..1e77ed49225 100644 --- a/dlls/dbghelp/dbghelp_private.h +++ b/dlls/dbghelp/dbghelp_private.h @@ -430,6 +430,8 @@ struct module_format } u; };
+struct cpu; + struct module { struct process* process; @@ -438,6 +440,7 @@ struct module struct module* next; enum module_type type : 16; unsigned short is_virtual : 1; + struct cpu* cpu; DWORD64 reloc_delta; WCHAR* real_path;
diff --git a/dlls/dbghelp/module.c b/dlls/dbghelp/module.c index 8168e727c52..65bdbb38fda 100644 --- a/dlls/dbghelp/module.c +++ b/dlls/dbghelp/module.c @@ -230,6 +230,9 @@ struct module* module_new(struct process* pcs, const WCHAR* name, module->addr_sorttab = NULL; module->num_sorttab = 0; module->num_symbols = 0; + module->cpu = cpu_find(machine); + if (!module->cpu) + module->cpu = dbghelp_current_cpu;
vector_init(&module->vsymt, sizeof(struct symt*), 128); vector_init(&module->vcustom_symt, sizeof(struct symt*), 16);
this fixes a couple of wrong pointer size computation when debugging a WoW64 process from a 64 bit debugger
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/dwarf.c | 7 ++++-- dlls/dbghelp/msc.c | 56 ++++++++++++++++++++++++++------------------------ dlls/dbghelp/stabs.c | 2 +- 3 files changed, 34 insertions(+), 31 deletions(-)
diff --git a/dlls/dbghelp/dwarf.c b/dlls/dbghelp/dwarf.c index d812e03f833..7ecd04d216e 100644 --- a/dlls/dbghelp/dwarf.c +++ b/dlls/dbghelp/dwarf.c @@ -1488,7 +1488,7 @@ static struct symt* dwarf2_parse_pointer_type(dwarf2_debug_info_t* di)
TRACE("%s\n", dwarf2_debug_di(di));
- if (!dwarf2_find_attribute(di, DW_AT_byte_size, &size)) size.u.uvalue = sizeof(void *); + if (!dwarf2_find_attribute(di, DW_AT_byte_size, &size)) size.u.uvalue = di->unit_ctx->module_ctx->module->cpu->word_size; ref_type = dwarf2_lookup_type(di); di->symt = &symt_new_pointer(di->unit_ctx->module_ctx->module, ref_type, size.u.uvalue)->symt; if (dwarf2_get_di_children(di)) FIXME("Unsupported children\n"); @@ -1645,7 +1645,7 @@ static struct symt* dwarf2_parse_unspecified_type(dwarf2_debug_info_t* di)
if (!dwarf2_find_attribute(di, DW_AT_name, &name)) name.u.string = "void"; - size.u.uvalue = sizeof(void *); + size.u.uvalue = di->unit_ctx->module_ctx->module->cpu->word_size;
basic = symt_new_basic(di->unit_ctx->module_ctx->module, btVoid, name.u.string, size.u.uvalue); di->symt = &basic->symt; @@ -1664,7 +1664,8 @@ static struct symt* dwarf2_parse_reference_type(dwarf2_debug_info_t* di)
ref_type = dwarf2_lookup_type(di); /* FIXME: for now, we hard-wire C++ references to pointers */ - di->symt = &symt_new_pointer(di->unit_ctx->module_ctx->module, ref_type, sizeof(void *))->symt; + di->symt = &symt_new_pointer(di->unit_ctx->module_ctx->module, ref_type, + di->unit_ctx->module_ctx->module->cpu->word_size)->symt;
if (dwarf2_get_di_children(di)) FIXME("Unsupported children\n");
diff --git a/dlls/dbghelp/msc.c b/dlls/dbghelp/msc.c index 97991be057f..a2d9f0bb368 100644 --- a/dlls/dbghelp/msc.c +++ b/dlls/dbghelp/msc.c @@ -139,6 +139,8 @@ static struct cv_defined_module*cv_current_module;
static void codeview_init_basic_types(struct module* module) { + unsigned ptrsz = module->cpu->word_size; + /* * These are the common builtin types that are used by VC++. */ @@ -228,32 +230,32 @@ static void codeview_init_basic_types(struct module* module) cv_basic_types[T_64PUINT8] = &symt_new_pointer(module, cv_basic_types[T_UINT8], 8)->symt; cv_basic_types[T_64PHRESULT]= &symt_new_pointer(module, cv_basic_types[T_HRESULT], 8)->symt;
- cv_basic_types[T_PVOID] = &symt_new_pointer(module, cv_basic_types[T_VOID], sizeof(void*))->symt; - cv_basic_types[T_PCHAR] = &symt_new_pointer(module, cv_basic_types[T_CHAR], sizeof(void*))->symt; - cv_basic_types[T_PSHORT] = &symt_new_pointer(module, cv_basic_types[T_SHORT], sizeof(void*))->symt; - cv_basic_types[T_PLONG] = &symt_new_pointer(module, cv_basic_types[T_LONG], sizeof(void*))->symt; - cv_basic_types[T_PQUAD] = &symt_new_pointer(module, cv_basic_types[T_QUAD], sizeof(void*))->symt; - cv_basic_types[T_PUCHAR] = &symt_new_pointer(module, cv_basic_types[T_UCHAR], sizeof(void*))->symt; - cv_basic_types[T_PUSHORT] = &symt_new_pointer(module, cv_basic_types[T_USHORT], sizeof(void*))->symt; - cv_basic_types[T_PULONG] = &symt_new_pointer(module, cv_basic_types[T_ULONG], sizeof(void*))->symt; - cv_basic_types[T_PUQUAD] = &symt_new_pointer(module, cv_basic_types[T_UQUAD], sizeof(void*))->symt; - cv_basic_types[T_PBOOL08] = &symt_new_pointer(module, cv_basic_types[T_BOOL08], sizeof(void*))->symt; - cv_basic_types[T_PBOOL16] = &symt_new_pointer(module, cv_basic_types[T_BOOL16], sizeof(void*))->symt; - cv_basic_types[T_PBOOL32] = &symt_new_pointer(module, cv_basic_types[T_BOOL32], sizeof(void*))->symt; - cv_basic_types[T_PBOOL64] = &symt_new_pointer(module, cv_basic_types[T_BOOL64], sizeof(void*))->symt; - cv_basic_types[T_PREAL32] = &symt_new_pointer(module, cv_basic_types[T_REAL32], sizeof(void*))->symt; - cv_basic_types[T_PREAL64] = &symt_new_pointer(module, cv_basic_types[T_REAL64], sizeof(void*))->symt; - cv_basic_types[T_PREAL80] = &symt_new_pointer(module, cv_basic_types[T_REAL80], sizeof(void*))->symt; - cv_basic_types[T_PRCHAR] = &symt_new_pointer(module, cv_basic_types[T_RCHAR], sizeof(void*))->symt; - cv_basic_types[T_PWCHAR] = &symt_new_pointer(module, cv_basic_types[T_WCHAR], sizeof(void*))->symt; - cv_basic_types[T_PCHAR16] = &symt_new_pointer(module, cv_basic_types[T_CHAR16], sizeof(void*))->symt; - cv_basic_types[T_PCHAR32] = &symt_new_pointer(module, cv_basic_types[T_CHAR32], sizeof(void*))->symt; - cv_basic_types[T_PINT2] = &symt_new_pointer(module, cv_basic_types[T_INT2], sizeof(void*))->symt; - cv_basic_types[T_PUINT2] = &symt_new_pointer(module, cv_basic_types[T_UINT2], sizeof(void*))->symt; - cv_basic_types[T_PINT4] = &symt_new_pointer(module, cv_basic_types[T_INT4], sizeof(void*))->symt; - cv_basic_types[T_PUINT4] = &symt_new_pointer(module, cv_basic_types[T_UINT4], sizeof(void*))->symt; - cv_basic_types[T_PINT8] = &symt_new_pointer(module, cv_basic_types[T_INT8], sizeof(void*))->symt; - cv_basic_types[T_PUINT8] = &symt_new_pointer(module, cv_basic_types[T_UINT8], sizeof(void*))->symt; + cv_basic_types[T_PVOID] = &symt_new_pointer(module, cv_basic_types[T_VOID], ptrsz)->symt; + cv_basic_types[T_PCHAR] = &symt_new_pointer(module, cv_basic_types[T_CHAR], ptrsz)->symt; + cv_basic_types[T_PSHORT] = &symt_new_pointer(module, cv_basic_types[T_SHORT], ptrsz)->symt; + cv_basic_types[T_PLONG] = &symt_new_pointer(module, cv_basic_types[T_LONG], ptrsz)->symt; + cv_basic_types[T_PQUAD] = &symt_new_pointer(module, cv_basic_types[T_QUAD], ptrsz)->symt; + cv_basic_types[T_PUCHAR] = &symt_new_pointer(module, cv_basic_types[T_UCHAR], ptrsz)->symt; + cv_basic_types[T_PUSHORT] = &symt_new_pointer(module, cv_basic_types[T_USHORT], ptrsz)->symt; + cv_basic_types[T_PULONG] = &symt_new_pointer(module, cv_basic_types[T_ULONG], ptrsz)->symt; + cv_basic_types[T_PUQUAD] = &symt_new_pointer(module, cv_basic_types[T_UQUAD], ptrsz)->symt; + cv_basic_types[T_PBOOL08] = &symt_new_pointer(module, cv_basic_types[T_BOOL08], ptrsz)->symt; + cv_basic_types[T_PBOOL16] = &symt_new_pointer(module, cv_basic_types[T_BOOL16], ptrsz)->symt; + cv_basic_types[T_PBOOL32] = &symt_new_pointer(module, cv_basic_types[T_BOOL32], ptrsz)->symt; + cv_basic_types[T_PBOOL64] = &symt_new_pointer(module, cv_basic_types[T_BOOL64], ptrsz)->symt; + cv_basic_types[T_PREAL32] = &symt_new_pointer(module, cv_basic_types[T_REAL32], ptrsz)->symt; + cv_basic_types[T_PREAL64] = &symt_new_pointer(module, cv_basic_types[T_REAL64], ptrsz)->symt; + cv_basic_types[T_PREAL80] = &symt_new_pointer(module, cv_basic_types[T_REAL80], ptrsz)->symt; + cv_basic_types[T_PRCHAR] = &symt_new_pointer(module, cv_basic_types[T_RCHAR], ptrsz)->symt; + cv_basic_types[T_PWCHAR] = &symt_new_pointer(module, cv_basic_types[T_WCHAR], ptrsz)->symt; + cv_basic_types[T_PCHAR16] = &symt_new_pointer(module, cv_basic_types[T_CHAR16], ptrsz)->symt; + cv_basic_types[T_PCHAR32] = &symt_new_pointer(module, cv_basic_types[T_CHAR32], ptrsz)->symt; + cv_basic_types[T_PINT2] = &symt_new_pointer(module, cv_basic_types[T_INT2], ptrsz)->symt; + cv_basic_types[T_PUINT2] = &symt_new_pointer(module, cv_basic_types[T_UINT2], ptrsz)->symt; + cv_basic_types[T_PINT4] = &symt_new_pointer(module, cv_basic_types[T_INT4], ptrsz)->symt; + cv_basic_types[T_PUINT4] = &symt_new_pointer(module, cv_basic_types[T_UINT4], ptrsz)->symt; + cv_basic_types[T_PINT8] = &symt_new_pointer(module, cv_basic_types[T_INT8], ptrsz)->symt; + cv_basic_types[T_PUINT8] = &symt_new_pointer(module, cv_basic_types[T_UINT8], ptrsz)->symt; }
static int leaf_as_variant(VARIANT* v, const unsigned short int* leaf) @@ -659,7 +661,7 @@ static struct symt* codeview_add_type_pointer(struct codeview_type_parse* ctp, return existing; } pointee = codeview_fetch_type(ctp, pointee_type, FALSE); - return &symt_new_pointer(ctp->module, pointee, sizeof(void *))->symt; + return &symt_new_pointer(ctp->module, pointee, ctp->module->cpu->word_size)->symt; }
static struct symt* codeview_add_type_array(struct codeview_type_parse* ctp, diff --git a/dlls/dbghelp/stabs.c b/dlls/dbghelp/stabs.c index 647a71ec258..f2b3e6d5c7d 100644 --- a/dlls/dbghelp/stabs.c +++ b/dlls/dbghelp/stabs.c @@ -804,7 +804,7 @@ static int stabs_pts_read_type_def(struct ParseTypedefData* ptd, const char* typ case '*': case '&': PTS_ABORTIF(ptd, stabs_pts_read_type_def(ptd, NULL, &ref_dt) == -1); - new_dt = &symt_new_pointer(ptd->module, ref_dt, sizeof(void*))->symt; + new_dt = &symt_new_pointer(ptd->module, ref_dt, ptd->module->cpu->word_size)->symt; break; case 'k': /* 'const' modifier */ case 'B': /* 'volatile' modifier */
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/dwarf.c | 50 +++++++++++++++++++++++++++---------------------- dlls/dbghelp/module.c | 6 +++--- dlls/dbghelp/stabs.c | 4 ++-- 3 files changed, 33 insertions(+), 27 deletions(-)
diff --git a/dlls/dbghelp/dwarf.c b/dlls/dbghelp/dwarf.c index 7ecd04d216e..90452d74eaf 100644 --- a/dlls/dbghelp/dwarf.c +++ b/dlls/dbghelp/dwarf.c @@ -812,7 +812,7 @@ static unsigned dwarf2_map_register(int regno, const struct module* module) FIXME("What the heck map reg 0x%x\n",regno); return 0; } - return dbghelp_current_cpu->map_dwarf_register(regno, module, FALSE); + return module->cpu->map_dwarf_register(regno, module, FALSE); }
static enum location_error @@ -847,8 +847,8 @@ compute_location(const struct module *module, const dwarf2_cuhead_t* head, DWORD cvreg = dwarf2_map_register(op - DW_OP_reg0, module); if (loc->reg != Wine_DW_no_register) FIXME("Only supporting one reg (%s/%d -> %s/%d)\n", - dbghelp_current_cpu->fetch_regname(loc->reg), loc->reg, - dbghelp_current_cpu->fetch_regname(cvreg), cvreg); + module->cpu->fetch_regname(loc->reg), loc->reg, + module->cpu->fetch_regname(cvreg), cvreg); loc->reg = cvreg; } loc->kind = loc_register; @@ -864,8 +864,8 @@ compute_location(const struct module *module, const dwarf2_cuhead_t* head, DWORD cvreg = dwarf2_map_register(op - DW_OP_breg0, module); if (loc->reg != Wine_DW_no_register) FIXME("Only supporting one breg (%s/%d -> %s/%d)\n", - dbghelp_current_cpu->fetch_regname(loc->reg), loc->reg, - dbghelp_current_cpu->fetch_regname(cvreg), cvreg); + module->cpu->fetch_regname(loc->reg), loc->reg, + module->cpu->fetch_regname(cvreg), cvreg); loc->reg = cvreg; } stack[++stk] = dwarf2_leb128_as_signed(ctx); @@ -938,7 +938,7 @@ compute_location(const struct module *module, const dwarf2_cuhead_t* head, case DW_OP_fbreg: if (loc->reg != Wine_DW_no_register) FIXME("Only supporting one reg (%s/%d -> -2)\n", - dbghelp_current_cpu->fetch_regname(loc->reg), loc->reg); + module->cpu->fetch_regname(loc->reg), loc->reg); if (frame && frame->kind == loc_register) { loc->kind = loc_regrel; @@ -2284,7 +2284,7 @@ static struct symt* dwarf2_parse_subprogram(dwarf2_debug_info_t* di) { /* on stack !! */ subpgm.frame.kind = loc_regrel; - subpgm.frame.reg = dbghelp_current_cpu->frame_regno; + subpgm.frame.reg = di->unit_ctx->module_ctx->module->cpu->frame_regno; subpgm.frame.offset = 0; } subpgm.non_computed_variable = FALSE; @@ -3256,7 +3256,7 @@ static void execute_cfa_instructions(struct module* module, dwarf2_traverse_cont if (!valid_reg(reg)) break; TRACE("%lx: DW_CFA_offset %s, %ld\n", info->ip, - dbghelp_current_cpu->fetch_regname(dbghelp_current_cpu->map_dwarf_register(reg, module, TRUE)), + module->cpu->fetch_regname(module->cpu->map_dwarf_register(reg, module, TRUE)), offset); info->state.regs[reg] = offset; info->state.rules[reg] = RULE_CFA_OFFSET; @@ -3268,7 +3268,7 @@ static void execute_cfa_instructions(struct module* module, dwarf2_traverse_cont if (!valid_reg(reg)) break; TRACE("%lx: DW_CFA_restore %s\n", info->ip, - dbghelp_current_cpu->fetch_regname(dbghelp_current_cpu->map_dwarf_register(reg, module, TRUE))); + module->cpu->fetch_regname(module->cpu->map_dwarf_register(reg, module, TRUE))); info->state.rules[reg] = RULE_UNSET; break; } @@ -3316,7 +3316,7 @@ static void execute_cfa_instructions(struct module* module, dwarf2_traverse_cont if (!valid_reg(reg)) break; TRACE("%lx: DW_CFA_offset_extended %s, %ld\n", info->ip, - dbghelp_current_cpu->fetch_regname(dbghelp_current_cpu->map_dwarf_register(reg, module, TRUE)), + module->cpu->fetch_regname(module->cpu->map_dwarf_register(reg, module, TRUE)), offset); info->state.regs[reg] = offset; info->state.rules[reg] = RULE_CFA_OFFSET; @@ -3328,7 +3328,7 @@ static void execute_cfa_instructions(struct module* module, dwarf2_traverse_cont if (!valid_reg(reg)) break; TRACE("%lx: DW_CFA_restore_extended %s\n", info->ip, - dbghelp_current_cpu->fetch_regname(dbghelp_current_cpu->map_dwarf_register(reg, module, TRUE))); + module->cpu->fetch_regname(module->cpu->map_dwarf_register(reg, module, TRUE))); info->state.rules[reg] = RULE_UNSET; break; } @@ -3338,7 +3338,7 @@ static void execute_cfa_instructions(struct module* module, dwarf2_traverse_cont if (!valid_reg(reg)) break; TRACE("%lx: DW_CFA_undefined %s\n", info->ip, - dbghelp_current_cpu->fetch_regname(dbghelp_current_cpu->map_dwarf_register(reg, module, TRUE))); + module->cpu->fetch_regname(module->cpu->map_dwarf_register(reg, module, TRUE))); info->state.rules[reg] = RULE_UNDEFINED; break; } @@ -3348,7 +3348,7 @@ static void execute_cfa_instructions(struct module* module, dwarf2_traverse_cont if (!valid_reg(reg)) break; TRACE("%lx: DW_CFA_same_value %s\n", info->ip, - dbghelp_current_cpu->fetch_regname(dbghelp_current_cpu->map_dwarf_register(reg, module, TRUE))); + module->cpu->fetch_regname(module->cpu->map_dwarf_register(reg, module, TRUE))); info->state.regs[reg] = reg; info->state.rules[reg] = RULE_SAME; break; @@ -3360,8 +3360,8 @@ static void execute_cfa_instructions(struct module* module, dwarf2_traverse_cont if (!valid_reg(reg) || !valid_reg(reg2)) break; TRACE("%lx: DW_CFA_register %s == %s\n", info->ip, - dbghelp_current_cpu->fetch_regname(dbghelp_current_cpu->map_dwarf_register(reg, module, TRUE)), - dbghelp_current_cpu->fetch_regname(dbghelp_current_cpu->map_dwarf_register(reg2, module, TRUE))); + module->cpu->fetch_regname(module->cpu->map_dwarf_register(reg, module, TRUE)), + module->cpu->fetch_regname(module->cpu->map_dwarf_register(reg2, module, TRUE))); info->state.regs[reg] = reg2; info->state.rules[reg] = RULE_OTHER_REG; break; @@ -3389,7 +3389,7 @@ static void execute_cfa_instructions(struct module* module, dwarf2_traverse_cont if (!valid_reg(reg)) break; TRACE("%lx: DW_CFA_def_cfa %s, %ld\n", info->ip, - dbghelp_current_cpu->fetch_regname(dbghelp_current_cpu->map_dwarf_register(reg, module, TRUE)), + module->cpu->fetch_regname(module->cpu->map_dwarf_register(reg, module, TRUE)), offset); info->state.cfa_reg = reg; info->state.cfa_offset = offset; @@ -3402,7 +3402,7 @@ static void execute_cfa_instructions(struct module* module, dwarf2_traverse_cont if (!valid_reg(reg)) break; TRACE("%lx: DW_CFA_def_cfa_register %s\n", info->ip, - dbghelp_current_cpu->fetch_regname(dbghelp_current_cpu->map_dwarf_register(reg, module, TRUE))); + module->cpu->fetch_regname(module->cpu->map_dwarf_register(reg, module, TRUE))); info->state.cfa_reg = reg; info->state.cfa_rule = RULE_CFA_OFFSET; break; @@ -3436,7 +3436,7 @@ static void execute_cfa_instructions(struct module* module, dwarf2_traverse_cont if (!valid_reg(reg)) break; TRACE("%lx: DW_CFA_%sexpression %s %lx-%lx\n", info->ip, (op == DW_CFA_expression) ? "" : "val_", - dbghelp_current_cpu->fetch_regname(dbghelp_current_cpu->map_dwarf_register(reg, module, TRUE)), + module->cpu->fetch_regname(module->cpu->map_dwarf_register(reg, module, TRUE)), expr, expr + len); info->state.regs[reg] = expr; info->state.rules[reg] = (op == DW_CFA_expression) ? RULE_EXPRESSION : RULE_VAL_EXPRESSION; @@ -3465,6 +3465,7 @@ static DWORD64 get_context_reg(const struct module* module, struct cpu_stack_wal unsigned regno = csw->cpu->map_dwarf_register(dw_reg, module, TRUE), sz; void* ptr = csw->cpu->fetch_context_reg(context, regno, &sz);
+ if (csw->cpu != module->cpu) FIXME("mismatch in cpu\n"); if (sz == 8) return *(DWORD64 *)ptr; else if (sz == 4) @@ -3481,6 +3482,7 @@ static void set_context_reg(const struct module* module, struct cpu_stack_walk* unsigned regno = csw->cpu->map_dwarf_register(dw_reg, module, TRUE), sz; ULONG_PTR* ptr = csw->cpu->fetch_context_reg(context, regno, &sz);
+ if (csw->cpu != module->cpu) FIXME("mismatch in cpu\n"); if (isdebuggee) { char tmp[16]; @@ -3518,6 +3520,7 @@ static void copy_context_reg(const struct module* module, struct cpu_stack_walk ULONG_PTR* ptrdst = csw->cpu->fetch_context_reg(dstcontext, regdstno, &szdst); ULONG_PTR* ptrsrc = csw->cpu->fetch_context_reg(srccontext, regsrcno, &szsrc);
+ if (csw->cpu != module->cpu) FIXME("mismatch in cpu\n"); if (szdst != szsrc) { FIXME("Cannot copy register %lu/%u => %lu/%u because of size mismatch (%u => %u)\n", @@ -3536,6 +3539,7 @@ static ULONG_PTR eval_expression(const struct module* module, struct cpu_stack_w int sp = -1; ULONG_PTR len;
+ if (csw->cpu != module->cpu) FIXME("mismatch in cpu\n"); ctx.data = zp; ctx.end_data = zp + 4; len = dwarf2_leb128_as_unsigned(&ctx); @@ -3647,6 +3651,7 @@ static void apply_frame_state(const struct module* module, struct cpu_stack_walk ULONG_PTR value; union ctx new_context = *context;
+ if (csw->cpu != module->cpu) FIXME("mismatch in cpu\n"); switch (state->cfa_rule) { case RULE_EXPRESSION: @@ -3756,6 +3761,7 @@ BOOL dwarf2_virtual_unwind(struct cpu_stack_walk *csw, ULONG_PTR ip, struct frame_info info;
if (!module_init_pair(&pair, csw->hProcess, ip)) return FALSE; + if (csw->cpu != pair.effective->cpu) FIXME("mismatch in cpu\n"); if (!dwarf2_fetch_frame_info(pair.effective, csw->cpu, ip, &info)) return FALSE;
/* if at very beginning of function, return and use default unwinder */ @@ -3773,15 +3779,15 @@ static BOOL compute_call_frame_cfa(struct module* module, ULONG_PTR ip, struct l { struct frame_info info;
- if (!dwarf2_fetch_frame_info(module, dbghelp_current_cpu, ip, &info)) return FALSE; + if (!dwarf2_fetch_frame_info(module, module->cpu, ip, &info)) return FALSE;
/* beginning of function, or no available dwarf information ? */ if (ip == info.ip || info.state.rules[info.retaddr_reg] == RULE_UNSET) { /* fake the default unwinder */ frame->kind = loc_regrel; - frame->reg = dbghelp_current_cpu->frame_regno; - frame->offset = dbghelp_current_cpu->word_size; /* FIXME stack direction */ + frame->reg = module->cpu->frame_regno; + frame->offset = module->cpu->word_size; /* FIXME stack direction */ } else { @@ -3798,7 +3804,7 @@ static BOOL compute_call_frame_cfa(struct module* module, ULONG_PTR ip, struct l return FALSE; default: frame->kind = loc_regrel; - frame->reg = dbghelp_current_cpu->map_dwarf_register(info.state.cfa_reg, module, TRUE); + frame->reg = module->cpu->map_dwarf_register(info.state.cfa_reg, module, TRUE); frame->offset = info.state.cfa_offset; break; } diff --git a/dlls/dbghelp/module.c b/dlls/dbghelp/module.c index 65bdbb38fda..302f85b0747 100644 --- a/dlls/dbghelp/module.c +++ b/dlls/dbghelp/module.c @@ -1480,11 +1480,11 @@ PVOID WINAPI SymFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase) struct process* pcs = process_find_by_handle(hProcess); struct module* module;
- if (!pcs || !dbghelp_current_cpu->find_runtime_function) return NULL; + if (!pcs) return NULL; module = module_find_by_addr(pcs, AddrBase, DMT_UNKNOWN); - if (!module) return NULL; + if (!module || !module->cpu->find_runtime_function) return NULL;
- return dbghelp_current_cpu->find_runtime_function(module, AddrBase); + return module->cpu->find_runtime_function(module, AddrBase); }
static BOOL native_synchronize_module_list(struct process* pcs) diff --git a/dlls/dbghelp/stabs.c b/dlls/dbghelp/stabs.c index f2b3e6d5c7d..931102c4fb3 100644 --- a/dlls/dbghelp/stabs.c +++ b/dlls/dbghelp/stabs.c @@ -1396,7 +1396,7 @@ BOOL stabs_parse(struct module* module, ULONG_PTR load_offset, continue; } loc.kind = loc_regrel; - loc.reg = dbghelp_current_cpu->frame_regno; + loc.reg = module->cpu->frame_regno; loc.offset = n_value; symt_add_func_local(module, curr_func, (int)n_value >= 0 ? DataIsParam : DataIsLocal, @@ -1476,7 +1476,7 @@ BOOL stabs_parse(struct module* module, ULONG_PTR load_offset, case N_LSYM: /* These are local variables */ loc.kind = loc_regrel; - loc.reg = dbghelp_current_cpu->frame_regno; + loc.reg = module->cpu->frame_regno; loc.offset = n_value; if (curr_func != NULL) pending_add_var(&pending_block, ptr, DataIsLocal, &loc); break;
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/msc.c | 4 ++++ include/cvconst.h | 3 ++- include/wine/mscvpdb.h | 7 +++++++ 3 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/dlls/dbghelp/msc.c b/dlls/dbghelp/msc.c index a2d9f0bb368..3a62736e7ed 100644 --- a/dlls/dbghelp/msc.c +++ b/dlls/dbghelp/msc.c @@ -166,6 +166,7 @@ static void codeview_init_basic_types(struct module* module) cv_basic_types[T_WCHAR] = &symt_new_basic(module, btWChar, "wchar_t", 2)->symt; cv_basic_types[T_CHAR16] = &symt_new_basic(module, btChar16,"char16_t", 2)->symt; cv_basic_types[T_CHAR32] = &symt_new_basic(module, btChar32,"char32_t", 4)->symt; + cv_basic_types[T_CHAR8] = &symt_new_basic(module, btChar8, "char8_t", 1)->symt; cv_basic_types[T_INT2] = &symt_new_basic(module, btInt, "INT2", 2)->symt; cv_basic_types[T_UINT2] = &symt_new_basic(module, btUInt, "UINT2", 2)->symt; cv_basic_types[T_INT4] = &symt_new_basic(module, btInt, "INT4", 4)->symt; @@ -194,6 +195,7 @@ static void codeview_init_basic_types(struct module* module) cv_basic_types[T_32PWCHAR] = &symt_new_pointer(module, cv_basic_types[T_WCHAR], 4)->symt; cv_basic_types[T_32PCHAR16] = &symt_new_pointer(module, cv_basic_types[T_CHAR16], 4)->symt; cv_basic_types[T_32PCHAR32] = &symt_new_pointer(module, cv_basic_types[T_CHAR32], 4)->symt; + cv_basic_types[T_32PCHAR8] = &symt_new_pointer(module, cv_basic_types[T_CHAR8], 4)->symt; cv_basic_types[T_32PINT2] = &symt_new_pointer(module, cv_basic_types[T_INT2], 4)->symt; cv_basic_types[T_32PUINT2] = &symt_new_pointer(module, cv_basic_types[T_UINT2], 4)->symt; cv_basic_types[T_32PINT4] = &symt_new_pointer(module, cv_basic_types[T_INT4], 4)->symt; @@ -222,6 +224,7 @@ static void codeview_init_basic_types(struct module* module) cv_basic_types[T_64PWCHAR] = &symt_new_pointer(module, cv_basic_types[T_WCHAR], 8)->symt; cv_basic_types[T_64PCHAR16] = &symt_new_pointer(module, cv_basic_types[T_CHAR16], 8)->symt; cv_basic_types[T_64PCHAR32] = &symt_new_pointer(module, cv_basic_types[T_CHAR32], 8)->symt; + cv_basic_types[T_64PCHAR8] = &symt_new_pointer(module, cv_basic_types[T_CHAR8], 8)->symt; cv_basic_types[T_64PINT2] = &symt_new_pointer(module, cv_basic_types[T_INT2], 8)->symt; cv_basic_types[T_64PUINT2] = &symt_new_pointer(module, cv_basic_types[T_UINT2], 8)->symt; cv_basic_types[T_64PINT4] = &symt_new_pointer(module, cv_basic_types[T_INT4], 8)->symt; @@ -250,6 +253,7 @@ static void codeview_init_basic_types(struct module* module) cv_basic_types[T_PWCHAR] = &symt_new_pointer(module, cv_basic_types[T_WCHAR], ptrsz)->symt; cv_basic_types[T_PCHAR16] = &symt_new_pointer(module, cv_basic_types[T_CHAR16], ptrsz)->symt; cv_basic_types[T_PCHAR32] = &symt_new_pointer(module, cv_basic_types[T_CHAR32], ptrsz)->symt; + cv_basic_types[T_PCHAR8] = &symt_new_pointer(module, cv_basic_types[T_CHAR8], ptrsz)->symt; cv_basic_types[T_PINT2] = &symt_new_pointer(module, cv_basic_types[T_INT2], ptrsz)->symt; cv_basic_types[T_PUINT2] = &symt_new_pointer(module, cv_basic_types[T_UINT2], ptrsz)->symt; cv_basic_types[T_PINT4] = &symt_new_pointer(module, cv_basic_types[T_INT4], ptrsz)->symt; diff --git a/include/cvconst.h b/include/cvconst.h index 82929dda772..9536ee8202d 100644 --- a/include/cvconst.h +++ b/include/cvconst.h @@ -91,7 +91,8 @@ enum BasicType btBSTR = 30, btHresult = 31, btChar16 = 32, - btChar32 = 33 + btChar32 = 33, + btChar8 = 34, };
/* kind of UDT */ diff --git a/include/wine/mscvpdb.h b/include/wine/mscvpdb.h index e199aff785f..1a173c097d7 100644 --- a/include/wine/mscvpdb.h +++ b/include/wine/mscvpdb.h @@ -945,6 +945,7 @@ union codeview_fieldtype #define T_UINT8 0x0077 /* 64-bit unsigned int */ #define T_CHAR16 0x007a /* 16-bit unicode char */ #define T_CHAR32 0x007b /* 32-bit unicode char */ +#define T_CHAR8 0x007c /* 8-bit unicode char (C++ 20) */
/* near pointers to basic types */ #define T_PVOID 0x0103 /* near pointer to void */ @@ -979,6 +980,7 @@ union codeview_fieldtype #define T_PUINT8 0x0177 /* Near pointer to 64-bit unsigned int */ #define T_PCHAR16 0x017a /* Near pointer to 16-bit unicode char */ #define T_PCHAR32 0x017b /* Near pointer to 32-bit unicode char */ +#define T_PCHAR8 0x017c /* Near pointer to 8-bit unicode char */
/* far pointers to basic types */ #define T_PFVOID 0x0203 /* Far pointer to void */ @@ -1013,6 +1015,7 @@ union codeview_fieldtype #define T_PFUINT8 0x0277 /* Far pointer to 64-bit unsigned int */ #define T_PFCHAR16 0x027a /* Far pointer to 16-bit unicode char */ #define T_PFCHAR32 0x027b /* Far pointer to 32-bit unicode char */ +#define T_PFCHAR8 0x027c /* Far pointer to 8-bit unicode char */
/* huge pointers to basic types */ #define T_PHVOID 0x0303 /* Huge pointer to void */ @@ -1047,6 +1050,7 @@ union codeview_fieldtype #define T_PHUINT8 0x0377 /* Huge pointer to 64-bit unsigned int */ #define T_PHCHAR16 0x037a /* Huge pointer to 16-bit unicode char */ #define T_PHCHAR32 0x037b /* Huge pointer to 32-bit unicode char */ +#define T_PHCHAR8 0x037c /* Huge pointer to 8-bit unicode char */
/* 32-bit near pointers to basic types */ #define T_32PVOID 0x0403 /* 32-bit near pointer to void */ @@ -1082,6 +1086,7 @@ union codeview_fieldtype #define T_32PUINT8 0x0477 /* 16:32 near pointer to 64-bit unsigned int */ #define T_32PCHAR16 0x047a /* 16:32 near pointer to 16-bit unicode char */ #define T_32PCHAR32 0x047b /* 16:32 near pointer to 32-bit unicode char */ +#define T_32PCHAR8 0x047c /* 16:32 near pointer to 8-bit unicode char */
/* 32-bit far pointers to basic types */ #define T_32PFVOID 0x0503 /* 32-bit far pointer to void */ @@ -1117,6 +1122,7 @@ union codeview_fieldtype #define T_32PFUINT8 0x0577 /* 16:32 far pointer to 64-bit unsigned int */ #define T_32PFCHAR16 0x057a /* 16:32 far pointer to 16-bit unicode char */ #define T_32PFCHAR32 0x057b /* 16:32 far pointer to 32-bit unicode char */ +#define T_32PFCHAR8 0x057c /* 16:32 far pointer to 8-bit unicode char */
/* 64-bit near pointers to basic types */ #define T_64PVOID 0x0603 /* 64-bit near pointer to void */ @@ -1152,6 +1158,7 @@ union codeview_fieldtype #define T_64PUINT8 0x0677 /* 64 near pointer to 64-bit unsigned int */ #define T_64PCHAR16 0x067a /* 64 near pointer to 16-bit unicode char */ #define T_64PCHAR32 0x067b /* 64 near pointer to 32-bit unicode char */ +#define T_64PCHAR8 0x067c /* 64 near pointer to 8-bit unicode char */
/* counts, bit masks, and shift values needed to access various parts of the built-in type numbers */ #define T_MAXPREDEFINEDTYPE 0x0580 /* maximum type index for all built-in types */
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/msc.c | 180 +++++++++++++++++++++++++++++++++++++++++++++++- include/wine/mscvpdb.h | 6 +- 2 files changed, 181 insertions(+), 5 deletions(-)
diff --git a/dlls/dbghelp/msc.c b/dlls/dbghelp/msc.c index 3a62736e7ed..0c58e5fc14f 100644 --- a/dlls/dbghelp/msc.c +++ b/dlls/dbghelp/msc.c @@ -88,6 +88,8 @@ struct pdb_module_info struct pdb_file_info pdb_files[CV_MAX_MODULES]; };
+#define loc_cv_local_range (loc_user + 0) /* loc.offset contain the copy of all defrange* Codeview records following S_LOCAL */ + /*======================================================================== * Debug file access helper routines */ @@ -1581,6 +1583,24 @@ static ULONG_PTR codeview_get_address(const struct msc_debug_info* msc_dbg, codeview_map_offset(msc_dbg, sectp[seg-1].VirtualAddress + offset); }
+static BOOL func_has_local(struct symt_function* func, const char* name) +{ + int i; + + for (i = 0; i < func->vchildren.num_elts; ++i) + { + struct symt* p = *(struct symt**)vector_at(&func->vchildren, i); + if (symt_check_tag(p, SymTagData) && !strcmp(((struct symt_data*)p)->hash_elt.name, name)) + return TRUE; + } + return FALSE; +} + +static const union codeview_symbol* get_next_sym(const union codeview_symbol* sym) +{ + return (const union codeview_symbol*)((const char*)sym + sym->generic.len + 2); +} + static inline void codeview_add_variable(const struct msc_debug_info* msc_dbg, struct symt_compiland* compiland, const char* name, @@ -1603,6 +1623,135 @@ static inline void codeview_add_variable(const struct msc_debug_info* msc_dbg, } }
+struct cv_local_info +{ + unsigned short kind; /* the S_DEFRANGE* */ + unsigned short ngaps; /* number of gaps */ + unsigned short reg; + unsigned short rangelen; /* after start */ + short offset; + DWORD_PTR start; + struct cv_addr_gap gaps[0]; +}; + +static const struct cv_addr_gap* codeview_get_gaps(const union codeview_symbol* symrange) +{ + const struct cv_addr_gap* gap; + switch (symrange->generic.id) + { + case S_DEFRANGE: gap = symrange->defrange_v3.gaps; break; + case S_DEFRANGE_SUBFIELD: gap = symrange->defrange_subfield_v3.gaps; break; + case S_DEFRANGE_REGISTER: gap = symrange->defrange_register_v3.gaps; break; + case S_DEFRANGE_FRAMEPOINTER_REL: gap = symrange->defrange_frameptrrel_v3.gaps; break; + case S_DEFRANGE_SUBFIELD_REGISTER: gap = symrange->defrange_subfield_register_v3.gaps; break; + case S_DEFRANGE_REGISTER_REL: gap = symrange->defrange_registerrel_v3.gaps; break; + /* no gaps for that one */ + case S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE: + default: return NULL; + } + return gap != (const struct cv_addr_gap*)get_next_sym(symrange) ? gap : NULL; +} + +static void codeview_xform_range(const struct msc_debug_info* msc_dbg, + struct cv_local_info* locinfo, + const struct cv_addr_range* adrange) +{ + locinfo->start = codeview_get_address(msc_dbg, adrange->isectStart, adrange->offStart); + locinfo->rangelen = adrange->cbRange; +} + +static unsigned codeview_transform_defrange(const struct msc_debug_info* msc_dbg, + struct symt_function* curr_func, + const union codeview_symbol* sym, + struct location* loc) +{ + const union codeview_symbol* first_symrange = get_next_sym(sym); + const union codeview_symbol* symrange; + const struct cv_addr_gap* gap; + unsigned len, alloc = sizeof(DWORD); /* for terminating kind = 0 */ + unsigned char* ptr; + + /* we need to transform the cv_addr_range into cv_local_info */ + for (symrange = first_symrange; + symrange->generic.id >= S_DEFRANGE && symrange->generic.id <= S_DEFRANGE_REGISTER_REL; + symrange = get_next_sym(symrange)) + { + gap = codeview_get_gaps(symrange); + alloc += sizeof(struct cv_local_info) + + (gap ? (const char*)get_next_sym(symrange) - (const char*)gap : 0); + } + /* total length of all S_DEFRANGE* records (in bytes) following S_LOCAL */ + len = (const char*)symrange - (const char*)first_symrange; + + ptr = pool_alloc(&msc_dbg->module->pool, alloc); + if (ptr) + { + struct cv_local_info* locinfo = (struct cv_local_info*)ptr; + + loc->kind = loc_cv_local_range; + loc->offset = (DWORD_PTR)ptr; + /* transform the cv_addr_range into cv_local_info */ + for (symrange = first_symrange; + symrange->generic.id >= S_DEFRANGE && symrange->generic.id <= S_DEFRANGE_REGISTER_REL; + symrange = get_next_sym(symrange)) + { + locinfo->kind = symrange->generic.id; + switch (symrange->generic.id) + { + case S_DEFRANGE: + case S_DEFRANGE_SUBFIELD: + /* FIXME: transformation unsupported; let loc_compute bark if actually needed */ + break; + case S_DEFRANGE_REGISTER: + locinfo->reg = symrange->defrange_register_v3.reg; + codeview_xform_range(msc_dbg, locinfo, &symrange->defrange_register_v3.range); + break; + case S_DEFRANGE_FRAMEPOINTER_REL: + locinfo->offset = symrange->defrange_frameptrrel_v3.offFramePointer; + codeview_xform_range(msc_dbg, locinfo, &symrange->defrange_frameptrrel_v3.range); + break; + case S_DEFRANGE_SUBFIELD_REGISTER: + locinfo->reg = symrange->defrange_subfield_register_v3.reg; + locinfo->offset = symrange->defrange_subfield_register_v3.offParent; + codeview_xform_range(msc_dbg, locinfo, &symrange->defrange_subfield_register_v3.range); + break; + case S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE: + locinfo->offset = symrange->defrange_frameptr_relfullscope_v3.offFramePointer; + locinfo->start = curr_func->address; + locinfo->rangelen = curr_func->size; + break; + case S_DEFRANGE_REGISTER_REL: + locinfo->reg = symrange->defrange_registerrel_v3.baseReg; + locinfo->offset = symrange->defrange_registerrel_v3.offBasePointer; + codeview_xform_range(msc_dbg, locinfo, &symrange->defrange_registerrel_v3.range); + break; + default: + assert(0); + } + gap = codeview_get_gaps(symrange); + if (gap) + { + unsigned gaplen = (const char*)get_next_sym(symrange) - (const char*)gap; + locinfo->ngaps = gaplen / sizeof(*gap); + memcpy(locinfo->gaps, gap, gaplen); + locinfo = (struct cv_local_info*)((unsigned char*)(locinfo + 1) + gaplen); + } + else + { + locinfo->ngaps = 0; + locinfo++; + } + } + *(DWORD*)locinfo = 0; /* store terminating kind == 0 */ + } + else + { + loc->kind = loc_error; + loc->reg = loc_err_internal; + } + return len; +} + static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg, const BYTE* root, int offset, int size, BOOL do_globals) { @@ -1774,6 +1923,8 @@ static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg, const BYTE* roo terminate_string(&sym->stack_v2.p_name)); break; case S_BPREL32: + /* S_BPREL32 can be present after S_LOCAL; prefer S_LOCAL when present */ + if (func_has_local(curr_func, sym->stack_v3.name)) break; loc.kind = loc_regrel; /* Yes, it's i386 dependent, but that's the symbol purpose. S_REGREL is used on other CPUs */ loc.reg = CV_REG_EBP; @@ -1785,6 +1936,8 @@ static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg, const BYTE* roo sym->stack_v3.name); break; case S_REGREL32: + /* S_REGREL32 can be present after S_LOCAL; prefer S_LOCAL when present */ + if (func_has_local(curr_func, sym->regrel_v3.name)) break; loc.kind = loc_regrel; loc.reg = sym->regrel_v3.reg; loc.offset = sym->regrel_v3.offset; @@ -1815,6 +1968,8 @@ static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg, const BYTE* roo terminate_string(&sym->register_v2.p_name)); break; case S_REGISTER: + /* S_REGISTER can be present after S_LOCAL; prefer S_LOCAL when present */ + if (func_has_local(curr_func, sym->register_v3.name)) break; loc.kind = loc_register; loc.reg = sym->register_v3.reg; loc.offset = 0; @@ -1989,6 +2144,14 @@ static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg, const BYTE* roo sym->udt_v3.name, sym->udt_v3.type); } break; + case S_LOCAL: + length += codeview_transform_defrange(msc_dbg, curr_func, sym, &loc); + symt_add_func_local(msc_dbg->module, curr_func, + sym->local_v3.varflags & 0x0001 ? DataIsParam : DataIsLocal, + &loc, block, + codeview_get_type(sym->local_v3.symtype, FALSE), + sym->local_v3.name); + break;
/* * These are special, in that they are always followed by an @@ -2027,8 +2190,11 @@ static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg, const BYTE* roo case S_SECTION: case S_COFFGROUP: case S_EXPORT: - case S_LOCAL: case S_CALLSITEINFO: + /* even if S_LOCAL groks all the S_DEFRANGE* records following itself, + * those kinds of records can also be present after a S_FILESTATIC record + * so silence them until (at least) S_FILESTATIC is supported + */ case S_DEFRANGE_REGISTER: case S_DEFRANGE_FRAMEPOINTER_REL: case S_DEFRANGE_SUBFIELD_REGISTER: @@ -2054,6 +2220,16 @@ static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg, const BYTE* roo return TRUE; }
+static void pdb_location_compute(struct process* pcs, + const struct module_format* modfmt, + const struct symt_function* func, + struct location* loc) + +{ + loc->kind = loc_register; + loc->reg = loc_err_internal; +} + static BOOL codeview_snarf_public(const struct msc_debug_info* msc_dbg, const BYTE* root, int offset, int size)
@@ -2886,7 +3062,7 @@ static BOOL pdb_process_file(const struct process* pcs, msc_dbg->module->format_info[DFI_PDB] = modfmt; modfmt->module = msc_dbg->module; modfmt->remove = pdb_module_remove; - modfmt->loc_compute = NULL; + modfmt->loc_compute = pdb_location_compute; modfmt->u.pdb_info = pdb_module_info;
memset(cv_zmodules, 0, sizeof(cv_zmodules)); diff --git a/include/wine/mscvpdb.h b/include/wine/mscvpdb.h index 1a173c097d7..9a733333837 100644 --- a/include/wine/mscvpdb.h +++ b/include/wine/mscvpdb.h @@ -1879,7 +1879,7 @@ union codeview_symbol { unsigned short int len; unsigned short int id; - unsigned int offFramePointer; + int offFramePointer; struct cv_addr_range range; struct cv_addr_gap gaps[0]; } defrange_frameptrrel_v3; @@ -1888,7 +1888,7 @@ union codeview_symbol { unsigned short int len; unsigned short int id; - unsigned int offFramePointer; + int offFramePointer; } defrange_frameptr_relfullscope_v3;
struct @@ -1911,7 +1911,7 @@ union codeview_symbol unsigned short spilledUdtMember : 1; unsigned short padding : 3; unsigned short offsetParent : 12; - unsigned int offBasePointer; + int offBasePointer; struct cv_addr_range range; struct cv_addr_gap gaps[0]; } defrange_registerrel_v3;
Add support for S_DEFRANGE* entries
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/msc.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 3 deletions(-)
diff --git a/dlls/dbghelp/msc.c b/dlls/dbghelp/msc.c index 0c58e5fc14f..0247a90f6ff 100644 --- a/dlls/dbghelp/msc.c +++ b/dlls/dbghelp/msc.c @@ -1699,7 +1699,11 @@ static unsigned codeview_transform_defrange(const struct msc_debug_info* msc_dbg switch (symrange->generic.id) { case S_DEFRANGE: + codeview_xform_range(msc_dbg, locinfo, &symrange->defrange_v3.range); + /* FIXME: transformation unsupported; let loc_compute bark if actually needed */ + break; case S_DEFRANGE_SUBFIELD: + codeview_xform_range(msc_dbg, locinfo, &symrange->defrange_subfield_v3.range); /* FIXME: transformation unsupported; let loc_compute bark if actually needed */ break; case S_DEFRANGE_REGISTER: @@ -1734,7 +1738,7 @@ static unsigned codeview_transform_defrange(const struct msc_debug_info* msc_dbg unsigned gaplen = (const char*)get_next_sym(symrange) - (const char*)gap; locinfo->ngaps = gaplen / sizeof(*gap); memcpy(locinfo->gaps, gap, gaplen); - locinfo = (struct cv_local_info*)((unsigned char*)(locinfo + 1) + gaplen); + locinfo = (struct cv_local_info*)((char*)(locinfo + 1) + gaplen); } else { @@ -2220,13 +2224,66 @@ static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg, const BYTE* roo return TRUE; }
+static BOOL codeview_is_inside(const struct cv_local_info* locinfo, const struct symt_function* func, DWORD_PTR ip) +{ + unsigned i; + /* ip must be in local_info range, but not in any of its gaps */ + if (ip < locinfo->start || ip >= locinfo->start + locinfo->rangelen) return FALSE; + for (i = 0; i < locinfo->ngaps; ++i) + if (func->address + locinfo->gaps[i].gapStartOffset <= ip && + ip < func->address + locinfo->gaps[i].gapStartOffset + locinfo->gaps[i].cbRange) + return FALSE; + return TRUE; +} + static void pdb_location_compute(struct process* pcs, const struct module_format* modfmt, const struct symt_function* func, struct location* loc) - { - loc->kind = loc_register; + const struct cv_local_info* locinfo; + + switch (loc->kind) + { + case loc_cv_local_range: + for (locinfo = (const struct cv_local_info*)loc->offset; + locinfo->kind != 0; + locinfo = (const struct cv_local_info*)((const char*)(locinfo + 1) + locinfo->ngaps * sizeof(locinfo->gaps[0]))) + { + if (!codeview_is_inside(locinfo, func, pcs->localscope_pc)) continue; + switch (locinfo->kind) + { + case S_DEFRANGE: + case S_DEFRANGE_SUBFIELD: + default: + FIXME("Unsupported defrange %d\n", locinfo->kind); + loc->kind = loc_error; + loc->reg = loc_err_internal; + return; + case S_DEFRANGE_SUBFIELD_REGISTER: + FIXME("sub-field part not handled\n"); + /* fall through */ + case S_DEFRANGE_REGISTER: + loc->kind = loc_register; + loc->reg = locinfo->reg; + return; + case S_DEFRANGE_REGISTER_REL: + loc->kind = loc_regrel; + loc->reg = locinfo->reg; + loc->offset = locinfo->offset; + return; + case S_DEFRANGE_FRAMEPOINTER_REL: + case S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE: + loc->kind = loc_regrel; + loc->reg = dbghelp_current_cpu->frame_regno; + loc->offset = locinfo->offset; + return; + } + } + break; + default: break; + } + loc->kind = loc_error; loc->reg = loc_err_internal; }
currently used for TPI stream
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/msc.c | 87 +++++++++++++++++++++++++++++----------------------- 1 file changed, 48 insertions(+), 39 deletions(-)
diff --git a/dlls/dbghelp/msc.c b/dlls/dbghelp/msc.c index 0247a90f6ff..d7b1e74edcd 100644 --- a/dlls/dbghelp/msc.c +++ b/dlls/dbghelp/msc.c @@ -2717,53 +2717,62 @@ static HANDLE map_pdb_file(const struct process* pcs, return hMap; }
+static BOOL pdb_init_type_parse(const struct msc_debug_info* msc_dbg, + struct codeview_type_parse* ctp, + BYTE* image) +{ + PDB_TYPES types; + DWORD total; + const BYTE* ptr; + DWORD* offset; + + pdb_convert_types_header(&types, image); + + /* Check for unknown versions */ + switch (types.version) + { + case 19950410: /* VC 4.0 */ + case 19951122: + case 19961031: /* VC 5.0 / 6.0 */ + case 19990903: /* VC 7.0 */ + case 20040203: /* VC 8.0 */ + break; + default: + ERR("-Unknown type info version %d\n", types.version); + } + + ctp->module = msc_dbg->module; + /* reconstruct the types offset... + * FIXME: maybe it's present in the newest PDB_TYPES structures + */ + total = types.last_index - types.first_index + 1; + offset = HeapAlloc(GetProcessHeap(), 0, sizeof(DWORD) * total); + if (!offset) return FALSE; + ctp->table = ptr = image + types.type_offset; + ctp->num = 0; + while (ptr < ctp->table + types.type_size && ctp->num < total) + { + offset[ctp->num++] = ptr - ctp->table; + ptr += ((const union codeview_type*)ptr)->generic.len + 2; + } + ctp->offset = offset; + return TRUE; +} + static void pdb_process_types(const struct msc_debug_info* msc_dbg, const struct pdb_file_info* pdb_file) { - BYTE* types_image = NULL; + struct codeview_type_parse ctp; + BYTE* types_image = pdb_read_file(pdb_file, 2);
- types_image = pdb_read_file(pdb_file, 2); if (types_image) { - PDB_TYPES types; - struct codeview_type_parse ctp; - DWORD total; - const BYTE* ptr; - DWORD* offset; - - pdb_convert_types_header(&types, types_image); - - /* Check for unknown versions */ - switch (types.version) + if (pdb_init_type_parse(msc_dbg, &ctp, types_image)) { - case 19950410: /* VC 4.0 */ - case 19951122: - case 19961031: /* VC 5.0 / 6.0 */ - case 19990903: /* VC 7.0 */ - case 20040203: /* VC 8.0 */ - break; - default: - ERR("-Unknown type info version %d\n", types.version); + /* Read type table */ + codeview_parse_type_table(&ctp); + HeapFree(GetProcessHeap(), 0, (DWORD*)ctp.offset); } - - ctp.module = msc_dbg->module; - /* reconstruct the types offset... - * FIXME: maybe it's present in the newest PDB_TYPES structures - */ - total = types.last_index - types.first_index + 1; - offset = HeapAlloc(GetProcessHeap(), 0, sizeof(DWORD) * total); - ctp.table = ptr = types_image + types.type_offset; - ctp.num = 0; - while (ptr < ctp.table + types.type_size && ctp.num < total) - { - offset[ctp.num++] = ptr - ctp.table; - ptr += ((const union codeview_type*)ptr)->generic.len + 2; - } - ctp.offset = offset; - - /* Read type table */ - codeview_parse_type_table(&ctp); - HeapFree(GetProcessHeap(), 0, offset); pdb_free(types_image); } }
(except old linetab v1)
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/msc.c | 62 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 24 deletions(-)
diff --git a/dlls/dbghelp/msc.c b/dlls/dbghelp/msc.c index d7b1e74edcd..12334a2e69d 100644 --- a/dlls/dbghelp/msc.c +++ b/dlls/dbghelp/msc.c @@ -90,6 +90,15 @@ struct pdb_module_info
#define loc_cv_local_range (loc_user + 0) /* loc.offset contain the copy of all defrange* Codeview records following S_LOCAL */
+struct cv_module_snarf +{ + const struct codeview_type_parse* ipi_ctp; + const struct CV_DebugSSubsectionHeader_t* dbgsubsect; + unsigned dbgsubsect_size; + const char* strimage; + unsigned strsize; +}; + /*======================================================================== * Debug file access helper routines */ @@ -1468,11 +1477,11 @@ static void codeview_snarf_linetab(const struct msc_debug_info* msc_dbg, const B } }
-static void codeview_snarf_linetab2(const struct msc_debug_info* msc_dbg, const BYTE* linetab, DWORD size, - const char* strimage, DWORD strsize) +static void codeview_snarf_linetab2(const struct msc_debug_info* msc_dbg, const struct cv_module_snarf* cvmod) { unsigned i; DWORD_PTR addr; + const void* hdr_last = (const char*)cvmod->dbgsubsect + cvmod->dbgsubsect_size; const struct CV_DebugSSubsectionHeader_t* hdr; const struct CV_DebugSSubsectionHeader_t* hdr_next; const struct CV_DebugSSubsectionHeader_t* hdr_files = NULL; @@ -1484,15 +1493,13 @@ static void codeview_snarf_linetab2(const struct msc_debug_info* msc_dbg, const struct symt_function* func;
/* locate DEBUG_S_FILECHKSMS (if any) */ - hdr = (const struct CV_DebugSSubsectionHeader_t*)linetab; - while (CV_IS_INSIDE(hdr, linetab + size)) + for (hdr = cvmod->dbgsubsect; CV_IS_INSIDE(hdr, hdr_last); hdr = CV_RECORD_GAP(hdr, hdr->cbLen)) { if (hdr->type == DEBUG_S_FILECHKSMS) { hdr_files = hdr; break; } - hdr = CV_RECORD_GAP(hdr, hdr->cbLen); } if (!hdr_files) { @@ -1500,8 +1507,7 @@ static void codeview_snarf_linetab2(const struct msc_debug_info* msc_dbg, const return; }
- hdr = (const struct CV_DebugSSubsectionHeader_t*)linetab; - while (CV_IS_INSIDE(hdr, linetab + size)) + for (hdr = cvmod->dbgsubsect; CV_IS_INSIDE(hdr, hdr_last); hdr = hdr_next) { hdr_next = CV_RECORD_GAP(hdr, hdr->cbLen); if (!(hdr->type & DEBUG_S_IGNORE)) @@ -1524,7 +1530,7 @@ static void codeview_snarf_linetab2(const struct msc_debug_info* msc_dbg, const break; } source = source_new(msc_dbg->module, NULL, - (chksms->strOffset < strsize) ? strimage + chksms->strOffset : "<<stroutofbounds>>"); + (chksms->strOffset < cvmod->strsize) ? cvmod->strimage + chksms->strOffset : "<<stroutofbounds>>"); func = (struct symt_function*)symt_find_nearest(msc_dbg->module, addr); /* FIXME: at least labels support line numbers */ if (!symt_check_tag(&func->symt, SymTagFunction) && !symt_check_tag(&func->symt, SymTagInlineSite)) @@ -1756,8 +1762,10 @@ static unsigned codeview_transform_defrange(const struct msc_debug_info* msc_dbg return len; }
-static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg, const BYTE* root, - int offset, int size, BOOL do_globals) +static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg, + const BYTE* root, unsigned offset, unsigned size, + const struct cv_module_snarf* cvmod, + BOOL do_globals) { struct symt_function* curr_func = NULL; int i, length; @@ -2220,7 +2228,7 @@ static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg, const BYTE* roo break; } } - + if (cvmod) codeview_snarf_linetab2(msc_dbg, cvmod); return TRUE; }
@@ -3011,6 +3019,8 @@ static BOOL pdb_process_internal(const struct process* pcs, PDB_SYMBOLS symbols; BYTE* globalimage; BYTE* modimage; + BYTE* ipi_image; + struct codeview_type_parse ipi_ctp; BYTE* file; int header_size = 0; PDB_STREAM_INDEXES* psi; @@ -3052,12 +3062,15 @@ static BOOL pdb_process_internal(const struct process* pcs, pdb_lookup, pdb_module_info, module_index); pdb_process_types(msc_dbg, pdb_file);
+ ipi_image = pdb_read_file(pdb_file, 4); + pdb_init_type_parse(msc_dbg, &ipi_ctp, ipi_image); + /* Read global symbol table */ globalimage = pdb_read_file(pdb_file, symbols.gsym_file); if (globalimage) { - codeview_snarf(msc_dbg, globalimage, 0, - pdb_get_file_size(pdb_file, symbols.gsym_file), FALSE); + codeview_snarf(msc_dbg, globalimage, 0, pdb_get_file_size(pdb_file, symbols.gsym_file), + NULL, FALSE); }
/* Read per-module symbols' tables */ @@ -3074,19 +3087,18 @@ static BOOL pdb_process_internal(const struct process* pcs, modimage = pdb_read_file(pdb_file, sfile.file); if (modimage) { - if (sfile.symbol_size) - codeview_snarf(msc_dbg, modimage, sizeof(DWORD), - sfile.symbol_size, TRUE); - - if (sfile.lineno_size && sfile.lineno2_size) FIXME("Both line info present... only supporting first\n"); - if (sfile.lineno_size) + struct cv_module_snarf cvmod = {&ipi_ctp, (const void*)(modimage + sfile.symbol_size), sfile.lineno2_size, + files_image + 12, files_size}; + codeview_snarf(msc_dbg, modimage, sizeof(DWORD), sfile.symbol_size, + &cvmod, TRUE); + + if (sfile.lineno_size && sfile.lineno2_size) + FIXME("Both line info present... only supporting second\n"); + else if (sfile.lineno_size) codeview_snarf_linetab(msc_dbg, modimage + sfile.symbol_size, sfile.lineno_size, pdb_file->kind == PDB_JG); - else if (sfile.lineno2_size && files_image) - codeview_snarf_linetab2(msc_dbg, modimage + sfile.symbol_size, sfile.lineno2_size, - files_image + 12, files_size);
pdb_free(modimage); } @@ -3101,6 +3113,8 @@ static BOOL pdb_process_internal(const struct process* pcs, pdb_get_file_size(pdb_file, symbols.gsym_file)); pdb_free(globalimage); } + HeapFree(GetProcessHeap(), 0, (DWORD*)ipi_ctp.offset); + pdb_free(ipi_image); } else pdb_process_symbol_imports(pcs, msc_dbg, NULL, NULL, image, @@ -3565,8 +3579,8 @@ static BOOL codeview_process_info(const struct process* pcs,
if (ent->SubSection == sstAlignSym) { - codeview_snarf(msc_dbg, msc_dbg->root + ent->lfo, sizeof(DWORD), - ent->cb, TRUE); + codeview_snarf(msc_dbg, msc_dbg->root + ent->lfo, sizeof(DWORD), ent->cb, + NULL, TRUE);
/* * Check the next and previous entry. If either is a
- support S_INLINESITE and S_INLINESITE_END
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/msc.c | 263 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 241 insertions(+), 22 deletions(-)
diff --git a/dlls/dbghelp/msc.c b/dlls/dbghelp/msc.c index 12334a2e69d..4fba245d815 100644 --- a/dlls/dbghelp/msc.c +++ b/dlls/dbghelp/msc.c @@ -1762,11 +1762,180 @@ static unsigned codeview_transform_defrange(const struct msc_debug_info* msc_dbg return len; }
+static unsigned codeview_binannot_uncompress(const unsigned char** pptr) +{ + unsigned res = (unsigned)(-1); + const unsigned char* ptr = *pptr; + + if ((*ptr & 0x80) == 0x00) + res = (unsigned)(*ptr++); + else if ((*ptr & 0xC0) == 0x80) + { + res = (unsigned)((*ptr++ & 0x3f) << 8); + res |= *ptr++; + } + else if ((*ptr & 0xE0) == 0xC0) + { + res = (*ptr++ & 0x1f) << 24; + res |= *ptr++ << 16; + res |= *ptr++ << 8; + res |= *ptr++; + } + else res = (unsigned)(-1); + *pptr = ptr; + return res; +} + +struct cv_binannot +{ + const unsigned char* annot; /* current pointer */ + const unsigned char* last_annot; /* end of binary annotation stream (first byte after) */ + unsigned opcode; /* last decoded opcode */ + unsigned arg1, arg2; +}; + +static BOOL codeview_advance_binannot(struct cv_binannot* cvba) +{ + if (cvba->annot >= cvba->last_annot) return FALSE; + cvba->opcode = codeview_binannot_uncompress(&cvba->annot); + if (cvba->opcode <= BA_OP_Invalid || cvba->opcode > BA_OP_ChangeColumnEnd) return FALSE; + if (cvba->annot >= cvba->last_annot) return FALSE; + cvba->arg1 = codeview_binannot_uncompress(&cvba->annot); + if (cvba->opcode == BA_OP_ChangeCodeOffsetAndLineOffset) + { + cvba->arg2 = cvba->arg1 >> 4; + cvba->arg1 &= 0x0F; + } + else if (cvba->opcode == BA_OP_ChangeCodeLengthAndCodeOffset) + { + if (cvba->annot >= cvba->last_annot) return FALSE; + cvba->arg2 = codeview_binannot_uncompress(&cvba->annot); + } + else cvba->arg2 = 0; + return TRUE; +} + +static struct symt_inlinesite* codeview_create_inline_site(const struct msc_debug_info* msc_dbg, + const struct cv_module_snarf* cvmod, + struct symt_function* top_func, + struct symt* container, + cv_itemid_t inlinee, + const unsigned char* annot, + const unsigned char* last_annot) +{ + const struct CV_DebugSSubsectionHeader_t* hdr_files = NULL; + const union codeview_type* cvt; + DWORD64 addr; + struct symt_inlinesite* inlined; + struct cv_binannot cvba; + BOOL found = FALSE; + unsigned first, offset, length; + + if (!cvmod->ipi_ctp || !(cvt = codeview_jump_to_type(cvmod->ipi_ctp, inlinee))) + { + FIXME("Couldn't find type %x in IPI stream\n", inlinee); + return NULL; + } + + addr = top_func->address; + /* grasp first code offset in binary annotation to compute inline site start address */ + cvba.annot = annot; + cvba.last_annot = last_annot; + while (codeview_advance_binannot(&cvba)) + if (cvba.opcode == BA_OP_CodeOffset || + cvba.opcode == BA_OP_ChangeCodeOffset || + cvba.opcode == BA_OP_ChangeCodeOffsetAndLineOffset) + { + addr += first = cvba.arg1; + length = 0; + found = TRUE; + break; + } + else if (cvba.opcode == BA_OP_ChangeCodeLengthAndCodeOffset) + { + addr += first = cvba.arg2; + length = cvba.arg1; + found = TRUE; + break; + } + offset = first; + + if (!found) + { + FIXME("Couldn't find start address of inlined\n"); + return NULL; + } + + switch (cvt->generic.id) + { + case LF_FUNC_ID: + inlined = symt_new_inlinesite(msc_dbg->module, top_func, container, + cvt->func_id_v3.name, addr, + codeview_get_type(cvt->func_id_v3.type, FALSE)); + break; + case LF_MFUNC_ID: + /* FIXME we just declare a function, not a method */ + inlined = symt_new_inlinesite(msc_dbg->module, top_func, container, + cvt->mfunc_id_v3.name, addr, + codeview_get_type(cvt->mfunc_id_v3.type, FALSE)); + break; + default: + FIXME("unsupported inlinee kind %x\n", cvt->generic.id); + return NULL; + } + + for (hdr_files = cvmod->dbgsubsect; + CV_IS_INSIDE(hdr_files, cvmod->dbgsubsect + cvmod->dbgsubsect_size); + hdr_files = CV_RECORD_GAP(hdr_files, hdr_files->cbLen)) + { + if (hdr_files->type == DEBUG_S_FILECHKSMS) + break; + } + if (!hdr_files) return FALSE; + + for (;;) + { + if (!codeview_advance_binannot(&cvba)) break; + switch (cvba.opcode) + { + case BA_OP_CodeOffset: + first = offset = cvba.arg1; + length = 1; + break; + case BA_OP_ChangeCodeOffset: + offset += cvba.arg1; + length = 1; + break; + case BA_OP_ChangeCodeLength: + length = cvba.arg1; + break; + case BA_OP_ChangeFile: + break; + case BA_OP_ChangeLineOffset: + break; + case BA_OP_ChangeCodeOffsetAndLineOffset: + offset += cvba.arg1; + length = 1; + break; + case BA_OP_ChangeCodeLengthAndCodeOffset: + offset += cvba.arg2; + length = cvba.arg1; + break; + default: + WARN("Unsupported op %d\n", cvba.opcode); + break; + } + } + symt_add_inlinesite_range(msc_dbg->module, inlined, top_func->address + first, top_func->address + offset + length); + return inlined; +} + static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg, const BYTE* root, unsigned offset, unsigned size, const struct cv_module_snarf* cvmod, BOOL do_globals) { + struct symt_function* top_func = NULL; struct symt_function* curr_func = NULL; int i, length; struct symt_block* block = NULL; @@ -1869,12 +2038,13 @@ static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg, */ case S_GPROC32_16t: case S_LPROC32_16t: - if (curr_func) FIXME("nested function\n"); - curr_func = symt_new_function(msc_dbg->module, compiland, - terminate_string(&sym->proc_v1.p_name), - codeview_get_address(msc_dbg, sym->proc_v1.segment, sym->proc_v1.offset), - sym->proc_v1.proc_len, - codeview_get_type(sym->proc_v1.proctype, FALSE)); + if (top_func) FIXME("nested function\n"); + top_func = symt_new_function(msc_dbg->module, compiland, + terminate_string(&sym->proc_v1.p_name), + codeview_get_address(msc_dbg, sym->proc_v1.segment, sym->proc_v1.offset), + sym->proc_v1.proc_len, + codeview_get_type(sym->proc_v1.proctype, FALSE)); + curr_func = top_func; loc.kind = loc_absolute; loc.offset = sym->proc_v1.debug_start; symt_add_function_point(msc_dbg->module, curr_func, SymTagFuncDebugStart, &loc, NULL); @@ -1883,12 +2053,13 @@ static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg, break; case S_GPROC32_ST: case S_LPROC32_ST: - if (curr_func) FIXME("nested function\n"); - curr_func = symt_new_function(msc_dbg->module, compiland, - terminate_string(&sym->proc_v2.p_name), - codeview_get_address(msc_dbg, sym->proc_v2.segment, sym->proc_v2.offset), - sym->proc_v2.proc_len, - codeview_get_type(sym->proc_v2.proctype, FALSE)); + if (top_func) FIXME("nested function\n"); + top_func = symt_new_function(msc_dbg->module, compiland, + terminate_string(&sym->proc_v2.p_name), + codeview_get_address(msc_dbg, sym->proc_v2.segment, sym->proc_v2.offset), + sym->proc_v2.proc_len, + codeview_get_type(sym->proc_v2.proctype, FALSE)); + curr_func = top_func; loc.kind = loc_absolute; loc.offset = sym->proc_v2.debug_start; symt_add_function_point(msc_dbg->module, curr_func, SymTagFuncDebugStart, &loc, NULL); @@ -1897,12 +2068,13 @@ static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg, break; case S_GPROC32: case S_LPROC32: - if (curr_func) FIXME("nested function\n"); - curr_func = symt_new_function(msc_dbg->module, compiland, - sym->proc_v3.name, - codeview_get_address(msc_dbg, sym->proc_v3.segment, sym->proc_v3.offset), - sym->proc_v3.proc_len, - codeview_get_type(sym->proc_v3.proctype, FALSE)); + if (top_func) FIXME("nested function\n"); + top_func = symt_new_function(msc_dbg->module, compiland, + sym->proc_v3.name, + codeview_get_address(msc_dbg, sym->proc_v3.segment, sym->proc_v3.offset), + sym->proc_v3.proc_len, + codeview_get_type(sym->proc_v3.proctype, FALSE)); + curr_func = top_func; loc.kind = loc_absolute; loc.offset = sym->proc_v3.debug_start; symt_add_function_point(msc_dbg->module, curr_func, SymTagFuncDebugStart, &loc, NULL); @@ -2007,9 +2179,10 @@ static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg, { block = symt_close_func_block(msc_dbg->module, curr_func, block, 0); } - else if (curr_func) + else if (top_func) { - curr_func = NULL; + if (curr_func != top_func) FIXME("shouldn't close a top function with an opened inlined function\n"); + top_func = curr_func = NULL; } break;
@@ -2164,6 +2337,54 @@ static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg, codeview_get_type(sym->local_v3.symtype, FALSE), sym->local_v3.name); break; + case S_INLINESITE: + { + struct symt_inlinesite* inlined = codeview_create_inline_site(msc_dbg, cvmod, top_func, + block ? &block->symt : &curr_func->symt, + sym->inline_site_v3.inlinee, + sym->inline_site_v3.binaryAnnotations, + (const unsigned char*)sym + length); + if (inlined) + { + curr_func = (struct symt_function*)inlined; + block = NULL; + } + else + { + /* skip all records until paired S_INLINESITE_END */ + sym = (const union codeview_symbol*)(root + sym->inline_site_v3.pEnd); + if (sym->generic.id != S_INLINESITE_END) FIXME("complete wreckage\n"); + length = sym->inline_site_v3.pEnd - i + sym->generic.len; + } + } + break; + case S_INLINESITE2: + { + struct symt_inlinesite* inlined = codeview_create_inline_site(msc_dbg, cvmod, top_func, + block ? &block->symt : &curr_func->symt, + sym->inline_site2_v3.inlinee, + sym->inline_site2_v3.binaryAnnotations, + (const unsigned char*)sym + length); + if (inlined) + { + curr_func = (struct symt_function*)inlined; + block = NULL; + } + else + { + /* skip all records until paired S_INLINESITE_END */ + sym = (const union codeview_symbol*)(root + sym->inline_site2_v3.pEnd); + if (sym->generic.id != S_INLINESITE_END) FIXME("complete wreckage\n"); + length = sym->inline_site_v3.pEnd - i + sym->generic.len; + } + } + break; + + case S_INLINESITE_END: + block = symt_check_tag(curr_func->container, SymTagBlock) ? + (struct symt_block*)curr_func->container : NULL; + curr_func = (struct symt_function*)symt_get_upper_inlined((struct symt_inlinesite*)curr_func); + break;
/* * These are special, in that they are always followed by an @@ -2213,8 +2434,6 @@ static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg, case S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE: case S_DEFRANGE_REGISTER_REL: case S_BUILDINFO: - case S_INLINESITE: - case S_INLINESITE_END: case S_FILESTATIC: case S_CALLEES: case S_UNAMESPACE:
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/msc.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-)
diff --git a/dlls/dbghelp/msc.c b/dlls/dbghelp/msc.c index 4fba245d815..1be73b723f0 100644 --- a/dlls/dbghelp/msc.c +++ b/dlls/dbghelp/msc.c @@ -1480,7 +1480,6 @@ static void codeview_snarf_linetab(const struct msc_debug_info* msc_dbg, const B static void codeview_snarf_linetab2(const struct msc_debug_info* msc_dbg, const struct cv_module_snarf* cvmod) { unsigned i; - DWORD_PTR addr; const void* hdr_last = (const char*)cvmod->dbgsubsect + cvmod->dbgsubsect_size; const struct CV_DebugSSubsectionHeader_t* hdr; const struct CV_DebugSSubsectionHeader_t* hdr_next; @@ -1512,6 +1511,7 @@ static void codeview_snarf_linetab2(const struct msc_debug_info* msc_dbg, const hdr_next = CV_RECORD_GAP(hdr, hdr->cbLen); if (!(hdr->type & DEBUG_S_IGNORE)) { + ULONG_PTR lineblk_base; /* FIXME: should also check that whole lines_blk fits in linetab + size */ switch (hdr->type) { @@ -1520,7 +1520,6 @@ static void codeview_snarf_linetab2(const struct msc_debug_info* msc_dbg, const files_hdr = CV_RECORD_AFTER(lines_hdr); /* Skip blocks that are too small - Intel C Compiler generates these. */ if (!CV_IS_INSIDE(files_hdr, hdr_next)) break; - addr = codeview_get_address(msc_dbg, lines_hdr->segCon, lines_hdr->offCon); TRACE("block from %04x:%08x #%x\n", lines_hdr->segCon, lines_hdr->offCon, lines_hdr->cbCon); chksms = CV_RECORD_GAP(hdr_files, files_hdr->offFile); @@ -1531,20 +1530,20 @@ static void codeview_snarf_linetab2(const struct msc_debug_info* msc_dbg, const } source = source_new(msc_dbg->module, NULL, (chksms->strOffset < cvmod->strsize) ? cvmod->strimage + chksms->strOffset : "<<stroutofbounds>>"); - func = (struct symt_function*)symt_find_nearest(msc_dbg->module, addr); - /* FIXME: at least labels support line numbers */ - if (!symt_check_tag(&func->symt, SymTagFunction) && !symt_check_tag(&func->symt, SymTagInlineSite)) - { - WARN("--not a func at %04x:%08x %Ix tag=%d\n", - lines_hdr->segCon, lines_hdr->offCon, addr, func ? func->symt.tag : -1); - break; - } + lineblk_base = codeview_get_address(msc_dbg, lines_hdr->segCon, lines_hdr->offCon); lines = CV_RECORD_AFTER(files_hdr); for (i = 0; i < files_hdr->nLines; i++) { + func = (struct symt_function*)symt_find_nearest(msc_dbg->module, lineblk_base + lines[i].offset); + /* FIXME: at least labels support line numbers */ + if (!symt_check_tag(&func->symt, SymTagFunction) && !symt_check_tag(&func->symt, SymTagInlineSite)) + { + WARN("--not a func at %04x:%08x %Ix tag=%d\n", + lines_hdr->segCon, lines_hdr->offCon + lines[i].offset, lineblk_base + lines[i].offset, func ? func->symt.tag : -1); + continue; + } symt_add_func_line(msc_dbg->module, func, source, - lines[i].linenumStart, - func->address + lines[i].offset); + lines[i].linenumStart, lineblk_base + lines[i].offset); } break; case DEBUG_S_FILECHKSMS: /* skip */
requires to join DEBUG_S_INLINEES subsection with symbol annotations
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/msc.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 2 deletions(-)
diff --git a/dlls/dbghelp/msc.c b/dlls/dbghelp/msc.c index 1be73b723f0..c0d09b75c56 100644 --- a/dlls/dbghelp/msc.c +++ b/dlls/dbghelp/msc.c @@ -1814,6 +1814,70 @@ static BOOL codeview_advance_binannot(struct cv_binannot* cvba) return TRUE; }
+static inline int binannot_getsigned(unsigned i) +{ + return (i & 1) ? -(int)(i >> 1) : (int)(i >> 1); +} + +static BOOL cv_dbgsubsect_find_inlinee(const struct msc_debug_info* msc_dbg, + unsigned inlineeid, + const struct cv_module_snarf* cvmod, + const struct CV_DebugSSubsectionHeader_t* hdr_files, + unsigned* srcfile, unsigned* srcline) +{ + const struct CV_DebugSSubsectionHeader_t* hdr; + const struct CV_DebugSSubsectionHeader_t* next_hdr; + const struct CV_InlineeSourceLine_t* inlsrc; + const struct CV_InlineeSourceLineEx_t* inlsrcex; + const struct CV_Checksum_t* chksms; + + for (hdr = cvmod->dbgsubsect; CV_IS_INSIDE(hdr, cvmod->dbgsubsect + cvmod->dbgsubsect_size); hdr = next_hdr) + { + next_hdr = CV_RECORD_GAP(hdr, hdr->cbLen); + if (hdr->type != DEBUG_S_INLINEELINES) continue; + /* subsection starts with a DWORD signature */ + switch (*(DWORD*)CV_RECORD_AFTER(hdr)) + { + case CV_INLINEE_SOURCE_LINE_SIGNATURE: + inlsrc = CV_RECORD_GAP(hdr, sizeof(DWORD)); + while (CV_IS_INSIDE(inlsrc, next_hdr)) + { + if (inlsrc->inlinee == inlineeid) + { + chksms = CV_RECORD_GAP(hdr_files, inlsrc->fileId); + if (!CV_IS_INSIDE(chksms, CV_RECORD_GAP(hdr_files, hdr_files->cbLen))) return FALSE; + *srcfile = source_new(msc_dbg->module, NULL, + (chksms->strOffset < cvmod->strsize) ? cvmod->strimage + chksms->strOffset : "<<str-out-of-bounds>>"); + *srcline = inlsrc->sourceLineNum; + return TRUE; + } + ++inlsrc; + } + break; + case CV_INLINEE_SOURCE_LINE_SIGNATURE_EX: + inlsrcex = CV_RECORD_GAP(hdr, sizeof(DWORD)); + while (CV_IS_INSIDE(inlsrcex, next_hdr)) + { + if (inlsrcex->inlinee == inlineeid) + { + chksms = CV_RECORD_GAP(hdr_files, inlsrcex->fileId); + if (!CV_IS_INSIDE(chksms, CV_RECORD_GAP(hdr_files, hdr_files->cbLen))) return FALSE; + *srcfile = source_new(msc_dbg->module, NULL, + (chksms->strOffset < cvmod->strsize) ? cvmod->strimage + chksms->strOffset : "<<str-out-of-bounds>>"); + *srcline = inlsrcex->sourceLineNum; + return TRUE; + } + inlsrcex = CV_RECORD_GAP(inlsrcex, inlsrcex->countOfExtraFiles * sizeof(inlsrcex->extraFileId[0])); + } + break; + default: + FIXME("Unknown signature %x in INLINEELINES subsection\n", *(DWORD*)CV_RECORD_AFTER(hdr)); + break; + } + } + return FALSE; +} + static struct symt_inlinesite* codeview_create_inline_site(const struct msc_debug_info* msc_dbg, const struct cv_module_snarf* cvmod, struct symt_function* top_func, @@ -1827,8 +1891,9 @@ static struct symt_inlinesite* codeview_create_inline_site(const struct msc_debu DWORD64 addr; struct symt_inlinesite* inlined; struct cv_binannot cvba; - BOOL found = FALSE; - unsigned first, offset, length; + BOOL srcok, found = FALSE; + unsigned first, offset, length, line, srcfile; + const struct CV_Checksum_t* chksms;
if (!cvmod->ipi_ctp || !(cvt = codeview_jump_to_type(cvmod->ipi_ctp, inlinee))) { @@ -1891,7 +1956,12 @@ static struct symt_inlinesite* codeview_create_inline_site(const struct msc_debu break; } if (!hdr_files) return FALSE; + srcok = cv_dbgsubsect_find_inlinee(msc_dbg, inlinee, cvmod, hdr_files, &srcfile, &line);
+ if (srcok) + symt_add_func_line(msc_dbg->module, &inlined->func, srcfile, line, top_func->address + offset); + else + srcfile = line = 0; for (;;) { if (!codeview_advance_binannot(&cvba)) break; @@ -1904,21 +1974,33 @@ static struct symt_inlinesite* codeview_create_inline_site(const struct msc_debu case BA_OP_ChangeCodeOffset: offset += cvba.arg1; length = 1; + if (srcok) + symt_add_func_line(msc_dbg->module, &inlined->func, srcfile, line, top_func->address + offset); break; case BA_OP_ChangeCodeLength: length = cvba.arg1; break; case BA_OP_ChangeFile: + chksms = CV_RECORD_GAP(hdr_files, cvba.arg1); + if (CV_IS_INSIDE(chksms, CV_RECORD_GAP(hdr_files, hdr_files->cbLen))) + srcfile = source_new(msc_dbg->module, NULL, + (chksms->strOffset < cvmod->strsize) ? cvmod->strimage + chksms->strOffset : "<<str-out-of-bounds>>"); break; case BA_OP_ChangeLineOffset: + line += binannot_getsigned(cvba.arg1); break; case BA_OP_ChangeCodeOffsetAndLineOffset: + if (srcok) + symt_add_func_line(msc_dbg->module, &inlined->func, srcfile, line, top_func->address + offset); + line += binannot_getsigned(cvba.arg2); offset += cvba.arg1; length = 1; break; case BA_OP_ChangeCodeLengthAndCodeOffset: offset += cvba.arg2; length = cvba.arg1; + if (srcok) + symt_add_func_line(msc_dbg->module, &inlined->func, srcfile, line, top_func->address + offset); break; default: WARN("Unsupported op %d\n", cvba.opcode);