[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
This commit is contained in:
Jason Molenda
2024-03-06 10:06:56 -08:00
committed by GitHub
parent dcd08daed5
commit aeaa11aeac
19 changed files with 517 additions and 45 deletions

View File

@@ -407,6 +407,120 @@ public:
/// 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.

View File

@@ -122,8 +122,8 @@ public:
/// 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 @@ protected:
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;

View File

@@ -1422,9 +1422,23 @@ public:
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 @@ protected:
// 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;

View File

@@ -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 @@ public:
void SetHighmemAddressableBits(uint32_t highmem_addressing_bits);
static lldb::addr_t AddressableBitToMask(uint32_t addressable_bits);
void SetProcessMasks(lldb_private::Process &process);
private:

View File

@@ -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)

View File

@@ -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

View File

@@ -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);

View File

@@ -1408,7 +1408,7 @@ protected:
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);

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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 {

View File

@@ -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";

View File

@@ -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
// differentiating 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
// differentiating 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;

View File

@@ -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();
}

View File

@@ -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);
}

View File

@@ -0,0 +1,3 @@
C_SOURCES := main.c
include Makefile.rules

View File

@@ -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 different address masks for high and low memory, when different
# 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))

View File

@@ -0,0 +1,5 @@
#include <stdio.h>
int main(int argc, char const *argv[]) {
puts("Hello address masking world"); // break here
}