Allow 64bit dbghelp handle a 32bit target on WOW64 context. The good news is that the serie is rather small.
Changes in v2: - rebased because of conflict with Michael Stefaniuc patch - in third patch, just offset PEB64 address to get to PEB32
A+
---
Eric Pouech (3): dbghelp: split storage of PE header dbghelp: now storing the IMAGE_OPTIONAL_HEADER in either 32bit or 64bit form dbghelp: fix failing SymInitialize for a live 32bit target from a 64bit caller in WOW64
dlls/dbghelp/dbghelp.c | 14 ++++++++++---- dlls/dbghelp/image_private.h | 6 +++++- dlls/dbghelp/pe_module.c | 37 ++++++++++++++++++++++++++---------- 3 files changed, 42 insertions(+), 15 deletions(-)
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/image_private.h | 3 ++- dlls/dbghelp/pe_module.c | 49 +++++++++++++++++++++--------------------- 2 files changed, 27 insertions(+), 25 deletions(-)
diff --git a/dlls/dbghelp/image_private.h b/dlls/dbghelp/image_private.h index 870f5300575..8d44458b7c9 100644 --- a/dlls/dbghelp/image_private.h +++ b/dlls/dbghelp/image_private.h @@ -150,7 +150,8 @@ struct image_file_map struct pe_file_map { HANDLE hMap; - IMAGE_NT_HEADERS ntheader; + IMAGE_FILE_HEADER file_header; + IMAGE_OPTIONAL_HEADER opt_header; BOOL builtin; unsigned full_count; void* full_map; diff --git a/dlls/dbghelp/pe_module.c b/dlls/dbghelp/pe_module.c index f0ca20e5e4f..e796622ae87 100644 --- a/dlls/dbghelp/pe_module.c +++ b/dlls/dbghelp/pe_module.c @@ -75,7 +75,7 @@ static const char* pe_map_section(struct image_section_map* ism) void* mapping; struct pe_file_map* fmap = &ism->fmap->u.pe;
- if (ism->sidx >= 0 && ism->sidx < fmap->ntheader.FileHeader.NumberOfSections && + if (ism->sidx >= 0 && ism->sidx < fmap->file_header.NumberOfSections && fmap->sect[ism->sidx].mapped == IMAGE_NO_MAP) { IMAGE_NT_HEADERS* nth; @@ -115,7 +115,7 @@ static BOOL pe_find_section(struct image_file_map* fmap, const char* name, unsigned i; char tmp[IMAGE_SIZEOF_SHORT_NAME + 1];
- for (i = 0; i < fmap->u.pe.ntheader.FileHeader.NumberOfSections; i++) + for (i = 0; i < fmap->u.pe.file_header.NumberOfSections; i++) { sectname = (const char*)fmap->u.pe.sect[i].shdr.Name; /* long section names start with a '/' (at least on MinGW32) */ @@ -147,7 +147,7 @@ static BOOL pe_find_section(struct image_file_map* fmap, const char* name, */ static void pe_unmap_section(struct image_section_map* ism) { - if (ism->sidx >= 0 && ism->sidx < ism->fmap->u.pe.ntheader.FileHeader.NumberOfSections && + if (ism->sidx >= 0 && ism->sidx < ism->fmap->u.pe.file_header.NumberOfSections && ism->fmap->u.pe.sect[ism->sidx].mapped != IMAGE_NO_MAP) { pe_unmap_full(ism->fmap); @@ -162,7 +162,7 @@ static void pe_unmap_section(struct image_section_map* ism) */ static DWORD_PTR pe_get_map_rva(const struct image_section_map* ism) { - if (ism->sidx < 0 || ism->sidx >= ism->fmap->u.pe.ntheader.FileHeader.NumberOfSections) + if (ism->sidx < 0 || ism->sidx >= ism->fmap->u.pe.file_header.NumberOfSections) return 0; return ism->fmap->u.pe.sect[ism->sidx].shdr.VirtualAddress; } @@ -174,7 +174,7 @@ static DWORD_PTR pe_get_map_rva(const struct image_section_map* ism) */ static unsigned pe_get_map_size(const struct image_section_map* ism) { - if (ism->sidx < 0 || ism->sidx >= ism->fmap->u.pe.ntheader.FileHeader.NumberOfSections) + if (ism->sidx < 0 || ism->sidx >= ism->fmap->u.pe.file_header.NumberOfSections) return 0; return ism->fmap->u.pe.sect[ism->sidx].shdr.Misc.VirtualSize; } @@ -190,7 +190,7 @@ static void pe_unmap_file(struct image_file_map* fmap) { struct image_section_map ism; ism.fmap = fmap; - for (ism.sidx = 0; ism.sidx < fmap->u.pe.ntheader.FileHeader.NumberOfSections; ism.sidx++) + for (ism.sidx = 0; ism.sidx < fmap->u.pe.file_header.NumberOfSections; ism.sidx++) { pe_unmap_section(&ism); } @@ -258,7 +258,8 @@ BOOL pe_map_file(HANDLE file, struct image_file_map* fmap, enum module_type mt) unsigned i;
if (!(nthdr = RtlImageNtHeader(mapping))) goto error; - memcpy(&fmap->u.pe.ntheader, nthdr, sizeof(fmap->u.pe.ntheader)); + memcpy(&fmap->u.pe.file_header, &nthdr->FileHeader, sizeof(fmap->u.pe.file_header)); + memcpy(&fmap->u.pe.opt_header, &nthdr->OptionalHeader, sizeof(fmap->u.pe.opt_header)); switch (nthdr->OptionalHeader.Magic) { case 0x10b: fmap->addr_size = 32; break; @@ -298,8 +299,8 @@ BOOL pe_map_file(HANDLE file, struct image_file_map* fmap, enum module_type mt) { WARN("Bad coff table... wipping out\n"); /* we have bad information here, wipe it out */ - fmap->u.pe.ntheader.FileHeader.PointerToSymbolTable = 0; - fmap->u.pe.ntheader.FileHeader.NumberOfSymbols = 0; + fmap->u.pe.file_header.PointerToSymbolTable = 0; + fmap->u.pe.file_header.NumberOfSymbols = 0; fmap->u.pe.strtable = NULL; } } @@ -362,16 +363,16 @@ static BOOL pe_locate_with_coff_symbol_table(struct module* module) struct symt_data* sym; const char* mapping;
- numsym = fmap->u.pe.ntheader.FileHeader.NumberOfSymbols; - if (!fmap->u.pe.ntheader.FileHeader.PointerToSymbolTable || !numsym) + numsym = fmap->u.pe.file_header.NumberOfSymbols; + if (!fmap->u.pe.file_header.PointerToSymbolTable || !numsym) return TRUE; if (!(mapping = pe_map_full(fmap, NULL))) return FALSE; - isym = (const IMAGE_SYMBOL*)(mapping + fmap->u.pe.ntheader.FileHeader.PointerToSymbolTable); + isym = (const IMAGE_SYMBOL*)(mapping + fmap->u.pe.file_header.PointerToSymbolTable);
for (i = 0; i < numsym; i+= naux, isym += naux) { if (isym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL && - isym->SectionNumber > 0 && isym->SectionNumber <= fmap->u.pe.ntheader.FileHeader.NumberOfSections) + isym->SectionNumber > 0 && isym->SectionNumber <= fmap->u.pe.file_header.NumberOfSections) { if (isym->N.Name.Short) { @@ -424,11 +425,11 @@ static BOOL pe_load_coff_symbol_table(struct module* module) const IMAGE_SECTION_HEADER* sect; const char* mapping;
- numsym = fmap->u.pe.ntheader.FileHeader.NumberOfSymbols; - if (!fmap->u.pe.ntheader.FileHeader.PointerToSymbolTable || !numsym) + numsym = fmap->u.pe.file_header.NumberOfSymbols; + if (!fmap->u.pe.file_header.PointerToSymbolTable || !numsym) return TRUE; if (!(mapping = pe_map_full(fmap, NULL))) return FALSE; - isym = (const IMAGE_SYMBOL*)(mapping + fmap->u.pe.ntheader.FileHeader.PointerToSymbolTable); + isym = (const IMAGE_SYMBOL*)(mapping + fmap->u.pe.file_header.PointerToSymbolTable); /* FIXME: no way to get strtable size */ strtable = (const char*)&isym[numsym]; sect = IMAGE_FIRST_SECTION(RtlImageNtHeader((HMODULE)mapping)); @@ -441,7 +442,7 @@ static BOOL pe_load_coff_symbol_table(struct module* module) compiland = NULL; } if (isym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL && - isym->SectionNumber > 0 && isym->SectionNumber <= fmap->u.pe.ntheader.FileHeader.NumberOfSections) + isym->SectionNumber > 0 && isym->SectionNumber <= fmap->u.pe.file_header.NumberOfSections) { if (isym->N.Name.Short) { @@ -496,7 +497,7 @@ static BOOL pe_load_stabs(const struct process* pcs, struct module* module) if (stab != IMAGE_NO_MAP && stabstr != IMAGE_NO_MAP) { ret = stabs_parse(module, - module->module.BaseOfImage - fmap->u.pe.ntheader.OptionalHeader.ImageBase, + module->module.BaseOfImage - fmap->u.pe.opt_header.ImageBase, stab, image_get_map_size(§_stabs) / sizeof(struct stab_nlist), sizeof(struct stab_nlist), stabstr, image_get_map_size(§_stabstr), NULL, NULL); @@ -522,7 +523,7 @@ static BOOL pe_load_dwarf(struct module* module) BOOL ret;
ret = dwarf2_parse(module, - module->module.BaseOfImage - fmap->u.pe.ntheader.OptionalHeader.ImageBase, + module->module.BaseOfImage - fmap->u.pe.opt_header.ImageBase, NULL, /* FIXME: some thunks to deal with ? */ fmap); TRACE("%s the DWARF debug info\n", ret ? "successfully loaded" : "failed to load"); @@ -792,12 +793,12 @@ struct module* pe_load_native_module(struct process* pcs, const WCHAR* name, image_unmap_file(&modfmt->u.pe_info->fmap); modfmt->u.pe_info->fmap = builtin.fmap; } - if (!base) base = modfmt->u.pe_info->fmap.u.pe.ntheader.OptionalHeader.ImageBase; - if (!size) size = modfmt->u.pe_info->fmap.u.pe.ntheader.OptionalHeader.SizeOfImage; + if (!base) base = modfmt->u.pe_info->fmap.u.pe.opt_header.ImageBase; + if (!size) size = modfmt->u.pe_info->fmap.u.pe.opt_header.SizeOfImage;
module = module_new(pcs, loaded_name, DMT_PE, FALSE, base, size, - modfmt->u.pe_info->fmap.u.pe.ntheader.FileHeader.TimeDateStamp, - modfmt->u.pe_info->fmap.u.pe.ntheader.OptionalHeader.CheckSum); + modfmt->u.pe_info->fmap.u.pe.file_header.TimeDateStamp, + modfmt->u.pe_info->fmap.u.pe.opt_header.CheckSum); if (module) { module->real_path = builtin.path; @@ -810,7 +811,7 @@ struct module* pe_load_native_module(struct process* pcs, const WCHAR* name, module->module.SymType = SymDeferred; else pe_load_debug_info(pcs, module); - module->reloc_delta = base - modfmt->u.pe_info->fmap.u.pe.ntheader.OptionalHeader.ImageBase; + module->reloc_delta = base - modfmt->u.pe_info->fmap.u.pe.opt_header.ImageBase; } else {
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/image_private.h | 6 +++++- dlls/dbghelp/pe_module.c | 37 +++++++++++++++++++++++++++---------- 2 files changed, 32 insertions(+), 11 deletions(-)
diff --git a/dlls/dbghelp/image_private.h b/dlls/dbghelp/image_private.h index 8d44458b7c9..83442ffb9e1 100644 --- a/dlls/dbghelp/image_private.h +++ b/dlls/dbghelp/image_private.h @@ -151,7 +151,11 @@ struct image_file_map { HANDLE hMap; IMAGE_FILE_HEADER file_header; - IMAGE_OPTIONAL_HEADER opt_header; + union + { + IMAGE_OPTIONAL_HEADER32 header32; + IMAGE_OPTIONAL_HEADER64 header64; + } opt; BOOL builtin; unsigned full_count; void* full_map; diff --git a/dlls/dbghelp/pe_module.c b/dlls/dbghelp/pe_module.c index e796622ae87..9b7c5e747b5 100644 --- a/dlls/dbghelp/pe_module.c +++ b/dlls/dbghelp/pe_module.c @@ -65,6 +65,11 @@ static void pe_unmap_full(struct image_file_map* fmap) } }
+/* as we store either IMAGE_OPTIONAL_HEADER(32|64) inside pe_file_map, + * this helper will read to any field 'field' inside such an header + */ +#define PE_FROM_OPTHDR(fmap, field) (((fmap)->addr_size == 32) ? ((fmap)->u.pe.opt.header32. field) : ((fmap)->u.pe.opt.header64. field)) + /****************************************************************** * pe_map_section * @@ -259,12 +264,24 @@ BOOL pe_map_file(HANDLE file, struct image_file_map* fmap, enum module_type mt)
if (!(nthdr = RtlImageNtHeader(mapping))) goto error; memcpy(&fmap->u.pe.file_header, &nthdr->FileHeader, sizeof(fmap->u.pe.file_header)); - memcpy(&fmap->u.pe.opt_header, &nthdr->OptionalHeader, sizeof(fmap->u.pe.opt_header)); switch (nthdr->OptionalHeader.Magic) { - case 0x10b: fmap->addr_size = 32; break; - case 0x20b: fmap->addr_size = 64; break; - default: return FALSE; + case 0x10b: + if (sizeof(void*) == 8 && !(SymGetOptions() & SYMOPT_INCLUDE_32BIT_MODULES)) + { + TRACE("Won't load 32bit module in 64bit dbghelp when options don't ask for it\n"); + goto error; + } + fmap->addr_size = 32; + memcpy(&fmap->u.pe.opt.header32, &nthdr->OptionalHeader, sizeof(fmap->u.pe.opt.header32)); + break; + case 0x20b: + if (sizeof(void*) == 4) return FALSE; + fmap->addr_size = 64; + memcpy(&fmap->u.pe.opt.header64, &nthdr->OptionalHeader, sizeof(fmap->u.pe.opt.header64)); + break; + default: + return FALSE; }
fmap->u.pe.builtin = !memcmp((const IMAGE_DOS_HEADER*)mapping + 1, builtin_signature, sizeof(builtin_signature)); @@ -497,7 +514,7 @@ static BOOL pe_load_stabs(const struct process* pcs, struct module* module) if (stab != IMAGE_NO_MAP && stabstr != IMAGE_NO_MAP) { ret = stabs_parse(module, - module->module.BaseOfImage - fmap->u.pe.opt_header.ImageBase, + module->module.BaseOfImage - PE_FROM_OPTHDR(fmap, ImageBase), stab, image_get_map_size(§_stabs) / sizeof(struct stab_nlist), sizeof(struct stab_nlist), stabstr, image_get_map_size(§_stabstr), NULL, NULL); @@ -523,7 +540,7 @@ static BOOL pe_load_dwarf(struct module* module) BOOL ret;
ret = dwarf2_parse(module, - module->module.BaseOfImage - fmap->u.pe.opt_header.ImageBase, + module->module.BaseOfImage - PE_FROM_OPTHDR(fmap, ImageBase), NULL, /* FIXME: some thunks to deal with ? */ fmap); TRACE("%s the DWARF debug info\n", ret ? "successfully loaded" : "failed to load"); @@ -793,12 +810,12 @@ struct module* pe_load_native_module(struct process* pcs, const WCHAR* name, image_unmap_file(&modfmt->u.pe_info->fmap); modfmt->u.pe_info->fmap = builtin.fmap; } - if (!base) base = modfmt->u.pe_info->fmap.u.pe.opt_header.ImageBase; - if (!size) size = modfmt->u.pe_info->fmap.u.pe.opt_header.SizeOfImage; + if (!base) base = PE_FROM_OPTHDR(&modfmt->u.pe_info->fmap, ImageBase); + if (!size) size = PE_FROM_OPTHDR(&modfmt->u.pe_info->fmap, SizeOfImage);
module = module_new(pcs, loaded_name, DMT_PE, FALSE, base, size, modfmt->u.pe_info->fmap.u.pe.file_header.TimeDateStamp, - modfmt->u.pe_info->fmap.u.pe.opt_header.CheckSum); + PE_FROM_OPTHDR(&modfmt->u.pe_info->fmap, CheckSum)); if (module) { module->real_path = builtin.path; @@ -811,7 +828,7 @@ struct module* pe_load_native_module(struct process* pcs, const WCHAR* name, module->module.SymType = SymDeferred; else pe_load_debug_info(pcs, module); - module->reloc_delta = base - modfmt->u.pe_info->fmap.u.pe.opt_header.ImageBase; + module->reloc_delta = base - PE_FROM_OPTHDR(&modfmt->u.pe_info->fmap, ImageBase); } else {
When: - caller of dbghelp is a 64bit process, - invoking SymInitialize on a 32bit live target running under WOW64
SymInitialize fails because: - check_live_target() erroneously reads the 64bit PEB of the target, while it actually wants the 32bit PEB. - as the ELF base header address isn't set (hidden in CloudFileFlags) in the 64bit PEB, hence causing the failure
So ensure that check_live_target() actually reads the 32bit PEB when handling a 32bit process.
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/dbghelp.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/dlls/dbghelp/dbghelp.c b/dlls/dbghelp/dbghelp.c index 00d7b61fbd8..9d99f0d646a 100644 --- a/dlls/dbghelp/dbghelp.c +++ b/dlls/dbghelp/dbghelp.c @@ -286,7 +286,7 @@ const WCHAR *process_getenv(const struct process *process, const WCHAR *name) * check_live_target * */ -static BOOL check_live_target(struct process* pcs) +static BOOL check_live_target(struct process* pcs, BOOL wow64, BOOL child_wow64) { PROCESS_BASIC_INFORMATION pbi; ULONG_PTR base = 0, env = 0; @@ -300,11 +300,17 @@ static BOOL check_live_target(struct process* pcs)
if (!pcs->is_64bit) { + const char* peb32_addr; DWORD env32; PEB32 peb32; + C_ASSERT(sizeof(void*) != 4 || FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Environment) == 0x48); - if (!ReadProcessMemory(pcs->handle, pbi.PebBaseAddress, &peb32, sizeof(peb32), NULL)) return FALSE; - if (!ReadProcessMemory(pcs->handle, (char *)pbi.PebBaseAddress + 0x460 /* CloudFileFlags */, &base, sizeof(base), NULL)) return FALSE; + peb32_addr = (const char*)pbi.PebBaseAddress; + if (!wow64 && child_wow64) + /* current process is 64bit, while child process is 32 bit, need to read 32bit PEB */ + peb32_addr += 0x1000; + if (!ReadProcessMemory(pcs->handle, peb32_addr, &peb32, sizeof(peb32), NULL)) return FALSE; + if (!ReadProcessMemory(pcs->handle, peb32_addr + 0x460 /* CloudFileFlags */, &base, sizeof(base), NULL)) return FALSE; if (read_process_memory(pcs, peb32.ProcessParameters + 0x48, &env32, sizeof(env32))) env = env32; } else @@ -454,7 +460,7 @@ BOOL WINAPI SymInitializeW(HANDLE hProcess, PCWSTR UserSearchPath, BOOL fInvadeP pcs->next = process_first; process_first = pcs;
- if (check_live_target(pcs)) + if (check_live_target(pcs, wow64, child_wow64)) { if (fInvadeProcess) EnumerateLoadedModulesW64(hProcess, process_invade_cb, hProcess);