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