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