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