https://github.com/charles-zablit created https://github.com/llvm/llvm-project/pull/213301
A Windows thread's local storage is accessed through its Thread Environment Block ([TEB](https://learn.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-teb)), but nothing in the target exposes that address, so a language runtime cannot resolve a variable local to the thread in the debuggee. This patch publishes the thread's TEB from `TargetThreadWindows::FetchThreadExtendedInfo` under the "teb_address" key. >From 31d0eb064fbed43ba505ff3f6a7d675d31b2a760 Mon Sep 17 00:00:00 2001 From: Charles Zablit <[email protected]> Date: Fri, 31 Jul 2026 16:51:10 +0100 Subject: [PATCH] [lldb][Windows] Expose each thread's TEB address as extended thread info --- .../Windows/Common/TargetThreadWindows.cpp | 40 +++++++++++++++++++ .../Windows/Common/TargetThreadWindows.h | 4 ++ 2 files changed, 44 insertions(+) diff --git a/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp index f94533a701817..38d08fff0d755 100644 --- a/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp @@ -44,6 +44,46 @@ void TargetThreadWindows::RefreshStateAfterStop() { void TargetThreadWindows::WillResume(lldb::StateType resume_state) {} +StructuredData::ObjectSP TargetThreadWindows::FetchThreadExtendedInfo() { + struct ThreadBasicInformation { + LONG ExitStatus; + PVOID TebBaseAddress; + struct { + HANDLE UniqueProcess; + HANDLE UniqueThread; + } ClientId; + ULONG_PTR AffinityMask; + LONG Priority; + LONG BasePriority; + }; + using NtQueryInformationThreadFn = + LONG(WINAPI *)(HANDLE ThreadHandle, ULONG ThreadInformationClass, + PVOID ThreadInformation, ULONG ThreadInformationLength, + PULONG ReturnLength); + + static LazyImport<NtQueryInformationThreadFn> s_query_information_thread{ + L"Kernel32.dll", "NtQueryInformationThread"}; + if (!s_query_information_thread) + return StructuredData::ObjectSP(); + auto NtQueryInformationThread = *s_query_information_thread; + + HANDLE handle = m_host_thread.GetNativeThread().GetSystemHandle(); + if (!handle || handle == INVALID_HANDLE_VALUE) + return StructuredData::ObjectSP(); + + ThreadBasicInformation info = {}; + // ThreadInformationClass 0 is ThreadBasicInformation. + if (NtQueryInformationThread(handle, 0, &info, sizeof(info), nullptr) < 0) + return StructuredData::ObjectSP(); + if (!info.TebBaseAddress) + return StructuredData::ObjectSP(); + + auto dict = std::make_shared<StructuredData::Dictionary>(); + dict->AddIntegerItem("teb_address", + reinterpret_cast<uint64_t>(info.TebBaseAddress)); + return dict; +} + void TargetThreadWindows::DidStop() {} RegisterContextSP TargetThreadWindows::GetRegisterContext() { diff --git a/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.h b/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.h index 2b8d4d9b1864d..4bdd1b351b3fe 100644 --- a/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.h +++ b/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.h @@ -34,6 +34,10 @@ class TargetThreadWindows : public lldb_private::Thread { bool CalculateStopInfo() override; const char *GetName() override; + /// Exposes this thread's TEB address under the "teb_address" key, so that + /// language runtimes can resolve thread-local storage. + lldb_private::StructuredData::ObjectSP FetchThreadExtendedInfo() override; + Status DoResume(); HostThread GetHostThread() const { return m_host_thread; } _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
