1 //===-- StopInfoMachException.cpp -------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "StopInfoMachException.h"
14 // Other libraries and framework includes
16 #include "lldb/Breakpoint/Watchpoint.h"
17 #include "lldb/Core/ArchSpec.h"
18 #include "lldb/Core/StreamString.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"
30 using namespace lldb_private;
32 const char *StopInfoMachException::GetDescription() {
33 if (m_description.empty() && m_value != 0) {
34 ExecutionContext exe_ctx(m_thread_wp.lock());
35 Target *target = exe_ctx.GetTargetPtr();
36 const llvm::Triple::ArchType cpu =
37 target ? target->GetArchitecture().GetMachine()
38 : llvm::Triple::UnknownArch;
40 const char *exc_desc = NULL;
41 const char *code_label = "code";
42 const char *code_desc = NULL;
43 const char *subcode_label = "subcode";
44 const char *subcode_desc = NULL;
46 case 1: // EXC_BAD_ACCESS
47 exc_desc = "EXC_BAD_ACCESS";
48 subcode_label = "address";
50 case llvm::Triple::x86:
51 case llvm::Triple::x86_64:
54 code_desc = "EXC_I386_GPFLT";
59 case llvm::Triple::arm:
60 case llvm::Triple::thumb:
63 code_desc = "EXC_ARM_DA_ALIGN";
66 code_desc = "EXC_ARM_DA_DEBUG";
71 case llvm::Triple::ppc:
72 case llvm::Triple::ppc64:
75 code_desc = "EXC_PPC_VM_PROT_READ";
78 code_desc = "EXC_PPC_BADSPACE";
81 code_desc = "EXC_PPC_UNALIGNED";
91 case 2: // EXC_BAD_INSTRUCTION
92 exc_desc = "EXC_BAD_INSTRUCTION";
94 case llvm::Triple::x86:
95 case llvm::Triple::x86_64:
97 code_desc = "EXC_I386_INVOP";
100 case llvm::Triple::ppc:
101 case llvm::Triple::ppc64:
102 switch (m_exc_code) {
104 code_desc = "EXC_PPC_INVALID_SYSCALL";
107 code_desc = "EXC_PPC_UNIPL_INST";
110 code_desc = "EXC_PPC_PRIVINST";
113 code_desc = "EXC_PPC_PRIVREG";
116 code_desc = "EXC_PPC_TRACE";
119 code_desc = "EXC_PPC_PERFMON";
124 case llvm::Triple::arm:
125 case llvm::Triple::thumb:
127 code_desc = "EXC_ARM_UNDEFINED";
135 case 3: // EXC_ARITHMETIC
136 exc_desc = "EXC_ARITHMETIC";
138 case llvm::Triple::x86:
139 case llvm::Triple::x86_64:
140 switch (m_exc_code) {
142 code_desc = "EXC_I386_DIV";
145 code_desc = "EXC_I386_INTO";
148 code_desc = "EXC_I386_NOEXT";
151 code_desc = "EXC_I386_EXTOVR";
154 code_desc = "EXC_I386_EXTERR";
157 code_desc = "EXC_I386_EMERR";
160 code_desc = "EXC_I386_BOUND";
163 code_desc = "EXC_I386_SSEEXTERR";
168 case llvm::Triple::ppc:
169 case llvm::Triple::ppc64:
170 switch (m_exc_code) {
172 code_desc = "EXC_PPC_OVERFLOW";
175 code_desc = "EXC_PPC_ZERO_DIVIDE";
178 code_desc = "EXC_PPC_FLT_INEXACT";
181 code_desc = "EXC_PPC_FLT_ZERO_DIVIDE";
184 code_desc = "EXC_PPC_FLT_UNDERFLOW";
187 code_desc = "EXC_PPC_FLT_OVERFLOW";
190 code_desc = "EXC_PPC_FLT_NOT_A_NUMBER";
200 case 4: // EXC_EMULATION
201 exc_desc = "EXC_EMULATION";
204 case 5: // EXC_SOFTWARE
205 exc_desc = "EXC_SOFTWARE";
206 if (m_exc_code == 0x10003) {
207 subcode_desc = "EXC_SOFT_SIGNAL";
208 subcode_label = "signo";
212 case 6: // EXC_BREAKPOINT
214 exc_desc = "EXC_BREAKPOINT";
216 case llvm::Triple::x86:
217 case llvm::Triple::x86_64:
218 switch (m_exc_code) {
220 code_desc = "EXC_I386_SGL";
223 code_desc = "EXC_I386_BPT";
228 case llvm::Triple::ppc:
229 case llvm::Triple::ppc64:
230 switch (m_exc_code) {
232 code_desc = "EXC_PPC_BREAKPOINT";
237 case llvm::Triple::arm:
238 case llvm::Triple::thumb:
239 switch (m_exc_code) {
241 code_desc = "EXC_ARM_DA_ALIGN";
244 code_desc = "EXC_ARM_DA_DEBUG";
247 code_desc = "EXC_ARM_BREAKPOINT";
249 // FIXME temporary workaround, exc_code 0 does not really mean
250 // EXC_ARM_BREAKPOINT
252 code_desc = "EXC_ARM_BREAKPOINT";
263 exc_desc = "EXC_SYSCALL";
267 exc_desc = "EXC_MACH_SYSCALL";
271 exc_desc = "EXC_RPC_ALERT";
275 exc_desc = "EXC_CRASH";
278 exc_desc = "EXC_RESOURCE";
281 exc_desc = "EXC_GUARD";
288 strm.PutCString(exc_desc);
290 strm.Printf("EXC_??? (%" PRIu64 ")", m_value);
292 if (m_exc_data_count >= 1) {
294 strm.Printf(" (%s=%s", code_label, code_desc);
296 strm.Printf(" (%s=%" PRIu64, code_label, m_exc_code);
299 if (m_exc_data_count >= 2) {
301 strm.Printf(", %s=%s", subcode_label, subcode_desc);
303 strm.Printf(", %s=0x%" PRIx64, subcode_label, m_exc_subcode);
306 if (m_exc_data_count > 0)
309 m_description = strm.GetString();
311 return m_description.c_str();
314 StopInfoSP StopInfoMachException::CreateStopReasonWithMachException(
315 Thread &thread, uint32_t exc_type, uint32_t exc_data_count,
316 uint64_t exc_code, uint64_t exc_sub_code, uint64_t exc_sub_sub_code,
317 bool pc_already_adjusted, bool adjust_pc_if_needed) {
319 uint32_t pc_decrement = 0;
320 ExecutionContext exe_ctx(thread.shared_from_this());
321 Target *target = exe_ctx.GetTargetPtr();
322 const llvm::Triple::ArchType cpu =
323 target ? target->GetArchitecture().GetMachine()
324 : llvm::Triple::UnknownArch;
327 case 1: // EXC_BAD_ACCESS
330 case 2: // EXC_BAD_INSTRUCTION
332 case llvm::Triple::ppc:
333 case llvm::Triple::ppc64:
335 case 1: // EXC_PPC_INVALID_SYSCALL
336 case 2: // EXC_PPC_UNIPL_INST
337 case 3: // EXC_PPC_PRIVINST
338 case 4: // EXC_PPC_PRIVREG
340 case 5: // EXC_PPC_TRACE
341 return StopInfo::CreateStopReasonToTrace(thread);
342 case 6: // EXC_PPC_PERFMON
352 case 3: // EXC_ARITHMETIC
353 case 4: // EXC_EMULATION
356 case 5: // EXC_SOFTWARE
357 if (exc_code == 0x10003) // EXC_SOFT_SIGNAL
359 if (exc_sub_code == 5) {
360 // On MacOSX, a SIGTRAP can signify that a process has called
361 // exec, so we should check with our dynamic loader to verify.
362 ProcessSP process_sp(thread.GetProcess());
364 DynamicLoader *dynamic_loader = process_sp->GetDynamicLoader();
365 if (dynamic_loader && dynamic_loader->ProcessDidExec()) {
366 // The program was re-exec'ed
367 return StopInfo::CreateStopReasonWithExec(thread);
369 // if (!process_did_exec)
371 // // We have a SIGTRAP, make sure we
372 // didn't exec by checking
373 // // for the PC being at
375 // lldb::StackFrameSP frame_sp
376 // (thread.GetStackFrameAtIndex(0));
379 // const Symbol *symbol =
380 // frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol;
383 // if (symbol->GetName() ==
384 // ConstString("_dyld_start"))
385 // process_did_exec = true;
391 return StopInfo::CreateStopReasonWithSignal(thread, exc_sub_code);
395 case 6: // EXC_BREAKPOINT
397 bool is_actual_breakpoint = false;
398 bool is_trace_if_actual_breakpoint_missing = false;
400 case llvm::Triple::x86:
401 case llvm::Triple::x86_64:
402 if (exc_code == 1) // EXC_I386_SGL
405 // This looks like a plain trap.
406 // Have to check if there is a breakpoint here as well. When you
407 // single-step onto a trap,
408 // the single step stops you not to trap. Since we also do that
409 // check below, let's just use
411 is_actual_breakpoint = true;
412 is_trace_if_actual_breakpoint_missing = true;
415 // It's a watchpoint, then.
416 // The exc_sub_code indicates the data break address.
417 lldb::WatchpointSP wp_sp;
419 wp_sp = target->GetWatchpointList().FindByAddress(
420 (lldb::addr_t)exc_sub_code);
421 if (wp_sp && wp_sp->IsEnabled()) {
422 // Debugserver may piggyback the hardware index of the fired
423 // watchpoint in the exception data.
424 // Set the hardware index if that's the case.
425 if (exc_data_count >= 3)
426 wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
427 return StopInfo::CreateStopReasonWithWatchpointID(thread,
431 } else if (exc_code == 2 || // EXC_I386_BPT
432 exc_code == 3) // EXC_I386_BPTFLT
434 // KDP returns EXC_I386_BPTFLT for trace breakpoints
436 is_trace_if_actual_breakpoint_missing = true;
438 is_actual_breakpoint = true;
439 if (!pc_already_adjusted)
444 case llvm::Triple::ppc:
445 case llvm::Triple::ppc64:
446 is_actual_breakpoint = exc_code == 1; // EXC_PPC_BREAKPOINT
449 case llvm::Triple::arm:
450 case llvm::Triple::thumb:
451 if (exc_code == 0x102) // EXC_ARM_DA_DEBUG
453 // It's a watchpoint, then, if the exc_sub_code indicates a
455 // data break address from our watchpoint list.
456 lldb::WatchpointSP wp_sp;
458 wp_sp = target->GetWatchpointList().FindByAddress(
459 (lldb::addr_t)exc_sub_code);
460 if (wp_sp && wp_sp->IsEnabled()) {
461 // Debugserver may piggyback the hardware index of the fired
462 // watchpoint in the exception data.
463 // Set the hardware index if that's the case.
464 if (exc_data_count >= 3)
465 wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
466 return StopInfo::CreateStopReasonWithWatchpointID(thread,
469 is_actual_breakpoint = true;
470 is_trace_if_actual_breakpoint_missing = true;
472 } else if (exc_code == 1) // EXC_ARM_BREAKPOINT
474 is_actual_breakpoint = true;
475 is_trace_if_actual_breakpoint_missing = true;
476 } else if (exc_code == 0) // FIXME not EXC_ARM_BREAKPOINT but a kernel
477 // is currently returning this so accept it as
478 // indicating a breakpoint until the kernel is
481 is_actual_breakpoint = true;
482 is_trace_if_actual_breakpoint_missing = true;
486 case llvm::Triple::aarch64: {
487 if (exc_code == 1 && exc_sub_code == 0) // EXC_ARM_BREAKPOINT
489 // This is hit when we single instruction step aka MDSCR_EL1 SS bit 0
491 is_actual_breakpoint = false;
492 is_trace_if_actual_breakpoint_missing = true;
494 if (exc_code == 0x102) // EXC_ARM_DA_DEBUG
496 // It's a watchpoint, then, if the exc_sub_code indicates a
498 // data break address from our watchpoint list.
499 lldb::WatchpointSP wp_sp;
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.
506 // Set the hardware index if 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,
512 // EXC_ARM_DA_DEBUG seems to be reused for EXC_BREAKPOINT as well as
514 if (thread.GetTemporaryResumeState() == eStateStepping)
515 return StopInfo::CreateStopReasonToTrace(thread);
517 // It looks like exc_sub_code has the 4 bytes of the instruction that
519 // exception, i.e. our breakpoint opcode
520 is_actual_breakpoint = exc_code == 1;
528 if (is_actual_breakpoint) {
529 RegisterContextSP reg_ctx_sp(thread.GetRegisterContext());
530 addr_t pc = reg_ctx_sp->GetPC() - pc_decrement;
532 ProcessSP process_sp(thread.CalculateProcess());
534 lldb::BreakpointSiteSP bp_site_sp;
536 bp_site_sp = process_sp->GetBreakpointSiteList().FindByAddress(pc);
537 if (bp_site_sp && bp_site_sp->IsEnabled()) {
538 // Update the PC if we were asked to do so, but only do
539 // so if we find a breakpoint that we know about cause
540 // this could be a trap instruction in the code
541 if (pc_decrement > 0 && adjust_pc_if_needed)
542 reg_ctx_sp->SetPC(pc);
544 // If the breakpoint is for this thread, then we'll report the hit,
545 // but if it is for another thread,
546 // we can just report no reason. We don't need to worry about
547 // stepping over the breakpoint here, that
548 // will be taken care of when the thread resumes and notices that
549 // there's a breakpoint under the pc.
550 // If we have an operating system plug-in, we might have set a thread
551 // specific breakpoint using the
552 // operating system thread ID, so we can't make any assumptions about
553 // the thread ID so we must always
554 // report the breakpoint regardless of the thread.
555 if (bp_site_sp->ValidForThisThread(&thread) ||
556 thread.GetProcess()->GetOperatingSystem() != NULL)
557 return StopInfo::CreateStopReasonWithBreakpointSiteID(
558 thread, bp_site_sp->GetID());
559 else if (is_trace_if_actual_breakpoint_missing)
560 return StopInfo::CreateStopReasonToTrace(thread);
565 // Don't call this a trace if we weren't single stepping this thread.
566 if (is_trace_if_actual_breakpoint_missing &&
567 thread.GetTemporaryResumeState() == eStateStepping) {
568 return StopInfo::CreateStopReasonToTrace(thread);
573 case 7: // EXC_SYSCALL
574 case 8: // EXC_MACH_SYSCALL
575 case 9: // EXC_RPC_ALERT
576 case 10: // EXC_CRASH
580 return StopInfoSP(new StopInfoMachException(
581 thread, exc_type, exc_data_count, exc_code, exc_sub_code));