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

Reply via email to