xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1dda28197Spatrick //===-- StopInfoMachException.cpp -----------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "StopInfoMachException.h"
10061da546Spatrick 
11dda28197Spatrick #include "lldb/lldb-forward.h"
12061da546Spatrick 
13061da546Spatrick #if defined(__APPLE__)
14061da546Spatrick // Needed for the EXC_RESOURCE interpretation macros
15061da546Spatrick #include <kern/exc_resource.h>
16061da546Spatrick #endif
17061da546Spatrick 
18061da546Spatrick #include "lldb/Breakpoint/Watchpoint.h"
19061da546Spatrick #include "lldb/Symbol/Symbol.h"
20*f6aab3d8Srobert #include "lldb/Target/ABI.h"
21061da546Spatrick #include "lldb/Target/DynamicLoader.h"
22061da546Spatrick #include "lldb/Target/ExecutionContext.h"
23061da546Spatrick #include "lldb/Target/Process.h"
24061da546Spatrick #include "lldb/Target/RegisterContext.h"
25061da546Spatrick #include "lldb/Target/Target.h"
26061da546Spatrick #include "lldb/Target/Thread.h"
27061da546Spatrick #include "lldb/Target/ThreadPlan.h"
28061da546Spatrick #include "lldb/Target/UnixSignals.h"
29061da546Spatrick #include "lldb/Utility/StreamString.h"
30*f6aab3d8Srobert #include <optional>
31061da546Spatrick 
32061da546Spatrick using namespace lldb;
33061da546Spatrick using namespace lldb_private;
34061da546Spatrick 
35*f6aab3d8Srobert /// Information about a pointer-authentication related instruction.
36*f6aab3d8Srobert struct PtrauthInstructionInfo {
37*f6aab3d8Srobert   bool IsAuthenticated;
38*f6aab3d8Srobert   bool IsLoad;
39*f6aab3d8Srobert   bool DoesBranch;
40*f6aab3d8Srobert };
41*f6aab3d8Srobert 
42*f6aab3d8Srobert /// Get any pointer-authentication related information about the instruction
43*f6aab3d8Srobert /// at address \p at_addr.
44*f6aab3d8Srobert static std::optional<PtrauthInstructionInfo>
GetPtrauthInstructionInfo(Target & target,const ArchSpec & arch,const Address & at_addr)45*f6aab3d8Srobert GetPtrauthInstructionInfo(Target &target, const ArchSpec &arch,
46*f6aab3d8Srobert                           const Address &at_addr) {
47*f6aab3d8Srobert   const char *plugin_name = nullptr;
48*f6aab3d8Srobert   const char *flavor = nullptr;
49*f6aab3d8Srobert   AddressRange range_bounds(at_addr, 4);
50*f6aab3d8Srobert   const bool prefer_file_cache = true;
51*f6aab3d8Srobert   DisassemblerSP disassembler_sp = Disassembler::DisassembleRange(
52*f6aab3d8Srobert       arch, plugin_name, flavor, target, range_bounds, prefer_file_cache);
53*f6aab3d8Srobert   if (!disassembler_sp)
54*f6aab3d8Srobert     return std::nullopt;
55*f6aab3d8Srobert 
56*f6aab3d8Srobert   InstructionList &insn_list = disassembler_sp->GetInstructionList();
57*f6aab3d8Srobert   InstructionSP insn = insn_list.GetInstructionAtIndex(0);
58*f6aab3d8Srobert   if (!insn)
59*f6aab3d8Srobert     return std::nullopt;
60*f6aab3d8Srobert 
61*f6aab3d8Srobert   return PtrauthInstructionInfo{insn->IsAuthenticated(), insn->IsLoad(),
62*f6aab3d8Srobert                                 insn->DoesBranch()};
63*f6aab3d8Srobert }
64*f6aab3d8Srobert 
65*f6aab3d8Srobert /// Describe the load address of \p addr using the format filename:line:col.
DescribeAddressBriefly(Stream & strm,const Address & addr,Target & target)66*f6aab3d8Srobert static void DescribeAddressBriefly(Stream &strm, const Address &addr,
67*f6aab3d8Srobert                                    Target &target) {
68*f6aab3d8Srobert   strm.Printf("at address=0x%" PRIx64, addr.GetLoadAddress(&target));
69*f6aab3d8Srobert   StreamString s;
70*f6aab3d8Srobert   if (addr.GetDescription(s, target, eDescriptionLevelBrief))
71*f6aab3d8Srobert     strm.Printf(" %s", s.GetString().data());
72*f6aab3d8Srobert   strm.Printf(".\n");
73*f6aab3d8Srobert }
74*f6aab3d8Srobert 
DeterminePtrauthFailure(ExecutionContext & exe_ctx)75*f6aab3d8Srobert bool StopInfoMachException::DeterminePtrauthFailure(ExecutionContext &exe_ctx) {
76*f6aab3d8Srobert   bool IsBreakpoint = m_value == 6; // EXC_BREAKPOINT
77*f6aab3d8Srobert   bool IsBadAccess = m_value == 1;  // EXC_BAD_ACCESS
78*f6aab3d8Srobert   if (!IsBreakpoint && !IsBadAccess)
79*f6aab3d8Srobert     return false;
80*f6aab3d8Srobert 
81*f6aab3d8Srobert   // Check that we have a live process.
82*f6aab3d8Srobert   if (!exe_ctx.HasProcessScope() || !exe_ctx.HasThreadScope() ||
83*f6aab3d8Srobert       !exe_ctx.HasTargetScope())
84*f6aab3d8Srobert     return false;
85*f6aab3d8Srobert 
86*f6aab3d8Srobert   Thread &thread = *exe_ctx.GetThreadPtr();
87*f6aab3d8Srobert   StackFrameSP current_frame = thread.GetStackFrameAtIndex(0);
88*f6aab3d8Srobert   if (!current_frame)
89*f6aab3d8Srobert     return false;
90*f6aab3d8Srobert 
91*f6aab3d8Srobert   Target &target = *exe_ctx.GetTargetPtr();
92*f6aab3d8Srobert   Process &process = *exe_ctx.GetProcessPtr();
93*f6aab3d8Srobert   ABISP abi_sp = process.GetABI();
94*f6aab3d8Srobert   const ArchSpec &arch = target.GetArchitecture();
95*f6aab3d8Srobert   assert(abi_sp && "Missing ABI info");
96*f6aab3d8Srobert 
97*f6aab3d8Srobert   // Check for a ptrauth-enabled target.
98*f6aab3d8Srobert   const bool ptrauth_enabled_target =
99*f6aab3d8Srobert       arch.GetCore() == ArchSpec::eCore_arm_arm64e;
100*f6aab3d8Srobert   if (!ptrauth_enabled_target)
101*f6aab3d8Srobert     return false;
102*f6aab3d8Srobert 
103*f6aab3d8Srobert   // Set up a stream we can write a diagnostic into.
104*f6aab3d8Srobert   StreamString strm;
105*f6aab3d8Srobert   auto emit_ptrauth_prologue = [&](uint64_t at_address) {
106*f6aab3d8Srobert     strm.Printf("EXC_BAD_ACCESS (code=%" PRIu64 ", address=0x%" PRIx64 ")\n",
107*f6aab3d8Srobert                 m_exc_code, at_address);
108*f6aab3d8Srobert     strm.Printf("Note: Possible pointer authentication failure detected.\n");
109*f6aab3d8Srobert   };
110*f6aab3d8Srobert 
111*f6aab3d8Srobert   // Check if we have a "brk 0xc47x" trap, where the value that failed to
112*f6aab3d8Srobert   // authenticate is in x16.
113*f6aab3d8Srobert   Address current_address = current_frame->GetFrameCodeAddress();
114*f6aab3d8Srobert   if (IsBreakpoint) {
115*f6aab3d8Srobert     RegisterContext *reg_ctx = exe_ctx.GetRegisterContext();
116*f6aab3d8Srobert     if (!reg_ctx)
117*f6aab3d8Srobert       return false;
118*f6aab3d8Srobert 
119*f6aab3d8Srobert     const RegisterInfo *X16Info = reg_ctx->GetRegisterInfoByName("x16");
120*f6aab3d8Srobert     RegisterValue X16Val;
121*f6aab3d8Srobert     if (!reg_ctx->ReadRegister(X16Info, X16Val))
122*f6aab3d8Srobert       return false;
123*f6aab3d8Srobert     uint64_t bad_address = X16Val.GetAsUInt64();
124*f6aab3d8Srobert 
125*f6aab3d8Srobert     uint64_t fixed_bad_address = abi_sp->FixCodeAddress(bad_address);
126*f6aab3d8Srobert     Address brk_address;
127*f6aab3d8Srobert     if (!target.ResolveLoadAddress(fixed_bad_address, brk_address))
128*f6aab3d8Srobert       return false;
129*f6aab3d8Srobert 
130*f6aab3d8Srobert     auto brk_ptrauth_info =
131*f6aab3d8Srobert         GetPtrauthInstructionInfo(target, arch, current_address);
132*f6aab3d8Srobert     if (brk_ptrauth_info && brk_ptrauth_info->IsAuthenticated) {
133*f6aab3d8Srobert       emit_ptrauth_prologue(bad_address);
134*f6aab3d8Srobert       strm.Printf("Found value that failed to authenticate ");
135*f6aab3d8Srobert       DescribeAddressBriefly(strm, brk_address, target);
136*f6aab3d8Srobert       m_description = std::string(strm.GetString());
137*f6aab3d8Srobert       return true;
138*f6aab3d8Srobert     }
139*f6aab3d8Srobert     return false;
140*f6aab3d8Srobert   }
141*f6aab3d8Srobert 
142*f6aab3d8Srobert   assert(IsBadAccess && "Handle EXC_BAD_ACCESS only after this point");
143*f6aab3d8Srobert 
144*f6aab3d8Srobert   // Check that we have the "bad address" from an EXC_BAD_ACCESS.
145*f6aab3d8Srobert   if (m_exc_data_count < 2)
146*f6aab3d8Srobert     return false;
147*f6aab3d8Srobert 
148*f6aab3d8Srobert   // Ok, we know the Target is valid and that it describes a ptrauth-enabled
149*f6aab3d8Srobert   // device. Now, we need to determine whether this exception was caused by a
150*f6aab3d8Srobert   // ptrauth failure.
151*f6aab3d8Srobert 
152*f6aab3d8Srobert   uint64_t bad_address = m_exc_subcode;
153*f6aab3d8Srobert   uint64_t fixed_bad_address = abi_sp->FixCodeAddress(bad_address);
154*f6aab3d8Srobert   uint64_t current_pc = current_address.GetLoadAddress(&target);
155*f6aab3d8Srobert 
156*f6aab3d8Srobert   // Detect: LDRAA, LDRAB (Load Register, with pointer authentication).
157*f6aab3d8Srobert   //
158*f6aab3d8Srobert   // If an authenticated load results in an exception, the instruction at the
159*f6aab3d8Srobert   // current PC should be one of LDRAx.
160*f6aab3d8Srobert   if (bad_address != current_pc && fixed_bad_address != current_pc) {
161*f6aab3d8Srobert     auto ptrauth_info =
162*f6aab3d8Srobert         GetPtrauthInstructionInfo(target, arch, current_address);
163*f6aab3d8Srobert     if (ptrauth_info && ptrauth_info->IsAuthenticated && ptrauth_info->IsLoad) {
164*f6aab3d8Srobert       emit_ptrauth_prologue(bad_address);
165*f6aab3d8Srobert       strm.Printf("Found authenticated load instruction ");
166*f6aab3d8Srobert       DescribeAddressBriefly(strm, current_address, target);
167*f6aab3d8Srobert       m_description = std::string(strm.GetString());
168*f6aab3d8Srobert       return true;
169*f6aab3d8Srobert     }
170*f6aab3d8Srobert   }
171*f6aab3d8Srobert 
172*f6aab3d8Srobert   // Detect: BLRAA, BLRAAZ, BLRAB, BLRABZ (Branch with Link to Register, with
173*f6aab3d8Srobert   // pointer authentication).
174*f6aab3d8Srobert   //
175*f6aab3d8Srobert   // TODO: Detect: BRAA, BRAAZ, BRAB, BRABZ (Branch to Register, with pointer
176*f6aab3d8Srobert   // authentication). At a minimum, this requires call site info support for
177*f6aab3d8Srobert   // indirect calls.
178*f6aab3d8Srobert   //
179*f6aab3d8Srobert   // If an authenticated call or tail call results in an exception, stripping
180*f6aab3d8Srobert   // the bad address should give the current PC, which points to the address
181*f6aab3d8Srobert   // we tried to branch to.
182*f6aab3d8Srobert   if (bad_address != current_pc && fixed_bad_address == current_pc) {
183*f6aab3d8Srobert     if (StackFrameSP parent_frame = thread.GetStackFrameAtIndex(1)) {
184*f6aab3d8Srobert       addr_t return_pc =
185*f6aab3d8Srobert           parent_frame->GetFrameCodeAddress().GetLoadAddress(&target);
186*f6aab3d8Srobert       Address blr_address;
187*f6aab3d8Srobert       if (!target.ResolveLoadAddress(return_pc - 4, blr_address))
188*f6aab3d8Srobert         return false;
189*f6aab3d8Srobert 
190*f6aab3d8Srobert       auto blr_ptrauth_info =
191*f6aab3d8Srobert           GetPtrauthInstructionInfo(target, arch, blr_address);
192*f6aab3d8Srobert       if (blr_ptrauth_info && blr_ptrauth_info->IsAuthenticated &&
193*f6aab3d8Srobert           blr_ptrauth_info->DoesBranch) {
194*f6aab3d8Srobert         emit_ptrauth_prologue(bad_address);
195*f6aab3d8Srobert         strm.Printf("Found authenticated indirect branch ");
196*f6aab3d8Srobert         DescribeAddressBriefly(strm, blr_address, target);
197*f6aab3d8Srobert         m_description = std::string(strm.GetString());
198*f6aab3d8Srobert         return true;
199*f6aab3d8Srobert       }
200*f6aab3d8Srobert     }
201*f6aab3d8Srobert   }
202*f6aab3d8Srobert 
203*f6aab3d8Srobert   // TODO: Detect: RETAA, RETAB (Return from subroutine, with pointer
204*f6aab3d8Srobert   // authentication).
205*f6aab3d8Srobert   //
206*f6aab3d8Srobert   // Is there a motivating, non-malicious code snippet that corrupts LR?
207*f6aab3d8Srobert 
208*f6aab3d8Srobert   return false;
209*f6aab3d8Srobert }
210*f6aab3d8Srobert 
GetDescription()211061da546Spatrick const char *StopInfoMachException::GetDescription() {
212061da546Spatrick   if (!m_description.empty())
213061da546Spatrick     return m_description.c_str();
214061da546Spatrick   if (GetValue() == eStopReasonInvalid)
215061da546Spatrick     return "invalid stop reason!";
216061da546Spatrick 
217061da546Spatrick   ExecutionContext exe_ctx(m_thread_wp.lock());
218061da546Spatrick   Target *target = exe_ctx.GetTargetPtr();
219061da546Spatrick   const llvm::Triple::ArchType cpu =
220061da546Spatrick       target ? target->GetArchitecture().GetMachine()
221061da546Spatrick              : llvm::Triple::UnknownArch;
222061da546Spatrick 
223061da546Spatrick   const char *exc_desc = nullptr;
224061da546Spatrick   const char *code_label = "code";
225061da546Spatrick   const char *code_desc = nullptr;
226061da546Spatrick   const char *subcode_label = "subcode";
227061da546Spatrick   const char *subcode_desc = nullptr;
228061da546Spatrick 
229061da546Spatrick #if defined(__APPLE__)
230061da546Spatrick   char code_desc_buf[32];
231061da546Spatrick   char subcode_desc_buf[32];
232061da546Spatrick #endif
233061da546Spatrick 
234061da546Spatrick   switch (m_value) {
235061da546Spatrick   case 1: // EXC_BAD_ACCESS
236061da546Spatrick     exc_desc = "EXC_BAD_ACCESS";
237061da546Spatrick     subcode_label = "address";
238061da546Spatrick     switch (cpu) {
239061da546Spatrick     case llvm::Triple::x86:
240061da546Spatrick     case llvm::Triple::x86_64:
241061da546Spatrick       switch (m_exc_code) {
242061da546Spatrick       case 0xd:
243061da546Spatrick         code_desc = "EXC_I386_GPFLT";
244061da546Spatrick         m_exc_data_count = 1;
245061da546Spatrick         break;
246061da546Spatrick       }
247061da546Spatrick       break;
248061da546Spatrick     case llvm::Triple::arm:
249061da546Spatrick     case llvm::Triple::thumb:
250061da546Spatrick       switch (m_exc_code) {
251061da546Spatrick       case 0x101:
252061da546Spatrick         code_desc = "EXC_ARM_DA_ALIGN";
253061da546Spatrick         break;
254061da546Spatrick       case 0x102:
255061da546Spatrick         code_desc = "EXC_ARM_DA_DEBUG";
256061da546Spatrick         break;
257061da546Spatrick       }
258061da546Spatrick       break;
259061da546Spatrick 
260*f6aab3d8Srobert     case llvm::Triple::aarch64:
261*f6aab3d8Srobert       if (DeterminePtrauthFailure(exe_ctx))
262*f6aab3d8Srobert         return m_description.c_str();
263*f6aab3d8Srobert       break;
264*f6aab3d8Srobert 
265061da546Spatrick     default:
266061da546Spatrick       break;
267061da546Spatrick     }
268061da546Spatrick     break;
269061da546Spatrick 
270061da546Spatrick   case 2: // EXC_BAD_INSTRUCTION
271061da546Spatrick     exc_desc = "EXC_BAD_INSTRUCTION";
272061da546Spatrick     switch (cpu) {
273061da546Spatrick     case llvm::Triple::x86:
274061da546Spatrick     case llvm::Triple::x86_64:
275061da546Spatrick       if (m_exc_code == 1)
276061da546Spatrick         code_desc = "EXC_I386_INVOP";
277061da546Spatrick       break;
278061da546Spatrick 
279061da546Spatrick     case llvm::Triple::arm:
280061da546Spatrick     case llvm::Triple::thumb:
281061da546Spatrick       if (m_exc_code == 1)
282061da546Spatrick         code_desc = "EXC_ARM_UNDEFINED";
283061da546Spatrick       break;
284061da546Spatrick 
285061da546Spatrick     default:
286061da546Spatrick       break;
287061da546Spatrick     }
288061da546Spatrick     break;
289061da546Spatrick 
290061da546Spatrick   case 3: // EXC_ARITHMETIC
291061da546Spatrick     exc_desc = "EXC_ARITHMETIC";
292061da546Spatrick     switch (cpu) {
293061da546Spatrick     case llvm::Triple::x86:
294061da546Spatrick     case llvm::Triple::x86_64:
295061da546Spatrick       switch (m_exc_code) {
296061da546Spatrick       case 1:
297061da546Spatrick         code_desc = "EXC_I386_DIV";
298061da546Spatrick         break;
299061da546Spatrick       case 2:
300061da546Spatrick         code_desc = "EXC_I386_INTO";
301061da546Spatrick         break;
302061da546Spatrick       case 3:
303061da546Spatrick         code_desc = "EXC_I386_NOEXT";
304061da546Spatrick         break;
305061da546Spatrick       case 4:
306061da546Spatrick         code_desc = "EXC_I386_EXTOVR";
307061da546Spatrick         break;
308061da546Spatrick       case 5:
309061da546Spatrick         code_desc = "EXC_I386_EXTERR";
310061da546Spatrick         break;
311061da546Spatrick       case 6:
312061da546Spatrick         code_desc = "EXC_I386_EMERR";
313061da546Spatrick         break;
314061da546Spatrick       case 7:
315061da546Spatrick         code_desc = "EXC_I386_BOUND";
316061da546Spatrick         break;
317061da546Spatrick       case 8:
318061da546Spatrick         code_desc = "EXC_I386_SSEEXTERR";
319061da546Spatrick         break;
320061da546Spatrick       }
321061da546Spatrick       break;
322061da546Spatrick 
323061da546Spatrick     default:
324061da546Spatrick       break;
325061da546Spatrick     }
326061da546Spatrick     break;
327061da546Spatrick 
328061da546Spatrick   case 4: // EXC_EMULATION
329061da546Spatrick     exc_desc = "EXC_EMULATION";
330061da546Spatrick     break;
331061da546Spatrick 
332061da546Spatrick   case 5: // EXC_SOFTWARE
333061da546Spatrick     exc_desc = "EXC_SOFTWARE";
334061da546Spatrick     if (m_exc_code == 0x10003) {
335061da546Spatrick       subcode_desc = "EXC_SOFT_SIGNAL";
336061da546Spatrick       subcode_label = "signo";
337061da546Spatrick     }
338061da546Spatrick     break;
339061da546Spatrick 
340061da546Spatrick   case 6: // EXC_BREAKPOINT
341061da546Spatrick   {
342061da546Spatrick     exc_desc = "EXC_BREAKPOINT";
343061da546Spatrick     switch (cpu) {
344061da546Spatrick     case llvm::Triple::x86:
345061da546Spatrick     case llvm::Triple::x86_64:
346061da546Spatrick       switch (m_exc_code) {
347061da546Spatrick       case 1:
348061da546Spatrick         code_desc = "EXC_I386_SGL";
349061da546Spatrick         break;
350061da546Spatrick       case 2:
351061da546Spatrick         code_desc = "EXC_I386_BPT";
352061da546Spatrick         break;
353061da546Spatrick       }
354061da546Spatrick       break;
355061da546Spatrick 
356061da546Spatrick     case llvm::Triple::arm:
357061da546Spatrick     case llvm::Triple::thumb:
358061da546Spatrick       switch (m_exc_code) {
359061da546Spatrick       case 0x101:
360061da546Spatrick         code_desc = "EXC_ARM_DA_ALIGN";
361061da546Spatrick         break;
362061da546Spatrick       case 0x102:
363061da546Spatrick         code_desc = "EXC_ARM_DA_DEBUG";
364061da546Spatrick         break;
365061da546Spatrick       case 1:
366061da546Spatrick         code_desc = "EXC_ARM_BREAKPOINT";
367061da546Spatrick         break;
368061da546Spatrick       // FIXME temporary workaround, exc_code 0 does not really mean
369061da546Spatrick       // EXC_ARM_BREAKPOINT
370061da546Spatrick       case 0:
371061da546Spatrick         code_desc = "EXC_ARM_BREAKPOINT";
372061da546Spatrick         break;
373061da546Spatrick       }
374061da546Spatrick       break;
375061da546Spatrick 
376*f6aab3d8Srobert     case llvm::Triple::aarch64:
377*f6aab3d8Srobert       if (DeterminePtrauthFailure(exe_ctx))
378*f6aab3d8Srobert         return m_description.c_str();
379*f6aab3d8Srobert       break;
380*f6aab3d8Srobert 
381061da546Spatrick     default:
382061da546Spatrick       break;
383061da546Spatrick     }
384061da546Spatrick   } break;
385061da546Spatrick 
386061da546Spatrick   case 7:
387061da546Spatrick     exc_desc = "EXC_SYSCALL";
388061da546Spatrick     break;
389061da546Spatrick 
390061da546Spatrick   case 8:
391061da546Spatrick     exc_desc = "EXC_MACH_SYSCALL";
392061da546Spatrick     break;
393061da546Spatrick 
394061da546Spatrick   case 9:
395061da546Spatrick     exc_desc = "EXC_RPC_ALERT";
396061da546Spatrick     break;
397061da546Spatrick 
398061da546Spatrick   case 10:
399061da546Spatrick     exc_desc = "EXC_CRASH";
400061da546Spatrick     break;
401061da546Spatrick   case 11:
402061da546Spatrick     exc_desc = "EXC_RESOURCE";
403061da546Spatrick #if defined(__APPLE__)
404061da546Spatrick     {
405061da546Spatrick       int resource_type = EXC_RESOURCE_DECODE_RESOURCE_TYPE(m_exc_code);
406061da546Spatrick 
407061da546Spatrick       code_label = "limit";
408061da546Spatrick       code_desc = code_desc_buf;
409061da546Spatrick       subcode_label = "observed";
410061da546Spatrick       subcode_desc = subcode_desc_buf;
411061da546Spatrick 
412061da546Spatrick       switch (resource_type) {
413061da546Spatrick       case RESOURCE_TYPE_CPU:
414*f6aab3d8Srobert         exc_desc =
415*f6aab3d8Srobert             "EXC_RESOURCE (RESOURCE_TYPE_CPU: CPU usage monitor tripped)";
416061da546Spatrick         snprintf(code_desc_buf, sizeof(code_desc_buf), "%d%%",
417061da546Spatrick                  (int)EXC_RESOURCE_CPUMONITOR_DECODE_PERCENTAGE(m_exc_code));
418061da546Spatrick         snprintf(subcode_desc_buf, sizeof(subcode_desc_buf), "%d%%",
419061da546Spatrick                  (int)EXC_RESOURCE_CPUMONITOR_DECODE_PERCENTAGE_OBSERVED(
420061da546Spatrick                      m_exc_subcode));
421061da546Spatrick         break;
422061da546Spatrick       case RESOURCE_TYPE_WAKEUPS:
423*f6aab3d8Srobert         exc_desc = "EXC_RESOURCE (RESOURCE_TYPE_WAKEUPS: idle wakeups monitor "
424*f6aab3d8Srobert                    "tripped)";
425061da546Spatrick         snprintf(
426061da546Spatrick             code_desc_buf, sizeof(code_desc_buf), "%d w/s",
427061da546Spatrick             (int)EXC_RESOURCE_CPUMONITOR_DECODE_WAKEUPS_PERMITTED(m_exc_code));
428061da546Spatrick         snprintf(subcode_desc_buf, sizeof(subcode_desc_buf), "%d w/s",
429061da546Spatrick                  (int)EXC_RESOURCE_CPUMONITOR_DECODE_WAKEUPS_OBSERVED(
430061da546Spatrick                      m_exc_subcode));
431061da546Spatrick         break;
432061da546Spatrick       case RESOURCE_TYPE_MEMORY:
433*f6aab3d8Srobert         exc_desc = "EXC_RESOURCE (RESOURCE_TYPE_MEMORY: high watermark memory "
434*f6aab3d8Srobert                    "limit exceeded)";
435061da546Spatrick         snprintf(code_desc_buf, sizeof(code_desc_buf), "%d MB",
436061da546Spatrick                  (int)EXC_RESOURCE_HWM_DECODE_LIMIT(m_exc_code));
437061da546Spatrick         subcode_desc = nullptr;
438*f6aab3d8Srobert         subcode_label = nullptr;
439061da546Spatrick         break;
440061da546Spatrick #if defined(RESOURCE_TYPE_IO)
441061da546Spatrick       // RESOURCE_TYPE_IO is introduced in macOS SDK 10.12.
442061da546Spatrick       case RESOURCE_TYPE_IO:
443061da546Spatrick         exc_desc = "EXC_RESOURCE RESOURCE_TYPE_IO";
444061da546Spatrick         snprintf(code_desc_buf, sizeof(code_desc_buf), "%d MB",
445061da546Spatrick                  (int)EXC_RESOURCE_IO_DECODE_LIMIT(m_exc_code));
446061da546Spatrick         snprintf(subcode_desc_buf, sizeof(subcode_desc_buf), "%d MB",
447061da546Spatrick                  (int)EXC_RESOURCE_IO_OBSERVED(m_exc_subcode));
448061da546Spatrick         ;
449061da546Spatrick         break;
450061da546Spatrick #endif
451061da546Spatrick       }
452061da546Spatrick     }
453061da546Spatrick #endif
454061da546Spatrick     break;
455061da546Spatrick   case 12:
456061da546Spatrick     exc_desc = "EXC_GUARD";
457061da546Spatrick     break;
458061da546Spatrick   }
459061da546Spatrick 
460061da546Spatrick   StreamString strm;
461061da546Spatrick 
462061da546Spatrick   if (exc_desc)
463061da546Spatrick     strm.PutCString(exc_desc);
464061da546Spatrick   else
465061da546Spatrick     strm.Printf("EXC_??? (%" PRIu64 ")", m_value);
466061da546Spatrick 
467061da546Spatrick   if (m_exc_data_count >= 1) {
468061da546Spatrick     if (code_desc)
469061da546Spatrick       strm.Printf(" (%s=%s", code_label, code_desc);
470061da546Spatrick     else
471061da546Spatrick       strm.Printf(" (%s=%" PRIu64, code_label, m_exc_code);
472061da546Spatrick   }
473061da546Spatrick 
474061da546Spatrick   if (m_exc_data_count >= 2) {
475*f6aab3d8Srobert     if (subcode_label && subcode_desc)
476061da546Spatrick       strm.Printf(", %s=%s", subcode_label, subcode_desc);
477*f6aab3d8Srobert     else if (subcode_label)
478061da546Spatrick       strm.Printf(", %s=0x%" PRIx64, subcode_label, m_exc_subcode);
479061da546Spatrick   }
480061da546Spatrick 
481061da546Spatrick   if (m_exc_data_count > 0)
482061da546Spatrick     strm.PutChar(')');
483061da546Spatrick 
484dda28197Spatrick   m_description = std::string(strm.GetString());
485061da546Spatrick   return m_description.c_str();
486061da546Spatrick }
487061da546Spatrick 
GetStopInfoForHardwareBP(Thread & thread,Target * target,uint32_t exc_data_count,uint64_t exc_sub_code,uint64_t exc_sub_sub_code)488dda28197Spatrick static StopInfoSP GetStopInfoForHardwareBP(Thread &thread, Target *target,
489dda28197Spatrick                                            uint32_t exc_data_count,
490dda28197Spatrick                                            uint64_t exc_sub_code,
491dda28197Spatrick                                            uint64_t exc_sub_sub_code) {
492dda28197Spatrick   // Try hardware watchpoint.
493dda28197Spatrick   if (target) {
494dda28197Spatrick     // The exc_sub_code indicates the data break address.
495dda28197Spatrick     lldb::WatchpointSP wp_sp =
496dda28197Spatrick         target->GetWatchpointList().FindByAddress((lldb::addr_t)exc_sub_code);
497dda28197Spatrick     if (wp_sp && wp_sp->IsEnabled()) {
498dda28197Spatrick       // Debugserver may piggyback the hardware index of the fired watchpoint
499dda28197Spatrick       // in the exception data. Set the hardware index if that's the case.
500dda28197Spatrick       if (exc_data_count >= 3)
501dda28197Spatrick         wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
502dda28197Spatrick       return StopInfo::CreateStopReasonWithWatchpointID(thread, wp_sp->GetID());
503dda28197Spatrick     }
504dda28197Spatrick   }
505dda28197Spatrick 
506dda28197Spatrick   // Try hardware breakpoint.
507dda28197Spatrick   ProcessSP process_sp(thread.GetProcess());
508dda28197Spatrick   if (process_sp) {
509dda28197Spatrick     // The exc_sub_code indicates the data break address.
510dda28197Spatrick     lldb::BreakpointSiteSP bp_sp =
511dda28197Spatrick         process_sp->GetBreakpointSiteList().FindByAddress(
512dda28197Spatrick             (lldb::addr_t)exc_sub_code);
513dda28197Spatrick     if (bp_sp && bp_sp->IsEnabled()) {
514dda28197Spatrick       // Debugserver may piggyback the hardware index of the fired breakpoint
515dda28197Spatrick       // in the exception data. Set the hardware index if that's the case.
516dda28197Spatrick       if (exc_data_count >= 3)
517dda28197Spatrick         bp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
518dda28197Spatrick       return StopInfo::CreateStopReasonWithBreakpointSiteID(thread,
519dda28197Spatrick                                                             bp_sp->GetID());
520dda28197Spatrick     }
521dda28197Spatrick   }
522dda28197Spatrick 
523dda28197Spatrick   return nullptr;
524dda28197Spatrick }
525dda28197Spatrick 
526*f6aab3d8Srobert #if defined(__APPLE__)
527*f6aab3d8Srobert const char *
Name(exception_type_t exc_type)528*f6aab3d8Srobert StopInfoMachException::MachException::Name(exception_type_t exc_type) {
529*f6aab3d8Srobert   switch (exc_type) {
530*f6aab3d8Srobert   case EXC_BAD_ACCESS:
531*f6aab3d8Srobert     return "EXC_BAD_ACCESS";
532*f6aab3d8Srobert   case EXC_BAD_INSTRUCTION:
533*f6aab3d8Srobert     return "EXC_BAD_INSTRUCTION";
534*f6aab3d8Srobert   case EXC_ARITHMETIC:
535*f6aab3d8Srobert     return "EXC_ARITHMETIC";
536*f6aab3d8Srobert   case EXC_EMULATION:
537*f6aab3d8Srobert     return "EXC_EMULATION";
538*f6aab3d8Srobert   case EXC_SOFTWARE:
539*f6aab3d8Srobert     return "EXC_SOFTWARE";
540*f6aab3d8Srobert   case EXC_BREAKPOINT:
541*f6aab3d8Srobert     return "EXC_BREAKPOINT";
542*f6aab3d8Srobert   case EXC_SYSCALL:
543*f6aab3d8Srobert     return "EXC_SYSCALL";
544*f6aab3d8Srobert   case EXC_MACH_SYSCALL:
545*f6aab3d8Srobert     return "EXC_MACH_SYSCALL";
546*f6aab3d8Srobert   case EXC_RPC_ALERT:
547*f6aab3d8Srobert     return "EXC_RPC_ALERT";
548*f6aab3d8Srobert #ifdef EXC_CRASH
549*f6aab3d8Srobert   case EXC_CRASH:
550*f6aab3d8Srobert     return "EXC_CRASH";
551*f6aab3d8Srobert #endif
552*f6aab3d8Srobert   case EXC_RESOURCE:
553*f6aab3d8Srobert     return "EXC_RESOURCE";
554*f6aab3d8Srobert #ifdef EXC_GUARD
555*f6aab3d8Srobert   case EXC_GUARD:
556*f6aab3d8Srobert     return "EXC_GUARD";
557*f6aab3d8Srobert #endif
558*f6aab3d8Srobert #ifdef EXC_CORPSE_NOTIFY
559*f6aab3d8Srobert   case EXC_CORPSE_NOTIFY:
560*f6aab3d8Srobert     return "EXC_CORPSE_NOTIFY";
561*f6aab3d8Srobert #endif
562*f6aab3d8Srobert #ifdef EXC_CORPSE_VARIANT_BIT
563*f6aab3d8Srobert   case EXC_CORPSE_VARIANT_BIT:
564*f6aab3d8Srobert     return "EXC_CORPSE_VARIANT_BIT";
565*f6aab3d8Srobert #endif
566*f6aab3d8Srobert   default:
567*f6aab3d8Srobert     break;
568*f6aab3d8Srobert   }
569*f6aab3d8Srobert   return NULL;
570*f6aab3d8Srobert }
571*f6aab3d8Srobert 
572*f6aab3d8Srobert std::optional<exception_type_t>
ExceptionCode(const char * name)573*f6aab3d8Srobert StopInfoMachException::MachException::ExceptionCode(const char *name) {
574*f6aab3d8Srobert   return llvm::StringSwitch<std::optional<exception_type_t>>(name)
575*f6aab3d8Srobert       .Case("EXC_BAD_ACCESS", EXC_BAD_ACCESS)
576*f6aab3d8Srobert       .Case("EXC_BAD_INSTRUCTION", EXC_BAD_INSTRUCTION)
577*f6aab3d8Srobert       .Case("EXC_ARITHMETIC", EXC_ARITHMETIC)
578*f6aab3d8Srobert       .Case("EXC_EMULATION", EXC_EMULATION)
579*f6aab3d8Srobert       .Case("EXC_SOFTWARE", EXC_SOFTWARE)
580*f6aab3d8Srobert       .Case("EXC_BREAKPOINT", EXC_BREAKPOINT)
581*f6aab3d8Srobert       .Case("EXC_SYSCALL", EXC_SYSCALL)
582*f6aab3d8Srobert       .Case("EXC_MACH_SYSCALL", EXC_MACH_SYSCALL)
583*f6aab3d8Srobert       .Case("EXC_RPC_ALERT", EXC_RPC_ALERT)
584*f6aab3d8Srobert #ifdef EXC_CRASH
585*f6aab3d8Srobert       .Case("EXC_CRASH", EXC_CRASH)
586*f6aab3d8Srobert #endif
587*f6aab3d8Srobert       .Case("EXC_RESOURCE", EXC_RESOURCE)
588*f6aab3d8Srobert #ifdef EXC_GUARD
589*f6aab3d8Srobert       .Case("EXC_GUARD", EXC_GUARD)
590*f6aab3d8Srobert #endif
591*f6aab3d8Srobert #ifdef EXC_CORPSE_NOTIFY
592*f6aab3d8Srobert       .Case("EXC_CORPSE_NOTIFY", EXC_CORPSE_NOTIFY)
593*f6aab3d8Srobert #endif
594*f6aab3d8Srobert       .Default(std::nullopt);
595*f6aab3d8Srobert }
596*f6aab3d8Srobert #endif
597*f6aab3d8Srobert 
CreateStopReasonWithMachException(Thread & thread,uint32_t exc_type,uint32_t exc_data_count,uint64_t exc_code,uint64_t exc_sub_code,uint64_t exc_sub_sub_code,bool pc_already_adjusted,bool adjust_pc_if_needed)598061da546Spatrick StopInfoSP StopInfoMachException::CreateStopReasonWithMachException(
599061da546Spatrick     Thread &thread, uint32_t exc_type, uint32_t exc_data_count,
600061da546Spatrick     uint64_t exc_code, uint64_t exc_sub_code, uint64_t exc_sub_sub_code,
601061da546Spatrick     bool pc_already_adjusted, bool adjust_pc_if_needed) {
602061da546Spatrick   if (exc_type == 0)
603061da546Spatrick     return StopInfoSP();
604061da546Spatrick 
605061da546Spatrick   uint32_t pc_decrement = 0;
606061da546Spatrick   ExecutionContext exe_ctx(thread.shared_from_this());
607061da546Spatrick   Target *target = exe_ctx.GetTargetPtr();
608061da546Spatrick   const llvm::Triple::ArchType cpu =
609061da546Spatrick       target ? target->GetArchitecture().GetMachine()
610061da546Spatrick              : llvm::Triple::UnknownArch;
611061da546Spatrick 
612061da546Spatrick   switch (exc_type) {
613061da546Spatrick   case 1: // EXC_BAD_ACCESS
614061da546Spatrick   case 2: // EXC_BAD_INSTRUCTION
615061da546Spatrick   case 3: // EXC_ARITHMETIC
616061da546Spatrick   case 4: // EXC_EMULATION
617061da546Spatrick     break;
618061da546Spatrick 
619061da546Spatrick   case 5:                    // EXC_SOFTWARE
620061da546Spatrick     if (exc_code == 0x10003) // EXC_SOFT_SIGNAL
621061da546Spatrick     {
622061da546Spatrick       if (exc_sub_code == 5) {
623061da546Spatrick         // On MacOSX, a SIGTRAP can signify that a process has called exec,
624061da546Spatrick         // so we should check with our dynamic loader to verify.
625061da546Spatrick         ProcessSP process_sp(thread.GetProcess());
626061da546Spatrick         if (process_sp) {
627061da546Spatrick           DynamicLoader *dynamic_loader = process_sp->GetDynamicLoader();
628061da546Spatrick           if (dynamic_loader && dynamic_loader->ProcessDidExec()) {
629061da546Spatrick             // The program was re-exec'ed
630061da546Spatrick             return StopInfo::CreateStopReasonWithExec(thread);
631061da546Spatrick           }
632061da546Spatrick         }
633061da546Spatrick       }
634061da546Spatrick       return StopInfo::CreateStopReasonWithSignal(thread, exc_sub_code);
635061da546Spatrick     }
636061da546Spatrick     break;
637061da546Spatrick 
638061da546Spatrick   case 6: // EXC_BREAKPOINT
639061da546Spatrick   {
640061da546Spatrick     bool is_actual_breakpoint = false;
641061da546Spatrick     bool is_trace_if_actual_breakpoint_missing = false;
642061da546Spatrick     switch (cpu) {
643061da546Spatrick     case llvm::Triple::x86:
644061da546Spatrick     case llvm::Triple::x86_64:
645061da546Spatrick       if (exc_code == 1) // EXC_I386_SGL
646061da546Spatrick       {
647061da546Spatrick         if (!exc_sub_code) {
648061da546Spatrick           // This looks like a plain trap.
649061da546Spatrick           // Have to check if there is a breakpoint here as well.  When you
650061da546Spatrick           // single-step onto a trap, the single step stops you not to trap.
651061da546Spatrick           // Since we also do that check below, let's just use that logic.
652061da546Spatrick           is_actual_breakpoint = true;
653061da546Spatrick           is_trace_if_actual_breakpoint_missing = true;
654061da546Spatrick         } else {
655dda28197Spatrick           if (StopInfoSP stop_info =
656dda28197Spatrick                   GetStopInfoForHardwareBP(thread, target, exc_data_count,
657dda28197Spatrick                                            exc_sub_code, exc_sub_sub_code))
658dda28197Spatrick             return stop_info;
659061da546Spatrick         }
660061da546Spatrick       } else if (exc_code == 2 || // EXC_I386_BPT
661061da546Spatrick                  exc_code == 3)   // EXC_I386_BPTFLT
662061da546Spatrick       {
663061da546Spatrick         // KDP returns EXC_I386_BPTFLT for trace breakpoints
664061da546Spatrick         if (exc_code == 3)
665061da546Spatrick           is_trace_if_actual_breakpoint_missing = true;
666061da546Spatrick 
667061da546Spatrick         is_actual_breakpoint = true;
668061da546Spatrick         if (!pc_already_adjusted)
669061da546Spatrick           pc_decrement = 1;
670061da546Spatrick       }
671061da546Spatrick       break;
672061da546Spatrick 
673061da546Spatrick     case llvm::Triple::arm:
674061da546Spatrick     case llvm::Triple::thumb:
675061da546Spatrick       if (exc_code == 0x102) // EXC_ARM_DA_DEBUG
676061da546Spatrick       {
677061da546Spatrick         // It's a watchpoint, then, if the exc_sub_code indicates a
678061da546Spatrick         // known/enabled data break address from our watchpoint list.
679061da546Spatrick         lldb::WatchpointSP wp_sp;
680061da546Spatrick         if (target)
681061da546Spatrick           wp_sp = target->GetWatchpointList().FindByAddress(
682061da546Spatrick               (lldb::addr_t)exc_sub_code);
683061da546Spatrick         if (wp_sp && wp_sp->IsEnabled()) {
684061da546Spatrick           // Debugserver may piggyback the hardware index of the fired
685061da546Spatrick           // watchpoint in the exception data. Set the hardware index if
686061da546Spatrick           // that's the case.
687061da546Spatrick           if (exc_data_count >= 3)
688061da546Spatrick             wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
689061da546Spatrick           return StopInfo::CreateStopReasonWithWatchpointID(thread,
690061da546Spatrick                                                             wp_sp->GetID());
691061da546Spatrick         } else {
692061da546Spatrick           is_actual_breakpoint = true;
693061da546Spatrick           is_trace_if_actual_breakpoint_missing = true;
694061da546Spatrick         }
695061da546Spatrick       } else if (exc_code == 1) // EXC_ARM_BREAKPOINT
696061da546Spatrick       {
697061da546Spatrick         is_actual_breakpoint = true;
698061da546Spatrick         is_trace_if_actual_breakpoint_missing = true;
699061da546Spatrick       } else if (exc_code == 0) // FIXME not EXC_ARM_BREAKPOINT but a kernel
700061da546Spatrick                                 // is currently returning this so accept it
701061da546Spatrick                                 // as indicating a breakpoint until the
702061da546Spatrick                                 // kernel is fixed
703061da546Spatrick       {
704061da546Spatrick         is_actual_breakpoint = true;
705061da546Spatrick         is_trace_if_actual_breakpoint_missing = true;
706061da546Spatrick       }
707061da546Spatrick       break;
708061da546Spatrick 
709061da546Spatrick     case llvm::Triple::aarch64_32:
710061da546Spatrick     case llvm::Triple::aarch64: {
711061da546Spatrick       if (exc_code == 1 && exc_sub_code == 0) // EXC_ARM_BREAKPOINT
712061da546Spatrick       {
713061da546Spatrick         // This is hit when we single instruction step aka MDSCR_EL1 SS bit 0
714061da546Spatrick         // is set
715061da546Spatrick         is_actual_breakpoint = false;
716061da546Spatrick         is_trace_if_actual_breakpoint_missing = true;
717061da546Spatrick       }
718061da546Spatrick       if (exc_code == 0x102) // EXC_ARM_DA_DEBUG
719061da546Spatrick       {
720061da546Spatrick         // It's a watchpoint, then, if the exc_sub_code indicates a
721061da546Spatrick         // known/enabled data break address from our watchpoint list.
722061da546Spatrick         lldb::WatchpointSP wp_sp;
723061da546Spatrick         if (target)
724061da546Spatrick           wp_sp = target->GetWatchpointList().FindByAddress(
725061da546Spatrick               (lldb::addr_t)exc_sub_code);
726061da546Spatrick         if (wp_sp && wp_sp->IsEnabled()) {
727061da546Spatrick           // Debugserver may piggyback the hardware index of the fired
728061da546Spatrick           // watchpoint in the exception data. Set the hardware index if
729061da546Spatrick           // that's the case.
730061da546Spatrick           if (exc_data_count >= 3)
731061da546Spatrick             wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
732061da546Spatrick           return StopInfo::CreateStopReasonWithWatchpointID(thread,
733061da546Spatrick                                                             wp_sp->GetID());
734061da546Spatrick         }
735061da546Spatrick         // EXC_ARM_DA_DEBUG seems to be reused for EXC_BREAKPOINT as well as
736061da546Spatrick         // EXC_BAD_ACCESS
737061da546Spatrick         if (thread.GetTemporaryResumeState() == eStateStepping)
738061da546Spatrick           return StopInfo::CreateStopReasonToTrace(thread);
739061da546Spatrick       }
740061da546Spatrick       // It looks like exc_sub_code has the 4 bytes of the instruction that
741061da546Spatrick       // triggered the exception, i.e. our breakpoint opcode
742061da546Spatrick       is_actual_breakpoint = exc_code == 1;
743061da546Spatrick       break;
744061da546Spatrick     }
745061da546Spatrick 
746061da546Spatrick     default:
747061da546Spatrick       break;
748061da546Spatrick     }
749061da546Spatrick 
750061da546Spatrick     if (is_actual_breakpoint) {
751061da546Spatrick       RegisterContextSP reg_ctx_sp(thread.GetRegisterContext());
752061da546Spatrick       addr_t pc = reg_ctx_sp->GetPC() - pc_decrement;
753061da546Spatrick 
754061da546Spatrick       ProcessSP process_sp(thread.CalculateProcess());
755061da546Spatrick 
756061da546Spatrick       lldb::BreakpointSiteSP bp_site_sp;
757061da546Spatrick       if (process_sp)
758061da546Spatrick         bp_site_sp = process_sp->GetBreakpointSiteList().FindByAddress(pc);
759061da546Spatrick       if (bp_site_sp && bp_site_sp->IsEnabled()) {
760061da546Spatrick         // Update the PC if we were asked to do so, but only do so if we find
761061da546Spatrick         // a breakpoint that we know about cause this could be a trap
762061da546Spatrick         // instruction in the code
763061da546Spatrick         if (pc_decrement > 0 && adjust_pc_if_needed)
764061da546Spatrick           reg_ctx_sp->SetPC(pc);
765061da546Spatrick 
766061da546Spatrick         // If the breakpoint is for this thread, then we'll report the hit,
767061da546Spatrick         // but if it is for another thread, we can just report no reason.  We
768061da546Spatrick         // don't need to worry about stepping over the breakpoint here, that
769061da546Spatrick         // will be taken care of when the thread resumes and notices that
770061da546Spatrick         // there's a breakpoint under the pc. If we have an operating system
771061da546Spatrick         // plug-in, we might have set a thread specific breakpoint using the
772061da546Spatrick         // operating system thread ID, so we can't make any assumptions about
773061da546Spatrick         // the thread ID so we must always report the breakpoint regardless
774061da546Spatrick         // of the thread.
775be691f3bSpatrick         if (bp_site_sp->ValidForThisThread(thread) ||
776061da546Spatrick             thread.GetProcess()->GetOperatingSystem() != nullptr)
777061da546Spatrick           return StopInfo::CreateStopReasonWithBreakpointSiteID(
778061da546Spatrick               thread, bp_site_sp->GetID());
779061da546Spatrick         else if (is_trace_if_actual_breakpoint_missing)
780061da546Spatrick           return StopInfo::CreateStopReasonToTrace(thread);
781061da546Spatrick         else
782061da546Spatrick           return StopInfoSP();
783061da546Spatrick       }
784061da546Spatrick 
785061da546Spatrick       // Don't call this a trace if we weren't single stepping this thread.
786061da546Spatrick       if (is_trace_if_actual_breakpoint_missing &&
787061da546Spatrick           thread.GetTemporaryResumeState() == eStateStepping) {
788061da546Spatrick         return StopInfo::CreateStopReasonToTrace(thread);
789061da546Spatrick       }
790061da546Spatrick     }
791061da546Spatrick   } break;
792061da546Spatrick 
793061da546Spatrick   case 7:  // EXC_SYSCALL
794061da546Spatrick   case 8:  // EXC_MACH_SYSCALL
795061da546Spatrick   case 9:  // EXC_RPC_ALERT
796061da546Spatrick   case 10: // EXC_CRASH
797061da546Spatrick     break;
798061da546Spatrick   }
799061da546Spatrick 
800061da546Spatrick   return StopInfoSP(new StopInfoMachException(thread, exc_type, exc_data_count,
801061da546Spatrick                                               exc_code, exc_sub_code));
802061da546Spatrick }
803