[Lldb-commits] [lldb] aeaa11a - [lldb] Address mask sbprocess apis and new mask invalid const (#83663)
via lldb-commits
lldb-commits at lists.llvm.org
Wed Mar 6 10:07:00 PST 2024
Author: Jason Molenda
Date: 2024-03-06T10:06:56-08:00
New Revision: aeaa11aeac0aedf32cafec6532d303fea595c5fc
URL: https://github.com/llvm/llvm-project/commit/aeaa11aeac0aedf32cafec6532d303fea595c5fc
DIFF: https://github.com/llvm/llvm-project/commit/aeaa11aeac0aedf32cafec6532d303fea595c5fc.diff
LOG: [lldb] Address mask sbprocess apis and new mask invalid const (#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. I originally landed this via
https://github.com/llvm/llvm-project/pull/83095 but it failed on CIs
outside of arm64 Darwin so I had to debug it on more environments
and update the patch.
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 all AArch64 ABI Fix* methods to apply the
Highmem masks if they have been set. These will not be set on a
Linux environment, but in TestAddressMasks.py I test the highmem
masks feature for any AArch64 target, so all AArch64 ABI plugins
must handle it.
rdar://123530562
Added:
lldb/test/API/python_api/process/address-masks/Makefile
lldb/test/API/python_api/process/address-masks/TestAddressMasks.py
lldb/test/API/python_api/process/address-masks/main.c
Modified:
lldb/include/lldb/API/SBProcess.h
lldb/include/lldb/Target/ABI.h
lldb/include/lldb/Target/Process.h
lldb/include/lldb/Utility/AddressableBits.h
lldb/include/lldb/lldb-defines.h
lldb/include/lldb/lldb-enumerations.h
lldb/source/API/SBProcess.cpp
lldb/source/Commands/CommandObjectProcess.cpp
lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp
lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp
lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp
lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
lldb/source/Target/ABI.cpp
lldb/source/Target/Process.cpp
lldb/source/Utility/AddressableBits.cpp
Removed:
################################################################################
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
diff erent 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
+ ///
diff erent page table setups for low and high memory, so
diff erent
+ /// 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
diff erent 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/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
diff erent 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
diff erent 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
diff erent 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/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/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/ABIAArch64.cpp b/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp
index ef53309f065fd0..256c1f828feb38 100644
--- a/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp
+++ b/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp
@@ -6,6 +6,8 @@
//
//===----------------------------------------------------------------------===//
+#include "lldb/lldb-types.h"
+
#include "ABIAArch64.h"
#include "ABIMacOSX_arm64.h"
#include "ABISysV_arm64.h"
@@ -16,6 +18,8 @@
#include <bitset>
#include <optional>
+using namespace lldb;
+
LLDB_PLUGIN_DEFINE(ABIAArch64)
void ABIAArch64::Initialize() {
@@ -29,14 +33,35 @@ void ABIAArch64::Terminate() {
}
lldb::addr_t ABIAArch64::FixCodeAddress(lldb::addr_t pc) {
- if (lldb::ProcessSP process_sp = GetProcessSP())
- return FixAddress(pc, process_sp->GetCodeAddressMask());
+ if (lldb::ProcessSP process_sp = GetProcessSP()) {
+ // 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();
+
+ if (mask != LLDB_INVALID_ADDRESS_MASK)
+ return FixAddress(pc, mask);
+ }
return pc;
}
lldb::addr_t ABIAArch64::FixDataAddress(lldb::addr_t pc) {
- if (lldb::ProcessSP process_sp = GetProcessSP())
- return FixAddress(pc, process_sp->GetDataAddressMask());
+ if (lldb::ProcessSP process_sp = GetProcessSP()) {
+ // 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();
+ if (mask != LLDB_INVALID_ADDRESS_MASK)
+ return FixAddress(pc, mask);
+ }
return pc;
}
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..110b5c86fc4256 100644
--- a/lldb/source/Target/ABI.cpp
+++ b/lldb/source/Target/ABI.cpp
@@ -147,6 +147,39 @@ 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();
+ if (mask == LLDB_INVALID_ADDRESS_MASK)
+ return pc;
+
+ // Assume the high bit is used for addressing, which
+ // may not be correct on all architectures e.g. AArch64
+ // where Top Byte Ignore mode is often used to store
+ // metadata in the top byte, and b55 is the bit used for
+ //
diff erentiating between low- and high-memory addresses.
+ // That target's ABIs need to override this method.
+ bool is_highmem = pc & (1ULL << 63);
+ 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();
+ if (mask == LLDB_INVALID_ADDRESS_MASK)
+ return pc;
+
+ // Assume the high bit is used for addressing, which
+ // may not be correct on all architectures e.g. AArch64
+ // where Top Byte Ignore mode is often used to store
+ // metadata in the top byte, and b55 is the bit used for
+ //
diff erentiating between low- and high-memory addresses.
+ // That target's ABIs need to override this method.
+ bool is_highmem = pc & (1ULL << 63);
+ 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 137795cb8cec9e..6d58873b54a3ad 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -5682,30 +5682,32 @@ 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);
- if (m_highmem_code_address_mask)
+ return AddressableBits::AddressableBitToMask(num_bits_setting);
+
+ if (m_highmem_code_address_mask != LLDB_INVALID_ADDRESS_MASK)
return m_highmem_code_address_mask;
return GetCodeAddressMask();
}
lldb::addr_t Process::GetHighmemDataAddressMask() {
if (uint32_t num_bits_setting = GetHighmemVirtualAddressableBits())
- return ~((1ULL << num_bits_setting) - 1);
- if (m_highmem_data_address_mask)
+ return AddressableBits::AddressableBitToMask(num_bits_setting);
+
+ if (m_highmem_data_address_mask != LLDB_INVALID_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..e0a570c15961c2
--- /dev/null
+++ b/lldb/test/API/python_api/process/address-masks/TestAddressMasks.py
@@ -0,0 +1,131 @@
+"""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 reset_all_masks(self, process):
+ process.SetAddressMask(
+ lldb.eAddressMaskTypeAll,
+ lldb.LLDB_INVALID_ADDRESS_MASK,
+ lldb.eAddressMaskRangeAll,
+ )
+ self.runCmd("settings set target.process.virtual-addressable-bits 0")
+ self.runCmd("settings set target.process.highmem-virtual-addressable-bits 0")
+
+ 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))
+ self.reset_all_masks(process)
+
+ # ~((1ULL<<42)-1) == 0xfffffc0000000000
+ process.SetAddressMask(lldb.eAddressMaskTypeAll, 0xFFFFFC0000000000)
+ self.assertEqual(0x0000029500003F94, process.FixAddress(0x00265E9500003F94))
+ self.reset_all_masks(process)
+
+ # Check that all bits can pass through unmodified
+ process.SetAddressableBits(lldb.eAddressMaskTypeAll, 64)
+ self.assertEqual(0x00265E9500003F94, process.FixAddress(0x00265E9500003F94))
+ self.reset_all_masks(process)
+
+ process.SetAddressableBits(
+ lldb.eAddressMaskTypeAll, 42, lldb.eAddressMaskRangeAll
+ )
+ self.assertEqual(0x000002950001F694, process.FixAddress(0x00265E950001F694))
+ self.assertEqual(0xFFFFFE950000F694, process.FixAddress(0xFFA65E950000F694))
+ self.reset_all_masks(process)
+
+ # 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)
+ 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),
+ )
+ self.reset_all_masks(process)
+
+ # The user can override whatever settings the Process thinks should be used.
+ process.SetAddressableBits(
+ lldb.eAddressMaskTypeAll, 42, lldb.eAddressMaskRangeLow
+ )
+ self.runCmd("settings set target.process.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.assertEqual(0x000002950001F694, process.FixAddress(0x00265E950001F694))
+ self.reset_all_masks(process)
+
+ # AArch64 can have
diff erent address masks for high and low memory, when
diff erent
+ # page tables are set up.
+ @skipIf(archs=no_match(["arm64", "arm64e", "aarch64"]))
+ def test_address_masks_target_supports_highmem_tests(self):
+ self.build()
+ (target, process, t, bp) = lldbutil.run_to_source_breakpoint(
+ self, "break here", lldb.SBFileSpec("main.c")
+ )
+
+ 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))
+ self.reset_all_masks(process)
+
+ # 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))
+ self.reset_all_masks(process)
+
+ # On most targets where we have a single mask for all address range, confirm
+ # that the high memory masks are ignored.
+ @skipIf(archs=["arm64", "arm64e", "aarch64"])
+ def test_address_masks_target_no_highmem(self):
+ self.build()
+ (target, process, t, bp) = lldbutil.run_to_source_breakpoint(
+ self, "break here", lldb.SBFileSpec("main.c")
+ )
+
+ process.SetAddressableBits(
+ lldb.eAddressMaskTypeAll, 42, lldb.eAddressMaskRangeLow
+ )
+ process.SetAddressableBits(
+ lldb.eAddressMaskTypeAll, 15, lldb.eAddressMaskRangeHigh
+ )
+ self.assertEqual(0x000002950001F694, process.FixAddress(0x00265E950001F694))
+ self.assertEqual(0xFFFFFE950000F694, process.FixAddress(0xFFA65E950000F694))
+ self.runCmd("settings set target.process.virtual-addressable-bits 15")
+ self.runCmd("settings set target.process.highmem-virtual-addressable-bits 42")
+ 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
+}
More information about the lldb-commits
mailing list