(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.~~ Resolved
-- v9: 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 aa94f2f18ab..f5c573cf30e 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, hFile, 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, hFile, 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 | 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)
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 Wed Jan 25 17:35:50 2023 +0000, eric pouech wrote:
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)
Applied