Skip to content

Commit 21dfaf6

Browse files
committed
Setting to control addressable bits in high memory
On AArch64, it is possible to have a program that accesses both low (0x000...) and high (0xfff...) memory, and with pointer authentication, you can have different numbers of bits used for pointer authentication depending on whether the address is in high or low memory. This adds a new target.process.highmem-virtual-addressable-bits setting which the AArch64 Mac ABI plugin will use, when set, to always set those unaddressable high bits for high memory addresses, and will use the existing target.process.virtual-addressable-bits setting for low memory addresses. This patch does not change the existing behavior when only target.process.virtual-addressable-bits is set. In that case, the value will apply to all addresses. Not yet done is recognizing metadata in a live process connection (gdb-remote qHostInfo) or a Mach-O corefile LC_NOTE to set the correct number of addressing bits for both memory ranges. That will be a future change. Differential Revision: https://reviews.llvm.org/D151292 rdar://109746900
1 parent bf8fe1c commit 21dfaf6

File tree

6 files changed

+100
-29
lines changed

6 files changed

+100
-29
lines changed

lldb/include/lldb/Target/Process.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ class ProcessProperties : public Properties {
8181
FileSpec GetPythonOSPluginPath() const;
8282
uint32_t GetVirtualAddressableBits() const;
8383
void SetVirtualAddressableBits(uint32_t bits);
84+
uint32_t GetHighmemVirtualAddressableBits() const;
85+
void SetHighmemVirtualAddressableBits(uint32_t bits);
8486
void SetPythonOSPluginPath(const FileSpec &file);
8587
bool GetIgnoreBreakpointsInExpressions() const;
8688
void SetIgnoreBreakpointsInExpressions(bool ignore);
@@ -1371,6 +1373,9 @@ class Process : public std::enable_shared_from_this<Process>,
13711373
lldb::addr_t GetCodeAddressMask();
13721374
lldb::addr_t GetDataAddressMask();
13731375

1376+
lldb::addr_t GetHighmemCodeAddressMask();
1377+
lldb::addr_t GetHighmemDataAddressMask();
1378+
13741379
void SetCodeAddressMask(lldb::addr_t code_address_mask) {
13751380
m_code_address_mask = code_address_mask;
13761381
}
@@ -1379,6 +1384,14 @@ class Process : public std::enable_shared_from_this<Process>,
13791384
m_data_address_mask = data_address_mask;
13801385
}
13811386

1387+
void SetHighmemCodeAddressMask(lldb::addr_t code_address_mask) {
1388+
m_highmem_code_address_mask = code_address_mask;
1389+
}
1390+
1391+
void SetHighmemDataAddressMask(lldb::addr_t data_address_mask) {
1392+
m_highmem_data_address_mask = data_address_mask;
1393+
}
1394+
13821395
/// Get the Modification ID of the process.
13831396
///
13841397
/// \return
@@ -3000,9 +3013,13 @@ void PruneThreadPlans();
30003013
/// Mask for code an data addresses. The default value (0) means no mask is
30013014
/// set. The bits set to 1 indicate bits that are NOT significant for
30023015
/// addressing.
3016+
/// The highmem versions are for targets where we may have different masks
3017+
/// for low memory versus high memory addresses.
30033018
/// @{
30043019
lldb::addr_t m_code_address_mask = 0;
30053020
lldb::addr_t m_data_address_mask = 0;
3021+
lldb::addr_t m_highmem_code_address_mask = 0;
3022+
lldb::addr_t m_highmem_data_address_mask = 0;
30063023
/// @}
30073024

30083025
bool m_clear_thread_plans_on_stop;

lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -814,15 +814,41 @@ ValueObjectSP ABIMacOSX_arm64::GetReturnValueObjectImpl(
814814
return return_valobj_sp;
815815
}
816816

817-
lldb::addr_t ABIMacOSX_arm64::FixAddress(addr_t pc, addr_t mask) {
818-
lldb::addr_t pac_sign_extension = 0x0080000000000000ULL;
819-
// When no mask is specified, clear/set the top byte; preserve
820-
// the low 55 bits (00..54) for addressing and bit 55 to indicate
821-
// sign.
822-
if (mask == 0) {
823-
// ~((1ULL<<55)-1)
824-
mask = 0xff80000000000000;
817+
addr_t ABIMacOSX_arm64::FixCodeAddress(addr_t pc) {
818+
addr_t pac_sign_extension = 0x0080000000000000ULL;
819+
addr_t tbi_mask = 0xff80000000000000ULL;
820+
addr_t mask = 0;
821+
822+
if (ProcessSP process_sp = GetProcessSP()) {
823+
mask = process_sp->GetCodeAddressMask();
824+
if (pc & pac_sign_extension) {
825+
addr_t highmem_mask = process_sp->GetHighmemCodeAddressMask();
826+
if (highmem_mask)
827+
mask = highmem_mask;
828+
}
829+
}
830+
if (mask == 0)
831+
mask = tbi_mask;
832+
833+
return (pc & pac_sign_extension) ? pc | mask : pc & (~mask);
834+
}
835+
836+
addr_t ABIMacOSX_arm64::FixDataAddress(addr_t pc) {
837+
addr_t pac_sign_extension = 0x0080000000000000ULL;
838+
addr_t tbi_mask = 0xff80000000000000ULL;
839+
addr_t mask = 0;
840+
841+
if (ProcessSP process_sp = GetProcessSP()) {
842+
mask = process_sp->GetDataAddressMask();
843+
if (pc & pac_sign_extension) {
844+
addr_t highmem_mask = process_sp->GetHighmemDataAddressMask();
845+
if (highmem_mask)
846+
mask = highmem_mask;
847+
}
825848
}
849+
if (mask == 0)
850+
mask = tbi_mask;
851+
826852
return (pc & pac_sign_extension) ? pc | mask : pc & (~mask);
827853
}
828854

lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ class ABIMacOSX_arm64 : public ABIAArch64 {
6262
return true;
6363
}
6464

65-
lldb::addr_t FixAddress(lldb::addr_t pc, lldb::addr_t mask) override;
65+
lldb::addr_t FixCodeAddress(lldb::addr_t pc) override;
66+
lldb::addr_t FixDataAddress(lldb::addr_t pc) override;
6667

6768
// Static Functions
6869

lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,15 +1080,18 @@ void DynamicLoaderDarwinKernel::LoadKernelModuleIfNeeded() {
10801080
}
10811081
// If the kernel global with the T1Sz setting is available,
10821082
// update the target.process.virtual-addressable-bits to be correct.
1083+
// NB the xnu kernel always has T0Sz and T1Sz the same value. If
1084+
// it wasn't the same, we would need to set
1085+
// target.process.virtual-addressable-bits = T0Sz
1086+
// target.process.highmem-virtual-addressable-bits = T1Sz
10831087
symbol = m_kernel.GetModule()->FindFirstSymbolWithNameAndType(
10841088
arm64_T1Sz_value, eSymbolTypeData);
10851089
if (symbol) {
1086-
const uint32_t orig_bits_value = m_process->GetVirtualAddressableBits();
1087-
// Mark all bits as addressable so we don't strip any from our
1088-
// memory read below, with an incorrect default value.
1089-
// b55 is the sign extension bit with PAC, b56:63 are TBI,
1090-
// don't mark those as addressable.
1091-
m_process->SetVirtualAddressableBits(55);
1090+
const addr_t orig_code_mask = m_process->GetCodeAddressMask();
1091+
const addr_t orig_data_mask = m_process->GetDataAddressMask();
1092+
1093+
m_process->SetCodeAddressMask(0);
1094+
m_process->SetDataAddressMask(0);
10921095
Status error;
10931096
// gT1Sz is 8 bytes. We may run on a stripped kernel binary
10941097
// where we can't get the size accurately. Hardcode it.
@@ -1103,9 +1106,12 @@ void DynamicLoaderDarwinKernel::LoadKernelModuleIfNeeded() {
11031106
// T1Sz is 25, then 64-25 == 39, bits 0..38 are used for
11041107
// addressing, bits 39..63 are used for PAC/TBI or whatever.
11051108
uint32_t virt_addr_bits = 64 - sym_value;
1106-
m_process->SetVirtualAddressableBits(virt_addr_bits);
1109+
addr_t mask = ~((1ULL << virt_addr_bits) - 1);
1110+
m_process->SetCodeAddressMask(mask);
1111+
m_process->SetDataAddressMask(mask);
11071112
} else {
1108-
m_process->SetVirtualAddressableBits(orig_bits_value);
1113+
m_process->SetCodeAddressMask(orig_code_mask);
1114+
m_process->SetDataAddressMask(orig_data_mask);
11091115
}
11101116
}
11111117
} else {

lldb/source/Target/Process.cpp

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,18 @@ void ProcessProperties::SetVirtualAddressableBits(uint32_t bits) {
227227
const uint32_t idx = ePropertyVirtualAddressableBits;
228228
SetPropertyAtIndex(idx, static_cast<uint64_t>(bits));
229229
}
230+
231+
uint32_t ProcessProperties::GetHighmemVirtualAddressableBits() const {
232+
const uint32_t idx = ePropertyHighmemVirtualAddressableBits;
233+
return GetPropertyAtIndexAs<uint64_t>(
234+
idx, g_process_properties[idx].default_uint_value);
235+
}
236+
237+
void ProcessProperties::SetHighmemVirtualAddressableBits(uint32_t bits) {
238+
const uint32_t idx = ePropertyHighmemVirtualAddressableBits;
239+
SetPropertyAtIndex(idx, static_cast<uint64_t>(bits));
240+
}
241+
230242
void ProcessProperties::SetPythonOSPluginPath(const FileSpec &file) {
231243
const uint32_t idx = ePropertyPythonOSPluginPath;
232244
SetPropertyAtIndex(idx, file);
@@ -5651,25 +5663,31 @@ void Process::Flush() {
56515663
}
56525664

56535665
lldb::addr_t Process::GetCodeAddressMask() {
5654-
if (m_code_address_mask == 0) {
5655-
if (uint32_t number_of_addressable_bits = GetVirtualAddressableBits()) {
5656-
lldb::addr_t address_mask = ~((1ULL << number_of_addressable_bits) - 1);
5657-
SetCodeAddressMask(address_mask);
5658-
}
5659-
}
5666+
if (uint32_t num_bits_setting = GetVirtualAddressableBits())
5667+
return ~((1ULL << num_bits_setting) - 1);
5668+
56605669
return m_code_address_mask;
56615670
}
56625671

56635672
lldb::addr_t Process::GetDataAddressMask() {
5664-
if (m_data_address_mask == 0) {
5665-
if (uint32_t number_of_addressable_bits = GetVirtualAddressableBits()) {
5666-
lldb::addr_t address_mask = ~((1ULL << number_of_addressable_bits) - 1);
5667-
SetDataAddressMask(address_mask);
5668-
}
5669-
}
5673+
if (uint32_t num_bits_setting = GetVirtualAddressableBits())
5674+
return ~((1ULL << num_bits_setting) - 1);
5675+
56705676
return m_data_address_mask;
56715677
}
56725678

5679+
lldb::addr_t Process::GetHighmemCodeAddressMask() {
5680+
if (uint32_t num_bits_setting = GetHighmemVirtualAddressableBits())
5681+
return ~((1ULL << num_bits_setting) - 1);
5682+
return GetCodeAddressMask();
5683+
}
5684+
5685+
lldb::addr_t Process::GetHighmemDataAddressMask() {
5686+
if (uint32_t num_bits_setting = GetHighmemVirtualAddressableBits())
5687+
return ~((1ULL << num_bits_setting) - 1);
5688+
return GetDataAddressMask();
5689+
}
5690+
56735691
void Process::DidExec() {
56745692
Log *log = GetLog(LLDBLog::Process);
56755693
LLDB_LOGF(log, "Process::%s()", __FUNCTION__);

lldb/source/Target/TargetProperties.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,9 @@ let Definition = "process" in {
255255
def VirtualAddressableBits: Property<"virtual-addressable-bits", "UInt64">,
256256
DefaultUnsignedValue<0>,
257257
Desc<"The number of bits used for addressing. If the value is 39, then bits 0..38 are used for addressing. The default value of 0 means unspecified.">;
258+
def HighmemVirtualAddressableBits: Property<"highmem-virtual-addressable-bits", "UInt64">,
259+
DefaultUnsignedValue<0>,
260+
Desc<"The number of bits used for addressing high memory, when it differs from low memory in the same Process. When this is non-zero, target.process.virtual-addressable-bits will be the value for low memory (0x000... addresses) and this setting will be the value for high memory (0xfff... addresses). When this is zero, target.process.virtual-addressable-bits applies to all addresses. It is very uncommon to use this setting.">;
258261
def FollowForkMode: Property<"follow-fork-mode", "Enum">,
259262
DefaultEnumValue<"eFollowParent">,
260263
EnumValues<"OptionEnumValues(g_follow_fork_mode_values)">,

0 commit comments

Comments
 (0)