Skip to content

[lldb] Add SBProcess methods for get/set/use address masks #83095

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
114 changes: 114 additions & 0 deletions lldb/include/lldb/API/SBProcess.h
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,120 @@ class LLDB_API SBProcess {
/// the process isn't loaded from a core file.
lldb::SBFileSpec GetCoreFile();

/// \{
/// \group Mask Address Methods
///
/// \a type
/// All of the methods in this group take \a type argument
/// which is an AddressMaskType enum value.
/// There can be different address masks for code addresses and
/// data addresses, this argument can select which to get/set,
/// or to use when clearing non-addressable bits from an address.
/// This choice of mask can be important for example on AArch32
/// systems. Where instructions where instructions start on even addresses,
/// the 0th bit may be used to indicate that a function is thumb code. On
/// such a target, the eAddressMaskTypeCode may clear the 0th bit from an
/// address to get the actual address Whereas eAddressMaskTypeData would not.
///
/// \a addr_range
/// Many of the methods in this group take an \a addr_range argument
/// which is an AddressMaskRange enum value.
/// Needing to specify the address range is highly unusual, and the
/// default argument can be used in nearly all circumstances.
/// On some architectures (e.g., AArch64), it is possible to have
/// different page table setups for low and high memory, so different
/// numbers of bits relevant to addressing. It is possible to have
/// a program running in one half of memory and accessing the other
/// as heap, so we need to maintain two different sets of address masks
/// to debug this correctly.

/// Get the current address mask that will be applied to addresses
/// before reading from memory.
///
/// \param[in] type
/// See \ref Mask Address Methods description of this argument.
/// eAddressMaskTypeAny is often a suitable value when code and
/// data masks are the same on a given target.
///
/// \param[in] addr_range
/// See \ref Mask Address Methods description of this argument.
/// This will default to eAddressMaskRangeLow which is the
/// only set of masks used normally.
///
/// \return
/// The address mask currently in use. Bits which are not used
/// for addressing will be set to 1 in the mask.
lldb::addr_t GetAddressMask(
lldb::AddressMaskType type,
lldb::AddressMaskRange addr_range = lldb::eAddressMaskRangeLow);

/// Set the current address mask that can be applied to addresses
/// before reading from memory.
///
/// \param[in] type
/// See \ref Mask Address Methods description of this argument.
/// eAddressMaskTypeAll is often a suitable value when the
/// same mask is being set for both code and data.
///
/// \param[in] mask
/// The address mask to set. Bits which are not used for addressing
/// should be set to 1 in the mask.
///
/// \param[in] addr_range
/// See \ref Mask Address Methods description of this argument.
/// This will default to eAddressMaskRangeLow which is the
/// only set of masks used normally.
void SetAddressMask(
lldb::AddressMaskType type, lldb::addr_t mask,
lldb::AddressMaskRange addr_range = lldb::eAddressMaskRangeLow);

/// Set the number of bits used for addressing in this Process.
///
/// On Darwin and similar systems, the addressable bits are expressed
/// as the number of low order bits that are relevant to addressing,
/// instead of a more general address mask.
/// This method calculates the correct mask value for a given number
/// of low order addressable bits.
///
/// \param[in] type
/// See \ref Mask Address Methods description of this argument.
/// eAddressMaskTypeAll is often a suitable value when the
/// same mask is being set for both code and data.
///
/// \param[in] num_bits
/// Number of bits that are used for addressing.
/// For example, a value of 42 indicates that the low 42 bits
/// are relevant for addressing, and that higher-order bits may
/// be used for various metadata like pointer authentication,
/// Type Byte Ignore, etc.
///
/// \param[in] addr_range
/// See \ref Mask Address Methods description of this argument.
/// This will default to eAddressMaskRangeLow which is the
/// only set of masks used normally.
void
SetAddressableBits(AddressMaskType type, uint32_t num_bits,
AddressMaskRange addr_range = lldb::eAddressMaskRangeLow);

/// Clear the non-address bits of an \a addr value and return a
/// virtual address in memory.
///
/// Bits that are not used in addressing may be used for other purposes;
/// pointer authentication, or metadata in the top byte, or the 0th bit
/// of armv7 code addresses to indicate arm/thumb are common examples.
///
/// \param[in] addr
/// The address that should be cleared of non-address bits.
///
/// \param[in] type
/// See \ref Mask Address Methods description of this argument.
/// eAddressMaskTypeAny is the default value, correct when it
/// is unknown if the address is a code or data address.
lldb::addr_t
FixAddress(lldb::addr_t addr,
lldb::AddressMaskType type = lldb::eAddressMaskTypeAny);
/// \}

/// Allocate memory within the process.
///
/// This function will allocate memory in the process's address space.
Expand Down
3 changes: 3 additions & 0 deletions lldb/include/lldb/Utility/AddressableBits.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#define LLDB_UTILITY_ADDRESSABLEBITS_H

#include "lldb/lldb-forward.h"
#include "lldb/lldb-public.h"

namespace lldb_private {

Expand All @@ -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:
Expand Down
5 changes: 5 additions & 0 deletions lldb/include/lldb/lldb-defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
16 changes: 16 additions & 0 deletions lldb/include/lldb/lldb-enumerations.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
92 changes: 92 additions & 0 deletions lldb/source/API/SBProcess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
10 changes: 6 additions & 4 deletions lldb/source/Target/Process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5682,29 +5682,31 @@ void Process::Flush() {

lldb::addr_t Process::GetCodeAddressMask() {
if (uint32_t num_bits_setting = GetVirtualAddressableBits())
return ~((1ULL << num_bits_setting) - 1);
return AddressableBits::AddressableBitToMask(num_bits_setting);

return m_code_address_mask;
}

lldb::addr_t Process::GetDataAddressMask() {
if (uint32_t num_bits_setting = GetVirtualAddressableBits())
return ~((1ULL << num_bits_setting) - 1);
return AddressableBits::AddressableBitToMask(num_bits_setting);

return m_data_address_mask;
}

lldb::addr_t Process::GetHighmemCodeAddressMask() {
if (uint32_t num_bits_setting = GetHighmemVirtualAddressableBits())
return ~((1ULL << num_bits_setting) - 1);
return AddressableBits::AddressableBitToMask(num_bits_setting);

if (m_highmem_code_address_mask)
return m_highmem_code_address_mask;
return GetCodeAddressMask();
}

lldb::addr_t Process::GetHighmemDataAddressMask() {
if (uint32_t num_bits_setting = GetHighmemVirtualAddressableBits())
return ~((1ULL << num_bits_setting) - 1);
return AddressableBits::AddressableBitToMask(num_bits_setting);

if (m_highmem_data_address_mask)
return m_highmem_data_address_mask;
return GetDataAddressMask();
Expand Down
12 changes: 10 additions & 2 deletions lldb/source/Utility/AddressableBits.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
3 changes: 3 additions & 0 deletions lldb/test/API/python_api/process/address-masks/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
C_SOURCES := main.c

include Makefile.rules
Loading