diff --git a/lldb/include/lldb/Expression/IRMemoryMap.h b/lldb/include/lldb/Expression/IRMemoryMap.h index abec5442793c6..deac6e00f04c8 100644 --- a/lldb/include/lldb/Expression/IRMemoryMap.h +++ b/lldb/include/lldb/Expression/IRMemoryMap.h @@ -59,7 +59,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); diff --git a/lldb/include/lldb/Target/ABI.h b/lldb/include/lldb/Target/ABI.h index dd941d1c905c1..4275dd6c9273b 100644 --- a/lldb/include/lldb/Target/ABI.h +++ b/lldb/include/lldb/Target/ABI.h @@ -140,6 +140,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 diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h index 657fa0d5a6d72..77122d7d9a9b5 100644 --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -1463,6 +1463,11 @@ class Process : public std::enable_shared_from_this, /// 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 diff --git a/lldb/include/lldb/Target/StackID.h b/lldb/include/lldb/Target/StackID.h index a965c3f6c7225..7dccf918cc22f 100644 --- a/lldb/include/lldb/Target/StackID.h +++ b/lldb/include/lldb/Target/StackID.h @@ -10,22 +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; - StackID(const StackID &rhs) = default; + explicit StackID(lldb::addr_t pc, lldb::addr_t cfa, + SymbolContextScope *symbol_scope, Process *process); ~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; } @@ -46,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; @@ -68,34 +62,34 @@ class StackID { protected: friend class StackFrame; - explicit StackID(lldb::addr_t pc, lldb::addr_t cfa) : m_pc(pc), m_cfa(cfa) {} - - void SetPC(lldb::addr_t pc) { m_pc = pc; } - - void SetCFA(lldb::addr_t cfa) { m_cfa = cfa; } - - 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). + void SetPC(lldb::addr_t pc, Process *process); + void SetCFA(lldb::addr_t cfa, Process *process); + + /// 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); diff --git a/lldb/source/API/SBFrame.cpp b/lldb/source/API/SBFrame.cpp index 6963da3ce88bf..135440b0eb035 100644 --- a/lldb/source/API/SBFrame.cpp +++ b/lldb/source/API/SBFrame.cpp @@ -318,7 +318,7 @@ lldb::addr_t SBFrame::GetCFA() const { StackFrame *frame = exe_ctx.GetFramePtr(); if (frame) - return frame->GetStackID().GetCallFrameAddress(); + return frame->GetStackID().GetCallFrameAddressWithoutMetadata(); return LLDB_INVALID_ADDRESS; } diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp index 536091be0284e..19235c919a8bb 100644 --- a/lldb/source/Expression/DWARFExpression.cpp +++ b/lldb/source/Expression/DWARFExpression.cpp @@ -1131,8 +1131,6 @@ llvm::Expected DWARFExpression::Evaluate( lldb::addr_t pointer_value = process->ReadPointerFromMemory(pointer_addr, error); if (pointer_value != LLDB_INVALID_ADDRESS) { - if (ABISP abi_sp = process->GetABI()) - pointer_value = abi_sp->FixCodeAddress(pointer_value); stack.back().GetScalar() = pointer_value; stack.back().ClearContext(); } else { @@ -2279,7 +2277,7 @@ llvm::Expected 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); diff --git a/lldb/source/Expression/IRMemoryMap.cpp b/lldb/source/Expression/IRMemoryMap.cpp index 65b5d11413c85..1bf1897e2fa06 100644 --- a/lldb/source/Expression/IRMemoryMap.cpp +++ b/lldb/source/Expression/IRMemoryMap.cpp @@ -635,10 +635,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); } diff --git a/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp b/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp index 49a9a42eab709..d33fef106e340 100644 --- a/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp +++ b/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp @@ -811,42 +811,48 @@ ValueObjectSP ABIMacOSX_arm64::GetReturnValueObjectImpl( return return_valobj_sp; } -addr_t ABIMacOSX_arm64::FixCodeAddress(addr_t pc) { - addr_t pac_sign_extension = 0x0080000000000000ULL; - addr_t tbi_mask = 0xff80000000000000ULL; - addr_t mask = 0; - - if (ProcessSP process_sp = GetProcessSP()) { - mask = process_sp->GetCodeAddressMask(); - if (pc & pac_sign_extension) { - addr_t highmem_mask = process_sp->GetHighmemCodeAddressMask(); - if (highmem_mask != LLDB_INVALID_ADDRESS_MASK) - mask = highmem_mask; - } - } +constexpr addr_t tbi_mask = 0xff80000000000000ULL; +constexpr addr_t pac_sign_extension = 0x0080000000000000ULL; + +/// Consults the process for its {code, data} address masks and applies it to +/// `addr`. +static addr_t DoFixAddr(addr_t addr, bool is_code, ProcessSP process_sp) { + if (!process_sp) + return addr; + + addr_t mask = is_code ? process_sp->GetCodeAddressMask() + : process_sp->GetDataAddressMask(); if (mask == LLDB_INVALID_ADDRESS_MASK) mask = tbi_mask; - return (pc & pac_sign_extension) ? pc | mask : pc & (~mask); + if (addr & pac_sign_extension) { + addr_t highmem_mask = is_code ? process_sp->GetHighmemCodeAddressMask() + : process_sp->GetHighmemCodeAddressMask(); + if (highmem_mask != LLDB_INVALID_ADDRESS_MASK) + return addr | highmem_mask; + return addr | mask; + } + + return addr & (~mask); } -addr_t ABIMacOSX_arm64::FixDataAddress(addr_t pc) { - addr_t pac_sign_extension = 0x0080000000000000ULL; - addr_t tbi_mask = 0xff80000000000000ULL; - addr_t mask = 0; - - if (ProcessSP process_sp = GetProcessSP()) { - mask = process_sp->GetDataAddressMask(); - if (pc & pac_sign_extension) { - addr_t highmem_mask = process_sp->GetHighmemDataAddressMask(); - if (highmem_mask != LLDB_INVALID_ADDRESS_MASK) - mask = highmem_mask; - } - } - if (mask == LLDB_INVALID_ADDRESS_MASK) - mask = tbi_mask; +addr_t ABIMacOSX_arm64::FixCodeAddress(addr_t pc) { + ProcessSP process_sp = GetProcessSP(); + return DoFixAddr(pc, true /*is_code*/, GetProcessSP()); +} + +addr_t ABIMacOSX_arm64::FixDataAddress(addr_t addr) { + ProcessSP process_sp = GetProcessSP(); + 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; - return (pc & pac_sign_extension) ? pc | mask : pc & (~mask); + addr_t fixed_addr = FixDataAddress(addr); + return old_mte_tag | (fixed_addr & (~mte_mask)); } void ABIMacOSX_arm64::Initialize() { diff --git a/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.h b/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.h index 025a7a3fc368b..763f07452bb0c 100644 --- a/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.h +++ b/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.h @@ -64,6 +64,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 diff --git a/lldb/source/Plugins/Language/Swift/SwiftFormatters.cpp b/lldb/source/Plugins/Language/Swift/SwiftFormatters.cpp index afc5d0c740bb2..58ecdf799cc5a 100644 --- a/lldb/source/Plugins/Language/Swift/SwiftFormatters.cpp +++ b/lldb/source/Plugins/Language/Swift/SwiftFormatters.cpp @@ -863,6 +863,8 @@ class TaskSyntheticFrontEnd : public SyntheticChildrenFrontEnd { m_ts->GetTypeFromMangledTypename(ConstString("$sSVD")); addr_t value = m_task_ptr; + if (auto process_sp = m_backend.GetProcessSP()) + value = process_sp->FixDataAddress(value); DataExtractor data{reinterpret_cast(&value), sizeof(value), endian::InlHostByteOrder(), sizeof(void *)}; @@ -903,7 +905,7 @@ class TaskSyntheticFrontEnd : public SyntheticChildrenFrontEnd { parent_addr = 0; } - addr_t value = parent_addr; + addr_t value = process_sp->FixDataAddress(parent_addr); DataExtractor data{reinterpret_cast(&value), sizeof(value), endian::InlHostByteOrder(), sizeof(void *)}; diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index 294b7fbd1ee6b..36a572df840e5 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -6048,6 +6048,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__); diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp index c40e0d59911e4..d167d135eee87 100644 --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -362,16 +362,10 @@ void RegisterContextUnwind::InitializeNonZerothFrame() { if (log) { UnwindLogMsg("pc = 0x%" PRIx64, pc); addr_t reg_val; - if (ReadGPRValue(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP, reg_val)) { - if (abi_sp) - reg_val = abi_sp->FixDataAddress(reg_val); + if (ReadGPRValue(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP, reg_val)) UnwindLogMsg("fp = 0x%" PRIx64, reg_val); - } - if (ReadGPRValue(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, reg_val)) { - if (abi_sp) - reg_val = abi_sp->FixDataAddress(reg_val); + if (ReadGPRValue(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, reg_val)) UnwindLogMsg("sp = 0x%" PRIx64, reg_val); - } } // A pc of 0x0 means it's the end of the stack crawl unless we're above a trap @@ -1989,32 +1983,31 @@ bool RegisterContextUnwind::ReadFrameAddress( switch (fa.GetValueType()) { case UnwindPlan::Row::FAValue::isRegisterDereferenced: { - RegisterNumber cfa_reg(m_thread, row_register_kind, - fa.GetRegisterNumber()); - if (ReadGPRValue(cfa_reg, cfa_reg_contents)) { + RegisterNumber regnum_to_deref(m_thread, row_register_kind, + fa.GetRegisterNumber()); + addr_t reg_to_deref_contents; + if (ReadGPRValue(regnum_to_deref, reg_to_deref_contents)) { const RegisterInfo *reg_info = - GetRegisterInfoAtIndex(cfa_reg.GetAsKind(eRegisterKindLLDB)); + GetRegisterInfoAtIndex(regnum_to_deref.GetAsKind(eRegisterKindLLDB)); RegisterValue reg_value; if (reg_info) { - if (abi_sp) - cfa_reg_contents = abi_sp->FixDataAddress(cfa_reg_contents); Status error = ReadRegisterValueFromMemory( - reg_info, cfa_reg_contents, reg_info->byte_size, reg_value); + 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, - cfa_reg.GetName(), cfa_reg.GetAsKind(eRegisterKindLLDB), - cfa_reg_contents, address); + regnum_to_deref.GetName(), + regnum_to_deref.GetAsKind(eRegisterKindLLDB), + reg_to_deref_contents, address); return true; } else { UnwindLogMsg("Tried to deref reg %s (%d) [0x%" PRIx64 "] but memory read failed.", - cfa_reg.GetName(), cfa_reg.GetAsKind(eRegisterKindLLDB), - cfa_reg_contents); + regnum_to_deref.GetName(), + regnum_to_deref.GetAsKind(eRegisterKindLLDB), + reg_to_deref_contents); } } } @@ -2024,8 +2017,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( @@ -2060,9 +2051,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; @@ -2102,7 +2090,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; } @@ -2195,9 +2182,6 @@ bool RegisterContextUnwind::ReadGPRValue(lldb::RegisterKind register_kind, if (generic_regnum == LLDB_REGNUM_GENERIC_PC || generic_regnum == LLDB_REGNUM_GENERIC_RA) value = abi_sp->FixCodeAddress(value); - if (generic_regnum == LLDB_REGNUM_GENERIC_SP || - generic_regnum == LLDB_REGNUM_GENERIC_FP) - value = abi_sp->FixDataAddress(value); } return true; } diff --git a/lldb/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp index 1df8b16da8a3d..1530827deab7c 100644 --- a/lldb/source/Target/StackFrame.cpp +++ b/lldb/source/Target/StackFrame.cpp @@ -64,7 +64,8 @@ StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx, const SymbolContext *sc_ptr) : m_thread_wp(thread_sp), m_frame_index(frame_idx), m_concrete_frame_index(unwind_frame_index), m_reg_context_sp(), - m_id(pc, cfa), m_frame_code_addr(pc), m_sc(), m_flags(), m_frame_base(), + m_id(pc, cfa, nullptr, thread_sp->GetProcess().get()), + m_frame_code_addr(pc), m_sc(), m_flags(), m_frame_base(), m_frame_base_error(), m_cfa_is_valid(cfa_is_valid), m_stack_frame_kind(kind), m_behaves_like_zeroth_frame(behaves_like_zeroth_frame), @@ -74,7 +75,7 @@ StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx, // recursive functions properly aren't confused with one another on a history // stack. if (IsHistorical() && !m_cfa_is_valid) { - m_id.SetCFA(m_frame_index); + m_id.SetCFA(m_frame_index, thread_sp->GetProcess().get()); } if (sc_ptr != nullptr) { @@ -90,9 +91,11 @@ StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx, const SymbolContext *sc_ptr) : m_thread_wp(thread_sp), m_frame_index(frame_idx), m_concrete_frame_index(unwind_frame_index), - m_reg_context_sp(reg_context_sp), m_id(pc, cfa), m_frame_code_addr(pc), - m_sc(), m_flags(), m_frame_base(), m_frame_base_error(), - m_cfa_is_valid(true), m_stack_frame_kind(StackFrame::Kind::Regular), + m_reg_context_sp(reg_context_sp), + m_id(pc, cfa, nullptr, thread_sp->GetProcess().get()), + m_frame_code_addr(pc), m_sc(), m_flags(), m_frame_base(), + m_frame_base_error(), m_cfa_is_valid(true), + m_stack_frame_kind(StackFrame::Kind::Regular), m_behaves_like_zeroth_frame(behaves_like_zeroth_frame), m_variable_list_sp(), m_variable_list_value_objects(), m_recognized_frame_sp(), m_disassembly(), m_mutex() { @@ -116,7 +119,8 @@ StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx, : m_thread_wp(thread_sp), m_frame_index(frame_idx), m_concrete_frame_index(unwind_frame_index), m_reg_context_sp(reg_context_sp), - m_id(pc_addr.GetLoadAddress(thread_sp->CalculateTarget().get()), cfa), + m_id(pc_addr.GetLoadAddress(thread_sp->CalculateTarget().get()), cfa, + nullptr, thread_sp->GetProcess().get()), m_frame_code_addr(pc_addr), m_sc(), m_flags(), m_frame_base(), m_frame_base_error(), m_cfa_is_valid(true), m_stack_frame_kind(StackFrame::Kind::Regular), @@ -2002,7 +2006,9 @@ void StackFrame::UpdatePreviousFrameFromCurrentFrame(StackFrame &curr_frame) { std::lock_guard guard(m_mutex); assert(GetStackID() == curr_frame.GetStackID()); // TODO: remove this after some testing - m_id.SetPC(curr_frame.m_id.GetPC()); // Update the Stack ID PC value + m_id.SetPC( + curr_frame.m_id.GetPC(), + curr_frame.CalculateProcess().get()); // Update the Stack ID PC value assert(GetThread() == curr_frame.GetThread()); m_frame_index = curr_frame.m_frame_index; m_concrete_frame_index = curr_frame.m_concrete_frame_index; diff --git a/lldb/source/Target/StackFrameList.cpp b/lldb/source/Target/StackFrameList.cpp index 4af34a61355da..be33e45889ba3 100644 --- a/lldb/source/Target/StackFrameList.cpp +++ b/lldb/source/Target/StackFrameList.cpp @@ -448,7 +448,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. diff --git a/lldb/source/Target/StackID.cpp b/lldb/source/Target/StackID.cpp index 19989d731d42c..640baf4c984e0 100644 --- a/lldb/source/Target/StackID.cpp +++ b/lldb/source/Target/StackID.cpp @@ -14,6 +14,7 @@ #include "lldb/Target/Process.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/LLDBLog.h" +#include "lldb/Target/Process.h" #include "lldb/Utility/Stream.h" using namespace lldb_private; @@ -32,6 +33,25 @@ bool StackID::IsCFAOnStack(Process &process) const { return m_cfa_on_stack == eLazyBoolYes; } +StackID::StackID(lldb::addr_t pc, lldb::addr_t cfa, + SymbolContextScope *symbol_scope, Process *process) + : 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); + } +} + +void StackID::SetPC(lldb::addr_t pc, Process *process) { + m_pc = process ? process->FixCodeAddress(pc) : pc; +} + +void StackID::SetCFA(lldb::addr_t cfa, Process *process) { + m_cfa_with_metadata = cfa; + m_cfa = process ? process->FixDataAddress(cfa) : cfa; +} + void StackID::Dump(Stream *s) { s->Printf("StackID (pc = 0x%16.16" PRIx64 ", cfa = 0x%16.16" PRIx64 ", cfa_on_stack = %d, symbol_scope = %p", @@ -49,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(); @@ -63,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 @@ -125,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; @@ -161,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 diff --git a/lldb/test/API/lang/swift/async/frame/variables_multiple_frames/TestSwiftAsyncFrameVarMultipleFrames.py b/lldb/test/API/lang/swift/async/frame/variables_multiple_frames/TestSwiftAsyncFrameVarMultipleFrames.py index 6a8daf44db31f..8e2578ee8a10b 100644 --- a/lldb/test/API/lang/swift/async/frame/variables_multiple_frames/TestSwiftAsyncFrameVarMultipleFrames.py +++ b/lldb/test/API/lang/swift/async/frame/variables_multiple_frames/TestSwiftAsyncFrameVarMultipleFrames.py @@ -17,11 +17,14 @@ def read_ptr_from_memory(self, process, addr): # Check that the CFA chain is correctly built def check_cfas(self, async_frames, process): - async_cfas = list(map(lambda frame: frame.GetCFA(), async_frames)) + async_cfas = list( + map(lambda frame: process.FixAddress(frame.GetCFA()), async_frames) + ) expected_cfas = [async_cfas[0]] # The CFA chain ends in nullptr. while expected_cfas[-1] != 0: - expected_cfas.append(self.read_ptr_from_memory(process, expected_cfas[-1])) + indirect_ctx = self.read_ptr_from_memory(process, expected_cfas[-1]) + expected_cfas.append(process.FixAddress(indirect_ctx)) self.assertEqual(async_cfas, expected_cfas[:-1]) @@ -36,20 +39,20 @@ 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" cfa = frame.GetCFA() is_indirect = "await resume" in frame.GetFunctionName() - async_register = frame.FindRegister(async_reg_name).GetValueAsUnsigned() - + async_ctx = frame.FindRegister(async_reg_name).GetValueAsUnsigned() if is_indirect: - deref_async_reg = self.read_ptr_from_memory(process, async_register) - self.assertEqual(deref_async_reg, cfa) - else: - self.assertEqual(async_register, cfa) + async_ctx = self.read_ptr_from_memory(process, async_ctx) + self.assertEqual(process.FixAddress(async_ctx), process.FixAddress(cfa)) def check_async_regs(self, async_frames, process): for frame in async_frames: diff --git a/lldb/test/API/lang/swift/async/unwind/backtrace_locals/TestSwiftAsyncBacktraceLocals.py b/lldb/test/API/lang/swift/async/unwind/backtrace_locals/TestSwiftAsyncBacktraceLocals.py index 928e6f91cda29..6568eb5543b52 100644 --- a/lldb/test/API/lang/swift/async/unwind/backtrace_locals/TestSwiftAsyncBacktraceLocals.py +++ b/lldb/test/API/lang/swift/async/unwind/backtrace_locals/TestSwiftAsyncBacktraceLocals.py @@ -75,8 +75,8 @@ def run_fibo_tests(self, target, process): # The PC of a logical frame is stored in its "callee" # AsyncContext as the second pointer field. error = lldb.SBError() - ret_addr = process.ReadPointerFromMemory( - cfa[fibonacci_number-1] + target.addr_size, error) + ret_addr = process.FixAddress(process.ReadPointerFromMemory( + cfa[fibonacci_number-1] + target.addr_size, error)) prologue_to_skip = frame.GetFunction().GetPrologueByteSize() self.assertSuccess(error, "Managed to read context memory") self.assertEqual(ret_addr + prologue_to_skip, frame.GetPC()) diff --git a/lldb/test/API/lang/swift/async/unwind/unwind_in_all_instructions/TestSwiftAsyncUnwindAllInstructions.py b/lldb/test/API/lang/swift/async/unwind/unwind_in_all_instructions/TestSwiftAsyncUnwindAllInstructions.py index 5ea9ee0144195..e46a8e49307ca 100644 --- a/lldb/test/API/lang/swift/async/unwind/unwind_in_all_instructions/TestSwiftAsyncUnwindAllInstructions.py +++ b/lldb/test/API/lang/swift/async/unwind/unwind_in_all_instructions/TestSwiftAsyncUnwindAllInstructions.py @@ -186,4 +186,4 @@ def test(self): # have some sanity check that we have hit at least a decent chunk of # them. breakpoints_not_hit = len(breakpoints) - self.assertLess(breakpoints_not_hit / num_breakpoints, 0.10) + self.assertLess(breakpoints_not_hit / num_breakpoints, 0.15) diff --git a/lldb/test/API/lang/swift/async/unwind/unwind_recursive_q_funclets/TestSwiftAsyncUnwindRecursiveQFunclets.py b/lldb/test/API/lang/swift/async/unwind/unwind_recursive_q_funclets/TestSwiftAsyncUnwindRecursiveQFunclets.py index 09a5603736b38..4a7d0273e1581 100644 --- a/lldb/test/API/lang/swift/async/unwind/unwind_recursive_q_funclets/TestSwiftAsyncUnwindRecursiveQFunclets.py +++ b/lldb/test/API/lang/swift/async/unwind/unwind_recursive_q_funclets/TestSwiftAsyncUnwindRecursiveQFunclets.py @@ -12,6 +12,7 @@ class TestCase(lldbtest.TestBase): @swiftTest @skipIf(oslist=["windows", "linux"]) + @skipIf(archs=["arm64e"]) def test(self): """Test that the debugger can unwind at all instructions of all funclets""" self.build() diff --git a/lldb/test/API/lang/swift/other_arch_dylib/TestSwiftOtherArchDylib.py b/lldb/test/API/lang/swift/other_arch_dylib/TestSwiftOtherArchDylib.py index 872cfe9d70392..fbeb7c99eafe2 100644 --- a/lldb/test/API/lang/swift/other_arch_dylib/TestSwiftOtherArchDylib.py +++ b/lldb/test/API/lang/swift/other_arch_dylib/TestSwiftOtherArchDylib.py @@ -13,7 +13,7 @@ class TestSwiftOtherArchDylib(TestBase): @skipUnlessDarwin @skipIfDarwinEmbedded @skipIf(archs=no_match(["arm64"])) - @skipIf(archs=["arm64"], bugnumber="the swift.org toolchain cannot produce arm64e binaries") + @skipIf(archs=["arm64e"], bugnumber="the swift.org toolchain cannot produce arm64e binaries") def test(self): """Test module import from dylibs with an architecture that uses a different SDK""" diff --git a/lldb/test/API/macosx/arm-pointer-metadata-cfa-dwarf-expr/Makefile b/lldb/test/API/macosx/arm-pointer-metadata-cfa-dwarf-expr/Makefile new file mode 100644 index 0000000000000..f0de8ffca59fc --- /dev/null +++ b/lldb/test/API/macosx/arm-pointer-metadata-cfa-dwarf-expr/Makefile @@ -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 diff --git a/lldb/test/API/macosx/arm-pointer-metadata-cfa-dwarf-expr/TestArmPointerMetadataCFADwarfExpr.py b/lldb/test/API/macosx/arm-pointer-metadata-cfa-dwarf-expr/TestArmPointerMetadataCFADwarfExpr.py new file mode 100644 index 0000000000000..839e0e1a4fc4d --- /dev/null +++ b/lldb/test/API/macosx/arm-pointer-metadata-cfa-dwarf-expr/TestArmPointerMetadataCFADwarfExpr.py @@ -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) diff --git a/lldb/test/API/macosx/arm-pointer-metadata-cfa-dwarf-expr/main.s b/lldb/test/API/macosx/arm-pointer-metadata-cfa-dwarf-expr/main.s new file mode 100644 index 0000000000000..0825c5ddd08b5 --- /dev/null +++ b/lldb/test/API/macosx/arm-pointer-metadata-cfa-dwarf-expr/main.s @@ -0,0 +1,226 @@ +; The assembly below corresponds to this program: +; __attribute__((nodebug)) +; int foo() { +; return 10; +; } +; int main(int argc, char **argv) { +; foo(); +; return 0; +; } +; +; The assembly was edited in two places (search for "EDIT"): +; 1. A "orr x29, x29, #0x1000000000000000" instruction was added in foo. This +; effectively changes the CFA value of the frame above foo (i.e. main). +; 2. In main, the DWARF location of `argv` was changed to DW_AT_call_frame_cfa. +; +; This allows us to stop in foo, go to frame 1 (main) and do `v &argv`, +; obtaining the result of evaluating DW_AT_call_frame_cfa. + + .section __TEXT,__text,regular,pure_instructions + .globl _foo ; -- Begin function foo + .p2align 2 +_foo: ; @foo +Lfunc_begin0: + .cfi_startproc + orr x29, x29, #0x1000000000000000 ; EDIT: Set top byte of fp. + stp x29, x30, [sp, #-16]! ; 16-byte Folded Spill + mov x29, sp + .cfi_def_cfa w29, 16 + .cfi_offset w30, -8 + .cfi_offset w29, -16 + mov w0, #10 ; =0xa + ldp x29, x30, [sp], #16 ; 16-byte Folded Reload + ret +Lfunc_end0: + .cfi_endproc + ; -- End function + .globl _main ; -- Begin function main + .p2align 2 +_main: ; @main +Lfunc_begin1: + .file 1 "/test" "test.c" + .loc 1 6 0 ; test.c:6:0 + .cfi_startproc + sub sp, sp, #48 + stp x29, x30, [sp, #32] ; 16-byte Folded Spill + add x29, sp, #32 + .cfi_def_cfa w29, 16 + .cfi_offset w30, -8 + .cfi_offset w29, -16 + mov w8, #0 ; =0x0 + str w8, [sp, #12] ; 4-byte Folded Spill + stur wzr, [x29, #-4] + stur w0, [x29, #-8] + str x1, [sp, #16] +Ltmp0: + bl _foo + ldr w0, [sp, #12] ; 4-byte Folded Reload + ldp x29, x30, [sp, #32] ; 16-byte Folded Reload + add sp, sp, #48 + ret +Ltmp1: +Lfunc_end1: + .cfi_endproc + ; -- End function + .section __DWARF,__debug_abbrev,regular,debug +Lsection_abbrev: + .byte 1 ; Abbreviation Code + .byte 17 ; DW_TAG_compile_unit + .byte 1 ; DW_CHILDREN_yes + .byte 37 ; DW_AT_producer + .byte 14 ; DW_FORM_strp + .byte 19 ; DW_AT_language + .byte 5 ; DW_FORM_data2 + .byte 3 ; DW_AT_name + .byte 14 ; DW_FORM_strp + .ascii "\202|" ; DW_AT_LLVM_sysroot + .byte 14 ; DW_FORM_strp + .ascii "\357\177" ; DW_AT_APPLE_sdk + .byte 14 ; DW_FORM_strp + .byte 16 ; DW_AT_stmt_list + .byte 23 ; DW_FORM_sec_offset + .byte 27 ; DW_AT_comp_dir + .byte 14 ; DW_FORM_strp + .byte 17 ; DW_AT_low_pc + .byte 1 ; DW_FORM_addr + .byte 18 ; DW_AT_high_pc + .byte 6 ; DW_FORM_data4 + .byte 0 ; EOM(1) + .byte 0 ; EOM(2) + .byte 2 ; Abbreviation Code + .byte 46 ; DW_TAG_subprogram + .byte 1 ; DW_CHILDREN_yes + .byte 17 ; DW_AT_low_pc + .byte 1 ; DW_FORM_addr + .byte 18 ; DW_AT_high_pc + .byte 6 ; DW_FORM_data4 + .byte 64 ; DW_AT_frame_base + .byte 24 ; DW_FORM_exprloc + .byte 3 ; DW_AT_name + .byte 14 ; DW_FORM_strp + .byte 58 ; DW_AT_decl_file + .byte 11 ; DW_FORM_data1 + .byte 59 ; DW_AT_decl_line + .byte 11 ; DW_FORM_data1 + .byte 39 ; DW_AT_prototyped + .byte 25 ; DW_FORM_flag_present + .byte 73 ; DW_AT_type + .byte 19 ; DW_FORM_ref4 + .byte 63 ; DW_AT_external + .byte 25 ; DW_FORM_flag_present + .byte 0 ; EOM(1) + .byte 0 ; EOM(2) + .byte 3 ; Abbreviation Code + .byte 5 ; DW_TAG_formal_parameter + .byte 0 ; DW_CHILDREN_no + .byte 2 ; DW_AT_location + .byte 24 ; DW_FORM_exprloc + .byte 3 ; DW_AT_name + .byte 14 ; DW_FORM_strp + .byte 58 ; DW_AT_decl_file + .byte 11 ; DW_FORM_data1 + .byte 59 ; DW_AT_decl_line + .byte 11 ; DW_FORM_data1 + .byte 73 ; DW_AT_type + .byte 19 ; DW_FORM_ref4 + .byte 0 ; EOM(1) + .byte 0 ; EOM(2) + .byte 4 ; Abbreviation Code + .byte 36 ; DW_TAG_base_type + .byte 0 ; DW_CHILDREN_no + .byte 3 ; DW_AT_name + .byte 14 ; DW_FORM_strp + .byte 62 ; DW_AT_encoding + .byte 11 ; DW_FORM_data1 + .byte 11 ; DW_AT_byte_size + .byte 11 ; DW_FORM_data1 + .byte 0 ; EOM(1) + .byte 0 ; EOM(2) + .byte 5 ; Abbreviation Code + .byte 15 ; DW_TAG_pointer_type + .byte 0 ; DW_CHILDREN_no + .byte 73 ; DW_AT_type + .byte 19 ; DW_FORM_ref4 + .byte 0 ; EOM(1) + .byte 0 ; EOM(2) + .byte 0 ; EOM(3) + .section __DWARF,__debug_info,regular,debug +Lsection_info: +Lcu_begin0: +.set Lset0, Ldebug_info_end0-Ldebug_info_start0 ; Length of Unit + .long Lset0 +Ldebug_info_start0: + .short 4 ; DWARF version number +.set Lset1, Lsection_abbrev-Lsection_abbrev ; Offset Into Abbrev. Section + .long Lset1 + .byte 8 ; Address Size (in bytes) + .byte 1 ; Abbrev [1] 0xb:0x76 DW_TAG_compile_unit + .long 0 ; DW_AT_producer + .short 12 ; DW_AT_language + .long 47 ; DW_AT_name + .long 54 ; DW_AT_LLVM_sysroot + .long 165 ; DW_AT_APPLE_sdk +.set Lset2, Lline_table_start0-Lsection_line ; DW_AT_stmt_list + .long Lset2 + .long 180 ; DW_AT_comp_dir + .quad Lfunc_begin1 ; DW_AT_low_pc +.set Lset3, Lfunc_end1-Lfunc_begin1 ; DW_AT_high_pc + .long Lset3 + .byte 2 ; Abbrev [2] 0x32:0x36 DW_TAG_subprogram + .quad Lfunc_begin1 ; DW_AT_low_pc +.set Lset4, Lfunc_end1-Lfunc_begin1 ; DW_AT_high_pc + .long Lset4 + .byte 1 ; DW_AT_frame_base + .byte 109 + .long 247 ; DW_AT_name + .byte 1 ; DW_AT_decl_file + .byte 6 ; DW_AT_decl_line + ; DW_AT_prototyped + .long 107 ; DW_AT_type + ; DW_AT_external + .byte 3 ; Abbrev [3] 0x4b:0xe DW_TAG_formal_parameter + .byte 2 ; DW_AT_location + .byte 145 + .byte 120 + .long 256 ; DW_AT_name + .byte 1 ; DW_AT_decl_file + .byte 6 ; DW_AT_decl_line + .long 103 ; DW_AT_type + .byte 3 ; Abbrev [3] 0x59:0xe DW_TAG_formal_parameter + .byte 1 ; DW_AT_location + .byte 0x9c ; EDIT: DW_AT_call_frame_cfa + .long 261 ; DW_AT_name + .byte 1 ; DW_AT_decl_file + .byte 6 ; DW_AT_decl_line + .long 110 ; DW_AT_type + .byte 0 ; End Of Children Mark + .byte 4 ; Abbrev [4] 0x68:0x7 DW_TAG_base_type + .long 252 ; DW_AT_name + .byte 5 ; DW_AT_encoding + .byte 4 ; DW_AT_byte_size + .byte 5 ; Abbrev [5] 0x6f:0x5 DW_TAG_pointer_type + .long 115 ; DW_AT_type + .byte 5 ; Abbrev [5] 0x74:0x5 DW_TAG_pointer_type + .long 120 ; DW_AT_type + .byte 4 ; Abbrev [4] 0x79:0x7 DW_TAG_base_type + .long 266 ; DW_AT_name + .byte 6 ; DW_AT_encoding + .byte 1 ; DW_AT_byte_size + .byte 0 ; End Of Children Mark +Ldebug_info_end0: + .section __DWARF,__debug_str,regular,debug +Linfo_string: + .asciz "Apple clang " ; string offset=0 + .asciz "test.c" ; string offset=47 + .asciz "/Applications/Xcode..........................................................................................." ; string offset=54 + .asciz ".............." ; string offset=165 + .asciz "......................................................../llvm_src1" ; string offset=180 + .asciz "main" ; string offset=247 + .asciz "int" ; string offset=252 + .asciz "argc" ; string offset=256 + .asciz "argv" ; string offset=261 + .asciz "char" ; string offset=266 +.subsections_via_symbols + .section __DWARF,__debug_line,regular,debug +Lsection_line: +Lline_table_start0: diff --git a/lldb/test/API/macosx/arm-pointer-metadata-stripping/Makefile b/lldb/test/API/macosx/arm-pointer-metadata-stripping/Makefile new file mode 100644 index 0000000000000..c9319d6e6888a --- /dev/null +++ b/lldb/test/API/macosx/arm-pointer-metadata-stripping/Makefile @@ -0,0 +1,2 @@ +C_SOURCES := main.c +include Makefile.rules diff --git a/lldb/test/API/macosx/arm-pointer-metadata-stripping/TestArmPointerMetadataStripping.py b/lldb/test/API/macosx/arm-pointer-metadata-stripping/TestArmPointerMetadataStripping.py new file mode 100644 index 0000000000000..2fb83485542c0 --- /dev/null +++ b/lldb/test/API/macosx/arm-pointer-metadata-stripping/TestArmPointerMetadataStripping.py @@ -0,0 +1,56 @@ +import lldb +import json +import os +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +@skip +@skipUnlessDarwin +@skipIf(archs=no_match(["arm64", "arm64e"])) +class TestArmPointerMetadataStripping(TestBase): + # Use extra_symbols.json as a template to add a new symbol whose address + # contains non-zero high order bits set. + def create_symbols_file(self): + template_path = os.path.join(self.getSourceDir(), "extra_symbols.json") + with open(template_path, "r") as f: + symbols_data = json.load(f) + + target = self.dbg.GetSelectedTarget() + symbols_data["triple"] = target.GetTriple() + + module = target.GetModuleAtIndex(0) + symbols_data["uuid"] = module.GetUUIDString() + + json_filename = self.getBuildArtifact("extra_symbols.json") + with open(json_filename, "w") as file: + json.dump(symbols_data, file, indent=4) + + return json_filename + + def test(self): + self.build() + src = lldb.SBFileSpec("main.c") + target, process, thread, bkpt = lldbutil.run_to_source_breakpoint( + self, "break here", src + ) + + symbols_file = self.create_symbols_file() + self.runCmd(f"target module add {symbols_file}") + + # The address of myglobal_json is: 0x1200AAAAAAAB1014 + # The high order bits should be stripped. + # On Darwin platforms, the lower nibble of the most significant byte is preserved. + if platform.system() == "Darwin": + expected_value = str(0x200000000000000) + else: + expected_value = "0" + + self.expect_expr("get_high_bits(&myglobal_json)", result_value=expected_value) + + # Mark all bits as used for addresses and ensure bits are no longer stripped. + self.runCmd("settings set target.process.virtual-addressable-bits 64") + self.expect_expr( + "get_high_bits(&myglobal_json)", result_value=str(0x1200000000000000) + ) diff --git a/lldb/test/API/macosx/arm-pointer-metadata-stripping/extra_symbols.json b/lldb/test/API/macosx/arm-pointer-metadata-stripping/extra_symbols.json new file mode 100644 index 0000000000000..5c2503d508b42 --- /dev/null +++ b/lldb/test/API/macosx/arm-pointer-metadata-stripping/extra_symbols.json @@ -0,0 +1,21 @@ +{ + "triple": "replace me", + "uuid": "replace me", + "type": "executable", + "sections": [ + { + "name": "__DATA", + "type": "data", + "address": 1297224342667202580, + "size": 16 + } + ], + "symbols": [ + { + "name": "myglobal_json", + "size": 8, + "type": "data", + "address": 1297224342667202580 + } + ] +} diff --git a/lldb/test/API/macosx/arm-pointer-metadata-stripping/main.c b/lldb/test/API/macosx/arm-pointer-metadata-stripping/main.c new file mode 100644 index 0000000000000..05a85133caf72 --- /dev/null +++ b/lldb/test/API/macosx/arm-pointer-metadata-stripping/main.c @@ -0,0 +1,13 @@ +#include + +uintptr_t get_high_bits(void *ptr) { + uintptr_t address_bits = 56; + uintptr_t mask = ~((1ULL << address_bits) - 1); + uintptr_t ptrtoint = (uintptr_t)ptr; + uintptr_t high_bits = ptrtoint & mask; + return high_bits; +} + +int main() { + return 0; // break here +} diff --git a/lldb/test/API/tools/lldb-dap/stackTraceMissingFunctionName/TestDAP_stackTraceMissingFunctionName.py b/lldb/test/API/tools/lldb-dap/stackTraceMissingFunctionName/TestDAP_stackTraceMissingFunctionName.py index f2131d6a82121..bfc88a5275e9b 100644 --- a/lldb/test/API/tools/lldb-dap/stackTraceMissingFunctionName/TestDAP_stackTraceMissingFunctionName.py +++ b/lldb/test/API/tools/lldb-dap/stackTraceMissingFunctionName/TestDAP_stackTraceMissingFunctionName.py @@ -8,6 +8,8 @@ class TestDAP_stackTraceMissingFunctionName(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows + # Jumping to address 0 will fail PAC signing before crashign on a bad frame. + @skipIf(archs=["arm64e"]) def test_missingFunctionName(self): """ Test that the stack frame without a function name is given its pc in the response. diff --git a/lldb/unittests/StackID/StackIDTest.cpp b/lldb/unittests/StackID/StackIDTest.cpp index de62f3cd9b4d2..9d5ab45fb8c97 100644 --- a/lldb/unittests/StackID/StackIDTest.cpp +++ b/lldb/unittests/StackID/StackIDTest.cpp @@ -68,8 +68,8 @@ enum OnStack { Yes, No }; /// Helper class to enable testing StackID::IsYounger. struct MockStackID : StackID { MockStackID(addr_t cfa, OnStack on_stack) : StackID() { - SetPC(0); - SetCFA(cfa); + SetPC(0, nullptr); + SetCFA(cfa, nullptr); m_cfa_on_stack = on_stack == OnStack::Yes ? LazyBool::eLazyBoolYes : LazyBool::eLazyBoolNo; }