This series: - fixes a couple of issues in mach-o modules support (getting information from system modules in wow setups, machine information...) - stops hiding information in some fields between dbghelp and winedbg (using an extensible solution, where more information can be shared in the future) - display elf/mach-o in winedbg (previously mach-o was reported as elf) - display PE native vs builtin module information in winedbg
From: Eric Pouech eric.pouech@gmail.com
Wine-Bugs: https://bugs.winehq.org/show_bug.cgi?id=55650
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/dbghelp/macho_module.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/dlls/dbghelp/macho_module.c b/dlls/dbghelp/macho_module.c index f1b3107408c..cdca7e595b2 100644 --- a/dlls/dbghelp/macho_module.c +++ b/dlls/dbghelp/macho_module.c @@ -744,9 +744,9 @@ static BOOL macho_map_file(struct process *pcs, const WCHAR *filenameW, WCHAR* filename; struct section_info info; BOOL ret = FALSE; - UINT32 target_cpu = (pcs->is_64bit) ? MACHO_CPU_TYPE_X86_64 : MACHO_CPU_TYPE_X86; - UINT32 target_magic = (pcs->is_64bit) ? MACHO_MH_MAGIC_64 : MACHO_MH_MAGIC_32; - UINT32 target_cmd = (pcs->is_64bit) ? MACHO_LC_SEGMENT_64 : MACHO_LC_SEGMENT; + UINT32 target_cpu = (pcs->is_system_64bit) ? MACHO_CPU_TYPE_X86_64 : MACHO_CPU_TYPE_X86; + UINT32 target_magic = (pcs->is_system_64bit) ? MACHO_MH_MAGIC_64 : MACHO_MH_MAGIC_32; + UINT32 target_cmd = (pcs->is_system_64bit) ? MACHO_LC_SEGMENT_64 : MACHO_LC_SEGMENT; DWORD bytes_read;
struct @@ -762,8 +762,8 @@ static BOOL macho_map_file(struct process *pcs, const WCHAR *filenameW, ifm->modtype = DMT_MACHO; ifm->ops = &macho_file_map_ops; ifm->alternate = NULL; - ifm->addr_size = (pcs->is_64bit) ? 64 : 32; - fmap->header_size = (pcs->is_64bit) ? sizeof(struct macho_header) : FIELD_OFFSET(struct macho_header, reserved); + ifm->addr_size = (pcs->is_system_64bit) ? 64 : 32; + fmap->header_size = (pcs->is_system_64bit) ? sizeof(struct macho_header) : FIELD_OFFSET(struct macho_header, reserved);
if (!(filename = get_dos_file_name(filenameW))) return FALSE;
@@ -1339,8 +1339,8 @@ static BOOL image_uses_split_segs(struct process* process, ULONG_PTR load_addr)
if (load_addr) { - UINT32 target_cpu = (process->is_64bit) ? MACHO_CPU_TYPE_X86_64 : MACHO_CPU_TYPE_X86; - UINT32 target_magic = (process->is_64bit) ? MACHO_MH_MAGIC_64 : MACHO_MH_MAGIC_32; + UINT32 target_cpu = (process->is_system_64bit) ? MACHO_CPU_TYPE_X86_64 : MACHO_CPU_TYPE_X86; + UINT32 target_magic = (process->is_system_64bit) ? MACHO_MH_MAGIC_64 : MACHO_MH_MAGIC_32; struct macho_header header;
if (read_process_memory(process, load_addr, &header, FIELD_OFFSET(struct macho_header, reserved)) && @@ -1608,14 +1608,14 @@ static BOOL macho_enum_modules_internal(const struct process* pcs, TRACE("(%p/%p, %s, %p, %p)\n", pcs, pcs->handle, debugstr_w(main_name), cb, user);
- if (pcs->is_64bit) + if (pcs->is_system_64bit) len = sizeof(image_infos.infos64); else len = sizeof(image_infos.infos32); if (!pcs->dbg_hdr_addr || !read_process_memory(pcs, pcs->dbg_hdr_addr, &image_infos, len)) goto done; - if (!pcs->is_64bit) + if (!pcs->is_system_64bit) { struct dyld_all_image_infos32 temp = image_infos.infos32; image_infos.infos64.infoArrayCount = temp.infoArrayCount; @@ -1625,7 +1625,7 @@ static BOOL macho_enum_modules_internal(const struct process* pcs, goto done; TRACE("Process has %u image infos at %I64x\n", image_infos.infos64.infoArrayCount, image_infos.infos64.infoArray);
- if (pcs->is_64bit) + if (pcs->is_system_64bit) len = sizeof(info_array->info64); else len = sizeof(info_array->info32); @@ -1639,7 +1639,7 @@ static BOOL macho_enum_modules_internal(const struct process* pcs, for (i = 0; i < image_infos.infos64.infoArrayCount; i++) { struct dyld_image_info64 info; - if (pcs->is_64bit) + if (pcs->is_system_64bit) info = info_array[i].info64; else { @@ -1829,13 +1829,13 @@ static BOOL macho_search_loader(struct process* pcs, struct macho_info* macho_in char path[1024]; BOOL got_path = FALSE;
- if (pcs->is_64bit) + if (pcs->is_system_64bit) len = sizeof(image_infos.infos64); else len = sizeof(image_infos.infos32); if (read_process_memory(pcs, pcs->dbg_hdr_addr, &image_infos, len)) { - if (pcs->is_64bit) + if (pcs->is_system_64bit) len = sizeof(image_info.info64); else { @@ -1847,7 +1847,7 @@ static BOOL macho_search_loader(struct process* pcs, struct macho_info* macho_in if (image_infos.infos64.infoArray && image_infos.infos64.infoArrayCount && read_process_memory(pcs, image_infos.infos64.infoArray, &image_info, len)) { - if (!pcs->is_64bit) + if (!pcs->is_system_64bit) { struct dyld_image_info32 temp = image_info.info32; image_info.info64.imageLoadAddress = temp.imageLoadAddress;
From: Eric Pouech epouech@codeweavers.com
Signed-off-by: Eric Pouech epouech@codeweavers.com --- dlls/dbghelp/macho_module.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-)
diff --git a/dlls/dbghelp/macho_module.c b/dlls/dbghelp/macho_module.c index cdca7e595b2..a36e737c618 100644 --- a/dlls/dbghelp/macho_module.c +++ b/dlls/dbghelp/macho_module.c @@ -206,6 +206,18 @@ static char* format_uuid(const UINT8 uuid[16], char out[UUID_STRING_LEN]) return out; }
+static USHORT macho_cpu_to_machine(unsigned cpu) +{ + switch (cpu) + { + case MACHO_CPU_TYPE_X86: return IMAGE_FILE_MACHINE_I386; + case MACHO_CPU_TYPE_X86_64: return IMAGE_FILE_MACHINE_AMD64; + default: + FIXME("Untranslated Mach-O CPU %x\n", cpu); + return IMAGE_FILE_MACHINE_UNKNOWN; + } +} + /****************************************************************** * macho_calc_range * @@ -1354,6 +1366,26 @@ static BOOL image_uses_split_segs(struct process* process, ULONG_PTR load_addr) return split_segs; }
+/****************************************************************** + * image_get_machine + * + * For a module identified by its load address, return the machine field + * of the (loaded) Macho header. + */ +static USHORT image_get_machine(struct process *process, ULONG_PTR load_addr) +{ + if (load_addr) + { + struct macho_header header; + UINT32 target_magic = (process->is_system_64bit) ? MACHO_MH_MAGIC_64 : MACHO_MH_MAGIC_32; + + if (read_process_memory(process, load_addr, &header, FIELD_OFFSET(struct macho_header, reserved)) && + header.magic == target_magic) + return macho_cpu_to_machine(header.cputype); + } + return IMAGE_FILE_MACHINE_UNKNOWN; +} + /****************************************************************** * macho_load_debug_info * @@ -1479,7 +1511,7 @@ static BOOL macho_load_file(struct process* pcs, const WCHAR* filename, load_addr = fmap.u.macho.segs_start; macho_info->module = module_new(pcs, filename, DMT_MACHO, FALSE, load_addr, fmap.u.macho.segs_size, 0, calc_crc32(fmap.u.macho.handle), - IMAGE_FILE_MACHINE_UNKNOWN); + image_get_machine(pcs, load_addr)); if (!macho_info->module) { HeapFree(GetProcessHeap(), 0, modfmt);
From: Eric Pouech epouech@codeweavers.com
Signed-off-by: Eric Pouech epouech@codeweavers.com --- dlls/dbghelp/dbghelp_private.h | 2 +- dlls/dbghelp/dwarf.c | 10 ++------ dlls/dbghelp/module.c | 16 +++++++++---- dlls/dbghelp/stabs.c | 2 +- include/dbghelp.h | 44 ++++++++++++++++++++++++++++++++++ programs/winedbg/info.c | 39 ++++++++++++++---------------- 6 files changed, 78 insertions(+), 35 deletions(-)
diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h index 1ce221a0f27..edae3f9324a 100644 --- a/dlls/dbghelp/dbghelp_private.h +++ b/dlls/dbghelp/dbghelp_private.h @@ -445,7 +445,7 @@ struct cpu; struct module { struct process* process; - IMAGEHLP_MODULEW64 module; + WINE_IMAGEHLP_MODULEW64 module; WCHAR modulename[64]; /* used for enumeration */ struct module* next; enum module_type type : 16; diff --git a/dlls/dbghelp/dwarf.c b/dlls/dbghelp/dwarf.c index 2a4f9a16228..c5a9373186a 100644 --- a/dlls/dbghelp/dwarf.c +++ b/dlls/dbghelp/dwarf.c @@ -175,7 +175,6 @@ typedef struct dwarf2_parse_module_context_s const struct elf_thunk_area*thunks; struct vector unit_contexts; struct dwarf2_dwz_alternate_s* dwz; - DWORD cu_versions; } dwarf2_parse_module_context_t;
typedef struct dwarf2_dwz_alternate_s @@ -2893,7 +2892,7 @@ static BOOL dwarf2_parse_compilation_unit_head(dwarf2_parse_context_t* ctx, TRACE("- offset_size: %u\n", ctx->head.offset_size);
if (ctx->head.version >= 2) - ctx->module_ctx->cu_versions |= 1 << (ctx->head.version - 2); + ctx->module_ctx->module->module.DebugFormatMask |= FORMAT_DWARF2 << (ctx->head.version - 2); if (max_supported_dwarf_version == 0) { char* env = getenv("DBGHELP_DWARF_VERSION"); @@ -4112,7 +4111,7 @@ static BOOL dwarf2_load_CU_module(dwarf2_parse_module_context_t* module_ctx, str module_ctx->thunks = thunks; module_ctx->load_offset = load_offset; vector_init(&module_ctx->unit_contexts, sizeof(dwarf2_parse_context_t), 16); - module_ctx->cu_versions = 0; + module_ctx->module->module.DebugFormatMask = 0;
/* phase I: parse all CU heads */ mod_ctx.data = sections[section_debug].address; @@ -4260,11 +4259,6 @@ BOOL dwarf2_parse(struct module* module, ULONG_PTR load_offset, 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; diff --git a/dlls/dbghelp/module.c b/dlls/dbghelp/module.c index 22b58950b43..6c69031ddfd 100644 --- a/dlls/dbghelp/module.c +++ b/dlls/dbghelp/module.c @@ -39,6 +39,8 @@ const WCHAR S_ElfW[] = L"<elf>"; const WCHAR S_WineLoaderW[] = L"<wine-loader>"; static const WCHAR * const ext[] = {L".acm", L".dll", L".drv", L".exe", L".ocx", L".vxd", NULL};
+C_ASSERT(sizeof(IMAGEHLP_MODULEW64) == FIELD_OFFSET(WINE_IMAGEHLP_MODULEW64, Magic)); + static int match_ext(const WCHAR* ptr, size_t len) { const WCHAR* const *e; @@ -225,6 +227,7 @@ struct module* module_new(struct process* pcs, const WCHAR* name, module->module.Publics = FALSE; module->module.MachineType = machine; module->module.Reserved = 0; + module->module.Magic = WINE_IMAGEHLP_MODULE_MAGIC;
module->reloc_delta = 0; module->type = type; @@ -1490,14 +1493,19 @@ BOOL WINAPI SymGetModuleInfo64(HANDLE hProcess, DWORD64 dwAddr, BOOL WINAPI SymGetModuleInfoW64(HANDLE hProcess, DWORD64 dwAddr, PIMAGEHLP_MODULEW64 ModuleInfo) { - struct process* pcs = process_find_by_handle(hProcess); - struct module* module; - IMAGEHLP_MODULEW64 miw64; + struct process* pcs = process_find_by_handle(hProcess); + struct module* module; + WINE_IMAGEHLP_MODULEW64 miw64;
TRACE("%p %I64x %p\n", hProcess, dwAddr, ModuleInfo);
if (!pcs) return FALSE; - if (ModuleInfo->SizeOfStruct > sizeof(*ModuleInfo)) return FALSE; + if (ModuleInfo->SizeOfStruct > sizeof(*ModuleInfo)) + { + if (!dbghelp_opt_native || ModuleInfo->SizeOfStruct != sizeof(miw64) || + ((WINE_IMAGEHLP_MODULEW64*)ModuleInfo)->Magic != WINE_IMAGEHLP_MODULE_MAGIC) + return FALSE; + } module = module_find_by_addr(pcs, dwAddr, DMT_UNKNOWN); if (!module) return FALSE;
diff --git a/dlls/dbghelp/stabs.c b/dlls/dbghelp/stabs.c index f21f7e15d0b..c44257037a9 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->module.DebugFormatMask |= 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 15e9f9d2d77..e864052ab32 100644 --- a/include/dbghelp.h +++ b/include/dbghelp.h @@ -255,6 +255,50 @@ typedef struct _IMAGEHLP_MODULEW64 DWORD Reserved; } IMAGEHLP_MODULEW64, *PIMAGEHLP_MODULEW64;
+#ifdef __WINESRC__ +/* Wine's own extention of IMAGEHLP_MODULEW64 */ +typedef struct +{ + DWORD SizeOfStruct; + DWORD64 BaseOfImage; + DWORD ImageSize; + DWORD TimeDateStamp; + DWORD CheckSum; + DWORD NumSyms; + SYM_TYPE SymType; + WCHAR ModuleName[32]; + WCHAR ImageName[256]; + WCHAR LoadedImageName[256]; + WCHAR LoadedPdbName[256]; + DWORD CVSig; + WCHAR CVData[MAX_PATH*3]; + DWORD PdbSig; + GUID PdbSig70; + DWORD PdbAge; + BOOL PdbUnmatched; + BOOL DbgUnmatched; + BOOL LineNumbers; + BOOL GlobalSymbols; + BOOL TypeInfo; + BOOL SourceIndexed; + BOOL Publics; + DWORD MachineType; + DWORD Reserved; + /* Wine's specific extensions (fields above must be in sync with IMAGELP_MODULEW64) */ + DWORD DECLSPEC_ALIGN(8) Magic; + enum format_mask /* when SymType is SymDIA */ + { + FORMAT_DWARF2 = 0x00000001, + FORMAT_DWARF3 = 0x00000002, + FORMAT_DWARF4 = 0x00000004, + FORMAT_DWARF5 = 0x00000008, + FORMAT_DWARF = 0x0000000F, + FORMAT_STABS = 0x00010000, + } DebugFormatMask; +} WINE_IMAGEHLP_MODULEW64; +#define WINE_IMAGEHLP_MODULE_MAGIC 0xB0507E17 +#endif /* __WINESRC__ */ + #if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) #define IMAGEHLP_LINE IMAGEHLP_LINE64 #define PIMAGEHLP_LINE PIMAGEHLP_LINE64 diff --git a/programs/winedbg/info.c b/programs/winedbg/info.c index 251b92c607b..a46ecec923a 100644 --- a/programs/winedbg/info.c +++ b/programs/winedbg/info.c @@ -116,7 +116,7 @@ void info_help(void) while (infotext[i]) dbg_printf("%s\n", infotext[i++]); }
-static const char* get_symtype_str(const IMAGEHLP_MODULE64* mi) +static const char* get_symtype_str(const WINE_IMAGEHLP_MODULEW64* mi) { switch (mi->SymType) { @@ -129,34 +129,30 @@ static const char* get_symtype_str(const IMAGEHLP_MODULE64* mi) case SymDeferred: return "Deferred"; case SymSym: return "Sym"; case SymDia: - switch (mi->CVSig) + if (mi->DebugFormatMask) { - 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 (mi->DebugFormatMask & FORMAT_STABS) strcpy(tmp, "stabs"); + if (mi->DebugFormatMask & FORMAT_DWARF) { - 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 (mi->DebugFormatMask & FORMAT_DWARF2) strcat(tmp, "-2"); + if (mi->DebugFormatMask & FORMAT_DWARF3) strcat(tmp, "-3"); + if (mi->DebugFormatMask & FORMAT_DWARF4) strcat(tmp, "-4"); + if (mi->DebugFormatMask & FORMAT_DWARF5) strcat(tmp, "-5"); } - return "DIA"; + return tmp; } + return "DIA"; } }
struct info_module { - IMAGEHLP_MODULE64 mi; - char name[64]; + WINE_IMAGEHLP_MODULEW64 mi; + char name[64]; };
struct info_modules @@ -226,7 +222,8 @@ 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)) + im->modules[im->num_used].mi.Magic = WINE_IMAGEHLP_MODULE_MAGIC; + if (SymGetModuleInfoW64(dbg_curr_process->handle, base, (IMAGEHLP_MODULEW64*)&im->modules[im->num_used].mi)) { const int dst_len = sizeof(im->modules[im->num_used].name); lstrcpynA(im->modules[im->num_used].name, mod_name, dst_len - 1);
From: Eric Pouech epouech@codeweavers.com
Under MacOS, lots of modules were incorrectly reported as 'ELF' modules. Use a generic model to advertize from dbghelp to winedbg if a module is a system module, and if so, what's its underlying file format.
Signed-off-by: Eric Pouech epouech@codeweavers.com --- dlls/dbghelp/dbghelp_private.h | 1 - dlls/dbghelp/elf_module.c | 4 ++- dlls/dbghelp/macho_module.c | 2 ++ dlls/dbghelp/module.c | 11 ++----- include/dbghelp.h | 6 ++++ programs/winedbg/info.c | 53 ++++++++++++++++++++++++++-------- 6 files changed, 55 insertions(+), 22 deletions(-)
diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h index edae3f9324a..05a1b53d41c 100644 --- a/dlls/dbghelp/dbghelp_private.h +++ b/dlls/dbghelp/dbghelp_private.h @@ -724,7 +724,6 @@ extern BOOL macho_read_wine_loader_dbg_info(struct process* pcs, ULONG_P void minidump_add_memory_block(struct dump_context* dc, ULONG64 base, ULONG size, ULONG rva) DECLSPEC_HIDDEN;
/* module.c */ -extern const WCHAR S_ElfW[] DECLSPEC_HIDDEN; extern const WCHAR S_WineLoaderW[] DECLSPEC_HIDDEN; extern const struct loader_ops no_loader_ops DECLSPEC_HIDDEN; extern const struct loader_ops empty_loader_ops DECLSPEC_HIDDEN; diff --git a/dlls/dbghelp/elf_module.c b/dlls/dbghelp/elf_module.c index a2a60752a68..248eee60734 100644 --- a/dlls/dbghelp/elf_module.c +++ b/dlls/dbghelp/elf_module.c @@ -1083,7 +1083,7 @@ static BOOL elf_load_debug_info_from_map(struct module* module, lret = dwarf2_parse(module, module->reloc_delta, thunks, fmap); ret = ret || lret; } - if (wcsstr(module->modulename, S_ElfW) || !wcscmp(module->modulename, S_WineLoaderW)) + if (module->format_info[DFI_ELF] || !wcscmp(module->modulename, S_WineLoaderW)) { /* add the thunks for native libraries */ if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY)) @@ -1249,6 +1249,7 @@ static BOOL elf_load_file_from_fmap(struct process* pcs, const WCHAR* filename, HeapFree(GetProcessHeap(), 0, modfmt); return FALSE; } + elf_info->module->module.SystemModule = WINE_SYSMODULE_ELF; elf_info->module->reloc_delta = elf_info->module->module.BaseOfImage - fmap->u.elf.elf_start; elf_module_info = (void*)(modfmt + 1); elf_info->module->format_info[DFI_ELF] = modfmt; @@ -1791,6 +1792,7 @@ BOOL elf_read_wine_loader_dbg_info(struct process* pcs, ULONG_PTR addr) TRACE("Found ELF debug header %#I64x\n", elf_info.dbg_hdr_addr); elf_info.module->format_info[DFI_ELF]->u.elf_info->elf_loader = 1; module_set_module(elf_info.module, S_WineLoaderW); + elf_info.module->module.SystemModule = WINE_SYSMODULE_ELF; pcs->dbg_hdr_addr = elf_info.dbg_hdr_addr; pcs->loader = &elf_loader_ops; return TRUE; diff --git a/dlls/dbghelp/macho_module.c b/dlls/dbghelp/macho_module.c index a36e737c618..b8783eac7e9 100644 --- a/dlls/dbghelp/macho_module.c +++ b/dlls/dbghelp/macho_module.c @@ -1517,6 +1517,7 @@ static BOOL macho_load_file(struct process* pcs, const WCHAR* filename, HeapFree(GetProcessHeap(), 0, modfmt); goto leave; } + macho_info->module->module.SystemModule = WINE_SYSMODULE_MACHO; macho_info->module->reloc_delta = macho_info->module->module.BaseOfImage - fmap.u.macho.segs_start; macho_module_info = (void*)(modfmt + 1); macho_info->module->format_info[DFI_MACHO] = modfmt; @@ -1948,6 +1949,7 @@ BOOL macho_read_wine_loader_dbg_info(struct process* pcs, ULONG_PTR addr) if (!macho_search_loader(pcs, &macho_info)) return FALSE; macho_info.module->format_info[DFI_MACHO]->u.macho_info->is_loader = 1; module_set_module(macho_info.module, S_WineLoaderW); + macho_info.module->module.SystemModule = WINE_SYSMODULE_MACHO; pcs->loader = &macho_loader_ops; TRACE("Found macho debug header %#Ix\n", pcs->dbg_hdr_addr); return TRUE; diff --git a/dlls/dbghelp/module.c b/dlls/dbghelp/module.c index 6c69031ddfd..e52ee7e35a1 100644 --- a/dlls/dbghelp/module.c +++ b/dlls/dbghelp/module.c @@ -35,7 +35,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
#define NOTE_GNU_BUILD_ID 3
-const WCHAR S_ElfW[] = L"<elf>"; const WCHAR S_WineLoaderW[] = L"<wine-loader>"; static const WCHAR * const ext[] = {L".acm", L".dll", L".drv", L".exe", L".ocx", L".vxd", NULL};
@@ -103,7 +102,7 @@ static BOOL is_wine_loader(const WCHAR *module) static void module_fill_module(const WCHAR* in, WCHAR* out, size_t size) { const WCHAR *ptr, *endptr; - size_t len, l; + size_t len;
endptr = in + lstrlenW(in); endptr -= match_ext(in, endptr - in); @@ -113,12 +112,6 @@ static void module_fill_module(const WCHAR* in, WCHAR* out, size_t size) out[len] = '\0'; if (is_wine_loader(out)) lstrcpynW(out, S_WineLoaderW, size); - else - { - if (len > 3 && !wcsicmp(&out[len - 3], L".so") && - (l = match_ext(out, len - 3))) - lstrcpyW(&out[len - l - 3], L"<elf>"); - } while ((*out = towlower(*out))) out++; }
@@ -229,6 +222,8 @@ struct module* module_new(struct process* pcs, const WCHAR* name, module->module.Reserved = 0; module->module.Magic = WINE_IMAGEHLP_MODULE_MAGIC;
+ module->module.SystemModule = WINE_SYSMODULE_NONE; + module->reloc_delta = 0; module->type = type; module->is_virtual = virtual; diff --git a/include/dbghelp.h b/include/dbghelp.h index e864052ab32..030e328a9ec 100644 --- a/include/dbghelp.h +++ b/include/dbghelp.h @@ -295,6 +295,12 @@ typedef struct FORMAT_DWARF = 0x0000000F, FORMAT_STABS = 0x00010000, } DebugFormatMask; + enum wine_sysmodule + { + WINE_SYSMODULE_NONE, + WINE_SYSMODULE_ELF, + WINE_SYSMODULE_MACHO, + } SystemModule; } WINE_IMAGEHLP_MODULEW64; #define WINE_IMAGEHLP_MODULE_MAGIC 0xB0507E17 #endif /* __WINESRC__ */ diff --git a/programs/winedbg/info.c b/programs/winedbg/info.c index a46ecec923a..1fde9641fa1 100644 --- a/programs/winedbg/info.c +++ b/programs/winedbg/info.c @@ -149,10 +149,20 @@ static const char* get_symtype_str(const WINE_IMAGEHLP_MODULEW64* mi) } }
+enum module_kind {MODKIND_SYSTEM = 0x00, MODKIND_ELF = 0x01, MODKIND_MACHO = 0x02, + MODKIND_PE = 0x10, MODKIND_PE_FAKEDLL = 0x11, + MODKIND_ERROR = 0x80}; + +static inline enum module_kind modkind_get_family(enum module_kind mk) +{ + return mk & 0xf0; +} + struct info_module { WINE_IMAGEHLP_MODULEW64 mi; char name[64]; + enum module_kind kind; };
struct info_modules @@ -210,6 +220,20 @@ static inline BOOL module_is_container(const struct info_module *wmod_cntnr, wmod_child->mi.BaseOfImage + wmod_child->mi.ImageSize; }
+static inline const char* module_get_type_name(const struct info_module* mod) +{ + switch (mod->kind) + { + case MODKIND_SYSTEM: return "System"; + case MODKIND_ELF: return "ELF"; + case MODKIND_MACHO: return "Mach-O"; + case MODKIND_PE_FAKEDLL: + case MODKIND_PE: return "PE"; + case MODKIND_ERROR: break; + } + return ""; +} + static BOOL CALLBACK info_mod_cb(PCSTR mod_name, DWORD64 base, PVOID ctx) { struct info_modules *im = ctx; @@ -225,9 +249,17 @@ static BOOL CALLBACK info_mod_cb(PCSTR mod_name, DWORD64 base, PVOID ctx) im->modules[im->num_used].mi.Magic = WINE_IMAGEHLP_MODULE_MAGIC; if (SymGetModuleInfoW64(dbg_curr_process->handle, base, (IMAGEHLP_MODULEW64*)&im->modules[im->num_used].mi)) { - const int dst_len = sizeof(im->modules[im->num_used].name); - lstrcpynA(im->modules[im->num_used].name, mod_name, dst_len - 1); - im->modules[im->num_used].name[dst_len - 1] = 0; + struct info_module* mod = &im->modules[im->num_used]; + static const size_t dst_len = sizeof(mod->name) - 1; + + switch (mod->mi.SystemModule) + { + case WINE_SYSMODULE_ELF: mod->kind = MODKIND_ELF; break; + case WINE_SYSMODULE_MACHO: mod->kind = MODKIND_MACHO; break; + case WINE_SYSMODULE_NONE: mod->kind = MODKIND_PE; break; + } + lstrcpynA(mod->name, mod_name, dst_len); + mod->name[dst_len] = 0; im->num_used++; } return TRUE; @@ -286,14 +318,14 @@ void info_win32_module(DWORD64 base, BOOL multi_machine) (base < im.modules[i].mi.BaseOfImage || base >= im.modules[i].mi.BaseOfImage + im.modules[i].mi.ImageSize)) continue; if (!multi_machine && machine != im.modules[i].mi.MachineType) continue; - if (strstr(im.modules[i].name, "<elf>")) + if (modkind_get_family(im.modules[i].kind) == MODKIND_SYSTEM) { - dbg_printf("ELF\t"); + dbg_printf("%s\t", module_get_type_name(&im.modules[i])); module_print_info(&im.modules[i], FALSE, multi_machine); /* print all modules embedded in this one */ for (j = 0; j < im.num_used; j++) { - if (!strstr(im.modules[j].name, "<elf>") && module_is_container(&im.modules[i], &im.modules[j])) + if (modkind_get_family(im.modules[j].kind) == MODKIND_PE && module_is_container(&im.modules[i], &im.modules[j])) { dbg_printf(" \-PE\t"); module_print_info(&im.modules[j], TRUE, multi_machine); @@ -303,16 +335,13 @@ void info_win32_module(DWORD64 base, BOOL multi_machine) else { /* check module is not embedded in another module */ - for (j = 0; j < im.num_used; j++) + for (j = 0; j < im.num_used; j++) { - if (strstr(im.modules[j].name, "<elf>") && module_is_container(&im.modules[j], &im.modules[i])) + if (modkind_get_family(im.modules[j].kind) == MODKIND_SYSTEM && module_is_container(&im.modules[j], &im.modules[i])) break; } if (j < im.num_used) continue; - if (strstr(im.modules[i].name, ".so") || strchr(im.modules[i].name, '<')) - dbg_printf("ELF\t"); - else - dbg_printf("PE\t"); + dbg_printf("%s\t", module_get_type_name(&im.modules[i])); module_print_info(&im.modules[i], FALSE, multi_machine); } num_printed++;
From: Eric Pouech epouech@codeweavers.com
Signed-off-by: Eric Pouech epouech@codeweavers.com --- programs/winedbg/info.c | 54 +++++++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 15 deletions(-)
diff --git a/programs/winedbg/info.c b/programs/winedbg/info.c index 1fde9641fa1..3e3d2e5c9a3 100644 --- a/programs/winedbg/info.c +++ b/programs/winedbg/info.c @@ -150,7 +150,7 @@ static const char* get_symtype_str(const WINE_IMAGEHLP_MODULEW64* mi) }
enum module_kind {MODKIND_SYSTEM = 0x00, MODKIND_ELF = 0x01, MODKIND_MACHO = 0x02, - MODKIND_PE = 0x10, MODKIND_PE_FAKEDLL = 0x11, + MODKIND_PE = 0x10, MODKIND_PE_FAKEDLL = 0x11, MODKIND_PE_NATIVE = 0x12, MODKIND_PE_BUILTIN = 0x13, MODKIND_ERROR = 0x80};
static inline enum module_kind modkind_get_family(enum module_kind mk) @@ -186,6 +186,32 @@ static const char* get_machine_str(DWORD machine) } }
+static const char builtin_signature[] = "Wine builtin DLL"; +static const char fakedll_signature[] = "Wine placeholder DLL"; + +static enum module_kind get_pe_module_kind(const struct info_module* module) +{ + char tmp[sizeof(IMAGE_DOS_HEADER) + 32]; + + if (dbg_read_memory((void*)(ULONG_PTR)module->mi.BaseOfImage, tmp, sizeof(tmp))) + { + const IMAGE_DOS_HEADER* dosh = (IMAGE_DOS_HEADER*)tmp; + if (dosh->e_magic == IMAGE_DOS_SIGNATURE) + { + SIZE_T len = dosh->e_lfanew; + if (len >= sizeof(IMAGE_DOS_HEADER) + 32) + { + if (!strcmp((char*)(dosh + 1), builtin_signature)) + return MODKIND_PE_BUILTIN; + if (!strcmp((char*)(dosh + 1), fakedll_signature)) + return MODKIND_PE_FAKEDLL; + } + return MODKIND_PE_NATIVE; + } + } + return MODKIND_ERROR; +} + static void module_print_info(const struct info_module *module, BOOL is_embedded, BOOL multi_machine) { if (multi_machine) @@ -227,8 +253,10 @@ static inline const char* module_get_type_name(const struct info_module* mod) case MODKIND_SYSTEM: return "System"; case MODKIND_ELF: return "ELF"; case MODKIND_MACHO: return "Mach-O"; - case MODKIND_PE_FAKEDLL: + case MODKIND_PE_NATIVE: case MODKIND_PE: return "PE"; + case MODKIND_PE_FAKEDLL: + case MODKIND_PE_BUILTIN: return "PE-Wine"; case MODKIND_ERROR: break; } return ""; @@ -254,9 +282,9 @@ static BOOL CALLBACK info_mod_cb(PCSTR mod_name, DWORD64 base, PVOID ctx)
switch (mod->mi.SystemModule) { - case WINE_SYSMODULE_ELF: mod->kind = MODKIND_ELF; break; - case WINE_SYSMODULE_MACHO: mod->kind = MODKIND_MACHO; break; - case WINE_SYSMODULE_NONE: mod->kind = MODKIND_PE; break; + case WINE_SYSMODULE_ELF: mod->kind = MODKIND_ELF; break; + case WINE_SYSMODULE_MACHO: mod->kind = MODKIND_MACHO; break; + case WINE_SYSMODULE_NONE: mod->kind = get_pe_module_kind(mod); break; } lstrcpynA(mod->name, mod_name, dst_len); mod->name[dst_len] = 0; @@ -314,36 +342,32 @@ void info_win32_module(DWORD64 base, BOOL multi_machine)
for (i = 0; i < im.num_used; i++) { + enum module_kind mod_family = modkind_get_family(im.modules[i].kind); if (base && (base < im.modules[i].mi.BaseOfImage || base >= im.modules[i].mi.BaseOfImage + im.modules[i].mi.ImageSize)) continue; if (!multi_machine && machine != im.modules[i].mi.MachineType) continue; - if (modkind_get_family(im.modules[i].kind) == MODKIND_SYSTEM) + if (mod_family == MODKIND_SYSTEM) { dbg_printf("%s\t", module_get_type_name(&im.modules[i])); module_print_info(&im.modules[i], FALSE, multi_machine); /* print all modules embedded in this one */ for (j = 0; j < im.num_used; j++) { - if (modkind_get_family(im.modules[j].kind) == MODKIND_PE && module_is_container(&im.modules[i], &im.modules[j])) + if (modkind_get_family(im.modules[j].kind) == MODKIND_PE_FAKEDLL && module_is_container(&im.modules[i], &im.modules[j])) { dbg_printf(" \-PE\t"); module_print_info(&im.modules[j], TRUE, multi_machine); } } } - else + else if (mod_family == MODKIND_PE && im.modules[i].kind != MODKIND_PE_FAKEDLL) { - /* check module is not embedded in another module */ - for (j = 0; j < im.num_used; j++) - { - if (modkind_get_family(im.modules[j].kind) == MODKIND_SYSTEM && module_is_container(&im.modules[j], &im.modules[i])) - break; - } - if (j < im.num_used) continue; dbg_printf("%s\t", module_get_type_name(&im.modules[i])); module_print_info(&im.modules[i], FALSE, multi_machine); } + else continue; + num_printed++; } free(im.modules);
Alexandre Julliard (@julliard) commented about include/dbghelp.h:
- {
FORMAT_DWARF2 = 0x00000001,
FORMAT_DWARF3 = 0x00000002,
FORMAT_DWARF4 = 0x00000004,
FORMAT_DWARF5 = 0x00000008,
FORMAT_DWARF = 0x0000000F,
FORMAT_STABS = 0x00010000,
- } DebugFormatMask;
- enum wine_sysmodule
- {
WINE_SYSMODULE_NONE,
WINE_SYSMODULE_ELF,
WINE_SYSMODULE_MACHO,
- } SystemModule;
+} WINE_IMAGEHLP_MODULEW64; +#define WINE_IMAGEHLP_MODULE_MAGIC 0xB0507E17
That's not very nice. Do we really need to export that info in the first place? And if so, do we really need to abuse an existing API structure?
On Thu Oct 5 19:35:47 2023 +0000, Alexandre Julliard wrote:
That's not very nice. Do we really need to export that info in the first place? And if so, do we really need to abuse an existing API structure?
we are already abusing this structure in many ways:
* decorate module name to advertize if the module is an host (elf/mach-o) module (vs PE module) * override meaning of some fields (eg dwarf info) * exposing real unix path of loaded image (needed to pass it to gdb in proxy mode)
most of these behaviors are only activated when setting some wine specific dbghelp's options (which are defined in dbghelp.h), but still have some limitation:
* module name decoration shortens the effective module name, with potential name clash * dwarf information is not protected by wine only option (but that's simple to change) * some of the override above shadow some information ; luckily as of today, the context of the call in winedbg decides whether to ask for the overridden value
but the core of the question is:
* do we reimplement on winedbg side a good part of what already exists in dbghelp (for example, list of loaded modules on winedbg side has been added to keep track of TLS debug directory information from PE image) * exposing native/builtin nature of PE images (IMO interesting for user report perspectives to detect module overrides): this can be done on winedbg side, but requires actual path to loaded module (cf gdbproxy) + query:ing image ; this could be simply exposed from dbghelp
so the more we stick to a pure dbghelp definition, the more we reimplement on the winedbg side
as an example, the real unix path of a module (which is gotten from the file handle passed in load dll debug event) could be only stored in winedbg but this would require rewriting a couple of winedbg functions using the internal winedbg module list rather than calling dbghelp for loaded modules
or the system vs PE image nature can also be obtained on winedbg side
I was more tempted not to replicate code and concentrate at most in dbghelp at the expense of twisting some API's output ; but I'm fine with the other way too
It can be implemented in dbghelp, but I don't think we need to shoehorn it into existing APIs. That's OK if it's just a flag here and there, but if we need more it would be better to export some Wine-specific entry points in dbghelp for things that can't be expressed through the MS API.
On Fri Oct 6 09:43:45 2023 +0000, Alexandre Julliard wrote:
It can be implemented in dbghelp, but I don't think we need to shoehorn it into existing APIs. That's OK if it's just a flag here and there, but if we need more it would be better to export some Wine-specific entry points in dbghelp for things that can't be expressed through the MS API.
I was reluctant to add new entry points because of https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/writing-... (native dbghelp has a couple of such entry points ; some are just commented out in wine's .spec file). but I guess (paranoids welcomed) we can protect usage of such an API with an extended dbghelp option
I'll update the MR accordingly