1 //===-- StopInfoMachException.cpp -----------------------------------------===// 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 #include "lldb/lldb-forward.h" 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/ABI.h" 21 #include "lldb/Target/DynamicLoader.h" 22 #include "lldb/Target/ExecutionContext.h" 23 #include "lldb/Target/Process.h" 24 #include "lldb/Target/RegisterContext.h" 25 #include "lldb/Target/Target.h" 26 #include "lldb/Target/Thread.h" 27 #include "lldb/Target/ThreadPlan.h" 28 #include "lldb/Target/UnixSignals.h" 29 #include "lldb/Utility/StreamString.h" 30 31 using namespace lldb; 32 using namespace lldb_private; 33 34 /// Information about a pointer-authentication related instruction. 35 struct PtrauthInstructionInfo { 36 bool IsAuthenticated; 37 bool IsLoad; 38 bool DoesBranch; 39 }; 40 41 /// Get any pointer-authentication related information about the instruction 42 /// at address \p at_addr. 43 static llvm::Optional<PtrauthInstructionInfo> 44 GetPtrauthInstructionInfo(Target &target, const ArchSpec &arch, 45 const Address &at_addr) { 46 const char *plugin_name = nullptr; 47 const char *flavor = nullptr; 48 AddressRange range_bounds(at_addr, 4); 49 const bool prefer_file_cache = true; 50 DisassemblerSP disassembler_sp = Disassembler::DisassembleRange( 51 arch, plugin_name, flavor, target, range_bounds, prefer_file_cache); 52 if (!disassembler_sp) 53 return llvm::None; 54 55 InstructionList &insn_list = disassembler_sp->GetInstructionList(); 56 InstructionSP insn = insn_list.GetInstructionAtIndex(0); 57 if (!insn) 58 return llvm::None; 59 60 return PtrauthInstructionInfo{insn->IsAuthenticated(), insn->IsLoad(), 61 insn->DoesBranch()}; 62 } 63 64 /// Describe the load address of \p addr using the format filename:line:col. 65 static void DescribeAddressBriefly(Stream &strm, const Address &addr, 66 Target &target) { 67 strm.Printf("at address=0x%" PRIx64, addr.GetLoadAddress(&target)); 68 StreamString s; 69 if (addr.GetDescription(s, target, eDescriptionLevelBrief)) 70 strm.Printf(" %s", s.GetString().data()); 71 strm.Printf(".\n"); 72 } 73 74 bool StopInfoMachException::DeterminePtrauthFailure(ExecutionContext &exe_ctx) { 75 bool IsBreakpoint = m_value == 6; // EXC_BREAKPOINT 76 bool IsBadAccess = m_value == 1; // EXC_BAD_ACCESS 77 if (!IsBreakpoint && !IsBadAccess) 78 return false; 79 80 // Check that we have a live process. 81 if (!exe_ctx.HasProcessScope() || !exe_ctx.HasThreadScope() || 82 !exe_ctx.HasTargetScope()) 83 return false; 84 85 Thread &thread = *exe_ctx.GetThreadPtr(); 86 StackFrameSP current_frame = thread.GetStackFrameAtIndex(0); 87 if (!current_frame) 88 return false; 89 90 Target &target = *exe_ctx.GetTargetPtr(); 91 Process &process = *exe_ctx.GetProcessPtr(); 92 ABISP abi_sp = process.GetABI(); 93 const ArchSpec &arch = target.GetArchitecture(); 94 assert(abi_sp && "Missing ABI info"); 95 96 // Check for a ptrauth-enabled target. 97 const bool ptrauth_enabled_target = 98 arch.GetCore() == ArchSpec::eCore_arm_arm64e; 99 if (!ptrauth_enabled_target) 100 return false; 101 102 // Set up a stream we can write a diagnostic into. 103 StreamString strm; 104 auto emit_ptrauth_prologue = [&](uint64_t at_address) { 105 strm.Printf("EXC_BAD_ACCESS (code=%" PRIu64 ", address=0x%" PRIx64 ")\n", 106 m_exc_code, at_address); 107 strm.Printf("Note: Possible pointer authentication failure detected.\n"); 108 }; 109 110 // Check if we have a "brk 0xc47x" trap, where the value that failed to 111 // authenticate is in x16. 112 Address current_address = current_frame->GetFrameCodeAddress(); 113 if (IsBreakpoint) { 114 RegisterContext *reg_ctx = exe_ctx.GetRegisterContext(); 115 if (!reg_ctx) 116 return false; 117 118 const RegisterInfo *X16Info = reg_ctx->GetRegisterInfoByName("x16"); 119 RegisterValue X16Val; 120 if (!reg_ctx->ReadRegister(X16Info, X16Val)) 121 return false; 122 uint64_t bad_address = X16Val.GetAsUInt64(); 123 124 uint64_t fixed_bad_address = abi_sp->FixCodeAddress(bad_address); 125 Address brk_address; 126 if (!target.ResolveLoadAddress(fixed_bad_address, brk_address)) 127 return false; 128 129 auto brk_ptrauth_info = 130 GetPtrauthInstructionInfo(target, arch, current_address); 131 if (brk_ptrauth_info && brk_ptrauth_info->IsAuthenticated) { 132 emit_ptrauth_prologue(bad_address); 133 strm.Printf("Found value that failed to authenticate "); 134 DescribeAddressBriefly(strm, brk_address, target); 135 m_description = std::string(strm.GetString()); 136 return true; 137 } 138 return false; 139 } 140 141 assert(IsBadAccess && "Handle EXC_BAD_ACCESS only after this point"); 142 143 // Check that we have the "bad address" from an EXC_BAD_ACCESS. 144 if (m_exc_data_count < 2) 145 return false; 146 147 // Ok, we know the Target is valid and that it describes a ptrauth-enabled 148 // device. Now, we need to determine whether this exception was caused by a 149 // ptrauth failure. 150 151 uint64_t bad_address = m_exc_subcode; 152 uint64_t fixed_bad_address = abi_sp->FixCodeAddress(bad_address); 153 uint64_t current_pc = current_address.GetLoadAddress(&target); 154 155 // Detect: LDRAA, LDRAB (Load Register, with pointer authentication). 156 // 157 // If an authenticated load results in an exception, the instruction at the 158 // current PC should be one of LDRAx. 159 if (bad_address != current_pc && fixed_bad_address != current_pc) { 160 auto ptrauth_info = 161 GetPtrauthInstructionInfo(target, arch, current_address); 162 if (ptrauth_info && ptrauth_info->IsAuthenticated && ptrauth_info->IsLoad) { 163 emit_ptrauth_prologue(bad_address); 164 strm.Printf("Found authenticated load instruction "); 165 DescribeAddressBriefly(strm, current_address, target); 166 m_description = std::string(strm.GetString()); 167 return true; 168 } 169 } 170 171 // Detect: BLRAA, BLRAAZ, BLRAB, BLRABZ (Branch with Link to Register, with 172 // pointer authentication). 173 // 174 // TODO: Detect: BRAA, BRAAZ, BRAB, BRABZ (Branch to Register, with pointer 175 // authentication). At a minimum, this requires call site info support for 176 // indirect calls. 177 // 178 // If an authenticated call or tail call results in an exception, stripping 179 // the bad address should give the current PC, which points to the address 180 // we tried to branch to. 181 if (bad_address != current_pc && fixed_bad_address == current_pc) { 182 if (StackFrameSP parent_frame = thread.GetStackFrameAtIndex(1)) { 183 addr_t return_pc = 184 parent_frame->GetFrameCodeAddress().GetLoadAddress(&target); 185 Address blr_address; 186 if (!target.ResolveLoadAddress(return_pc - 4, blr_address)) 187 return false; 188 189 auto blr_ptrauth_info = 190 GetPtrauthInstructionInfo(target, arch, blr_address); 191 if (blr_ptrauth_info && blr_ptrauth_info->IsAuthenticated && 192 blr_ptrauth_info->DoesBranch) { 193 emit_ptrauth_prologue(bad_address); 194 strm.Printf("Found authenticated indirect branch "); 195 DescribeAddressBriefly(strm, blr_address, target); 196 m_description = std::string(strm.GetString()); 197 return true; 198 } 199 } 200 } 201 202 // TODO: Detect: RETAA, RETAB (Return from subroutine, with pointer 203 // authentication). 204 // 205 // Is there a motivating, non-malicious code snippet that corrupts LR? 206 207 return false; 208 } 209 210 const char *StopInfoMachException::GetDescription() { 211 if (!m_description.empty()) 212 return m_description.c_str(); 213 if (GetValue() == eStopReasonInvalid) 214 return "invalid stop reason!"; 215 216 ExecutionContext exe_ctx(m_thread_wp.lock()); 217 Target *target = exe_ctx.GetTargetPtr(); 218 const llvm::Triple::ArchType cpu = 219 target ? target->GetArchitecture().GetMachine() 220 : llvm::Triple::UnknownArch; 221 222 const char *exc_desc = nullptr; 223 const char *code_label = "code"; 224 const char *code_desc = nullptr; 225 const char *subcode_label = "subcode"; 226 const char *subcode_desc = nullptr; 227 228 #if defined(__APPLE__) 229 char code_desc_buf[32]; 230 char subcode_desc_buf[32]; 231 #endif 232 233 switch (m_value) { 234 case 1: // EXC_BAD_ACCESS 235 exc_desc = "EXC_BAD_ACCESS"; 236 subcode_label = "address"; 237 switch (cpu) { 238 case llvm::Triple::x86: 239 case llvm::Triple::x86_64: 240 switch (m_exc_code) { 241 case 0xd: 242 code_desc = "EXC_I386_GPFLT"; 243 m_exc_data_count = 1; 244 break; 245 } 246 break; 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 } 257 break; 258 259 case llvm::Triple::aarch64: 260 if (DeterminePtrauthFailure(exe_ctx)) 261 return m_description.c_str(); 262 break; 263 264 default: 265 break; 266 } 267 break; 268 269 case 2: // EXC_BAD_INSTRUCTION 270 exc_desc = "EXC_BAD_INSTRUCTION"; 271 switch (cpu) { 272 case llvm::Triple::x86: 273 case llvm::Triple::x86_64: 274 if (m_exc_code == 1) 275 code_desc = "EXC_I386_INVOP"; 276 break; 277 278 case llvm::Triple::arm: 279 case llvm::Triple::thumb: 280 if (m_exc_code == 1) 281 code_desc = "EXC_ARM_UNDEFINED"; 282 break; 283 284 default: 285 break; 286 } 287 break; 288 289 case 3: // EXC_ARITHMETIC 290 exc_desc = "EXC_ARITHMETIC"; 291 switch (cpu) { 292 case llvm::Triple::x86: 293 case llvm::Triple::x86_64: 294 switch (m_exc_code) { 295 case 1: 296 code_desc = "EXC_I386_DIV"; 297 break; 298 case 2: 299 code_desc = "EXC_I386_INTO"; 300 break; 301 case 3: 302 code_desc = "EXC_I386_NOEXT"; 303 break; 304 case 4: 305 code_desc = "EXC_I386_EXTOVR"; 306 break; 307 case 5: 308 code_desc = "EXC_I386_EXTERR"; 309 break; 310 case 6: 311 code_desc = "EXC_I386_EMERR"; 312 break; 313 case 7: 314 code_desc = "EXC_I386_BOUND"; 315 break; 316 case 8: 317 code_desc = "EXC_I386_SSEEXTERR"; 318 break; 319 } 320 break; 321 322 default: 323 break; 324 } 325 break; 326 327 case 4: // EXC_EMULATION 328 exc_desc = "EXC_EMULATION"; 329 break; 330 331 case 5: // EXC_SOFTWARE 332 exc_desc = "EXC_SOFTWARE"; 333 if (m_exc_code == 0x10003) { 334 subcode_desc = "EXC_SOFT_SIGNAL"; 335 subcode_label = "signo"; 336 } 337 break; 338 339 case 6: // EXC_BREAKPOINT 340 { 341 exc_desc = "EXC_BREAKPOINT"; 342 switch (cpu) { 343 case llvm::Triple::x86: 344 case llvm::Triple::x86_64: 345 switch (m_exc_code) { 346 case 1: 347 code_desc = "EXC_I386_SGL"; 348 break; 349 case 2: 350 code_desc = "EXC_I386_BPT"; 351 break; 352 } 353 break; 354 355 case llvm::Triple::arm: 356 case llvm::Triple::thumb: 357 switch (m_exc_code) { 358 case 0x101: 359 code_desc = "EXC_ARM_DA_ALIGN"; 360 break; 361 case 0x102: 362 code_desc = "EXC_ARM_DA_DEBUG"; 363 break; 364 case 1: 365 code_desc = "EXC_ARM_BREAKPOINT"; 366 break; 367 // FIXME temporary workaround, exc_code 0 does not really mean 368 // EXC_ARM_BREAKPOINT 369 case 0: 370 code_desc = "EXC_ARM_BREAKPOINT"; 371 break; 372 } 373 break; 374 375 case llvm::Triple::aarch64: 376 if (DeterminePtrauthFailure(exe_ctx)) 377 return m_description.c_str(); 378 break; 379 380 default: 381 break; 382 } 383 } break; 384 385 case 7: 386 exc_desc = "EXC_SYSCALL"; 387 break; 388 389 case 8: 390 exc_desc = "EXC_MACH_SYSCALL"; 391 break; 392 393 case 9: 394 exc_desc = "EXC_RPC_ALERT"; 395 break; 396 397 case 10: 398 exc_desc = "EXC_CRASH"; 399 break; 400 case 11: 401 exc_desc = "EXC_RESOURCE"; 402 #if defined(__APPLE__) 403 { 404 int resource_type = EXC_RESOURCE_DECODE_RESOURCE_TYPE(m_exc_code); 405 406 code_label = "limit"; 407 code_desc = code_desc_buf; 408 subcode_label = "observed"; 409 subcode_desc = subcode_desc_buf; 410 411 switch (resource_type) { 412 case RESOURCE_TYPE_CPU: 413 exc_desc = "EXC_RESOURCE RESOURCE_TYPE_CPU"; 414 snprintf(code_desc_buf, sizeof(code_desc_buf), "%d%%", 415 (int)EXC_RESOURCE_CPUMONITOR_DECODE_PERCENTAGE(m_exc_code)); 416 snprintf(subcode_desc_buf, sizeof(subcode_desc_buf), "%d%%", 417 (int)EXC_RESOURCE_CPUMONITOR_DECODE_PERCENTAGE_OBSERVED( 418 m_exc_subcode)); 419 break; 420 case RESOURCE_TYPE_WAKEUPS: 421 exc_desc = "EXC_RESOURCE RESOURCE_TYPE_WAKEUPS"; 422 snprintf( 423 code_desc_buf, sizeof(code_desc_buf), "%d w/s", 424 (int)EXC_RESOURCE_CPUMONITOR_DECODE_WAKEUPS_PERMITTED(m_exc_code)); 425 snprintf(subcode_desc_buf, sizeof(subcode_desc_buf), "%d w/s", 426 (int)EXC_RESOURCE_CPUMONITOR_DECODE_WAKEUPS_OBSERVED( 427 m_exc_subcode)); 428 break; 429 case RESOURCE_TYPE_MEMORY: 430 exc_desc = "EXC_RESOURCE RESOURCE_TYPE_MEMORY"; 431 snprintf(code_desc_buf, sizeof(code_desc_buf), "%d MB", 432 (int)EXC_RESOURCE_HWM_DECODE_LIMIT(m_exc_code)); 433 subcode_desc = nullptr; 434 subcode_label = "unused"; 435 break; 436 #if defined(RESOURCE_TYPE_IO) 437 // RESOURCE_TYPE_IO is introduced in macOS SDK 10.12. 438 case RESOURCE_TYPE_IO: 439 exc_desc = "EXC_RESOURCE RESOURCE_TYPE_IO"; 440 snprintf(code_desc_buf, sizeof(code_desc_buf), "%d MB", 441 (int)EXC_RESOURCE_IO_DECODE_LIMIT(m_exc_code)); 442 snprintf(subcode_desc_buf, sizeof(subcode_desc_buf), "%d MB", 443 (int)EXC_RESOURCE_IO_OBSERVED(m_exc_subcode)); 444 ; 445 break; 446 #endif 447 } 448 } 449 #endif 450 break; 451 case 12: 452 exc_desc = "EXC_GUARD"; 453 break; 454 } 455 456 StreamString strm; 457 458 if (exc_desc) 459 strm.PutCString(exc_desc); 460 else 461 strm.Printf("EXC_??? (%" PRIu64 ")", m_value); 462 463 if (m_exc_data_count >= 1) { 464 if (code_desc) 465 strm.Printf(" (%s=%s", code_label, code_desc); 466 else 467 strm.Printf(" (%s=%" PRIu64, code_label, m_exc_code); 468 } 469 470 if (m_exc_data_count >= 2) { 471 if (subcode_desc) 472 strm.Printf(", %s=%s", subcode_label, subcode_desc); 473 else 474 strm.Printf(", %s=0x%" PRIx64, subcode_label, m_exc_subcode); 475 } 476 477 if (m_exc_data_count > 0) 478 strm.PutChar(')'); 479 480 m_description = std::string(strm.GetString()); 481 return m_description.c_str(); 482 } 483 484 static StopInfoSP GetStopInfoForHardwareBP(Thread &thread, Target *target, 485 uint32_t exc_data_count, 486 uint64_t exc_sub_code, 487 uint64_t exc_sub_sub_code) { 488 // Try hardware watchpoint. 489 if (target) { 490 // The exc_sub_code indicates the data break address. 491 lldb::WatchpointSP wp_sp = 492 target->GetWatchpointList().FindByAddress((lldb::addr_t)exc_sub_code); 493 if (wp_sp && wp_sp->IsEnabled()) { 494 // Debugserver may piggyback the hardware index of the fired watchpoint 495 // in the exception data. Set the hardware index if that's the case. 496 if (exc_data_count >= 3) 497 wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code); 498 return StopInfo::CreateStopReasonWithWatchpointID(thread, wp_sp->GetID()); 499 } 500 } 501 502 // Try hardware breakpoint. 503 ProcessSP process_sp(thread.GetProcess()); 504 if (process_sp) { 505 // The exc_sub_code indicates the data break address. 506 lldb::BreakpointSiteSP bp_sp = 507 process_sp->GetBreakpointSiteList().FindByAddress( 508 (lldb::addr_t)exc_sub_code); 509 if (bp_sp && bp_sp->IsEnabled()) { 510 // Debugserver may piggyback the hardware index of the fired breakpoint 511 // in the exception data. Set the hardware index if that's the case. 512 if (exc_data_count >= 3) 513 bp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code); 514 return StopInfo::CreateStopReasonWithBreakpointSiteID(thread, 515 bp_sp->GetID()); 516 } 517 } 518 519 return nullptr; 520 } 521 522 StopInfoSP StopInfoMachException::CreateStopReasonWithMachException( 523 Thread &thread, uint32_t exc_type, uint32_t exc_data_count, 524 uint64_t exc_code, uint64_t exc_sub_code, uint64_t exc_sub_sub_code, 525 bool pc_already_adjusted, bool adjust_pc_if_needed) { 526 if (exc_type == 0) 527 return StopInfoSP(); 528 529 uint32_t pc_decrement = 0; 530 ExecutionContext exe_ctx(thread.shared_from_this()); 531 Target *target = exe_ctx.GetTargetPtr(); 532 const llvm::Triple::ArchType cpu = 533 target ? target->GetArchitecture().GetMachine() 534 : llvm::Triple::UnknownArch; 535 536 switch (exc_type) { 537 case 1: // EXC_BAD_ACCESS 538 case 2: // EXC_BAD_INSTRUCTION 539 case 3: // EXC_ARITHMETIC 540 case 4: // EXC_EMULATION 541 break; 542 543 case 5: // EXC_SOFTWARE 544 if (exc_code == 0x10003) // EXC_SOFT_SIGNAL 545 { 546 if (exc_sub_code == 5) { 547 // On MacOSX, a SIGTRAP can signify that a process has called exec, 548 // so we should check with our dynamic loader to verify. 549 ProcessSP process_sp(thread.GetProcess()); 550 if (process_sp) { 551 DynamicLoader *dynamic_loader = process_sp->GetDynamicLoader(); 552 if (dynamic_loader && dynamic_loader->ProcessDidExec()) { 553 // The program was re-exec'ed 554 return StopInfo::CreateStopReasonWithExec(thread); 555 } 556 } 557 } 558 return StopInfo::CreateStopReasonWithSignal(thread, exc_sub_code); 559 } 560 break; 561 562 case 6: // EXC_BREAKPOINT 563 { 564 bool is_actual_breakpoint = false; 565 bool is_trace_if_actual_breakpoint_missing = false; 566 switch (cpu) { 567 case llvm::Triple::x86: 568 case llvm::Triple::x86_64: 569 if (exc_code == 1) // EXC_I386_SGL 570 { 571 if (!exc_sub_code) { 572 // This looks like a plain trap. 573 // Have to check if there is a breakpoint here as well. When you 574 // single-step onto a trap, the single step stops you not to trap. 575 // Since we also do that check below, let's just use that logic. 576 is_actual_breakpoint = true; 577 is_trace_if_actual_breakpoint_missing = true; 578 } else { 579 if (StopInfoSP stop_info = 580 GetStopInfoForHardwareBP(thread, target, exc_data_count, 581 exc_sub_code, exc_sub_sub_code)) 582 return stop_info; 583 } 584 } else if (exc_code == 2 || // EXC_I386_BPT 585 exc_code == 3) // EXC_I386_BPTFLT 586 { 587 // KDP returns EXC_I386_BPTFLT for trace breakpoints 588 if (exc_code == 3) 589 is_trace_if_actual_breakpoint_missing = true; 590 591 is_actual_breakpoint = true; 592 if (!pc_already_adjusted) 593 pc_decrement = 1; 594 } 595 break; 596 597 case llvm::Triple::arm: 598 case llvm::Triple::thumb: 599 if (exc_code == 0x102) // EXC_ARM_DA_DEBUG 600 { 601 // It's a watchpoint, then, if the exc_sub_code indicates a 602 // known/enabled data break address from our watchpoint list. 603 lldb::WatchpointSP wp_sp; 604 if (target) 605 wp_sp = target->GetWatchpointList().FindByAddress( 606 (lldb::addr_t)exc_sub_code); 607 if (wp_sp && wp_sp->IsEnabled()) { 608 // Debugserver may piggyback the hardware index of the fired 609 // watchpoint in the exception data. Set the hardware index if 610 // that's the case. 611 if (exc_data_count >= 3) 612 wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code); 613 return StopInfo::CreateStopReasonWithWatchpointID(thread, 614 wp_sp->GetID()); 615 } else { 616 is_actual_breakpoint = true; 617 is_trace_if_actual_breakpoint_missing = true; 618 } 619 } else if (exc_code == 1) // EXC_ARM_BREAKPOINT 620 { 621 is_actual_breakpoint = true; 622 is_trace_if_actual_breakpoint_missing = true; 623 } else if (exc_code == 0) // FIXME not EXC_ARM_BREAKPOINT but a kernel 624 // is currently returning this so accept it 625 // as indicating a breakpoint until the 626 // kernel is fixed 627 { 628 is_actual_breakpoint = true; 629 is_trace_if_actual_breakpoint_missing = true; 630 } 631 break; 632 633 case llvm::Triple::aarch64_32: 634 case llvm::Triple::aarch64: { 635 if (exc_code == 1 && exc_sub_code == 0) // EXC_ARM_BREAKPOINT 636 { 637 // This is hit when we single instruction step aka MDSCR_EL1 SS bit 0 638 // is set 639 is_actual_breakpoint = false; 640 is_trace_if_actual_breakpoint_missing = true; 641 } 642 if (exc_code == 0x102) // EXC_ARM_DA_DEBUG 643 { 644 // It's a watchpoint, then, if the exc_sub_code indicates a 645 // known/enabled data break address from our watchpoint list. 646 lldb::WatchpointSP wp_sp; 647 if (target) 648 wp_sp = target->GetWatchpointList().FindByAddress( 649 (lldb::addr_t)exc_sub_code); 650 if (wp_sp && wp_sp->IsEnabled()) { 651 // Debugserver may piggyback the hardware index of the fired 652 // watchpoint in the exception data. Set the hardware index if 653 // that's the case. 654 if (exc_data_count >= 3) 655 wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code); 656 return StopInfo::CreateStopReasonWithWatchpointID(thread, 657 wp_sp->GetID()); 658 } 659 // EXC_ARM_DA_DEBUG seems to be reused for EXC_BREAKPOINT as well as 660 // EXC_BAD_ACCESS 661 if (thread.GetTemporaryResumeState() == eStateStepping) 662 return StopInfo::CreateStopReasonToTrace(thread); 663 } 664 // It looks like exc_sub_code has the 4 bytes of the instruction that 665 // triggered the exception, i.e. our breakpoint opcode 666 is_actual_breakpoint = exc_code == 1; 667 break; 668 } 669 670 default: 671 break; 672 } 673 674 if (is_actual_breakpoint) { 675 RegisterContextSP reg_ctx_sp(thread.GetRegisterContext()); 676 addr_t pc = reg_ctx_sp->GetPC() - pc_decrement; 677 678 ProcessSP process_sp(thread.CalculateProcess()); 679 680 lldb::BreakpointSiteSP bp_site_sp; 681 if (process_sp) 682 bp_site_sp = process_sp->GetBreakpointSiteList().FindByAddress(pc); 683 if (bp_site_sp && bp_site_sp->IsEnabled()) { 684 // Update the PC if we were asked to do so, but only do so if we find 685 // a breakpoint that we know about cause this could be a trap 686 // instruction in the code 687 if (pc_decrement > 0 && adjust_pc_if_needed) 688 reg_ctx_sp->SetPC(pc); 689 690 // If the breakpoint is for this thread, then we'll report the hit, 691 // but if it is for another thread, we can just report no reason. We 692 // don't need to worry about stepping over the breakpoint here, that 693 // will be taken care of when the thread resumes and notices that 694 // there's a breakpoint under the pc. If we have an operating system 695 // plug-in, we might have set a thread specific breakpoint using the 696 // operating system thread ID, so we can't make any assumptions about 697 // the thread ID so we must always report the breakpoint regardless 698 // of the thread. 699 if (bp_site_sp->ValidForThisThread(thread) || 700 thread.GetProcess()->GetOperatingSystem() != nullptr) 701 return StopInfo::CreateStopReasonWithBreakpointSiteID( 702 thread, bp_site_sp->GetID()); 703 else if (is_trace_if_actual_breakpoint_missing) 704 return StopInfo::CreateStopReasonToTrace(thread); 705 else 706 return StopInfoSP(); 707 } 708 709 // Don't call this a trace if we weren't single stepping this thread. 710 if (is_trace_if_actual_breakpoint_missing && 711 thread.GetTemporaryResumeState() == eStateStepping) { 712 return StopInfo::CreateStopReasonToTrace(thread); 713 } 714 } 715 } break; 716 717 case 7: // EXC_SYSCALL 718 case 8: // EXC_MACH_SYSCALL 719 case 9: // EXC_RPC_ALERT 720 case 10: // EXC_CRASH 721 break; 722 } 723 724 return StopInfoSP(new StopInfoMachException(thread, exc_type, exc_data_count, 725 exc_code, exc_sub_code)); 726 } 727