jasonmolenda created this revision.
jasonmolenda added reviewers: DavidSpickett, JDevlieghere, jingham, omjavaid.
jasonmolenda added a project: LLDB.
Herald added a subscriber: kristof.beyls.
Herald added a project: All.
jasonmolenda requested review of this revision.
Herald added a subscriber: lldb-commits.

The number of bits used for addressing on AArch64 is a bit more complicated 
than we're representing today in lldb.  The same values apply to both EL0 and 
EL1 execution, but the number of bits used in addressing may be different for 
low memory (0x000...) versus high memory (0xfff...) addresses.  The Darwin 
kernel always has the same page table setup for low and high memory, but I'm 
supporting some teams that need to have different settings for each, and 
they're managing to capture a single corefile / JTAG connection capturing the 
virtual addresses for both high and low memory in a single process. Having a 
single number of addressing bits cannot handle this situation today.  
Internally we use the Linux model of code address and data address mask, but 
that also doesn't encompass this concept.

This patch adds a high memory code and data mask, mirroring our existing 
code/data masks.  By default the high memory masks will either be default value 
0, or will have the same mask values.  I'll need three ways of receiving the 
correct address bit numbers:  a setting, an LC_NOTE way to get it from a 
corefile, and a qProcessInfo way of getting it from a gdb-remote connection to 
a JTAG etc device.

To start, I changed `target.process.virtual-addressable-bits` from taking a 
uint to an array of strings (it should be an array of uint's but I wasn't 
getting that to work correctly, I'll play around with it more later).  The 
array can be zero elements (no user override), a single element (used for all 
addresses, like today), or two elements (first number is low memory, second 
number is high memory).  The alternative is to have an additional setting for 
those environments that need to specify a different address mask for high 
memory vrs. low memory.

I also changed `Process::GetDataAddressMask` and `Process::GetCodeAddressMask` 
to have a clear set of precedence for values.  If the user specifies a number 
of addressing bits in that setting, this overrides what the system might tell 
lldb.  The user's specified values do not overwrite/set the Process address 
mask.

Current behavior is that the mask is overwritten by the setting value if the 
mask is unset.  But once the mask is set, the user setting is ignored.  In 
practice this means you can set the setting ONCE in a Process lifetime, and 
then further changes to the setting are ignored.  Made it a little annoying to 
experiment with this environment when I first started working on it. :)

None of this should change behavior on linux, but if folks from the linux world 
have a comment or reaction to this change, I would be interested to hear 
opinions.  I haven't done much testing beyond the one test corefile, and I 
still need to work out how the two values are communicated in corefiles & live 
debug, but those are trivial details on the core idea.

FTR this is the AArch64 TCR_EL1.T0SZ and TCR_EL1.T1SZ.  The values of this 
control register apply to both EL0 and EL1 execution, but the T0SZ value 
applies to the TTBR0_EL1 for low memory addresses and the TCR_EL1.T1SZ applies 
to TTBR1_EL1 for high memory addresses.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D151292

Files:
  lldb/include/lldb/Target/Process.h
  lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp
  lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.h
  lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
  lldb/source/Target/Process.cpp
  lldb/source/Target/TargetProperties.td

Index: lldb/source/Target/TargetProperties.td
===================================================================
--- lldb/source/Target/TargetProperties.td
+++ lldb/source/Target/TargetProperties.td
@@ -252,9 +252,9 @@
   def SteppingRunsAllThreads: Property<"run-all-threads", "Boolean">,
     DefaultFalse,
     Desc<"If true, stepping operations will run all threads.  This is equivalent to setting the run-mode option to 'all-threads'.">;
-  def VirtualAddressableBits: Property<"virtual-addressable-bits", "UInt64">,
-    DefaultUnsignedValue<0>,
-    Desc<"The number of bits used for addressing. If the value is 39, then bits 0..38 are used for addressing. The default value of 0 means unspecified.">;
+  def VirtualAddressableBits: Property<"virtual-addressable-bits", "Array">,
+    ElementType<"String">,
+    Desc<"The number of bits used for addressing. If the value is 39, then bits 0..38 are used for addressing. If two values are provided, the first value is for low memory addresses, the second value for high memory addresses.  This is uncommon.">;
   def FollowForkMode: Property<"follow-fork-mode", "Enum">,
     DefaultEnumValue<"eFollowParent">,
     EnumValues<"OptionEnumValues(g_follow_fork_mode_values)">,
Index: lldb/source/Target/Process.cpp
===================================================================
--- lldb/source/Target/Process.cpp
+++ lldb/source/Target/Process.cpp
@@ -217,15 +217,16 @@
   return GetPropertyAtIndexAs<FileSpec>(idx, {});
 }
 
-uint32_t ProcessProperties::GetVirtualAddressableBits() const {
+Args ProcessProperties::GetVirtualAddressableBits() const {
+  Args args;
   const uint32_t idx = ePropertyVirtualAddressableBits;
-  return GetPropertyAtIndexAs<uint64_t>(
-      idx, g_process_properties[idx].default_uint_value);
+  m_collection_sp->GetPropertyAtIndexAsArgs(idx, args);
+  return args;
 }
 
-void ProcessProperties::SetVirtualAddressableBits(uint32_t bits) {
+void ProcessProperties::SetVirtualAddressableBits(const Args &args) {
   const uint32_t idx = ePropertyVirtualAddressableBits;
-  SetPropertyAtIndex(idx, static_cast<uint64_t>(bits));
+  m_collection_sp->SetPropertyAtIndexFromArgs(idx, args);
 }
 void ProcessProperties::SetPythonOSPluginPath(const FileSpec &file) {
   const uint32_t idx = ePropertyPythonOSPluginPath;
@@ -5651,25 +5652,50 @@
 }
 
 lldb::addr_t Process::GetCodeAddressMask() {
-  if (m_code_address_mask == 0) {
-    if (uint32_t number_of_addressable_bits = GetVirtualAddressableBits()) {
-      lldb::addr_t address_mask = ~((1ULL << number_of_addressable_bits) - 1);
-      SetCodeAddressMask(address_mask);
-    }
-  }
+  Args args = GetVirtualAddressableBits();
+  uint32_t bits;
+  if (args.GetArgumentCount() >= 1)
+    if (llvm::to_integer(args.GetArgumentAtIndex(0), bits, 10))
+      return ~((1ULL << bits) - 1);
+
   return m_code_address_mask;
 }
 
 lldb::addr_t Process::GetDataAddressMask() {
-  if (m_data_address_mask == 0) {
-    if (uint32_t number_of_addressable_bits = GetVirtualAddressableBits()) {
-      lldb::addr_t address_mask = ~((1ULL << number_of_addressable_bits) - 1);
-      SetDataAddressMask(address_mask);
-    }
-  }
+  Args args = GetVirtualAddressableBits();
+  uint32_t bits;
+  if (args.GetArgumentCount() >= 1)
+    if (llvm::to_integer(args.GetArgumentAtIndex(0), bits, 10))
+      return ~((1ULL << bits) - 1);
+
   return m_data_address_mask;
 }
 
+lldb::addr_t Process::GetHighmemCodeAddressMask() {
+  Args args = GetVirtualAddressableBits();
+  size_t count = args.GetArgumentCount();
+  uint32_t bits;
+
+  if (count == 2 && llvm::to_integer(args.GetArgumentAtIndex(1), bits, 10))
+    return ~((1ULL << bits) - 1);
+  if (count == 1 && llvm::to_integer(args.GetArgumentAtIndex(0), bits, 10))
+    return ~((1ULL << bits) - 1);
+
+  return m_highmem_code_address_mask;
+}
+
+lldb::addr_t Process::GetHighmemDataAddressMask() {
+  Args args = GetVirtualAddressableBits();
+  size_t count = args.GetArgumentCount();
+  uint32_t bits;
+  if (count == 2 && llvm::to_integer(args.GetArgumentAtIndex(1), bits, 10))
+    return ~((1ULL << bits) - 1);
+  if (count == 1 && llvm::to_integer(args.GetArgumentAtIndex(0), bits, 10))
+    return ~((1ULL << bits) - 1);
+
+  return m_highmem_data_address_mask;
+}
+
 void Process::DidExec() {
   Log *log = GetLog(LLDBLog::Process);
   LLDB_LOGF(log, "Process::%s()", __FUNCTION__);
Index: lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
===================================================================
--- lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
+++ lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
@@ -1083,12 +1083,11 @@
       symbol = m_kernel.GetModule()->FindFirstSymbolWithNameAndType(
           arm64_T1Sz_value, eSymbolTypeData);
       if (symbol) {
-        const uint32_t orig_bits_value = m_process->GetVirtualAddressableBits();
-        // Mark all bits as addressable so we don't strip any from our
-        // memory read below, with an incorrect default value.
-        // b55 is the sign extension bit with PAC, b56:63 are TBI,
-        // don't mark those as addressable.
-        m_process->SetVirtualAddressableBits(55);
+        const addr_t orig_code_mask = m_process->GetCodeAddressMask();
+        const addr_t orig_data_mask = m_process->GetDataAddressMask();
+
+        m_process->SetCodeAddressMask(0);
+        m_process->SetDataAddressMask(0);
         Status error;
         // gT1Sz is 8 bytes.  We may run on a stripped kernel binary
         // where we can't get the size accurately.  Hardcode it.
@@ -1103,9 +1102,12 @@
           // T1Sz is 25, then 64-25 == 39, bits 0..38 are used for
           // addressing, bits 39..63 are used for PAC/TBI or whatever.
           uint32_t virt_addr_bits = 64 - sym_value;
-          m_process->SetVirtualAddressableBits(virt_addr_bits);
+          addr_t mask = ~((1ULL << virt_addr_bits) - 1);
+          m_process->SetCodeAddressMask(mask);
+          m_process->SetDataAddressMask(mask);
         } else {
-          m_process->SetVirtualAddressableBits(orig_bits_value);
+          m_process->SetCodeAddressMask(orig_code_mask);
+          m_process->SetDataAddressMask(orig_data_mask);
         }
       }
     } else {
Index: lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.h
===================================================================
--- lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.h
+++ lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.h
@@ -62,7 +62,8 @@
     return true;
   }
 
-  lldb::addr_t FixAddress(lldb::addr_t pc, lldb::addr_t mask) override;
+  lldb::addr_t FixCodeAddress(lldb::addr_t pc) override;
+  lldb::addr_t FixDataAddress(lldb::addr_t pc) override;
 
   // Static Functions
 
Index: lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp
===================================================================
--- lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp
+++ lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp
@@ -814,15 +814,41 @@
   return return_valobj_sp;
 }
 
-lldb::addr_t ABIMacOSX_arm64::FixAddress(addr_t pc, addr_t mask) {
-  lldb::addr_t pac_sign_extension = 0x0080000000000000ULL;
-  // When no mask is specified, clear/set the top byte; preserve
-  // the low 55 bits (00..54) for addressing and bit 55 to indicate
-  // sign.
-  if (mask == 0) {
-    // ~((1ULL<<55)-1)
-    mask = 0xff80000000000000;
+addr_t ABIMacOSX_arm64::FixCodeAddress(addr_t pc) {
+  addr_t pac_sign_extension = 0x0080000000000000ULL;
+  addr_t tbi_mask = 0xff80000000000000ULL;
+  addr_t mask = 0;
+
+  if (ProcessSP process_sp = GetProcessSP()) {
+    mask = process_sp->GetCodeAddressMask();
+    if (pc & pac_sign_extension) {
+      addr_t highmem_mask = process_sp->GetHighmemCodeAddressMask();
+      if (highmem_mask)
+        mask = highmem_mask;
+    }
+  }
+  if (mask == 0)
+    mask = tbi_mask;
+
+  return (pc & pac_sign_extension) ? pc | mask : pc & (~mask);
+}
+
+addr_t ABIMacOSX_arm64::FixDataAddress(addr_t pc) {
+  addr_t pac_sign_extension = 0x0080000000000000ULL;
+  addr_t tbi_mask = 0xff80000000000000ULL;
+  addr_t mask = 0;
+
+  if (ProcessSP process_sp = GetProcessSP()) {
+    mask = process_sp->GetDataAddressMask();
+    if (pc & pac_sign_extension) {
+      addr_t highmem_mask = process_sp->GetHighmemDataAddressMask();
+      if (highmem_mask)
+        mask = highmem_mask;
+    }
   }
+  if (mask == 0)
+    mask = tbi_mask;
+
   return (pc & pac_sign_extension) ? pc | mask : pc & (~mask);
 }
 
Index: lldb/include/lldb/Target/Process.h
===================================================================
--- lldb/include/lldb/Target/Process.h
+++ lldb/include/lldb/Target/Process.h
@@ -79,8 +79,8 @@
   Args GetExtraStartupCommands() const;
   void SetExtraStartupCommands(const Args &args);
   FileSpec GetPythonOSPluginPath() const;
-  uint32_t GetVirtualAddressableBits() const;
-  void SetVirtualAddressableBits(uint32_t bits);
+  Args GetVirtualAddressableBits() const;
+  void SetVirtualAddressableBits(const Args &args);
   void SetPythonOSPluginPath(const FileSpec &file);
   bool GetIgnoreBreakpointsInExpressions() const;
   void SetIgnoreBreakpointsInExpressions(bool ignore);
@@ -1371,6 +1371,9 @@
   lldb::addr_t GetCodeAddressMask();
   lldb::addr_t GetDataAddressMask();
 
+  lldb::addr_t GetHighmemCodeAddressMask();
+  lldb::addr_t GetHighmemDataAddressMask();
+
   void SetCodeAddressMask(lldb::addr_t code_address_mask) {
     m_code_address_mask = code_address_mask;
   }
@@ -1379,6 +1382,14 @@
     m_data_address_mask = data_address_mask;
   }
 
+  void SetHighmemCodeAddressMask(lldb::addr_t code_address_mask) {
+    m_highmem_code_address_mask = code_address_mask;
+  }
+
+  void SetHighmemDataAddressMask(lldb::addr_t data_address_mask) {
+    m_highmem_data_address_mask = data_address_mask;
+  }
+
   /// Get the Modification ID of the process.
   ///
   /// \return
@@ -3000,9 +3011,13 @@
   /// Mask for code an data addresses. The default value (0) means no mask is
   /// set.  The bits set to 1 indicate bits that are NOT significant for
   /// addressing.
+  /// The highmem versions are for targets where we may have different masks
+  /// for low memory versus high memory addresses.
   /// @{
   lldb::addr_t m_code_address_mask = 0;
   lldb::addr_t m_data_address_mask = 0;
+  lldb::addr_t m_highmem_code_address_mask = 0;
+  lldb::addr_t m_highmem_data_address_mask = 0;
   /// @}
 
   bool m_clear_thread_plans_on_stop;
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to