(The TlsIndex field in the LDR_DATA_TABLE_ENTRY structure appears to be unused except as a flag that the module has TLS (being always set to -1), at least as far back as Windows XP. It is worth mentioning that the WINE implementation of implicit TLS incorrectly uses TlsIndex as the real module TLS index, so it may be unreliable to assume that it is always -1 if you care about working on WINE.)
and the "links to that article but still doesn't work in wine" award goes to... [the D runtime](https://github.com/dlang/dmd/blob/6bf60ea0eb174631ede0074a77d3898d943e0b30/d... (Admittedly, there aren't too many ways to do what they're trying to do.)
With this, the D runtime will now work in Wine, even if in a dll loaded into an exe with no tls (which gets it the tls index 0)
The changes to the debugger are a bit icky, a possible alternative is to find some other easily-debugger-accessible place to stuff the tls index.
-- v8: ntdll: TlsIndex should not actually contain tls indices winedbg: Fix read access to variables with thread local storage. winedbg: Track loaded modules
From: Eric Pouech eric.pouech@gmail.com
Co-authored-by: Evan Tang etang@codeweavers.com --- programs/winedbg/debugger.h | 12 ++++++- programs/winedbg/tgt_active.c | 3 +- programs/winedbg/types.c | 12 +++---- programs/winedbg/winedbg.c | 61 +++++++++++++++++++++++++++++++---- 4 files changed, 72 insertions(+), 16 deletions(-)
diff --git a/programs/winedbg/debugger.h b/programs/winedbg/debugger.h index c4c0402ef5f..2948b1ba437 100644 --- a/programs/winedbg/debugger.h +++ b/programs/winedbg/debugger.h @@ -246,6 +246,12 @@ struct dbg_thread BOOL suspended; };
+struct dbg_module +{ + struct list entry; + DWORD_PTR base; +}; + struct dbg_delayed_bp { BOOL is_symbol; @@ -271,6 +277,7 @@ struct dbg_process void* pio_data; const WCHAR* imageName; struct list threads; + struct list modules; struct backend_cpu* be_cpu; HANDLE event_on_first_exception; BOOL active_debuggee; @@ -503,7 +510,7 @@ extern BOOL types_is_integral_type(const struct dbg_lvalue*); extern BOOL types_is_float_type(const struct dbg_lvalue*); extern BOOL types_is_pointer_type(const struct dbg_lvalue*); extern BOOL types_find_basic(const WCHAR*, const char*, struct dbg_type* type); -extern BOOL types_unload_module(DWORD_PTR linear); +extern BOOL types_unload_module(struct dbg_process* pcs, DWORD_PTR linear);
/* winedbg.c */ #ifdef __GNUC__ @@ -524,6 +531,9 @@ extern struct dbg_thread* dbg_get_thread(struct dbg_process* p, DWORD tid); extern void dbg_del_thread(struct dbg_thread* t); extern BOOL dbg_init(HANDLE hProc, const WCHAR* in, BOOL invade); extern BOOL dbg_load_module(HANDLE hProc, HANDLE hFile, const WCHAR* name, DWORD_PTR base, DWORD size); +extern struct dbg_module* dbg_get_module(struct dbg_process* pcs, DWORD_PTR base); +extern void dbg_del_module(struct dbg_module* mod); +extern BOOL dbg_unload_module(struct dbg_process* pcs, DWORD_PTR base); extern void dbg_set_option(const char*, const char*); extern void dbg_start_interactive(const char*, HANDLE hFile); extern void dbg_init_console(void); diff --git a/programs/winedbg/tgt_active.c b/programs/winedbg/tgt_active.c index 9e130038f22..0d5ae754af5 100644 --- a/programs/winedbg/tgt_active.c +++ b/programs/winedbg/tgt_active.c @@ -501,8 +501,7 @@ static unsigned dbg_handle_debug_event(DEBUG_EVENT* de) de->dwProcessId, de->dwThreadId, de->u.UnloadDll.lpBaseOfDll); break_delete_xpoints_from_module((DWORD_PTR)de->u.UnloadDll.lpBaseOfDll); - types_unload_module((DWORD_PTR)de->u.UnloadDll.lpBaseOfDll); - SymUnloadModule64(dbg_curr_process->handle, (DWORD_PTR)de->u.UnloadDll.lpBaseOfDll); + dbg_unload_module(dbg_curr_process, (DWORD_PTR)de->u.UnloadDll.lpBaseOfDll); break;
case OUTPUT_DEBUG_STRING_EVENT: diff --git a/programs/winedbg/types.c b/programs/winedbg/types.c index 5f5f1346c67..44872a7edad 100644 --- a/programs/winedbg/types.c +++ b/programs/winedbg/types.c @@ -1205,16 +1205,16 @@ BOOL types_get_info(const struct dbg_type* type, IMAGEHLP_SYMBOL_TYPE_INFO ti, v return TRUE; }
-BOOL types_unload_module(DWORD_PTR linear) +BOOL types_unload_module(struct dbg_process* pcs, DWORD_PTR linear) { unsigned i; - if (!dbg_curr_process) return FALSE; - for (i = 0; i < dbg_curr_process->num_synthetized_types; i++) + if (!pcs) return FALSE; + for (i = 0; i < pcs->num_synthetized_types; i++) { - if (dbg_curr_process->synthetized_types[i].module == linear) + if (pcs->synthetized_types[i].module == linear) { - dbg_curr_process->synthetized_types[i].module = 0; - dbg_curr_process->synthetized_types[i].id = dbg_itype_none; + pcs->synthetized_types[i].module = 0; + pcs->synthetized_types[i].id = dbg_itype_none; } } return TRUE; diff --git a/programs/winedbg/winedbg.c b/programs/winedbg/winedbg.c index 84ec7802396..87e39c06d7f 100644 --- a/programs/winedbg/winedbg.c +++ b/programs/winedbg/winedbg.c @@ -273,6 +273,7 @@ struct dbg_process* dbg_add_process(const struct be_process_io* pio, DWORD pid, p->pio_data = NULL; p->imageName = NULL; list_init(&p->threads); + list_init(&p->modules); p->event_on_first_exception = NULL; p->active_debuggee = FALSE; p->next_bp = 1; /* breakpoint 0 is reserved for step-over */ @@ -316,11 +317,16 @@ void dbg_del_process(struct dbg_process* p) { struct dbg_thread* t; struct dbg_thread* t2; + struct dbg_module* mod; + struct dbg_module* mod2; int i;
LIST_FOR_EACH_ENTRY_SAFE(t, t2, &p->threads, struct dbg_thread, entry) dbg_del_thread(t);
+ LIST_FOR_EACH_ENTRY_SAFE(mod, mod2, &p->modules, struct dbg_module, entry) + dbg_del_module(mod); + for (i = 0; i < p->num_delayed_bp; i++) if (p->delayed_bp[i].is_symbol) free(p->delayed_bp[i].u.symbol.name); @@ -377,15 +383,56 @@ BOOL dbg_init(HANDLE hProc, const WCHAR* in, BOOL invade)
BOOL dbg_load_module(HANDLE hProc, HANDLE hFile, const WCHAR* name, DWORD_PTR base, DWORD size) { - BOOL ret = SymLoadModuleExW(hProc, NULL, name, NULL, base, size, NULL, 0); - if (ret) + struct dbg_process* pcs = dbg_get_process_h(hProc); + struct dbg_module* mod; + IMAGEHLP_MODULEW64 info; + + if (!pcs) return FALSE; + mod = malloc(sizeof(struct dbg_module)); + if (!mod) return FALSE; + if (!SymLoadModuleExW(hProc, NULL, name, NULL, base, size, NULL, 0)) { - IMAGEHLP_MODULEW64 ihm; - ihm.SizeOfStruct = sizeof(ihm); - if (SymGetModuleInfoW64(hProc, base, &ihm) && (ihm.PdbUnmatched || ihm.DbgUnmatched)) - dbg_printf("Loaded unmatched debug information for %s\n", wine_dbgstr_w(name)); + free(mod); + return FALSE; } - return ret; + mod->base = base; + list_add_head(&pcs->modules, &mod->entry); + + info.SizeOfStruct = sizeof(info); + if (SymGetModuleInfoW64(hProc, base, &info)) + if (info.PdbUnmatched || info.DbgUnmatched) + dbg_printf("Loaded unmatched debug information for %s\n", wine_dbgstr_w(name)); + + return TRUE; +} + +void dbg_del_module(struct dbg_module* mod) +{ + list_remove(&mod->entry); + free(mod); +} + +struct dbg_module* dbg_get_module(struct dbg_process* pcs, DWORD_PTR base) +{ + struct dbg_module* mod; + + if (!pcs) + return NULL; + LIST_FOR_EACH_ENTRY(mod, &pcs->modules, struct dbg_module, entry) + if (mod->base == base) + return mod; + return NULL; +} + +BOOL dbg_unload_module(struct dbg_process* pcs, DWORD_PTR base) +{ + struct dbg_module* mod = dbg_get_module(pcs, base); + + types_unload_module(pcs, base); + SymUnloadModule64(pcs->handle, base); + dbg_del_module(mod); + + return !!mod; }
struct dbg_thread* dbg_get_thread(struct dbg_process* p, DWORD tid)
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)
From: Evan Tang etang@codeweavers.com
It actually contains a -1 if the module has a tls slot and a 0 if it doesn't. Putting tls indices in it breaks initialization of the D runtime if a D dll is loaded into a tls-free exe and gets assigned tls slot 0, as it makes the D runtime think the OS hasn't initialized a tls slot: https://github.com/dlang/dmd/blob/6bf60ea0eb174631ede0074a77d3898d943e0b30/d... --- dlls/ntdll/loader.c | 35 +++++++++++++++++++++-------------- dlls/ntdll/tests/rtl.c | 19 +++++++++++++++++++ 2 files changed, 40 insertions(+), 14 deletions(-)
diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index 61aeb25898b..c4b5bc63a54 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -1222,7 +1222,7 @@ static BOOL is_dll_native_subsystem( LDR_DATA_TABLE_ENTRY *mod, const IMAGE_NT_H * Allocate a TLS slot for a newly-loaded module. * The loader_section must be locked while calling this function. */ -static SHORT alloc_tls_slot( LDR_DATA_TABLE_ENTRY *mod ) +static BOOL alloc_tls_slot( LDR_DATA_TABLE_ENTRY *mod ) { const IMAGE_TLS_DIRECTORY *dir; ULONG i, size; @@ -1230,10 +1230,10 @@ static SHORT alloc_tls_slot( LDR_DATA_TABLE_ENTRY *mod ) LIST_ENTRY *entry;
if (!(dir = RtlImageDirectoryEntryToData( mod->DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_TLS, &size ))) - return -1; + return FALSE;
size = dir->EndAddressOfRawData - dir->StartAddressOfRawData; - if (!size && !dir->SizeOfZeroFill && !dir->AddressOfCallBacks) return -1; + if (!size && !dir->SizeOfZeroFill && !dir->AddressOfCallBacks) return FALSE;
for (i = 0; i < tls_module_count; i++) { @@ -1255,7 +1255,7 @@ static SHORT alloc_tls_slot( LDR_DATA_TABLE_ENTRY *mod ) else new_ptr = RtlReAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, tls_dirs, new_count * sizeof(*tls_dirs) ); - if (!new_ptr) return -1; + if (!new_ptr) return FALSE;
/* resize the pointer block in all running threads */ for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink) @@ -1264,7 +1264,7 @@ static SHORT alloc_tls_slot( LDR_DATA_TABLE_ENTRY *mod ) void **old = teb->ThreadLocalStoragePointer; void **new = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, new_count * sizeof(*new));
- if (!new) return -1; + if (!new) return FALSE; if (old) memcpy( new, old, tls_module_count * sizeof(*new) ); teb->ThreadLocalStoragePointer = new; #ifdef __x86_64__ /* macOS-specific hack */ @@ -1296,7 +1296,7 @@ static SHORT alloc_tls_slot( LDR_DATA_TABLE_ENTRY *mod )
*(DWORD *)dir->AddressOfIndex = i; tls_dirs[i] = *dir; - return i; + return TRUE; }
@@ -1308,9 +1308,15 @@ static SHORT alloc_tls_slot( LDR_DATA_TABLE_ENTRY *mod ) */ static void free_tls_slot( LDR_DATA_TABLE_ENTRY *mod ) { - ULONG i = (USHORT)mod->TlsIndex; + const IMAGE_TLS_DIRECTORY *dir; + ULONG i, size; + + if (mod->TlsIndex != -1) + return; + if (!(dir = RtlImageDirectoryEntryToData( mod->DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_TLS, &size ))) + return;
- if (mod->TlsIndex == -1) return; + i = *(ULONG*)dir->AddressOfIndex; assert( i < tls_module_count ); memset( &tls_dirs[i], 0, sizeof(tls_dirs[i]) ); } @@ -1374,7 +1380,8 @@ static NTSTATUS fixup_imports( WINE_MODREF *wm, LPCWSTR load_path ) if (!(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS)) return STATUS_SUCCESS; /* already done */ wm->ldr.Flags &= ~LDR_DONT_RESOLVE_REFS;
- wm->ldr.TlsIndex = alloc_tls_slot( &wm->ldr ); + if (alloc_tls_slot( &wm->ldr )) + wm->ldr.TlsIndex = -1;
if (!(imports = RtlImageDirectoryEntryToData( wm->ldr.DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size ))) @@ -1431,7 +1438,7 @@ static WINE_MODREF *alloc_module( HMODULE hModule, const UNICODE_STRING *nt_name wm->ldr.DllBase = hModule; wm->ldr.SizeOfImage = nt->OptionalHeader.SizeOfImage; wm->ldr.Flags = LDR_DONT_RESOLVE_REFS | (builtin ? LDR_WINE_INTERNAL : 0); - wm->ldr.TlsIndex = -1; + wm->ldr.TlsIndex = 0; wm->ldr.LoadCount = 1; wm->CheckSum = nt->OptionalHeader.CheckSum; wm->ldr.TimeDateStamp = nt->FileHeader.TimeDateStamp; @@ -1783,7 +1790,7 @@ NTSTATUS WINAPI LdrDisableThreadCalloutsForDll(HMODULE hModule) RtlEnterCriticalSection( &loader_section );
wm = get_modref( hModule ); - if (!wm || wm->ldr.TlsIndex != -1) + if (!wm || wm->ldr.TlsIndex == -1) ret = STATUS_DLL_NOT_FOUND; else wm->ldr.Flags |= LDR_NO_DLL_CALLS; @@ -3712,7 +3719,7 @@ void WINAPI LdrShutdownThread(void) DLL_THREAD_DETACH, NULL ); }
- if (wm->ldr.TlsIndex != -1) call_tls_callbacks( wm->ldr.DllBase, DLL_THREAD_DETACH ); + if (wm->ldr.TlsIndex == -1) call_tls_callbacks( wm->ldr.DllBase, DLL_THREAD_DETACH );
RtlAcquirePebLock(); if (NtCurrentTeb()->TlsLinks.Flink) RemoveEntryList( &NtCurrentTeb()->TlsLinks ); @@ -4216,7 +4223,7 @@ void WINAPI LdrInitializeThunk( CONTEXT *context, ULONG_PTR unknown2, ULONG_PTR NtTerminateProcess( GetCurrentProcess(), status ); } release_address_space(); - if (wm->ldr.TlsIndex != -1) call_tls_callbacks( wm->ldr.DllBase, DLL_PROCESS_ATTACH ); + if (wm->ldr.TlsIndex == -1) call_tls_callbacks( wm->ldr.DllBase, DLL_PROCESS_ATTACH ); if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie ); process_breakpoint(); } @@ -4225,7 +4232,7 @@ void WINAPI LdrInitializeThunk( CONTEXT *context, ULONG_PTR unknown2, ULONG_PTR if ((status = alloc_thread_tls()) != STATUS_SUCCESS) NtTerminateThread( GetCurrentThread(), status ); thread_attach(); - if (wm->ldr.TlsIndex != -1) call_tls_callbacks( wm->ldr.DllBase, DLL_THREAD_ATTACH ); + if (wm->ldr.TlsIndex == -1) call_tls_callbacks( wm->ldr.DllBase, DLL_THREAD_ATTACH ); }
RtlLeaveCriticalSection( &loader_section ); diff --git a/dlls/ntdll/tests/rtl.c b/dlls/ntdll/tests/rtl.c index c2ca8ea11a7..6a94f783105 100644 --- a/dlls/ntdll/tests/rtl.c +++ b/dlls/ntdll/tests/rtl.c @@ -3788,6 +3788,24 @@ static void test_RtlFirstFreeAce(void) HeapFree(GetProcessHeap(), 0, acl); }
+static void test_TlsIndex(void) +{ + LIST_ENTRY *root = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList; + for (LIST_ENTRY *entry = root->Flink; entry != root; entry = entry->Flink) { + LDR_DATA_TABLE_ENTRY *mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); + if (lstrcmpiW(L"ntdll.dll", mod->BaseDllName.Buffer) == 0) { + /* Pick ntdll as a dll that definitely won't have TLS */ + ok(mod->TlsIndex == 0, "ntdll.dll TlsIndex: %d instead of 0\n", mod->TlsIndex); + } else if (mod->DllBase == GetModuleHandleA(NULL)) { + /* mingw gcc doesn't support MSVC-style TLS */ + /* If we do get a way to add tls to this exe, uncomment the following test: */ + /* ok(mod->TlsIndex == -1, "Test exe TlsIndex: %d instead of -1\n", mod->TlsIndex); */ + } else { + ok(mod->TlsIndex == 0 || mod->TlsIndex == -1, "%s TlsIndex: %d\n", debugstr_w(mod->BaseDllName.Buffer), mod->TlsIndex); + } + } +} + START_TEST(rtl) { InitFunctionPtrs(); @@ -3832,4 +3850,5 @@ START_TEST(rtl) test_DbgPrint(); test_RtlDestroyHeap(); test_RtlFirstFreeAce(); + test_TlsIndex(); }
On Mon Jan 2 16:48:54 2023 +0000, eric pouech wrote:
I had a look... I changed a bit your first patch (about introducing dbg_module in winedbg):
- IMO, we should keep the loaded module list in winedbg in sync with
dbghelp... so don't have two separate functions... nothing critical, mostly stylish The last (TMP) didn't work with my local tests. Moreover:
- current code (before your patches) didn't expect at all the WOW64
situation (32bit debuggee and 64bit debuggeer).
- reduced a bunch of PE format reading by mapping the DLL image and
using Rtl* functions that already implement it.
- So I reworked it.
You can find the two modified patches attached here [patch.tls](/uploads/d2230ff815ddfa90f674439dfbc52b7d/patch.tls). They've been successfully tested with and without the ntdll patch applied (and in the three cases of bitness: 32/32, 64/64 and 64/32). So these two patches should be first in serie, and the ntdll last.
I put the patches in if you want to make sure everything still works
This merge request was approved by eric pouech.
Hi Evan,
Unfortunately some other merged changes to winedbg conflict with this MR. Please find included an adapted version of the two first patches: - resolving conflicts with other merges - using a helper for getting tls values (and finally getting rid of the goto:s) - simplifying some accesses (like, using TEB address that is already stored in winedbg) - fixing some errors in size handling
[patch.tls3](/uploads/ee5381506756933c2aafedde16d85549/patch.tls3)