[Lldb-commits] [lldb] 66902a3 - [StopInfoMachException] Summarize arm64e BLRAx/LDRAx auth failures
Vedant Kumar via lldb-commits
lldb-commits at lists.llvm.org
Tue Sep 14 14:04:53 PDT 2021
Author: Vedant Kumar
Date: 2021-09-14T13:31:52-07:00
New Revision: 66902a32c83809d26662f76e4107d5dd777610c3
URL: https://github.com/llvm/llvm-project/commit/66902a32c83809d26662f76e4107d5dd777610c3
DIFF: https://github.com/llvm/llvm-project/commit/66902a32c83809d26662f76e4107d5dd777610c3.diff
LOG: [StopInfoMachException] Summarize arm64e BLRAx/LDRAx auth failures
Upstream lldb support for summarizing BLRAx and LDRAx auth failures.
rdar://41615322
Differential Revision: https://reviews.llvm.org/D102428
Added:
lldb/test/API/functionalities/ptrauth_diagnostics/BLRAA_error/Makefile
lldb/test/API/functionalities/ptrauth_diagnostics/BLRAA_error/TestPtrauthBLRAADiagnostic.py
lldb/test/API/functionalities/ptrauth_diagnostics/BLRAA_error/blraa.c
lldb/test/API/functionalities/ptrauth_diagnostics/BRAA_error/Makefile
lldb/test/API/functionalities/ptrauth_diagnostics/BRAA_error/TestPtrauthBRAADiagnostic.py
lldb/test/API/functionalities/ptrauth_diagnostics/BRAA_error/braa.c
lldb/test/API/functionalities/ptrauth_diagnostics/LDRAA_error/Makefile
lldb/test/API/functionalities/ptrauth_diagnostics/LDRAA_error/TestPtrauthLDRAADiagnostic.py
lldb/test/API/functionalities/ptrauth_diagnostics/LDRAA_error/ldraa.c
lldb/test/API/functionalities/ptrauth_diagnostics/brkC47x_code/Makefile
lldb/test/API/functionalities/ptrauth_diagnostics/brkC47x_code/TestPtrauthBRKc47xDiagnostic.py
lldb/test/API/functionalities/ptrauth_diagnostics/brkC47x_code/brkC47x.c
lldb/test/API/functionalities/ptrauth_diagnostics/brkC47x_x16_invalid/Makefile
lldb/test/API/functionalities/ptrauth_diagnostics/brkC47x_x16_invalid/TestPtrauthBRKc47xX16Invalid.py
lldb/test/API/functionalities/ptrauth_diagnostics/brkC47x_x16_invalid/brkC47x.c
Modified:
lldb/include/lldb/Core/Address.h
lldb/include/lldb/Core/Disassembler.h
lldb/source/Core/Address.cpp
lldb/source/Core/Disassembler.cpp
lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp
lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp
lldb/source/Plugins/Process/Utility/StopInfoMachException.h
Removed:
################################################################################
diff --git a/lldb/include/lldb/Core/Address.h b/lldb/include/lldb/Core/Address.h
index ec393a1871e35..dc50e27ca277a 100644
--- a/lldb/include/lldb/Core/Address.h
+++ b/lldb/include/lldb/Core/Address.h
@@ -210,6 +210,10 @@ class Address {
}
};
+ /// Write a description of this object to a Stream.
+ bool GetDescription(Stream &s, Target &target,
+ lldb::DescriptionLevel level) const;
+
/// Dump a description of this object to a Stream.
///
/// Dump a description of the contents of this object to the supplied stream
diff --git a/lldb/include/lldb/Core/Disassembler.h b/lldb/include/lldb/Core/Disassembler.h
index 622c23ff64928..0925bf358b9c3 100644
--- a/lldb/include/lldb/Core/Disassembler.h
+++ b/lldb/include/lldb/Core/Disassembler.h
@@ -150,6 +150,10 @@ class Instruction {
virtual bool HasDelaySlot();
+ virtual bool IsLoad() = 0;
+
+ virtual bool IsAuthenticated() = 0;
+
bool CanSetBreakpoint ();
virtual size_t Decode(const Disassembler &disassembler,
@@ -336,6 +340,10 @@ class PseudoInstruction : public Instruction {
bool HasDelaySlot() override;
+ bool IsLoad() override;
+
+ bool IsAuthenticated() override;
+
void CalculateMnemonicOperandsAndComment(
const ExecutionContext *exe_ctx) override {
// TODO: fill this in and put opcode name into Instruction::m_opcode_name,
diff --git a/lldb/source/Core/Address.cpp b/lldb/source/Core/Address.cpp
index f0c7e2b34f99c..122bed924b420 100644
--- a/lldb/source/Core/Address.cpp
+++ b/lldb/source/Core/Address.cpp
@@ -389,6 +389,19 @@ bool Address::SetOpcodeLoadAddress(lldb::addr_t load_addr, Target *target,
return false;
}
+bool Address::GetDescription(Stream &s, Target &target,
+ DescriptionLevel level) const {
+ assert(level == eDescriptionLevelBrief &&
+ "Non-brief descriptions not implemented");
+ LineEntry line_entry;
+ if (CalculateSymbolContextLineEntry(line_entry)) {
+ s.Printf(" (%s:%u:%u)", line_entry.file.GetFilename().GetCString(),
+ line_entry.line, line_entry.column);
+ return true;
+ }
+ return false;
+}
+
bool Address::Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style,
DumpStyle fallback_style, uint32_t addr_size) const {
// If the section was nullptr, only load address is going to work unless we
diff --git a/lldb/source/Core/Disassembler.cpp b/lldb/source/Core/Disassembler.cpp
index 704b3df4b2ac8..d147f8fbb0dba 100644
--- a/lldb/source/Core/Disassembler.cpp
+++ b/lldb/source/Core/Disassembler.cpp
@@ -1123,6 +1123,10 @@ bool PseudoInstruction::HasDelaySlot() {
return false;
}
+bool PseudoInstruction::IsLoad() { return false; }
+
+bool PseudoInstruction::IsAuthenticated() { return false; }
+
size_t PseudoInstruction::Decode(const lldb_private::Disassembler &disassembler,
const lldb_private::DataExtractor &data,
lldb::offset_t data_offset) {
diff --git a/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp b/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp
index 3c83b1a9e17e4..fcd5aa5159d7f 100644
--- a/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp
+++ b/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp
@@ -61,6 +61,8 @@ class DisassemblerLLVMC::MCDisasmInstance {
bool CanBranch(llvm::MCInst &mc_inst) const;
bool HasDelaySlot(llvm::MCInst &mc_inst) const;
bool IsCall(llvm::MCInst &mc_inst) const;
+ bool IsLoad(llvm::MCInst &mc_inst) const;
+ bool IsAuthenticated(llvm::MCInst &mc_inst) const;
private:
MCDisasmInstance(std::unique_ptr<llvm::MCInstrInfo> &&instr_info_up,
@@ -102,6 +104,16 @@ class InstructionLLVMC : public lldb_private::Instruction {
return m_has_delay_slot;
}
+ bool IsLoad() override {
+ VisitInstruction();
+ return m_is_load;
+ }
+
+ bool IsAuthenticated() override {
+ VisitInstruction();
+ return m_is_authenticated;
+ }
+
DisassemblerLLVMC::MCDisasmInstance *GetDisasmToUse(bool &is_alternate_isa) {
DisassemblerScope disasm(*this);
return GetDisasmToUse(is_alternate_isa, disasm);
@@ -817,9 +829,13 @@ class InstructionLLVMC : public lldb_private::Instruction {
// - Might branch
// - Does not have a delay slot
// - Is not a call
+ // - Is not a load
+ // - Is not an authenticated instruction
bool m_does_branch = true;
bool m_has_delay_slot = false;
bool m_is_call = false;
+ bool m_is_load = false;
+ bool m_is_authenticated = false;
void VisitInstruction() {
if (m_has_visited_instruction)
@@ -849,6 +865,8 @@ class InstructionLLVMC : public lldb_private::Instruction {
m_does_branch = mc_disasm_ptr->CanBranch(inst);
m_has_delay_slot = mc_disasm_ptr->HasDelaySlot(inst);
m_is_call = mc_disasm_ptr->IsCall(inst);
+ m_is_load = mc_disasm_ptr->IsLoad(inst);
+ m_is_authenticated = mc_disasm_ptr->IsAuthenticated(inst);
}
private:
@@ -1027,6 +1045,27 @@ bool DisassemblerLLVMC::MCDisasmInstance::IsCall(llvm::MCInst &mc_inst) const {
return m_instr_info_up->get(mc_inst.getOpcode()).isCall();
}
+bool DisassemblerLLVMC::MCDisasmInstance::IsLoad(llvm::MCInst &mc_inst) const {
+ return m_instr_info_up->get(mc_inst.getOpcode()).mayLoad();
+}
+
+bool DisassemblerLLVMC::MCDisasmInstance::IsAuthenticated(
+ llvm::MCInst &mc_inst) const {
+ auto InstrDesc = m_instr_info_up->get(mc_inst.getOpcode());
+
+ // Treat software auth traps (brk 0xc470 + aut key, where 0x70 == 'p', 0xc4
+ // == 'a' + 'c') as authenticated instructions for reporting purposes, in
+ // addition to the standard authenticated instructions specified in ARMv8.3.
+ bool IsBrkC47x = false;
+ if (InstrDesc.isTrap() && mc_inst.getNumOperands() == 1) {
+ const llvm::MCOperand &Op0 = mc_inst.getOperand(0);
+ if (Op0.isImm() && Op0.getImm() >= 0xc470 && Op0.getImm() <= 0xc474)
+ IsBrkC47x = true;
+ }
+
+ return InstrDesc.isAuthenticated() || IsBrkC47x;
+}
+
DisassemblerLLVMC::DisassemblerLLVMC(const ArchSpec &arch,
const char *flavor_string)
: Disassembler(arch, flavor_string), m_exe_ctx(nullptr), m_inst(nullptr),
diff --git a/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp b/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp
index 85785a20354d5..4df210032153f 100644
--- a/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp
+++ b/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp
@@ -17,6 +17,7 @@
#include "lldb/Breakpoint/Watchpoint.h"
#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/ABI.h"
#include "lldb/Target/DynamicLoader.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
@@ -30,6 +31,182 @@
using namespace lldb;
using namespace lldb_private;
+/// Information about a pointer-authentication related instruction.
+struct PtrauthInstructionInfo {
+ bool IsAuthenticated;
+ bool IsLoad;
+ bool DoesBranch;
+};
+
+/// Get any pointer-authentication related information about the instruction
+/// at address \p at_addr.
+static llvm::Optional<PtrauthInstructionInfo>
+GetPtrauthInstructionInfo(Target &target, const ArchSpec &arch,
+ const Address &at_addr) {
+ const char *plugin_name = nullptr;
+ const char *flavor = nullptr;
+ AddressRange range_bounds(at_addr, 4);
+ const bool prefer_file_cache = true;
+ DisassemblerSP disassembler_sp = Disassembler::DisassembleRange(
+ arch, plugin_name, flavor, target, range_bounds, prefer_file_cache);
+ if (!disassembler_sp)
+ return llvm::None;
+
+ InstructionList &insn_list = disassembler_sp->GetInstructionList();
+ InstructionSP insn = insn_list.GetInstructionAtIndex(0);
+ if (!insn)
+ return llvm::None;
+
+ return PtrauthInstructionInfo{insn->IsAuthenticated(), insn->IsLoad(),
+ insn->DoesBranch()};
+}
+
+/// Describe the load address of \p addr using the format filename:line:col.
+static void DescribeAddressBriefly(Stream &strm, const Address &addr,
+ Target &target) {
+ strm.Printf("at address=0x%" PRIx64, addr.GetLoadAddress(&target));
+ StreamString s;
+ if (addr.GetDescription(s, target, eDescriptionLevelBrief))
+ strm.Printf(" %s", s.GetString().data());
+ strm.Printf(".\n");
+}
+
+bool StopInfoMachException::DeterminePtrauthFailure(ExecutionContext &exe_ctx) {
+ bool IsBreakpoint = m_value == 6; // EXC_BREAKPOINT
+ bool IsBadAccess = m_value == 1; // EXC_BAD_ACCESS
+ if (!IsBreakpoint && !IsBadAccess)
+ return false;
+
+ // Check that we have a live process.
+ if (!exe_ctx.HasProcessScope() || !exe_ctx.HasThreadScope() ||
+ !exe_ctx.HasTargetScope())
+ return false;
+
+ Thread &thread = *exe_ctx.GetThreadPtr();
+ StackFrameSP current_frame = thread.GetStackFrameAtIndex(0);
+ if (!current_frame)
+ return false;
+
+ Target &target = *exe_ctx.GetTargetPtr();
+ Process &process = *exe_ctx.GetProcessPtr();
+ ABISP abi_sp = process.GetABI();
+ const ArchSpec &arch = target.GetArchitecture();
+ assert(abi_sp && "Missing ABI info");
+
+ // Check for a ptrauth-enabled target.
+ const bool ptrauth_enabled_target =
+ arch.GetCore() == ArchSpec::eCore_arm_arm64e;
+ if (!ptrauth_enabled_target)
+ return false;
+
+ // Set up a stream we can write a diagnostic into.
+ StreamString strm;
+ auto emit_ptrauth_prologue = [&](uint64_t at_address) {
+ strm.Printf("EXC_BAD_ACCESS (code=%" PRIu64 ", address=0x%" PRIx64 ")\n",
+ m_exc_code, at_address);
+ strm.Printf("Note: Possible pointer authentication failure detected.\n");
+ };
+
+ // Check if we have a "brk 0xc47x" trap, where the value that failed to
+ // authenticate is in x16.
+ Address current_address = current_frame->GetFrameCodeAddress();
+ if (IsBreakpoint) {
+ RegisterContext *reg_ctx = exe_ctx.GetRegisterContext();
+ if (!reg_ctx)
+ return false;
+
+ const RegisterInfo *X16Info = reg_ctx->GetRegisterInfoByName("x16");
+ RegisterValue X16Val;
+ if (!reg_ctx->ReadRegister(X16Info, X16Val))
+ return false;
+ uint64_t bad_address = X16Val.GetAsUInt64();
+
+ uint64_t fixed_bad_address = abi_sp->FixCodeAddress(bad_address);
+ Address brk_address;
+ if (!target.ResolveLoadAddress(fixed_bad_address, brk_address))
+ return false;
+
+ auto brk_ptrauth_info =
+ GetPtrauthInstructionInfo(target, arch, current_address);
+ if (brk_ptrauth_info && brk_ptrauth_info->IsAuthenticated) {
+ emit_ptrauth_prologue(bad_address);
+ strm.Printf("Found value that failed to authenticate ");
+ DescribeAddressBriefly(strm, brk_address, target);
+ m_description = std::string(strm.GetString());
+ return true;
+ }
+ return false;
+ }
+
+ assert(IsBadAccess && "Handle EXC_BAD_ACCESS only after this point");
+
+ // Check that we have the "bad address" from an EXC_BAD_ACCESS.
+ if (m_exc_data_count < 2)
+ return false;
+
+ // Ok, we know the Target is valid and that it describes a ptrauth-enabled
+ // device. Now, we need to determine whether this exception was caused by a
+ // ptrauth failure.
+
+ uint64_t bad_address = m_exc_subcode;
+ uint64_t fixed_bad_address = abi_sp->FixCodeAddress(bad_address);
+ uint64_t current_pc = current_address.GetLoadAddress(&target);
+
+ // Detect: LDRAA, LDRAB (Load Register, with pointer authentication).
+ //
+ // If an authenticated load results in an exception, the instruction at the
+ // current PC should be one of LDRAx.
+ if (bad_address != current_pc && fixed_bad_address != current_pc) {
+ auto ptrauth_info =
+ GetPtrauthInstructionInfo(target, arch, current_address);
+ if (ptrauth_info && ptrauth_info->IsAuthenticated && ptrauth_info->IsLoad) {
+ emit_ptrauth_prologue(bad_address);
+ strm.Printf("Found authenticated load instruction ");
+ DescribeAddressBriefly(strm, current_address, target);
+ m_description = std::string(strm.GetString());
+ return true;
+ }
+ }
+
+ // Detect: BLRAA, BLRAAZ, BLRAB, BLRABZ (Branch with Link to Register, with
+ // pointer authentication).
+ //
+ // TODO: Detect: BRAA, BRAAZ, BRAB, BRABZ (Branch to Register, with pointer
+ // authentication). At a minimum, this requires call site info support for
+ // indirect calls.
+ //
+ // If an authenticated call or tail call results in an exception, stripping
+ // the bad address should give the current PC, which points to the address
+ // we tried to branch to.
+ if (bad_address != current_pc && fixed_bad_address == current_pc) {
+ if (StackFrameSP parent_frame = thread.GetStackFrameAtIndex(1)) {
+ addr_t return_pc =
+ parent_frame->GetFrameCodeAddress().GetLoadAddress(&target);
+ Address blr_address;
+ if (!target.ResolveLoadAddress(return_pc - 4, blr_address))
+ return false;
+
+ auto blr_ptrauth_info =
+ GetPtrauthInstructionInfo(target, arch, blr_address);
+ if (blr_ptrauth_info && blr_ptrauth_info->IsAuthenticated &&
+ blr_ptrauth_info->DoesBranch) {
+ emit_ptrauth_prologue(bad_address);
+ strm.Printf("Found authenticated indirect branch ");
+ DescribeAddressBriefly(strm, blr_address, target);
+ m_description = std::string(strm.GetString());
+ return true;
+ }
+ }
+ }
+
+ // TODO: Detect: RETAA, RETAB (Return from subroutine, with pointer
+ // authentication).
+ //
+ // Is there a motivating, non-malicious code snippet that corrupts LR?
+
+ return false;
+}
+
const char *StopInfoMachException::GetDescription() {
if (!m_description.empty())
return m_description.c_str();
@@ -79,6 +256,11 @@ const char *StopInfoMachException::GetDescription() {
}
break;
+ case llvm::Triple::aarch64:
+ if (DeterminePtrauthFailure(exe_ctx))
+ return m_description.c_str();
+ break;
+
default:
break;
}
@@ -190,6 +372,11 @@ const char *StopInfoMachException::GetDescription() {
}
break;
+ case llvm::Triple::aarch64:
+ if (DeterminePtrauthFailure(exe_ctx))
+ return m_description.c_str();
+ break;
+
default:
break;
}
diff --git a/lldb/source/Plugins/Process/Utility/StopInfoMachException.h b/lldb/source/Plugins/Process/Utility/StopInfoMachException.h
index d9c1886d70964..6467745a7bf21 100644
--- a/lldb/source/Plugins/Process/Utility/StopInfoMachException.h
+++ b/lldb/source/Plugins/Process/Utility/StopInfoMachException.h
@@ -16,6 +16,11 @@
namespace lldb_private {
class StopInfoMachException : public StopInfo {
+ /// Determine the pointer-authentication related failure that caused this
+ /// exception. Returns true and fills out the failure description if there
+ /// is auth-related failure, and returns false otherwise.
+ bool DeterminePtrauthFailure(ExecutionContext &exe_ctx);
+
public:
// Constructors and Destructors
StopInfoMachException(Thread &thread, uint32_t exc_type,
diff --git a/lldb/test/API/functionalities/ptrauth_diagnostics/BLRAA_error/Makefile b/lldb/test/API/functionalities/ptrauth_diagnostics/BLRAA_error/Makefile
new file mode 100644
index 0000000000000..debf412ee6b7f
--- /dev/null
+++ b/lldb/test/API/functionalities/ptrauth_diagnostics/BLRAA_error/Makefile
@@ -0,0 +1,2 @@
+C_SOURCES := blraa.c
+include Makefile.rules
diff --git a/lldb/test/API/functionalities/ptrauth_diagnostics/BLRAA_error/TestPtrauthBLRAADiagnostic.py b/lldb/test/API/functionalities/ptrauth_diagnostics/BLRAA_error/TestPtrauthBLRAADiagnostic.py
new file mode 100644
index 0000000000000..e7cb210e05e65
--- /dev/null
+++ b/lldb/test/API/functionalities/ptrauth_diagnostics/BLRAA_error/TestPtrauthBLRAADiagnostic.py
@@ -0,0 +1,5 @@
+from lldbsuite.test import lldbinline
+from lldbsuite.test import decorators
+
+lldbinline.MakeInlineTest(__file__, globals(),
+ [decorators.skipIf(archs=decorators.no_match(['arm64e']))])
diff --git a/lldb/test/API/functionalities/ptrauth_diagnostics/BLRAA_error/blraa.c b/lldb/test/API/functionalities/ptrauth_diagnostics/BLRAA_error/blraa.c
new file mode 100644
index 0000000000000..cb48a809feb69
--- /dev/null
+++ b/lldb/test/API/functionalities/ptrauth_diagnostics/BLRAA_error/blraa.c
@@ -0,0 +1,28 @@
+void foo() {}
+
+int main() {
+ //% self.filecheck("c", "blraa.c")
+ // CHECK: stop reason = EXC_BAD_ACCESS
+ // CHECK-NEXT: Note: Possible pointer authentication failure detected.
+ // CHECK-NEXT: Found authenticated indirect branch at address=0x{{.*}} (blraa.c:[[@LINE+1]]:3).
+ asm volatile (
+ "mov x9, #0xbad \n"
+ "blraa %[target], x9 \n"
+ /* Outputs */ :
+ /* Inputs */ : [target] "r"(&foo)
+ /* Clobbers */ : "x9"
+ );
+
+ return 1;
+}
+
+// Expected codegen and exception message without ptrauth diagnostics:
+// * thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x2000000100007f9c)
+// frame #0: 0x0000000100007f9c blraa2`foo
+// blraa2`foo:
+// 0x100007f9c <+0>: ret
+//
+// blraa2`main:
+// 0x100007fa0 <+0>: nop
+// 0x100007fa4 <+4>: ldr x8, #0x5c
+// 0x100007fa8 <+8>: mov x9, #0xbad
diff --git a/lldb/test/API/functionalities/ptrauth_diagnostics/BRAA_error/Makefile b/lldb/test/API/functionalities/ptrauth_diagnostics/BRAA_error/Makefile
new file mode 100644
index 0000000000000..c1b4052bf1394
--- /dev/null
+++ b/lldb/test/API/functionalities/ptrauth_diagnostics/BRAA_error/Makefile
@@ -0,0 +1,2 @@
+C_SOURCES := braa.c
+include Makefile.rules
diff --git a/lldb/test/API/functionalities/ptrauth_diagnostics/BRAA_error/TestPtrauthBRAADiagnostic.py b/lldb/test/API/functionalities/ptrauth_diagnostics/BRAA_error/TestPtrauthBRAADiagnostic.py
new file mode 100644
index 0000000000000..e7cb210e05e65
--- /dev/null
+++ b/lldb/test/API/functionalities/ptrauth_diagnostics/BRAA_error/TestPtrauthBRAADiagnostic.py
@@ -0,0 +1,5 @@
+from lldbsuite.test import lldbinline
+from lldbsuite.test import decorators
+
+lldbinline.MakeInlineTest(__file__, globals(),
+ [decorators.skipIf(archs=decorators.no_match(['arm64e']))])
diff --git a/lldb/test/API/functionalities/ptrauth_diagnostics/BRAA_error/braa.c b/lldb/test/API/functionalities/ptrauth_diagnostics/BRAA_error/braa.c
new file mode 100644
index 0000000000000..c53f4725164e6
--- /dev/null
+++ b/lldb/test/API/functionalities/ptrauth_diagnostics/BRAA_error/braa.c
@@ -0,0 +1,29 @@
+void foo() {}
+
+int main() {
+ //% self.filecheck("c", "braa.c")
+ // CHECK: stop reason = EXC_BAD_ACCESS
+ //
+ // TODO: We need call site info support for indirect calls to make this work.
+ // CHECK-NOT: pointer authentication failure
+ asm volatile (
+ "mov x9, #0xbad \n"
+ "braa %[target], x9 \n"
+ /* Outputs */ :
+ /* Inputs */ : [target] "r"(&foo)
+ /* Clobbers */ : "x9"
+ );
+
+ return 1;
+}
+
+// Expected codegen and exception message without ptrauth diagnostics:
+// * thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x2000000100007f9c)
+// frame #0: 0x0000000100007f9c braa`foo
+// braa`foo:
+// 0x100007f9c <+0>: ret
+//
+// braa`main:
+// 0x100007fa0 <+0>: nop
+// 0x100007fa4 <+4>: ldr x8, #0x5c
+// 0x100007fa8 <+8>: mov x9, #0xbad
diff --git a/lldb/test/API/functionalities/ptrauth_diagnostics/LDRAA_error/Makefile b/lldb/test/API/functionalities/ptrauth_diagnostics/LDRAA_error/Makefile
new file mode 100644
index 0000000000000..be911c9910bec
--- /dev/null
+++ b/lldb/test/API/functionalities/ptrauth_diagnostics/LDRAA_error/Makefile
@@ -0,0 +1,2 @@
+C_SOURCES := ldraa.c
+include Makefile.rules
diff --git a/lldb/test/API/functionalities/ptrauth_diagnostics/LDRAA_error/TestPtrauthLDRAADiagnostic.py b/lldb/test/API/functionalities/ptrauth_diagnostics/LDRAA_error/TestPtrauthLDRAADiagnostic.py
new file mode 100644
index 0000000000000..e7cb210e05e65
--- /dev/null
+++ b/lldb/test/API/functionalities/ptrauth_diagnostics/LDRAA_error/TestPtrauthLDRAADiagnostic.py
@@ -0,0 +1,5 @@
+from lldbsuite.test import lldbinline
+from lldbsuite.test import decorators
+
+lldbinline.MakeInlineTest(__file__, globals(),
+ [decorators.skipIf(archs=decorators.no_match(['arm64e']))])
diff --git a/lldb/test/API/functionalities/ptrauth_diagnostics/LDRAA_error/ldraa.c b/lldb/test/API/functionalities/ptrauth_diagnostics/LDRAA_error/ldraa.c
new file mode 100644
index 0000000000000..bfe9c255e8325
--- /dev/null
+++ b/lldb/test/API/functionalities/ptrauth_diagnostics/LDRAA_error/ldraa.c
@@ -0,0 +1,31 @@
+int main() {
+ //% self.filecheck("c", "ldraa.c")
+ // CHECK: EXC_BAD_ACCESS
+ // CHECK-NEXT: Note: Possible pointer authentication failure detected.
+ // CHECK-NEXT: Found authenticated load instruction at address=0x{{.*}} (ldraa.c:[[@LINE+3]]:3).
+ long long foo = 0;
+
+ asm volatile (
+ "ldraa x9, [%[target]] \n"
+ /* Outputs */ :
+ /* Inputs */ : [target] "r"(&foo)
+ /* Clobbers */ :
+ );
+
+ return 1;
+}
+
+// Expected codegen, register state, and exception message without ptrauth diagnostics:
+// * thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x2000016fdffc38)
+// frame #0: 0x0000000100007fa8 ldraa`main + 12
+// ldraa`main:
+// -> 0x100007fa8 <+12>: ldraa x9, [x8]
+// 0x100007fac <+16>: orr w0, wzr, #0x1
+// 0x100007fb0 <+20>: add sp, sp, #0x10 ; =0x10
+// 0x100007fb4 <+24>: ret
+// Target 0: (ldraa) stopped.
+// (lldb) p/x $x8
+// (unsigned long) $0 = 0x000000016fdffc38
+// (lldb) x/8 $x8
+// 0x16fdffc38: 0x00000000 0x00000000 0x80254f30 0x00000001
+// 0x16fdffc48: 0x00000000 0x00000000 0x00000000 0x00000000
diff --git a/lldb/test/API/functionalities/ptrauth_diagnostics/brkC47x_code/Makefile b/lldb/test/API/functionalities/ptrauth_diagnostics/brkC47x_code/Makefile
new file mode 100644
index 0000000000000..04b90fada31c0
--- /dev/null
+++ b/lldb/test/API/functionalities/ptrauth_diagnostics/brkC47x_code/Makefile
@@ -0,0 +1,2 @@
+C_SOURCES := brkC47x.c
+include Makefile.rules
diff --git a/lldb/test/API/functionalities/ptrauth_diagnostics/brkC47x_code/TestPtrauthBRKc47xDiagnostic.py b/lldb/test/API/functionalities/ptrauth_diagnostics/brkC47x_code/TestPtrauthBRKc47xDiagnostic.py
new file mode 100644
index 0000000000000..e7cb210e05e65
--- /dev/null
+++ b/lldb/test/API/functionalities/ptrauth_diagnostics/brkC47x_code/TestPtrauthBRKc47xDiagnostic.py
@@ -0,0 +1,5 @@
+from lldbsuite.test import lldbinline
+from lldbsuite.test import decorators
+
+lldbinline.MakeInlineTest(__file__, globals(),
+ [decorators.skipIf(archs=decorators.no_match(['arm64e']))])
diff --git a/lldb/test/API/functionalities/ptrauth_diagnostics/brkC47x_code/brkC47x.c b/lldb/test/API/functionalities/ptrauth_diagnostics/brkC47x_code/brkC47x.c
new file mode 100644
index 0000000000000..c91e832bb2a3a
--- /dev/null
+++ b/lldb/test/API/functionalities/ptrauth_diagnostics/brkC47x_code/brkC47x.c
@@ -0,0 +1,17 @@
+void foo() {}
+
+int main() {
+ //% self.filecheck("c", "brkC47x.c")
+ // CHECK: stop reason = EXC_BAD_ACCESS
+ // CHECK-NEXT: Note: Possible pointer authentication failure detected.
+ // CHECK-NEXT: Found value that failed to authenticate at address=0x{{.*}} (brkC47x.c:1:13).
+ asm volatile (
+ "mov x16, %[target] \n"
+ "brk 0xc470 \n"
+ /* Outputs */ :
+ /* Inputs */ : [target] "r"(&foo)
+ /* Clobbers */ : "x16"
+ );
+
+ return 1;
+}
diff --git a/lldb/test/API/functionalities/ptrauth_diagnostics/brkC47x_x16_invalid/Makefile b/lldb/test/API/functionalities/ptrauth_diagnostics/brkC47x_x16_invalid/Makefile
new file mode 100644
index 0000000000000..04b90fada31c0
--- /dev/null
+++ b/lldb/test/API/functionalities/ptrauth_diagnostics/brkC47x_x16_invalid/Makefile
@@ -0,0 +1,2 @@
+C_SOURCES := brkC47x.c
+include Makefile.rules
diff --git a/lldb/test/API/functionalities/ptrauth_diagnostics/brkC47x_x16_invalid/TestPtrauthBRKc47xX16Invalid.py b/lldb/test/API/functionalities/ptrauth_diagnostics/brkC47x_x16_invalid/TestPtrauthBRKc47xX16Invalid.py
new file mode 100644
index 0000000000000..e7cb210e05e65
--- /dev/null
+++ b/lldb/test/API/functionalities/ptrauth_diagnostics/brkC47x_x16_invalid/TestPtrauthBRKc47xX16Invalid.py
@@ -0,0 +1,5 @@
+from lldbsuite.test import lldbinline
+from lldbsuite.test import decorators
+
+lldbinline.MakeInlineTest(__file__, globals(),
+ [decorators.skipIf(archs=decorators.no_match(['arm64e']))])
diff --git a/lldb/test/API/functionalities/ptrauth_diagnostics/brkC47x_x16_invalid/brkC47x.c b/lldb/test/API/functionalities/ptrauth_diagnostics/brkC47x_x16_invalid/brkC47x.c
new file mode 100644
index 0000000000000..7119277351585
--- /dev/null
+++ b/lldb/test/API/functionalities/ptrauth_diagnostics/brkC47x_x16_invalid/brkC47x.c
@@ -0,0 +1,14 @@
+int main() {
+ //% self.filecheck("c", "brkC47x.c")
+ // CHECK: stop reason = EXC_BAD_ACCESS
+ // CHECK-NOT: Note: Possible pointer authentication failure detected.
+ asm volatile (
+ "mov x16, #0xbad \n"
+ "brk 0xc470 \n"
+ /* Outputs */ :
+ /* Inputs */ :
+ /* Clobbers */ : "x16"
+ );
+
+ return 1;
+}
More information about the lldb-commits
mailing list