Skip to content

Commit 55105fc

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 (cherry picked from commit 21dfaf6)
1 parent 60e2a62 commit 55105fc

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);
@@ -1388,6 +1390,9 @@ class Process : public std::enable_shared_from_this<Process>,
13881390
lldb::addr_t GetCodeAddressMask();
13891391
lldb::addr_t GetDataAddressMask();
13901392

1393+
lldb::addr_t GetHighmemCodeAddressMask();
1394+
lldb::addr_t GetHighmemDataAddressMask();
1395+
13911396
void SetCodeAddressMask(lldb::addr_t code_address_mask) {
13921397
m_code_address_mask = code_address_mask;
13931398
}
@@ -1396,6 +1401,14 @@ class Process : public std::enable_shared_from_this<Process>,
13961401
m_data_address_mask = data_address_mask;
13971402
}
13981403

1404+
void SetHighmemCodeAddressMask(lldb::addr_t code_address_mask) {
1405+
m_highmem_code_address_mask = code_address_mask;
1406+
}
1407+
1408+
void SetHighmemDataAddressMask(lldb::addr_t data_address_mask) {
1409+
m_highmem_data_address_mask = data_address_mask;
1410+
}
1411+
13991412
/// Get the Modification ID of the process.
14001413
///
14011414
/// \return
@@ -3036,9 +3049,13 @@ void PruneThreadPlans();
30363049
/// Mask for code an data addresses. The default value (0) means no mask is
30373050
/// set. The bits set to 1 indicate bits that are NOT significant for
30383051
/// addressing.
3052+
/// The highmem versions are for targets where we may have different masks
3053+
/// for low memory versus high memory addresses.
30393054
/// @{
30403055
lldb::addr_t m_code_address_mask = 0;
30413056
lldb::addr_t m_data_address_mask = 0;
3057+
lldb::addr_t m_highmem_code_address_mask = 0;
3058+
lldb::addr_t m_highmem_data_address_mask = 0;
30423059
/// @}
30433060

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

lldb/source/Target/Process.cpp

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,18 @@ void ProcessProperties::SetVirtualAddressableBits(uint32_t bits) {
231231
const uint32_t idx = ePropertyVirtualAddressableBits;
232232
m_collection_sp->SetPropertyAtIndexAsUInt64(nullptr, idx, bits);
233233
}
234+
235+
uint32_t ProcessProperties::GetHighmemVirtualAddressableBits() const {
236+
const uint32_t idx = ePropertyHighmemVirtualAddressableBits;
237+
return GetPropertyAtIndexAs<uint64_t>(
238+
idx, g_process_properties[idx].default_uint_value);
239+
}
240+
241+
void ProcessProperties::SetHighmemVirtualAddressableBits(uint32_t bits) {
242+
const uint32_t idx = ePropertyHighmemVirtualAddressableBits;
243+
SetPropertyAtIndex(idx, static_cast<uint64_t>(bits));
244+
}
245+
234246
void ProcessProperties::SetPythonOSPluginPath(const FileSpec &file) {
235247
const uint32_t idx = ePropertyPythonOSPluginPath;
236248
m_collection_sp->SetPropertyAtIndexAsFileSpec(nullptr, idx, file);
@@ -5817,25 +5829,31 @@ void Process::Flush() {
58175829
}
58185830

58195831
lldb::addr_t Process::GetCodeAddressMask() {
5820-
if (m_code_address_mask == 0) {
5821-
if (uint32_t number_of_addressable_bits = GetVirtualAddressableBits()) {
5822-
lldb::addr_t address_mask = ~((1ULL << number_of_addressable_bits) - 1);
5823-
SetCodeAddressMask(address_mask);
5824-
}
5825-
}
5832+
if (uint32_t num_bits_setting = GetVirtualAddressableBits())
5833+
return ~((1ULL << num_bits_setting) - 1);
5834+
58265835
return m_code_address_mask;
58275836
}
58285837

58295838
lldb::addr_t Process::GetDataAddressMask() {
5830-
if (m_data_address_mask == 0) {
5831-
if (uint32_t number_of_addressable_bits = GetVirtualAddressableBits()) {
5832-
lldb::addr_t address_mask = ~((1ULL << number_of_addressable_bits) - 1);
5833-
SetDataAddressMask(address_mask);
5834-
}
5835-
}
5839+
if (uint32_t num_bits_setting = GetVirtualAddressableBits())
5840+
return ~((1ULL << num_bits_setting) - 1);
5841+
58365842
return m_data_address_mask;
58375843
}
58385844

5845+
lldb::addr_t Process::GetHighmemCodeAddressMask() {
5846+
if (uint32_t num_bits_setting = GetHighmemVirtualAddressableBits())
5847+
return ~((1ULL << num_bits_setting) - 1);
5848+
return GetCodeAddressMask();
5849+
}
5850+
5851+
lldb::addr_t Process::GetHighmemDataAddressMask() {
5852+
if (uint32_t num_bits_setting = GetHighmemVirtualAddressableBits())
5853+
return ~((1ULL << num_bits_setting) - 1);
5854+
return GetDataAddressMask();
5855+
}
5856+
58395857
void Process::DidExec() {
58405858
Log *log = GetLog(LLDBLog::Process);
58415859
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
@@ -289,6 +289,9 @@ let Definition = "process" in {
289289
def VirtualAddressableBits: Property<"virtual-addressable-bits", "UInt64">,
290290
DefaultUnsignedValue<0>,
291291
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.">;
292+
def HighmemVirtualAddressableBits: Property<"highmem-virtual-addressable-bits", "UInt64">,
293+
DefaultUnsignedValue<0>,
294+
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.">;
292295
def FollowForkMode: Property<"follow-fork-mode", "Enum">,
293296
DefaultEnumValue<"eFollowParent">,
294297
EnumValues<"OptionEnumValues(g_follow_fork_mode_values)">,

0 commit comments

Comments
 (0)