15ffd83dbSDimitry Andric //===-- StopInfoMachException.cpp -----------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "StopInfoMachException.h" 100b57cec5SDimitry Andric 115ffd83dbSDimitry Andric #include "lldb/lldb-forward.h" 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #if defined(__APPLE__) 140b57cec5SDimitry Andric // Needed for the EXC_RESOURCE interpretation macros 150b57cec5SDimitry Andric #include <kern/exc_resource.h> 160b57cec5SDimitry Andric #endif 170b57cec5SDimitry Andric 180b57cec5SDimitry Andric #include "lldb/Breakpoint/Watchpoint.h" 190b57cec5SDimitry Andric #include "lldb/Symbol/Symbol.h" 20349cc55cSDimitry Andric #include "lldb/Target/ABI.h" 210b57cec5SDimitry Andric #include "lldb/Target/DynamicLoader.h" 220b57cec5SDimitry Andric #include "lldb/Target/ExecutionContext.h" 230b57cec5SDimitry Andric #include "lldb/Target/Process.h" 240b57cec5SDimitry Andric #include "lldb/Target/RegisterContext.h" 250b57cec5SDimitry Andric #include "lldb/Target/Target.h" 260b57cec5SDimitry Andric #include "lldb/Target/Thread.h" 270b57cec5SDimitry Andric #include "lldb/Target/ThreadPlan.h" 280b57cec5SDimitry Andric #include "lldb/Target/UnixSignals.h" 29*0fca6ea1SDimitry Andric #include "lldb/Utility/LLDBLog.h" 30*0fca6ea1SDimitry Andric #include "lldb/Utility/Log.h" 310b57cec5SDimitry Andric #include "lldb/Utility/StreamString.h" 32bdd1243dSDimitry Andric #include <optional> 330b57cec5SDimitry Andric 340b57cec5SDimitry Andric using namespace lldb; 350b57cec5SDimitry Andric using namespace lldb_private; 360b57cec5SDimitry Andric 37349cc55cSDimitry Andric /// Information about a pointer-authentication related instruction. 38349cc55cSDimitry Andric struct PtrauthInstructionInfo { 39349cc55cSDimitry Andric bool IsAuthenticated; 40349cc55cSDimitry Andric bool IsLoad; 41349cc55cSDimitry Andric bool DoesBranch; 42349cc55cSDimitry Andric }; 43349cc55cSDimitry Andric 44349cc55cSDimitry Andric /// Get any pointer-authentication related information about the instruction 45349cc55cSDimitry Andric /// at address \p at_addr. 46bdd1243dSDimitry Andric static std::optional<PtrauthInstructionInfo> 47349cc55cSDimitry Andric GetPtrauthInstructionInfo(Target &target, const ArchSpec &arch, 48349cc55cSDimitry Andric const Address &at_addr) { 49349cc55cSDimitry Andric const char *plugin_name = nullptr; 50349cc55cSDimitry Andric const char *flavor = nullptr; 51349cc55cSDimitry Andric AddressRange range_bounds(at_addr, 4); 52349cc55cSDimitry Andric const bool prefer_file_cache = true; 53349cc55cSDimitry Andric DisassemblerSP disassembler_sp = Disassembler::DisassembleRange( 54349cc55cSDimitry Andric arch, plugin_name, flavor, target, range_bounds, prefer_file_cache); 55349cc55cSDimitry Andric if (!disassembler_sp) 56bdd1243dSDimitry Andric return std::nullopt; 57349cc55cSDimitry Andric 58349cc55cSDimitry Andric InstructionList &insn_list = disassembler_sp->GetInstructionList(); 59349cc55cSDimitry Andric InstructionSP insn = insn_list.GetInstructionAtIndex(0); 60349cc55cSDimitry Andric if (!insn) 61bdd1243dSDimitry Andric return std::nullopt; 62349cc55cSDimitry Andric 63349cc55cSDimitry Andric return PtrauthInstructionInfo{insn->IsAuthenticated(), insn->IsLoad(), 64349cc55cSDimitry Andric insn->DoesBranch()}; 65349cc55cSDimitry Andric } 66349cc55cSDimitry Andric 67349cc55cSDimitry Andric /// Describe the load address of \p addr using the format filename:line:col. 68349cc55cSDimitry Andric static void DescribeAddressBriefly(Stream &strm, const Address &addr, 69349cc55cSDimitry Andric Target &target) { 70349cc55cSDimitry Andric strm.Printf("at address=0x%" PRIx64, addr.GetLoadAddress(&target)); 71349cc55cSDimitry Andric StreamString s; 72349cc55cSDimitry Andric if (addr.GetDescription(s, target, eDescriptionLevelBrief)) 73349cc55cSDimitry Andric strm.Printf(" %s", s.GetString().data()); 74349cc55cSDimitry Andric strm.Printf(".\n"); 75349cc55cSDimitry Andric } 76349cc55cSDimitry Andric 77349cc55cSDimitry Andric bool StopInfoMachException::DeterminePtrauthFailure(ExecutionContext &exe_ctx) { 78349cc55cSDimitry Andric bool IsBreakpoint = m_value == 6; // EXC_BREAKPOINT 79349cc55cSDimitry Andric bool IsBadAccess = m_value == 1; // EXC_BAD_ACCESS 80349cc55cSDimitry Andric if (!IsBreakpoint && !IsBadAccess) 81349cc55cSDimitry Andric return false; 82349cc55cSDimitry Andric 83349cc55cSDimitry Andric // Check that we have a live process. 84349cc55cSDimitry Andric if (!exe_ctx.HasProcessScope() || !exe_ctx.HasThreadScope() || 85349cc55cSDimitry Andric !exe_ctx.HasTargetScope()) 86349cc55cSDimitry Andric return false; 87349cc55cSDimitry Andric 88349cc55cSDimitry Andric Thread &thread = *exe_ctx.GetThreadPtr(); 89349cc55cSDimitry Andric StackFrameSP current_frame = thread.GetStackFrameAtIndex(0); 90349cc55cSDimitry Andric if (!current_frame) 91349cc55cSDimitry Andric return false; 92349cc55cSDimitry Andric 93349cc55cSDimitry Andric Target &target = *exe_ctx.GetTargetPtr(); 94349cc55cSDimitry Andric Process &process = *exe_ctx.GetProcessPtr(); 95349cc55cSDimitry Andric const ArchSpec &arch = target.GetArchitecture(); 96349cc55cSDimitry Andric 97349cc55cSDimitry Andric // Check for a ptrauth-enabled target. 98349cc55cSDimitry Andric const bool ptrauth_enabled_target = 99349cc55cSDimitry Andric arch.GetCore() == ArchSpec::eCore_arm_arm64e; 100349cc55cSDimitry Andric if (!ptrauth_enabled_target) 101349cc55cSDimitry Andric return false; 102349cc55cSDimitry Andric 103349cc55cSDimitry Andric // Set up a stream we can write a diagnostic into. 104349cc55cSDimitry Andric StreamString strm; 105349cc55cSDimitry Andric auto emit_ptrauth_prologue = [&](uint64_t at_address) { 106349cc55cSDimitry Andric strm.Printf("EXC_BAD_ACCESS (code=%" PRIu64 ", address=0x%" PRIx64 ")\n", 107349cc55cSDimitry Andric m_exc_code, at_address); 108349cc55cSDimitry Andric strm.Printf("Note: Possible pointer authentication failure detected.\n"); 109349cc55cSDimitry Andric }; 110349cc55cSDimitry Andric 111*0fca6ea1SDimitry Andric ABISP abi_sp = process.GetABI(); 112*0fca6ea1SDimitry Andric assert(abi_sp && "Missing ABI info"); 113*0fca6ea1SDimitry Andric 114349cc55cSDimitry Andric // Check if we have a "brk 0xc47x" trap, where the value that failed to 115349cc55cSDimitry Andric // authenticate is in x16. 116349cc55cSDimitry Andric Address current_address = current_frame->GetFrameCodeAddress(); 117349cc55cSDimitry Andric if (IsBreakpoint) { 118349cc55cSDimitry Andric RegisterContext *reg_ctx = exe_ctx.GetRegisterContext(); 119349cc55cSDimitry Andric if (!reg_ctx) 120349cc55cSDimitry Andric return false; 121349cc55cSDimitry Andric 122349cc55cSDimitry Andric const RegisterInfo *X16Info = reg_ctx->GetRegisterInfoByName("x16"); 123349cc55cSDimitry Andric RegisterValue X16Val; 124349cc55cSDimitry Andric if (!reg_ctx->ReadRegister(X16Info, X16Val)) 125349cc55cSDimitry Andric return false; 126349cc55cSDimitry Andric uint64_t bad_address = X16Val.GetAsUInt64(); 127349cc55cSDimitry Andric 128349cc55cSDimitry Andric uint64_t fixed_bad_address = abi_sp->FixCodeAddress(bad_address); 129349cc55cSDimitry Andric Address brk_address; 130349cc55cSDimitry Andric if (!target.ResolveLoadAddress(fixed_bad_address, brk_address)) 131349cc55cSDimitry Andric return false; 132349cc55cSDimitry Andric 133349cc55cSDimitry Andric auto brk_ptrauth_info = 134349cc55cSDimitry Andric GetPtrauthInstructionInfo(target, arch, current_address); 135349cc55cSDimitry Andric if (brk_ptrauth_info && brk_ptrauth_info->IsAuthenticated) { 136349cc55cSDimitry Andric emit_ptrauth_prologue(bad_address); 137349cc55cSDimitry Andric strm.Printf("Found value that failed to authenticate "); 138349cc55cSDimitry Andric DescribeAddressBriefly(strm, brk_address, target); 139349cc55cSDimitry Andric m_description = std::string(strm.GetString()); 140349cc55cSDimitry Andric return true; 141349cc55cSDimitry Andric } 142349cc55cSDimitry Andric return false; 143349cc55cSDimitry Andric } 144349cc55cSDimitry Andric 145349cc55cSDimitry Andric assert(IsBadAccess && "Handle EXC_BAD_ACCESS only after this point"); 146349cc55cSDimitry Andric 147349cc55cSDimitry Andric // Check that we have the "bad address" from an EXC_BAD_ACCESS. 148349cc55cSDimitry Andric if (m_exc_data_count < 2) 149349cc55cSDimitry Andric return false; 150349cc55cSDimitry Andric 151349cc55cSDimitry Andric // Ok, we know the Target is valid and that it describes a ptrauth-enabled 152349cc55cSDimitry Andric // device. Now, we need to determine whether this exception was caused by a 153349cc55cSDimitry Andric // ptrauth failure. 154349cc55cSDimitry Andric 155349cc55cSDimitry Andric uint64_t bad_address = m_exc_subcode; 156349cc55cSDimitry Andric uint64_t fixed_bad_address = abi_sp->FixCodeAddress(bad_address); 157349cc55cSDimitry Andric uint64_t current_pc = current_address.GetLoadAddress(&target); 158349cc55cSDimitry Andric 159349cc55cSDimitry Andric // Detect: LDRAA, LDRAB (Load Register, with pointer authentication). 160349cc55cSDimitry Andric // 161349cc55cSDimitry Andric // If an authenticated load results in an exception, the instruction at the 162349cc55cSDimitry Andric // current PC should be one of LDRAx. 163349cc55cSDimitry Andric if (bad_address != current_pc && fixed_bad_address != current_pc) { 164349cc55cSDimitry Andric auto ptrauth_info = 165349cc55cSDimitry Andric GetPtrauthInstructionInfo(target, arch, current_address); 166349cc55cSDimitry Andric if (ptrauth_info && ptrauth_info->IsAuthenticated && ptrauth_info->IsLoad) { 167349cc55cSDimitry Andric emit_ptrauth_prologue(bad_address); 168349cc55cSDimitry Andric strm.Printf("Found authenticated load instruction "); 169349cc55cSDimitry Andric DescribeAddressBriefly(strm, current_address, target); 170349cc55cSDimitry Andric m_description = std::string(strm.GetString()); 171349cc55cSDimitry Andric return true; 172349cc55cSDimitry Andric } 173349cc55cSDimitry Andric } 174349cc55cSDimitry Andric 175349cc55cSDimitry Andric // Detect: BLRAA, BLRAAZ, BLRAB, BLRABZ (Branch with Link to Register, with 176349cc55cSDimitry Andric // pointer authentication). 177349cc55cSDimitry Andric // 178349cc55cSDimitry Andric // TODO: Detect: BRAA, BRAAZ, BRAB, BRABZ (Branch to Register, with pointer 179349cc55cSDimitry Andric // authentication). At a minimum, this requires call site info support for 180349cc55cSDimitry Andric // indirect calls. 181349cc55cSDimitry Andric // 182349cc55cSDimitry Andric // If an authenticated call or tail call results in an exception, stripping 183349cc55cSDimitry Andric // the bad address should give the current PC, which points to the address 184349cc55cSDimitry Andric // we tried to branch to. 185349cc55cSDimitry Andric if (bad_address != current_pc && fixed_bad_address == current_pc) { 186349cc55cSDimitry Andric if (StackFrameSP parent_frame = thread.GetStackFrameAtIndex(1)) { 187349cc55cSDimitry Andric addr_t return_pc = 188349cc55cSDimitry Andric parent_frame->GetFrameCodeAddress().GetLoadAddress(&target); 189349cc55cSDimitry Andric Address blr_address; 190349cc55cSDimitry Andric if (!target.ResolveLoadAddress(return_pc - 4, blr_address)) 191349cc55cSDimitry Andric return false; 192349cc55cSDimitry Andric 193349cc55cSDimitry Andric auto blr_ptrauth_info = 194349cc55cSDimitry Andric GetPtrauthInstructionInfo(target, arch, blr_address); 195349cc55cSDimitry Andric if (blr_ptrauth_info && blr_ptrauth_info->IsAuthenticated && 196349cc55cSDimitry Andric blr_ptrauth_info->DoesBranch) { 197349cc55cSDimitry Andric emit_ptrauth_prologue(bad_address); 198349cc55cSDimitry Andric strm.Printf("Found authenticated indirect branch "); 199349cc55cSDimitry Andric DescribeAddressBriefly(strm, blr_address, target); 200349cc55cSDimitry Andric m_description = std::string(strm.GetString()); 201349cc55cSDimitry Andric return true; 202349cc55cSDimitry Andric } 203349cc55cSDimitry Andric } 204349cc55cSDimitry Andric } 205349cc55cSDimitry Andric 206349cc55cSDimitry Andric // TODO: Detect: RETAA, RETAB (Return from subroutine, with pointer 207349cc55cSDimitry Andric // authentication). 208349cc55cSDimitry Andric // 209349cc55cSDimitry Andric // Is there a motivating, non-malicious code snippet that corrupts LR? 210349cc55cSDimitry Andric 211349cc55cSDimitry Andric return false; 212349cc55cSDimitry Andric } 213349cc55cSDimitry Andric 2140b57cec5SDimitry Andric const char *StopInfoMachException::GetDescription() { 2159dba64beSDimitry Andric if (!m_description.empty()) 2169dba64beSDimitry Andric return m_description.c_str(); 2179dba64beSDimitry Andric if (GetValue() == eStopReasonInvalid) 2189dba64beSDimitry Andric return "invalid stop reason!"; 2199dba64beSDimitry Andric 2200b57cec5SDimitry Andric ExecutionContext exe_ctx(m_thread_wp.lock()); 2210b57cec5SDimitry Andric Target *target = exe_ctx.GetTargetPtr(); 2220b57cec5SDimitry Andric const llvm::Triple::ArchType cpu = 2230b57cec5SDimitry Andric target ? target->GetArchitecture().GetMachine() 2240b57cec5SDimitry Andric : llvm::Triple::UnknownArch; 2250b57cec5SDimitry Andric 2260b57cec5SDimitry Andric const char *exc_desc = nullptr; 2270b57cec5SDimitry Andric const char *code_label = "code"; 2280b57cec5SDimitry Andric const char *code_desc = nullptr; 2290b57cec5SDimitry Andric const char *subcode_label = "subcode"; 2300b57cec5SDimitry Andric const char *subcode_desc = nullptr; 2310b57cec5SDimitry Andric 2320b57cec5SDimitry Andric #if defined(__APPLE__) 2330b57cec5SDimitry Andric char code_desc_buf[32]; 2340b57cec5SDimitry Andric char subcode_desc_buf[32]; 2350b57cec5SDimitry Andric #endif 2360b57cec5SDimitry Andric 2370b57cec5SDimitry Andric switch (m_value) { 2380b57cec5SDimitry Andric case 1: // EXC_BAD_ACCESS 2390b57cec5SDimitry Andric exc_desc = "EXC_BAD_ACCESS"; 2400b57cec5SDimitry Andric subcode_label = "address"; 2410b57cec5SDimitry Andric switch (cpu) { 2420b57cec5SDimitry Andric case llvm::Triple::x86: 2430b57cec5SDimitry Andric case llvm::Triple::x86_64: 2440b57cec5SDimitry Andric switch (m_exc_code) { 2450b57cec5SDimitry Andric case 0xd: 2460b57cec5SDimitry Andric code_desc = "EXC_I386_GPFLT"; 2470b57cec5SDimitry Andric m_exc_data_count = 1; 2480b57cec5SDimitry Andric break; 2490b57cec5SDimitry Andric } 2500b57cec5SDimitry Andric break; 2510b57cec5SDimitry Andric case llvm::Triple::arm: 2520b57cec5SDimitry Andric case llvm::Triple::thumb: 2530b57cec5SDimitry Andric switch (m_exc_code) { 2540b57cec5SDimitry Andric case 0x101: 2550b57cec5SDimitry Andric code_desc = "EXC_ARM_DA_ALIGN"; 2560b57cec5SDimitry Andric break; 2570b57cec5SDimitry Andric case 0x102: 2580b57cec5SDimitry Andric code_desc = "EXC_ARM_DA_DEBUG"; 2590b57cec5SDimitry Andric break; 2600b57cec5SDimitry Andric } 2610b57cec5SDimitry Andric break; 2620b57cec5SDimitry Andric 263349cc55cSDimitry Andric case llvm::Triple::aarch64: 264349cc55cSDimitry Andric if (DeterminePtrauthFailure(exe_ctx)) 265349cc55cSDimitry Andric return m_description.c_str(); 266349cc55cSDimitry Andric break; 267349cc55cSDimitry Andric 2680b57cec5SDimitry Andric default: 2690b57cec5SDimitry Andric break; 2700b57cec5SDimitry Andric } 2710b57cec5SDimitry Andric break; 2720b57cec5SDimitry Andric 2730b57cec5SDimitry Andric case 2: // EXC_BAD_INSTRUCTION 2740b57cec5SDimitry Andric exc_desc = "EXC_BAD_INSTRUCTION"; 2750b57cec5SDimitry Andric switch (cpu) { 2760b57cec5SDimitry Andric case llvm::Triple::x86: 2770b57cec5SDimitry Andric case llvm::Triple::x86_64: 2780b57cec5SDimitry Andric if (m_exc_code == 1) 2790b57cec5SDimitry Andric code_desc = "EXC_I386_INVOP"; 2800b57cec5SDimitry Andric break; 2810b57cec5SDimitry Andric 2820b57cec5SDimitry Andric case llvm::Triple::arm: 2830b57cec5SDimitry Andric case llvm::Triple::thumb: 2840b57cec5SDimitry Andric if (m_exc_code == 1) 2850b57cec5SDimitry Andric code_desc = "EXC_ARM_UNDEFINED"; 2860b57cec5SDimitry Andric break; 2870b57cec5SDimitry Andric 2880b57cec5SDimitry Andric default: 2890b57cec5SDimitry Andric break; 2900b57cec5SDimitry Andric } 2910b57cec5SDimitry Andric break; 2920b57cec5SDimitry Andric 2930b57cec5SDimitry Andric case 3: // EXC_ARITHMETIC 2940b57cec5SDimitry Andric exc_desc = "EXC_ARITHMETIC"; 2950b57cec5SDimitry Andric switch (cpu) { 2960b57cec5SDimitry Andric case llvm::Triple::x86: 2970b57cec5SDimitry Andric case llvm::Triple::x86_64: 2980b57cec5SDimitry Andric switch (m_exc_code) { 2990b57cec5SDimitry Andric case 1: 3000b57cec5SDimitry Andric code_desc = "EXC_I386_DIV"; 3010b57cec5SDimitry Andric break; 3020b57cec5SDimitry Andric case 2: 3030b57cec5SDimitry Andric code_desc = "EXC_I386_INTO"; 3040b57cec5SDimitry Andric break; 3050b57cec5SDimitry Andric case 3: 3060b57cec5SDimitry Andric code_desc = "EXC_I386_NOEXT"; 3070b57cec5SDimitry Andric break; 3080b57cec5SDimitry Andric case 4: 3090b57cec5SDimitry Andric code_desc = "EXC_I386_EXTOVR"; 3100b57cec5SDimitry Andric break; 3110b57cec5SDimitry Andric case 5: 3120b57cec5SDimitry Andric code_desc = "EXC_I386_EXTERR"; 3130b57cec5SDimitry Andric break; 3140b57cec5SDimitry Andric case 6: 3150b57cec5SDimitry Andric code_desc = "EXC_I386_EMERR"; 3160b57cec5SDimitry Andric break; 3170b57cec5SDimitry Andric case 7: 3180b57cec5SDimitry Andric code_desc = "EXC_I386_BOUND"; 3190b57cec5SDimitry Andric break; 3200b57cec5SDimitry Andric case 8: 3210b57cec5SDimitry Andric code_desc = "EXC_I386_SSEEXTERR"; 3220b57cec5SDimitry Andric break; 3230b57cec5SDimitry Andric } 3240b57cec5SDimitry Andric break; 3250b57cec5SDimitry Andric 3260b57cec5SDimitry Andric default: 3270b57cec5SDimitry Andric break; 3280b57cec5SDimitry Andric } 3290b57cec5SDimitry Andric break; 3300b57cec5SDimitry Andric 3310b57cec5SDimitry Andric case 4: // EXC_EMULATION 3320b57cec5SDimitry Andric exc_desc = "EXC_EMULATION"; 3330b57cec5SDimitry Andric break; 3340b57cec5SDimitry Andric 3350b57cec5SDimitry Andric case 5: // EXC_SOFTWARE 3360b57cec5SDimitry Andric exc_desc = "EXC_SOFTWARE"; 3370b57cec5SDimitry Andric if (m_exc_code == 0x10003) { 3380b57cec5SDimitry Andric subcode_desc = "EXC_SOFT_SIGNAL"; 3390b57cec5SDimitry Andric subcode_label = "signo"; 3400b57cec5SDimitry Andric } 3410b57cec5SDimitry Andric break; 3420b57cec5SDimitry Andric 3430b57cec5SDimitry Andric case 6: // EXC_BREAKPOINT 3440b57cec5SDimitry Andric { 3450b57cec5SDimitry Andric exc_desc = "EXC_BREAKPOINT"; 3460b57cec5SDimitry Andric switch (cpu) { 3470b57cec5SDimitry Andric case llvm::Triple::x86: 3480b57cec5SDimitry Andric case llvm::Triple::x86_64: 3490b57cec5SDimitry Andric switch (m_exc_code) { 3500b57cec5SDimitry Andric case 1: 3510b57cec5SDimitry Andric code_desc = "EXC_I386_SGL"; 3520b57cec5SDimitry Andric break; 3530b57cec5SDimitry Andric case 2: 3540b57cec5SDimitry Andric code_desc = "EXC_I386_BPT"; 3550b57cec5SDimitry Andric break; 3560b57cec5SDimitry Andric } 3570b57cec5SDimitry Andric break; 3580b57cec5SDimitry Andric 3590b57cec5SDimitry Andric case llvm::Triple::arm: 3600b57cec5SDimitry Andric case llvm::Triple::thumb: 3610b57cec5SDimitry Andric switch (m_exc_code) { 3620b57cec5SDimitry Andric case 0x101: 3630b57cec5SDimitry Andric code_desc = "EXC_ARM_DA_ALIGN"; 3640b57cec5SDimitry Andric break; 3650b57cec5SDimitry Andric case 0x102: 3660b57cec5SDimitry Andric code_desc = "EXC_ARM_DA_DEBUG"; 3670b57cec5SDimitry Andric break; 3680b57cec5SDimitry Andric case 1: 3690b57cec5SDimitry Andric code_desc = "EXC_ARM_BREAKPOINT"; 3700b57cec5SDimitry Andric break; 3710b57cec5SDimitry Andric // FIXME temporary workaround, exc_code 0 does not really mean 3720b57cec5SDimitry Andric // EXC_ARM_BREAKPOINT 3730b57cec5SDimitry Andric case 0: 3740b57cec5SDimitry Andric code_desc = "EXC_ARM_BREAKPOINT"; 3750b57cec5SDimitry Andric break; 3760b57cec5SDimitry Andric } 3770b57cec5SDimitry Andric break; 3780b57cec5SDimitry Andric 379349cc55cSDimitry Andric case llvm::Triple::aarch64: 380349cc55cSDimitry Andric if (DeterminePtrauthFailure(exe_ctx)) 381349cc55cSDimitry Andric return m_description.c_str(); 382349cc55cSDimitry Andric break; 383349cc55cSDimitry Andric 3840b57cec5SDimitry Andric default: 3850b57cec5SDimitry Andric break; 3860b57cec5SDimitry Andric } 3870b57cec5SDimitry Andric } break; 3880b57cec5SDimitry Andric 3890b57cec5SDimitry Andric case 7: 3900b57cec5SDimitry Andric exc_desc = "EXC_SYSCALL"; 3910b57cec5SDimitry Andric break; 3920b57cec5SDimitry Andric 3930b57cec5SDimitry Andric case 8: 3940b57cec5SDimitry Andric exc_desc = "EXC_MACH_SYSCALL"; 3950b57cec5SDimitry Andric break; 3960b57cec5SDimitry Andric 3970b57cec5SDimitry Andric case 9: 3980b57cec5SDimitry Andric exc_desc = "EXC_RPC_ALERT"; 3990b57cec5SDimitry Andric break; 4000b57cec5SDimitry Andric 4010b57cec5SDimitry Andric case 10: 4020b57cec5SDimitry Andric exc_desc = "EXC_CRASH"; 4030b57cec5SDimitry Andric break; 4040b57cec5SDimitry Andric case 11: 4050b57cec5SDimitry Andric exc_desc = "EXC_RESOURCE"; 4060b57cec5SDimitry Andric #if defined(__APPLE__) 4070b57cec5SDimitry Andric { 4080b57cec5SDimitry Andric int resource_type = EXC_RESOURCE_DECODE_RESOURCE_TYPE(m_exc_code); 4090b57cec5SDimitry Andric 4100b57cec5SDimitry Andric code_label = "limit"; 4110b57cec5SDimitry Andric code_desc = code_desc_buf; 4120b57cec5SDimitry Andric subcode_label = "observed"; 4130b57cec5SDimitry Andric subcode_desc = subcode_desc_buf; 4140b57cec5SDimitry Andric 4150b57cec5SDimitry Andric switch (resource_type) { 4160b57cec5SDimitry Andric case RESOURCE_TYPE_CPU: 417bdd1243dSDimitry Andric exc_desc = 418bdd1243dSDimitry Andric "EXC_RESOURCE (RESOURCE_TYPE_CPU: CPU usage monitor tripped)"; 4190b57cec5SDimitry Andric snprintf(code_desc_buf, sizeof(code_desc_buf), "%d%%", 4200b57cec5SDimitry Andric (int)EXC_RESOURCE_CPUMONITOR_DECODE_PERCENTAGE(m_exc_code)); 4210b57cec5SDimitry Andric snprintf(subcode_desc_buf, sizeof(subcode_desc_buf), "%d%%", 4229dba64beSDimitry Andric (int)EXC_RESOURCE_CPUMONITOR_DECODE_PERCENTAGE_OBSERVED( 4239dba64beSDimitry Andric m_exc_subcode)); 4240b57cec5SDimitry Andric break; 4250b57cec5SDimitry Andric case RESOURCE_TYPE_WAKEUPS: 426bdd1243dSDimitry Andric exc_desc = "EXC_RESOURCE (RESOURCE_TYPE_WAKEUPS: idle wakeups monitor " 427bdd1243dSDimitry Andric "tripped)"; 4289dba64beSDimitry Andric snprintf( 4299dba64beSDimitry Andric code_desc_buf, sizeof(code_desc_buf), "%d w/s", 4300b57cec5SDimitry Andric (int)EXC_RESOURCE_CPUMONITOR_DECODE_WAKEUPS_PERMITTED(m_exc_code)); 4310b57cec5SDimitry Andric snprintf(subcode_desc_buf, sizeof(subcode_desc_buf), "%d w/s", 4329dba64beSDimitry Andric (int)EXC_RESOURCE_CPUMONITOR_DECODE_WAKEUPS_OBSERVED( 4339dba64beSDimitry Andric m_exc_subcode)); 4340b57cec5SDimitry Andric break; 4350b57cec5SDimitry Andric case RESOURCE_TYPE_MEMORY: 436bdd1243dSDimitry Andric exc_desc = "EXC_RESOURCE (RESOURCE_TYPE_MEMORY: high watermark memory " 437bdd1243dSDimitry Andric "limit exceeded)"; 4380b57cec5SDimitry Andric snprintf(code_desc_buf, sizeof(code_desc_buf), "%d MB", 4390b57cec5SDimitry Andric (int)EXC_RESOURCE_HWM_DECODE_LIMIT(m_exc_code)); 4400b57cec5SDimitry Andric subcode_desc = nullptr; 441bdd1243dSDimitry Andric subcode_label = nullptr; 4420b57cec5SDimitry Andric break; 4439dba64beSDimitry Andric #if defined(RESOURCE_TYPE_IO) 4449dba64beSDimitry Andric // RESOURCE_TYPE_IO is introduced in macOS SDK 10.12. 4450b57cec5SDimitry Andric case RESOURCE_TYPE_IO: 4460b57cec5SDimitry Andric exc_desc = "EXC_RESOURCE RESOURCE_TYPE_IO"; 4470b57cec5SDimitry Andric snprintf(code_desc_buf, sizeof(code_desc_buf), "%d MB", 4480b57cec5SDimitry Andric (int)EXC_RESOURCE_IO_DECODE_LIMIT(m_exc_code)); 4490b57cec5SDimitry Andric snprintf(subcode_desc_buf, sizeof(subcode_desc_buf), "%d MB", 4509dba64beSDimitry Andric (int)EXC_RESOURCE_IO_OBSERVED(m_exc_subcode)); 4519dba64beSDimitry Andric ; 4520b57cec5SDimitry Andric break; 4539dba64beSDimitry Andric #endif 4540b57cec5SDimitry Andric } 4550b57cec5SDimitry Andric } 4560b57cec5SDimitry Andric #endif 4570b57cec5SDimitry Andric break; 4580b57cec5SDimitry Andric case 12: 4590b57cec5SDimitry Andric exc_desc = "EXC_GUARD"; 4600b57cec5SDimitry Andric break; 4610b57cec5SDimitry Andric } 4620b57cec5SDimitry Andric 4630b57cec5SDimitry Andric StreamString strm; 4640b57cec5SDimitry Andric 4650b57cec5SDimitry Andric if (exc_desc) 4660b57cec5SDimitry Andric strm.PutCString(exc_desc); 4670b57cec5SDimitry Andric else 4680b57cec5SDimitry Andric strm.Printf("EXC_??? (%" PRIu64 ")", m_value); 4690b57cec5SDimitry Andric 4700b57cec5SDimitry Andric if (m_exc_data_count >= 1) { 4710b57cec5SDimitry Andric if (code_desc) 4720b57cec5SDimitry Andric strm.Printf(" (%s=%s", code_label, code_desc); 4730b57cec5SDimitry Andric else 4740b57cec5SDimitry Andric strm.Printf(" (%s=%" PRIu64, code_label, m_exc_code); 4750b57cec5SDimitry Andric } 4760b57cec5SDimitry Andric 4770b57cec5SDimitry Andric if (m_exc_data_count >= 2) { 478bdd1243dSDimitry Andric if (subcode_label && subcode_desc) 4790b57cec5SDimitry Andric strm.Printf(", %s=%s", subcode_label, subcode_desc); 480bdd1243dSDimitry Andric else if (subcode_label) 4810b57cec5SDimitry Andric strm.Printf(", %s=0x%" PRIx64, subcode_label, m_exc_subcode); 4820b57cec5SDimitry Andric } 4830b57cec5SDimitry Andric 4840b57cec5SDimitry Andric if (m_exc_data_count > 0) 4850b57cec5SDimitry Andric strm.PutChar(')'); 4860b57cec5SDimitry Andric 4875ffd83dbSDimitry Andric m_description = std::string(strm.GetString()); 4880b57cec5SDimitry Andric return m_description.c_str(); 4890b57cec5SDimitry Andric } 4900b57cec5SDimitry Andric 4915ffd83dbSDimitry Andric static StopInfoSP GetStopInfoForHardwareBP(Thread &thread, Target *target, 4925ffd83dbSDimitry Andric uint32_t exc_data_count, 4935ffd83dbSDimitry Andric uint64_t exc_sub_code, 4945ffd83dbSDimitry Andric uint64_t exc_sub_sub_code) { 4955ffd83dbSDimitry Andric // Try hardware watchpoint. 4965ffd83dbSDimitry Andric if (target) { 4975ffd83dbSDimitry Andric // The exc_sub_code indicates the data break address. 498*0fca6ea1SDimitry Andric WatchpointResourceSP wp_rsrc_sp = 499*0fca6ea1SDimitry Andric target->GetProcessSP()->GetWatchpointResourceList().FindByAddress( 500*0fca6ea1SDimitry Andric (addr_t)exc_sub_code); 501*0fca6ea1SDimitry Andric if (wp_rsrc_sp && wp_rsrc_sp->GetNumberOfConstituents() > 0) { 502*0fca6ea1SDimitry Andric return StopInfo::CreateStopReasonWithWatchpointID( 503*0fca6ea1SDimitry Andric thread, wp_rsrc_sp->GetConstituentAtIndex(0)->GetID()); 5045ffd83dbSDimitry Andric } 5055ffd83dbSDimitry Andric } 5065ffd83dbSDimitry Andric 5075ffd83dbSDimitry Andric // Try hardware breakpoint. 5085ffd83dbSDimitry Andric ProcessSP process_sp(thread.GetProcess()); 5095ffd83dbSDimitry Andric if (process_sp) { 5105ffd83dbSDimitry Andric // The exc_sub_code indicates the data break address. 5115ffd83dbSDimitry Andric lldb::BreakpointSiteSP bp_sp = 5125ffd83dbSDimitry Andric process_sp->GetBreakpointSiteList().FindByAddress( 5135ffd83dbSDimitry Andric (lldb::addr_t)exc_sub_code); 5145ffd83dbSDimitry Andric if (bp_sp && bp_sp->IsEnabled()) { 5155ffd83dbSDimitry Andric return StopInfo::CreateStopReasonWithBreakpointSiteID(thread, 5165ffd83dbSDimitry Andric bp_sp->GetID()); 5175ffd83dbSDimitry Andric } 5185ffd83dbSDimitry Andric } 5195ffd83dbSDimitry Andric 5205ffd83dbSDimitry Andric return nullptr; 5215ffd83dbSDimitry Andric } 5225ffd83dbSDimitry Andric 523bdd1243dSDimitry Andric #if defined(__APPLE__) 524bdd1243dSDimitry Andric const char * 525bdd1243dSDimitry Andric StopInfoMachException::MachException::Name(exception_type_t exc_type) { 526bdd1243dSDimitry Andric switch (exc_type) { 527bdd1243dSDimitry Andric case EXC_BAD_ACCESS: 528bdd1243dSDimitry Andric return "EXC_BAD_ACCESS"; 529bdd1243dSDimitry Andric case EXC_BAD_INSTRUCTION: 530bdd1243dSDimitry Andric return "EXC_BAD_INSTRUCTION"; 531bdd1243dSDimitry Andric case EXC_ARITHMETIC: 532bdd1243dSDimitry Andric return "EXC_ARITHMETIC"; 533bdd1243dSDimitry Andric case EXC_EMULATION: 534bdd1243dSDimitry Andric return "EXC_EMULATION"; 535bdd1243dSDimitry Andric case EXC_SOFTWARE: 536bdd1243dSDimitry Andric return "EXC_SOFTWARE"; 537bdd1243dSDimitry Andric case EXC_BREAKPOINT: 538bdd1243dSDimitry Andric return "EXC_BREAKPOINT"; 539bdd1243dSDimitry Andric case EXC_SYSCALL: 540bdd1243dSDimitry Andric return "EXC_SYSCALL"; 541bdd1243dSDimitry Andric case EXC_MACH_SYSCALL: 542bdd1243dSDimitry Andric return "EXC_MACH_SYSCALL"; 543bdd1243dSDimitry Andric case EXC_RPC_ALERT: 544bdd1243dSDimitry Andric return "EXC_RPC_ALERT"; 545bdd1243dSDimitry Andric #ifdef EXC_CRASH 546bdd1243dSDimitry Andric case EXC_CRASH: 547bdd1243dSDimitry Andric return "EXC_CRASH"; 548bdd1243dSDimitry Andric #endif 549bdd1243dSDimitry Andric case EXC_RESOURCE: 550bdd1243dSDimitry Andric return "EXC_RESOURCE"; 551bdd1243dSDimitry Andric #ifdef EXC_GUARD 552bdd1243dSDimitry Andric case EXC_GUARD: 553bdd1243dSDimitry Andric return "EXC_GUARD"; 554bdd1243dSDimitry Andric #endif 555bdd1243dSDimitry Andric #ifdef EXC_CORPSE_NOTIFY 556bdd1243dSDimitry Andric case EXC_CORPSE_NOTIFY: 557bdd1243dSDimitry Andric return "EXC_CORPSE_NOTIFY"; 558bdd1243dSDimitry Andric #endif 559bdd1243dSDimitry Andric #ifdef EXC_CORPSE_VARIANT_BIT 560bdd1243dSDimitry Andric case EXC_CORPSE_VARIANT_BIT: 561bdd1243dSDimitry Andric return "EXC_CORPSE_VARIANT_BIT"; 562bdd1243dSDimitry Andric #endif 563bdd1243dSDimitry Andric default: 564bdd1243dSDimitry Andric break; 565bdd1243dSDimitry Andric } 566bdd1243dSDimitry Andric return NULL; 567bdd1243dSDimitry Andric } 568bdd1243dSDimitry Andric 569bdd1243dSDimitry Andric std::optional<exception_type_t> 570bdd1243dSDimitry Andric StopInfoMachException::MachException::ExceptionCode(const char *name) { 571bdd1243dSDimitry Andric return llvm::StringSwitch<std::optional<exception_type_t>>(name) 572bdd1243dSDimitry Andric .Case("EXC_BAD_ACCESS", EXC_BAD_ACCESS) 573bdd1243dSDimitry Andric .Case("EXC_BAD_INSTRUCTION", EXC_BAD_INSTRUCTION) 574bdd1243dSDimitry Andric .Case("EXC_ARITHMETIC", EXC_ARITHMETIC) 575bdd1243dSDimitry Andric .Case("EXC_EMULATION", EXC_EMULATION) 576bdd1243dSDimitry Andric .Case("EXC_SOFTWARE", EXC_SOFTWARE) 577bdd1243dSDimitry Andric .Case("EXC_BREAKPOINT", EXC_BREAKPOINT) 578bdd1243dSDimitry Andric .Case("EXC_SYSCALL", EXC_SYSCALL) 579bdd1243dSDimitry Andric .Case("EXC_MACH_SYSCALL", EXC_MACH_SYSCALL) 580bdd1243dSDimitry Andric .Case("EXC_RPC_ALERT", EXC_RPC_ALERT) 581bdd1243dSDimitry Andric #ifdef EXC_CRASH 582bdd1243dSDimitry Andric .Case("EXC_CRASH", EXC_CRASH) 583bdd1243dSDimitry Andric #endif 584bdd1243dSDimitry Andric .Case("EXC_RESOURCE", EXC_RESOURCE) 585bdd1243dSDimitry Andric #ifdef EXC_GUARD 586bdd1243dSDimitry Andric .Case("EXC_GUARD", EXC_GUARD) 587bdd1243dSDimitry Andric #endif 588bdd1243dSDimitry Andric #ifdef EXC_CORPSE_NOTIFY 589bdd1243dSDimitry Andric .Case("EXC_CORPSE_NOTIFY", EXC_CORPSE_NOTIFY) 590bdd1243dSDimitry Andric #endif 591bdd1243dSDimitry Andric .Default(std::nullopt); 592bdd1243dSDimitry Andric } 593bdd1243dSDimitry Andric #endif 594bdd1243dSDimitry Andric 5950b57cec5SDimitry Andric StopInfoSP StopInfoMachException::CreateStopReasonWithMachException( 5960b57cec5SDimitry Andric Thread &thread, uint32_t exc_type, uint32_t exc_data_count, 5970b57cec5SDimitry Andric uint64_t exc_code, uint64_t exc_sub_code, uint64_t exc_sub_sub_code, 5980b57cec5SDimitry Andric bool pc_already_adjusted, bool adjust_pc_if_needed) { 5999dba64beSDimitry Andric if (exc_type == 0) 6009dba64beSDimitry Andric return StopInfoSP(); 6019dba64beSDimitry Andric 602*0fca6ea1SDimitry Andric bool not_stepping_but_got_singlestep_exception = false; 6030b57cec5SDimitry Andric uint32_t pc_decrement = 0; 6040b57cec5SDimitry Andric ExecutionContext exe_ctx(thread.shared_from_this()); 6050b57cec5SDimitry Andric Target *target = exe_ctx.GetTargetPtr(); 6060b57cec5SDimitry Andric const llvm::Triple::ArchType cpu = 6070b57cec5SDimitry Andric target ? target->GetArchitecture().GetMachine() 6080b57cec5SDimitry Andric : llvm::Triple::UnknownArch; 6090b57cec5SDimitry Andric 6100b57cec5SDimitry Andric switch (exc_type) { 6110b57cec5SDimitry Andric case 1: // EXC_BAD_ACCESS 6120b57cec5SDimitry Andric case 2: // EXC_BAD_INSTRUCTION 6130b57cec5SDimitry Andric case 3: // EXC_ARITHMETIC 6140b57cec5SDimitry Andric case 4: // EXC_EMULATION 6150b57cec5SDimitry Andric break; 6160b57cec5SDimitry Andric 6170b57cec5SDimitry Andric case 5: // EXC_SOFTWARE 6180b57cec5SDimitry Andric if (exc_code == 0x10003) // EXC_SOFT_SIGNAL 6190b57cec5SDimitry Andric { 6200b57cec5SDimitry Andric if (exc_sub_code == 5) { 6210b57cec5SDimitry Andric // On MacOSX, a SIGTRAP can signify that a process has called exec, 6220b57cec5SDimitry Andric // so we should check with our dynamic loader to verify. 6230b57cec5SDimitry Andric ProcessSP process_sp(thread.GetProcess()); 6240b57cec5SDimitry Andric if (process_sp) { 6250b57cec5SDimitry Andric DynamicLoader *dynamic_loader = process_sp->GetDynamicLoader(); 6260b57cec5SDimitry Andric if (dynamic_loader && dynamic_loader->ProcessDidExec()) { 6270b57cec5SDimitry Andric // The program was re-exec'ed 6280b57cec5SDimitry Andric return StopInfo::CreateStopReasonWithExec(thread); 6290b57cec5SDimitry Andric } 6300b57cec5SDimitry Andric } 6310b57cec5SDimitry Andric } 6320b57cec5SDimitry Andric return StopInfo::CreateStopReasonWithSignal(thread, exc_sub_code); 6330b57cec5SDimitry Andric } 6340b57cec5SDimitry Andric break; 6350b57cec5SDimitry Andric 6360b57cec5SDimitry Andric case 6: // EXC_BREAKPOINT 6370b57cec5SDimitry Andric { 6380b57cec5SDimitry Andric bool is_actual_breakpoint = false; 6390b57cec5SDimitry Andric bool is_trace_if_actual_breakpoint_missing = false; 6400b57cec5SDimitry Andric switch (cpu) { 6410b57cec5SDimitry Andric case llvm::Triple::x86: 6420b57cec5SDimitry Andric case llvm::Triple::x86_64: 6430b57cec5SDimitry Andric if (exc_code == 1) // EXC_I386_SGL 6440b57cec5SDimitry Andric { 6450b57cec5SDimitry Andric if (!exc_sub_code) { 6460b57cec5SDimitry Andric // This looks like a plain trap. 6470b57cec5SDimitry Andric // Have to check if there is a breakpoint here as well. When you 6480b57cec5SDimitry Andric // single-step onto a trap, the single step stops you not to trap. 6490b57cec5SDimitry Andric // Since we also do that check below, let's just use that logic. 6500b57cec5SDimitry Andric is_actual_breakpoint = true; 6510b57cec5SDimitry Andric is_trace_if_actual_breakpoint_missing = true; 6520b57cec5SDimitry Andric } else { 6535ffd83dbSDimitry Andric if (StopInfoSP stop_info = 6545ffd83dbSDimitry Andric GetStopInfoForHardwareBP(thread, target, exc_data_count, 6555ffd83dbSDimitry Andric exc_sub_code, exc_sub_sub_code)) 6565ffd83dbSDimitry Andric return stop_info; 6570b57cec5SDimitry Andric } 6580b57cec5SDimitry Andric } else if (exc_code == 2 || // EXC_I386_BPT 6590b57cec5SDimitry Andric exc_code == 3) // EXC_I386_BPTFLT 6600b57cec5SDimitry Andric { 6610b57cec5SDimitry Andric // KDP returns EXC_I386_BPTFLT for trace breakpoints 6620b57cec5SDimitry Andric if (exc_code == 3) 6630b57cec5SDimitry Andric is_trace_if_actual_breakpoint_missing = true; 6640b57cec5SDimitry Andric 6650b57cec5SDimitry Andric is_actual_breakpoint = true; 6660b57cec5SDimitry Andric if (!pc_already_adjusted) 6670b57cec5SDimitry Andric pc_decrement = 1; 6680b57cec5SDimitry Andric } 6690b57cec5SDimitry Andric break; 6700b57cec5SDimitry Andric 6710b57cec5SDimitry Andric case llvm::Triple::arm: 6720b57cec5SDimitry Andric case llvm::Triple::thumb: 6730b57cec5SDimitry Andric if (exc_code == 0x102) // EXC_ARM_DA_DEBUG 6740b57cec5SDimitry Andric { 6755f757f3fSDimitry Andric // LWP_TODO: We need to find the WatchpointResource that matches 6765f757f3fSDimitry Andric // the address, and evaluate its Watchpoints. 6775f757f3fSDimitry Andric 6780b57cec5SDimitry Andric // It's a watchpoint, then, if the exc_sub_code indicates a 6790b57cec5SDimitry Andric // known/enabled data break address from our watchpoint list. 6800b57cec5SDimitry Andric lldb::WatchpointSP wp_sp; 6810b57cec5SDimitry Andric if (target) 6820b57cec5SDimitry Andric wp_sp = target->GetWatchpointList().FindByAddress( 6830b57cec5SDimitry Andric (lldb::addr_t)exc_sub_code); 6840b57cec5SDimitry Andric if (wp_sp && wp_sp->IsEnabled()) { 6850b57cec5SDimitry Andric return StopInfo::CreateStopReasonWithWatchpointID(thread, 6860b57cec5SDimitry Andric wp_sp->GetID()); 6870b57cec5SDimitry Andric } else { 6880b57cec5SDimitry Andric is_actual_breakpoint = true; 6890b57cec5SDimitry Andric is_trace_if_actual_breakpoint_missing = true; 6900b57cec5SDimitry Andric } 6910b57cec5SDimitry Andric } else if (exc_code == 1) // EXC_ARM_BREAKPOINT 6920b57cec5SDimitry Andric { 6930b57cec5SDimitry Andric is_actual_breakpoint = true; 6940b57cec5SDimitry Andric is_trace_if_actual_breakpoint_missing = true; 6950b57cec5SDimitry Andric } else if (exc_code == 0) // FIXME not EXC_ARM_BREAKPOINT but a kernel 6960b57cec5SDimitry Andric // is currently returning this so accept it 6970b57cec5SDimitry Andric // as indicating a breakpoint until the 6980b57cec5SDimitry Andric // kernel is fixed 6990b57cec5SDimitry Andric { 7000b57cec5SDimitry Andric is_actual_breakpoint = true; 7010b57cec5SDimitry Andric is_trace_if_actual_breakpoint_missing = true; 7020b57cec5SDimitry Andric } 7030b57cec5SDimitry Andric break; 7040b57cec5SDimitry Andric 7059dba64beSDimitry Andric case llvm::Triple::aarch64_32: 7060b57cec5SDimitry Andric case llvm::Triple::aarch64: { 70706c3fb27SDimitry Andric // xnu describes three things with type EXC_BREAKPOINT: 70806c3fb27SDimitry Andric // 70906c3fb27SDimitry Andric // exc_code 0x102 [EXC_ARM_DA_DEBUG], exc_sub_code addr-of-insn 71006c3fb27SDimitry Andric // Watchpoint access. exc_sub_code is the address of the 71106c3fb27SDimitry Andric // instruction which trigged the watchpoint trap. 71206c3fb27SDimitry Andric // debugserver may add the watchpoint number that was triggered 71306c3fb27SDimitry Andric // in exc_sub_sub_code. 71406c3fb27SDimitry Andric // 71506c3fb27SDimitry Andric // exc_code 1 [EXC_ARM_BREAKPOINT], exc_sub_code 0 71606c3fb27SDimitry Andric // Instruction step has completed. 71706c3fb27SDimitry Andric // 71806c3fb27SDimitry Andric // exc_code 1 [EXC_ARM_BREAKPOINT], exc_sub_code address-of-instruction 71906c3fb27SDimitry Andric // Software breakpoint instruction executed. 72006c3fb27SDimitry Andric 7210b57cec5SDimitry Andric if (exc_code == 1 && exc_sub_code == 0) // EXC_ARM_BREAKPOINT 7220b57cec5SDimitry Andric { 7230b57cec5SDimitry Andric // This is hit when we single instruction step aka MDSCR_EL1 SS bit 0 7240b57cec5SDimitry Andric // is set 72506c3fb27SDimitry Andric is_actual_breakpoint = true; 7260b57cec5SDimitry Andric is_trace_if_actual_breakpoint_missing = true; 727*0fca6ea1SDimitry Andric if (thread.GetTemporaryResumeState() != eStateStepping) 728*0fca6ea1SDimitry Andric not_stepping_but_got_singlestep_exception = true; 7290b57cec5SDimitry Andric } 7300b57cec5SDimitry Andric if (exc_code == 0x102) // EXC_ARM_DA_DEBUG 7310b57cec5SDimitry Andric { 7325f757f3fSDimitry Andric // LWP_TODO: We need to find the WatchpointResource that matches 7335f757f3fSDimitry Andric // the address, and evaluate its Watchpoints. 7345f757f3fSDimitry Andric 7350b57cec5SDimitry Andric // It's a watchpoint, then, if the exc_sub_code indicates a 7360b57cec5SDimitry Andric // known/enabled data break address from our watchpoint list. 7370b57cec5SDimitry Andric lldb::WatchpointSP wp_sp; 7380b57cec5SDimitry Andric if (target) 7390b57cec5SDimitry Andric wp_sp = target->GetWatchpointList().FindByAddress( 7400b57cec5SDimitry Andric (lldb::addr_t)exc_sub_code); 7410b57cec5SDimitry Andric if (wp_sp && wp_sp->IsEnabled()) { 7420b57cec5SDimitry Andric return StopInfo::CreateStopReasonWithWatchpointID(thread, 7430b57cec5SDimitry Andric wp_sp->GetID()); 7440b57cec5SDimitry Andric } 7450b57cec5SDimitry Andric // EXC_ARM_DA_DEBUG seems to be reused for EXC_BREAKPOINT as well as 7460b57cec5SDimitry Andric // EXC_BAD_ACCESS 7470b57cec5SDimitry Andric if (thread.GetTemporaryResumeState() == eStateStepping) 7480b57cec5SDimitry Andric return StopInfo::CreateStopReasonToTrace(thread); 7490b57cec5SDimitry Andric } 7500b57cec5SDimitry Andric // It looks like exc_sub_code has the 4 bytes of the instruction that 7510b57cec5SDimitry Andric // triggered the exception, i.e. our breakpoint opcode 7520b57cec5SDimitry Andric is_actual_breakpoint = exc_code == 1; 7530b57cec5SDimitry Andric break; 7540b57cec5SDimitry Andric } 7550b57cec5SDimitry Andric 7560b57cec5SDimitry Andric default: 7570b57cec5SDimitry Andric break; 7580b57cec5SDimitry Andric } 7590b57cec5SDimitry Andric 7600b57cec5SDimitry Andric if (is_actual_breakpoint) { 7610b57cec5SDimitry Andric RegisterContextSP reg_ctx_sp(thread.GetRegisterContext()); 7620b57cec5SDimitry Andric addr_t pc = reg_ctx_sp->GetPC() - pc_decrement; 7630b57cec5SDimitry Andric 7640b57cec5SDimitry Andric ProcessSP process_sp(thread.CalculateProcess()); 7650b57cec5SDimitry Andric 7660b57cec5SDimitry Andric lldb::BreakpointSiteSP bp_site_sp; 7670b57cec5SDimitry Andric if (process_sp) 7680b57cec5SDimitry Andric bp_site_sp = process_sp->GetBreakpointSiteList().FindByAddress(pc); 7690b57cec5SDimitry Andric if (bp_site_sp && bp_site_sp->IsEnabled()) { 7700b57cec5SDimitry Andric // Update the PC if we were asked to do so, but only do so if we find 7710b57cec5SDimitry Andric // a breakpoint that we know about cause this could be a trap 7720b57cec5SDimitry Andric // instruction in the code 7730b57cec5SDimitry Andric if (pc_decrement > 0 && adjust_pc_if_needed) 7740b57cec5SDimitry Andric reg_ctx_sp->SetPC(pc); 7750b57cec5SDimitry Andric 7760b57cec5SDimitry Andric // If the breakpoint is for this thread, then we'll report the hit, 7770b57cec5SDimitry Andric // but if it is for another thread, we can just report no reason. We 7780b57cec5SDimitry Andric // don't need to worry about stepping over the breakpoint here, that 7790b57cec5SDimitry Andric // will be taken care of when the thread resumes and notices that 7800b57cec5SDimitry Andric // there's a breakpoint under the pc. If we have an operating system 7810b57cec5SDimitry Andric // plug-in, we might have set a thread specific breakpoint using the 7820b57cec5SDimitry Andric // operating system thread ID, so we can't make any assumptions about 7830b57cec5SDimitry Andric // the thread ID so we must always report the breakpoint regardless 7840b57cec5SDimitry Andric // of the thread. 785fe6060f1SDimitry Andric if (bp_site_sp->ValidForThisThread(thread) || 7860b57cec5SDimitry Andric thread.GetProcess()->GetOperatingSystem() != nullptr) 7870b57cec5SDimitry Andric return StopInfo::CreateStopReasonWithBreakpointSiteID( 7880b57cec5SDimitry Andric thread, bp_site_sp->GetID()); 7890b57cec5SDimitry Andric else if (is_trace_if_actual_breakpoint_missing) 7900b57cec5SDimitry Andric return StopInfo::CreateStopReasonToTrace(thread); 7910b57cec5SDimitry Andric else 7920b57cec5SDimitry Andric return StopInfoSP(); 7930b57cec5SDimitry Andric } 7940b57cec5SDimitry Andric 7950b57cec5SDimitry Andric // Don't call this a trace if we weren't single stepping this thread. 7960b57cec5SDimitry Andric if (is_trace_if_actual_breakpoint_missing && 7970b57cec5SDimitry Andric thread.GetTemporaryResumeState() == eStateStepping) { 7980b57cec5SDimitry Andric return StopInfo::CreateStopReasonToTrace(thread); 7990b57cec5SDimitry Andric } 8000b57cec5SDimitry Andric } 8010b57cec5SDimitry Andric } break; 8020b57cec5SDimitry Andric 8030b57cec5SDimitry Andric case 7: // EXC_SYSCALL 8040b57cec5SDimitry Andric case 8: // EXC_MACH_SYSCALL 8050b57cec5SDimitry Andric case 9: // EXC_RPC_ALERT 8060b57cec5SDimitry Andric case 10: // EXC_CRASH 8070b57cec5SDimitry Andric break; 8080b57cec5SDimitry Andric } 8090b57cec5SDimitry Andric 810*0fca6ea1SDimitry Andric return std::make_shared<StopInfoMachException>( 811*0fca6ea1SDimitry Andric thread, exc_type, exc_data_count, exc_code, exc_sub_code, 812*0fca6ea1SDimitry Andric not_stepping_but_got_singlestep_exception); 813*0fca6ea1SDimitry Andric } 814*0fca6ea1SDimitry Andric 815*0fca6ea1SDimitry Andric // Detect an unusual situation on Darwin where: 816*0fca6ea1SDimitry Andric // 817*0fca6ea1SDimitry Andric // 0. We did an instruction-step before this. 818*0fca6ea1SDimitry Andric // 1. We have a hardware breakpoint or watchpoint set. 819*0fca6ea1SDimitry Andric // 2. We resumed the process, but not with an instruction-step. 820*0fca6ea1SDimitry Andric // 3. The thread gets an "instruction-step completed" mach exception. 821*0fca6ea1SDimitry Andric // 4. The pc has not advanced - it is the same as before. 822*0fca6ea1SDimitry Andric // 823*0fca6ea1SDimitry Andric // This method returns true for that combination of events. 824*0fca6ea1SDimitry Andric bool StopInfoMachException::WasContinueInterrupted(Thread &thread) { 825*0fca6ea1SDimitry Andric Log *log = GetLog(LLDBLog::Step); 826*0fca6ea1SDimitry Andric 827*0fca6ea1SDimitry Andric // We got an instruction-step completed mach exception but we were not 828*0fca6ea1SDimitry Andric // doing an instruction step on this thread. 829*0fca6ea1SDimitry Andric if (!m_not_stepping_but_got_singlestep_exception) 830*0fca6ea1SDimitry Andric return false; 831*0fca6ea1SDimitry Andric 832*0fca6ea1SDimitry Andric RegisterContextSP reg_ctx_sp(thread.GetRegisterContext()); 833*0fca6ea1SDimitry Andric std::optional<addr_t> prev_pc = thread.GetPreviousFrameZeroPC(); 834*0fca6ea1SDimitry Andric if (!reg_ctx_sp || !prev_pc) 835*0fca6ea1SDimitry Andric return false; 836*0fca6ea1SDimitry Andric 837*0fca6ea1SDimitry Andric // The previous pc value and current pc value are the same. 838*0fca6ea1SDimitry Andric if (*prev_pc != reg_ctx_sp->GetPC()) 839*0fca6ea1SDimitry Andric return false; 840*0fca6ea1SDimitry Andric 841*0fca6ea1SDimitry Andric // We have a watchpoint -- this is the kernel bug. 842*0fca6ea1SDimitry Andric ProcessSP process_sp = thread.GetProcess(); 843*0fca6ea1SDimitry Andric if (process_sp->GetWatchpointResourceList().GetSize()) { 844*0fca6ea1SDimitry Andric LLDB_LOGF(log, 845*0fca6ea1SDimitry Andric "Thread stopped with insn-step completed mach exception but " 846*0fca6ea1SDimitry Andric "thread was not stepping; there is a hardware watchpoint set."); 847*0fca6ea1SDimitry Andric return true; 848*0fca6ea1SDimitry Andric } 849*0fca6ea1SDimitry Andric 850*0fca6ea1SDimitry Andric // We have a hardware breakpoint -- this is the kernel bug. 851*0fca6ea1SDimitry Andric auto &bp_site_list = process_sp->GetBreakpointSiteList(); 852*0fca6ea1SDimitry Andric for (auto &site : bp_site_list.Sites()) { 853*0fca6ea1SDimitry Andric if (site->IsHardware() && site->IsEnabled()) { 854*0fca6ea1SDimitry Andric LLDB_LOGF(log, 855*0fca6ea1SDimitry Andric "Thread stopped with insn-step completed mach exception but " 856*0fca6ea1SDimitry Andric "thread was not stepping; there is a hardware breakpoint set."); 857*0fca6ea1SDimitry Andric return true; 858*0fca6ea1SDimitry Andric } 859*0fca6ea1SDimitry Andric } 860*0fca6ea1SDimitry Andric 861*0fca6ea1SDimitry Andric return false; 8620b57cec5SDimitry Andric } 863