Module: wine Branch: master Commit: 433bc1270965c07d440ef676d5593de1ef329918 URL: https://gitlab.winehq.org/wine/wine/-/commit/433bc1270965c07d440ef676d5593de...
Author: Eric Pouech eric.pouech@gmail.com Date: Mon Jan 16 11:14:59 2023 -0600
winedbg: Fix read access to variables with thread local storage.
No longer relying on loaded module info (getting index address out of PE image, and caching it in struct dbg_module).
Co-authored-by: Evan Tang etang@codeweavers.com
---
programs/winedbg/debugger.h | 1 + programs/winedbg/symbol.c | 74 +++++++++++++++++++++++---------------------- programs/winedbg/winedbg.c | 29 ++++++++++++++++++ 3 files changed, 68 insertions(+), 36 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..22c34033752 100644 --- a/programs/winedbg/symbol.c +++ b/programs/winedbg/symbol.c @@ -61,6 +61,43 @@ static BOOL symbol_get_debug_start(const struct dbg_type* func, ULONG64* start) return FALSE; }
+static BOOL fetch_tls_lvalue(const SYMBOL_INFO* sym, struct dbg_lvalue* lvalue) +{ + 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; + char* teb_tls_storage; + + if (!mod || !mod->tls_index_offset || !dbg_curr_thread) + return FALSE; + /* get ThreadLocalStoragePointer offset depending on debuggee bitness */ + teb_tls_storage = (char*)dbg_curr_thread->teb; + if (ADDRSIZE == sizeof(void*)) + /* debugger and debuggee have same bitness */ + teb_tls_storage += offsetof(TEB, ThreadLocalStoragePointer); + else + /* debugger is 64bit, while debuggee is 32bit */ + teb_tls_storage += 0x2000 /* TEB64 => TEB32 */ + offsetof(TEB32, ThreadLocalStoragePointer); + init_lvalue(&lv_teb_tls, TRUE, teb_tls_storage); + + if (!memory_fetch_integer(&lv_teb_tls, ADDRSIZE, FALSE, &teb_tls_addr)) + return FALSE; + + 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)) + return FALSE; + + if (!dbg_read_memory((const char*)(DWORD_PTR)index_addr, &tlsindex, sizeof(tlsindex))) + return FALSE; + + 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)) + return FALSE; + init_lvalue(lvalue, TRUE, (void*)(DWORD_PTR)(tls_module_addr + sym->Address)); + return TRUE; +} + static BOOL fill_sym_lvalue(const SYMBOL_INFO* sym, ULONG_PTR base, struct dbg_lvalue* lvalue, char* buffer, size_t sz) { @@ -128,46 +165,11 @@ 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) || - NtQueryInformationThread(dbg_curr_thread->handle, ThreadBasicInformation, - &tbi, sizeof(tbi), NULL)) + if (!fetch_tls_lvalue(sym, lvalue)) { - tls_error: 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))) - 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)); } else { diff --git a/programs/winedbg/winedbg.c b/programs/winedbg/winedbg.c index f5c573cf30e..9815ed4a046 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_DIRECTORY64)) + 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)