[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