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