From: Eric Pouech eric.pouech@gmail.com
- no longer relying on loaded module info (getting index address out of PE image, and caching it in struct dbg_module) - fixing Wow64 access
Co-authored-by: Evan Tang etang@codeweavers.com --- programs/winedbg/debugger.h | 1 + programs/winedbg/symbol.c | 61 +++++++++++++++++++------------------ programs/winedbg/winedbg.c | 29 ++++++++++++++++++ 3 files changed, 61 insertions(+), 30 deletions(-)
diff --git a/programs/winedbg/debugger.h b/programs/winedbg/debugger.h index 2948b1ba437..61fb055e53f 100644 --- a/programs/winedbg/debugger.h +++ b/programs/winedbg/debugger.h @@ -250,6 +250,7 @@ struct dbg_module { struct list entry; DWORD_PTR base; + DWORD_PTR tls_index_offset; };
struct dbg_delayed_bp diff --git a/programs/winedbg/symbol.c b/programs/winedbg/symbol.c index 961dc95585a..047e5d64fd1 100644 --- a/programs/winedbg/symbol.c +++ b/programs/winedbg/symbol.c @@ -128,17 +128,14 @@ static BOOL fill_sym_lvalue(const SYMBOL_INFO* sym, ULONG_PTR base, } else if (sym->Flags & SYMFLAG_TLSREL) { - PROCESS_BASIC_INFORMATION pbi; THREAD_BASIC_INFORMATION tbi; - DWORD_PTR addr; - PEB peb; - PEB_LDR_DATA ldr_data; - PLIST_ENTRY head, current; - LDR_DATA_TABLE_ENTRY ldr_module; - unsigned tlsindex = -1; - - if (NtQueryInformationProcess(dbg_curr_process->handle, ProcessBasicInformation, - &pbi, sizeof(pbi), NULL) || + struct dbg_module* mod = dbg_get_module(dbg_curr_process, sym->ModBase); + unsigned tlsindex; + struct dbg_lvalue lv_teb_tls, lv_index_addr, lv_module_tls; + dbg_lgint_t teb_tls_addr, index_addr, tls_module_addr; + + if (!mod || + !mod->tls_index_offset || NtQueryInformationThread(dbg_curr_thread->handle, ThreadBasicInformation, &tbi, sizeof(tbi), NULL)) { @@ -146,28 +143,32 @@ static BOOL fill_sym_lvalue(const SYMBOL_INFO* sym, ULONG_PTR base, if (buffer) snprintf(buffer, sz, "Cannot read TLS address\n"); return FALSE; } - addr = (DWORD_PTR)&(((TEB*)tbi.TebBaseAddress)->ThreadLocalStoragePointer); - if (!dbg_read_memory((void*)addr, &addr, sizeof(addr)) || - !dbg_read_memory(pbi.PebBaseAddress, &peb, sizeof(peb)) || - !dbg_read_memory(peb.LdrData, &ldr_data, sizeof(ldr_data))) + + if (ADDRSIZE == sizeof(void*)) /* easy, debugger and debuggee have same bitness */ + init_lvalue(&lv_teb_tls, TRUE, + (void*)((DWORD_PTR)tbi.TebBaseAddress + offsetof(TEB, ThreadLocalStoragePointer))); + else + /* debugger is 64bit, while debuggee is 32 bit. + * tbi.TebBaseAddress refers to the 64bit TEB... + * We want 32bit TEB, so offset by 0x2000 to get it. + */ + init_lvalue(&lv_teb_tls, TRUE, + (void*)((DWORD_PTR)tbi.TebBaseAddress + 0x2000 + offsetof(TEB32, ThreadLocalStoragePointer))); + + if (!memory_fetch_integer(&lv_teb_tls, 4, FALSE, &teb_tls_addr)) + goto tls_error; + + init_lvalue(&lv_index_addr, TRUE, (void*)(DWORD_PTR)(sym->ModBase + mod->tls_index_offset)); + if (!memory_fetch_integer(&lv_index_addr, ADDRSIZE, FALSE, &index_addr)) goto tls_error; - current = ldr_data.InLoadOrderModuleList.Flink; - head = &((PEB_LDR_DATA*)peb.LdrData)->InLoadOrderModuleList; - do - { - if (!dbg_read_memory(CONTAINING_RECORD(current, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks), - &ldr_module, sizeof(ldr_module))) goto tls_error; - if ((DWORD_PTR)ldr_module.DllBase == sym->ModBase) - { - tlsindex = ldr_module.TlsIndex; - break; - } - current = ldr_module.InLoadOrderLinks.Flink; - } while (current != head);
- addr += tlsindex * sizeof(DWORD_PTR); - if (!dbg_read_memory((void*)addr, &addr, sizeof(addr))) goto tls_error; - init_lvalue(lvalue, TRUE, (void*)(DWORD_PTR)(addr + sym->Address)); + if (!dbg_read_memory((const char*)(DWORD_PTR)index_addr, &tlsindex, sizeof(tlsindex))) + goto tls_error; + + init_lvalue(&lv_module_tls, TRUE, (void*)(DWORD_PTR)(teb_tls_addr + tlsindex * ADDRSIZE)); + if (!memory_fetch_integer(&lv_module_tls, ADDRSIZE, FALSE, &tls_module_addr)) + goto tls_error; + init_lvalue(lvalue, TRUE, (void*)(DWORD_PTR)(tls_module_addr + sym->Address)); } else { diff --git a/programs/winedbg/winedbg.c b/programs/winedbg/winedbg.c index 87e39c06d7f..7e5f8265d69 100644 --- a/programs/winedbg/winedbg.c +++ b/programs/winedbg/winedbg.c @@ -386,6 +386,8 @@ BOOL dbg_load_module(HANDLE hProc, HANDLE hFile, const WCHAR* name, DWORD_PTR ba struct dbg_process* pcs = dbg_get_process_h(hProc); struct dbg_module* mod; IMAGEHLP_MODULEW64 info; + HANDLE hMap; + void* image;
if (!pcs) return FALSE; mod = malloc(sizeof(struct dbg_module)); @@ -398,6 +400,33 @@ BOOL dbg_load_module(HANDLE hProc, HANDLE hFile, const WCHAR* name, DWORD_PTR ba mod->base = base; list_add_head(&pcs->modules, &mod->entry);
+ mod->tls_index_offset = 0; + if ((hMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL))) + { + if ((image = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0))) + { + IMAGE_NT_HEADERS* nth = RtlImageNtHeader(image); + const void* tlsdir; + ULONG sz; + + tlsdir = RtlImageDirectoryEntryToData(image, TRUE, IMAGE_DIRECTORY_ENTRY_TLS, &sz); + switch (nth->OptionalHeader.Magic) + { + case IMAGE_NT_OPTIONAL_HDR32_MAGIC: + if (tlsdir && sz >= sizeof(IMAGE_TLS_DIRECTORY32)) + mod->tls_index_offset = (const char*)tlsdir - (const char*)image + + offsetof(IMAGE_TLS_DIRECTORY32, AddressOfIndex); + break; + case IMAGE_NT_OPTIONAL_HDR64_MAGIC: + if (tlsdir && sz >= sizeof(IMAGE_TLS_DIRECTORY32)) + mod->tls_index_offset = (const char*)tlsdir - (const char*)image + + offsetof(IMAGE_TLS_DIRECTORY64, AddressOfIndex); + break; + } + UnmapViewOfFile(image); + } + CloseHandle(hMap); + } info.SizeOfStruct = sizeof(info); if (SymGetModuleInfoW64(hProc, base, &info)) if (info.PdbUnmatched || info.DbgUnmatched)