1 //===-- StopInfoMachException.cpp -------------------------------*- C++ -*-===// 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 12 #if defined(__APPLE__) 13 // Needed for the EXC_RESOURCE interpretation macros 14 #include <kern/exc_resource.h> 15 #endif 16 17 #include "lldb/Breakpoint/Watchpoint.h" 18 #include "lldb/Symbol/Symbol.h" 19 #include "lldb/Target/DynamicLoader.h" 20 #include "lldb/Target/ExecutionContext.h" 21 #include "lldb/Target/Process.h" 22 #include "lldb/Target/RegisterContext.h" 23 #include "lldb/Target/Target.h" 24 #include "lldb/Target/Thread.h" 25 #include "lldb/Target/ThreadPlan.h" 26 #include "lldb/Target/UnixSignals.h" 27 #include "lldb/Utility/StreamString.h" 28 29 using namespace lldb; 30 using namespace lldb_private; 31 32 const char *StopInfoMachException::GetDescription() { 33 if (!m_description.empty()) 34 return m_description.c_str(); 35 if (GetValue() == eStopReasonInvalid) 36 return "invalid stop reason!"; 37 38 ExecutionContext exe_ctx(m_thread_wp.lock()); 39 Target *target = exe_ctx.GetTargetPtr(); 40 const llvm::Triple::ArchType cpu = 41 target ? target->GetArchitecture().GetMachine() 42 : llvm::Triple::UnknownArch; 43 44 const char *exc_desc = nullptr; 45 const char *code_label = "code"; 46 const char *code_desc = nullptr; 47 const char *subcode_label = "subcode"; 48 const char *subcode_desc = nullptr; 49 50 #if defined(__APPLE__) 51 char code_desc_buf[32]; 52 char subcode_desc_buf[32]; 53 #endif 54 55 switch (m_value) { 56 case 1: // EXC_BAD_ACCESS 57 exc_desc = "EXC_BAD_ACCESS"; 58 subcode_label = "address"; 59 switch (cpu) { 60 case llvm::Triple::x86: 61 case llvm::Triple::x86_64: 62 switch (m_exc_code) { 63 case 0xd: 64 code_desc = "EXC_I386_GPFLT"; 65 m_exc_data_count = 1; 66 break; 67 } 68 break; 69 case llvm::Triple::arm: 70 case llvm::Triple::thumb: 71 switch (m_exc_code) { 72 case 0x101: 73 code_desc = "EXC_ARM_DA_ALIGN"; 74 break; 75 case 0x102: 76 code_desc = "EXC_ARM_DA_DEBUG"; 77 break; 78 } 79 break; 80 81 case llvm::Triple::ppc: 82 case llvm::Triple::ppc64: 83 switch (m_exc_code) { 84 case 0x101: 85 code_desc = "EXC_PPC_VM_PROT_READ"; 86 break; 87 case 0x102: 88 code_desc = "EXC_PPC_BADSPACE"; 89 break; 90 case 0x103: 91 code_desc = "EXC_PPC_UNALIGNED"; 92 break; 93 } 94 break; 95 96 default: 97 break; 98 } 99 break; 100 101 case 2: // EXC_BAD_INSTRUCTION 102 exc_desc = "EXC_BAD_INSTRUCTION"; 103 switch (cpu) { 104 case llvm::Triple::x86: 105 case llvm::Triple::x86_64: 106 if (m_exc_code == 1) 107 code_desc = "EXC_I386_INVOP"; 108 break; 109 110 case llvm::Triple::ppc: 111 case llvm::Triple::ppc64: 112 switch (m_exc_code) { 113 case 1: 114 code_desc = "EXC_PPC_INVALID_SYSCALL"; 115 break; 116 case 2: 117 code_desc = "EXC_PPC_UNIPL_INST"; 118 break; 119 case 3: 120 code_desc = "EXC_PPC_PRIVINST"; 121 break; 122 case 4: 123 code_desc = "EXC_PPC_PRIVREG"; 124 break; 125 case 5: 126 code_desc = "EXC_PPC_TRACE"; 127 break; 128 case 6: 129 code_desc = "EXC_PPC_PERFMON"; 130 break; 131 } 132 break; 133 134 case llvm::Triple::arm: 135 case llvm::Triple::thumb: 136 if (m_exc_code == 1) 137 code_desc = "EXC_ARM_UNDEFINED"; 138 break; 139 140 default: 141 break; 142 } 143 break; 144 145 case 3: // EXC_ARITHMETIC 146 exc_desc = "EXC_ARITHMETIC"; 147 switch (cpu) { 148 case llvm::Triple::x86: 149 case llvm::Triple::x86_64: 150 switch (m_exc_code) { 151 case 1: 152 code_desc = "EXC_I386_DIV"; 153 break; 154 case 2: 155 code_desc = "EXC_I386_INTO"; 156 break; 157 case 3: 158 code_desc = "EXC_I386_NOEXT"; 159 break; 160 case 4: 161 code_desc = "EXC_I386_EXTOVR"; 162 break; 163 case 5: 164 code_desc = "EXC_I386_EXTERR"; 165 break; 166 case 6: 167 code_desc = "EXC_I386_EMERR"; 168 break; 169 case 7: 170 code_desc = "EXC_I386_BOUND"; 171 break; 172 case 8: 173 code_desc = "EXC_I386_SSEEXTERR"; 174 break; 175 } 176 break; 177 178 case llvm::Triple::ppc: 179 case llvm::Triple::ppc64: 180 switch (m_exc_code) { 181 case 1: 182 code_desc = "EXC_PPC_OVERFLOW"; 183 break; 184 case 2: 185 code_desc = "EXC_PPC_ZERO_DIVIDE"; 186 break; 187 case 3: 188 code_desc = "EXC_PPC_FLT_INEXACT"; 189 break; 190 case 4: 191 code_desc = "EXC_PPC_FLT_ZERO_DIVIDE"; 192 break; 193 case 5: 194 code_desc = "EXC_PPC_FLT_UNDERFLOW"; 195 break; 196 case 6: 197 code_desc = "EXC_PPC_FLT_OVERFLOW"; 198 break; 199 case 7: 200 code_desc = "EXC_PPC_FLT_NOT_A_NUMBER"; 201 break; 202 } 203 break; 204 205 default: 206 break; 207 } 208 break; 209 210 case 4: // EXC_EMULATION 211 exc_desc = "EXC_EMULATION"; 212 break; 213 214 case 5: // EXC_SOFTWARE 215 exc_desc = "EXC_SOFTWARE"; 216 if (m_exc_code == 0x10003) { 217 subcode_desc = "EXC_SOFT_SIGNAL"; 218 subcode_label = "signo"; 219 } 220 break; 221 222 case 6: // EXC_BREAKPOINT 223 { 224 exc_desc = "EXC_BREAKPOINT"; 225 switch (cpu) { 226 case llvm::Triple::x86: 227 case llvm::Triple::x86_64: 228 switch (m_exc_code) { 229 case 1: 230 code_desc = "EXC_I386_SGL"; 231 break; 232 case 2: 233 code_desc = "EXC_I386_BPT"; 234 break; 235 } 236 break; 237 238 case llvm::Triple::ppc: 239 case llvm::Triple::ppc64: 240 switch (m_exc_code) { 241 case 1: 242 code_desc = "EXC_PPC_BREAKPOINT"; 243 break; 244 } 245 break; 246 247 case llvm::Triple::arm: 248 case llvm::Triple::thumb: 249 switch (m_exc_code) { 250 case 0x101: 251 code_desc = "EXC_ARM_DA_ALIGN"; 252 break; 253 case 0x102: 254 code_desc = "EXC_ARM_DA_DEBUG"; 255 break; 256 case 1: 257 code_desc = "EXC_ARM_BREAKPOINT"; 258 break; 259 // FIXME temporary workaround, exc_code 0 does not really mean 260 // EXC_ARM_BREAKPOINT 261 case 0: 262 code_desc = "EXC_ARM_BREAKPOINT"; 263 break; 264 } 265 break; 266 267 default: 268 break; 269 } 270 } break; 271 272 case 7: 273 exc_desc = "EXC_SYSCALL"; 274 break; 275 276 case 8: 277 exc_desc = "EXC_MACH_SYSCALL"; 278 break; 279 280 case 9: 281 exc_desc = "EXC_RPC_ALERT"; 282 break; 283 284 case 10: 285 exc_desc = "EXC_CRASH"; 286 break; 287 case 11: 288 exc_desc = "EXC_RESOURCE"; 289 #if defined(__APPLE__) 290 { 291 int resource_type = EXC_RESOURCE_DECODE_RESOURCE_TYPE(m_exc_code); 292 293 code_label = "limit"; 294 code_desc = code_desc_buf; 295 subcode_label = "observed"; 296 subcode_desc = subcode_desc_buf; 297 298 switch (resource_type) { 299 case RESOURCE_TYPE_CPU: 300 exc_desc = "EXC_RESOURCE RESOURCE_TYPE_CPU"; 301 snprintf(code_desc_buf, sizeof(code_desc_buf), "%d%%", 302 (int)EXC_RESOURCE_CPUMONITOR_DECODE_PERCENTAGE(m_exc_code)); 303 snprintf(subcode_desc_buf, sizeof(subcode_desc_buf), "%d%%", 304 (int)EXC_RESOURCE_CPUMONITOR_DECODE_PERCENTAGE_OBSERVED( 305 m_exc_subcode)); 306 break; 307 case RESOURCE_TYPE_WAKEUPS: 308 exc_desc = "EXC_RESOURCE RESOURCE_TYPE_WAKEUPS"; 309 snprintf( 310 code_desc_buf, sizeof(code_desc_buf), "%d w/s", 311 (int)EXC_RESOURCE_CPUMONITOR_DECODE_WAKEUPS_PERMITTED(m_exc_code)); 312 snprintf(subcode_desc_buf, sizeof(subcode_desc_buf), "%d w/s", 313 (int)EXC_RESOURCE_CPUMONITOR_DECODE_WAKEUPS_OBSERVED( 314 m_exc_subcode)); 315 break; 316 case RESOURCE_TYPE_MEMORY: 317 exc_desc = "EXC_RESOURCE RESOURCE_TYPE_MEMORY"; 318 snprintf(code_desc_buf, sizeof(code_desc_buf), "%d MB", 319 (int)EXC_RESOURCE_HWM_DECODE_LIMIT(m_exc_code)); 320 subcode_desc = nullptr; 321 subcode_label = "unused"; 322 break; 323 #if defined(RESOURCE_TYPE_IO) 324 // RESOURCE_TYPE_IO is introduced in macOS SDK 10.12. 325 case RESOURCE_TYPE_IO: 326 exc_desc = "EXC_RESOURCE RESOURCE_TYPE_IO"; 327 snprintf(code_desc_buf, sizeof(code_desc_buf), "%d MB", 328 (int)EXC_RESOURCE_IO_DECODE_LIMIT(m_exc_code)); 329 snprintf(subcode_desc_buf, sizeof(subcode_desc_buf), "%d MB", 330 (int)EXC_RESOURCE_IO_OBSERVED(m_exc_subcode)); 331 ; 332 break; 333 #endif 334 } 335 } 336 #endif 337 break; 338 case 12: 339 exc_desc = "EXC_GUARD"; 340 break; 341 } 342 343 StreamString strm; 344 345 if (exc_desc) 346 strm.PutCString(exc_desc); 347 else 348 strm.Printf("EXC_??? (%" PRIu64 ")", m_value); 349 350 if (m_exc_data_count >= 1) { 351 if (code_desc) 352 strm.Printf(" (%s=%s", code_label, code_desc); 353 else 354 strm.Printf(" (%s=%" PRIu64, code_label, m_exc_code); 355 } 356 357 if (m_exc_data_count >= 2) { 358 if (subcode_desc) 359 strm.Printf(", %s=%s", subcode_label, subcode_desc); 360 else 361 strm.Printf(", %s=0x%" PRIx64, subcode_label, m_exc_subcode); 362 } 363 364 if (m_exc_data_count > 0) 365 strm.PutChar(')'); 366 367 m_description = strm.GetString(); 368 return m_description.c_str(); 369 } 370 371 StopInfoSP StopInfoMachException::CreateStopReasonWithMachException( 372 Thread &thread, uint32_t exc_type, uint32_t exc_data_count, 373 uint64_t exc_code, uint64_t exc_sub_code, uint64_t exc_sub_sub_code, 374 bool pc_already_adjusted, bool adjust_pc_if_needed) { 375 if (exc_type == 0) 376 return StopInfoSP(); 377 378 uint32_t pc_decrement = 0; 379 ExecutionContext exe_ctx(thread.shared_from_this()); 380 Target *target = exe_ctx.GetTargetPtr(); 381 const llvm::Triple::ArchType cpu = 382 target ? target->GetArchitecture().GetMachine() 383 : llvm::Triple::UnknownArch; 384 385 switch (exc_type) { 386 case 1: // EXC_BAD_ACCESS 387 break; 388 389 case 2: // EXC_BAD_INSTRUCTION 390 switch (cpu) { 391 case llvm::Triple::ppc: 392 case llvm::Triple::ppc64: 393 switch (exc_code) { 394 case 1: // EXC_PPC_INVALID_SYSCALL 395 case 2: // EXC_PPC_UNIPL_INST 396 case 3: // EXC_PPC_PRIVINST 397 case 4: // EXC_PPC_PRIVREG 398 break; 399 case 5: // EXC_PPC_TRACE 400 return StopInfo::CreateStopReasonToTrace(thread); 401 case 6: // EXC_PPC_PERFMON 402 break; 403 } 404 break; 405 406 default: 407 break; 408 } 409 break; 410 411 case 3: // EXC_ARITHMETIC 412 case 4: // EXC_EMULATION 413 break; 414 415 case 5: // EXC_SOFTWARE 416 if (exc_code == 0x10003) // EXC_SOFT_SIGNAL 417 { 418 if (exc_sub_code == 5) { 419 // On MacOSX, a SIGTRAP can signify that a process has called exec, 420 // so we should check with our dynamic loader to verify. 421 ProcessSP process_sp(thread.GetProcess()); 422 if (process_sp) { 423 DynamicLoader *dynamic_loader = process_sp->GetDynamicLoader(); 424 if (dynamic_loader && dynamic_loader->ProcessDidExec()) { 425 // The program was re-exec'ed 426 return StopInfo::CreateStopReasonWithExec(thread); 427 } 428 } 429 } 430 return StopInfo::CreateStopReasonWithSignal(thread, exc_sub_code); 431 } 432 break; 433 434 case 6: // EXC_BREAKPOINT 435 { 436 bool is_actual_breakpoint = false; 437 bool is_trace_if_actual_breakpoint_missing = false; 438 switch (cpu) { 439 case llvm::Triple::x86: 440 case llvm::Triple::x86_64: 441 if (exc_code == 1) // EXC_I386_SGL 442 { 443 if (!exc_sub_code) { 444 // This looks like a plain trap. 445 // Have to check if there is a breakpoint here as well. When you 446 // single-step onto a trap, the single step stops you not to trap. 447 // Since we also do that check below, let's just use that logic. 448 is_actual_breakpoint = true; 449 is_trace_if_actual_breakpoint_missing = true; 450 } else { 451 452 // It's a watchpoint, then. 453 // The exc_sub_code indicates the data break address. 454 lldb::WatchpointSP wp_sp; 455 if (target) 456 wp_sp = target->GetWatchpointList().FindByAddress( 457 (lldb::addr_t)exc_sub_code); 458 if (wp_sp && wp_sp->IsEnabled()) { 459 // Debugserver may piggyback the hardware index of the fired 460 // watchpoint in the exception data. Set the hardware index if 461 // that's the case. 462 if (exc_data_count >= 3) 463 wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code); 464 return StopInfo::CreateStopReasonWithWatchpointID(thread, 465 wp_sp->GetID()); 466 } 467 } 468 } else if (exc_code == 2 || // EXC_I386_BPT 469 exc_code == 3) // EXC_I386_BPTFLT 470 { 471 // KDP returns EXC_I386_BPTFLT for trace breakpoints 472 if (exc_code == 3) 473 is_trace_if_actual_breakpoint_missing = true; 474 475 is_actual_breakpoint = true; 476 if (!pc_already_adjusted) 477 pc_decrement = 1; 478 } 479 break; 480 481 case llvm::Triple::ppc: 482 case llvm::Triple::ppc64: 483 is_actual_breakpoint = exc_code == 1; // EXC_PPC_BREAKPOINT 484 break; 485 486 case llvm::Triple::arm: 487 case llvm::Triple::thumb: 488 if (exc_code == 0x102) // EXC_ARM_DA_DEBUG 489 { 490 // It's a watchpoint, then, if the exc_sub_code indicates a 491 // known/enabled data break address from our watchpoint list. 492 lldb::WatchpointSP wp_sp; 493 if (target) 494 wp_sp = target->GetWatchpointList().FindByAddress( 495 (lldb::addr_t)exc_sub_code); 496 if (wp_sp && wp_sp->IsEnabled()) { 497 // Debugserver may piggyback the hardware index of the fired 498 // watchpoint in the exception data. Set the hardware index if 499 // 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, 503 wp_sp->GetID()); 504 } else { 505 is_actual_breakpoint = true; 506 is_trace_if_actual_breakpoint_missing = true; 507 } 508 } else if (exc_code == 1) // EXC_ARM_BREAKPOINT 509 { 510 is_actual_breakpoint = true; 511 is_trace_if_actual_breakpoint_missing = true; 512 } else if (exc_code == 0) // FIXME not EXC_ARM_BREAKPOINT but a kernel 513 // is currently returning this so accept it 514 // as indicating a breakpoint until the 515 // kernel is fixed 516 { 517 is_actual_breakpoint = true; 518 is_trace_if_actual_breakpoint_missing = true; 519 } 520 break; 521 522 case llvm::Triple::aarch64: { 523 if (exc_code == 1 && exc_sub_code == 0) // EXC_ARM_BREAKPOINT 524 { 525 // This is hit when we single instruction step aka MDSCR_EL1 SS bit 0 526 // is set 527 is_actual_breakpoint = false; 528 is_trace_if_actual_breakpoint_missing = true; 529 } 530 if (exc_code == 0x102) // EXC_ARM_DA_DEBUG 531 { 532 // It's a watchpoint, then, if the exc_sub_code indicates a 533 // known/enabled data break address from our watchpoint list. 534 lldb::WatchpointSP wp_sp; 535 if (target) 536 wp_sp = target->GetWatchpointList().FindByAddress( 537 (lldb::addr_t)exc_sub_code); 538 if (wp_sp && wp_sp->IsEnabled()) { 539 // Debugserver may piggyback the hardware index of the fired 540 // watchpoint in the exception data. Set the hardware index if 541 // that's the case. 542 if (exc_data_count >= 3) 543 wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code); 544 return StopInfo::CreateStopReasonWithWatchpointID(thread, 545 wp_sp->GetID()); 546 } 547 // EXC_ARM_DA_DEBUG seems to be reused for EXC_BREAKPOINT as well as 548 // EXC_BAD_ACCESS 549 if (thread.GetTemporaryResumeState() == eStateStepping) 550 return StopInfo::CreateStopReasonToTrace(thread); 551 } 552 // It looks like exc_sub_code has the 4 bytes of the instruction that 553 // triggered the exception, i.e. our breakpoint opcode 554 is_actual_breakpoint = exc_code == 1; 555 break; 556 } 557 558 default: 559 break; 560 } 561 562 if (is_actual_breakpoint) { 563 RegisterContextSP reg_ctx_sp(thread.GetRegisterContext()); 564 addr_t pc = reg_ctx_sp->GetPC() - pc_decrement; 565 566 ProcessSP process_sp(thread.CalculateProcess()); 567 568 lldb::BreakpointSiteSP bp_site_sp; 569 if (process_sp) 570 bp_site_sp = process_sp->GetBreakpointSiteList().FindByAddress(pc); 571 if (bp_site_sp && bp_site_sp->IsEnabled()) { 572 // Update the PC if we were asked to do so, but only do so if we find 573 // a breakpoint that we know about cause this could be a trap 574 // instruction in the code 575 if (pc_decrement > 0 && adjust_pc_if_needed) 576 reg_ctx_sp->SetPC(pc); 577 578 // If the breakpoint is for this thread, then we'll report the hit, 579 // but if it is for another thread, we can just report no reason. We 580 // don't need to worry about stepping over the breakpoint here, that 581 // will be taken care of when the thread resumes and notices that 582 // there's a breakpoint under the pc. If we have an operating system 583 // plug-in, we might have set a thread specific breakpoint using the 584 // operating system thread ID, so we can't make any assumptions about 585 // the thread ID so we must always report the breakpoint regardless 586 // of the thread. 587 if (bp_site_sp->ValidForThisThread(&thread) || 588 thread.GetProcess()->GetOperatingSystem() != nullptr) 589 return StopInfo::CreateStopReasonWithBreakpointSiteID( 590 thread, bp_site_sp->GetID()); 591 else if (is_trace_if_actual_breakpoint_missing) 592 return StopInfo::CreateStopReasonToTrace(thread); 593 else 594 return StopInfoSP(); 595 } 596 597 // Don't call this a trace if we weren't single stepping this thread. 598 if (is_trace_if_actual_breakpoint_missing && 599 thread.GetTemporaryResumeState() == eStateStepping) { 600 return StopInfo::CreateStopReasonToTrace(thread); 601 } 602 } 603 } break; 604 605 case 7: // EXC_SYSCALL 606 case 8: // EXC_MACH_SYSCALL 607 case 9: // EXC_RPC_ALERT 608 case 10: // EXC_CRASH 609 break; 610 } 611 612 return StopInfoSP(new StopInfoMachException(thread, exc_type, exc_data_count, 613 exc_code, exc_sub_code)); 614 } 615