omjavaid created this revision.
omjavaid added reviewers: labath, justincohen, jasonmolenda, DavidSpickett.
Herald added subscribers: danielkiss, kristof.beyls.
omjavaid requested review of this revision.

This patch adds a new field to Process class which represents no of bits
used for addresses by the current process. A get/set function is also
added for the same.

This is useful for architectures where not all ptr bits are used for
addressing, rather some of the top bits are used to store extra
information. For example on AArch64 52 bits are maximum possible bits
available for addressing while remaining bits are used to store tags
or pointer authentication code.

This causes problem for unwinder in case return address register
contains extra information in top bits. This patch adds a function to
ABISysV_arm64 which clear those top bits and resulting sign extended
address is returned for use wherever required.

This patch also configures RegisterContextPOSIXCore_arm64 to calcualte
and set address bits currently being used by the process.

This includes elf-core test demonstrating unwinder can successfully
calculate elf-core backtrace in presence of PAC code in return address.

A follow up patch will include AArch64 Linux support for the same.


https://reviews.llvm.org/D99944

Files:
  lldb/include/lldb/Target/Process.h
  lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp
  lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.h
  lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp
  lldb/test/API/functionalities/postmortem/elf-core/TestLinuxCore.py
  lldb/test/API/functionalities/postmortem/elf-core/linux-aarch64-pac.out

Index: lldb/test/API/functionalities/postmortem/elf-core/TestLinuxCore.py
===================================================================
--- lldb/test/API/functionalities/postmortem/elf-core/TestLinuxCore.py
+++ lldb/test/API/functionalities/postmortem/elf-core/TestLinuxCore.py
@@ -20,6 +20,7 @@
     mydir = TestBase.compute_mydir(__file__)
 
     _aarch64_pid = 37688
+    _aarch64_pac_pid = 387
     _i386_pid = 32306
     _x86_64_pid = 32259
     _s390x_pid = 1045
@@ -257,6 +258,18 @@
 
         self.dbg.DeleteTarget(target)
 
+    @skipIfLLVMTargetMissing("AArch64")
+    def test_aarch64_pac(self):
+        """Test that lldb can find the exe for an AArch64 Linux core file which has PAC enabled."""
+
+        target = self.dbg.CreateTarget("linux-aarch64-pac.out")
+        self.assertTrue(target, VALID_TARGET)
+        process = target.LoadCore("linux-aarch64-pac.core")
+
+        self.check_all(process, self._aarch64_pac_pid, self._aarch64_regions, "a.out")
+
+        self.dbg.DeleteTarget(target)
+
     @skipIfLLVMTargetMissing("AArch64")
     @expectedFailureAll(archs=["aarch64"], oslist=["freebsd"],
                         bugnumber="llvm.org/pr49415")
Index: lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp
===================================================================
--- lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp
+++ lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp
@@ -10,6 +10,7 @@
 #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"
 
 #include "Plugins/Process/elf-core/RegisterUtilities.h"
+#include "lldb/Target/Process.h"
 #include "lldb/Target/Thread.h"
 #include "lldb/Utility/RegisterValue.h"
 
@@ -53,9 +54,24 @@
   if (m_register_info_up->IsSVEEnabled())
     m_sve_data = getRegset(notes, target_triple, AARCH64_SVE_Desc);
 
-  if (m_register_info_up->IsPAuthEnabled())
+  if (m_register_info_up->IsPAuthEnabled()) {
     m_pac_data = getRegset(notes, target_triple, AARCH64_PAC_Desc);
 
+    // At this stage we should be able to guess no of address bits
+    // being used by target configuration when elf-core was generated.
+    // This will either be 48 or 52 bits depending on AArch64 virtual
+    // address size configuration. Following code checks if PAC starts
+    // from 48th or 52nd bit onwards and accordingly sets address bits
+    // in use by the this elf-core process.
+    uint64_t pac_masks[2] = {0, 0};
+    uint64_t pac_test_mask = 1ULL << 48;
+    lldb::offset_t pac_data_offset = 0;
+    if (m_pac_data.GetU64(&pac_data_offset, pac_masks, 2) &&
+        ((pac_masks[0] & pac_test_mask) || (pac_masks[1] & pac_test_mask)))
+      thread.GetProcess()->SetAddressBitsInUse(48);
+    else
+      thread.GetProcess()->SetAddressBitsInUse(52);
+  }
   ConfigureRegisterContext();
 }
 
Index: lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.h
===================================================================
--- lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.h
+++ lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.h
@@ -67,6 +67,8 @@
 
   bool GetPointerReturnRegister(const char *&name) override;
 
+  lldb::addr_t FixCodeAddress(lldb::addr_t pc) override;
+
   // Static Functions
 
   static void Initialize();
Index: lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp
===================================================================
--- lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp
+++ lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp
@@ -33,6 +33,20 @@
 using namespace lldb;
 using namespace lldb_private;
 
+lldb::addr_t ABISysV_arm64::FixCodeAddress(lldb::addr_t pc) {
+  // This function clears top bits of argument pc which are not used for
+  // addressing by current target process. Resulting sign extended
+  // address is returned.
+  uint32_t address_shift_width = GetProcessSP()->GetAddressBitsInUse();
+  if (address_shift_width &&
+      (address_shift_width < (sizeof(lldb::addr_t) * CHAR_BIT))) {
+    lldb::addr_t sign = (lldb::addr_t)1 << (address_shift_width - 1);
+    pc &= ((lldb::addr_t)1 << address_shift_width) - 1;
+    pc = (pc ^ sign) - sign;
+  }
+  return pc;
+}
+
 bool ABISysV_arm64::GetPointerReturnRegister(const char *&name) {
   name = "x0";
   return true;
Index: lldb/include/lldb/Target/Process.h
===================================================================
--- lldb/include/lldb/Target/Process.h
+++ lldb/include/lldb/Target/Process.h
@@ -1328,6 +1328,23 @@
 
   virtual void DidExit() {}
 
+  /// Get number of bits being used by process for addressing.
+  ///
+  /// \return
+  ///     Number of bits out of maximum address bit size used
+  ///     for addressing.
+  uint32_t GetAddressBitsInUse() { return m_address_bits_in_use; }
+
+  /// Set number of bits being used by process for addressing.
+  ///
+  /// \param [in] address_bits_in_use
+  ///     Number of bits out of maximum address bit size used
+  ///     for addressing. Default value is zero meaning all
+  ///     address bits will be used for addressing.
+  void SetAddressBitsInUse(uint32_t address_bits_in_use) {
+    m_address_bits_in_use = address_bits_in_use;
+  }
+
   /// Get the Modification ID of the process.
   ///
   /// \return
@@ -2876,6 +2893,10 @@
   /// from looking up or creating things during or after a finalize call.
   std::atomic<bool> m_finalizing;
 
+  uint32_t m_address_bits_in_use = 0; ///< No of bits in use by address out
+                                      /// of total target address bit width.
+                                      /// or 0 if not set.
+
   bool m_clear_thread_plans_on_stop;
   bool m_force_next_event_delivery;
   lldb::StateType m_last_broadcast_state; /// This helps with the Public event
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to