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 // C Includes
13 #include <kern/exc_resource.h>
14 
15 // C++ Includes
16 // Other libraries and framework includes
17 // Project includes
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       {
285         int resource_type = EXC_RESOURCE_DECODE_RESOURCE_TYPE(m_exc_code);
286 
287         code_label = "limit";
288         code_desc = code_desc_buf;
289         subcode_label = "observed";
290         subcode_desc = subcode_desc_buf;
291 
292         switch (resource_type) {
293         case RESOURCE_TYPE_CPU:
294           exc_desc = "EXC_RESOURCE RESOURCE_TYPE_CPU";
295           snprintf(code_desc_buf, sizeof(code_desc_buf), "%d%%",
296             (int)EXC_RESOURCE_CPUMONITOR_DECODE_PERCENTAGE(m_exc_code));
297           snprintf(subcode_desc_buf, sizeof(subcode_desc_buf), "%d%%",
298             (int)EXC_RESOURCE_CPUMONITOR_DECODE_PERCENTAGE_OBSERVED(m_exc_subcode));
299           break;
300         case RESOURCE_TYPE_WAKEUPS:
301           exc_desc = "EXC_RESOURCE RESOURCE_TYPE_WAKEUPS";
302           snprintf(code_desc_buf, sizeof(code_desc_buf), "%d w/s",
303             (int)EXC_RESOURCE_CPUMONITOR_DECODE_WAKEUPS_PERMITTED(m_exc_code));
304           snprintf(subcode_desc_buf, sizeof(subcode_desc_buf), "%d w/s",
305             (int)EXC_RESOURCE_CPUMONITOR_DECODE_WAKEUPS_OBSERVED(m_exc_subcode));
306           break;
307         case RESOURCE_TYPE_MEMORY:
308           exc_desc = "EXC_RESOURCE RESOURCE_TYPE_MEMORY";
309           snprintf(code_desc_buf, sizeof(code_desc_buf), "%d MB",
310             (int)EXC_RESOURCE_HWM_DECODE_LIMIT(m_exc_code));
311           subcode_desc = nullptr;
312           subcode_label = "unused";
313           break;
314         case RESOURCE_TYPE_IO:
315           exc_desc = "EXC_RESOURCE RESOURCE_TYPE_IO";
316           snprintf(code_desc_buf, sizeof(code_desc_buf), "%d MB",
317             (int)EXC_RESOURCE_IO_DECODE_LIMIT(m_exc_code));
318           snprintf(subcode_desc_buf, sizeof(subcode_desc_buf), "%d MB",
319             (int)EXC_RESOURCE_IO_OBSERVED(m_exc_subcode));;
320           break;
321         }
322       }
323       break;
324     case 12:
325       exc_desc = "EXC_GUARD";
326       break;
327     }
328 
329     StreamString strm;
330 
331     if (exc_desc)
332       strm.PutCString(exc_desc);
333     else
334       strm.Printf("EXC_??? (%" PRIu64 ")", m_value);
335 
336     if (m_exc_data_count >= 1) {
337       if (code_desc)
338         strm.Printf(" (%s=%s", code_label, code_desc);
339       else
340         strm.Printf(" (%s=%" PRIu64, code_label, m_exc_code);
341     }
342 
343     if (m_exc_data_count >= 2) {
344       if (subcode_desc)
345         strm.Printf(", %s=%s", subcode_label, subcode_desc);
346       else
347         strm.Printf(", %s=0x%" PRIx64, subcode_label, m_exc_subcode);
348     }
349 
350     if (m_exc_data_count > 0)
351       strm.PutChar(')');
352 
353     m_description = strm.GetString();
354   }
355   return m_description.c_str();
356 }
357 
358 StopInfoSP StopInfoMachException::CreateStopReasonWithMachException(
359     Thread &thread, uint32_t exc_type, uint32_t exc_data_count,
360     uint64_t exc_code, uint64_t exc_sub_code, uint64_t exc_sub_sub_code,
361     bool pc_already_adjusted, bool adjust_pc_if_needed) {
362   if (exc_type != 0) {
363     uint32_t pc_decrement = 0;
364     ExecutionContext exe_ctx(thread.shared_from_this());
365     Target *target = exe_ctx.GetTargetPtr();
366     const llvm::Triple::ArchType cpu =
367         target ? target->GetArchitecture().GetMachine()
368                : llvm::Triple::UnknownArch;
369 
370     switch (exc_type) {
371     case 1: // EXC_BAD_ACCESS
372       break;
373 
374     case 2: // EXC_BAD_INSTRUCTION
375       switch (cpu) {
376       case llvm::Triple::ppc:
377       case llvm::Triple::ppc64:
378         switch (exc_code) {
379         case 1: // EXC_PPC_INVALID_SYSCALL
380         case 2: // EXC_PPC_UNIPL_INST
381         case 3: // EXC_PPC_PRIVINST
382         case 4: // EXC_PPC_PRIVREG
383           break;
384         case 5: // EXC_PPC_TRACE
385           return StopInfo::CreateStopReasonToTrace(thread);
386         case 6: // EXC_PPC_PERFMON
387           break;
388         }
389         break;
390 
391       default:
392         break;
393       }
394       break;
395 
396     case 3: // EXC_ARITHMETIC
397     case 4: // EXC_EMULATION
398       break;
399 
400     case 5:                    // EXC_SOFTWARE
401       if (exc_code == 0x10003) // EXC_SOFT_SIGNAL
402       {
403         if (exc_sub_code == 5) {
404           // On MacOSX, a SIGTRAP can signify that a process has called exec,
405           // so we should check with our dynamic loader to verify.
406           ProcessSP process_sp(thread.GetProcess());
407           if (process_sp) {
408             DynamicLoader *dynamic_loader = process_sp->GetDynamicLoader();
409             if (dynamic_loader && dynamic_loader->ProcessDidExec()) {
410               // The program was re-exec'ed
411               return StopInfo::CreateStopReasonWithExec(thread);
412             }
413             //                        if (!process_did_exec)
414             //                        {
415             //                            // We have a SIGTRAP, make sure we
416             //                            didn't exec by checking
417             //                            // for the PC being at
418             //                            "_dyld_start"...
419             //                            lldb::StackFrameSP frame_sp
420             //                            (thread.GetStackFrameAtIndex(0));
421             //                            if (frame_sp)
422             //                            {
423             //                                const Symbol *symbol =
424             //                                frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol;
425             //                                if (symbol)
426             //                                {
427             //                                    if (symbol->GetName() ==
428             //                                    ConstString("_dyld_start"))
429             //                                        process_did_exec = true;
430             //                                }
431             //                            }
432             //                        }
433           }
434         }
435         return StopInfo::CreateStopReasonWithSignal(thread, exc_sub_code);
436       }
437       break;
438 
439     case 6: // EXC_BREAKPOINT
440     {
441       bool is_actual_breakpoint = false;
442       bool is_trace_if_actual_breakpoint_missing = false;
443       switch (cpu) {
444       case llvm::Triple::x86:
445       case llvm::Triple::x86_64:
446         if (exc_code == 1) // EXC_I386_SGL
447         {
448           if (!exc_sub_code) {
449             // This looks like a plain trap.
450             // Have to check if there is a breakpoint here as well.  When you
451             // single-step onto a trap, the single step stops you not to trap.
452             // Since we also do that check below, let's just use that logic.
453             is_actual_breakpoint = true;
454             is_trace_if_actual_breakpoint_missing = true;
455           } else {
456 
457             // It's a watchpoint, then.
458             // The exc_sub_code indicates the data break address.
459             lldb::WatchpointSP wp_sp;
460             if (target)
461               wp_sp = target->GetWatchpointList().FindByAddress(
462                   (lldb::addr_t)exc_sub_code);
463             if (wp_sp && wp_sp->IsEnabled()) {
464               // Debugserver may piggyback the hardware index of the fired
465               // watchpoint in the exception data. Set the hardware index if
466               // that's the case.
467               if (exc_data_count >= 3)
468                 wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
469               return StopInfo::CreateStopReasonWithWatchpointID(thread,
470                                                                 wp_sp->GetID());
471             }
472           }
473         } else if (exc_code == 2 || // EXC_I386_BPT
474                    exc_code == 3)   // EXC_I386_BPTFLT
475         {
476           // KDP returns EXC_I386_BPTFLT for trace breakpoints
477           if (exc_code == 3)
478             is_trace_if_actual_breakpoint_missing = true;
479 
480           is_actual_breakpoint = true;
481           if (!pc_already_adjusted)
482             pc_decrement = 1;
483         }
484         break;
485 
486       case llvm::Triple::ppc:
487       case llvm::Triple::ppc64:
488         is_actual_breakpoint = exc_code == 1; // EXC_PPC_BREAKPOINT
489         break;
490 
491       case llvm::Triple::arm:
492       case llvm::Triple::thumb:
493         if (exc_code == 0x102) // EXC_ARM_DA_DEBUG
494         {
495           // It's a watchpoint, then, if the exc_sub_code indicates a
496           // known/enabled data break address from our watchpoint list.
497           lldb::WatchpointSP wp_sp;
498           if (target)
499             wp_sp = target->GetWatchpointList().FindByAddress(
500                 (lldb::addr_t)exc_sub_code);
501           if (wp_sp && wp_sp->IsEnabled()) {
502             // Debugserver may piggyback the hardware index of the fired
503             // watchpoint in the exception data. Set the hardware index if
504             // that's the case.
505             if (exc_data_count >= 3)
506               wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
507             return StopInfo::CreateStopReasonWithWatchpointID(thread,
508                                                               wp_sp->GetID());
509           } else {
510             is_actual_breakpoint = true;
511             is_trace_if_actual_breakpoint_missing = true;
512           }
513         } else if (exc_code == 1) // EXC_ARM_BREAKPOINT
514         {
515           is_actual_breakpoint = true;
516           is_trace_if_actual_breakpoint_missing = true;
517         } else if (exc_code == 0) // FIXME not EXC_ARM_BREAKPOINT but a kernel
518                                   // is currently returning this so accept it
519                                   // as indicating a breakpoint until the
520                                   // kernel is fixed
521         {
522           is_actual_breakpoint = true;
523           is_trace_if_actual_breakpoint_missing = true;
524         }
525         break;
526 
527       case llvm::Triple::aarch64: {
528         if (exc_code == 1 && exc_sub_code == 0) // EXC_ARM_BREAKPOINT
529         {
530           // This is hit when we single instruction step aka MDSCR_EL1 SS bit 0
531           // is set
532           is_actual_breakpoint = false;
533           is_trace_if_actual_breakpoint_missing = true;
534         }
535         if (exc_code == 0x102) // EXC_ARM_DA_DEBUG
536         {
537           // It's a watchpoint, then, if the exc_sub_code indicates a
538           // known/enabled data break address from our watchpoint list.
539           lldb::WatchpointSP wp_sp;
540           if (target)
541             wp_sp = target->GetWatchpointList().FindByAddress(
542                 (lldb::addr_t)exc_sub_code);
543           if (wp_sp && wp_sp->IsEnabled()) {
544             // Debugserver may piggyback the hardware index of the fired
545             // watchpoint in the exception data. Set the hardware index if
546             // that's the case.
547             if (exc_data_count >= 3)
548               wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
549             return StopInfo::CreateStopReasonWithWatchpointID(thread,
550                                                               wp_sp->GetID());
551           }
552           // EXC_ARM_DA_DEBUG seems to be reused for EXC_BREAKPOINT as well as
553           // EXC_BAD_ACCESS
554           if (thread.GetTemporaryResumeState() == eStateStepping)
555             return StopInfo::CreateStopReasonToTrace(thread);
556         }
557         // It looks like exc_sub_code has the 4 bytes of the instruction that
558         // triggered the exception, i.e. our breakpoint opcode
559         is_actual_breakpoint = exc_code == 1;
560         break;
561       }
562 
563       default:
564         break;
565       }
566 
567       if (is_actual_breakpoint) {
568         RegisterContextSP reg_ctx_sp(thread.GetRegisterContext());
569         addr_t pc = reg_ctx_sp->GetPC() - pc_decrement;
570 
571         ProcessSP process_sp(thread.CalculateProcess());
572 
573         lldb::BreakpointSiteSP bp_site_sp;
574         if (process_sp)
575           bp_site_sp = process_sp->GetBreakpointSiteList().FindByAddress(pc);
576         if (bp_site_sp && bp_site_sp->IsEnabled()) {
577           // Update the PC if we were asked to do so, but only do so if we find
578           // a breakpoint that we know about cause this could be a trap
579           // instruction in the code
580           if (pc_decrement > 0 && adjust_pc_if_needed)
581             reg_ctx_sp->SetPC(pc);
582 
583           // If the breakpoint is for this thread, then we'll report the hit,
584           // but if it is for another thread, we can just report no reason.  We
585           // don't need to worry about stepping over the breakpoint here, that
586           // will be taken care of when the thread resumes and notices that
587           // there's a breakpoint under the pc. If we have an operating system
588           // plug-in, we might have set a thread specific breakpoint using the
589           // operating system thread ID, so we can't make any assumptions about
590           // the thread ID so we must always report the breakpoint regardless
591           // of the thread.
592           if (bp_site_sp->ValidForThisThread(&thread) ||
593               thread.GetProcess()->GetOperatingSystem() != NULL)
594             return StopInfo::CreateStopReasonWithBreakpointSiteID(
595                 thread, bp_site_sp->GetID());
596           else if (is_trace_if_actual_breakpoint_missing)
597             return StopInfo::CreateStopReasonToTrace(thread);
598           else
599             return StopInfoSP();
600         }
601 
602         // Don't call this a trace if we weren't single stepping this thread.
603         if (is_trace_if_actual_breakpoint_missing &&
604             thread.GetTemporaryResumeState() == eStateStepping) {
605           return StopInfo::CreateStopReasonToTrace(thread);
606         }
607       }
608     } break;
609 
610     case 7:  // EXC_SYSCALL
611     case 8:  // EXC_MACH_SYSCALL
612     case 9:  // EXC_RPC_ALERT
613     case 10: // EXC_CRASH
614       break;
615     }
616 
617     return StopInfoSP(new StopInfoMachException(
618         thread, exc_type, exc_data_count, exc_code, exc_sub_code));
619   }
620   return StopInfoSP();
621 }
622