[Lldb-commits] [lldb] [lldb] Add SBProcess methods for get/set/use address masks (PR #83095)

Jason Molenda via lldb-commits lldb-commits at lists.llvm.org
Thu Feb 29 14:42:06 PST 2024


https://github.com/jasonmolenda updated https://github.com/llvm/llvm-project/pull/83095

>From dae16776e8c97158e8965e4d0e950cd2ce836f75 Mon Sep 17 00:00:00 2001
From: Jason Molenda <jason at molenda.com>
Date: Mon, 26 Feb 2024 18:05:27 -0800
Subject: [PATCH 1/7] [lldb] Add SBProcess methods for get/set/use address
 masks

I'm reviving a patch from phabracator, https://reviews.llvm.org/D155905
which was approved but I wasn't thrilled with all the API I was
adding to SBProcess for all of the address mask types / memory
regions. In this update, I added enums to control type address mask
type (code, data, any) and address space specifiers (low, high,
all) with defaulted arguments for the most common case.

This patch is also fixing a bug in the "addressable bits to address
mask" calculation I added in AddressableBits::SetProcessMasks.
If lldb were told that 64 bits are valid for addressing, this method
would overflow the calculation and set an invalid mask.  Added tests
to check this specific bug while I was adding these APIs.

rdar://123530562
---
 lldb/include/lldb/API/SBProcess.h             | 123 ++++++++++++++++++
 lldb/include/lldb/Utility/AddressableBits.h   |   3 +
 lldb/include/lldb/lldb-enumerations.h         |  14 ++
 lldb/source/API/SBProcess.cpp                 |  89 +++++++++++++
 lldb/source/Utility/AddressableBits.cpp       |  12 +-
 .../python_api/process/address-masks/Makefile |   3 +
 .../process/address-masks/TestAddressMasks.py |  64 +++++++++
 .../python_api/process/address-masks/main.c   |   5 +
 8 files changed, 311 insertions(+), 2 deletions(-)
 create mode 100644 lldb/test/API/python_api/process/address-masks/Makefile
 create mode 100644 lldb/test/API/python_api/process/address-masks/TestAddressMasks.py
 create mode 100644 lldb/test/API/python_api/process/address-masks/main.c

diff --git a/lldb/include/lldb/API/SBProcess.h b/lldb/include/lldb/API/SBProcess.h
index 4f92a41f3028a2..7e9ad7d9a274f2 100644
--- a/lldb/include/lldb/API/SBProcess.h
+++ b/lldb/include/lldb/API/SBProcess.h
@@ -407,6 +407,129 @@ class LLDB_API SBProcess {
   ///     the process isn't loaded from a core file.
   lldb::SBFileSpec GetCoreFile();
 
+  /// Get the current address mask that can be applied to addresses
+  /// before reading from memory.
+  ///
+  /// \param[in] type
+  ///     lldb may have different address masks for code and data
+  ///     addresses.  Either can be requested, or most commonly,
+  ///     eAddressMaskTypeAny can be requested and the least specific
+  ///     mask will be fetched.  e.g. on a target where instructions
+  ///     are word aligned, the Code mask might clear the low 2 bits.
+  ///
+  /// \param[in] addr_range
+  ///     Specify whether the address mask for high or low address spaces
+  ///     is requested.
+  ///     It is highly unusual to have different address masks in high
+  ///     or low memory, and by default the eAddressMaskRangeLow is the
+  ///     only one used for both types of addresses, the default value for
+  ///     this argument is the correct one.
+  ///
+  ///     On some architectures like AArch64, it is possible to have
+  ///     different page table setups for low and high memory, so different
+  ///     numbers of bits relevant to addressing, and it is possible to have
+  ///     a program running in one half of memory and accessing the other
+  ///     as heap, etc.  In that case the eAddressMaskRangeLow and
+  ///     eAddressMaskRangeHigh will have different masks that must be handled.
+  ///
+  /// \return
+  ///     The address mask currently in use.  Bits which are not used
+  ///     for addressing will be set to 1 in the mask.
+  lldb::addr_t GetAddressMask(
+      lldb::AddressMaskType type,
+      lldb::AddressMaskRange addr_range = lldb::eAddressMaskRangeLow);
+
+  /// Set the current address mask that can be applied to addresses
+  /// before reading from memory.
+  ///
+  /// \param[in] type
+  ///     lldb may have different address masks for code and data
+  ///     addresses.  Either can be set, or most commonly,
+  ///     eAddressMaskTypeAll can be set for both types of addresses.
+  ///     An example where they could be different is a target where
+  ///     instructions are word aligned, so the low 2 bits are always
+  ///     zero.
+  ///
+  /// \param[in] mask
+  ///     The address mask to set.  Bits which are not used for addressing
+  ///     should be set to 1 in the mask.
+  ///
+  /// \param[in] addr_range
+  ///     Specify whether the address mask for high or low address spaces
+  ///     is being set.
+  ///     It is highly unusual to have different address masks in high
+  ///     or low memory, and by default the eAddressMaskRangeLow is the
+  ///     only one used for both types of addresses, the default value for
+  ///     this argument is the correct one.
+  ///
+  ///     On some architectures like AArch64, it is possible to have
+  ///     different page table setups for low and high memory, so different
+  ///     numbers of bits relevant to addressing, and it is possible to have
+  ///     a program running in one half of memory and accessing the other
+  ///     as heap, etc.  In that case the eAddressMaskRangeLow and
+  ///     eAddressMaskRangeHigh will have different masks that must be
+  ///     specified.
+  void SetAddressMask(
+      lldb::AddressMaskType type, lldb::addr_t mask,
+      lldb::AddressMaskRange addr_range = lldb::eAddressMaskRangeLow);
+
+  /// Set the number of bits used for addressing in this Process.
+  ///
+  /// In some environments, the number of bits that are used for addressing
+  /// is the natural representation insted of a mask; this method calculates
+  /// the addressing mask that lldb uses internally from that number.
+  ///
+  /// \param[in] type
+  ///     lldb may have different address masks for code and data
+  ///     addresses.  Either can be set, or most commonly,
+  ///     eAddressMaskTypeAll can be set for both types of addresses.
+  ///     An example where they could be different is a target where
+  ///     instructions are word aligned, so the low 2 bits are always
+  ///     zero.
+  ///
+  /// \param[in] num_bits
+  ///     Number of bits that are used for addressing.  e.g. the low 42
+  ///     bits may be the only ones used for addressing, and high bits may
+  ///     store metadata and should be ignored by lldb.
+  ///
+  /// \param[in] addr_range
+  ///     Specify whether the address mask for high or low address spaces
+  ///     is being set.
+  ///     It is highly unusual to have different address masks in high
+  ///     or low memory, and by default the eAddressMaskRangeLow is the
+  ///     only one used for both types of addresses, the default value for
+  ///     this argument is the correct one.
+  ///
+  ///     On some architectures like AArch64, it is possible to have
+  ///     different page table setups for low and high memory, so different
+  ///     numbers of bits relevant to addressing, and it is possible to have
+  ///     a program running in one half of memory and accessing the other
+  ///     as heap, etc.  In that case the eAddressMaskRangeLow and
+  ///     eAddressMaskRangeHigh will have different masks that must be
+  ///     specified.
+  void
+  SetAddressableBits(AddressMaskType type, uint32_t num_bits,
+                     AddressMaskRange addr_range = lldb::eAddressMaskRangeLow);
+
+  /// Clear the non-addressable bits of an \a addr value and return a
+  /// virtual address in memory.
+  ///
+  /// Bits that are not used in addressing may be used for other purposes;
+  /// pointer authentication, or metadata in the top byte, or the 0th bit
+  /// of armv7 code addresses to indicate arm/thumb are common examples.
+  ///
+  /// \param[in] addr
+  ///     The address that should be cleared of non-addressable bits.
+  ///
+  /// \param[in] type
+  ///     If the address is known to be a code address (address of a function,
+  ///     for example), eAddressMaskTypeCode may be passed, which may have
+  ///     stricter address clearing than data addresses e.g. the low 2 bits
+  ///     being unused for code addresses on AArch64.
+  lldb::addr_t
+  FixAddress(lldb::addr_t addr,
+             lldb::AddressMaskType type = lldb::eAddressMaskTypeAny);
+
   /// Allocate memory within the process.
   ///
   /// This function will allocate memory in the process's address space.
diff --git a/lldb/include/lldb/Utility/AddressableBits.h b/lldb/include/lldb/Utility/AddressableBits.h
index 13c21329a8c617..75752fcf840a44 100644
--- a/lldb/include/lldb/Utility/AddressableBits.h
+++ b/lldb/include/lldb/Utility/AddressableBits.h
@@ -10,6 +10,7 @@
 #define LLDB_UTILITY_ADDRESSABLEBITS_H
 
 #include "lldb/lldb-forward.h"
+#include "lldb/lldb-public.h"
 
 namespace lldb_private {
 
@@ -33,6 +34,8 @@ class AddressableBits {
 
   void SetHighmemAddressableBits(uint32_t highmem_addressing_bits);
 
+  static lldb::addr_t AddressableBitToMask(uint32_t addressable_bits);
+
   void SetProcessMasks(lldb_private::Process &process);
 
 private:
diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h
index 85769071dae785..853370bf5eb515 100644
--- a/lldb/include/lldb/lldb-enumerations.h
+++ b/lldb/include/lldb/lldb-enumerations.h
@@ -1323,6 +1323,20 @@ enum SymbolDownload {
   eSymbolDownloadForeground = 2,
 };
 
+enum AddressMaskType {
+  eAddressMaskTypeCode = 0,
+  eAddressMaskTypeData,
+  eAddressMaskTypeAny,
+  eAddressMaskTypeAll = eAddressMaskTypeAny
+};
+
+enum AddressMaskRange {
+  eAddressMaskRangeLow = 0,
+  eAddressMaskRangeHigh,
+  eAddressMaskRangeAny,
+  eAddressMaskRangeAll = eAddressMaskRangeAny,
+};
+
 } // namespace lldb
 
 #endif // LLDB_LLDB_ENUMERATIONS_H
diff --git a/lldb/source/API/SBProcess.cpp b/lldb/source/API/SBProcess.cpp
index a9fe915324683e..7edaa6b84fd7d7 100644
--- a/lldb/source/API/SBProcess.cpp
+++ b/lldb/source/API/SBProcess.cpp
@@ -1255,6 +1255,95 @@ lldb::SBFileSpec SBProcess::GetCoreFile() {
   return SBFileSpec(core_file);
 }
 
+addr_t SBProcess::GetAddressMask(AddressMaskType type,
+                                 AddressMaskRange addr_range) {
+  LLDB_INSTRUMENT_VA(this, type, addr_range);
+  addr_t default_mask = 0;
+  if (ProcessSP process_sp = GetSP()) {
+    switch (type) {
+    case eAddressMaskTypeCode:
+      if (addr_range == eAddressMaskRangeHigh)
+        return process_sp->GetHighmemCodeAddressMask();
+      else
+        return process_sp->GetCodeAddressMask();
+    case eAddressMaskTypeData:
+      if (addr_range == eAddressMaskRangeHigh)
+        return process_sp->GetHighmemDataAddressMask();
+      else
+        return process_sp->GetDataAddressMask();
+    case eAddressMaskTypeAny:
+      if (addr_range == eAddressMaskRangeHigh)
+        return process_sp->GetHighmemDataAddressMask();
+      else
+        return process_sp->GetDataAddressMask();
+    }
+  }
+  return default_mask;
+}
+
+void SBProcess::SetAddressMask(AddressMaskType type, addr_t mask,
+                               AddressMaskRange addr_range) {
+  LLDB_INSTRUMENT_VA(this, type, mask, addr_range);
+  if (ProcessSP process_sp = GetSP()) {
+    switch (type) {
+    case eAddressMaskTypeCode:
+      if (addr_range == eAddressMaskRangeAll) {
+        process_sp->SetCodeAddressMask(mask);
+        process_sp->SetHighmemCodeAddressMask(mask);
+      } else if (addr_range == eAddressMaskRangeHigh) {
+        process_sp->SetHighmemCodeAddressMask(mask);
+      } else {
+        process_sp->SetCodeAddressMask(mask);
+      }
+      break;
+    case eAddressMaskTypeData:
+      if (addr_range == eAddressMaskRangeAll) {
+        process_sp->SetDataAddressMask(mask);
+        process_sp->SetHighmemDataAddressMask(mask);
+      } else if (addr_range == eAddressMaskRangeHigh) {
+        process_sp->SetHighmemDataAddressMask(mask);
+      } else {
+        process_sp->SetDataAddressMask(mask);
+      }
+      break;
+    case eAddressMaskTypeAll:
+      if (addr_range == eAddressMaskRangeAll) {
+        process_sp->SetCodeAddressMask(mask);
+        process_sp->SetDataAddressMask(mask);
+        process_sp->SetHighmemCodeAddressMask(mask);
+        process_sp->SetHighmemDataAddressMask(mask);
+      } else if (addr_range == eAddressMaskRangeHigh) {
+        process_sp->SetHighmemCodeAddressMask(mask);
+        process_sp->SetHighmemDataAddressMask(mask);
+      } else {
+        process_sp->SetCodeAddressMask(mask);
+        process_sp->SetDataAddressMask(mask);
+      }
+      break;
+    }
+  }
+}
+
+void SBProcess::SetAddressableBits(AddressMaskType type, uint32_t num_bits,
+                                   AddressMaskRange addr_range) {
+  LLDB_INSTRUMENT_VA(this, type, num_bits, addr_range);
+  SetAddressMask(type, AddressableBits::AddressableBitToMask(num_bits),
+                 addr_range);
+}
+
+addr_t SBProcess::FixAddress(addr_t addr, AddressMaskType type) {
+  LLDB_INSTRUMENT_VA(this, addr, type);
+  if (ProcessSP process_sp = GetSP()) {
+    if (type == eAddressMaskTypeAny)
+      return process_sp->FixAnyAddress(addr);
+    else if (type == eAddressMaskTypeData)
+      return process_sp->FixDataAddress(addr);
+    else if (type == eAddressMaskTypeCode)
+      return process_sp->FixCodeAddress(addr);
+  }
+  return addr;
+}
+
 lldb::addr_t SBProcess::AllocateMemory(size_t size, uint32_t permissions,
                                        lldb::SBError &sb_error) {
   LLDB_INSTRUMENT_VA(this, size, permissions, sb_error);
diff --git a/lldb/source/Utility/AddressableBits.cpp b/lldb/source/Utility/AddressableBits.cpp
index c6e25f608da73d..7f9d7ec6c1349c 100644
--- a/lldb/source/Utility/AddressableBits.cpp
+++ b/lldb/source/Utility/AddressableBits.cpp
@@ -33,18 +33,26 @@ void AddressableBits::SetHighmemAddressableBits(
   m_high_memory_addr_bits = highmem_addressing_bits;
 }
 
+addr_t AddressableBits::AddressableBitToMask(uint32_t addressable_bits) {
+  assert(addressable_bits <= sizeof(addr_t) * 8);
+  if (addressable_bits == 64)
+    return 0; // all bits used for addressing
+  else
+    return ~((1ULL << addressable_bits) - 1);
+}
+
 void AddressableBits::SetProcessMasks(Process &process) {
   if (m_low_memory_addr_bits == 0 && m_high_memory_addr_bits == 0)
     return;
 
   if (m_low_memory_addr_bits != 0) {
-    addr_t low_addr_mask = ~((1ULL << m_low_memory_addr_bits) - 1);
+    addr_t low_addr_mask = AddressableBitToMask(m_low_memory_addr_bits);
     process.SetCodeAddressMask(low_addr_mask);
     process.SetDataAddressMask(low_addr_mask);
   }
 
   if (m_high_memory_addr_bits != 0) {
-    addr_t hi_addr_mask = ~((1ULL << m_high_memory_addr_bits) - 1);
+    addr_t hi_addr_mask = AddressableBitToMask(m_high_memory_addr_bits);
     process.SetHighmemCodeAddressMask(hi_addr_mask);
     process.SetHighmemDataAddressMask(hi_addr_mask);
   }
diff --git a/lldb/test/API/python_api/process/address-masks/Makefile b/lldb/test/API/python_api/process/address-masks/Makefile
new file mode 100644
index 00000000000000..10495940055b63
--- /dev/null
+++ b/lldb/test/API/python_api/process/address-masks/Makefile
@@ -0,0 +1,3 @@
+C_SOURCES := main.c
+
+include Makefile.rules
diff --git a/lldb/test/API/python_api/process/address-masks/TestAddressMasks.py b/lldb/test/API/python_api/process/address-masks/TestAddressMasks.py
new file mode 100644
index 00000000000000..4a6a737e94f9d9
--- /dev/null
+++ b/lldb/test/API/python_api/process/address-masks/TestAddressMasks.py
@@ -0,0 +1,64 @@
+"""Test Python APIs for setting, getting, and using address masks."""
+
+import os
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class AddressMasksTestCase(TestBase):
+    NO_DEBUG_INFO_TESTCASE = True
+
+    def test_address_masks(self):
+        self.build()
+        (target, process, t, bp) = lldbutil.run_to_source_breakpoint(
+            self, "break here", lldb.SBFileSpec("main.c")
+        )
+
+        process.SetAddressableBits(lldb.eAddressMaskTypeAll, 42)
+        self.assertEqual(0x0000029500003F94, process.FixAddress(0x00265E9500003F94))
+
+        # ~((1ULL<<42)-1) == 0xfffffc0000000000
+        process.SetAddressMask(lldb.eAddressMaskTypeAll, 0xFFFFFC0000000000)
+        self.assertEqual(0x0000029500003F94, process.FixAddress(0x00265E9500003F94))
+
+        # Check that all bits can pass through unmodified
+        process.SetAddressableBits(lldb.eAddressMaskTypeAll, 64)
+        self.assertEqual(0x00265E9500003F94, process.FixAddress(0x00265E9500003F94))
+
+        process.SetAddressableBits(
+            lldb.eAddressMaskTypeAll, 42, lldb.eAddressMaskRangeLow
+        )
+        process.SetAddressableBits(
+            lldb.eAddressMaskTypeAll, 15, lldb.eAddressMaskRangeHigh
+        )
+        self.assertEqual(0x000002950001F694, process.FixAddress(0x00265E950001F694))
+        self.assertEqual(0xFFFFFFFFFFFFF694, process.FixAddress(0xFFA65E950000F694))
+
+        process.SetAddressableBits(
+            lldb.eAddressMaskTypeAll, 42, lldb.eAddressMaskRangeAll
+        )
+        self.assertEqual(0x000002950001F694, process.FixAddress(0x00265E950001F694))
+        self.assertEqual(0xFFFFFE950000F694, process.FixAddress(0xFFA65E950000F694))
+
+        process.SetAddressMask(lldb.eAddressMaskTypeCode, 0xFFFFFC0000000003)
+        self.assertEqual(0x000002950001F697, process.FixAddress(0x00265E950001F697))
+        self.assertEqual(0xFFFFFE950000F697, process.FixAddress(0xFFA65E950000F697))
+        self.assertEqual(
+            0x000002950001F697,
+            process.FixAddress(0x00265E950001F697, lldb.eAddressMaskTypeData),
+        )
+        self.assertEqual(
+            0x000002950001F694,
+            process.FixAddress(0x00265E950001F697, lldb.eAddressMaskTypeCode),
+        )
+
+        # The user can override whatever settings the Process thinks should be used.
+        process.SetAddressableBits(
+            lldb.eAddressMaskTypeAll, 42, lldb.eAddressMaskRangeAll
+        )
+        self.runCmd("settings set target.process.virtual-addressable-bits 15")
+        self.runCmd("settings set target.process.highmem-virtual-addressable-bits 15")
+        self.assertEqual(0x0000000000007694, process.FixAddress(0x00265E950001F694))
+        self.assertEqual(0xFFFFFFFFFFFFF694, process.FixAddress(0xFFA65E950000F694))
diff --git a/lldb/test/API/python_api/process/address-masks/main.c b/lldb/test/API/python_api/process/address-masks/main.c
new file mode 100644
index 00000000000000..f21a10a16d5a75
--- /dev/null
+++ b/lldb/test/API/python_api/process/address-masks/main.c
@@ -0,0 +1,5 @@
+#include <stdio.h>
+
+int main(int argc, char const *argv[]) {
+  puts("Hello address masking world"); // break here
+}

>From 20653227a94330648e7f1016fc5f278e4e2eb27f Mon Sep 17 00:00:00 2001
From: Jason Molenda <jmolenda at apple.com>
Date: Tue, 27 Feb 2024 15:36:53 -0800
Subject: [PATCH 2/7] Doxygen group these methods in SBProcess.h, add longer
 form definitions for the `type` and `addr_range` arguments that are used by
 all of them, and refer back to those longer descriptions in each individual
 message.

Fix the descriptions as suggested by David and Will.
---
 lldb/include/lldb/API/SBProcess.h     | 124 ++++++++++++--------------
 lldb/include/lldb/lldb-enumerations.h |   2 +
 2 files changed, 58 insertions(+), 68 deletions(-)

diff --git a/lldb/include/lldb/API/SBProcess.h b/lldb/include/lldb/API/SBProcess.h
index 7e9ad7d9a274f2..2ef26502193400 100644
--- a/lldb/include/lldb/API/SBProcess.h
+++ b/lldb/include/lldb/API/SBProcess.h
@@ -407,30 +407,44 @@ class LLDB_API SBProcess {
   ///     the process isn't loaded from a core file.
   lldb::SBFileSpec GetCoreFile();
 
-  /// Get the current address mask that can be applied to addresses
+  /// \{
+  /// \group Mask Address Methods
+  ///
+  /// \a type
+  /// All of the methods in this group take \a type argument
+  /// which is an AddressMaskType enum value.
+  /// There can be different address masks for code addresses and
+  /// data addresses, this argument can select which to get/set,
+  /// or to use when clearing non-addressable bits from an address.
+  /// On AArch32 code with arm+thumb code, where instructions start
+  /// on even addresses, the 0th bit may be used to indicate that
+  /// a function is thumb code.  On such a target, the eAddressMaskTypeCode
+  /// may clear the 0th bit from an address to get the actual address.
+  ///
+  /// \a addr_range
+  /// Many of the methods in this group take an \a addr_range argument
+  /// which is an AddressMaskRange enum value.
+  /// Needing to specify the address range is highly unusual, and the
+  /// default argument can be used in nearly all circumstances.
+  /// On some architectures like AArch64, it is possible to have
+  /// different page table setups for low and high memory, so different
+  /// numbers of bits relevant to addressing. It is possible to have
+  /// a program running in one half of memory and accessing the other
+  /// as heap, so we need to maintain two different sets of address masks
+  /// to debug this correctly.
+
+  /// Get the current address mask that will be applied to addresses
   /// before reading from memory.
   ///
   /// \param[in] type
-  ///     lldb may have different address masks for code and data
-  ///     addresses.  Either can be requested, or most commonly,
-  ///     eAddressMaskTypeAny can be requested and the least specific
-  ///     mask will be fetched.  e.g. on a target where instructions
-  ///     are word aligned, the Code mask might clear the low 2 bits.
+  ///     See \ref Mask Address Methods descripton of this argument.
+  ///     eAddressMaskTypeAny is often a suitable value when code and
+  ///     data masks are the same on a given target.
   ///
   /// \param[in] addr_range
-  ///     Specify whether the address mask for high or low address spaces
-  ///     is requested.
-  ///     It is highly unusual to have different address masks in high
-  ///     or low memory, and by default the eAddressMaskRangeLow is the
-  ///     only one used for both types of addresses, the default value for
-  ///     this argument is the correct one.
-  ///
-  ///     On some architectures like AArch64, it is possible to have
-  ///     different page table setups for low and high memory, so different
-  ///     numbers of bits relevant to addressing, and it is possible to have
-  ///     a program running in one half of memory and accessing the other
-  ///     as heap, etc.  In that case the eAddressMaskRangeLow and
-  ///     eAddressMaskRangeHigh will have different masks that must be handled.
+  ///     See \ref Mask Address Methods descripton of this argument.
+  ///     This will default to eAddressMaskRangeLow which is the
+  ///     only set of masks used normally.
   ///
   /// \return
   ///     The address mask currently in use.  Bits which are not used
@@ -443,32 +457,18 @@ class LLDB_API SBProcess {
   /// before reading from memory.
   ///
   /// \param[in] type
-  ///     lldb may have different address masks for code and data
-  ///     addresses.  Either can be set, or most commonly,
-  ///     eAddressMaskTypeAll can be set for both types of addresses.
-  ///     An example where they could be different is a target where
-  ///     instructions are word aligned, so the low 2 bits are always
-  ///     zero.
+  ///     See \ref Mask Address Methods descripton of this argument.
+  ///     eAddressMaskTypeAll is often a suitable value when the
+  ///     same mask is being set for both code and data.
   ///
   /// \param[in] mask
   ///     The address mask to set.  Bits which are not used for addressing
   ///     should be set to 1 in the mask.
   ///
   /// \param[in] addr_range
-  ///     Specify whether the address mask for high or low address spaces
-  ///     is being set.
-  ///     It is highly unusual to have different address masks in high
-  ///     or low memory, and by default the eAddressMaskRangeLow is the
-  ///     only one used for both types of addresses, the default value for
-  ///     this argument is the correct one.
-  ///
-  ///     On some architectures like AArch64, it is possible to have
-  ///     different page table setups for low and high memory, so different
-  ///     numbers of bits relevant to addressing, and it is possible to have
-  ///     a program running in one half of memory and accessing the other
-  ///     as heap, etc.  In that case the eAddressMaskRangeLow and
-  ///     eAddressMaskRangeHigh will have different masks that must be
-  ///     specified.
+  ///     See \ref Mask Address Methods descripton of this argument.
+  ///     This will default to eAddressMaskRangeLow which is the
+  ///     only set of masks used normally.
   void SetAddressMask(
       lldb::AddressMaskType type, lldb::addr_t mask,
       lldb::AddressMaskRange addr_range = lldb::eAddressMaskRangeLow);
@@ -476,37 +476,25 @@ class LLDB_API SBProcess {
   /// Set the number of bits used for addressing in this Process.
   ///
   /// In some environments, the number of bits that are used for addressing
-  /// is the natural representation insted of a mask; this method calculates
-  /// the addressing mask that lldb uses internally from that number.
+  /// is the natural representation instead of a mask, but lldb
+  /// internally represents this as a mask.  This method calculates
+  /// the addressing mask that lldb uses that number of addressable bits.
   ///
   /// \param[in] type
-  ///     lldb may have different address masks for code and data
-  ///     addresses.  Either can be set, or most commonly,
-  ///     eAddressMaskTypeAll can be set for both types of addresses.
-  ///     An example where they could be different is a target where
-  ///     instructions are word aligned, so the low 2 bits are always
-  ///     zero.
+  ///     See \ref Mask Address Methods descripton of this argument.
+  ///     eAddressMaskTypeAll is often a suitable value when the
+  ///     same mask is being set for both code and data.
   ///
   /// \param[in] num_bits
-  ///     Number of bits that are used for addressing.  e.g. the low 42
-  ///     bits may be the only ones used for addressing, and high bits may
-  ///     store metadata and should be ignored by lldb.
+  ///     Number of bits that are used for addressing.
+  ///     A value of 42 indicates that the low 42 bits are relevant for
+  ///     addressing, and that higher order bits may be used for various
+  ///     metadata like pointer authentication, Type Byte Ignore, etc.
   ///
   /// \param[in] addr_range
-  ///     Specify whether the address mask for high or low address spaces
-  ///     is being set.
-  ///     It is highly unusual to have different address masks in high
-  ///     or low memory, and by default the eAddressMaskRangeLow is the
-  ///     only one used for both types of addresses, the default value for
-  ///     this argument is the correct one.
-  ///
-  ///     On some architectures like AArch64, it is possible to have
-  ///     different page table setups for low and high memory, so different
-  ///     numbers of bits relevant to addressing, and it is possible to have
-  ///     a program running in one half of memory and accessing the other
-  ///     as heap, etc.  In that case the eAddressMaskRangeLow and
-  ///     eAddressMaskRangeHigh will have different masks that must be
-  ///     specified.
+  ///     See \ref Mask Address Methods descripton of this argument.
+  ///     This will default to eAddressMaskRangeLow which is the
+  ///     only set of masks used normally.
   void
   SetAddressableBits(AddressMaskType type, uint32_t num_bits,
                      AddressMaskRange addr_range = lldb::eAddressMaskRangeLow);
@@ -522,13 +510,13 @@ class LLDB_API SBProcess {
   ///     The address that should be cleared of non-addressable bits.
   ///
   /// \param[in] type
-  ///     If the address is known to be a code address (address of a function,
-  ///     for example), eAddressMaskTypeCode may be passed, which may have
-  ///     stricter address clearing than data addresses e.g. the low 2 bits
-  ///     being unused for code addresses on AArch64.
+  ///     See \ref Mask Address Methods descripton of this argument.
+  ///     eAddressMaskTypeAny is the default value, correct when it
+  ///     is unknown if the address is a code or data address.
   lldb::addr_t
   FixAddress(lldb::addr_t addr,
              lldb::AddressMaskType type = lldb::eAddressMaskTypeAny);
+  /// \}
 
   /// Allocate memory within the process.
   ///
diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h
index 853370bf5eb515..646f7bfda98475 100644
--- a/lldb/include/lldb/lldb-enumerations.h
+++ b/lldb/include/lldb/lldb-enumerations.h
@@ -1323,6 +1323,7 @@ enum SymbolDownload {
   eSymbolDownloadForeground = 2,
 };
 
+/// Used in the SBProcess AddressMask/FixAddress methods.
 enum AddressMaskType {
   eAddressMaskTypeCode = 0,
   eAddressMaskTypeData,
@@ -1330,6 +1331,7 @@ enum AddressMaskType {
   eAddressMaskTypeAll = eAddressMaskTypeAny
 };
 
+/// Used in the SBProcess AddressMask/FixAddress methods.
 enum AddressMaskRange {
   eAddressMaskRangeLow = 0,
   eAddressMaskRangeHigh,

>From dbed95d5af61e8156c161f8880517daa8a5c3ead Mon Sep 17 00:00:00 2001
From: Jason Molenda <jmolenda at apple.com>
Date: Wed, 28 Feb 2024 16:35:52 -0800
Subject: [PATCH 3/7] Fix typeos spotted by Will, update SetAddressableBits doc

---
 lldb/include/lldb/API/SBProcess.h | 23 ++++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)

diff --git a/lldb/include/lldb/API/SBProcess.h b/lldb/include/lldb/API/SBProcess.h
index 2ef26502193400..13b69508112a8c 100644
--- a/lldb/include/lldb/API/SBProcess.h
+++ b/lldb/include/lldb/API/SBProcess.h
@@ -437,12 +437,12 @@ class LLDB_API SBProcess {
   /// before reading from memory.
   ///
   /// \param[in] type
-  ///     See \ref Mask Address Methods descripton of this argument.
+  ///     See \ref Mask Address Methods description of this argument.
   ///     eAddressMaskTypeAny is often a suitable value when code and
   ///     data masks are the same on a given target.
   ///
   /// \param[in] addr_range
-  ///     See \ref Mask Address Methods descripton of this argument.
+  ///     See \ref Mask Address Methods description of this argument.
   ///     This will default to eAddressMaskRangeLow which is the
   ///     only set of masks used normally.
   ///
@@ -457,7 +457,7 @@ class LLDB_API SBProcess {
   /// before reading from memory.
   ///
   /// \param[in] type
-  ///     See \ref Mask Address Methods descripton of this argument.
+  ///     See \ref Mask Address Methods description of this argument.
   ///     eAddressMaskTypeAll is often a suitable value when the
   ///     same mask is being set for both code and data.
   ///
@@ -466,7 +466,7 @@ class LLDB_API SBProcess {
   ///     should be set to 1 in the mask.
   ///
   /// \param[in] addr_range
-  ///     See \ref Mask Address Methods descripton of this argument.
+  ///     See \ref Mask Address Methods description of this argument.
   ///     This will default to eAddressMaskRangeLow which is the
   ///     only set of masks used normally.
   void SetAddressMask(
@@ -475,13 +475,14 @@ class LLDB_API SBProcess {
 
   /// Set the number of bits used for addressing in this Process.
   ///
-  /// In some environments, the number of bits that are used for addressing
-  /// is the natural representation instead of a mask, but lldb
-  /// internally represents this as a mask.  This method calculates
-  /// the addressing mask that lldb uses that number of addressable bits.
+  /// On Darwin and similar systems, the addressable bits are expressed
+  /// as the number of low order bits that are relevant to addressing,
+  /// instead of a more general address mask.
+  /// This method calculates the correct mask value for a given number
+  /// of low order addressable bits.
   ///
   /// \param[in] type
-  ///     See \ref Mask Address Methods descripton of this argument.
+  ///     See \ref Mask Address Methods description of this argument.
   ///     eAddressMaskTypeAll is often a suitable value when the
   ///     same mask is being set for both code and data.
   ///
@@ -492,7 +493,7 @@ class LLDB_API SBProcess {
   ///     metadata like pointer authentication, Type Byte Ignore, etc.
   ///
   /// \param[in] addr_range
-  ///     See \ref Mask Address Methods descripton of this argument.
+  ///     See \ref Mask Address Methods description of this argument.
   ///     This will default to eAddressMaskRangeLow which is the
   ///     only set of masks used normally.
   void
@@ -510,7 +511,7 @@ class LLDB_API SBProcess {
   ///     The address that should be cleared of non-addressable bits.
   ///
   /// \param[in] type
-  ///     See \ref Mask Address Methods descripton of this argument.
+  ///     See \ref Mask Address Methods description of this argument.
   ///     eAddressMaskTypeAny is the default value, correct when it
   ///     is unknown if the address is a code or data address.
   lldb::addr_t

>From dceaef27675b724309f353aa22999563cf036cd3 Mon Sep 17 00:00:00 2001
From: Jason Molenda <github-mail at molenda.com>
Date: Thu, 29 Feb 2024 14:04:56 -0800
Subject: [PATCH 4/7] Apply suggestions from code review

Add Will's good copyedit suggestions.

Co-authored-by: Will Hawkins <whh8b at obs.cr>
---
 lldb/include/lldb/API/SBProcess.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/lldb/include/lldb/API/SBProcess.h b/lldb/include/lldb/API/SBProcess.h
index 13b69508112a8c..e2a6922724f005 100644
--- a/lldb/include/lldb/API/SBProcess.h
+++ b/lldb/include/lldb/API/SBProcess.h
@@ -426,7 +426,7 @@ class LLDB_API SBProcess {
   /// which is an AddressMaskRange enum value.
   /// Needing to specify the address range is highly unusual, and the
   /// default argument can be used in nearly all circumstances.
-  /// On some architectures like AArch64, it is possible to have
+  /// On some architectures (e.g., AArch64), it is possible to have
   /// different page table setups for low and high memory, so different
   /// numbers of bits relevant to addressing. It is possible to have
   /// a program running in one half of memory and accessing the other
@@ -488,8 +488,8 @@ class LLDB_API SBProcess {
   ///
   /// \param[in] num_bits
   ///     Number of bits that are used for addressing.
-  ///     A value of 42 indicates that the low 42 bits are relevant for
-  ///     addressing, and that higher order bits may be used for various
+  ///     For example, a value of 42 indicates that the low 42 bits are relevant for
+  ///     addressing, and that higher-order bits may be used for various
   ///     metadata like pointer authentication, Type Byte Ignore, etc.
   ///
   /// \param[in] addr_range

>From 586cd9153791343bf196ef3d91b467db7f5a475b Mon Sep 17 00:00:00 2001
From: Jason Molenda <jmolenda at apple.com>
Date: Thu, 29 Feb 2024 14:07:14 -0800
Subject: [PATCH 5/7] Address Jonas' suggestions, add LLDB_INVALID_ADDRESS_MASK

Have SBProcess::GetAddressMask return LLDB_INVALID_ADDRESS_MASK if
no mask can be retrieved.
---
 lldb/include/lldb/lldb-defines.h | 3 +++
 lldb/source/API/SBProcess.cpp    | 7 +++++--
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/lldb/include/lldb/lldb-defines.h b/lldb/include/lldb/lldb-defines.h
index 469be92eabecf3..dffd6f3d05e39a 100644
--- a/lldb/include/lldb/lldb-defines.h
+++ b/lldb/include/lldb/lldb-defines.h
@@ -127,6 +127,9 @@
 #define MAX_PATH 260
 #endif
 
+/// Address Mask
+#define LLDB_INVALID_ADDRESS_MASK 0
+
 // ignore GCC function attributes
 #if defined(_MSC_VER) && !defined(__clang__)
 #define __attribute__(X)
diff --git a/lldb/source/API/SBProcess.cpp b/lldb/source/API/SBProcess.cpp
index 7edaa6b84fd7d7..b80664882ebcac 100644
--- a/lldb/source/API/SBProcess.cpp
+++ b/lldb/source/API/SBProcess.cpp
@@ -1258,7 +1258,7 @@ lldb::SBFileSpec SBProcess::GetCoreFile() {
 addr_t SBProcess::GetAddressMask(AddressMaskType type,
                                  AddressMaskRange addr_range) {
   LLDB_INSTRUMENT_VA(this, type, addr_range);
-  addr_t default_mask = 0;
+
   if (ProcessSP process_sp = GetSP()) {
     switch (type) {
     case eAddressMaskTypeCode:
@@ -1278,12 +1278,13 @@ addr_t SBProcess::GetAddressMask(AddressMaskType type,
         return process_sp->GetDataAddressMask();
     }
   }
-  return default_mask;
+  return LLDB_INVALID_ADDRESS_MASK;
 }
 
 void SBProcess::SetAddressMask(AddressMaskType type, addr_t mask,
                                AddressMaskRange addr_range) {
   LLDB_INSTRUMENT_VA(this, type, mask, addr_range);
+
   if (ProcessSP process_sp = GetSP()) {
     switch (type) {
     case eAddressMaskTypeCode:
@@ -1327,12 +1328,14 @@ void SBProcess::SetAddressMask(AddressMaskType type, addr_t mask,
 void SBProcess::SetAddressableBits(AddressMaskType type, uint32_t num_bits,
                                    AddressMaskRange addr_range) {
   LLDB_INSTRUMENT_VA(this, type, num_bits, addr_range);
+
   SetAddressMask(type, AddressableBits::AddressableBitToMask(num_bits),
                  addr_range);
 }
 
 addr_t SBProcess::FixAddress(addr_t addr, AddressMaskType type) {
   LLDB_INSTRUMENT_VA(this, addr, type);
+
   if (ProcessSP process_sp = GetSP()) {
     if (type == eAddressMaskTypeAny)
       return process_sp->FixAnyAddress(addr);

>From dec508f00b2860eb20fcdb6c5d98309178157bbf Mon Sep 17 00:00:00 2001
From: Jason Molenda <jmolenda at apple.com>
Date: Thu, 29 Feb 2024 14:12:00 -0800
Subject: [PATCH 6/7] Incorporate David's documentation improvements

---
 lldb/include/lldb/API/SBProcess.h | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/lldb/include/lldb/API/SBProcess.h b/lldb/include/lldb/API/SBProcess.h
index e2a6922724f005..aecf4ef4166960 100644
--- a/lldb/include/lldb/API/SBProcess.h
+++ b/lldb/include/lldb/API/SBProcess.h
@@ -416,10 +416,11 @@ class LLDB_API SBProcess {
   /// There can be different address masks for code addresses and
   /// data addresses, this argument can select which to get/set,
   /// or to use when clearing non-addressable bits from an address.
-  /// On AArch32 code with arm+thumb code, where instructions start
-  /// on even addresses, the 0th bit may be used to indicate that
-  /// a function is thumb code.  On such a target, the eAddressMaskTypeCode
-  /// may clear the 0th bit from an address to get the actual address.
+  /// This choice of mask can be important for example on AArch32 systems. Where
+  /// instructions where instructions start on even addresses, the 0th bit may
+  /// be used to indicate that a function is thumb code.  On such a target, the
+  /// eAddressMaskTypeCode may clear the 0th bit from an address to get the
+  /// actual address Whereas eAddressMaskTypeData would not.
   ///
   /// \a addr_range
   /// Many of the methods in this group take an \a addr_range argument
@@ -500,7 +501,7 @@ class LLDB_API SBProcess {
   SetAddressableBits(AddressMaskType type, uint32_t num_bits,
                      AddressMaskRange addr_range = lldb::eAddressMaskRangeLow);
 
-  /// Clear the non-addressable bits of an \a addr value and return a
+  /// Clear the non-address bits of an \a addr value and return a
   /// virtual address in memory.
   ///
   /// Bits that are not used in addressing may be used for other purposes;
@@ -508,7 +509,7 @@ class LLDB_API SBProcess {
   /// of armv7 code addresses to indicate arm/thumb are common examples.
   ///
   /// \param[in] addr
-  ///     The address that should be cleared of non-addressable bits.
+  ///     The address that should be cleared of non-address bits.
   ///
   /// \param[in] type
   ///     See \ref Mask Address Methods description of this argument.

>From 7ef231d8252c2dccf03d1b73b7820c9725b298df Mon Sep 17 00:00:00 2001
From: Jason Molenda <jmolenda at apple.com>
Date: Thu, 29 Feb 2024 14:40:37 -0800
Subject: [PATCH 7/7] Use static method to compute mask from bits for settings

David asked if I should assert on >64 addressable bits from
the user settings, and I saw that I failed to use the new
static method in AddressableBits when creating a mask from
the settings, which has the assert it in.

Also make the API test a little easier to read for the
eAddressMaskTypeCode.
---
 lldb/source/Target/Process.cpp                         | 10 ++++++----
 .../process/address-masks/TestAddressMasks.py          | 10 ++++++++++
 2 files changed, 16 insertions(+), 4 deletions(-)

diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index 137795cb8cec9e..970bcdf5d69b35 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -5682,21 +5682,22 @@ void Process::Flush() {
 
 lldb::addr_t Process::GetCodeAddressMask() {
   if (uint32_t num_bits_setting = GetVirtualAddressableBits())
-    return ~((1ULL << num_bits_setting) - 1);
+    return AddressableBits::AddressableBitToMask(num_bits_setting);
 
   return m_code_address_mask;
 }
 
 lldb::addr_t Process::GetDataAddressMask() {
   if (uint32_t num_bits_setting = GetVirtualAddressableBits())
-    return ~((1ULL << num_bits_setting) - 1);
+    return AddressableBits::AddressableBitToMask(num_bits_setting);
 
   return m_data_address_mask;
 }
 
 lldb::addr_t Process::GetHighmemCodeAddressMask() {
   if (uint32_t num_bits_setting = GetHighmemVirtualAddressableBits())
-    return ~((1ULL << num_bits_setting) - 1);
+    return AddressableBits::AddressableBitToMask(num_bits_setting);
+
   if (m_highmem_code_address_mask)
     return m_highmem_code_address_mask;
   return GetCodeAddressMask();
@@ -5704,7 +5705,8 @@ lldb::addr_t Process::GetHighmemCodeAddressMask() {
 
 lldb::addr_t Process::GetHighmemDataAddressMask() {
   if (uint32_t num_bits_setting = GetHighmemVirtualAddressableBits())
-    return ~((1ULL << num_bits_setting) - 1);
+    return AddressableBits::AddressableBitToMask(num_bits_setting);
+
   if (m_highmem_data_address_mask)
     return m_highmem_data_address_mask;
   return GetDataAddressMask();
diff --git a/lldb/test/API/python_api/process/address-masks/TestAddressMasks.py b/lldb/test/API/python_api/process/address-masks/TestAddressMasks.py
index 4a6a737e94f9d9..5fa6b328ad5229 100644
--- a/lldb/test/API/python_api/process/address-masks/TestAddressMasks.py
+++ b/lldb/test/API/python_api/process/address-masks/TestAddressMasks.py
@@ -42,6 +42,13 @@ def test_address_masks(self):
         self.assertEqual(0x000002950001F694, process.FixAddress(0x00265E950001F694))
         self.assertEqual(0xFFFFFE950000F694, process.FixAddress(0xFFA65E950000F694))
 
+        # Set a eAddressMaskTypeCode which has the low 3 bits marked as non-address
+        # bits, confirm that they're cleared by FixAddress.
+        process.SetAddressableBits(
+            lldb.eAddressMaskTypeAll, 42, lldb.eAddressMaskRangeAll
+        )
+        mask = process.GetAddressMask(lldb.eAddressMaskTypeAny)
+        process.SetAddressMask(lldb.eAddressMaskTypeCode, mask | 0x3)
         process.SetAddressMask(lldb.eAddressMaskTypeCode, 0xFFFFFC0000000003)
         self.assertEqual(0x000002950001F697, process.FixAddress(0x00265E950001F697))
         self.assertEqual(0xFFFFFE950000F697, process.FixAddress(0xFFA65E950000F697))
@@ -62,3 +69,6 @@ def test_address_masks(self):
         self.runCmd("settings set target.process.highmem-virtual-addressable-bits 15")
         self.assertEqual(0x0000000000007694, process.FixAddress(0x00265E950001F694))
         self.assertEqual(0xFFFFFFFFFFFFF694, process.FixAddress(0xFFA65E950000F694))
+        self.runCmd("settings set target.process.virtual-addressable-bits 0")
+        self.runCmd("settings set target.process.highmem-virtual-addressable-bits 0")
+        self.assertEqual(0x000002950001F694, process.FixAddress(0x00265E950001F694))



More information about the lldb-commits mailing list