mirror of
https://github.com/intel/llvm.git
synced 2026-01-13 19:08:21 +08:00
[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:
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
3
lldb/test/API/python_api/process/address-masks/Makefile
Normal file
3
lldb/test/API/python_api/process/address-masks/Makefile
Normal file
@@ -0,0 +1,3 @@
|
||||
C_SOURCES := main.c
|
||||
|
||||
include Makefile.rules
|
||||
@@ -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))
|
||||
5
lldb/test/API/python_api/process/address-masks/main.c
Normal file
5
lldb/test/API/python_api/process/address-masks/main.c
Normal file
@@ -0,0 +1,5 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char const *argv[]) {
|
||||
puts("Hello address masking world"); // break here
|
||||
}
|
||||
Reference in New Issue
Block a user