[Lldb-commits] [lldb] Address mask sbprocess apis and new mask invalid const (PR #83663)
Jason Molenda via lldb-commits
lldb-commits at lists.llvm.org
Fri Mar 1 23:24:09 PST 2024
https://github.com/jasonmolenda created https://github.com/llvm/llvm-project/pull/83663
[lldb] Add SBProcess methods for get/set/use address masks (#83095)
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.
This patch changes the value of "no mask set" from 0 to
LLDB_INVALID_ADDRESS_MASK, which is UINT64_MAX. A mask of all 1's
means "no bits are used for addressing" which is an impossible mask,
whereas a mask of 0 means "all bits are used for addressing" which
is possible.
I added a base class implementation of ABI::FixCodeAddress and
ABI::FixDataAddress that will apply the Process mask values if they
are set to a value other than LLDB_INVALID_ADDRESS_MASK.
I updated all the callers/users of the Mask methods which were
handling a value of 0 to mean invalid mask to use
LLDB_INVALID_ADDRESS_MASK.
I added code to the ABISysV_arm64 Fix override methods to apply the
Highmem masks if they have been set. These will not be set on a
Linux environment, but I have tests in TestAddressMasks.py which
set the highmem masks and I need all Fix*Mask implementations to
check & use them for the tests to pass.
rdar://123530562
>From c993c7cc7c1669ca7d06e52f1a1ff8dbefe9ebc9 Mon Sep 17 00:00:00 2001
From: Jason Molenda <jmolenda at apple.com>
Date: Thu, 29 Feb 2024 17:02:42 -0800
Subject: [PATCH 1/2] [lldb] Add SBProcess methods for get/set/use address
masks (#83095)
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 | 114 ++++++++++++++++++
lldb/include/lldb/Utility/AddressableBits.h | 3 +
lldb/include/lldb/lldb-defines.h | 5 +
lldb/include/lldb/lldb-enumerations.h | 16 +++
lldb/source/API/SBProcess.cpp | 92 ++++++++++++++
lldb/source/Target/Process.cpp | 10 +-
lldb/source/Utility/AddressableBits.cpp | 12 +-
.../python_api/process/address-masks/Makefile | 3 +
.../process/address-masks/TestAddressMasks.py | 74 ++++++++++++
.../python_api/process/address-masks/main.c | 5 +
10 files changed, 328 insertions(+), 6 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..7da3335a7234b7 100644
--- a/lldb/include/lldb/API/SBProcess.h
+++ b/lldb/include/lldb/API/SBProcess.h
@@ -407,6 +407,120 @@ class LLDB_API SBProcess {
/// the process isn't loaded from a core file.
lldb::SBFileSpec GetCoreFile();
+ /// \{
+ /// \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.
+ /// 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
+ /// 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 (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
+ /// 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
+ /// 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 description 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
+ /// 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
+ /// 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.
+ ///
+ /// \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
+ /// 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(
+ lldb::AddressMaskType type, lldb::addr_t mask,
+ lldb::AddressMaskRange addr_range = lldb::eAddressMaskRangeLow);
+
+ /// Set the number of bits used for addressing in this Process.
+ ///
+ /// 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 description 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.
+ /// 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
+ /// See \ref Mask Address Methods description 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);
+
+ /// 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;
+ /// 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-address bits.
+ ///
+ /// \param[in] type
+ /// 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
+ 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-defines.h b/lldb/include/lldb/lldb-defines.h
index 469be92eabecf3..c7bd019c5c90eb 100644
--- a/lldb/include/lldb/lldb-defines.h
+++ b/lldb/include/lldb/lldb-defines.h
@@ -127,6 +127,11 @@
#define MAX_PATH 260
#endif
+/// Address Mask
+/// Bits not used for addressing are set to 1 in the mask;
+/// all mask bits set is an invalid value.
+#define LLDB_INVALID_ADDRESS_MASK UINT64_MAX
+
// ignore GCC function attributes
#if defined(_MSC_VER) && !defined(__clang__)
#define __attribute__(X)
diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h
index 85769071dae785..646f7bfda98475 100644
--- a/lldb/include/lldb/lldb-enumerations.h
+++ b/lldb/include/lldb/lldb-enumerations.h
@@ -1323,6 +1323,22 @@ enum SymbolDownload {
eSymbolDownloadForeground = 2,
};
+/// Used in the SBProcess AddressMask/FixAddress methods.
+enum AddressMaskType {
+ eAddressMaskTypeCode = 0,
+ eAddressMaskTypeData,
+ eAddressMaskTypeAny,
+ eAddressMaskTypeAll = eAddressMaskTypeAny
+};
+
+/// Used in the SBProcess AddressMask/FixAddress methods.
+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..b80664882ebcac 100644
--- a/lldb/source/API/SBProcess.cpp
+++ b/lldb/source/API/SBProcess.cpp
@@ -1255,6 +1255,98 @@ lldb::SBFileSpec SBProcess::GetCoreFile() {
return SBFileSpec(core_file);
}
+addr_t SBProcess::GetAddressMask(AddressMaskType type,
+ AddressMaskRange addr_range) {
+ LLDB_INSTRUMENT_VA(this, type, addr_range);
+
+ 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 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:
+ 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/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/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..5fa6b328ad5229
--- /dev/null
+++ b/lldb/test/API/python_api/process/address-masks/TestAddressMasks.py
@@ -0,0 +1,74 @@
+"""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))
+
+ # 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))
+ 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))
+ 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))
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 0f021d350ca200d97a37c330270c2e8b4ff06c2a Mon Sep 17 00:00:00 2001
From: Jason Molenda <jason at molenda.com>
Date: Fri, 1 Mar 2024 23:12:31 -0800
Subject: [PATCH 2/2] [lldb] Use new value for no-mask, add ABI base method,
update others
This changes the value of "no mask set" from 0 to
LLDB_INVALID_ADDRESS_MASK, which is UINT64_MAX. A mask of all 1's
means "no bits are used for addressing" which is an impossible mask,
whereas a mask of 0 means "all bits are used for addressing" which
is possible.
I added a base class implementation of ABI::FixCodeAddress and
ABI::FixDataAddress that will apply the Process mask values if
they are set to a value other than LLDB_INVALID_ADDRESS_MASK.
I updated all the callers/users of the Mask methods which were
handling a value of 0 to mean invalid mask to use
LLDB_INVALID_ADDRESS_MASK.
I added code to the ABISysV_arm64 Fix override methods to
apply the Highmem masks if they have been set. These will
not be set on a Linux environment, but I have tests in
TestAddressMasks.py which set the highmem masks and I need
all Fix*Mask implementations to check & use them for the
tests to pass. It may be better to conditionalize the
highmem tests for arm64-apple, where that's an environment
we do need to support.
---
lldb/include/lldb/Target/ABI.h | 8 +---
lldb/include/lldb/Target/Process.h | 36 ++++++++++++-----
lldb/source/Commands/CommandObjectProcess.cpp | 2 +-
.../Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp | 8 ++--
.../Plugins/ABI/AArch64/ABISysV_arm64.cpp | 40 ++++++++++++++-----
.../DynamicLoaderDarwinKernel.cpp | 3 +-
.../ObjectFile/Mach-O/ObjectFileMachO.cpp | 4 +-
lldb/source/Target/ABI.cpp | 26 ++++++++++++
lldb/source/Target/Process.cpp | 4 +-
9 files changed, 96 insertions(+), 35 deletions(-)
diff --git a/lldb/include/lldb/Target/ABI.h b/lldb/include/lldb/Target/ABI.h
index f600e29c7c4b0e..7b646d743346b7 100644
--- a/lldb/include/lldb/Target/ABI.h
+++ b/lldb/include/lldb/Target/ABI.h
@@ -122,8 +122,8 @@ class ABI : public PluginInterface {
/// ARM uses bit zero to signify a code address is thumb, so any ARM ABI
/// plug-ins would strip those bits.
/// @{
- virtual lldb::addr_t FixCodeAddress(lldb::addr_t pc) { return pc; }
- virtual lldb::addr_t FixDataAddress(lldb::addr_t pc) { return pc; }
+ virtual lldb::addr_t FixCodeAddress(lldb::addr_t pc);
+ virtual lldb::addr_t FixDataAddress(lldb::addr_t pc);
/// @}
/// Use this method when you do not know, or do not care what kind of address
@@ -166,10 +166,6 @@ class ABI : public PluginInterface {
lldb::ProcessWP m_process_wp;
std::unique_ptr<llvm::MCRegisterInfo> m_mc_register_info_up;
- virtual lldb::addr_t FixCodeAddress(lldb::addr_t pc, lldb::addr_t mask) {
- return pc;
- }
-
private:
ABI(const ABI &) = delete;
const ABI &operator=(const ABI &) = delete;
diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h
index 0ad626ffd3613c..e260e1b4b797bc 100644
--- a/lldb/include/lldb/Target/Process.h
+++ b/lldb/include/lldb/Target/Process.h
@@ -1422,9 +1422,23 @@ class Process : public std::enable_shared_from_this<Process>,
virtual void DidExit() {}
+ /// Get the current address mask in the Process
+ ///
+ /// This mask can used to set/clear non-address bits in an addr_t.
+ ///
+ /// \return
+ /// The current address mask.
+ /// Bits which are set to 1 are not used for addressing.
+ /// An address mask of 0 means all bits are used for addressing.
+ /// An address mask of LLDB_INVALID_ADDRESS_MASK (all 1's) means
+ /// that no mask has been set.
lldb::addr_t GetCodeAddressMask();
lldb::addr_t GetDataAddressMask();
+ /// The highmem masks are for targets where we may have different masks
+ /// for low memory versus high memory addresses, and they will be left
+ /// as LLDB_INVALID_ADDRESS_MASK normally, meaning the base masks
+ /// should be applied to all addresses.
lldb::addr_t GetHighmemCodeAddressMask();
lldb::addr_t GetHighmemDataAddressMask();
@@ -3096,16 +3110,20 @@ void PruneThreadPlans();
// if run while destructing. We use this flag to determine that.
std::atomic<bool> m_destructing;
- /// 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.
+ /// Mask for code an data addresses.
+ /// The default value LLDB_INVALID_ADDRESS_MASK means no mask has been set,
+ /// and addresses values should not be modified.
+ /// In these masks, the bits are set to 1 indicate bits that are not
+ /// significant for addressing.
+ /// The highmem masks are for targets where we may have different masks
+ /// for low memory versus high memory addresses, and they will be left
+ /// as LLDB_INVALID_ADDRESS_MASK normally, meaning the base masks
+ /// should be applied to all 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;
+ lldb::addr_t m_code_address_mask = LLDB_INVALID_ADDRESS_MASK;
+ lldb::addr_t m_data_address_mask = LLDB_INVALID_ADDRESS_MASK;
+ lldb::addr_t m_highmem_code_address_mask = LLDB_INVALID_ADDRESS_MASK;
+ lldb::addr_t m_highmem_data_address_mask = LLDB_INVALID_ADDRESS_MASK;
/// @}
bool m_clear_thread_plans_on_stop;
diff --git a/lldb/source/Commands/CommandObjectProcess.cpp b/lldb/source/Commands/CommandObjectProcess.cpp
index 9ac97eb66b6232..3587a8f529e4ab 100644
--- a/lldb/source/Commands/CommandObjectProcess.cpp
+++ b/lldb/source/Commands/CommandObjectProcess.cpp
@@ -1408,7 +1408,7 @@ class CommandObjectProcessStatus : public CommandObjectParsed {
if (m_options.m_verbose) {
addr_t code_mask = process->GetCodeAddressMask();
addr_t data_mask = process->GetDataAddressMask();
- if (code_mask != 0) {
+ if (code_mask != LLDB_INVALID_ADDRESS_MASK) {
int bits = std::bitset<64>(~code_mask).count();
result.AppendMessageWithFormat(
"Addressable code address mask: 0x%" PRIx64 "\n", code_mask);
diff --git a/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp b/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp
index f4ef9b4fc824b0..045d6a405e6972 100644
--- a/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp
+++ b/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp
@@ -814,11 +814,11 @@ addr_t ABIMacOSX_arm64::FixCodeAddress(addr_t pc) {
mask = process_sp->GetCodeAddressMask();
if (pc & pac_sign_extension) {
addr_t highmem_mask = process_sp->GetHighmemCodeAddressMask();
- if (highmem_mask)
+ if (highmem_mask != LLDB_INVALID_ADDRESS_MASK)
mask = highmem_mask;
}
}
- if (mask == 0)
+ if (mask == LLDB_INVALID_ADDRESS_MASK)
mask = tbi_mask;
return (pc & pac_sign_extension) ? pc | mask : pc & (~mask);
@@ -833,11 +833,11 @@ addr_t ABIMacOSX_arm64::FixDataAddress(addr_t pc) {
mask = process_sp->GetDataAddressMask();
if (pc & pac_sign_extension) {
addr_t highmem_mask = process_sp->GetHighmemDataAddressMask();
- if (highmem_mask)
+ if (highmem_mask != LLDB_INVALID_ADDRESS_MASK)
mask = highmem_mask;
}
}
- if (mask == 0)
+ if (mask == LLDB_INVALID_ADDRESS_MASK)
mask = tbi_mask;
return (pc & pac_sign_extension) ? pc | mask : pc & (~mask);
diff --git a/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp b/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp
index bf3c5ddd588977..cd7481f88efdd8 100644
--- a/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp
+++ b/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp
@@ -775,6 +775,8 @@ ValueObjectSP ABISysV_arm64::GetReturnValueObjectImpl(
}
lldb::addr_t ABISysV_arm64::FixAddress(addr_t pc, addr_t mask) {
+ if (mask == LLDB_INVALID_ADDRESS_MASK)
+ return pc;
lldb::addr_t pac_sign_extension = 0x0080000000000000ULL;
return (pc & pac_sign_extension) ? pc | mask : pc & (~mask);
}
@@ -782,12 +784,12 @@ lldb::addr_t ABISysV_arm64::FixAddress(addr_t pc, addr_t mask) {
// Reads code or data address mask for the current Linux process.
static lldb::addr_t ReadLinuxProcessAddressMask(lldb::ProcessSP process_sp,
llvm::StringRef reg_name) {
- // 0 means there isn't a mask or it has not been read yet.
- // We do not return the top byte mask unless thread_sp is valid.
- // This prevents calls to this function before the thread is setup locking
- // in the value to just the top byte mask, in cases where pointer
- // authentication might also be active.
- uint64_t address_mask = 0;
+ // LLDB_INVALID_ADDRESS_MASK means there isn't a mask or it has not been read
+ // yet. We do not return the top byte mask unless thread_sp is valid. This
+ // prevents calls to this function before the thread is setup locking in the
+ // value to just the top byte mask, in cases where pointer authentication
+ // might also be active.
+ uint64_t address_mask = LLDB_INVALID_ADDRESS_MASK;
lldb::ThreadSP thread_sp = process_sp->GetThreadList().GetSelectedThread();
if (thread_sp) {
// Linux configures user-space virtual addresses with top byte ignored.
@@ -814,11 +816,20 @@ static lldb::addr_t ReadLinuxProcessAddressMask(lldb::ProcessSP process_sp,
lldb::addr_t ABISysV_arm64::FixCodeAddress(lldb::addr_t pc) {
if (lldb::ProcessSP process_sp = GetProcessSP()) {
if (process_sp->GetTarget().GetArchitecture().GetTriple().isOSLinux() &&
- !process_sp->GetCodeAddressMask())
+ process_sp->GetCodeAddressMask() == LLDB_INVALID_ADDRESS_MASK)
process_sp->SetCodeAddressMask(
ReadLinuxProcessAddressMask(process_sp, "code_mask"));
- return FixAddress(pc, process_sp->GetCodeAddressMask());
+ // b55 is the highest bit outside TBI (if it's enabled), use
+ // it to determine if the high bits are set to 0 or 1.
+ const addr_t pac_sign_extension = 0x0080000000000000ULL;
+ addr_t mask = process_sp->GetCodeAddressMask();
+ // Test if the high memory mask has been overriden separately
+ if (pc & pac_sign_extension &&
+ process_sp->GetHighmemCodeAddressMask() != LLDB_INVALID_ADDRESS_MASK)
+ mask = process_sp->GetHighmemCodeAddressMask();
+
+ return FixAddress(pc, mask);
}
return pc;
}
@@ -826,11 +837,20 @@ lldb::addr_t ABISysV_arm64::FixCodeAddress(lldb::addr_t pc) {
lldb::addr_t ABISysV_arm64::FixDataAddress(lldb::addr_t pc) {
if (lldb::ProcessSP process_sp = GetProcessSP()) {
if (process_sp->GetTarget().GetArchitecture().GetTriple().isOSLinux() &&
- !process_sp->GetDataAddressMask())
+ process_sp->GetDataAddressMask() == LLDB_INVALID_ADDRESS_MASK)
process_sp->SetDataAddressMask(
ReadLinuxProcessAddressMask(process_sp, "data_mask"));
- return FixAddress(pc, process_sp->GetDataAddressMask());
+ // b55 is the highest bit outside TBI (if it's enabled), use
+ // it to determine if the high bits are set to 0 or 1.
+ const addr_t pac_sign_extension = 0x0080000000000000ULL;
+ addr_t mask = process_sp->GetDataAddressMask();
+ // Test if the high memory mask has been overriden separately
+ if (pc & pac_sign_extension &&
+ process_sp->GetHighmemDataAddressMask() != LLDB_INVALID_ADDRESS_MASK)
+ mask = process_sp->GetHighmemDataAddressMask();
+
+ return FixAddress(pc, mask);
}
return pc;
}
diff --git a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
index 3bdbce5a3b7c46..8d83937aab6681 100644
--- a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
+++ b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
@@ -22,6 +22,7 @@
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlanRunToAddress.h"
+#include "lldb/Utility/AddressableBits.h"
#include "lldb/Utility/DataBuffer.h"
#include "lldb/Utility/DataBufferHeap.h"
#include "lldb/Utility/LLDBLog.h"
@@ -1109,7 +1110,7 @@ void DynamicLoaderDarwinKernel::LoadKernelModuleIfNeeded() {
// 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;
- addr_t mask = ~((1ULL << virt_addr_bits) - 1);
+ addr_t mask = AddressableBits::AddressableBitToMask(virt_addr_bits);
m_process->SetCodeAddressMask(mask);
m_process->SetDataAddressMask(mask);
} else {
diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
index 729fbd3256715d..bcf3a3274cf3a0 100644
--- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
+++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
@@ -6620,7 +6620,7 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp,
// Bits will be set to indicate which bits are NOT used in
// addressing in this process or 0 for unknown.
uint64_t address_mask = process_sp->GetCodeAddressMask();
- if (address_mask != 0) {
+ if (address_mask != LLDB_INVALID_ADDRESS_MASK) {
// LC_NOTE "addrable bits"
mach_header.ncmds++;
mach_header.sizeofcmds += sizeof(llvm::MachO::note_command);
@@ -6654,7 +6654,7 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp,
std::vector<std::unique_ptr<LCNoteEntry>> lc_notes;
// Add "addrable bits" LC_NOTE when an address mask is available
- if (address_mask != 0) {
+ if (address_mask != LLDB_INVALID_ADDRESS_MASK) {
std::unique_ptr<LCNoteEntry> addrable_bits_lcnote_up(
new LCNoteEntry(addr_byte_size, byte_order));
addrable_bits_lcnote_up->name = "addrable bits";
diff --git a/lldb/source/Target/ABI.cpp b/lldb/source/Target/ABI.cpp
index 86bf0118027155..76b1f6ec64adf9 100644
--- a/lldb/source/Target/ABI.cpp
+++ b/lldb/source/Target/ABI.cpp
@@ -147,6 +147,32 @@ ValueObjectSP ABI::GetReturnValueObject(Thread &thread, CompilerType &ast_type,
return return_valobj_sp;
}
+addr_t ABI::FixCodeAddress(lldb::addr_t pc) {
+ ProcessSP process_sp(GetProcessSP());
+ addr_t mask = process_sp->GetCodeAddressMask();
+ bool is_highmem = pc & (1ULL << 63);
+ if (is_highmem &&
+ process_sp->GetHighmemCodeAddressMask() != LLDB_INVALID_ADDRESS_MASK)
+ mask = process_sp->GetHighmemCodeAddressMask();
+ if (mask == LLDB_INVALID_ADDRESS_MASK)
+ return pc;
+
+ return is_highmem ? pc | mask : pc & (~mask);
+}
+
+addr_t ABI::FixDataAddress(lldb::addr_t pc) {
+ ProcessSP process_sp(GetProcessSP());
+ addr_t mask = process_sp->GetDataAddressMask();
+ bool is_highmem = pc & (1ULL << 63);
+ if (is_highmem &&
+ process_sp->GetHighmemDataAddressMask() != LLDB_INVALID_ADDRESS_MASK)
+ mask = process_sp->GetHighmemCodeAddressMask();
+ if (mask == LLDB_INVALID_ADDRESS_MASK)
+ return pc;
+
+ return is_highmem ? pc | mask : pc & (~mask);
+}
+
ValueObjectSP ABI::GetReturnValueObject(Thread &thread, llvm::Type &ast_type,
bool persistent) const {
ValueObjectSP return_valobj_sp;
diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index 970bcdf5d69b35..6d58873b54a3ad 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -5698,7 +5698,7 @@ lldb::addr_t Process::GetHighmemCodeAddressMask() {
if (uint32_t num_bits_setting = GetHighmemVirtualAddressableBits())
return AddressableBits::AddressableBitToMask(num_bits_setting);
- if (m_highmem_code_address_mask)
+ if (m_highmem_code_address_mask != LLDB_INVALID_ADDRESS_MASK)
return m_highmem_code_address_mask;
return GetCodeAddressMask();
}
@@ -5707,7 +5707,7 @@ lldb::addr_t Process::GetHighmemDataAddressMask() {
if (uint32_t num_bits_setting = GetHighmemVirtualAddressableBits())
return AddressableBits::AddressableBitToMask(num_bits_setting);
- if (m_highmem_data_address_mask)
+ if (m_highmem_data_address_mask != LLDB_INVALID_ADDRESS_MASK)
return m_highmem_data_address_mask;
return GetDataAddressMask();
}
More information about the lldb-commits
mailing list