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