From c50e02ec9ce78361afca88f740c7b71bf7b23986 Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Thu, 16 Nov 2023 18:38:02 +0100 Subject: [PATCH] dbghelp: Expose some internal information about modules to winedbg. Signed-off-by: Eric Pouech --- dlls/dbghelp/dbghelp.c | 7 ++++ dlls/dbghelp/dbghelp.spec | 3 ++ dlls/dbghelp/dbghelp_private.h | 13 ++----- dlls/dbghelp/dwarf.c | 25 ++++++------ dlls/dbghelp/image_private.h | 2 +- dlls/dbghelp/module.c | 37 +++++++++++++++++- dlls/dbghelp/stabs.c | 2 +- include/dbghelp.h | 33 ++++++++++++++++ programs/winedbg/info.c | 69 +++++++++++++++++----------------- programs/winedbg/winedbg.c | 1 + 10 files changed, 131 insertions(+), 61 deletions(-) diff --git a/dlls/dbghelp/dbghelp.c b/dlls/dbghelp/dbghelp.c index d0f711761d4..4e6938cb557 100644 --- a/dlls/dbghelp/dbghelp.c +++ b/dlls/dbghelp/dbghelp.c @@ -67,6 +67,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dbghelp); unsigned dbghelp_options = SYMOPT_UNDNAME; BOOL dbghelp_opt_native = FALSE; +BOOL dbghelp_opt_extension_api = FALSE; BOOL dbghelp_opt_real_path = FALSE; BOOL dbghelp_opt_source_actual_path = FALSE; SYSTEM_INFO sysinfo; @@ -612,6 +613,10 @@ BOOL WINAPI SymSetExtendedOption(IMAGEHLP_EXTENDED_OPTIONS option, BOOL value) old = dbghelp_opt_native; dbghelp_opt_native = value; break; + case SYMOPT_EX_WINE_EXTENSION_API: + old = dbghelp_opt_extension_api; + dbghelp_opt_extension_api = value; + break; case SYMOPT_EX_WINE_MODULE_REAL_PATH: old = dbghelp_opt_real_path; dbghelp_opt_real_path = value; @@ -637,6 +642,8 @@ BOOL WINAPI SymGetExtendedOption(IMAGEHLP_EXTENDED_OPTIONS option) { case SYMOPT_EX_WINE_NATIVE_MODULES: return dbghelp_opt_native; + case SYMOPT_EX_WINE_EXTENSION_API: + return dbghelp_opt_extension_api; case SYMOPT_EX_WINE_MODULE_REAL_PATH: return dbghelp_opt_real_path; case SYMOPT_EX_WINE_SOURCE_ACTUAL_PATH: diff --git a/dlls/dbghelp/dbghelp.spec b/dlls/dbghelp/dbghelp.spec index 9ef5922386e..a89c2c1d86b 100644 --- a/dlls/dbghelp/dbghelp.spec +++ b/dlls/dbghelp/dbghelp.spec @@ -215,3 +215,6 @@ #@ stub sym #@ stub symsrv #@ stub vc7fpo + +# wine extensions +@ stdcall wine_get_module_information(long int64 ptr long) diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h index f7caf8d3b5c..e8f536e95a8 100644 --- a/dlls/dbghelp/dbghelp_private.h +++ b/dlls/dbghelp/dbghelp_private.h @@ -112,6 +112,7 @@ void* hash_table_iter_up(struct hash_table_iter* hti); extern unsigned dbghelp_options; extern BOOL dbghelp_opt_native; +extern BOOL dbghelp_opt_extension_api; extern BOOL dbghelp_opt_real_path; extern BOOL dbghelp_opt_source_actual_path; extern SYSTEM_INFO sysinfo; @@ -396,13 +397,6 @@ struct symt_udt struct vector vchildren; }; -enum module_type -{ - DMT_ELF, /* a real ELF shared module */ - DMT_PE, /* a native or builtin PE module */ - DMT_MACHO, /* a real Mach-O shared module */ -}; - struct process; struct module; @@ -445,7 +439,7 @@ struct module IMAGEHLP_MODULEW64 module; WCHAR modulename[64]; /* used for enumeration */ struct module* next; - enum module_type type : 16; + enum dhext_module_type type : 16; unsigned short is_virtual : 1; struct cpu* cpu; DWORD64 reloc_delta; @@ -453,6 +447,7 @@ struct module /* specific information for debug types */ struct module_format* format_info[DFI_LAST]; + unsigned debug_format_bitmask; /* memory allocation pool */ struct pool pool; @@ -742,7 +737,7 @@ extern struct module* extern BOOL module_get_debug(struct module_pair*); extern struct module* module_new(struct process* pcs, const WCHAR* name, - enum module_type type, BOOL virtual, + enum dhext_module_type type, BOOL virtual, DWORD64 addr, DWORD64 size, ULONG_PTR stamp, ULONG_PTR checksum, WORD machine); extern struct module* diff --git a/dlls/dbghelp/dwarf.c b/dlls/dbghelp/dwarf.c index 2a4f9a16228..332c3da1059 100644 --- a/dlls/dbghelp/dwarf.c +++ b/dlls/dbghelp/dwarf.c @@ -2892,8 +2892,8 @@ static BOOL dwarf2_parse_compilation_unit_head(dwarf2_parse_context_t* ctx, TRACE("- word_size: %u\n", ctx->head.word_size); TRACE("- offset_size: %u\n", ctx->head.offset_size); - if (ctx->head.version >= 2) - ctx->module_ctx->cu_versions |= 1 << (ctx->head.version - 2); + if (ctx->head.version >= 2 && ctx->head.version <= 5) + ctx->module_ctx->cu_versions |= DHEXT_FORMAT_DWARF2 << (ctx->head.version - 2); if (max_supported_dwarf_version == 0) { char* env = getenv("DBGHELP_DWARF_VERSION"); @@ -4259,17 +4259,16 @@ BOOL dwarf2_parse(struct module* module, ULONG_PTR load_offset, module_ctx.dwz = dwarf2_load_dwz(fmap, module); dwarf2_load_CU_module(&module_ctx, module, section, load_offset, thunks, FALSE); - dwarf2_modfmt->module->module.SymType = SymDia; - /* hide dwarf versions in CVSig - * bits 24-31 will be set according to found dwarf version - * different CU can have different dwarf version, so use a bit per version (version 2 => b24) - */ - dwarf2_modfmt->module->module.CVSig = 'D' | ('W' << 8) | ('F' << 16) | ((module_ctx.cu_versions & 0xFF) << 24); - /* FIXME: we could have a finer grain here */ - dwarf2_modfmt->module->module.GlobalSymbols = TRUE; - dwarf2_modfmt->module->module.TypeInfo = TRUE; - dwarf2_modfmt->module->module.SourceIndexed = TRUE; - dwarf2_modfmt->module->module.Publics = TRUE; + if (module_ctx.cu_versions) + { + dwarf2_modfmt->module->module.SymType = SymDia; + module->debug_format_bitmask |= module_ctx.cu_versions; + /* FIXME: we could have a finer grain here */ + dwarf2_modfmt->module->module.GlobalSymbols = TRUE; + dwarf2_modfmt->module->module.TypeInfo = TRUE; + dwarf2_modfmt->module->module.SourceIndexed = TRUE; + dwarf2_modfmt->module->module.Publics = TRUE; + } dwarf2_unload_CU_module(&module_ctx); leave: diff --git a/dlls/dbghelp/image_private.h b/dlls/dbghelp/image_private.h index 969f93abfd8..d5daac9dd47 100644 --- a/dlls/dbghelp/image_private.h +++ b/dlls/dbghelp/image_private.h @@ -102,7 +102,7 @@ struct macho_section32 */ struct image_file_map { - enum module_type modtype; + enum dhext_module_type modtype; const struct image_file_map_ops *ops; unsigned addr_size; /* either 16 (not used), 32 or 64 */ struct image_file_map* alternate; /* another file linked to this one */ diff --git a/dlls/dbghelp/module.c b/dlls/dbghelp/module.c index e6ee9534ff4..62cff1260dc 100644 --- a/dlls/dbghelp/module.c +++ b/dlls/dbghelp/module.c @@ -162,7 +162,7 @@ WCHAR *get_wine_loader_name(struct process *pcs) return altname; } -static const char* get_module_type(enum module_type type, BOOL virtual) +static const char* get_module_type(enum dhext_module_type type, BOOL virtual) { switch (type) { @@ -177,7 +177,7 @@ static const char* get_module_type(enum module_type type, BOOL virtual) * Creates and links a new module to a process */ struct module* module_new(struct process* pcs, const WCHAR* name, - enum module_type type, BOOL virtual, + enum dhext_module_type type, BOOL virtual, DWORD64 mod_addr, DWORD64 size, ULONG_PTR stamp, ULONG_PTR checksum, WORD machine) { @@ -238,6 +238,7 @@ struct module* module_new(struct process* pcs, const WCHAR* name, module->cpu = cpu_find(machine); if (!module->cpu) module->cpu = dbghelp_current_cpu; + module->debug_format_bitmask = 0; vector_init(&module->vsymt, sizeof(struct symt*), 128); vector_init(&module->vcustom_symt, sizeof(struct symt*), 16); @@ -1653,3 +1654,35 @@ const struct loader_ops empty_loader_ops = empty_enum_modules, native_fetch_file_info, }; + +BOOL WINAPI wine_get_module_information(HANDLE proc, DWORD64 base, struct dhext_module_information* wmi, unsigned len) +{ + struct process* pcs; + struct module* module; + struct dhext_module_information dhmi; + + /* could be interpreted as a WinDbg extension */ + if (!dbghelp_opt_extension_api) + { + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; + } + + TRACE("(%p %I64x %p %u\n", proc, base, wmi, len); + + if (!(pcs = process_find_by_handle(proc))) return FALSE; + if (len > sizeof(*wmi)) return FALSE; + + module = module_find_by_addr(pcs, base); + if (!module) return FALSE; + + dhmi.type = module->type; + dhmi.debug_format_bitmask = module->debug_format_bitmask; + if ((module = module_get_container(pcs, module))) + { + dhmi.debug_format_bitmask |= module->debug_format_bitmask; + } + memcpy(wmi, &dhmi, len); + + return TRUE; +} diff --git a/dlls/dbghelp/stabs.c b/dlls/dbghelp/stabs.c index f21f7e15d0b..552b334f2da 100644 --- a/dlls/dbghelp/stabs.c +++ b/dlls/dbghelp/stabs.c @@ -1664,7 +1664,7 @@ BOOL stabs_parse(struct module* module, ULONG_PTR load_offset, stab_ptr->n_type, (ULONG_PTR)n_value, debugstr_a(strs + stab_ptr->n_strx)); } module->module.SymType = SymDia; - module->module.CVSig = 'S' | ('T' << 8) | ('A' << 16) | ('B' << 24); + module->debug_format_bitmask |= DHEXT_FORMAT_STABS; /* FIXME: we could have a finer grain here */ module->module.LineNumbers = TRUE; module->module.GlobalSymbols = TRUE; diff --git a/include/dbghelp.h b/include/dbghelp.h index 9672b667f1e..af27ddd115b 100644 --- a/include/dbghelp.h +++ b/include/dbghelp.h @@ -1098,6 +1098,8 @@ typedef enum #ifdef __WINESRC__ /* Include ELF/Mach-O modules in module operations */ SYMOPT_EX_WINE_NATIVE_MODULES = 1000, + /* Enable Wine's extension APIs */ + SYMOPT_EX_WINE_EXTENSION_API, /* Return the Unix actual path of loaded module */ SYMOPT_EX_WINE_MODULE_REAL_PATH, /* Return the raw source file path from debug info (not always mapped to DOS) */ @@ -1240,6 +1242,37 @@ BOOL IMAGEAPI SymUnloadModule(HANDLE, DWORD); #endif +#ifdef __WINESRC__ + +/* Wine extensions to dbghelp */ +enum dhext_module_type +{ + DMT_UNKNOWN, /* for lookup, not actually used for a module */ + DMT_ELF, /* a real ELF shared module */ + DMT_MACHO, /* a real Mach-O shared module */ + DMT_PE, /* a native or builtin PE module */ +}; + +/* only reporting the formats not exposed in regular IMAGHELP_MODULE_INFO */ +enum dhext_debug_format +{ + DHEXT_FORMAT_DWARF2 = 0x0001, + DHEXT_FORMAT_DWARF3 = 0x0002, + DHEXT_FORMAT_DWARF4 = 0x0004, + DHEXT_FORMAT_DWARF5 = 0x0008, + DHEXT_FORMAT_STABS = 0x0010, +}; + +struct dhext_module_information +{ + enum dhext_module_type type; + unsigned debug_format_bitmask; +}; + +extern BOOL WINAPI wine_get_module_information(HANDLE, DWORD64 base, struct dhext_module_information*, unsigned len); + +#endif /* __WINESRC__ */ + #ifdef __cplusplus } /* extern "C" */ #endif /* defined(__cplusplus) */ diff --git a/programs/winedbg/info.c b/programs/winedbg/info.c index 251b92c607b..ce33539321d 100644 --- a/programs/winedbg/info.c +++ b/programs/winedbg/info.c @@ -116,9 +116,23 @@ void info_help(void) while (infotext[i]) dbg_printf("%s\n", infotext[i++]); } -static const char* get_symtype_str(const IMAGEHLP_MODULE64* mi) +struct info_module { - switch (mi->SymType) + IMAGEHLP_MODULEW64 mi; + struct dhext_module_information ext_module_info; + char name[64]; +}; + +struct info_modules +{ + struct info_module *modules; + unsigned num_alloc; + unsigned num_used; +}; + +static const char* get_symtype_str(const struct info_module* im) +{ + switch (im->mi.SymType) { default: case SymNone: return "--none--"; @@ -129,43 +143,26 @@ static const char* get_symtype_str(const IMAGEHLP_MODULE64* mi) case SymDeferred: return "Deferred"; case SymSym: return "Sym"; case SymDia: - switch (mi->CVSig) + if (im->ext_module_info.debug_format_bitmask) { - case 'S' | ('T' << 8) | ('A' << 16) | ('B' << 24): - return "Stabs"; - case 'D' | ('W' << 8) | ('A' << 16) | ('R' << 24): - /* previous versions of dbghelp used to report this... */ - return "Dwarf"; - default: - if ((mi->CVSig & 0x00FFFFFF) == ('D' | ('W' << 8) | ('F' << 16))) + static char tmp[64]; + tmp[0] = '\0'; + if (im->ext_module_info.debug_format_bitmask & DHEXT_FORMAT_STABS) strcpy(tmp, "stabs"); + if (im->ext_module_info.debug_format_bitmask & (DHEXT_FORMAT_DWARF2 | DHEXT_FORMAT_DWARF3 | DHEXT_FORMAT_DWARF4 | DHEXT_FORMAT_DWARF5)) { - static char tmp[64]; - DWORD versbit = mi->CVSig >> 24; - strcpy(tmp, "Dwarf"); - if (versbit & 1) strcat(tmp, "-2"); - if (versbit & 2) strcat(tmp, "-3"); - if (versbit & 4) strcat(tmp, "-4"); - if (versbit & 8) strcat(tmp, "-5"); - return tmp; + if (tmp[0]) strcat(tmp, ", "); + strcat(tmp, "Dwarf"); + if (im->ext_module_info.debug_format_bitmask & DHEXT_FORMAT_DWARF2) strcat(tmp, "-2"); + if (im->ext_module_info.debug_format_bitmask & DHEXT_FORMAT_DWARF3) strcat(tmp, "-3"); + if (im->ext_module_info.debug_format_bitmask & DHEXT_FORMAT_DWARF4) strcat(tmp, "-4"); + if (im->ext_module_info.debug_format_bitmask & DHEXT_FORMAT_DWARF5) strcat(tmp, "-5"); } - return "DIA"; + return tmp; } + return "DIA"; } } -struct info_module -{ - IMAGEHLP_MODULE64 mi; - char name[64]; -}; - -struct info_modules -{ - struct info_module *modules; - unsigned num_alloc; - unsigned num_used; -}; - static const char* get_machine_str(DWORD machine) { static char tmp[32]; @@ -187,12 +184,12 @@ static void module_print_info(const struct info_module *module, BOOL is_embedded module->mi.BaseOfImage, module->mi.BaseOfImage + module->mi.ImageSize, get_machine_str(module->mi.MachineType), - is_embedded ? "\\" : get_symtype_str(&module->mi), module->name); + is_embedded ? "\\" : get_symtype_str(module), module->name); else dbg_printf("%*.*I64x-%*.*I64x\t%-16s%s\n", ADDRWIDTH, ADDRWIDTH, module->mi.BaseOfImage, ADDRWIDTH, ADDRWIDTH, module->mi.BaseOfImage + module->mi.ImageSize, - is_embedded ? "\\" : get_symtype_str(&module->mi), module->name); + is_embedded ? "\\" : get_symtype_str(module), module->name); } static int __cdecl module_compare(const void* p1, const void* p2) @@ -226,7 +223,9 @@ static BOOL CALLBACK info_mod_cb(PCSTR mod_name, DWORD64 base, PVOID ctx) im->modules = new; } im->modules[im->num_used].mi.SizeOfStruct = sizeof(im->modules[im->num_used].mi); - if (SymGetModuleInfo64(dbg_curr_process->handle, base, &im->modules[im->num_used].mi)) + if (SymGetModuleInfoW64(dbg_curr_process->handle, base, &im->modules[im->num_used].mi) && + wine_get_module_information(dbg_curr_process->handle, base, &im->modules[im->num_used].ext_module_info, + sizeof(im->modules[im->num_used].ext_module_info))) { const int dst_len = sizeof(im->modules[im->num_used].name); lstrcpynA(im->modules[im->num_used].name, mod_name, dst_len - 1); diff --git a/programs/winedbg/winedbg.c b/programs/winedbg/winedbg.c index 438d4a3d94b..92fa77429f6 100644 --- a/programs/winedbg/winedbg.c +++ b/programs/winedbg/winedbg.c @@ -723,6 +723,7 @@ int main(int argc, char** argv) SYMOPT_LOAD_LINES | SYMOPT_DEFERRED_LOADS | SYMOPT_AUTO_PUBLICS | SYMOPT_INCLUDE_32BIT_MODULES); + SymSetExtendedOption(SYMOPT_EX_WINE_EXTENSION_API, TRUE); SymSetExtendedOption(SYMOPT_EX_WINE_SOURCE_ACTUAL_PATH, TRUE); if (argc && !strcmp(argv[0], "--auto"))