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