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 // C++ Includes 14 // Other libraries and framework includes 15 // Project 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" 28 29 using namespace lldb; 30 using namespace lldb_private; 31 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; 39 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; 45 switch (m_value) { 46 case 1: // EXC_BAD_ACCESS 47 exc_desc = "EXC_BAD_ACCESS"; 48 subcode_label = "address"; 49 switch (cpu) { 50 case llvm::Triple::x86: 51 case llvm::Triple::x86_64: 52 switch (m_exc_code) { 53 case 0xd: 54 code_desc = "EXC_I386_GPFLT"; 55 m_exc_data_count = 1; 56 break; 57 } 58 break; 59 case llvm::Triple::arm: 60 case llvm::Triple::thumb: 61 switch (m_exc_code) { 62 case 0x101: 63 code_desc = "EXC_ARM_DA_ALIGN"; 64 break; 65 case 0x102: 66 code_desc = "EXC_ARM_DA_DEBUG"; 67 break; 68 } 69 break; 70 71 case llvm::Triple::ppc: 72 case llvm::Triple::ppc64: 73 switch (m_exc_code) { 74 case 0x101: 75 code_desc = "EXC_PPC_VM_PROT_READ"; 76 break; 77 case 0x102: 78 code_desc = "EXC_PPC_BADSPACE"; 79 break; 80 case 0x103: 81 code_desc = "EXC_PPC_UNALIGNED"; 82 break; 83 } 84 break; 85 86 default: 87 break; 88 } 89 break; 90 91 case 2: // EXC_BAD_INSTRUCTION 92 exc_desc = "EXC_BAD_INSTRUCTION"; 93 switch (cpu) { 94 case llvm::Triple::x86: 95 case llvm::Triple::x86_64: 96 if (m_exc_code == 1) 97 code_desc = "EXC_I386_INVOP"; 98 break; 99 100 case llvm::Triple::ppc: 101 case llvm::Triple::ppc64: 102 switch (m_exc_code) { 103 case 1: 104 code_desc = "EXC_PPC_INVALID_SYSCALL"; 105 break; 106 case 2: 107 code_desc = "EXC_PPC_UNIPL_INST"; 108 break; 109 case 3: 110 code_desc = "EXC_PPC_PRIVINST"; 111 break; 112 case 4: 113 code_desc = "EXC_PPC_PRIVREG"; 114 break; 115 case 5: 116 code_desc = "EXC_PPC_TRACE"; 117 break; 118 case 6: 119 code_desc = "EXC_PPC_PERFMON"; 120 break; 121 } 122 break; 123 124 case llvm::Triple::arm: 125 case llvm::Triple::thumb: 126 if (m_exc_code == 1) 127 code_desc = "EXC_ARM_UNDEFINED"; 128 break; 129 130 default: 131 break; 132 } 133 break; 134 135 case 3: // EXC_ARITHMETIC 136 exc_desc = "EXC_ARITHMETIC"; 137 switch (cpu) { 138 case llvm::Triple::x86: 139 case llvm::Triple::x86_64: 140 switch (m_exc_code) { 141 case 1: 142 code_desc = "EXC_I386_DIV"; 143 break; 144 case 2: 145 code_desc = "EXC_I386_INTO"; 146 break; 147 case 3: 148 code_desc = "EXC_I386_NOEXT"; 149 break; 150 case 4: 151 code_desc = "EXC_I386_EXTOVR"; 152 break; 153 case 5: 154 code_desc = "EXC_I386_EXTERR"; 155 break; 156 case 6: 157 code_desc = "EXC_I386_EMERR"; 158 break; 159 case 7: 160 code_desc = "EXC_I386_BOUND"; 161 break; 162 case 8: 163 code_desc = "EXC_I386_SSEEXTERR"; 164 break; 165 } 166 break; 167 168 case llvm::Triple::ppc: 169 case llvm::Triple::ppc64: 170 switch (m_exc_code) { 171 case 1: 172 code_desc = "EXC_PPC_OVERFLOW"; 173 break; 174 case 2: 175 code_desc = "EXC_PPC_ZERO_DIVIDE"; 176 break; 177 case 3: 178 code_desc = "EXC_PPC_FLT_INEXACT"; 179 break; 180 case 4: 181 code_desc = "EXC_PPC_FLT_ZERO_DIVIDE"; 182 break; 183 case 5: 184 code_desc = "EXC_PPC_FLT_UNDERFLOW"; 185 break; 186 case 6: 187 code_desc = "EXC_PPC_FLT_OVERFLOW"; 188 break; 189 case 7: 190 code_desc = "EXC_PPC_FLT_NOT_A_NUMBER"; 191 break; 192 } 193 break; 194 195 default: 196 break; 197 } 198 break; 199 200 case 4: // EXC_EMULATION 201 exc_desc = "EXC_EMULATION"; 202 break; 203 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"; 209 } 210 break; 211 212 case 6: // EXC_BREAKPOINT 213 { 214 exc_desc = "EXC_BREAKPOINT"; 215 switch (cpu) { 216 case llvm::Triple::x86: 217 case llvm::Triple::x86_64: 218 switch (m_exc_code) { 219 case 1: 220 code_desc = "EXC_I386_SGL"; 221 break; 222 case 2: 223 code_desc = "EXC_I386_BPT"; 224 break; 225 } 226 break; 227 228 case llvm::Triple::ppc: 229 case llvm::Triple::ppc64: 230 switch (m_exc_code) { 231 case 1: 232 code_desc = "EXC_PPC_BREAKPOINT"; 233 break; 234 } 235 break; 236 237 case llvm::Triple::arm: 238 case llvm::Triple::thumb: 239 switch (m_exc_code) { 240 case 0x101: 241 code_desc = "EXC_ARM_DA_ALIGN"; 242 break; 243 case 0x102: 244 code_desc = "EXC_ARM_DA_DEBUG"; 245 break; 246 case 1: 247 code_desc = "EXC_ARM_BREAKPOINT"; 248 break; 249 // FIXME temporary workaround, exc_code 0 does not really mean 250 // EXC_ARM_BREAKPOINT 251 case 0: 252 code_desc = "EXC_ARM_BREAKPOINT"; 253 break; 254 } 255 break; 256 257 default: 258 break; 259 } 260 } break; 261 262 case 7: 263 exc_desc = "EXC_SYSCALL"; 264 break; 265 266 case 8: 267 exc_desc = "EXC_MACH_SYSCALL"; 268 break; 269 270 case 9: 271 exc_desc = "EXC_RPC_ALERT"; 272 break; 273 274 case 10: 275 exc_desc = "EXC_CRASH"; 276 break; 277 case 11: 278 exc_desc = "EXC_RESOURCE"; 279 break; 280 case 12: 281 exc_desc = "EXC_GUARD"; 282 break; 283 } 284 285 StreamString strm; 286 287 if (exc_desc) 288 strm.PutCString(exc_desc); 289 else 290 strm.Printf("EXC_??? (%" PRIu64 ")", m_value); 291 292 if (m_exc_data_count >= 1) { 293 if (code_desc) 294 strm.Printf(" (%s=%s", code_label, code_desc); 295 else 296 strm.Printf(" (%s=%" PRIu64, code_label, m_exc_code); 297 } 298 299 if (m_exc_data_count >= 2) { 300 if (subcode_desc) 301 strm.Printf(", %s=%s", subcode_label, subcode_desc); 302 else 303 strm.Printf(", %s=0x%" PRIx64, subcode_label, m_exc_subcode); 304 } 305 306 if (m_exc_data_count > 0) 307 strm.PutChar(')'); 308 309 m_description.swap(strm.GetString()); 310 } 311 return m_description.c_str(); 312 } 313 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) { 318 if (exc_type != 0) { 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; 325 326 switch (exc_type) { 327 case 1: // EXC_BAD_ACCESS 328 break; 329 330 case 2: // EXC_BAD_INSTRUCTION 331 switch (cpu) { 332 case llvm::Triple::ppc: 333 case llvm::Triple::ppc64: 334 switch (exc_code) { 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 339 break; 340 case 5: // EXC_PPC_TRACE 341 return StopInfo::CreateStopReasonToTrace(thread); 342 case 6: // EXC_PPC_PERFMON 343 break; 344 } 345 break; 346 347 default: 348 break; 349 } 350 break; 351 352 case 3: // EXC_ARITHMETIC 353 case 4: // EXC_EMULATION 354 break; 355 356 case 5: // EXC_SOFTWARE 357 if (exc_code == 0x10003) // EXC_SOFT_SIGNAL 358 { 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()); 363 if (process_sp) { 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); 368 } 369 // if (!process_did_exec) 370 // { 371 // // We have a SIGTRAP, make sure we 372 // didn't exec by checking 373 // // for the PC being at 374 // "_dyld_start"... 375 // lldb::StackFrameSP frame_sp 376 // (thread.GetStackFrameAtIndex(0)); 377 // if (frame_sp) 378 // { 379 // const Symbol *symbol = 380 // frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol; 381 // if (symbol) 382 // { 383 // if (symbol->GetName() == 384 // ConstString("_dyld_start")) 385 // process_did_exec = true; 386 // } 387 // } 388 // } 389 } 390 } 391 return StopInfo::CreateStopReasonWithSignal(thread, exc_sub_code); 392 } 393 break; 394 395 case 6: // EXC_BREAKPOINT 396 { 397 bool is_actual_breakpoint = false; 398 bool is_trace_if_actual_breakpoint_missing = false; 399 switch (cpu) { 400 case llvm::Triple::x86: 401 case llvm::Triple::x86_64: 402 if (exc_code == 1) // EXC_I386_SGL 403 { 404 if (!exc_sub_code) { 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 410 // that logic. 411 is_actual_breakpoint = true; 412 is_trace_if_actual_breakpoint_missing = true; 413 } else { 414 415 // It's a watchpoint, then. 416 // The exc_sub_code indicates the data break address. 417 lldb::WatchpointSP wp_sp; 418 if (target) 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, 428 wp_sp->GetID()); 429 } 430 } 431 } else if (exc_code == 2 || // EXC_I386_BPT 432 exc_code == 3) // EXC_I386_BPTFLT 433 { 434 // KDP returns EXC_I386_BPTFLT for trace breakpoints 435 if (exc_code == 3) 436 is_trace_if_actual_breakpoint_missing = true; 437 438 is_actual_breakpoint = true; 439 if (!pc_already_adjusted) 440 pc_decrement = 1; 441 } 442 break; 443 444 case llvm::Triple::ppc: 445 case llvm::Triple::ppc64: 446 is_actual_breakpoint = exc_code == 1; // EXC_PPC_BREAKPOINT 447 break; 448 449 case llvm::Triple::arm: 450 case llvm::Triple::thumb: 451 if (exc_code == 0x102) // EXC_ARM_DA_DEBUG 452 { 453 // It's a watchpoint, then, if the exc_sub_code indicates a 454 // known/enabled 455 // data break address from our watchpoint list. 456 lldb::WatchpointSP wp_sp; 457 if (target) 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, 467 wp_sp->GetID()); 468 } else { 469 is_actual_breakpoint = true; 470 is_trace_if_actual_breakpoint_missing = true; 471 } 472 } else if (exc_code == 1) // EXC_ARM_BREAKPOINT 473 { 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 479 // fixed 480 { 481 is_actual_breakpoint = true; 482 is_trace_if_actual_breakpoint_missing = true; 483 } 484 break; 485 486 case llvm::Triple::aarch64: { 487 if (exc_code == 1 && exc_sub_code == 0) // EXC_ARM_BREAKPOINT 488 { 489 // This is hit when we single instruction step aka MDSCR_EL1 SS bit 0 490 // is set 491 is_actual_breakpoint = false; 492 is_trace_if_actual_breakpoint_missing = true; 493 } 494 if (exc_code == 0x102) // EXC_ARM_DA_DEBUG 495 { 496 // It's a watchpoint, then, if the exc_sub_code indicates a 497 // known/enabled 498 // 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. 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, 510 wp_sp->GetID()); 511 } 512 // EXC_ARM_DA_DEBUG seems to be reused for EXC_BREAKPOINT as well as 513 // EXC_BAD_ACCESS 514 if (thread.GetTemporaryResumeState() == eStateStepping) 515 return StopInfo::CreateStopReasonToTrace(thread); 516 } 517 // It looks like exc_sub_code has the 4 bytes of the instruction that 518 // triggered the 519 // exception, i.e. our breakpoint opcode 520 is_actual_breakpoint = exc_code == 1; 521 break; 522 } 523 524 default: 525 break; 526 } 527 528 if (is_actual_breakpoint) { 529 RegisterContextSP reg_ctx_sp(thread.GetRegisterContext()); 530 addr_t pc = reg_ctx_sp->GetPC() - pc_decrement; 531 532 ProcessSP process_sp(thread.CalculateProcess()); 533 534 lldb::BreakpointSiteSP bp_site_sp; 535 if (process_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); 543 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); 561 else 562 return StopInfoSP(); 563 } 564 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); 569 } 570 } 571 } break; 572 573 case 7: // EXC_SYSCALL 574 case 8: // EXC_MACH_SYSCALL 575 case 9: // EXC_RPC_ALERT 576 case 10: // EXC_CRASH 577 break; 578 } 579 580 return StopInfoSP(new StopInfoMachException( 581 thread, exc_type, exc_data_count, exc_code, exc_sub_code)); 582 } 583 return StopInfoSP(); 584 } 585