Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lldb/include/lldb/Expression/IRMemoryMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class IRMemoryMap {
size_t size, Status &error);
void WriteScalarToMemory(lldb::addr_t process_address, Scalar &scalar,
size_t size, Status &error);
void WritePointerToMemory(lldb::addr_t process_address, lldb::addr_t address,
void WritePointerToMemory(lldb::addr_t process_address, lldb::addr_t pointer,
Status &error);
void ReadMemory(uint8_t *bytes, lldb::addr_t process_address, size_t size,
Status &error);
Expand Down
4 changes: 4 additions & 0 deletions lldb/include/lldb/Target/ABI.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,10 @@ class ABI : public PluginInterface {
return FixDataAddress(pc);
}

virtual lldb::addr_t FixAnyAddressPreservingAuthentication(lldb::addr_t pc) {
return FixAnyAddress(pc);
}

llvm::MCRegisterInfo &GetMCRegisterInfo() { return *m_mc_register_info_up; }

virtual void
Expand Down
5 changes: 5 additions & 0 deletions lldb/include/lldb/Target/Process.h
Original file line number Diff line number Diff line change
Expand Up @@ -1473,6 +1473,11 @@ class Process : public std::enable_shared_from_this<Process>,
/// platforms where there is a difference (only Arm Thumb at this time).
lldb::addr_t FixAnyAddress(lldb::addr_t pc);

/// Strip pointer metadata except for the bits necessary to authenticate a
/// memory access. This is useful, for example, if `address` requires
/// authentication and it is going to be consumed in JITed code.
lldb::addr_t FixAnyAddressPreservingAuthentication(lldb::addr_t address);

/// Get the Modification ID of the process.
///
/// \return
Expand Down
66 changes: 29 additions & 37 deletions lldb/include/lldb/Target/StackID.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,27 @@
#define LLDB_TARGET_STACKID_H

#include "lldb/Core/AddressRange.h"
#include "lldb/lldb-private.h"

namespace lldb_private {

class Process;

class StackID {
public:
// Constructors and Destructors
StackID() = default;

explicit StackID(lldb::addr_t pc, lldb::addr_t cfa,
SymbolContextScope *symbol_scope, Process *process);

StackID(const StackID &rhs) = default;

~StackID() = default;

lldb::addr_t GetPC() const { return m_pc; }

lldb::addr_t GetCallFrameAddress() const { return m_cfa; }
lldb::addr_t GetCallFrameAddressWithMetadata() const {
return m_cfa_with_metadata;
}

lldb::addr_t GetCallFrameAddressWithoutMetadata() const { return m_cfa; }

SymbolContextScope *GetSymbolContextScope() const { return m_symbol_scope; }

Expand All @@ -51,17 +51,6 @@ class StackID {

void Dump(Stream *s);

// Operators
const StackID &operator=(const StackID &rhs) {
if (this != &rhs) {
m_pc = rhs.m_pc;
m_cfa = rhs.m_cfa;
m_cfa_on_stack = rhs.m_cfa_on_stack;
m_symbol_scope = rhs.m_symbol_scope;
}
return *this;
}

/// Check if the CFA is on the stack, or elsewhere in the process, such as on
/// the heap.
bool IsCFAOnStack(Process &process) const;
Expand All @@ -76,28 +65,31 @@ class StackID {
void SetPC(lldb::addr_t pc, Process *process);
void SetCFA(lldb::addr_t cfa, Process *process);

lldb::addr_t m_pc =
LLDB_INVALID_ADDRESS; // The pc value for the function/symbol for this
// frame. This will
// only get used if the symbol scope is nullptr (the code where we are
// stopped is not represented by any function or symbol in any shared
// library).
lldb::addr_t m_cfa =
LLDB_INVALID_ADDRESS; // The call frame address (stack pointer) value
// at the beginning of the function that uniquely
// identifies this frame (along with m_symbol_scope
// below)
// True if the CFA is an address on the stack, false if it's an address
// elsewhere (ie heap).
/// The pc value for the function/symbol for this frame. This will only get
/// used if the symbol scope is nullptr (the code where we are stopped is not
/// represented by any function or symbol in any shared library).
lldb::addr_t m_pc = LLDB_INVALID_ADDRESS;

/// The call frame address (stack pointer) value at the beginning of the
/// function that uniquely identifies this frame (along with m_symbol_scope
/// below)
lldb::addr_t m_cfa = LLDB_INVALID_ADDRESS;

/// The cfa with metadata (i.e. prior to Process::FixAddress).
lldb::addr_t m_cfa_with_metadata = LLDB_INVALID_ADDRESS;

/// If nullptr, there is no block or symbol for this frame. If not nullptr,
/// this will either be the scope for the lexical block for the frame, or the
/// scope for the symbol. Symbol context scopes are always be unique pointers
/// since the are part of the Block and Symbol objects and can easily be used
/// to tell if a stack ID is the same as another.
SymbolContextScope *m_symbol_scope = nullptr;

// BEGIN SWIFT
/// True if the CFA is an address on the stack, false if it's an address
/// elsewhere (ie heap).
mutable LazyBool m_cfa_on_stack = eLazyBoolCalculate;
SymbolContextScope *m_symbol_scope =
nullptr; // If nullptr, there is no block or symbol for this frame.
// If not nullptr, this will either be the scope for the
// lexical block for the frame, or the scope for the
// symbol. Symbol context scopes are always be unique
// pointers since the are part of the Block and Symbol
// objects and can easily be used to tell if a stack ID
// is the same as another.
// END SWIFT
};

bool operator==(const StackID &lhs, const StackID &rhs);
Expand Down
2 changes: 1 addition & 1 deletion lldb/source/API/SBFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ lldb::addr_t SBFrame::GetCFA() const {
}

if (StackFrame *frame = exe_ctx->GetFramePtr())
return frame->GetStackID().GetCallFrameAddress();
return frame->GetStackID().GetCallFrameAddressWithoutMetadata();
return LLDB_INVALID_ADDRESS;
}

Expand Down
2 changes: 1 addition & 1 deletion lldb/source/Expression/DWARFExpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2278,7 +2278,7 @@ llvm::Expected<Value> DWARFExpression::Evaluate(
// Note that we don't have to parse FDEs because this DWARF expression
// is commonly evaluated with a valid stack frame.
StackID id = frame->GetStackID();
addr_t cfa = id.GetCallFrameAddress();
addr_t cfa = id.GetCallFrameAddressWithMetadata();
if (cfa != LLDB_INVALID_ADDRESS) {
stack.push_back(Scalar(cfa));
stack.back().SetValueType(Value::ValueType::LoadAddress);
Expand Down
13 changes: 11 additions & 2 deletions lldb/source/Expression/IRMemoryMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -637,10 +637,19 @@ void IRMemoryMap::WriteScalarToMemory(lldb::addr_t process_address,
}

void IRMemoryMap::WritePointerToMemory(lldb::addr_t process_address,
lldb::addr_t address, Status &error) {
lldb::addr_t pointer, Status &error) {
error.Clear();

Scalar scalar(address);
/// Only ask the Process to fix `pointer` if the address belongs to the
/// process. An address belongs to the process if the Allocation policy is not
/// eAllocationPolicyHostOnly.
auto it = FindAllocation(pointer, 1);
if (it == m_allocations.end() ||
it->second.m_policy != AllocationPolicy::eAllocationPolicyHostOnly)
if (auto process_sp = GetProcessWP().lock())
pointer = process_sp->FixAnyAddressPreservingAuthentication(pointer);

Scalar scalar(pointer);

WriteScalarToMemory(process_address, scalar, GetAddressByteSize(), error);
}
Expand Down
9 changes: 9 additions & 0 deletions lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -792,6 +792,15 @@ addr_t ABIMacOSX_arm64::FixDataAddress(addr_t addr) {
return DoFixAddr(addr, false /*is_code*/, GetProcessSP());
}

addr_t ABIMacOSX_arm64::FixAnyAddressPreservingAuthentication(addr_t addr) {
// Save the old MTE tag and restore it later.
constexpr addr_t mte_mask = 0x0f00000000000000ULL;
addr_t old_mte_tag = addr & mte_mask;

addr_t fixed_addr = FixDataAddress(addr);
return old_mte_tag | (fixed_addr & (~mte_mask));
}

void ABIMacOSX_arm64::Initialize() {
PluginManager::RegisterPlugin(GetPluginNameStatic(), pluginDesc,
CreateInstance);
Expand Down
1 change: 1 addition & 0 deletions lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ class ABIMacOSX_arm64 : public ABIAArch64 {

lldb::addr_t FixCodeAddress(lldb::addr_t pc) override;
lldb::addr_t FixDataAddress(lldb::addr_t pc) override;
lldb::addr_t FixAnyAddressPreservingAuthentication(lldb::addr_t pc) override;

// Static Functions

Expand Down
6 changes: 6 additions & 0 deletions lldb/source/Target/Process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6133,6 +6133,12 @@ addr_t Process::FixAnyAddress(addr_t addr) {
return addr;
}

addr_t Process::FixAnyAddressPreservingAuthentication(addr_t addr) {
if (ABISP abi_sp = GetABI())
addr = abi_sp->FixAnyAddressPreservingAuthentication(addr);
return addr;
}

void Process::DidExec() {
Log *log = GetLog(LLDBLog::Process);
LLDB_LOGF(log, "Process::%s()", __FUNCTION__);
Expand Down
8 changes: 0 additions & 8 deletions lldb/source/Target/RegisterContextUnwind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2009,8 +2009,6 @@ bool RegisterContextUnwind::ReadFrameAddress(
reg_info, reg_to_deref_contents, reg_info->byte_size, reg_value);
if (error.Success()) {
address = reg_value.GetAsUInt64();
if (abi_sp)
address = abi_sp->FixCodeAddress(address);
UnwindLogMsg(
"CFA value via dereferencing reg %s (%d): reg has val 0x%" PRIx64
", CFA value is 0x%" PRIx64,
Expand All @@ -2033,8 +2031,6 @@ bool RegisterContextUnwind::ReadFrameAddress(
RegisterNumber cfa_reg(m_thread, row_register_kind,
fa.GetRegisterNumber());
if (ReadGPRValue(cfa_reg, cfa_reg_contents)) {
if (abi_sp)
cfa_reg_contents = abi_sp->FixDataAddress(cfa_reg_contents);
if (cfa_reg_contents == LLDB_INVALID_ADDRESS || cfa_reg_contents == 0 ||
cfa_reg_contents == 1) {
UnwindLogMsg(
Expand Down Expand Up @@ -2069,9 +2065,6 @@ bool RegisterContextUnwind::ReadFrameAddress(
dwarfexpr.Evaluate(&exe_ctx, this, 0, nullptr, nullptr);
if (result) {
address = result->GetScalar().ULongLong();
if (ABISP abi_sp = m_thread.GetProcess()->GetABI())
address = abi_sp->FixCodeAddress(address);

UnwindLogMsg("CFA value set by DWARF expression is 0x%" PRIx64,
address);
return true;
Expand Down Expand Up @@ -2111,7 +2104,6 @@ bool RegisterContextUnwind::ReadFrameAddress(
}
case UnwindPlan::Row::FAValue::isConstant: {
address = fa.GetConstant();
address = m_thread.GetProcess()->FixDataAddress(address);
UnwindLogMsg("CFA value set by constant is 0x%" PRIx64, address);
return true;
}
Expand Down
2 changes: 1 addition & 1 deletion lldb/source/Target/StackFrameList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ bool StackFrameList::FetchFramesUpTo(uint32_t end_idx,
}
} else {
unwind_frame_sp = m_frames.front();
cfa = unwind_frame_sp->m_id.GetCallFrameAddress();
cfa = unwind_frame_sp->m_id.GetCallFrameAddressWithoutMetadata();
}
} else {
// Check for interruption when building the frames.
Expand Down
28 changes: 11 additions & 17 deletions lldb/source/Target/StackID.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ bool StackID::IsCFAOnStack(Process &process) const {

StackID::StackID(lldb::addr_t pc, lldb::addr_t cfa,
SymbolContextScope *symbol_scope, Process *process)
: m_pc(pc), m_cfa(cfa), m_symbol_scope(symbol_scope) {
: m_pc(pc), m_cfa(cfa), m_cfa_with_metadata(cfa),
m_symbol_scope(symbol_scope) {
if (process) {
m_pc = process->FixCodeAddress(m_pc);
m_cfa = process->FixDataAddress(m_cfa);
Expand All @@ -47,6 +48,7 @@ void StackID::SetPC(lldb::addr_t pc, Process *process) {
}

void StackID::SetCFA(lldb::addr_t cfa, Process *process) {
m_cfa_with_metadata = cfa;
m_cfa = process ? process->FixDataAddress(cfa) : cfa;
}

Expand All @@ -67,7 +69,8 @@ void StackID::Dump(Stream *s) {
}

bool lldb_private::operator==(const StackID &lhs, const StackID &rhs) {
if (lhs.GetCallFrameAddress() != rhs.GetCallFrameAddress())
if (lhs.GetCallFrameAddressWithoutMetadata() !=
rhs.GetCallFrameAddressWithoutMetadata())
return false;

SymbolContextScope *lhs_scope = lhs.GetSymbolContextScope();
Expand All @@ -81,16 +84,7 @@ bool lldb_private::operator==(const StackID &lhs, const StackID &rhs) {
}

bool lldb_private::operator!=(const StackID &lhs, const StackID &rhs) {
if (lhs.GetCallFrameAddress() != rhs.GetCallFrameAddress())
return true;

SymbolContextScope *lhs_scope = lhs.GetSymbolContextScope();
SymbolContextScope *rhs_scope = rhs.GetSymbolContextScope();

if (lhs_scope == nullptr && rhs_scope == nullptr)
return lhs.GetPC() != rhs.GetPC();

return lhs_scope != rhs_scope;
return !(lhs == rhs);
}

// BEGIN SWIFT
Expand Down Expand Up @@ -143,8 +137,8 @@ CompareHeapCFAs(const StackID &lhs, const StackID &rhs, Process &process) {
if (!lhs_cfa_on_stack && rhs_cfa_on_stack)
return HeapCFAComparisonResult::Older;

const lldb::addr_t lhs_cfa = lhs.GetCallFrameAddress();
const lldb::addr_t rhs_cfa = rhs.GetCallFrameAddress();
const lldb::addr_t lhs_cfa = lhs.GetCallFrameAddressWithoutMetadata();
const lldb::addr_t rhs_cfa = rhs.GetCallFrameAddressWithoutMetadata();
// If the cfas are the same, fallback to the usual scope comparison.
if (lhs_cfa == rhs_cfa)
return HeapCFAComparisonResult::NoOpinion;
Expand Down Expand Up @@ -179,9 +173,9 @@ bool StackID::IsYounger(const StackID &lhs, const StackID &rhs,
break;
}
// END SWIFT

const lldb::addr_t lhs_cfa = lhs.GetCallFrameAddress();
const lldb::addr_t rhs_cfa = rhs.GetCallFrameAddress();
//
const lldb::addr_t lhs_cfa = lhs.GetCallFrameAddressWithoutMetadata();
const lldb::addr_t rhs_cfa = rhs.GetCallFrameAddressWithoutMetadata();

// FIXME: We are assuming that the stacks grow downward in memory. That's not
// necessary, but true on
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ def check_pcs(self, async_frames, process, target):
# with the funclet's prologue skipped.
parent_frame = async_frames[idx + 1]
prologue_to_skip = parent_frame.GetFunction().GetPrologueByteSize()
self.assertEqual(continuation_ptr + prologue_to_skip, parent_frame.GetPC())
self.assertEqual(
process.FixAddress(continuation_ptr) + prologue_to_skip,
parent_frame.GetPC(),
)

def check_async_regs_one_frame(self, frame, process):
async_reg_name = "r14" if self.getArchitecture() == "x86_64" else "x22"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
ASM_SOURCES := main.s

# This is to appease Makefile.rules, there is no main.c
C_SOURCES := main.c

ASM_OBJS := $(ASM_SOURCES:.s=.o)

%.o: %.s
$(CC) -c -x assembler $< -o $@

include Makefile.rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil


@skipUnlessDarwin
@skipIf(archs=no_match(["arm64"]))
class TestArmPointerMetadataStripping(TestBase):
def test(self):
self.build()
target, process, thread, bkpt = lldbutil.run_to_name_breakpoint(self, "foo")

# Step over the first two instructions of foo in order to
# toggle the bit of fp and save it on the stack:
# orr x29, x29, #0x1000000000000000
# stp x29, x30, [sp, #-16]!
# This is effectively adding metadata to the CFA of the caller frame (main).
thread.StepInstruction(False)
thread.StepInstruction(False)

# The location of `argv` has been artificially made equal to the CFA of the frame.
# As such, it should have the metadata artificially set previously.
argv_addr = thread.frames[1].GetValueForVariablePath("&argv")
self.assertTrue(argv_addr.IsValid())
argv_addr_uint = argv_addr.GetValueAsUnsigned()
self.assertNotEqual((argv_addr_uint & (1 << 60)), 0)

# GetCFA strips metadata.
cfa = thread.frames[1].GetCFA()
self.assertEqual((cfa & (1 << 60)), 0)

# If the test worked correctly, the cfa and the location should be identical,
# modulo the metadata.
self.assertEqual(cfa | (1 << 60), argv_addr_uint)
Loading