This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rGefa43d785ee6: [lldb][AArch64] Add the tpidr2 TLS register
that comes with SME (authored by DavidSpickett).
Changed prior to commit:
https://reviews.llvm.org/D154930?vs=542932&id=544269#toc
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D154930/new/
https://reviews.llvm.org/D154930
Files:
lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h
lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp
lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h
lldb/test/API/linux/aarch64/tls_register/Makefile
lldb/test/API/linux/aarch64/tls_register/TestAArch64LinuxTLSRegister.py
lldb/test/API/linux/aarch64/tls_register/main.c
lldb/test/API/linux/aarch64/tls_registers/Makefile
lldb/test/API/linux/aarch64/tls_registers/TestAArch64LinuxTLSRegisters.py
lldb/test/API/linux/aarch64/tls_registers/main.c
Index: lldb/test/API/linux/aarch64/tls_registers/main.c
===================================================================
--- /dev/null
+++ lldb/test/API/linux/aarch64/tls_registers/main.c
@@ -0,0 +1,60 @@
+#include <stdbool.h>
+#include <stdint.h>
+
+uint64_t get_tpidr(void) {
+ uint64_t tpidr = 0;
+ __asm__ volatile("mrs %0, tpidr_el0" : "=r"(tpidr));
+ return tpidr;
+}
+
+uint64_t get_tpidr2(void) {
+ uint64_t tpidr2 = 0;
+ // S3_3_C13_C0_5 means tpidr2, and will work with older tools.
+ __asm__ volatile("mrs %0, S3_3_C13_C0_5" : "=r"(tpidr2));
+ return tpidr2;
+}
+
+void set_tpidr(uint64_t value) {
+ __asm__ volatile("msr tpidr_el0, %0" ::"r"(value));
+}
+
+void set_tpidr2(uint64_t value) {
+ __asm__ volatile("msr S3_3_C13_C0_5, %0" ::"r"(value));
+}
+
+int main(int argc, char *argv[]) {
+ bool use_tpidr2 = argc > 1;
+
+ uint64_t original_tpidr = get_tpidr();
+ // Accessing this on a core without it produces SIGILL. Only do this if
+ // requested.
+ uint64_t original_tpidr2 = 0;
+ if (use_tpidr2)
+ original_tpidr2 = get_tpidr2();
+
+ uint64_t tpidr_pattern = 0x1122334455667788;
+ set_tpidr(tpidr_pattern);
+
+ uint64_t tpidr2_pattern = 0x8877665544332211;
+ if (use_tpidr2)
+ set_tpidr2(tpidr2_pattern);
+
+ // Set break point at this line.
+ // lldb will now set its own pattern(s) for us to find.
+
+ uint64_t new_tpidr = get_tpidr();
+ volatile bool tpidr_was_set = new_tpidr == 0x1111222233334444;
+
+ uint64_t new_tpidr2 = 0;
+ volatile bool tpidr2_was_set = false;
+ if (use_tpidr2) {
+ new_tpidr2 = get_tpidr2();
+ tpidr2_was_set = new_tpidr2 == 0x4444333322221111;
+ }
+
+ set_tpidr(original_tpidr);
+ if (use_tpidr2)
+ set_tpidr2(original_tpidr2);
+
+ return 0; // Set break point 2 at this line.
+}
Index: lldb/test/API/linux/aarch64/tls_registers/TestAArch64LinuxTLSRegisters.py
===================================================================
--- /dev/null
+++ lldb/test/API/linux/aarch64/tls_registers/TestAArch64LinuxTLSRegisters.py
@@ -0,0 +1,115 @@
+"""
+Test lldb's ability to read and write the AArch64 TLS registers.
+"""
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class AArch64LinuxTLSRegisters(TestBase):
+ NO_DEBUG_INFO_TESTCASE = True
+
+ def setup(self, registers):
+ self.build()
+ self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
+
+ lldbutil.run_break_set_by_file_and_line(
+ self,
+ "main.c",
+ line_number("main.c", "// Set break point at this line."),
+ num_expected_locations=1,
+ )
+
+ lldbutil.run_break_set_by_file_and_line(
+ self,
+ "main.c",
+ line_number("main.c", "// Set break point 2 at this line."),
+ num_expected_locations=1,
+ )
+
+ if "tpidr2" in registers:
+ self.runCmd("settings set target.run-args 1")
+ self.runCmd("run", RUN_SUCCEEDED)
+
+ if self.process().GetState() == lldb.eStateExited:
+ self.fail("Test program failed to run.")
+
+ self.expect(
+ "thread list",
+ STOPPED_DUE_TO_BREAKPOINT,
+ substrs=["stopped", "stop reason = breakpoint"],
+ )
+
+ def check_tls_reg(self, registers):
+ self.setup(registers)
+
+ regs = self.thread().GetSelectedFrame().GetRegisters()
+ tls_regs = regs.GetFirstValueByName("Thread Local Storage Registers")
+ self.assertTrue(tls_regs.IsValid(), "No TLS registers found.")
+
+ # Since we can't predict what the value will be, the program has set
+ # a target value for us to find.
+ initial_values = {
+ "tpidr": 0x1122334455667788,
+ "tpidr2": 0x8877665544332211,
+ }
+
+ for register in registers:
+ tls_reg = tls_regs.GetChildMemberWithName(register)
+ self.assertTrue(tls_reg.IsValid(), "{} register not found.".format(
+ register))
+ self.assertEqual(tls_reg.GetValueAsUnsigned(), initial_values[register])
+
+ set_values = {
+ "tpidr": 0x1111222233334444,
+ "tpidr2": 0x4444333322221111,
+ }
+
+ # Set our own value(s) for the program to find.
+ for register in registers:
+ self.expect("register write {} 0x{:x}".format(register,
+ set_values[register]))
+
+ self.expect("continue")
+
+ self.expect(
+ "thread list",
+ STOPPED_DUE_TO_BREAKPOINT,
+ substrs=["stopped", "stop reason = breakpoint"],
+ )
+
+ for register in registers:
+ self.expect("p {}_was_set".format(register), substrs=["true"])
+
+ @skipUnlessArch("aarch64")
+ @skipUnlessPlatform(["linux"])
+ def test_tls_no_sme(self):
+ if self.isAArch64SME():
+ self.skipTest("SME must not be present.")
+
+ self.check_tls_reg(["tpidr"])
+
+ @skipUnlessArch("aarch64")
+ @skipUnlessPlatform(["linux"])
+ def test_tls_sme(self):
+ if not self.isAArch64SME():
+ self.skipTest("SME must present.")
+
+ self.check_tls_reg(["tpidr", "tpidr2"])
+
+ @skipUnlessArch("aarch64")
+ @skipUnlessPlatform(["linux"])
+ def test_tpidr2_no_sme(self):
+ if self.isAArch64SME():
+ self.skipTest("SME must not be present.")
+
+ self.setup("tpidr")
+
+ regs = self.thread().GetSelectedFrame().GetRegisters()
+ tls_regs = regs.GetFirstValueByName("Thread Local Storage Registers")
+ self.assertTrue(tls_regs.IsValid(), "No TLS registers found.")
+ tls_reg = tls_regs.GetChildMemberWithName("tpidr2")
+ self.assertFalse(tls_reg.IsValid(),
+ "tpdir2 should not be present without SME")
Index: lldb/test/API/linux/aarch64/tls_register/main.c
===================================================================
--- lldb/test/API/linux/aarch64/tls_register/main.c
+++ /dev/null
@@ -1,24 +0,0 @@
-#include <stdbool.h>
-#include <stdint.h>
-
-int main() {
- // Save tpidr to restore later.
- uint64_t tpidr = 0;
- __asm__ volatile("mrs %0, tpidr_el0" : "=r"(tpidr));
-
- // Set a pattern for lldb to find.
- uint64_t pattern = 0x1122334455667788;
- __asm__ volatile("msr tpidr_el0, %0" ::"r"(pattern));
-
- // Set break point at this line.
- // lldb will now set its own pattern for us to find.
-
- uint64_t new_tpidr = pattern;
- __asm__ volatile("mrs %0, tpidr_el0" : "=r"(new_tpidr));
- volatile bool tpidr_was_set = new_tpidr == 0x8877665544332211;
-
- // Restore the original.
- __asm__ volatile("msr tpidr_el0, %0" ::"r"(tpidr));
-
- return 0; // Set break point 2 at this line.
-}
Index: lldb/test/API/linux/aarch64/tls_register/TestAArch64LinuxTLSRegister.py
===================================================================
--- lldb/test/API/linux/aarch64/tls_register/TestAArch64LinuxTLSRegister.py
+++ /dev/null
@@ -1,66 +0,0 @@
-"""
-Test lldb's ability to read and write the AArch64 TLS register tpidr.
-"""
-
-import lldb
-from lldbsuite.test.decorators import *
-from lldbsuite.test.lldbtest import *
-from lldbsuite.test import lldbutil
-
-
-class AArch64LinuxTLSRegister(TestBase):
- NO_DEBUG_INFO_TESTCASE = True
-
- @skipUnlessArch("aarch64")
- @skipUnlessPlatform(["linux"])
- def test_tls(self):
- self.build()
- self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
-
- lldbutil.run_break_set_by_file_and_line(
- self,
- "main.c",
- line_number("main.c", "// Set break point at this line."),
- num_expected_locations=1,
- )
-
- lldbutil.run_break_set_by_file_and_line(
- self,
- "main.c",
- line_number("main.c", "// Set break point 2 at this line."),
- num_expected_locations=1,
- )
-
- self.runCmd("run", RUN_SUCCEEDED)
-
- if self.process().GetState() == lldb.eStateExited:
- self.fail("Test program failed to run.")
-
- self.expect(
- "thread list",
- STOPPED_DUE_TO_BREAKPOINT,
- substrs=["stopped", "stop reason = breakpoint"],
- )
-
- # Since we can't predict what the value will be, the program has set
- # a target value for us to find.
-
- regs = self.thread().GetSelectedFrame().GetRegisters()
- tls_regs = regs.GetFirstValueByName("Thread Local Storage Registers")
- self.assertTrue(tls_regs.IsValid(), "No TLS registers found.")
- tpidr = tls_regs.GetChildMemberWithName("tpidr")
- self.assertTrue(tpidr.IsValid(), "No tpidr register found.")
-
- self.assertEqual(tpidr.GetValueAsUnsigned(), 0x1122334455667788)
-
- # Set our own value for the program to find.
- self.expect("register write tpidr 0x{:x}".format(0x8877665544332211))
- self.expect("continue")
-
- self.expect(
- "thread list",
- STOPPED_DUE_TO_BREAKPOINT,
- substrs=["stopped", "stop reason = breakpoint"],
- )
-
- self.expect("p tpidr_was_set", substrs=["true"])
\ No newline at end of file
Index: lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h
===================================================================
--- lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h
+++ lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h
@@ -104,7 +104,7 @@
void AddRegSetMTE();
- void AddRegSetTLS();
+ void AddRegSetTLS(bool has_tpidr2);
uint32_t ConfigureVectorLength(uint32_t sve_vq);
Index: lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp
===================================================================
--- lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp
+++ lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp
@@ -79,7 +79,9 @@
DEFINE_EXTENSION_REG(mte_ctrl)};
static lldb_private::RegisterInfo g_register_infos_tls[] = {
- DEFINE_EXTENSION_REG(tpidr)};
+ DEFINE_EXTENSION_REG(tpidr),
+ // Only present when SME is present
+ DEFINE_EXTENSION_REG(tpidr2)};
// Number of register sets provided by this context.
enum {
@@ -87,7 +89,7 @@
k_num_fpr_registers = fpu_fpcr - fpu_v0 + 1,
k_num_sve_registers = sve_ffr - sve_vg + 1,
k_num_mte_register = 1,
- k_num_tls_register = 1,
+ // Number of TLS registers is dynamic so it is not listed here.
k_num_pauth_register = 2,
k_num_register_sets_default = 2,
k_num_register_sets = 3
@@ -193,8 +195,7 @@
static const lldb_private::RegisterSet g_reg_set_mte_arm64 = {
"MTE Control Register", "mte", k_num_mte_register, nullptr};
-static const lldb_private::RegisterSet g_reg_set_tls_arm64 = {
- "Thread Local Storage Registers", "tls", k_num_tls_register, nullptr};
+// The size of the TLS set is dynamic, so not listed here.
RegisterInfoPOSIX_arm64::RegisterInfoPOSIX_arm64(
const lldb_private::ArchSpec &target_arch, lldb_private::Flags opt_regsets)
@@ -236,9 +237,9 @@
if (m_opt_regsets.AllSet(eRegsetMaskMTE))
AddRegSetMTE();
- // tpidr is always present, but in future there will be others so this is
- // done as a dynamic set.
- AddRegSetTLS();
+ // The TLS set always contains tpidr but only has tpidr2 when SME is
+ // present.
+ AddRegSetTLS(m_opt_regsets.AllSet(eRegsetMaskSSVE));
m_register_info_count = m_dynamic_reg_infos.size();
m_register_info_p = m_dynamic_reg_infos.data();
@@ -323,18 +324,23 @@
m_dynamic_reg_sets.back().registers = m_mte_regnum_collection.data();
}
-void RegisterInfoPOSIX_arm64::AddRegSetTLS() {
+void RegisterInfoPOSIX_arm64::AddRegSetTLS(bool has_tpidr2) {
uint32_t tls_regnum = m_dynamic_reg_infos.size();
- m_tls_regnum_collection.push_back(tls_regnum);
- m_dynamic_reg_infos.push_back(g_register_infos_tls[0]);
- m_dynamic_reg_infos[tls_regnum].byte_offset =
- m_dynamic_reg_infos[tls_regnum - 1].byte_offset +
- m_dynamic_reg_infos[tls_regnum - 1].byte_size;
- m_dynamic_reg_infos[tls_regnum].kinds[lldb::eRegisterKindLLDB] = tls_regnum;
+ uint32_t num_regs = has_tpidr2 ? 2 : 1;
+ for (uint32_t i = 0; i < num_regs; i++) {
+ m_tls_regnum_collection.push_back(tls_regnum + i);
+ m_dynamic_reg_infos.push_back(g_register_infos_tls[i]);
+ m_dynamic_reg_infos[tls_regnum + i].byte_offset =
+ m_dynamic_reg_infos[tls_regnum + i - 1].byte_offset +
+ m_dynamic_reg_infos[tls_regnum + i - 1].byte_size;
+ m_dynamic_reg_infos[tls_regnum + i].kinds[lldb::eRegisterKindLLDB] =
+ tls_regnum + i;
+ }
m_per_regset_regnum_range[m_register_set_count] =
- std::make_pair(tls_regnum, tls_regnum + 1);
- m_dynamic_reg_sets.push_back(g_reg_set_tls_arm64);
+ std::make_pair(tls_regnum, m_dynamic_reg_infos.size());
+ m_dynamic_reg_sets.push_back(
+ {"Thread Local Storage Registers", "tls", num_regs, nullptr});
m_dynamic_reg_sets.back().registers = m_tls_regnum_collection.data();
}
Index: lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h
===================================================================
--- lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h
+++ lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h
@@ -83,10 +83,11 @@
bool m_fpu_is_valid;
bool m_sve_buffer_is_valid;
bool m_mte_ctrl_is_valid;
- bool m_tls_tpidr_is_valid;
bool m_sve_header_is_valid;
bool m_pac_mask_is_valid;
+ bool m_tls_is_valid;
+ size_t m_tls_size;
struct user_pt_regs m_gpr_arm64; // 64-bit general purpose registers.
@@ -108,7 +109,13 @@
uint64_t m_mte_ctrl_reg;
- uint64_t m_tls_tpidr_reg;
+ struct tls_regs {
+ uint64_t tpidr_reg;
+ // Only valid when SME is present.
+ uint64_t tpidr2_reg;
+ };
+
+ struct tls_regs m_tls_regs;
bool IsGPR(unsigned reg) const;
@@ -128,9 +135,9 @@
Status WriteMTEControl();
- Status ReadTLSTPIDR();
+ Status ReadTLS();
- Status WriteTLSTPIDR();
+ Status WriteTLS();
bool IsSVE(unsigned reg) const;
bool IsPAuth(unsigned reg) const;
@@ -147,7 +154,7 @@
void *GetMTEControl() { return &m_mte_ctrl_reg; }
- void *GetTLSTPIDR() { return &m_tls_tpidr_reg; }
+ void *GetTLSBuffer() { return &m_tls_regs; }
void *GetSVEBuffer() { return m_sve_ptrace_payload.data(); }
@@ -161,7 +168,7 @@
size_t GetMTEControlSize() { return sizeof(m_mte_ctrl_reg); }
- size_t GetTLSTPIDRSize() { return sizeof(m_tls_tpidr_reg); }
+ size_t GetTLSBufferSize() { return m_tls_size; }
llvm::Error ReadHardwareDebugInfo() override;
Index: lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
===================================================================
--- lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
+++ lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
@@ -132,9 +132,9 @@
::memset(&m_hbp_regs, 0, sizeof(m_hbp_regs));
::memset(&m_sve_header, 0, sizeof(m_sve_header));
::memset(&m_pac_mask, 0, sizeof(m_pac_mask));
+ ::memset(&m_tls_regs, 0, sizeof(m_tls_regs));
m_mte_ctrl_reg = 0;
- m_tls_tpidr_reg = 0;
// 16 is just a maximum value, query hardware for actual watchpoint count
m_max_hwp_supported = 16;
@@ -148,7 +148,11 @@
m_sve_header_is_valid = false;
m_pac_mask_is_valid = false;
m_mte_ctrl_is_valid = false;
- m_tls_tpidr_is_valid = false;
+ m_tls_is_valid = false;
+
+ // SME adds the tpidr2 register
+ m_tls_size = GetRegisterInfo().IsSSVEEnabled() ? sizeof(m_tls_regs)
+ : sizeof(m_tls_regs.tpidr_reg);
if (GetRegisterInfo().IsSVEEnabled() || GetRegisterInfo().IsSSVEEnabled())
m_sve_state = SVEState::Unknown;
@@ -255,13 +259,13 @@
src = (uint8_t *)GetSVEBuffer() + offset;
}
} else if (IsTLS(reg)) {
- error = ReadTLSTPIDR();
+ error = ReadTLS();
if (error.Fail())
return error;
offset = reg_info->byte_offset - GetRegisterInfo().GetTLSOffset();
- assert(offset < GetTLSTPIDRSize());
- src = (uint8_t *)GetTLSTPIDR() + offset;
+ assert(offset < GetTLSBufferSize());
+ src = (uint8_t *)GetTLSBuffer() + offset;
} else if (IsSVE(reg)) {
if (m_sve_state == SVEState::Disabled || m_sve_state == SVEState::Unknown)
return Status("SVE disabled or not supported");
@@ -480,16 +484,16 @@
return WriteMTEControl();
} else if (IsTLS(reg)) {
- error = ReadTLSTPIDR();
+ error = ReadTLS();
if (error.Fail())
return error;
offset = reg_info->byte_offset - GetRegisterInfo().GetTLSOffset();
- assert(offset < GetTLSTPIDRSize());
- dst = (uint8_t *)GetTLSTPIDR() + offset;
+ assert(offset < GetTLSBufferSize());
+ dst = (uint8_t *)GetTLSBuffer() + offset;
::memcpy(dst, reg_value.GetBytes(), reg_info->byte_size);
- return WriteTLSTPIDR();
+ return WriteTLS();
}
return Status("Failed to write register value");
@@ -533,9 +537,9 @@
return error;
}
- // tpidr is always present but there will be more in future.
- reg_data_byte_size += GetTLSTPIDRSize();
- error = ReadTLSTPIDR();
+ // tpidr is always present but tpidr2 depends on SME.
+ reg_data_byte_size += GetTLSBufferSize();
+ error = ReadTLS();
if (error.Fail())
return error;
@@ -558,7 +562,7 @@
if (GetRegisterInfo().IsMTEEnabled())
::memcpy(dst, GetMTEControl(), GetMTEControlSize());
- ::memcpy(dst, GetTLSTPIDR(), GetTLSTPIDRSize());
+ ::memcpy(dst, GetTLSBuffer(), GetTLSBufferSize());
return error;
}
@@ -845,7 +849,7 @@
m_sve_header_is_valid = false;
m_pac_mask_is_valid = false;
m_mte_ctrl_is_valid = false;
- m_tls_tpidr_is_valid = false;
+ m_tls_is_valid = false;
// Update SVE registers in case there is change in configuration.
ConfigureRegisterContext();
@@ -979,38 +983,38 @@
return WriteRegisterSet(&ioVec, GetMTEControlSize(), NT_ARM_TAGGED_ADDR_CTRL);
}
-Status NativeRegisterContextLinux_arm64::ReadTLSTPIDR() {
+Status NativeRegisterContextLinux_arm64::ReadTLS() {
Status error;
- if (m_tls_tpidr_is_valid)
+ if (m_tls_is_valid)
return error;
struct iovec ioVec;
- ioVec.iov_base = GetTLSTPIDR();
- ioVec.iov_len = GetTLSTPIDRSize();
+ ioVec.iov_base = GetTLSBuffer();
+ ioVec.iov_len = GetTLSBufferSize();
- error = ReadRegisterSet(&ioVec, GetTLSTPIDRSize(), NT_ARM_TLS);
+ error = ReadRegisterSet(&ioVec, GetTLSBufferSize(), NT_ARM_TLS);
if (error.Success())
- m_tls_tpidr_is_valid = true;
+ m_tls_is_valid = true;
return error;
}
-Status NativeRegisterContextLinux_arm64::WriteTLSTPIDR() {
+Status NativeRegisterContextLinux_arm64::WriteTLS() {
Status error;
- error = ReadTLSTPIDR();
+ error = ReadTLS();
if (error.Fail())
return error;
struct iovec ioVec;
- ioVec.iov_base = GetTLSTPIDR();
- ioVec.iov_len = GetTLSTPIDRSize();
+ ioVec.iov_base = GetTLSBuffer();
+ ioVec.iov_len = GetTLSBufferSize();
- m_tls_tpidr_is_valid = false;
+ m_tls_is_valid = false;
- return WriteRegisterSet(&ioVec, GetTLSTPIDRSize(), NT_ARM_TLS);
+ return WriteRegisterSet(&ioVec, GetTLSBufferSize(), NT_ARM_TLS);
}
void NativeRegisterContextLinux_arm64::ConfigureRegisterContext() {
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits