1 //===-- StopInfoMachException.cpp -----------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "StopInfoMachException.h"
10 
11 #include "lldb/lldb-forward.h"
12 
13 #if defined(__APPLE__)
14 // Needed for the EXC_RESOURCE interpretation macros
15 #include <kern/exc_resource.h>
16 #endif
17 
18 #include "lldb/Breakpoint/Watchpoint.h"
19 #include "lldb/Symbol/Symbol.h"
20 #include "lldb/Target/ABI.h"
21 #include "lldb/Target/DynamicLoader.h"
22 #include "lldb/Target/ExecutionContext.h"
23 #include "lldb/Target/Process.h"
24 #include "lldb/Target/RegisterContext.h"
25 #include "lldb/Target/Target.h"
26 #include "lldb/Target/Thread.h"
27 #include "lldb/Target/ThreadPlan.h"
28 #include "lldb/Target/UnixSignals.h"
29 #include "lldb/Utility/StreamString.h"
30 
31 using namespace lldb;
32 using namespace lldb_private;
33 
34 /// Information about a pointer-authentication related instruction.
35 struct PtrauthInstructionInfo {
36   bool IsAuthenticated;
37   bool IsLoad;
38   bool DoesBranch;
39 };
40 
41 /// Get any pointer-authentication related information about the instruction
42 /// at address \p at_addr.
43 static llvm::Optional<PtrauthInstructionInfo>
44 GetPtrauthInstructionInfo(Target &target, const ArchSpec &arch,
45                           const Address &at_addr) {
46   const char *plugin_name = nullptr;
47   const char *flavor = nullptr;
48   AddressRange range_bounds(at_addr, 4);
49   const bool prefer_file_cache = true;
50   DisassemblerSP disassembler_sp = Disassembler::DisassembleRange(
51       arch, plugin_name, flavor, target, range_bounds, prefer_file_cache);
52   if (!disassembler_sp)
53     return llvm::None;
54 
55   InstructionList &insn_list = disassembler_sp->GetInstructionList();
56   InstructionSP insn = insn_list.GetInstructionAtIndex(0);
57   if (!insn)
58     return llvm::None;
59 
60   return PtrauthInstructionInfo{insn->IsAuthenticated(), insn->IsLoad(),
61                                 insn->DoesBranch()};
62 }
63 
64 /// Describe the load address of \p addr using the format filename:line:col.
65 static void DescribeAddressBriefly(Stream &strm, const Address &addr,
66                                    Target &target) {
67   strm.Printf("at address=0x%" PRIx64, addr.GetLoadAddress(&target));
68   StreamString s;
69   if (addr.GetDescription(s, target, eDescriptionLevelBrief))
70     strm.Printf(" %s", s.GetString().data());
71   strm.Printf(".\n");
72 }
73 
74 bool StopInfoMachException::DeterminePtrauthFailure(ExecutionContext &exe_ctx) {
75   bool IsBreakpoint = m_value == 6; // EXC_BREAKPOINT
76   bool IsBadAccess = m_value == 1;  // EXC_BAD_ACCESS
77   if (!IsBreakpoint && !IsBadAccess)
78     return false;
79 
80   // Check that we have a live process.
81   if (!exe_ctx.HasProcessScope() || !exe_ctx.HasThreadScope() ||
82       !exe_ctx.HasTargetScope())
83     return false;
84 
85   Thread &thread = *exe_ctx.GetThreadPtr();
86   StackFrameSP current_frame = thread.GetStackFrameAtIndex(0);
87   if (!current_frame)
88     return false;
89 
90   Target &target = *exe_ctx.GetTargetPtr();
91   Process &process = *exe_ctx.GetProcessPtr();
92   ABISP abi_sp = process.GetABI();
93   const ArchSpec &arch = target.GetArchitecture();
94   assert(abi_sp && "Missing ABI info");
95 
96   // Check for a ptrauth-enabled target.
97   const bool ptrauth_enabled_target =
98       arch.GetCore() == ArchSpec::eCore_arm_arm64e;
99   if (!ptrauth_enabled_target)
100     return false;
101 
102   // Set up a stream we can write a diagnostic into.
103   StreamString strm;
104   auto emit_ptrauth_prologue = [&](uint64_t at_address) {
105     strm.Printf("EXC_BAD_ACCESS (code=%" PRIu64 ", address=0x%" PRIx64 ")\n",
106                 m_exc_code, at_address);
107     strm.Printf("Note: Possible pointer authentication failure detected.\n");
108   };
109 
110   // Check if we have a "brk 0xc47x" trap, where the value that failed to
111   // authenticate is in x16.
112   Address current_address = current_frame->GetFrameCodeAddress();
113   if (IsBreakpoint) {
114     RegisterContext *reg_ctx = exe_ctx.GetRegisterContext();
115     if (!reg_ctx)
116       return false;
117 
118     const RegisterInfo *X16Info = reg_ctx->GetRegisterInfoByName("x16");
119     RegisterValue X16Val;
120     if (!reg_ctx->ReadRegister(X16Info, X16Val))
121       return false;
122     uint64_t bad_address = X16Val.GetAsUInt64();
123 
124     uint64_t fixed_bad_address = abi_sp->FixCodeAddress(bad_address);
125     Address brk_address;
126     if (!target.ResolveLoadAddress(fixed_bad_address, brk_address))
127       return false;
128 
129     auto brk_ptrauth_info =
130         GetPtrauthInstructionInfo(target, arch, current_address);
131     if (brk_ptrauth_info && brk_ptrauth_info->IsAuthenticated) {
132       emit_ptrauth_prologue(bad_address);
133       strm.Printf("Found value that failed to authenticate ");
134       DescribeAddressBriefly(strm, brk_address, target);
135       m_description = std::string(strm.GetString());
136       return true;
137     }
138     return false;
139   }
140 
141   assert(IsBadAccess && "Handle EXC_BAD_ACCESS only after this point");
142 
143   // Check that we have the "bad address" from an EXC_BAD_ACCESS.
144   if (m_exc_data_count < 2)
145     return false;
146 
147   // Ok, we know the Target is valid and that it describes a ptrauth-enabled
148   // device. Now, we need to determine whether this exception was caused by a
149   // ptrauth failure.
150 
151   uint64_t bad_address = m_exc_subcode;
152   uint64_t fixed_bad_address = abi_sp->FixCodeAddress(bad_address);
153   uint64_t current_pc = current_address.GetLoadAddress(&target);
154 
155   // Detect: LDRAA, LDRAB (Load Register, with pointer authentication).
156   //
157   // If an authenticated load results in an exception, the instruction at the
158   // current PC should be one of LDRAx.
159   if (bad_address != current_pc && fixed_bad_address != current_pc) {
160     auto ptrauth_info =
161         GetPtrauthInstructionInfo(target, arch, current_address);
162     if (ptrauth_info && ptrauth_info->IsAuthenticated && ptrauth_info->IsLoad) {
163       emit_ptrauth_prologue(bad_address);
164       strm.Printf("Found authenticated load instruction ");
165       DescribeAddressBriefly(strm, current_address, target);
166       m_description = std::string(strm.GetString());
167       return true;
168     }
169   }
170 
171   // Detect: BLRAA, BLRAAZ, BLRAB, BLRABZ (Branch with Link to Register, with
172   // pointer authentication).
173   //
174   // TODO: Detect: BRAA, BRAAZ, BRAB, BRABZ (Branch to Register, with pointer
175   // authentication). At a minimum, this requires call site info support for
176   // indirect calls.
177   //
178   // If an authenticated call or tail call results in an exception, stripping
179   // the bad address should give the current PC, which points to the address
180   // we tried to branch to.
181   if (bad_address != current_pc && fixed_bad_address == current_pc) {
182     if (StackFrameSP parent_frame = thread.GetStackFrameAtIndex(1)) {
183       addr_t return_pc =
184           parent_frame->GetFrameCodeAddress().GetLoadAddress(&target);
185       Address blr_address;
186       if (!target.ResolveLoadAddress(return_pc - 4, blr_address))
187         return false;
188 
189       auto blr_ptrauth_info =
190           GetPtrauthInstructionInfo(target, arch, blr_address);
191       if (blr_ptrauth_info && blr_ptrauth_info->IsAuthenticated &&
192           blr_ptrauth_info->DoesBranch) {
193         emit_ptrauth_prologue(bad_address);
194         strm.Printf("Found authenticated indirect branch ");
195         DescribeAddressBriefly(strm, blr_address, target);
196         m_description = std::string(strm.GetString());
197         return true;
198       }
199     }
200   }
201 
202   // TODO: Detect: RETAA, RETAB (Return from subroutine, with pointer
203   // authentication).
204   //
205   // Is there a motivating, non-malicious code snippet that corrupts LR?
206 
207   return false;
208 }
209 
210 const char *StopInfoMachException::GetDescription() {
211   if (!m_description.empty())
212     return m_description.c_str();
213   if (GetValue() == eStopReasonInvalid)
214     return "invalid stop reason!";
215 
216   ExecutionContext exe_ctx(m_thread_wp.lock());
217   Target *target = exe_ctx.GetTargetPtr();
218   const llvm::Triple::ArchType cpu =
219       target ? target->GetArchitecture().GetMachine()
220              : llvm::Triple::UnknownArch;
221 
222   const char *exc_desc = nullptr;
223   const char *code_label = "code";
224   const char *code_desc = nullptr;
225   const char *subcode_label = "subcode";
226   const char *subcode_desc = nullptr;
227 
228 #if defined(__APPLE__)
229   char code_desc_buf[32];
230   char subcode_desc_buf[32];
231 #endif
232 
233   switch (m_value) {
234   case 1: // EXC_BAD_ACCESS
235     exc_desc = "EXC_BAD_ACCESS";
236     subcode_label = "address";
237     switch (cpu) {
238     case llvm::Triple::x86:
239     case llvm::Triple::x86_64:
240       switch (m_exc_code) {
241       case 0xd:
242         code_desc = "EXC_I386_GPFLT";
243         m_exc_data_count = 1;
244         break;
245       }
246       break;
247     case llvm::Triple::arm:
248     case llvm::Triple::thumb:
249       switch (m_exc_code) {
250       case 0x101:
251         code_desc = "EXC_ARM_DA_ALIGN";
252         break;
253       case 0x102:
254         code_desc = "EXC_ARM_DA_DEBUG";
255         break;
256       }
257       break;
258 
259     case llvm::Triple::aarch64:
260       if (DeterminePtrauthFailure(exe_ctx))
261         return m_description.c_str();
262       break;
263 
264     default:
265       break;
266     }
267     break;
268 
269   case 2: // EXC_BAD_INSTRUCTION
270     exc_desc = "EXC_BAD_INSTRUCTION";
271     switch (cpu) {
272     case llvm::Triple::x86:
273     case llvm::Triple::x86_64:
274       if (m_exc_code == 1)
275         code_desc = "EXC_I386_INVOP";
276       break;
277 
278     case llvm::Triple::arm:
279     case llvm::Triple::thumb:
280       if (m_exc_code == 1)
281         code_desc = "EXC_ARM_UNDEFINED";
282       break;
283 
284     default:
285       break;
286     }
287     break;
288 
289   case 3: // EXC_ARITHMETIC
290     exc_desc = "EXC_ARITHMETIC";
291     switch (cpu) {
292     case llvm::Triple::x86:
293     case llvm::Triple::x86_64:
294       switch (m_exc_code) {
295       case 1:
296         code_desc = "EXC_I386_DIV";
297         break;
298       case 2:
299         code_desc = "EXC_I386_INTO";
300         break;
301       case 3:
302         code_desc = "EXC_I386_NOEXT";
303         break;
304       case 4:
305         code_desc = "EXC_I386_EXTOVR";
306         break;
307       case 5:
308         code_desc = "EXC_I386_EXTERR";
309         break;
310       case 6:
311         code_desc = "EXC_I386_EMERR";
312         break;
313       case 7:
314         code_desc = "EXC_I386_BOUND";
315         break;
316       case 8:
317         code_desc = "EXC_I386_SSEEXTERR";
318         break;
319       }
320       break;
321 
322     default:
323       break;
324     }
325     break;
326 
327   case 4: // EXC_EMULATION
328     exc_desc = "EXC_EMULATION";
329     break;
330 
331   case 5: // EXC_SOFTWARE
332     exc_desc = "EXC_SOFTWARE";
333     if (m_exc_code == 0x10003) {
334       subcode_desc = "EXC_SOFT_SIGNAL";
335       subcode_label = "signo";
336     }
337     break;
338 
339   case 6: // EXC_BREAKPOINT
340   {
341     exc_desc = "EXC_BREAKPOINT";
342     switch (cpu) {
343     case llvm::Triple::x86:
344     case llvm::Triple::x86_64:
345       switch (m_exc_code) {
346       case 1:
347         code_desc = "EXC_I386_SGL";
348         break;
349       case 2:
350         code_desc = "EXC_I386_BPT";
351         break;
352       }
353       break;
354 
355     case llvm::Triple::arm:
356     case llvm::Triple::thumb:
357       switch (m_exc_code) {
358       case 0x101:
359         code_desc = "EXC_ARM_DA_ALIGN";
360         break;
361       case 0x102:
362         code_desc = "EXC_ARM_DA_DEBUG";
363         break;
364       case 1:
365         code_desc = "EXC_ARM_BREAKPOINT";
366         break;
367       // FIXME temporary workaround, exc_code 0 does not really mean
368       // EXC_ARM_BREAKPOINT
369       case 0:
370         code_desc = "EXC_ARM_BREAKPOINT";
371         break;
372       }
373       break;
374 
375     case llvm::Triple::aarch64:
376       if (DeterminePtrauthFailure(exe_ctx))
377         return m_description.c_str();
378       break;
379 
380     default:
381       break;
382     }
383   } break;
384 
385   case 7:
386     exc_desc = "EXC_SYSCALL";
387     break;
388 
389   case 8:
390     exc_desc = "EXC_MACH_SYSCALL";
391     break;
392 
393   case 9:
394     exc_desc = "EXC_RPC_ALERT";
395     break;
396 
397   case 10:
398     exc_desc = "EXC_CRASH";
399     break;
400   case 11:
401     exc_desc = "EXC_RESOURCE";
402 #if defined(__APPLE__)
403     {
404       int resource_type = EXC_RESOURCE_DECODE_RESOURCE_TYPE(m_exc_code);
405 
406       code_label = "limit";
407       code_desc = code_desc_buf;
408       subcode_label = "observed";
409       subcode_desc = subcode_desc_buf;
410 
411       switch (resource_type) {
412       case RESOURCE_TYPE_CPU:
413         exc_desc = "EXC_RESOURCE RESOURCE_TYPE_CPU";
414         snprintf(code_desc_buf, sizeof(code_desc_buf), "%d%%",
415                  (int)EXC_RESOURCE_CPUMONITOR_DECODE_PERCENTAGE(m_exc_code));
416         snprintf(subcode_desc_buf, sizeof(subcode_desc_buf), "%d%%",
417                  (int)EXC_RESOURCE_CPUMONITOR_DECODE_PERCENTAGE_OBSERVED(
418                      m_exc_subcode));
419         break;
420       case RESOURCE_TYPE_WAKEUPS:
421         exc_desc = "EXC_RESOURCE RESOURCE_TYPE_WAKEUPS";
422         snprintf(
423             code_desc_buf, sizeof(code_desc_buf), "%d w/s",
424             (int)EXC_RESOURCE_CPUMONITOR_DECODE_WAKEUPS_PERMITTED(m_exc_code));
425         snprintf(subcode_desc_buf, sizeof(subcode_desc_buf), "%d w/s",
426                  (int)EXC_RESOURCE_CPUMONITOR_DECODE_WAKEUPS_OBSERVED(
427                      m_exc_subcode));
428         break;
429       case RESOURCE_TYPE_MEMORY:
430         exc_desc = "EXC_RESOURCE RESOURCE_TYPE_MEMORY";
431         snprintf(code_desc_buf, sizeof(code_desc_buf), "%d MB",
432                  (int)EXC_RESOURCE_HWM_DECODE_LIMIT(m_exc_code));
433         subcode_desc = nullptr;
434         subcode_label = "unused";
435         break;
436 #if defined(RESOURCE_TYPE_IO)
437       // RESOURCE_TYPE_IO is introduced in macOS SDK 10.12.
438       case RESOURCE_TYPE_IO:
439         exc_desc = "EXC_RESOURCE RESOURCE_TYPE_IO";
440         snprintf(code_desc_buf, sizeof(code_desc_buf), "%d MB",
441                  (int)EXC_RESOURCE_IO_DECODE_LIMIT(m_exc_code));
442         snprintf(subcode_desc_buf, sizeof(subcode_desc_buf), "%d MB",
443                  (int)EXC_RESOURCE_IO_OBSERVED(m_exc_subcode));
444         ;
445         break;
446 #endif
447       }
448     }
449 #endif
450     break;
451   case 12:
452     exc_desc = "EXC_GUARD";
453     break;
454   }
455 
456   StreamString strm;
457 
458   if (exc_desc)
459     strm.PutCString(exc_desc);
460   else
461     strm.Printf("EXC_??? (%" PRIu64 ")", m_value);
462 
463   if (m_exc_data_count >= 1) {
464     if (code_desc)
465       strm.Printf(" (%s=%s", code_label, code_desc);
466     else
467       strm.Printf(" (%s=%" PRIu64, code_label, m_exc_code);
468   }
469 
470   if (m_exc_data_count >= 2) {
471     if (subcode_desc)
472       strm.Printf(", %s=%s", subcode_label, subcode_desc);
473     else
474       strm.Printf(", %s=0x%" PRIx64, subcode_label, m_exc_subcode);
475   }
476 
477   if (m_exc_data_count > 0)
478     strm.PutChar(')');
479 
480   m_description = std::string(strm.GetString());
481   return m_description.c_str();
482 }
483 
484 static StopInfoSP GetStopInfoForHardwareBP(Thread &thread, Target *target,
485                                            uint32_t exc_data_count,
486                                            uint64_t exc_sub_code,
487                                            uint64_t exc_sub_sub_code) {
488   // Try hardware watchpoint.
489   if (target) {
490     // The exc_sub_code indicates the data break address.
491     lldb::WatchpointSP wp_sp =
492         target->GetWatchpointList().FindByAddress((lldb::addr_t)exc_sub_code);
493     if (wp_sp && wp_sp->IsEnabled()) {
494       // Debugserver may piggyback the hardware index of the fired watchpoint
495       // in the exception data. Set the hardware index if that's the case.
496       if (exc_data_count >= 3)
497         wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
498       return StopInfo::CreateStopReasonWithWatchpointID(thread, wp_sp->GetID());
499     }
500   }
501 
502   // Try hardware breakpoint.
503   ProcessSP process_sp(thread.GetProcess());
504   if (process_sp) {
505     // The exc_sub_code indicates the data break address.
506     lldb::BreakpointSiteSP bp_sp =
507         process_sp->GetBreakpointSiteList().FindByAddress(
508             (lldb::addr_t)exc_sub_code);
509     if (bp_sp && bp_sp->IsEnabled()) {
510       // Debugserver may piggyback the hardware index of the fired breakpoint
511       // in the exception data. Set the hardware index if that's the case.
512       if (exc_data_count >= 3)
513         bp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
514       return StopInfo::CreateStopReasonWithBreakpointSiteID(thread,
515                                                             bp_sp->GetID());
516     }
517   }
518 
519   return nullptr;
520 }
521 
522 StopInfoSP StopInfoMachException::CreateStopReasonWithMachException(
523     Thread &thread, uint32_t exc_type, uint32_t exc_data_count,
524     uint64_t exc_code, uint64_t exc_sub_code, uint64_t exc_sub_sub_code,
525     bool pc_already_adjusted, bool adjust_pc_if_needed) {
526   if (exc_type == 0)
527     return StopInfoSP();
528 
529   uint32_t pc_decrement = 0;
530   ExecutionContext exe_ctx(thread.shared_from_this());
531   Target *target = exe_ctx.GetTargetPtr();
532   const llvm::Triple::ArchType cpu =
533       target ? target->GetArchitecture().GetMachine()
534              : llvm::Triple::UnknownArch;
535 
536   switch (exc_type) {
537   case 1: // EXC_BAD_ACCESS
538   case 2: // EXC_BAD_INSTRUCTION
539   case 3: // EXC_ARITHMETIC
540   case 4: // EXC_EMULATION
541     break;
542 
543   case 5:                    // EXC_SOFTWARE
544     if (exc_code == 0x10003) // EXC_SOFT_SIGNAL
545     {
546       if (exc_sub_code == 5) {
547         // On MacOSX, a SIGTRAP can signify that a process has called exec,
548         // so we should check with our dynamic loader to verify.
549         ProcessSP process_sp(thread.GetProcess());
550         if (process_sp) {
551           DynamicLoader *dynamic_loader = process_sp->GetDynamicLoader();
552           if (dynamic_loader && dynamic_loader->ProcessDidExec()) {
553             // The program was re-exec'ed
554             return StopInfo::CreateStopReasonWithExec(thread);
555           }
556         }
557       }
558       return StopInfo::CreateStopReasonWithSignal(thread, exc_sub_code);
559     }
560     break;
561 
562   case 6: // EXC_BREAKPOINT
563   {
564     bool is_actual_breakpoint = false;
565     bool is_trace_if_actual_breakpoint_missing = false;
566     switch (cpu) {
567     case llvm::Triple::x86:
568     case llvm::Triple::x86_64:
569       if (exc_code == 1) // EXC_I386_SGL
570       {
571         if (!exc_sub_code) {
572           // This looks like a plain trap.
573           // Have to check if there is a breakpoint here as well.  When you
574           // single-step onto a trap, the single step stops you not to trap.
575           // Since we also do that check below, let's just use that logic.
576           is_actual_breakpoint = true;
577           is_trace_if_actual_breakpoint_missing = true;
578         } else {
579           if (StopInfoSP stop_info =
580                   GetStopInfoForHardwareBP(thread, target, exc_data_count,
581                                            exc_sub_code, exc_sub_sub_code))
582             return stop_info;
583         }
584       } else if (exc_code == 2 || // EXC_I386_BPT
585                  exc_code == 3)   // EXC_I386_BPTFLT
586       {
587         // KDP returns EXC_I386_BPTFLT for trace breakpoints
588         if (exc_code == 3)
589           is_trace_if_actual_breakpoint_missing = true;
590 
591         is_actual_breakpoint = true;
592         if (!pc_already_adjusted)
593           pc_decrement = 1;
594       }
595       break;
596 
597     case llvm::Triple::arm:
598     case llvm::Triple::thumb:
599       if (exc_code == 0x102) // EXC_ARM_DA_DEBUG
600       {
601         // It's a watchpoint, then, if the exc_sub_code indicates a
602         // known/enabled data break address from our watchpoint list.
603         lldb::WatchpointSP wp_sp;
604         if (target)
605           wp_sp = target->GetWatchpointList().FindByAddress(
606               (lldb::addr_t)exc_sub_code);
607         if (wp_sp && wp_sp->IsEnabled()) {
608           // Debugserver may piggyback the hardware index of the fired
609           // watchpoint in the exception data. Set the hardware index if
610           // that's the case.
611           if (exc_data_count >= 3)
612             wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
613           return StopInfo::CreateStopReasonWithWatchpointID(thread,
614                                                             wp_sp->GetID());
615         } else {
616           is_actual_breakpoint = true;
617           is_trace_if_actual_breakpoint_missing = true;
618         }
619       } else if (exc_code == 1) // EXC_ARM_BREAKPOINT
620       {
621         is_actual_breakpoint = true;
622         is_trace_if_actual_breakpoint_missing = true;
623       } else if (exc_code == 0) // FIXME not EXC_ARM_BREAKPOINT but a kernel
624                                 // is currently returning this so accept it
625                                 // as indicating a breakpoint until the
626                                 // kernel is fixed
627       {
628         is_actual_breakpoint = true;
629         is_trace_if_actual_breakpoint_missing = true;
630       }
631       break;
632 
633     case llvm::Triple::aarch64_32:
634     case llvm::Triple::aarch64: {
635       if (exc_code == 1 && exc_sub_code == 0) // EXC_ARM_BREAKPOINT
636       {
637         // This is hit when we single instruction step aka MDSCR_EL1 SS bit 0
638         // is set
639         is_actual_breakpoint = false;
640         is_trace_if_actual_breakpoint_missing = true;
641       }
642       if (exc_code == 0x102) // EXC_ARM_DA_DEBUG
643       {
644         // It's a watchpoint, then, if the exc_sub_code indicates a
645         // known/enabled data break address from our watchpoint list.
646         lldb::WatchpointSP wp_sp;
647         if (target)
648           wp_sp = target->GetWatchpointList().FindByAddress(
649               (lldb::addr_t)exc_sub_code);
650         if (wp_sp && wp_sp->IsEnabled()) {
651           // Debugserver may piggyback the hardware index of the fired
652           // watchpoint in the exception data. Set the hardware index if
653           // that's the case.
654           if (exc_data_count >= 3)
655             wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
656           return StopInfo::CreateStopReasonWithWatchpointID(thread,
657                                                             wp_sp->GetID());
658         }
659         // EXC_ARM_DA_DEBUG seems to be reused for EXC_BREAKPOINT as well as
660         // EXC_BAD_ACCESS
661         if (thread.GetTemporaryResumeState() == eStateStepping)
662           return StopInfo::CreateStopReasonToTrace(thread);
663       }
664       // It looks like exc_sub_code has the 4 bytes of the instruction that
665       // triggered the exception, i.e. our breakpoint opcode
666       is_actual_breakpoint = exc_code == 1;
667       break;
668     }
669 
670     default:
671       break;
672     }
673 
674     if (is_actual_breakpoint) {
675       RegisterContextSP reg_ctx_sp(thread.GetRegisterContext());
676       addr_t pc = reg_ctx_sp->GetPC() - pc_decrement;
677 
678       ProcessSP process_sp(thread.CalculateProcess());
679 
680       lldb::BreakpointSiteSP bp_site_sp;
681       if (process_sp)
682         bp_site_sp = process_sp->GetBreakpointSiteList().FindByAddress(pc);
683       if (bp_site_sp && bp_site_sp->IsEnabled()) {
684         // Update the PC if we were asked to do so, but only do so if we find
685         // a breakpoint that we know about cause this could be a trap
686         // instruction in the code
687         if (pc_decrement > 0 && adjust_pc_if_needed)
688           reg_ctx_sp->SetPC(pc);
689 
690         // If the breakpoint is for this thread, then we'll report the hit,
691         // but if it is for another thread, we can just report no reason.  We
692         // don't need to worry about stepping over the breakpoint here, that
693         // will be taken care of when the thread resumes and notices that
694         // there's a breakpoint under the pc. If we have an operating system
695         // plug-in, we might have set a thread specific breakpoint using the
696         // operating system thread ID, so we can't make any assumptions about
697         // the thread ID so we must always report the breakpoint regardless
698         // of the thread.
699         if (bp_site_sp->ValidForThisThread(thread) ||
700             thread.GetProcess()->GetOperatingSystem() != nullptr)
701           return StopInfo::CreateStopReasonWithBreakpointSiteID(
702               thread, bp_site_sp->GetID());
703         else if (is_trace_if_actual_breakpoint_missing)
704           return StopInfo::CreateStopReasonToTrace(thread);
705         else
706           return StopInfoSP();
707       }
708 
709       // Don't call this a trace if we weren't single stepping this thread.
710       if (is_trace_if_actual_breakpoint_missing &&
711           thread.GetTemporaryResumeState() == eStateStepping) {
712         return StopInfo::CreateStopReasonToTrace(thread);
713       }
714     }
715   } break;
716 
717   case 7:  // EXC_SYSCALL
718   case 8:  // EXC_MACH_SYSCALL
719   case 9:  // EXC_RPC_ALERT
720   case 10: // EXC_CRASH
721     break;
722   }
723 
724   return StopInfoSP(new StopInfoMachException(thread, exc_type, exc_data_count,
725                                               exc_code, exc_sub_code));
726 }
727