1 /* 2 * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2010-2016, Rene Gollent, rene@gollent.com. 4 * Distributed under the terms of the MIT License. 5 */ 6 7 8 #include "ThreadHandler.h" 9 10 #include <stdio.h> 11 12 #include <new> 13 14 #include <AutoDeleter.h> 15 #include <AutoLocker.h> 16 #include <Variant.h> 17 18 #include "Architecture.h" 19 #include "BreakpointManager.h" 20 #include "CpuState.h" 21 #include "DebugEvent.h" 22 #include "DebuggerInterface.h" 23 #include "ExpressionInfo.h" 24 #include "FunctionInstance.h" 25 #include "ImageDebugInfo.h" 26 #include "InstructionInfo.h" 27 #include "Jobs.h" 28 #include "MessageCodes.h" 29 #include "Register.h" 30 #include "SignalDispositionTypes.h" 31 #include "SourceCode.h" 32 #include "SourceLanguage.h" 33 #include "SpecificImageDebugInfo.h" 34 #include "StackTrace.h" 35 #include "Statement.h" 36 #include "SyntheticPrimitiveType.h" 37 #include "Team.h" 38 #include "Tracing.h" 39 #include "Value.h" 40 #include "ValueLocation.h" 41 #include "Worker.h" 42 43 44 // step modes 45 enum { 46 STEP_NONE, 47 STEP_OVER, 48 STEP_INTO, 49 STEP_OUT, 50 STEP_UNTIL 51 }; 52 53 54 class ExpressionEvaluationListener : public ExpressionInfo::Listener { 55 public: 56 ExpressionEvaluationListener(ThreadHandler* handler) 57 : 58 fHandler(handler) 59 { 60 fHandler->AcquireReference(); 61 } 62 63 ~ExpressionEvaluationListener() 64 { 65 fHandler->ReleaseReference(); 66 } 67 68 virtual void ExpressionEvaluated(ExpressionInfo* info, status_t result, 69 ExpressionResult* value) 70 { 71 fHandler->_HandleBreakpointConditionEvaluated(value); 72 } 73 74 private: 75 ThreadHandler* fHandler; 76 }; 77 78 79 ThreadHandler::ThreadHandler(::Thread* thread, Worker* worker, 80 DebuggerInterface* debuggerInterface, JobListener* jobListener, 81 BreakpointManager* breakpointManager) 82 : 83 fThread(thread), 84 fWorker(worker), 85 fDebuggerInterface(debuggerInterface), 86 fJobListener(jobListener), 87 fBreakpointManager(breakpointManager), 88 fStepMode(STEP_NONE), 89 fStepStatement(NULL), 90 fBreakpointAddress(0), 91 fSteppedOverFunctionAddress(0), 92 fPreviousInstructionPointer(0), 93 fPreviousFrameAddress(0), 94 fSingleStepping(false), 95 fConditionWaitSem(-1), 96 fConditionResult(NULL) 97 { 98 fDebuggerInterface->AcquireReference(); 99 } 100 101 102 ThreadHandler::~ThreadHandler() 103 { 104 _ClearContinuationState(); 105 fDebuggerInterface->ReleaseReference(); 106 107 if (fConditionWaitSem > 0) 108 delete_sem(fConditionWaitSem); 109 } 110 111 112 void 113 ThreadHandler::Init() 114 { 115 fWorker->ScheduleJob(new(std::nothrow) GetThreadStateJob(fDebuggerInterface, 116 fThread), fJobListener); 117 fConditionWaitSem = create_sem(0, "breakpoint condition waiter"); 118 } 119 120 121 status_t 122 ThreadHandler::SetBreakpointAndRun(target_addr_t address) 123 { 124 status_t error = _InstallTemporaryBreakpoint(address); 125 if (error != B_OK) 126 return error; 127 128 fPreviousInstructionPointer = 0; 129 fDebuggerInterface->ContinueThread(ThreadID()); 130 131 // Pretend "step out" mode, so that the temporary breakpoint hit will not 132 // be ignored. 133 fStepMode = STEP_OUT; 134 fSingleStepping = false; 135 136 return B_OK; 137 } 138 139 140 bool 141 ThreadHandler::HandleThreadDebugged(ThreadDebuggedEvent* event, 142 const BString& stoppedReason) 143 { 144 return _HandleThreadStopped(NULL, THREAD_STOPPED_DEBUGGED, stoppedReason); 145 } 146 147 148 bool 149 ThreadHandler::HandleDebuggerCall(DebuggerCallEvent* event) 150 { 151 BString message; 152 fDebuggerInterface->ReadMemoryString(event->Message(), 1024, message); 153 return _HandleThreadStopped(NULL, THREAD_STOPPED_DEBUGGER_CALL, message); 154 } 155 156 157 bool 158 ThreadHandler::HandleBreakpointHit(BreakpointHitEvent* event) 159 { 160 CpuState* cpuState = event->GetCpuState(); 161 target_addr_t instructionPointer = cpuState->InstructionPointer(); 162 163 TRACE_EVENTS("ThreadHandler::HandleBreakpointHit(): ip: %" B_PRIx64 "\n", 164 instructionPointer); 165 166 // check whether this is a temporary breakpoint we're waiting for 167 if (fBreakpointAddress != 0 && instructionPointer == fBreakpointAddress 168 && fStepMode != STEP_NONE) { 169 if (fStepMode != STEP_UNTIL && _HandleBreakpointHitStep(cpuState)) 170 return true; 171 } else { 172 // Might be a user breakpoint, but could as well be a temporary 173 // breakpoint of another thread. 174 AutoLocker<Team> locker(fThread->GetTeam()); 175 Breakpoint* breakpoint = fThread->GetTeam()->BreakpointAtAddress( 176 cpuState->InstructionPointer()); 177 bool continueThread = false; 178 if (breakpoint == NULL) { 179 // spurious breakpoint -- might be a temporary breakpoint, that has 180 // already been uninstalled 181 continueThread = true; 182 } else if (!breakpoint->HasEnabledUserBreakpoint()) { 183 // breakpoint of another thread or one that has been disabled in 184 // the meantime 185 continueThread = true; 186 } 187 188 if (continueThread) { 189 if (fSingleStepping) { 190 // We might have hit a just-installed software breakpoint and 191 // thus haven't stepped at all. Just try again. 192 if (fPreviousInstructionPointer == instructionPointer) { 193 fDebuggerInterface->SingleStepThread(ThreadID()); 194 return true; 195 } 196 197 // That shouldn't happen. Try something reasonable anyway. 198 if (fStepMode != STEP_NONE) { 199 if (_HandleSingleStepStep(cpuState)) 200 return true; 201 } 202 } 203 204 return false; 205 } else { 206 locker.Unlock(); 207 if (_HandleBreakpointConditionIfNeeded(cpuState)) 208 return true; 209 210 locker.Lock(); 211 } 212 } 213 214 return _HandleThreadStopped(cpuState, THREAD_STOPPED_BREAKPOINT); 215 } 216 217 218 bool 219 ThreadHandler::HandleWatchpointHit(WatchpointHitEvent* event) 220 { 221 return _HandleThreadStopped(event->GetCpuState(), 222 THREAD_STOPPED_WATCHPOINT); 223 } 224 225 226 bool 227 ThreadHandler::HandleSingleStep(SingleStepEvent* event) 228 { 229 // Check whether we're stepping automatically. 230 if (fStepMode != STEP_NONE) { 231 if (_HandleSingleStepStep(event->GetCpuState())) 232 return true; 233 } 234 235 return _HandleThreadStopped(event->GetCpuState(), 236 THREAD_STOPPED_SINGLE_STEP); 237 } 238 239 240 bool 241 ThreadHandler::HandleExceptionOccurred(ExceptionOccurredEvent* event) 242 { 243 char buffer[256]; 244 get_debug_exception_string(event->Exception(), buffer, sizeof(buffer)); 245 return _HandleThreadStopped(NULL, THREAD_STOPPED_EXCEPTION, buffer); 246 } 247 248 249 bool 250 ThreadHandler::HandleSignalReceived(SignalReceivedEvent* event) 251 { 252 ::Team* team = fThread->GetTeam(); 253 AutoLocker<Team> locker(team); 254 255 const SignalInfo& info = event->GetSignalInfo(); 256 int32 signal = info.Signal(); 257 int32 disposition = team->SignalDispositionFor(signal); 258 259 switch (disposition) { 260 case SIGNAL_DISPOSITION_IGNORE: 261 return false; 262 case SIGNAL_DISPOSITION_STOP_AT_SIGNAL_HANDLER: 263 { 264 const struct sigaction& handlerInfo = info.Handler(); 265 target_addr_t address = 0; 266 if ((handlerInfo.sa_flags & SA_SIGINFO) != 0) 267 address = (target_addr_t)handlerInfo.sa_sigaction; 268 else 269 address = (target_addr_t)handlerInfo.sa_handler; 270 271 if (address == (target_addr_t)SIG_DFL 272 || address == (target_addr_t)SIG_IGN 273 || address == (target_addr_t)SIG_HOLD) { 274 address = 0; 275 } 276 277 if (address != 0 && _InstallTemporaryBreakpoint(address) == B_OK 278 && fDebuggerInterface->ContinueThread(ThreadID()) == B_OK) { 279 fStepMode = STEP_UNTIL; 280 return true; 281 } 282 283 // fall through if no handler or if we failed to 284 // set a breakpoint at the handler 285 } 286 case SIGNAL_DISPOSITION_STOP_AT_RECEIPT: 287 { 288 BString stopReason; 289 stopReason.SetToFormat("Received signal %" B_PRId32 " (%s)", 290 signal, strsignal(signal)); 291 return _HandleThreadStopped(NULL, THREAD_STOPPED_DEBUGGED, 292 stopReason); 293 } 294 default: 295 break; 296 } 297 298 return false; 299 } 300 301 302 void 303 ThreadHandler::HandleThreadAction(uint32 action, target_addr_t address) 304 { 305 AutoLocker<Team> locker(fThread->GetTeam()); 306 307 if (fThread->State() == THREAD_STATE_UNKNOWN) 308 return; 309 310 // When stop is requested, thread must be running, otherwise stopped. 311 if (action == MSG_THREAD_STOP 312 ? fThread->State() != THREAD_STATE_RUNNING 313 : fThread->State() != THREAD_STATE_STOPPED) { 314 return; 315 } 316 317 // When stepping we need a stack trace. Save it before unsetting the state. 318 CpuState* cpuState = fThread->GetCpuState(); 319 StackTrace* stackTrace = fThread->GetStackTrace(); 320 BReference<CpuState> cpuStateReference(cpuState); 321 BReference<StackTrace> stackTraceReference(stackTrace); 322 323 if (action == MSG_THREAD_SET_ADDRESS) { 324 _HandleSetAddress(cpuState, address); 325 return; 326 } 327 328 // When continuing the thread update thread state before actually issuing 329 // the command, since we need to unlock. 330 if (action != MSG_THREAD_STOP) { 331 _SetThreadState(THREAD_STATE_RUNNING, NULL, THREAD_STOPPED_UNKNOWN, 332 BString()); 333 } 334 335 locker.Unlock(); 336 337 switch (action) { 338 case MSG_THREAD_RUN: 339 fStepMode = address != 0 ? STEP_UNTIL : STEP_NONE; 340 if (address != 0) 341 _InstallTemporaryBreakpoint(address); 342 _RunThread(0); 343 return; 344 case MSG_THREAD_STOP: 345 fStepMode = STEP_NONE; 346 if (fDebuggerInterface->StopThread(ThreadID()) == B_OK) 347 fThread->SetStopRequestPending(); 348 return; 349 case MSG_THREAD_STEP_OVER: 350 case MSG_THREAD_STEP_INTO: 351 case MSG_THREAD_STEP_OUT: 352 break; 353 } 354 355 TRACE_CONTROL("ThreadHandler::HandleThreadAction(MSG_THREAD_STEP_*)\n"); 356 357 // We want to step. We need a stack trace for that purpose. If we don't 358 // have one yet, get it. Start with the CPU state. 359 if (stackTrace == NULL && cpuState == NULL) { 360 if (fDebuggerInterface->GetCpuState(fThread->ID(), cpuState) == B_OK) 361 cpuStateReference.SetTo(cpuState, true); 362 } 363 364 if (stackTrace == NULL && cpuState != NULL) { 365 if (fDebuggerInterface->GetArchitecture()->CreateStackTrace( 366 fThread->GetTeam(), this, cpuState, stackTrace, NULL, 1, 367 false, false) == B_OK) { 368 stackTraceReference.SetTo(stackTrace, true); 369 } 370 } 371 372 if (stackTrace == NULL || stackTrace->CountFrames() == 0) { 373 _StepFallback(); 374 return; 375 } 376 377 StackFrame* frame = stackTrace->FrameAt(0); 378 379 TRACE_CONTROL(" ip: %#" B_PRIx64 "\n", frame->InstructionPointer()); 380 381 target_addr_t frameIP = frame->GetCpuState()->InstructionPointer(); 382 // When the thread is in a syscall, do the same for all step kinds: Stop it 383 // when it returns by means of a breakpoint. 384 if (frame->Type() == STACK_FRAME_TYPE_SYSCALL) { 385 // set a breakpoint at the CPU state's instruction pointer (points to 386 // the return address, unlike the stack frame's instruction pointer) 387 // TODO: This is doesn't work correctly anymore. When stepping over a "syscall" 388 // instruction the thread is stopped twice. The after the first step the PC is 389 // incorrectly shown at the "syscall" instruction. Then we step again and are 390 // stopped at the temporary breakpoint after the "syscall" instruction. There 391 // are two problems. The first one is that we don't (cannot?) discriminate 392 // between the thread being in a syscall (like in a blocking syscall) and the 393 // thread having been stopped (or singled-stepped) at the end of the syscall. 394 // The second issue is that the temporary breakpoint is probably not necessary 395 // anymore, since single-stepping over "syscall" instructions should just work 396 // as expected. 397 status_t error = _InstallTemporaryBreakpoint(frameIP); 398 if (error != B_OK) { 399 _StepFallback(); 400 return; 401 } 402 403 fStepMode = STEP_OUT; 404 _RunThread(frameIP); 405 return; 406 } 407 408 // For "step out" just set a temporary breakpoint on the return address. 409 if (action == MSG_THREAD_STEP_OUT) { 410 status_t error = _InstallTemporaryBreakpoint(frame->ReturnAddress()); 411 if (error != B_OK) { 412 _StepFallback(); 413 return; 414 } 415 fPreviousInstructionPointer = frameIP; 416 fPreviousFrameAddress = frame->FrameAddress(); 417 fStepMode = STEP_OUT; 418 _RunThread(frameIP); 419 return; 420 } 421 422 // For "step in" and "step over" we also need the source code statement at 423 // the current instruction pointer. 424 fStepStatement = _GetStatementAtInstructionPointer(frame); 425 if (fStepStatement == NULL) { 426 _StepFallback(); 427 return; 428 } 429 430 TRACE_CONTROL(" statement: %#" B_PRIx64 " - %#" B_PRIx64 "\n", 431 fStepStatement->CoveringAddressRange().Start(), 432 fStepStatement->CoveringAddressRange().End()); 433 434 if (action == MSG_THREAD_STEP_INTO) { 435 // step into 436 fStepMode = STEP_INTO; 437 _SingleStepThread(frameIP); 438 } else { 439 fPreviousFrameAddress = frame->FrameAddress(); 440 // step over 441 fStepMode = STEP_OVER; 442 if (!_DoStepOver(frame->GetCpuState())) 443 _StepFallback(); 444 } 445 } 446 447 448 void 449 ThreadHandler::HandleThreadStateChanged() 450 { 451 AutoLocker<Team> locker(fThread->GetTeam()); 452 453 // cancel jobs for this thread 454 fWorker->AbortJob(SimpleJobKey(fThread, JOB_TYPE_GET_CPU_STATE)); 455 fWorker->AbortJob(SimpleJobKey(fThread, JOB_TYPE_GET_STACK_TRACE)); 456 457 // If the thread is stopped and has no CPU state yet, schedule a job. 458 if (fThread->State() == THREAD_STATE_STOPPED 459 && fThread->GetCpuState() == NULL) { 460 fWorker->ScheduleJob( 461 new(std::nothrow) GetCpuStateJob(fDebuggerInterface, fThread), 462 fJobListener); 463 } 464 } 465 466 467 void 468 ThreadHandler::HandleCpuStateChanged() 469 { 470 AutoLocker<Team> locker(fThread->GetTeam()); 471 472 // cancel stack trace job for this thread 473 fWorker->AbortJob(SimpleJobKey(fThread, JOB_TYPE_GET_STACK_TRACE)); 474 475 // If the thread has a CPU state, but no stack trace yet, schedule a job. 476 if (fThread->GetCpuState() != NULL && fThread->GetStackTrace() == NULL) { 477 fWorker->ScheduleJob( 478 new(std::nothrow) GetStackTraceJob(fDebuggerInterface, 479 fJobListener, fDebuggerInterface->GetArchitecture(), 480 fThread), fJobListener); 481 } 482 } 483 484 485 void 486 ThreadHandler::HandleStackTraceChanged() 487 { 488 } 489 490 491 status_t 492 ThreadHandler::GetImageDebugInfo(Image* image, ImageDebugInfo*& _info) 493 { 494 AutoLocker<Team> teamLocker(fThread->GetTeam()); 495 496 if (image->GetImageDebugInfo() != NULL) { 497 _info = image->GetImageDebugInfo(); 498 _info->AcquireReference(); 499 return B_OK; 500 } 501 502 // Let's be lazy. If the image debug info has not been loaded yet, the user 503 // can't have seen any source code either. 504 return B_ENTRY_NOT_FOUND; 505 } 506 507 508 bool 509 ThreadHandler::_HandleThreadStopped(CpuState* cpuState, uint32 stoppedReason, 510 const BString& stoppedReasonInfo) 511 { 512 _ClearContinuationState(); 513 514 AutoLocker<Team> locker(fThread->GetTeam()); 515 516 _SetThreadState(THREAD_STATE_STOPPED, cpuState, stoppedReason, 517 stoppedReasonInfo); 518 519 return true; 520 } 521 522 523 bool 524 ThreadHandler::_HandleSetAddress(CpuState* state, target_addr_t address) 525 { 526 CpuState* newState = NULL; 527 if (state->Clone(newState) != B_OK) 528 return false; 529 BReference<CpuState> stateReference(newState, true); 530 531 newState->SetInstructionPointer(address); 532 if (fDebuggerInterface->SetCpuState(fThread->ID(), newState) != B_OK) 533 return false; 534 535 AutoLocker<Team> locker(fThread->GetTeam()); 536 fThread->SetStackTrace(NULL); 537 fThread->SetCpuState(newState); 538 539 return true; 540 } 541 542 543 void 544 ThreadHandler::_SetThreadState(uint32 state, CpuState* cpuState, 545 uint32 stoppedReason, const BString& stoppedReasonInfo) 546 { 547 fThread->SetState(state, stoppedReason, stoppedReasonInfo); 548 fThread->SetCpuState(cpuState); 549 } 550 551 552 Statement* 553 ThreadHandler::_GetStatementAtInstructionPointer(StackFrame* frame) 554 { 555 AutoLocker<Team> locker(fThread->GetTeam()); 556 557 FunctionInstance* functionInstance = frame->Function(); 558 if (functionInstance == NULL) 559 return NULL; 560 FunctionDebugInfo* function = functionInstance->GetFunctionDebugInfo(); 561 562 // If there's source code attached to the function, we can just get the 563 // statement. 564 // SourceCode* sourceCode = function->GetSourceCode(); 565 // if (sourceCode != NULL) { 566 // Statement* statement = sourceCode->StatementAtAddress( 567 // frame->InstructionPointer()); 568 // if (statement != NULL) 569 // statement->AcquireReference(); 570 // return statement; 571 // } 572 573 locker.Unlock(); 574 575 // We need to get the statement from the debug info of the function. 576 Statement* statement; 577 if (function->GetSpecificImageDebugInfo()->GetStatement(function, 578 frame->InstructionPointer(), statement) != B_OK) { 579 return NULL; 580 } 581 582 return statement; 583 } 584 585 586 void 587 ThreadHandler::_StepFallback() 588 { 589 fStepMode = STEP_NONE; 590 _SingleStepThread(0); 591 } 592 593 594 bool 595 ThreadHandler::_DoStepOver(CpuState* cpuState) 596 { 597 TRACE_CONTROL("ThreadHandler::_DoStepOver()\n"); 598 599 // The basic strategy is to single-step out of the statement like for 600 // "step into", only we have to avoid stepping into subroutines. Hence we 601 // check whether the current instruction is a subroutine call. If not, we 602 // just single-step, otherwise we set a breakpoint after the instruction. 603 InstructionInfo info; 604 if (fDebuggerInterface->GetArchitecture()->GetInstructionInfo( 605 cpuState->InstructionPointer(), info, cpuState) != B_OK) { 606 TRACE_CONTROL(" failed to get instruction info\n"); 607 return false; 608 } 609 610 if (info.Type() != INSTRUCTION_TYPE_SUBROUTINE_CALL) { 611 _SingleStepThread(cpuState->InstructionPointer()); 612 613 TRACE_CONTROL(" not a subroutine call\n"); 614 return true; 615 } 616 617 TRACE_CONTROL(" subroutine call -- installing breakpoint at address " 618 "%#" B_PRIx64 "\n", info.Address() + info.Size()); 619 620 if (_InstallTemporaryBreakpoint(info.Address() + info.Size()) != B_OK) 621 return false; 622 623 fSteppedOverFunctionAddress = info.TargetAddress(); 624 625 _RunThread(cpuState->InstructionPointer()); 626 return true; 627 } 628 629 630 status_t 631 ThreadHandler::_InstallTemporaryBreakpoint(target_addr_t address) 632 { 633 _UninstallTemporaryBreakpoint(); 634 635 status_t error = fBreakpointManager->InstallTemporaryBreakpoint(address, 636 this); 637 if (error != B_OK) 638 return error; 639 640 fBreakpointAddress = address; 641 return B_OK; 642 } 643 644 645 void 646 ThreadHandler::_UninstallTemporaryBreakpoint() 647 { 648 if (fBreakpointAddress == 0) 649 return; 650 651 fBreakpointManager->UninstallTemporaryBreakpoint(fBreakpointAddress, this); 652 fBreakpointAddress = 0; 653 } 654 655 656 void 657 ThreadHandler::_ClearContinuationState() 658 { 659 _UninstallTemporaryBreakpoint(); 660 661 if (fStepStatement != NULL) { 662 fStepStatement->ReleaseReference(); 663 fStepStatement = NULL; 664 } 665 666 fStepMode = STEP_NONE; 667 fSingleStepping = false; 668 } 669 670 671 void 672 ThreadHandler::_RunThread(target_addr_t instructionPointer) 673 { 674 fPreviousInstructionPointer = instructionPointer; 675 fDebuggerInterface->ContinueThread(ThreadID()); 676 fSingleStepping = false; 677 } 678 679 680 void 681 ThreadHandler::_SingleStepThread(target_addr_t instructionPointer) 682 { 683 fPreviousInstructionPointer = instructionPointer; 684 fDebuggerInterface->SingleStepThread(ThreadID()); 685 fSingleStepping = true; 686 } 687 688 689 bool 690 ThreadHandler::_HandleBreakpointHitStep(CpuState* cpuState) 691 { 692 // in any case uninstall the temporary breakpoint 693 _UninstallTemporaryBreakpoint(); 694 695 switch (fStepMode) { 696 case STEP_OVER: 697 { 698 StackTrace* stackTrace = fThread->GetStackTrace(); 699 BReference<StackTrace> stackTraceReference(stackTrace); 700 701 if (stackTrace == NULL && cpuState != NULL) { 702 if (fDebuggerInterface->GetArchitecture()->CreateStackTrace( 703 fThread->GetTeam(), this, cpuState, stackTrace, NULL, 704 1, false, false) == B_OK) { 705 stackTraceReference.SetTo(stackTrace, true); 706 } 707 } 708 if (stackTrace != NULL) { 709 StackFrame* frame = stackTrace->FrameAt(0); 710 // If we're not in the same frame we started in, 711 // keep executing. 712 if (frame != NULL && fPreviousFrameAddress 713 != frame->FrameAddress()) { 714 status_t error = _InstallTemporaryBreakpoint( 715 cpuState->InstructionPointer()); 716 if (error != B_OK) 717 _StepFallback(); 718 else 719 _RunThread(cpuState->InstructionPointer()); 720 return true; 721 } 722 } 723 724 if (fPreviousFrameAddress != 0 && fSteppedOverFunctionAddress != 0 725 && fSteppedOverFunctionAddress != cpuState->InstructionPointer()) { 726 TRACE_CONTROL("STEP_OVER: called function address %#" B_PRIx64 727 ", previous frame address: %#" B_PRIx64 ", frame address: %#" 728 B_PRIx64 ", adding return info\n", fSteppedOverFunctionAddress, 729 fPreviousFrameAddress, stackTrace->FrameAt(0)->FrameAddress()); 730 ReturnValueInfo* returnInfo = new(std::nothrow) ReturnValueInfo( 731 fSteppedOverFunctionAddress, cpuState); 732 if (returnInfo == NULL) 733 return false; 734 735 BReference<ReturnValueInfo> returnInfoReference(returnInfo, true); 736 737 if (fThread->AddReturnValueInfo(returnInfo) != B_OK) 738 return false; 739 740 returnInfoReference.Detach(); 741 fSteppedOverFunctionAddress = 0; 742 } 743 744 // If we're still in the statement, we continue single-stepping, 745 // otherwise we're done. 746 if (fStepStatement->ContainsAddress( 747 cpuState->InstructionPointer())) { 748 if (!_DoStepOver(cpuState)) 749 _StepFallback(); 750 return true; 751 } 752 fPreviousFrameAddress = 0; 753 return false; 754 } 755 756 case STEP_INTO: 757 // Should never happen -- we don't set a breakpoint in this case. 758 return false; 759 760 case STEP_OUT: 761 { 762 // That's the return address, so we're done in theory, 763 // unless we're a recursive function. Check if we've actually 764 // exited the previous stack frame or not 765 if (!_HasExitedFrame(cpuState->StackFramePointer())) { 766 status_t error = _InstallTemporaryBreakpoint( 767 cpuState->InstructionPointer()); 768 if (error != B_OK) 769 _StepFallback(); 770 else 771 _RunThread(cpuState->InstructionPointer()); 772 return true; 773 } 774 775 if (fPreviousFrameAddress == 0) 776 return false; 777 778 TRACE_CONTROL("ThreadHandler::_HandleBreakpointHitStep() - " 779 "frame pointer 0x%#" B_PRIx64 ", previous: 0x%#" B_PRIx64 780 " - step out adding return value\n", cpuState 781 ->StackFramePointer(), fPreviousFrameAddress); 782 ReturnValueInfo* info = new(std::nothrow) ReturnValueInfo( 783 fPreviousInstructionPointer, cpuState); 784 if (info == NULL) 785 return false; 786 BReference<ReturnValueInfo> infoReference(info, true); 787 if (fThread->AddReturnValueInfo(info) != B_OK) 788 return false; 789 790 infoReference.Detach(); 791 fPreviousFrameAddress = 0; 792 } 793 794 default: 795 return false; 796 } 797 } 798 799 800 bool 801 ThreadHandler::_HandleSingleStepStep(CpuState* cpuState) 802 { 803 TRACE_CONTROL("ThreadHandler::_HandleSingleStepStep(): ip: %" B_PRIx64 "\n", 804 cpuState->InstructionPointer()); 805 806 switch (fStepMode) { 807 case STEP_INTO: 808 { 809 // We continue stepping as long as we're in the statement. 810 if (fStepStatement->ContainsAddress(cpuState->InstructionPointer())) { 811 _SingleStepThread(cpuState->InstructionPointer()); 812 return true; 813 } 814 815 StackTrace* stackTrace = fThread->GetStackTrace(); 816 BReference<StackTrace> stackTraceReference(stackTrace); 817 818 if (stackTrace == NULL && cpuState != NULL) { 819 if (fDebuggerInterface->GetArchitecture()->CreateStackTrace( 820 fThread->GetTeam(), this, cpuState, stackTrace, NULL, 821 1, false, false) == B_OK) { 822 stackTraceReference.SetTo(stackTrace, true); 823 } 824 } 825 826 if (stackTrace != NULL) { 827 StackFrame* frame = stackTrace->FrameAt(0); 828 Image* image = frame->GetImage(); 829 if (image == NULL) 830 return false; 831 832 ImageDebugInfo* info = NULL; 833 if (GetImageDebugInfo(image, info) != B_OK) 834 return false; 835 836 BReference<ImageDebugInfo>(info, true); 837 if (info->GetAddressSectionType( 838 cpuState->InstructionPointer()) 839 == ADDRESS_SECTION_TYPE_PLT) { 840 _SingleStepThread(cpuState->InstructionPointer()); 841 return true; 842 } 843 } 844 return false; 845 } 846 847 case STEP_OVER: 848 { 849 // If we have stepped out of the statement, we're done. 850 if (!fStepStatement->ContainsAddress(cpuState->InstructionPointer())) { 851 StackTrace* stackTrace = fThread->GetStackTrace(); 852 BReference<StackTrace> stackTraceReference(stackTrace); 853 if (stackTrace == NULL && cpuState != NULL) { 854 if (fDebuggerInterface->GetArchitecture()->CreateStackTrace( 855 fThread->GetTeam(), this, cpuState, stackTrace, 856 NULL, 1, false, false) == B_OK) { 857 stackTraceReference.SetTo(stackTrace, true); 858 } 859 } 860 861 862 if (stackTrace != NULL) { 863 if (_HasExitedFrame(stackTrace->FrameAt(0) 864 ->FrameAddress())) { 865 TRACE_CONTROL("ThreadHandler::_HandleSingleStepStep() " 866 " - adding return value for STEP_OVER\n"); 867 ReturnValueInfo* info = new(std::nothrow) 868 ReturnValueInfo(fStepStatement 869 ->CoveringAddressRange().Start(), cpuState); 870 if (info == NULL) 871 return false; 872 BReference<ReturnValueInfo> infoReference(info, true); 873 if (fThread->AddReturnValueInfo(info) != B_OK) 874 return false; 875 876 infoReference.Detach(); 877 } 878 } 879 return false; 880 } 881 return _DoStepOver(cpuState); 882 } 883 884 case STEP_OUT: 885 // We never single-step in this case. 886 default: 887 return false; 888 } 889 } 890 891 892 bool 893 ThreadHandler::_HandleBreakpointConditionIfNeeded(CpuState* cpuState) 894 { 895 AutoLocker< ::Team> teamLocker(fThread->GetTeam()); 896 Breakpoint* breakpoint = fThread->GetTeam()->BreakpointAtAddress( 897 cpuState->InstructionPointer()); 898 899 if (breakpoint == NULL) 900 return false; 901 902 if (!breakpoint->HasEnabledUserBreakpoint()) 903 return false; 904 905 const UserBreakpointInstanceList& breakpoints 906 = breakpoint->UserBreakpoints(); 907 908 for (UserBreakpointInstanceList::ConstIterator it 909 = breakpoints.GetIterator(); it.HasNext();) { 910 UserBreakpoint* userBreakpoint = it.Next()->GetUserBreakpoint(); 911 if (!userBreakpoint->IsValid()) 912 continue; 913 if (!userBreakpoint->IsEnabled()) 914 continue; 915 if (!userBreakpoint->HasCondition()) 916 continue; 917 918 StackTrace* stackTrace = fThread->GetStackTrace(); 919 BReference<StackTrace> stackTraceReference; 920 if (stackTrace == NULL) { 921 if (fDebuggerInterface->GetArchitecture()->CreateStackTrace( 922 fThread->GetTeam(), this, cpuState, stackTrace, NULL, 1, 923 false, true) == B_OK) { 924 stackTraceReference.SetTo(stackTrace, true); 925 } else 926 return false; 927 } 928 929 StackFrame* frame = stackTrace->FrameAt(0); 930 FunctionDebugInfo* info = frame->Function()->GetFunctionDebugInfo(); 931 if (info == NULL) 932 return false; 933 934 SpecificImageDebugInfo* specificInfo 935 = info->GetSpecificImageDebugInfo(); 936 if (specificInfo == NULL) 937 return false; 938 939 SourceLanguage* language; 940 if (specificInfo->GetSourceLanguage(info, language) != B_OK) 941 return false; 942 943 BReference<SourceLanguage> reference(language, true); 944 ExpressionEvaluationListener* listener 945 = new(std::nothrow) ExpressionEvaluationListener(this); 946 if (listener == NULL) 947 return false; 948 949 ExpressionInfo* expressionInfo = new(std::nothrow) ExpressionInfo( 950 userBreakpoint->Condition()); 951 952 if (expressionInfo == NULL) { 953 delete listener; 954 return false; 955 } 956 957 BReference<ExpressionInfo> expressionReference(expressionInfo, true); 958 959 expressionInfo->AddListener(listener); 960 961 status_t error = fWorker->ScheduleJob( 962 new(std::nothrow) ExpressionEvaluationJob(fThread->GetTeam(), 963 fDebuggerInterface, language, expressionInfo, frame, fThread), 964 fJobListener); 965 966 BPrivate::ObjectDeleter<ExpressionEvaluationListener> deleter( 967 listener); 968 if (error == B_OK) { 969 teamLocker.Unlock(); 970 do { 971 error = acquire_sem(fConditionWaitSem); 972 } while (error == B_INTERRUPTED); 973 974 teamLocker.Lock(); 975 976 if (_CheckStopCondition()) { 977 if (fConditionResult != NULL) { 978 fConditionResult->ReleaseReference(); 979 fConditionResult = NULL; 980 } 981 _SetThreadState(THREAD_STATE_STOPPED, cpuState, 982 THREAD_STOPPED_BREAKPOINT, BString()); 983 return false; 984 } else { 985 fDebuggerInterface->ContinueThread(ThreadID()); 986 return true; 987 } 988 } 989 } 990 991 return false; 992 } 993 994 995 void 996 ThreadHandler::_HandleBreakpointConditionEvaluated(ExpressionResult* value) 997 { 998 fConditionResult = value; 999 if (fConditionResult != NULL) 1000 fConditionResult->AcquireReference(); 1001 release_sem(fConditionWaitSem); 1002 } 1003 1004 1005 bool 1006 ThreadHandler::_CheckStopCondition() 1007 { 1008 // if we we're unable to properly assess the expression result 1009 // in any way, fall back to behaving like an unconditional breakpoint. 1010 if (fConditionResult == NULL) 1011 return true; 1012 1013 if (fConditionResult->Kind() != EXPRESSION_RESULT_KIND_PRIMITIVE) 1014 return true; 1015 1016 BVariant value; 1017 if (!fConditionResult->PrimitiveValue()->ToVariant(value)) 1018 return true; 1019 1020 return value.ToBool(); 1021 } 1022 1023 1024 bool 1025 ThreadHandler::_HasExitedFrame(target_addr_t framePointer) const 1026 { 1027 return fDebuggerInterface->GetArchitecture()->StackGrowthDirection() 1028 == STACK_GROWTH_DIRECTION_POSITIVE 1029 ? framePointer < fPreviousFrameAddress 1030 : framePointer > fPreviousFrameAddress; 1031 } 1032