[Lldb-commits] [lldb] [lldb][RISCV] Implement access to TLS variables on RISC-V (PR #191410)

Georgiy Samoylov via lldb-commits lldb-commits at lists.llvm.org
Fri Apr 10 06:01:21 PDT 2026


https://github.com/sga-sc updated https://github.com/llvm/llvm-project/pull/191410

>From 0b4cb356700d05007ecd530114c9f32be0e1d890 Mon Sep 17 00:00:00 2001
From: Georgiy Samoylov <Ignitor21838 at gmail.com>
Date: Fri, 10 Apr 2026 15:55:51 +0300
Subject: [PATCH 1/2] [lldb][RISCV] Add TP constants for RISC-V

---
 lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp             | 3 ++-
 lldb/source/Plugins/Process/Utility/RegisterInfos_riscv64.h | 2 +-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp b/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp
index dce905f08aa5f..d25db67ef6a2e 100644
--- a/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp
+++ b/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp
@@ -91,7 +91,7 @@ static const std::array<RegisterInfo, 33> g_register_infos = {
      DEFINE_GENERIC_REGISTER_STUB(ra, nullptr, LLDB_REGNUM_GENERIC_RA),
      DEFINE_GENERIC_REGISTER_STUB(sp, nullptr, LLDB_REGNUM_GENERIC_SP),
      DEFINE_REGISTER_STUB(gp, nullptr),
-     DEFINE_REGISTER_STUB(tp, nullptr),
+     DEFINE_REGISTER_STUB(tp, nullptr, LLDB_REGNUM_GENERIC_TP),
      DEFINE_REGISTER_STUB(t0, nullptr),
      DEFINE_REGISTER_STUB(t1, nullptr),
      DEFINE_REGISTER_STUB(t2, nullptr),
@@ -820,6 +820,7 @@ static uint32_t GetGenericNum(llvm::StringRef name) {
       .Cases({"ra", "x1"}, LLDB_REGNUM_GENERIC_RA)
       .Cases({"sp", "x2"}, LLDB_REGNUM_GENERIC_SP)
       .Cases({"fp", "s0"}, LLDB_REGNUM_GENERIC_FP)
+      .Cases({"tp", "x4"}, LLDB_REGNUM_GENERIC_TP)
       .Case("a0", LLDB_REGNUM_GENERIC_ARG1)
       .Case("a1", LLDB_REGNUM_GENERIC_ARG2)
       .Case("a2", LLDB_REGNUM_GENERIC_ARG3)
diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfos_riscv64.h b/lldb/source/Plugins/Process/Utility/RegisterInfos_riscv64.h
index 628ed3770bdc0..c9959168b1536 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterInfos_riscv64.h
+++ b/lldb/source/Plugins/Process/Utility/RegisterInfos_riscv64.h
@@ -85,7 +85,7 @@ static lldb_private::RegisterInfo g_register_infos_riscv64_gpr[] = {
     DEFINE_GPR64_ALT(ra, x1, LLDB_REGNUM_GENERIC_RA),
     DEFINE_GPR64_ALT(sp, x2, LLDB_REGNUM_GENERIC_SP),
     DEFINE_GPR64_ALT(gp, x3, LLDB_INVALID_REGNUM),
-    DEFINE_GPR64_ALT(tp, x4, LLDB_INVALID_REGNUM),
+    DEFINE_GPR64_ALT(tp, x4, LLDB_REGNUM_GENERIC_TP),
     DEFINE_GPR64_ALT(t0, x5, LLDB_INVALID_REGNUM),
     DEFINE_GPR64_ALT(t1, x6, LLDB_INVALID_REGNUM),
     DEFINE_GPR64_ALT(t2, x7, LLDB_INVALID_REGNUM),

>From a7dafd1833360d32b45173f25233404e3efe0b20 Mon Sep 17 00:00:00 2001
From: Georgiy Samoylov <Ignitor21838 at gmail.com>
Date: Fri, 10 Apr 2026 15:56:11 +0300
Subject: [PATCH 2/2] [lldb][RISCV] Add helper for VMA search inside PT_TLS

---
 .../POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp     | 57 ++++++++++++++++++-
 1 file changed, 55 insertions(+), 2 deletions(-)

diff --git a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
index f80fb3b2d2655..5272eaac51f32 100644
--- a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
+++ b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
@@ -9,6 +9,7 @@
 // Main header include
 #include "DynamicLoaderPOSIXDYLD.h"
 
+#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
 #include "Plugins/ObjectFile/Placeholder/ObjectFilePlaceholder.h"
 #include "lldb/Breakpoint/BreakpointLocation.h"
 #include "lldb/Core/Debugger.h"
@@ -27,6 +28,7 @@
 #include "lldb/Utility/LLDBLog.h"
 #include "lldb/Utility/Log.h"
 #include "lldb/Utility/ProcessInfo.h"
+#include "llvm/BinaryFormat/ELF.h"
 #include "llvm/Support/ThreadPool.h"
 
 #include <memory>
@@ -814,6 +816,26 @@ addr_t DynamicLoaderPOSIXDYLD::GetEntryPoint() {
   return m_entry_point;
 }
 
+static lldb::addr_t GetPTTLSVAddr(const lldb::ModuleSP &module_sp) {
+  if (!module_sp)
+    return LLDB_INVALID_ADDRESS;
+
+  ObjectFile *objfile = module_sp->GetObjectFile();
+  if (!objfile)
+    return LLDB_INVALID_ADDRESS;
+
+  auto *elf_obj = llvm::dyn_cast<ObjectFileELF>(objfile);
+  if (!elf_obj)
+    return LLDB_INVALID_ADDRESS;
+
+  for (const auto &phdr : elf_obj->ProgramHeaders()) {
+    if (phdr.p_type == llvm::ELF::PT_TLS)
+      return phdr.p_vaddr;
+  }
+
+  return LLDB_INVALID_ADDRESS;
+}
+
 lldb::addr_t
 DynamicLoaderPOSIXDYLD::GetThreadLocalData(const lldb::ModuleSP module_sp,
                                            const lldb::ThreadSP thread,
@@ -894,6 +916,19 @@ DynamicLoaderPOSIXDYLD::GetThreadLocalData(const lldb::ModuleSP module_sp,
       dtv_ptr = tp;
     }
   }
+  const llvm::Triple &triple = module_sp->GetArchitecture().GetTriple();
+
+  // On RISC-V with glibc the TLS layout uses Variant I (TLS_DTV_AT_TP).
+  // The thread pointer (tp) points just past a tcbhead_t header which
+  // contains two pointers: { dtv, private }. This means the DTV pointer
+  // itself is located two pointer-sized slots before tp, so dtv_ptr must
+  // be computed as tp - 2 * sizeof(void*). See MaskRay, “All about
+  // thread-local storage” (RISC-V/glibc section) and glibc's RISC-V
+  // TLS port (__tls_get_addr / THREAD_DTV).
+  if (triple.isRISCV()) {
+    dtv_ptr = tp - 2 * triple.getArchPointerBitWidth() / 8;
+  }
+
   addr_t dtv = (dtv_ptr != LLDB_INVALID_ADDRESS) ? ReadPointer(dtv_ptr)
                                                  : LLDB_INVALID_ADDRESS;
   if (dtv == LLDB_INVALID_ADDRESS) {
@@ -915,8 +950,26 @@ DynamicLoaderPOSIXDYLD::GetThreadLocalData(const lldb::ModuleSP module_sp,
   if (tls_block == LLDB_INVALID_ADDRESS) {
     LLDB_LOGF(log, "GetThreadLocalData error: fail to read tls_block");
     return LLDB_INVALID_ADDRESS;
-  } else
-    return tls_block + tls_file_addr;
+  }
+
+  // DW_OP_GNU_push_tls_address gives us a value in tls_file_addr that can be
+  // either:
+  //   - a pure offset inside the TLS block (e.g. x86_64/glibc), or
+  //   - a virtual address inside the PT_TLS segment (e.g. RISC-V/glibc),
+  //     roughly PT_TLS.p_vaddr + TPOFF(sym).
+  // To handle both cases, we try to normalize it to a plain offset (tpoff)
+  // by subtracting PT_TLS.p_vaddr when available.
+  addr_t pt_tls_vaddr = GetPTTLSVAddr(module_sp);
+  addr_t tpoff = tls_file_addr;
+
+  // If the module has a PT_TLS segment and the DWARF value lies at or above
+  // its p_vaddr, treat tls_file_addr as a VMA within PT_TLS and convert it
+  // to an offset. Otherwise, keep the original value (it is already an offset
+  // on targets like x86_64).
+  if (pt_tls_vaddr != LLDB_INVALID_ADDRESS && tls_file_addr >= pt_tls_vaddr)
+    tpoff = tls_file_addr - pt_tls_vaddr;
+
+  return tls_block + tpoff;
 }
 
 void DynamicLoaderPOSIXDYLD::ResolveExecutableModule(



More information about the lldb-commits mailing list