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