1 //===-- StopInfoMachException.cpp -------------------------------*- C++ -*-===//
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 
12 #if defined(__APPLE__)
13 // Needed for the EXC_RESOURCE interpretation macros
14 #include <kern/exc_resource.h>
15 #endif
16 
17 #include "lldb/Breakpoint/Watchpoint.h"
18 #include "lldb/Symbol/Symbol.h"
19 #include "lldb/Target/DynamicLoader.h"
20 #include "lldb/Target/ExecutionContext.h"
21 #include "lldb/Target/Process.h"
22 #include "lldb/Target/RegisterContext.h"
23 #include "lldb/Target/Target.h"
24 #include "lldb/Target/Thread.h"
25 #include "lldb/Target/ThreadPlan.h"
26 #include "lldb/Target/UnixSignals.h"
27 #include "lldb/Utility/StreamString.h"
28 
29 using namespace lldb;
30 using namespace lldb_private;
31 
32 const char *StopInfoMachException::GetDescription() {
33   if (!m_description.empty())
34     return m_description.c_str();
35   if (GetValue() == eStopReasonInvalid)
36     return "invalid stop reason!";
37 
38   ExecutionContext exe_ctx(m_thread_wp.lock());
39   Target *target = exe_ctx.GetTargetPtr();
40   const llvm::Triple::ArchType cpu =
41       target ? target->GetArchitecture().GetMachine()
42              : llvm::Triple::UnknownArch;
43 
44   const char *exc_desc = nullptr;
45   const char *code_label = "code";
46   const char *code_desc = nullptr;
47   const char *subcode_label = "subcode";
48   const char *subcode_desc = nullptr;
49 
50 #if defined(__APPLE__)
51   char code_desc_buf[32];
52   char subcode_desc_buf[32];
53 #endif
54 
55   switch (m_value) {
56   case 1: // EXC_BAD_ACCESS
57     exc_desc = "EXC_BAD_ACCESS";
58     subcode_label = "address";
59     switch (cpu) {
60     case llvm::Triple::x86:
61     case llvm::Triple::x86_64:
62       switch (m_exc_code) {
63       case 0xd:
64         code_desc = "EXC_I386_GPFLT";
65         m_exc_data_count = 1;
66         break;
67       }
68       break;
69     case llvm::Triple::arm:
70     case llvm::Triple::thumb:
71       switch (m_exc_code) {
72       case 0x101:
73         code_desc = "EXC_ARM_DA_ALIGN";
74         break;
75       case 0x102:
76         code_desc = "EXC_ARM_DA_DEBUG";
77         break;
78       }
79       break;
80 
81     case llvm::Triple::ppc:
82     case llvm::Triple::ppc64:
83       switch (m_exc_code) {
84       case 0x101:
85         code_desc = "EXC_PPC_VM_PROT_READ";
86         break;
87       case 0x102:
88         code_desc = "EXC_PPC_BADSPACE";
89         break;
90       case 0x103:
91         code_desc = "EXC_PPC_UNALIGNED";
92         break;
93       }
94       break;
95 
96     default:
97       break;
98     }
99     break;
100 
101   case 2: // EXC_BAD_INSTRUCTION
102     exc_desc = "EXC_BAD_INSTRUCTION";
103     switch (cpu) {
104     case llvm::Triple::x86:
105     case llvm::Triple::x86_64:
106       if (m_exc_code == 1)
107         code_desc = "EXC_I386_INVOP";
108       break;
109 
110     case llvm::Triple::ppc:
111     case llvm::Triple::ppc64:
112       switch (m_exc_code) {
113       case 1:
114         code_desc = "EXC_PPC_INVALID_SYSCALL";
115         break;
116       case 2:
117         code_desc = "EXC_PPC_UNIPL_INST";
118         break;
119       case 3:
120         code_desc = "EXC_PPC_PRIVINST";
121         break;
122       case 4:
123         code_desc = "EXC_PPC_PRIVREG";
124         break;
125       case 5:
126         code_desc = "EXC_PPC_TRACE";
127         break;
128       case 6:
129         code_desc = "EXC_PPC_PERFMON";
130         break;
131       }
132       break;
133 
134     case llvm::Triple::arm:
135     case llvm::Triple::thumb:
136       if (m_exc_code == 1)
137         code_desc = "EXC_ARM_UNDEFINED";
138       break;
139 
140     default:
141       break;
142     }
143     break;
144 
145   case 3: // EXC_ARITHMETIC
146     exc_desc = "EXC_ARITHMETIC";
147     switch (cpu) {
148     case llvm::Triple::x86:
149     case llvm::Triple::x86_64:
150       switch (m_exc_code) {
151       case 1:
152         code_desc = "EXC_I386_DIV";
153         break;
154       case 2:
155         code_desc = "EXC_I386_INTO";
156         break;
157       case 3:
158         code_desc = "EXC_I386_NOEXT";
159         break;
160       case 4:
161         code_desc = "EXC_I386_EXTOVR";
162         break;
163       case 5:
164         code_desc = "EXC_I386_EXTERR";
165         break;
166       case 6:
167         code_desc = "EXC_I386_EMERR";
168         break;
169       case 7:
170         code_desc = "EXC_I386_BOUND";
171         break;
172       case 8:
173         code_desc = "EXC_I386_SSEEXTERR";
174         break;
175       }
176       break;
177 
178     case llvm::Triple::ppc:
179     case llvm::Triple::ppc64:
180       switch (m_exc_code) {
181       case 1:
182         code_desc = "EXC_PPC_OVERFLOW";
183         break;
184       case 2:
185         code_desc = "EXC_PPC_ZERO_DIVIDE";
186         break;
187       case 3:
188         code_desc = "EXC_PPC_FLT_INEXACT";
189         break;
190       case 4:
191         code_desc = "EXC_PPC_FLT_ZERO_DIVIDE";
192         break;
193       case 5:
194         code_desc = "EXC_PPC_FLT_UNDERFLOW";
195         break;
196       case 6:
197         code_desc = "EXC_PPC_FLT_OVERFLOW";
198         break;
199       case 7:
200         code_desc = "EXC_PPC_FLT_NOT_A_NUMBER";
201         break;
202       }
203       break;
204 
205     default:
206       break;
207     }
208     break;
209 
210   case 4: // EXC_EMULATION
211     exc_desc = "EXC_EMULATION";
212     break;
213 
214   case 5: // EXC_SOFTWARE
215     exc_desc = "EXC_SOFTWARE";
216     if (m_exc_code == 0x10003) {
217       subcode_desc = "EXC_SOFT_SIGNAL";
218       subcode_label = "signo";
219     }
220     break;
221 
222   case 6: // EXC_BREAKPOINT
223   {
224     exc_desc = "EXC_BREAKPOINT";
225     switch (cpu) {
226     case llvm::Triple::x86:
227     case llvm::Triple::x86_64:
228       switch (m_exc_code) {
229       case 1:
230         code_desc = "EXC_I386_SGL";
231         break;
232       case 2:
233         code_desc = "EXC_I386_BPT";
234         break;
235       }
236       break;
237 
238     case llvm::Triple::ppc:
239     case llvm::Triple::ppc64:
240       switch (m_exc_code) {
241       case 1:
242         code_desc = "EXC_PPC_BREAKPOINT";
243         break;
244       }
245       break;
246 
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       case 1:
257         code_desc = "EXC_ARM_BREAKPOINT";
258         break;
259       // FIXME temporary workaround, exc_code 0 does not really mean
260       // EXC_ARM_BREAKPOINT
261       case 0:
262         code_desc = "EXC_ARM_BREAKPOINT";
263         break;
264       }
265       break;
266 
267     default:
268       break;
269     }
270   } break;
271 
272   case 7:
273     exc_desc = "EXC_SYSCALL";
274     break;
275 
276   case 8:
277     exc_desc = "EXC_MACH_SYSCALL";
278     break;
279 
280   case 9:
281     exc_desc = "EXC_RPC_ALERT";
282     break;
283 
284   case 10:
285     exc_desc = "EXC_CRASH";
286     break;
287   case 11:
288     exc_desc = "EXC_RESOURCE";
289 #if defined(__APPLE__)
290     {
291       int resource_type = EXC_RESOURCE_DECODE_RESOURCE_TYPE(m_exc_code);
292 
293       code_label = "limit";
294       code_desc = code_desc_buf;
295       subcode_label = "observed";
296       subcode_desc = subcode_desc_buf;
297 
298       switch (resource_type) {
299       case RESOURCE_TYPE_CPU:
300         exc_desc = "EXC_RESOURCE RESOURCE_TYPE_CPU";
301         snprintf(code_desc_buf, sizeof(code_desc_buf), "%d%%",
302                  (int)EXC_RESOURCE_CPUMONITOR_DECODE_PERCENTAGE(m_exc_code));
303         snprintf(subcode_desc_buf, sizeof(subcode_desc_buf), "%d%%",
304                  (int)EXC_RESOURCE_CPUMONITOR_DECODE_PERCENTAGE_OBSERVED(
305                      m_exc_subcode));
306         break;
307       case RESOURCE_TYPE_WAKEUPS:
308         exc_desc = "EXC_RESOURCE RESOURCE_TYPE_WAKEUPS";
309         snprintf(
310             code_desc_buf, sizeof(code_desc_buf), "%d w/s",
311             (int)EXC_RESOURCE_CPUMONITOR_DECODE_WAKEUPS_PERMITTED(m_exc_code));
312         snprintf(subcode_desc_buf, sizeof(subcode_desc_buf), "%d w/s",
313                  (int)EXC_RESOURCE_CPUMONITOR_DECODE_WAKEUPS_OBSERVED(
314                      m_exc_subcode));
315         break;
316       case RESOURCE_TYPE_MEMORY:
317         exc_desc = "EXC_RESOURCE RESOURCE_TYPE_MEMORY";
318         snprintf(code_desc_buf, sizeof(code_desc_buf), "%d MB",
319                  (int)EXC_RESOURCE_HWM_DECODE_LIMIT(m_exc_code));
320         subcode_desc = nullptr;
321         subcode_label = "unused";
322         break;
323 #if defined(RESOURCE_TYPE_IO)
324       // RESOURCE_TYPE_IO is introduced in macOS SDK 10.12.
325       case RESOURCE_TYPE_IO:
326         exc_desc = "EXC_RESOURCE RESOURCE_TYPE_IO";
327         snprintf(code_desc_buf, sizeof(code_desc_buf), "%d MB",
328                  (int)EXC_RESOURCE_IO_DECODE_LIMIT(m_exc_code));
329         snprintf(subcode_desc_buf, sizeof(subcode_desc_buf), "%d MB",
330                  (int)EXC_RESOURCE_IO_OBSERVED(m_exc_subcode));
331         ;
332         break;
333 #endif
334       }
335     }
336 #endif
337     break;
338   case 12:
339     exc_desc = "EXC_GUARD";
340     break;
341   }
342 
343   StreamString strm;
344 
345   if (exc_desc)
346     strm.PutCString(exc_desc);
347   else
348     strm.Printf("EXC_??? (%" PRIu64 ")", m_value);
349 
350   if (m_exc_data_count >= 1) {
351     if (code_desc)
352       strm.Printf(" (%s=%s", code_label, code_desc);
353     else
354       strm.Printf(" (%s=%" PRIu64, code_label, m_exc_code);
355   }
356 
357   if (m_exc_data_count >= 2) {
358     if (subcode_desc)
359       strm.Printf(", %s=%s", subcode_label, subcode_desc);
360     else
361       strm.Printf(", %s=0x%" PRIx64, subcode_label, m_exc_subcode);
362   }
363 
364   if (m_exc_data_count > 0)
365     strm.PutChar(')');
366 
367   m_description = strm.GetString();
368   return m_description.c_str();
369 }
370 
371 StopInfoSP StopInfoMachException::CreateStopReasonWithMachException(
372     Thread &thread, uint32_t exc_type, uint32_t exc_data_count,
373     uint64_t exc_code, uint64_t exc_sub_code, uint64_t exc_sub_sub_code,
374     bool pc_already_adjusted, bool adjust_pc_if_needed) {
375   if (exc_type == 0)
376     return StopInfoSP();
377 
378   uint32_t pc_decrement = 0;
379   ExecutionContext exe_ctx(thread.shared_from_this());
380   Target *target = exe_ctx.GetTargetPtr();
381   const llvm::Triple::ArchType cpu =
382       target ? target->GetArchitecture().GetMachine()
383              : llvm::Triple::UnknownArch;
384 
385   switch (exc_type) {
386   case 1: // EXC_BAD_ACCESS
387     break;
388 
389   case 2: // EXC_BAD_INSTRUCTION
390     switch (cpu) {
391     case llvm::Triple::ppc:
392     case llvm::Triple::ppc64:
393       switch (exc_code) {
394       case 1: // EXC_PPC_INVALID_SYSCALL
395       case 2: // EXC_PPC_UNIPL_INST
396       case 3: // EXC_PPC_PRIVINST
397       case 4: // EXC_PPC_PRIVREG
398         break;
399       case 5: // EXC_PPC_TRACE
400         return StopInfo::CreateStopReasonToTrace(thread);
401       case 6: // EXC_PPC_PERFMON
402         break;
403       }
404       break;
405 
406     default:
407       break;
408     }
409     break;
410 
411   case 3: // EXC_ARITHMETIC
412   case 4: // EXC_EMULATION
413     break;
414 
415   case 5:                    // EXC_SOFTWARE
416     if (exc_code == 0x10003) // EXC_SOFT_SIGNAL
417     {
418       if (exc_sub_code == 5) {
419         // On MacOSX, a SIGTRAP can signify that a process has called exec,
420         // so we should check with our dynamic loader to verify.
421         ProcessSP process_sp(thread.GetProcess());
422         if (process_sp) {
423           DynamicLoader *dynamic_loader = process_sp->GetDynamicLoader();
424           if (dynamic_loader && dynamic_loader->ProcessDidExec()) {
425             // The program was re-exec'ed
426             return StopInfo::CreateStopReasonWithExec(thread);
427           }
428         }
429       }
430       return StopInfo::CreateStopReasonWithSignal(thread, exc_sub_code);
431     }
432     break;
433 
434   case 6: // EXC_BREAKPOINT
435   {
436     bool is_actual_breakpoint = false;
437     bool is_trace_if_actual_breakpoint_missing = false;
438     switch (cpu) {
439     case llvm::Triple::x86:
440     case llvm::Triple::x86_64:
441       if (exc_code == 1) // EXC_I386_SGL
442       {
443         if (!exc_sub_code) {
444           // This looks like a plain trap.
445           // Have to check if there is a breakpoint here as well.  When you
446           // single-step onto a trap, the single step stops you not to trap.
447           // Since we also do that check below, let's just use that logic.
448           is_actual_breakpoint = true;
449           is_trace_if_actual_breakpoint_missing = true;
450         } else {
451 
452           // It's a watchpoint, then.
453           // The exc_sub_code indicates the data break address.
454           lldb::WatchpointSP wp_sp;
455           if (target)
456             wp_sp = target->GetWatchpointList().FindByAddress(
457                 (lldb::addr_t)exc_sub_code);
458           if (wp_sp && wp_sp->IsEnabled()) {
459             // Debugserver may piggyback the hardware index of the fired
460             // watchpoint in the exception data. Set the hardware index if
461             // that's the case.
462             if (exc_data_count >= 3)
463               wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
464             return StopInfo::CreateStopReasonWithWatchpointID(thread,
465                                                               wp_sp->GetID());
466           }
467         }
468       } else if (exc_code == 2 || // EXC_I386_BPT
469                  exc_code == 3)   // EXC_I386_BPTFLT
470       {
471         // KDP returns EXC_I386_BPTFLT for trace breakpoints
472         if (exc_code == 3)
473           is_trace_if_actual_breakpoint_missing = true;
474 
475         is_actual_breakpoint = true;
476         if (!pc_already_adjusted)
477           pc_decrement = 1;
478       }
479       break;
480 
481     case llvm::Triple::ppc:
482     case llvm::Triple::ppc64:
483       is_actual_breakpoint = exc_code == 1; // EXC_PPC_BREAKPOINT
484       break;
485 
486     case llvm::Triple::arm:
487     case llvm::Triple::thumb:
488       if (exc_code == 0x102) // EXC_ARM_DA_DEBUG
489       {
490         // It's a watchpoint, then, if the exc_sub_code indicates a
491         // known/enabled data break address from our watchpoint list.
492         lldb::WatchpointSP wp_sp;
493         if (target)
494           wp_sp = target->GetWatchpointList().FindByAddress(
495               (lldb::addr_t)exc_sub_code);
496         if (wp_sp && wp_sp->IsEnabled()) {
497           // Debugserver may piggyback the hardware index of the fired
498           // watchpoint in the exception data. Set the hardware index if
499           // that's the case.
500           if (exc_data_count >= 3)
501             wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
502           return StopInfo::CreateStopReasonWithWatchpointID(thread,
503                                                             wp_sp->GetID());
504         } else {
505           is_actual_breakpoint = true;
506           is_trace_if_actual_breakpoint_missing = true;
507         }
508       } else if (exc_code == 1) // EXC_ARM_BREAKPOINT
509       {
510         is_actual_breakpoint = true;
511         is_trace_if_actual_breakpoint_missing = true;
512       } else if (exc_code == 0) // FIXME not EXC_ARM_BREAKPOINT but a kernel
513                                 // is currently returning this so accept it
514                                 // as indicating a breakpoint until the
515                                 // kernel is fixed
516       {
517         is_actual_breakpoint = true;
518         is_trace_if_actual_breakpoint_missing = true;
519       }
520       break;
521 
522     case llvm::Triple::aarch64: {
523       if (exc_code == 1 && exc_sub_code == 0) // EXC_ARM_BREAKPOINT
524       {
525         // This is hit when we single instruction step aka MDSCR_EL1 SS bit 0
526         // is set
527         is_actual_breakpoint = false;
528         is_trace_if_actual_breakpoint_missing = true;
529       }
530       if (exc_code == 0x102) // EXC_ARM_DA_DEBUG
531       {
532         // It's a watchpoint, then, if the exc_sub_code indicates a
533         // known/enabled data break address from our watchpoint list.
534         lldb::WatchpointSP wp_sp;
535         if (target)
536           wp_sp = target->GetWatchpointList().FindByAddress(
537               (lldb::addr_t)exc_sub_code);
538         if (wp_sp && wp_sp->IsEnabled()) {
539           // Debugserver may piggyback the hardware index of the fired
540           // watchpoint in the exception data. Set the hardware index if
541           // that's the case.
542           if (exc_data_count >= 3)
543             wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
544           return StopInfo::CreateStopReasonWithWatchpointID(thread,
545                                                             wp_sp->GetID());
546         }
547         // EXC_ARM_DA_DEBUG seems to be reused for EXC_BREAKPOINT as well as
548         // EXC_BAD_ACCESS
549         if (thread.GetTemporaryResumeState() == eStateStepping)
550           return StopInfo::CreateStopReasonToTrace(thread);
551       }
552       // It looks like exc_sub_code has the 4 bytes of the instruction that
553       // triggered the exception, i.e. our breakpoint opcode
554       is_actual_breakpoint = exc_code == 1;
555       break;
556     }
557 
558     default:
559       break;
560     }
561 
562     if (is_actual_breakpoint) {
563       RegisterContextSP reg_ctx_sp(thread.GetRegisterContext());
564       addr_t pc = reg_ctx_sp->GetPC() - pc_decrement;
565 
566       ProcessSP process_sp(thread.CalculateProcess());
567 
568       lldb::BreakpointSiteSP bp_site_sp;
569       if (process_sp)
570         bp_site_sp = process_sp->GetBreakpointSiteList().FindByAddress(pc);
571       if (bp_site_sp && bp_site_sp->IsEnabled()) {
572         // Update the PC if we were asked to do so, but only do so if we find
573         // a breakpoint that we know about cause this could be a trap
574         // instruction in the code
575         if (pc_decrement > 0 && adjust_pc_if_needed)
576           reg_ctx_sp->SetPC(pc);
577 
578         // If the breakpoint is for this thread, then we'll report the hit,
579         // but if it is for another thread, we can just report no reason.  We
580         // don't need to worry about stepping over the breakpoint here, that
581         // will be taken care of when the thread resumes and notices that
582         // there's a breakpoint under the pc. If we have an operating system
583         // plug-in, we might have set a thread specific breakpoint using the
584         // operating system thread ID, so we can't make any assumptions about
585         // the thread ID so we must always report the breakpoint regardless
586         // of the thread.
587         if (bp_site_sp->ValidForThisThread(&thread) ||
588             thread.GetProcess()->GetOperatingSystem() != nullptr)
589           return StopInfo::CreateStopReasonWithBreakpointSiteID(
590               thread, bp_site_sp->GetID());
591         else if (is_trace_if_actual_breakpoint_missing)
592           return StopInfo::CreateStopReasonToTrace(thread);
593         else
594           return StopInfoSP();
595       }
596 
597       // Don't call this a trace if we weren't single stepping this thread.
598       if (is_trace_if_actual_breakpoint_missing &&
599           thread.GetTemporaryResumeState() == eStateStepping) {
600         return StopInfo::CreateStopReasonToTrace(thread);
601       }
602     }
603   } break;
604 
605   case 7:  // EXC_SYSCALL
606   case 8:  // EXC_MACH_SYSCALL
607   case 9:  // EXC_RPC_ALERT
608   case 10: // EXC_CRASH
609     break;
610   }
611 
612   return StopInfoSP(new StopInfoMachException(thread, exc_type, exc_data_count,
613                                               exc_code, exc_sub_code));
614 }
615