llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lldb

Author: Igor Kudrin (igorkudrin)

<details>
<summary>Changes</summary>

This implements reading the TPIDRURO register, which serves as the thread local 
register on Arm Linux.

---
Full diff: https://github.com/llvm/llvm-project/pull/182438.diff


11 Files Affected:

- (modified) lldb/include/lldb/Host/linux/Ptrace.h (+8-1) 
- (modified) 
lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp (+45-4) 
- (modified) lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h 
(+9) 
- (modified) lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.cpp 
(+28-10) 
- (modified) lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.h 
(+10-2) 
- (modified) lldb/source/Plugins/Process/Utility/RegisterInfos_arm.h (+20) 
- (modified) 
lldb/source/Plugins/Process/Windows/Common/arm/RegisterContextWindows_arm.cpp 
(+1) 
- (added) lldb/test/API/linux/arm/tls_register/Makefile (+3) 
- (added) lldb/test/API/linux/arm/tls_register/TestArmLinuxTLSRegister.py (+45) 
- (added) lldb/test/API/linux/arm/tls_register/main.c (+7) 
- (modified) llvm/docs/ReleaseNotes.md (+4) 


``````````diff
diff --git a/lldb/include/lldb/Host/linux/Ptrace.h 
b/lldb/include/lldb/Host/linux/Ptrace.h
index aabd3fd4fc557..0a45516a45c7f 100644
--- a/lldb/include/lldb/Host/linux/Ptrace.h
+++ b/lldb/include/lldb/Host/linux/Ptrace.h
@@ -38,9 +38,16 @@ typedef int __ptrace_request;
 #ifndef PTRACE_SETREGSET
 #define PTRACE_SETREGSET 0x4205
 #endif
+
 #ifndef PTRACE_GET_THREAD_AREA
+#ifdef __arm__
+// Arm has a different value, see arch/arm/include/uapi/asm/ptrace.h.
+#define PTRACE_GET_THREAD_AREA 22
+#else
 #define PTRACE_GET_THREAD_AREA 25
-#endif
+#endif // __arm__
+#endif // PTRACE_GET_THREAD_AREA
+
 #ifndef PTRACE_ARCH_PRCTL
 #define PTRACE_ARCH_PRCTL 30
 #endif
diff --git 
a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp 
b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp
index c1bc6a3f036bf..c83cea2bbf5bd 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp
@@ -25,11 +25,12 @@
 
 #if defined(__arm64__) || defined(__aarch64__)
 #include "NativeRegisterContextLinux_arm64dbreg.h"
+#endif
+
 #include "lldb/Host/linux/Ptrace.h"
 #include <asm/ptrace.h>
-#endif
 
-#define REG_CONTEXT_SIZE (GetGPRSize() + sizeof(m_fpr))
+#define REG_CONTEXT_SIZE (GetGPRSize() + sizeof(m_fpr) + sizeof(m_tls))
 
 #ifndef PTRACE_GETVFPREGS
 #define PTRACE_GETVFPREGS 27
@@ -68,12 +69,14 @@ 
NativeRegisterContextLinux::DetermineArchitecture(lldb::tid_t tid) {
 
 NativeRegisterContextLinux_arm::NativeRegisterContextLinux_arm(
     const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
-    : NativeRegisterContextRegisterInfo(native_thread,
-                                        new 
RegisterInfoPOSIX_arm(target_arch)),
+    : NativeRegisterContextRegisterInfo(
+          native_thread,
+          new RegisterInfoPOSIX_arm(target_arch, /*has_tls_reg=*/true)),
       NativeRegisterContextLinux(native_thread) {
   assert(target_arch.GetMachine() == llvm::Triple::arm);
 
   ::memset(&m_fpr, 0, sizeof(m_fpr));
+  ::memset(&m_tls, 0, sizeof(m_tls));
   ::memset(&m_gpr_arm, 0, sizeof(m_gpr_arm));
   ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs));
   ::memset(&m_hbp_regs, 0, sizeof(m_hbp_regs));
@@ -120,6 +123,11 @@ NativeRegisterContextLinux_arm::ReadRegister(const 
RegisterInfo *reg_info,
     error = ReadFPR();
     if (error.Fail())
       return error;
+  } else if (IsTLS(reg)) {
+    error = ReadTLS();
+    if (error.Success())
+      reg_value.SetUInt32(m_tls.tpidruro);
+    return error;
   } else {
     uint32_t full_reg = reg;
     bool is_subreg = reg_info->invalidate_regs &&
@@ -199,6 +207,10 @@ NativeRegisterContextLinux_arm::WriteRegister(const 
RegisterInfo *reg_info,
     return WriteFPR();
   }
 
+  if (IsTLS(reg_index))
+    return Status::FromErrorString(
+        "writing to a thread pointer register is not implemented");
+
   return Status::FromErrorString(
       "failed - register wasn't recognized to be a GPR or an FPR, "
       "write strategy unknown");
@@ -217,10 +229,16 @@ Status 
NativeRegisterContextLinux_arm::ReadAllRegisterValues(
   if (error.Fail())
     return error;
 
+  error = ReadTLS();
+  if (error.Fail())
+    return error;
+
   uint8_t *dst = data_sp->GetBytes();
   ::memcpy(dst, &m_gpr_arm, GetGPRSize());
   dst += GetGPRSize();
   ::memcpy(dst, &m_fpr, sizeof(m_fpr));
+  dst += sizeof(m_fpr);
+  ::memcpy(dst, &m_tls, sizeof(m_tls));
 
   return error;
 }
@@ -266,6 +284,8 @@ Status 
NativeRegisterContextLinux_arm::WriteAllRegisterValues(
   if (error.Fail())
     return error;
 
+  // Note: writing to a thread pointer register is not implemented.
+
   return error;
 }
 
@@ -283,6 +303,11 @@ bool NativeRegisterContextLinux_arm::IsFPR(unsigned reg) 
const {
   return false;
 }
 
+bool NativeRegisterContextLinux_arm::IsTLS(unsigned reg) const {
+  return GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
+         RegisterInfoPOSIX_arm::TLSRegSet;
+}
+
 llvm::Error NativeRegisterContextLinux_arm::ReadHardwareDebugInfo() {
   if (!m_refresh_hwdebug_info)
     return llvm::Error::success();
@@ -480,4 +505,20 @@ Status NativeRegisterContextLinux_arm::WriteFPR() {
 #endif // __arm__
 }
 
+Status NativeRegisterContextLinux_arm::ReadTLS() {
+#ifdef __arm__
+  return NativeProcessLinux::PtraceWrapper(PTRACE_GET_THREAD_AREA,
+                                           m_thread.GetID(), nullptr,
+                                           GetTLSBuffer(), GetTLSSize());
+#else  // __aarch64__
+  Status error;
+
+  struct iovec ioVec;
+  ioVec.iov_base = GetTLSBuffer();
+  ioVec.iov_len = GetTLSSize();
+
+  return ReadRegisterSet(&ioVec, GetTLSSize(), NT_ARM_TLS);
+#endif // __arm__
+}
+
 #endif // defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h 
b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h
index cf36859b16ad4..3722f667b62c5 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h
@@ -58,15 +58,22 @@ class NativeRegisterContextLinux_arm : public 
NativeRegisterContextLinux,
 
   Status WriteFPR() override;
 
+  Status ReadTLS();
+
   void *GetGPRBuffer() override { return &m_gpr_arm; }
 
   void *GetFPRBuffer() override { return &m_fpr; }
 
   size_t GetFPRSize() override { return sizeof(m_fpr); }
 
+  void *GetTLSBuffer() { return &m_tls; }
+
+  size_t GetTLSSize() { return sizeof(m_tls); }
+
 private:
   uint32_t m_gpr_arm[k_num_gpr_registers_arm];
   RegisterInfoPOSIX_arm::FPU m_fpr;
+  RegisterInfoPOSIX_arm::TLS m_tls;
 
   bool m_refresh_hwdebug_info;
 
@@ -74,6 +81,8 @@ class NativeRegisterContextLinux_arm : public 
NativeRegisterContextLinux,
 
   bool IsFPR(unsigned reg) const;
 
+  bool IsTLS(unsigned reg) const;
+
   llvm::Error ReadHardwareDebugInfo() override;
 
   llvm::Error WriteHardwareDebugRegs(DREGType hwbType) override;
diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.cpp 
b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.cpp
index d47647422ae21..021ea56325e77 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.cpp
+++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.cpp
@@ -24,13 +24,15 @@ using namespace lldb_private;
 #define FPSCR_OFFSET                                                           
\
   (LLVM_EXTENSION offsetof(RegisterInfoPOSIX_arm::FPU, fpscr) +                
\
    sizeof(RegisterInfoPOSIX_arm::GPR))
+#define TLS_OFFSET                                                             
\
+  (sizeof(RegisterInfoPOSIX_arm::GPR) + sizeof(RegisterInfoPOSIX_arm::FPU))
 #define EXC_OFFSET(idx)                                                        
\
-  ((idx)*4 + sizeof(RegisterInfoPOSIX_arm::GPR) +                              
\
-   sizeof(RegisterInfoPOSIX_arm::FPU))
+  ((idx) * 4 + sizeof(RegisterInfoPOSIX_arm::GPR) +                            
\
+   sizeof(RegisterInfoPOSIX_arm::FPU) + sizeof(RegisterInfoPOSIX_arm::TLS))
 #define DBG_OFFSET(reg)                                                        
\
   ((LLVM_EXTENSION offsetof(RegisterInfoPOSIX_arm::DBG, reg) +                 
\
     sizeof(RegisterInfoPOSIX_arm::GPR) + sizeof(RegisterInfoPOSIX_arm::FPU) +  
\
-    sizeof(RegisterInfoPOSIX_arm::EXC)))
+    sizeof(RegisterInfoPOSIX_arm::TLS) + sizeof(RegisterInfoPOSIX_arm::EXC)))
 
 #define DEFINE_DBG(reg, i)                                                     
\
   #reg, NULL, sizeof(((RegisterInfoPOSIX_arm::DBG *) NULL)->reg[i]),           
\
@@ -75,7 +77,9 @@ GetRegisterInfoCount(const lldb_private::ArchSpec 
&target_arch) {
 enum {
   k_num_gpr_registers = gpr_cpsr - gpr_r0 + 1,
   k_num_fpr_registers = fpu_q15 - fpu_s0 + 1,
-  k_num_register_sets = 2
+  k_num_tls_registers = 1,
+  k_num_register_sets_without_tls = 2,
+  k_num_register_sets_with_tls = 3
 };
 
 // arm general purpose registers.
@@ -142,18 +146,29 @@ static_assert(((sizeof g_fpu_regnums_arm / sizeof 
g_fpu_regnums_arm[0]) - 1) ==
                   k_num_fpr_registers,
               "g_fpu_regnums_arm has wrong number of register infos");
 
+// arm thread local storage registers.
+static const uint32_t g_tls_regnums_arm[] = {
+    tls_tpidruro,
+    LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+static_assert(((sizeof g_tls_regnums_arm / sizeof g_tls_regnums_arm[0]) - 1) ==
+                  k_num_tls_registers,
+              "g_tls_regnums_arm has wrong number of register infos");
+
 // Register sets for arm.
-static const RegisterSet g_reg_sets_arm[k_num_register_sets] = {
+static const RegisterSet g_reg_sets_arm[k_num_register_sets_with_tls] = {
     {"General Purpose Registers", "gpr", k_num_gpr_registers,
      g_gpr_regnums_arm},
-    {"Floating Point Registers", "fpu", k_num_fpr_registers,
-     g_fpu_regnums_arm}};
+    {"Floating Point Registers", "fpu", k_num_fpr_registers, 
g_fpu_regnums_arm},
+    {"Thread Local Storage Registers", "tls", k_num_tls_registers,
+     g_tls_regnums_arm}};
 
 RegisterInfoPOSIX_arm::RegisterInfoPOSIX_arm(
-    const lldb_private::ArchSpec &target_arch)
+    const lldb_private::ArchSpec &target_arch, bool has_tls_reg)
     : lldb_private::RegisterInfoAndSetInterface(target_arch),
       m_register_info_p(GetRegisterInfoPtr(target_arch)),
-      m_register_info_count(GetRegisterInfoCount(target_arch)) {}
+      m_register_info_count(GetRegisterInfoCount(target_arch)),
+      m_has_tls_reg(has_tls_reg) {}
 
 size_t RegisterInfoPOSIX_arm::GetGPRSize() const {
   return sizeof(struct RegisterInfoPOSIX_arm::GPR);
@@ -169,7 +184,8 @@ RegisterInfoPOSIX_arm::GetRegisterInfo() const {
 }
 
 size_t RegisterInfoPOSIX_arm::GetRegisterSetCount() const {
-  return k_num_register_sets;
+  return m_has_tls_reg ? k_num_register_sets_with_tls
+                       : k_num_register_sets_without_tls;
 }
 
 size_t RegisterInfoPOSIX_arm::GetRegisterSetFromRegisterIndex(
@@ -178,6 +194,8 @@ size_t 
RegisterInfoPOSIX_arm::GetRegisterSetFromRegisterIndex(
     return GPRegSet;
   if (reg_index <= fpu_q15)
     return FPRegSet;
+  if (reg_index == tls_tpidruro && m_has_tls_reg)
+    return TLSRegSet;
   return LLDB_INVALID_REGNUM;
 }
 
diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.h 
b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.h
index db155d757ca8c..0695b0afd858e 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.h
+++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.h
@@ -15,7 +15,7 @@
 
 class RegisterInfoPOSIX_arm : public lldb_private::RegisterInfoAndSetInterface 
{
 public:
-  enum { GPRegSet = 0, FPRegSet};
+  enum { GPRegSet = 0, FPRegSet, TLSRegSet };
 
   struct GPR {
     uint32_t r[16]; // R0-R15
@@ -40,6 +40,10 @@ class RegisterInfoPOSIX_arm : public 
lldb_private::RegisterInfoAndSetInterface {
     uint32_t far; /* Virtual Fault Address */
   };
 
+  struct TLS {
+    uint32_t tpidruro;
+  };
+
   struct DBG {
     uint32_t bvr[16];
     uint32_t bcr[16];
@@ -47,7 +51,8 @@ class RegisterInfoPOSIX_arm : public 
lldb_private::RegisterInfoAndSetInterface {
     uint32_t wcr[16];
   };
 
-  RegisterInfoPOSIX_arm(const lldb_private::ArchSpec &target_arch);
+  RegisterInfoPOSIX_arm(const lldb_private::ArchSpec &target_arch,
+                        bool has_tls_reg = false);
 
   size_t GetGPRSize() const override;
 
@@ -67,6 +72,9 @@ class RegisterInfoPOSIX_arm : public 
lldb_private::RegisterInfoAndSetInterface {
 private:
   const lldb_private::RegisterInfo *m_register_info_p;
   uint32_t m_register_info_count;
+  // Only provide information about the TLS register to users of this class 
that
+  // can handle it. Currently, only `NativeRegisterContextLinux_arm` reads it.
+  bool m_has_tls_reg;
 };
 
 #endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERINFOPOSIX_ARM_H
diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfos_arm.h 
b/lldb/source/Plugins/Process/Utility/RegisterInfos_arm.h
index f535ca40c4030..6bcfe949bd478 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterInfos_arm.h
+++ b/lldb/source/Plugins/Process/Utility/RegisterInfos_arm.h
@@ -32,6 +32,10 @@ using namespace lldb_private;
 #error FPSCR_OFFSET must be defined before including this header file
 #endif
 
+#ifndef TLS_OFFSET
+#error TLS_OFFSET must be defined before including this header file
+#endif
+
 #ifndef EXC_OFFSET
 #error EXC_OFFSET_NAME must be defined before including this header file
 #endif
@@ -146,6 +150,8 @@ enum {
   fpu_q14,
   fpu_q15,
 
+  tls_tpidruro,
+
   exc_exception,
   exc_fsr,
   exc_far,
@@ -682,6 +688,20 @@ static RegisterInfo g_register_infos_arm[] = {
     FPU_QREG(q14, 56),
     FPU_QREG(q15, 60),
 
+    {
+        "tpidruro",
+        nullptr,
+        4,
+        TLS_OFFSET,
+        eEncodingUint,
+        eFormatHex,
+        {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_REGNUM_GENERIC_TP,
+         LLDB_INVALID_REGNUM, tls_tpidruro},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+
     {
         "exception",
         nullptr,
diff --git 
a/lldb/source/Plugins/Process/Windows/Common/arm/RegisterContextWindows_arm.cpp 
b/lldb/source/Plugins/Process/Windows/Common/arm/RegisterContextWindows_arm.cpp
index bf970bd521c73..6f0efc257695d 100644
--- 
a/lldb/source/Plugins/Process/Windows/Common/arm/RegisterContextWindows_arm.cpp
+++ 
b/lldb/source/Plugins/Process/Windows/Common/arm/RegisterContextWindows_arm.cpp
@@ -25,6 +25,7 @@ using namespace lldb_private;
 #define GPR_OFFSET(idx) 0
 #define FPU_OFFSET(idx) 0
 #define FPSCR_OFFSET 0
+#define TLS_OFFSET 0
 #define EXC_OFFSET(reg) 0
 #define DBG_OFFSET_NAME(reg) 0
 
diff --git a/lldb/test/API/linux/arm/tls_register/Makefile 
b/lldb/test/API/linux/arm/tls_register/Makefile
new file mode 100644
index 0000000000000..10495940055b6
--- /dev/null
+++ b/lldb/test/API/linux/arm/tls_register/Makefile
@@ -0,0 +1,3 @@
+C_SOURCES := main.c
+
+include Makefile.rules
diff --git a/lldb/test/API/linux/arm/tls_register/TestArmLinuxTLSRegister.py 
b/lldb/test/API/linux/arm/tls_register/TestArmLinuxTLSRegister.py
new file mode 100644
index 0000000000000..5f5699702eaa5
--- /dev/null
+++ b/lldb/test/API/linux/arm/tls_register/TestArmLinuxTLSRegister.py
@@ -0,0 +1,45 @@
+"""
+Test lldb's ability to read the Arm TLS register.
+"""
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+@skipUnlessArch("arm")
+@skipUnlessPlatform(["linux"])
+class ArmLinuxTLSRegister(TestBase):
+    NO_DEBUG_INFO_TESTCASE = True
+
+    def test_tls_reg_read(self):
+        self.build()
+        (_, _, thread, _) = lldbutil.run_to_source_breakpoint(
+            self, "// Set breakpoint here.", lldb.SBFileSpec("main.c")
+        )
+        frame = thread.GetFrameAtIndex(0)
+
+        tpidruro_var = frame.FindVariable("tpidruro")
+        self.assertTrue(tpidruro_var.IsValid())
+
+        regs = frame.GetRegisters()
+        tls_regs = regs.GetFirstValueByName("Thread Local Storage Registers")
+        self.assertTrue(tls_regs.IsValid(), "No TLS registers found.")
+        tpidruro_reg = tls_regs.GetChildMemberWithName("tpidruro")
+        self.assertTrue(tpidruro_reg.IsValid(), "tpidruro register not found.")
+
+        val = tpidruro_var.GetValueAsUnsigned()
+        self.assertEqual(tpidruro_reg.GetValueAsUnsigned(), val)
+        self.expect("reg read tp", substrs=[hex(val)])
+
+    def test_tls_reg_write(self):
+        self.build()
+        lldbutil.run_to_source_breakpoint(
+            self, "// Set breakpoint here.", lldb.SBFileSpec("main.c")
+        )
+        self.expect(
+            "register write tpidruro 0x1234",
+            error=True,
+            substrs=["Failed to write register 'tpidruro'"],
+        )
diff --git a/lldb/test/API/linux/arm/tls_register/main.c 
b/lldb/test/API/linux/arm/tls_register/main.c
new file mode 100644
index 0000000000000..ccbc3cbc45377
--- /dev/null
+++ b/lldb/test/API/linux/arm/tls_register/main.c
@@ -0,0 +1,7 @@
+#include <stdint.h>
+
+int main(int argc, char *argv[]) {
+  uint32_t tpidruro = 0;
+  __asm__ volatile("mrc p15, 0, %0, c13, c0, 3" : "=r"(tpidruro));
+  return 0; // Set breakpoint here.
+}
diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md
index 2e121923e0bb9..184a1c0dc9407 100644
--- a/llvm/docs/ReleaseNotes.md
+++ b/llvm/docs/ReleaseNotes.md
@@ -213,6 +213,10 @@ Changes to LLDB
 * The crashed thread is now automatically selected on start.
 * Threads are listed in incrmental order by pid then by tid.
 
+### Linux
+
+* On Arm Linux, the tpidruro register can now be read. Writing to this 
register is not supported.
+
 Changes to BOLT
 ---------------
 

``````````

</details>


https://github.com/llvm/llvm-project/pull/182438
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to