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 32using namespace lldb; 33using namespace lldb_private; 34 35/// Information about a pointer-authentication related instruction. 36struct 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. 44static std::optional<PtrauthInstructionInfo> 45GetPtrauthInstructionInfo(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. 66static 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 75bool 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 211const 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 488static 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 // LWP_TODO: We need to find the WatchpointResource that matches 495 // the address, and evaluate its Watchpoints. 496 497 // The exc_sub_code indicates the data break address. 498 lldb::WatchpointSP wp_sp = 499 target->GetWatchpointList().FindByAddress((lldb::addr_t)exc_sub_code); 500 if (wp_sp && wp_sp->IsEnabled()) { 501 return StopInfo::CreateStopReasonWithWatchpointID(thread, wp_sp->GetID()); 502 } 503 } 504 505 // Try hardware breakpoint. 506 ProcessSP process_sp(thread.GetProcess()); 507 if (process_sp) { 508 // The exc_sub_code indicates the data break address. 509 lldb::BreakpointSiteSP bp_sp = 510 process_sp->GetBreakpointSiteList().FindByAddress( 511 (lldb::addr_t)exc_sub_code); 512 if (bp_sp && bp_sp->IsEnabled()) { 513 return StopInfo::CreateStopReasonWithBreakpointSiteID(thread, 514 bp_sp->GetID()); 515 } 516 } 517 518 return nullptr; 519} 520 521#if defined(__APPLE__) 522const char * 523StopInfoMachException::MachException::Name(exception_type_t exc_type) { 524 switch (exc_type) { 525 case EXC_BAD_ACCESS: 526 return "EXC_BAD_ACCESS"; 527 case EXC_BAD_INSTRUCTION: 528 return "EXC_BAD_INSTRUCTION"; 529 case EXC_ARITHMETIC: 530 return "EXC_ARITHMETIC"; 531 case EXC_EMULATION: 532 return "EXC_EMULATION"; 533 case EXC_SOFTWARE: 534 return "EXC_SOFTWARE"; 535 case EXC_BREAKPOINT: 536 return "EXC_BREAKPOINT"; 537 case EXC_SYSCALL: 538 return "EXC_SYSCALL"; 539 case EXC_MACH_SYSCALL: 540 return "EXC_MACH_SYSCALL"; 541 case EXC_RPC_ALERT: 542 return "EXC_RPC_ALERT"; 543#ifdef EXC_CRASH 544 case EXC_CRASH: 545 return "EXC_CRASH"; 546#endif 547 case EXC_RESOURCE: 548 return "EXC_RESOURCE"; 549#ifdef EXC_GUARD 550 case EXC_GUARD: 551 return "EXC_GUARD"; 552#endif 553#ifdef EXC_CORPSE_NOTIFY 554 case EXC_CORPSE_NOTIFY: 555 return "EXC_CORPSE_NOTIFY"; 556#endif 557#ifdef EXC_CORPSE_VARIANT_BIT 558 case EXC_CORPSE_VARIANT_BIT: 559 return "EXC_CORPSE_VARIANT_BIT"; 560#endif 561 default: 562 break; 563 } 564 return NULL; 565} 566 567std::optional<exception_type_t> 568StopInfoMachException::MachException::ExceptionCode(const char *name) { 569 return llvm::StringSwitch<std::optional<exception_type_t>>(name) 570 .Case("EXC_BAD_ACCESS", EXC_BAD_ACCESS) 571 .Case("EXC_BAD_INSTRUCTION", EXC_BAD_INSTRUCTION) 572 .Case("EXC_ARITHMETIC", EXC_ARITHMETIC) 573 .Case("EXC_EMULATION", EXC_EMULATION) 574 .Case("EXC_SOFTWARE", EXC_SOFTWARE) 575 .Case("EXC_BREAKPOINT", EXC_BREAKPOINT) 576 .Case("EXC_SYSCALL", EXC_SYSCALL) 577 .Case("EXC_MACH_SYSCALL", EXC_MACH_SYSCALL) 578 .Case("EXC_RPC_ALERT", EXC_RPC_ALERT) 579#ifdef EXC_CRASH 580 .Case("EXC_CRASH", EXC_CRASH) 581#endif 582 .Case("EXC_RESOURCE", EXC_RESOURCE) 583#ifdef EXC_GUARD 584 .Case("EXC_GUARD", EXC_GUARD) 585#endif 586#ifdef EXC_CORPSE_NOTIFY 587 .Case("EXC_CORPSE_NOTIFY", EXC_CORPSE_NOTIFY) 588#endif 589 .Default(std::nullopt); 590} 591#endif 592 593StopInfoSP StopInfoMachException::CreateStopReasonWithMachException( 594 Thread &thread, uint32_t exc_type, uint32_t exc_data_count, 595 uint64_t exc_code, uint64_t exc_sub_code, uint64_t exc_sub_sub_code, 596 bool pc_already_adjusted, bool adjust_pc_if_needed) { 597 if (exc_type == 0) 598 return StopInfoSP(); 599 600 uint32_t pc_decrement = 0; 601 ExecutionContext exe_ctx(thread.shared_from_this()); 602 Target *target = exe_ctx.GetTargetPtr(); 603 const llvm::Triple::ArchType cpu = 604 target ? target->GetArchitecture().GetMachine() 605 : llvm::Triple::UnknownArch; 606 607 switch (exc_type) { 608 case 1: // EXC_BAD_ACCESS 609 case 2: // EXC_BAD_INSTRUCTION 610 case 3: // EXC_ARITHMETIC 611 case 4: // EXC_EMULATION 612 break; 613 614 case 5: // EXC_SOFTWARE 615 if (exc_code == 0x10003) // EXC_SOFT_SIGNAL 616 { 617 if (exc_sub_code == 5) { 618 // On MacOSX, a SIGTRAP can signify that a process has called exec, 619 // so we should check with our dynamic loader to verify. 620 ProcessSP process_sp(thread.GetProcess()); 621 if (process_sp) { 622 DynamicLoader *dynamic_loader = process_sp->GetDynamicLoader(); 623 if (dynamic_loader && dynamic_loader->ProcessDidExec()) { 624 // The program was re-exec'ed 625 return StopInfo::CreateStopReasonWithExec(thread); 626 } 627 } 628 } 629 return StopInfo::CreateStopReasonWithSignal(thread, exc_sub_code); 630 } 631 break; 632 633 case 6: // EXC_BREAKPOINT 634 { 635 bool is_actual_breakpoint = false; 636 bool is_trace_if_actual_breakpoint_missing = false; 637 switch (cpu) { 638 case llvm::Triple::x86: 639 case llvm::Triple::x86_64: 640 if (exc_code == 1) // EXC_I386_SGL 641 { 642 if (!exc_sub_code) { 643 // This looks like a plain trap. 644 // Have to check if there is a breakpoint here as well. When you 645 // single-step onto a trap, the single step stops you not to trap. 646 // Since we also do that check below, let's just use that logic. 647 is_actual_breakpoint = true; 648 is_trace_if_actual_breakpoint_missing = true; 649 } else { 650 if (StopInfoSP stop_info = 651 GetStopInfoForHardwareBP(thread, target, exc_data_count, 652 exc_sub_code, exc_sub_sub_code)) 653 return stop_info; 654 } 655 } else if (exc_code == 2 || // EXC_I386_BPT 656 exc_code == 3) // EXC_I386_BPTFLT 657 { 658 // KDP returns EXC_I386_BPTFLT for trace breakpoints 659 if (exc_code == 3) 660 is_trace_if_actual_breakpoint_missing = true; 661 662 is_actual_breakpoint = true; 663 if (!pc_already_adjusted) 664 pc_decrement = 1; 665 } 666 break; 667 668 case llvm::Triple::arm: 669 case llvm::Triple::thumb: 670 if (exc_code == 0x102) // EXC_ARM_DA_DEBUG 671 { 672 // LWP_TODO: We need to find the WatchpointResource that matches 673 // the address, and evaluate its Watchpoints. 674 675 // It's a watchpoint, then, if the exc_sub_code indicates a 676 // known/enabled data break address from our watchpoint list. 677 lldb::WatchpointSP wp_sp; 678 if (target) 679 wp_sp = target->GetWatchpointList().FindByAddress( 680 (lldb::addr_t)exc_sub_code); 681 if (wp_sp && wp_sp->IsEnabled()) { 682 return StopInfo::CreateStopReasonWithWatchpointID(thread, 683 wp_sp->GetID()); 684 } else { 685 is_actual_breakpoint = true; 686 is_trace_if_actual_breakpoint_missing = true; 687 } 688 } else if (exc_code == 1) // EXC_ARM_BREAKPOINT 689 { 690 is_actual_breakpoint = true; 691 is_trace_if_actual_breakpoint_missing = true; 692 } else if (exc_code == 0) // FIXME not EXC_ARM_BREAKPOINT but a kernel 693 // is currently returning this so accept it 694 // as indicating a breakpoint until the 695 // kernel is fixed 696 { 697 is_actual_breakpoint = true; 698 is_trace_if_actual_breakpoint_missing = true; 699 } 700 break; 701 702 case llvm::Triple::aarch64_32: 703 case llvm::Triple::aarch64: { 704 // xnu describes three things with type EXC_BREAKPOINT: 705 // 706 // exc_code 0x102 [EXC_ARM_DA_DEBUG], exc_sub_code addr-of-insn 707 // Watchpoint access. exc_sub_code is the address of the 708 // instruction which trigged the watchpoint trap. 709 // debugserver may add the watchpoint number that was triggered 710 // in exc_sub_sub_code. 711 // 712 // exc_code 1 [EXC_ARM_BREAKPOINT], exc_sub_code 0 713 // Instruction step has completed. 714 // 715 // exc_code 1 [EXC_ARM_BREAKPOINT], exc_sub_code address-of-instruction 716 // Software breakpoint instruction executed. 717 718 if (exc_code == 1 && exc_sub_code == 0) // EXC_ARM_BREAKPOINT 719 { 720 // This is hit when we single instruction step aka MDSCR_EL1 SS bit 0 721 // is set 722 is_actual_breakpoint = true; 723 is_trace_if_actual_breakpoint_missing = true; 724#ifndef NDEBUG 725 if (thread.GetTemporaryResumeState() != eStateStepping) { 726 StreamString s; 727 s.Printf("CreateStopReasonWithMachException got EXC_BREAKPOINT [1,0] " 728 "indicating trace event, but thread is not tracing, it has " 729 "ResumeState %d", 730 thread.GetTemporaryResumeState()); 731 if (RegisterContextSP regctx = thread.GetRegisterContext()) { 732 if (const RegisterInfo *ri = regctx->GetRegisterInfoByName("esr")) { 733 uint32_t esr = 734 (uint32_t)regctx->ReadRegisterAsUnsigned(ri, UINT32_MAX); 735 if (esr != UINT32_MAX) { 736 s.Printf(" esr value: 0x%" PRIx32, esr); 737 } 738 } 739 } 740 thread.GetProcess()->DumpPluginHistory(s); 741 llvm::report_fatal_error(s.GetData()); 742 lldbassert( 743 false && 744 "CreateStopReasonWithMachException got EXC_BREAKPOINT [1,0] " 745 "indicating trace event, but thread was not doing a step."); 746 } 747#endif 748 } 749 if (exc_code == 0x102) // EXC_ARM_DA_DEBUG 750 { 751 // LWP_TODO: We need to find the WatchpointResource that matches 752 // the address, and evaluate its Watchpoints. 753 754 // It's a watchpoint, then, if the exc_sub_code indicates a 755 // known/enabled data break address from our watchpoint list. 756 lldb::WatchpointSP wp_sp; 757 if (target) 758 wp_sp = target->GetWatchpointList().FindByAddress( 759 (lldb::addr_t)exc_sub_code); 760 if (wp_sp && wp_sp->IsEnabled()) { 761 return StopInfo::CreateStopReasonWithWatchpointID(thread, 762 wp_sp->GetID()); 763 } 764 // EXC_ARM_DA_DEBUG seems to be reused for EXC_BREAKPOINT as well as 765 // EXC_BAD_ACCESS 766 if (thread.GetTemporaryResumeState() == eStateStepping) 767 return StopInfo::CreateStopReasonToTrace(thread); 768 } 769 // It looks like exc_sub_code has the 4 bytes of the instruction that 770 // triggered the exception, i.e. our breakpoint opcode 771 is_actual_breakpoint = exc_code == 1; 772 break; 773 } 774 775 default: 776 break; 777 } 778 779 if (is_actual_breakpoint) { 780 RegisterContextSP reg_ctx_sp(thread.GetRegisterContext()); 781 addr_t pc = reg_ctx_sp->GetPC() - pc_decrement; 782 783 ProcessSP process_sp(thread.CalculateProcess()); 784 785 lldb::BreakpointSiteSP bp_site_sp; 786 if (process_sp) 787 bp_site_sp = process_sp->GetBreakpointSiteList().FindByAddress(pc); 788 if (bp_site_sp && bp_site_sp->IsEnabled()) { 789 // Update the PC if we were asked to do so, but only do so if we find 790 // a breakpoint that we know about cause this could be a trap 791 // instruction in the code 792 if (pc_decrement > 0 && adjust_pc_if_needed) 793 reg_ctx_sp->SetPC(pc); 794 795 // If the breakpoint is for this thread, then we'll report the hit, 796 // but if it is for another thread, we can just report no reason. We 797 // don't need to worry about stepping over the breakpoint here, that 798 // will be taken care of when the thread resumes and notices that 799 // there's a breakpoint under the pc. If we have an operating system 800 // plug-in, we might have set a thread specific breakpoint using the 801 // operating system thread ID, so we can't make any assumptions about 802 // the thread ID so we must always report the breakpoint regardless 803 // of the thread. 804 if (bp_site_sp->ValidForThisThread(thread) || 805 thread.GetProcess()->GetOperatingSystem() != nullptr) 806 return StopInfo::CreateStopReasonWithBreakpointSiteID( 807 thread, bp_site_sp->GetID()); 808 else if (is_trace_if_actual_breakpoint_missing) 809 return StopInfo::CreateStopReasonToTrace(thread); 810 else 811 return StopInfoSP(); 812 } 813 814 // Don't call this a trace if we weren't single stepping this thread. 815 if (is_trace_if_actual_breakpoint_missing && 816 thread.GetTemporaryResumeState() == eStateStepping) { 817 return StopInfo::CreateStopReasonToTrace(thread); 818 } 819 } 820 } break; 821 822 case 7: // EXC_SYSCALL 823 case 8: // EXC_MACH_SYSCALL 824 case 9: // EXC_RPC_ALERT 825 case 10: // EXC_CRASH 826 break; 827 } 828 829 return StopInfoSP(new StopInfoMachException(thread, exc_type, exc_data_count, 830 exc_code, exc_sub_code)); 831} 832