[Lldb-commits] [lldb] 0d0ca51 - [lldb][AArch64] Read SME2's ZT0 register from Linux core files (#70934)

via lldb-commits lldb-commits at lists.llvm.org
Thu Nov 2 08:56:49 PDT 2023


Author: David Spickett
Date: 2023-11-02T15:56:46Z
New Revision: 0d0ca51ffe1002cec3b1b7a332e290176b650390

URL: https://github.com/llvm/llvm-project/commit/0d0ca51ffe1002cec3b1b7a332e290176b650390
DIFF: https://github.com/llvm/llvm-project/commit/0d0ca51ffe1002cec3b1b7a332e290176b650390.diff

LOG: [lldb][AArch64] Read SME2's ZT0 register from Linux core files (#70934)

The ZT0 register is always 64 bytes in size so it is a lot easier to
handle than ZA which is scalable. In addition, reading an inactive ZT0
via ptrace returns all 0s, unlike ZA which returns no register data.

This means that a corefile from a process where ZA and ZT0 were inactive
still contains an NT_ARM_ZT note and we can simply say that if it's
there, then we should be able to read from it.

Along the way I removed a redundant check on the size of the ZA note. If
that note's size is < the ZA header size, we do not have SME, and
therefore could not have SME2 either.

I have added ZT0 to the existing SME core files tests. This means that
you need an SME2 system to generate them (Arm's FVP at this point). I
think this is a fair tradeoff given that this is all running in
simulation anyway and seperate ZT0 tests would be 99% identical copies
of the ZA only tests.

Added: 
    lldb/test/API/linux/aarch64/sme_core_file/generate.sh

Modified: 
    lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp
    lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h
    lldb/test/API/linux/aarch64/sme_core_file/TestAArch64LinuxSMECoreFile.py
    lldb/test/API/linux/aarch64/sme_core_file/core_0_16_32_1
    lldb/test/API/linux/aarch64/sme_core_file/core_0_32_16_0
    lldb/test/API/linux/aarch64/sme_core_file/core_1_16_32_0
    lldb/test/API/linux/aarch64/sme_core_file/core_1_32_16_1
    lldb/test/API/linux/aarch64/sme_core_file/main.c

Removed: 
    


################################################################################
diff  --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp
index db37b7cbb99d7e8..85073b56f64bf79 100644
--- a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp
+++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp
@@ -54,6 +54,13 @@ RegisterContextCorePOSIX_arm64::Create(Thread &thread, const ArchSpec &arch,
   if (mte_data.GetByteSize() >= sizeof(uint64_t))
     opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskMTE);
 
+  DataExtractor zt_data = getRegset(notes, arch.GetTriple(), AARCH64_ZT_Desc);
+  // Although ZT0 can be in a disabled state like ZA can, the kernel reports
+  // its content as 0s in that state. Therefore even a disabled ZT0 will have
+  // a note containing those 0s. ZT0 is a 512 bit / 64 byte register.
+  if (zt_data.GetByteSize() >= 64)
+    opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskZT);
+
   auto register_info_up =
       std::make_unique<RegisterInfoPOSIX_arm64>(arch, opt_regsets);
   return std::unique_ptr<RegisterContextCorePOSIX_arm64>(
@@ -98,6 +105,9 @@ RegisterContextCorePOSIX_arm64::RegisterContextCorePOSIX_arm64(
   if (m_register_info_up->IsMTEPresent())
     m_mte_data = getRegset(notes, target_triple, AARCH64_MTE_Desc);
 
+  if (m_register_info_up->IsZTPresent())
+    m_zt_data = getRegset(notes, target_triple, AARCH64_ZT_Desc);
+
   ConfigureRegisterContext();
 }
 
@@ -298,19 +308,7 @@ bool RegisterContextCorePOSIX_arm64::ReadRegister(const RegisterInfo *reg_info,
     if (m_za_data.GetByteSize() < sizeof(sve::user_za_header))
       return false;
 
-    if (!IsSMEZA(reg)) {
-      offset = reg_info->byte_offset - m_register_info_up->GetSMEOffset();
-      assert(offset < sizeof(m_sme_pseudo_regs));
-      // Host endian since these values are derived instead of being read from a
-      // core file note.
-      value.SetFromMemoryData(
-          *reg_info, reinterpret_cast<uint8_t *>(&m_sme_pseudo_regs) + offset,
-          reg_info->byte_size, lldb_private::endian::InlHostByteOrder(), error);
-    } else {
-      // If the process did not have the SME extension.
-      if (m_za_data.GetByteSize() < sizeof(sve::user_za_header))
-        return false;
-
+    if (m_register_info_up->IsSMERegZA(reg)) {
       // Don't use the size of the note to tell whether ZA is enabled. There may
       // be non-register padding data after the header. Use the embedded
       // header's size field instead.
@@ -339,6 +337,18 @@ bool RegisterContextCorePOSIX_arm64::ReadRegister(const RegisterInfo *reg_info,
       value.SetFromMemoryData(*reg_info, src + sizeof(sve::user_za_header),
                               reg_info->byte_size, lldb::eByteOrderLittle,
                               error);
+    } else if (m_register_info_up->IsSMERegZT(reg)) {
+      value.SetFromMemoryData(*reg_info, m_zt_data.GetDataStart(),
+                              reg_info->byte_size, lldb::eByteOrderLittle,
+                              error);
+    } else {
+      offset = reg_info->byte_offset - m_register_info_up->GetSMEOffset();
+      assert(offset < sizeof(m_sme_pseudo_regs));
+      // Host endian since these values are derived instead of being read from a
+      // core file note.
+      value.SetFromMemoryData(
+          *reg_info, reinterpret_cast<uint8_t *>(&m_sme_pseudo_regs) + offset,
+          reg_info->byte_size, lldb_private::endian::InlHostByteOrder(), error);
     }
   } else
     return false;

diff  --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h
index 86bdeb426ab3fe0..95527af74fb5334 100644
--- a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h
+++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h
@@ -60,6 +60,7 @@ class RegisterContextCorePOSIX_arm64 : public RegisterContextPOSIX_arm64 {
   lldb_private::DataExtractor m_tls_data;
   lldb_private::DataExtractor m_za_data;
   lldb_private::DataExtractor m_mte_data;
+  lldb_private::DataExtractor m_zt_data;
 
   SVEState m_sve_state = SVEState::Unknown;
   uint16_t m_sve_vector_length = 0;

diff  --git a/lldb/test/API/linux/aarch64/sme_core_file/TestAArch64LinuxSMECoreFile.py b/lldb/test/API/linux/aarch64/sme_core_file/TestAArch64LinuxSMECoreFile.py
index f65e64f9db739ae..a5fdd0ab2068cbb 100644
--- a/lldb/test/API/linux/aarch64/sme_core_file/TestAArch64LinuxSMECoreFile.py
+++ b/lldb/test/API/linux/aarch64/sme_core_file/TestAArch64LinuxSMECoreFile.py
@@ -89,14 +89,19 @@ def check_corefile(self, corefile):
             # Each row of ZA is set to the row number plus 1. For example:
             # za = {0x01 0x01 0x01 0x01 <repeat until end of row> 0x02 0x02 ...
             make_row = repeat_bytes
+            expected_zt0 = "{{{}}}".format(
+                " ".join(["0x{:02x}".format(i + 1) for i in range(512 // 8)])
+            )
         else:
             # When ZA is disabled lldb shows it as 0s.
             make_row = lambda _, n: repeat_bytes(0, n)
+            expected_zt0 = "{{{}}}".format(" ".join(["0x00" for i in range(512 // 8)]))
 
         expected_za = "{{{}}}".format(
             " ".join([make_row(i + 1, svl) for i in range(svl)])
         )
         self.expect("register read za", substrs=[expected_za])
+        self.expect("register read zt0", substrs=[expected_zt0])
 
     @skipIfLLVMTargetMissing("AArch64")
     def test_sme_core_file_ssve_vl32_svl16_za_enabled(self):

diff  --git a/lldb/test/API/linux/aarch64/sme_core_file/core_0_16_32_1 b/lldb/test/API/linux/aarch64/sme_core_file/core_0_16_32_1
index b7c6250324cc21e..b7345748c363741 100644
Binary files a/lldb/test/API/linux/aarch64/sme_core_file/core_0_16_32_1 and b/lldb/test/API/linux/aarch64/sme_core_file/core_0_16_32_1 
diff er

diff  --git a/lldb/test/API/linux/aarch64/sme_core_file/core_0_32_16_0 b/lldb/test/API/linux/aarch64/sme_core_file/core_0_32_16_0
index cba6c0f0738370a..713fb2384a29f43 100644
Binary files a/lldb/test/API/linux/aarch64/sme_core_file/core_0_32_16_0 and b/lldb/test/API/linux/aarch64/sme_core_file/core_0_32_16_0 
diff er

diff  --git a/lldb/test/API/linux/aarch64/sme_core_file/core_1_16_32_0 b/lldb/test/API/linux/aarch64/sme_core_file/core_1_16_32_0
index dcda36c862bfb66..9d6efd7f9c7510f 100644
Binary files a/lldb/test/API/linux/aarch64/sme_core_file/core_1_16_32_0 and b/lldb/test/API/linux/aarch64/sme_core_file/core_1_16_32_0 
diff er

diff  --git a/lldb/test/API/linux/aarch64/sme_core_file/core_1_32_16_1 b/lldb/test/API/linux/aarch64/sme_core_file/core_1_32_16_1
index 7ec49584f2b6424..9c6f2033adc10fa 100644
Binary files a/lldb/test/API/linux/aarch64/sme_core_file/core_1_32_16_1 and b/lldb/test/API/linux/aarch64/sme_core_file/core_1_32_16_1 
diff er

diff  --git a/lldb/test/API/linux/aarch64/sme_core_file/generate.sh b/lldb/test/API/linux/aarch64/sme_core_file/generate.sh
new file mode 100644
index 000000000000000..5e75a5cdb8bd03b
--- /dev/null
+++ b/lldb/test/API/linux/aarch64/sme_core_file/generate.sh
@@ -0,0 +1,9 @@
+run () {
+  ./a.out "$@"
+  mv core core_$(echo "$*" | sed 's/ /_/g')
+}
+
+run 0 16 32 1
+run 0 32 16 0
+run 1 16 32 0
+run 1 32 16 1

diff  --git a/lldb/test/API/linux/aarch64/sme_core_file/main.c b/lldb/test/API/linux/aarch64/sme_core_file/main.c
index 21793a4ad63d39e..10fc92ba2fcabe0 100644
--- a/lldb/test/API/linux/aarch64/sme_core_file/main.c
+++ b/lldb/test/API/linux/aarch64/sme_core_file/main.c
@@ -1,16 +1,21 @@
 // clang-format off
 // Compile with:
-// clang -target aarch64-unknown-linux-gnu main.c -o a.out -g -march=armv8.6-a+sve+sme
+// clang -target aarch64-unknown-linux-gnu main.c -o a.out -g -march=armv8.6-a+sve+sme+sme2
 //
 // For minimal corefile size, do this before running the program:
-// echo 0x20 > /proc/self/coredeump_filter
+// echo 0x20 > /proc/self/coredump_filter
 //
-// Must be run on a system that has SVE and SME, including the smefa64
-// extension. Example command:
-// main 0 32 64 1
+// Must be run on a system that has SVE, SME and SME2, including the smefa64
+// extension.
+//
+// Example command:
+// ./a.out 0 32 64 1
 //
 // This would not enter streaming mode, set non-streaming VL to 32
-// bytes, streaming VL to 64 bytes and enable ZA.
+// bytes, streaming VL to 64 bytes and enable ZA and ZT0.
+//
+// To generate all the test files, use the generate.sh script that's in this
+// folder.
 // clang-format on
 
 #include <stdbool.h>
@@ -94,6 +99,17 @@ void set_za_register(int streaming_vl) {
                  "r"(&data)
                  : "w12");
   }
+#undef MAX_VL_BYTES
+}
+
+void set_zt0_register() {
+#define ZTO_LEN (512 / 8)
+  uint8_t data[ZTO_LEN];
+  for (unsigned i = 0; i < ZTO_LEN; ++i)
+    data[i] = i + 1;
+
+  asm volatile("ldr zt0, [%0]" ::"r"(&data));
+#undef ZT0_LEN
 }
 
 void set_tpidr2(uint64_t value) {
@@ -132,6 +148,7 @@ int main(int argc, char **argv) {
   if (strcmp(argv[4], "1") == 0) {
     SMSTART_ZA;
     set_za_register(streaming_vl);
+    set_zt0_register();
   }
 
   *(volatile char *)(0) = 0; // Crashes here.


        


More information about the lldb-commits mailing list