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 "controllers/TeamDebugger.h" 9 10 #include <stdarg.h> 11 #include <stdio.h> 12 13 #include <new> 14 15 #include <Entry.h> 16 #include <InterfaceDefs.h> 17 #include <Message.h> 18 #include <StringList.h> 19 20 #include <AutoDeleter.h> 21 #include <AutoLocker.h> 22 23 #include "debug_utils.h" 24 #include "syscall_numbers.h" 25 26 #include "Architecture.h" 27 #include "BreakpointManager.h" 28 #include "BreakpointSetting.h" 29 #include "CpuState.h" 30 #include "DebugEvent.h" 31 #include "DebuggerInterface.h" 32 #include "DebugReportGenerator.h" 33 #include "ExpressionInfo.h" 34 #include "FileManager.h" 35 #include "Function.h" 36 #include "FunctionID.h" 37 #include "ImageDebugInfo.h" 38 #include "ImageDebugInfoLoadingState.h" 39 #include "ImageDebugLoadingStateHandler.h" 40 #include "ImageDebugLoadingStateHandlerRoster.h" 41 #include "Jobs.h" 42 #include "LocatableFile.h" 43 #include "MessageCodes.h" 44 #include "NoOpSettingsManager.h" 45 #include "SettingsManager.h" 46 #include "SourceCode.h" 47 #include "SourceLanguage.h" 48 #include "SpecificImageDebugInfo.h" 49 #include "SpecificImageDebugInfoLoadingState.h" 50 #include "StackFrame.h" 51 #include "StackFrameValues.h" 52 #include "Statement.h" 53 #include "SymbolInfo.h" 54 #include "TeamDebugInfo.h" 55 #include "TeamInfo.h" 56 #include "TeamMemoryBlock.h" 57 #include "TeamMemoryBlockManager.h" 58 #include "TeamSettings.h" 59 #include "TeamSignalSettings.h" 60 #include "TeamUiSettings.h" 61 #include "Tracing.h" 62 #include "ValueNode.h" 63 #include "ValueNodeContainer.h" 64 #include "Variable.h" 65 #include "WatchpointManager.h" 66 67 68 // #pragma mark - ImageHandler 69 70 71 struct TeamDebugger::ImageHandler : public BReferenceable, 72 private LocatableFile::Listener { 73 public: 74 ImageHandler(TeamDebugger* teamDebugger, Image* image) 75 : 76 fTeamDebugger(teamDebugger), 77 fImage(image) 78 { 79 fImage->AcquireReference(); 80 if (fImage->ImageFile() != NULL) 81 fImage->ImageFile()->AddListener(this); 82 } 83 84 ~ImageHandler() 85 { 86 if (fImage->ImageFile() != NULL) 87 fImage->ImageFile()->RemoveListener(this); 88 fImage->ReleaseReference(); 89 } 90 91 Image* GetImage() const 92 { 93 return fImage; 94 } 95 96 image_id ImageID() const 97 { 98 return fImage->ID(); 99 } 100 101 private: 102 // LocatableFile::Listener 103 virtual void LocatableFileChanged(LocatableFile* file) 104 { 105 BMessage message(MSG_IMAGE_FILE_CHANGED); 106 message.AddInt32("image", fImage->ID()); 107 fTeamDebugger->PostMessage(&message); 108 } 109 110 private: 111 TeamDebugger* fTeamDebugger; 112 Image* fImage; 113 114 public: 115 ImageHandler* fNext; 116 }; 117 118 119 // #pragma mark - ImageHandlerHashDefinition 120 121 122 struct TeamDebugger::ImageHandlerHashDefinition { 123 typedef image_id KeyType; 124 typedef ImageHandler ValueType; 125 126 size_t HashKey(image_id key) const 127 { 128 return (size_t)key; 129 } 130 131 size_t Hash(const ImageHandler* value) const 132 { 133 return HashKey(value->ImageID()); 134 } 135 136 bool Compare(image_id key, const ImageHandler* value) const 137 { 138 return value->ImageID() == key; 139 } 140 141 ImageHandler*& GetLink(ImageHandler* value) const 142 { 143 return value->fNext; 144 } 145 }; 146 147 148 // #pragma mark - ImageInfoPendingThread 149 150 151 struct TeamDebugger::ImageInfoPendingThread { 152 public: 153 ImageInfoPendingThread(image_id image, thread_id thread) 154 : 155 fImage(image), 156 fThread(thread) 157 { 158 } 159 160 ~ImageInfoPendingThread() 161 { 162 } 163 164 image_id ImageID() const 165 { 166 return fImage; 167 } 168 169 thread_id ThreadID() const 170 { 171 return fThread; 172 } 173 174 private: 175 image_id fImage; 176 thread_id fThread; 177 178 public: 179 ImageInfoPendingThread* fNext; 180 }; 181 182 183 // #pragma mark - ImageHandlerHashDefinition 184 185 186 struct TeamDebugger::ImageInfoPendingThreadHashDefinition { 187 typedef image_id KeyType; 188 typedef ImageInfoPendingThread ValueType; 189 190 size_t HashKey(image_id key) const 191 { 192 return (size_t)key; 193 } 194 195 size_t Hash(const ImageInfoPendingThread* value) const 196 { 197 return HashKey(value->ImageID()); 198 } 199 200 bool Compare(image_id key, const ImageInfoPendingThread* value) const 201 { 202 return value->ImageID() == key; 203 } 204 205 ImageInfoPendingThread*& GetLink(ImageInfoPendingThread* value) const 206 { 207 return value->fNext; 208 } 209 }; 210 211 212 // #pragma mark - TeamDebugger 213 214 215 TeamDebugger::TeamDebugger(Listener* listener, UserInterface* userInterface, 216 SettingsManager* settingsManager) 217 : 218 BLooper("team debugger"), 219 fListener(listener), 220 fSettingsManager(settingsManager), 221 fTeam(NULL), 222 fTeamID(-1), 223 fIsPostMortem(false), 224 fImageHandlers(NULL), 225 fImageInfoPendingThreads(NULL), 226 fDebuggerInterface(NULL), 227 fFileManager(NULL), 228 fWorker(NULL), 229 fBreakpointManager(NULL), 230 fWatchpointManager(NULL), 231 fMemoryBlockManager(NULL), 232 fReportGenerator(NULL), 233 fDebugEventListener(-1), 234 fUserInterface(userInterface), 235 fTerminating(false), 236 fKillTeamOnQuit(false), 237 fCommandLineArgc(0), 238 fCommandLineArgv(NULL), 239 fExecPending(false) 240 { 241 fUserInterface->AcquireReference(); 242 } 243 244 245 TeamDebugger::~TeamDebugger() 246 { 247 if (fTeam != NULL) 248 _SaveSettings(); 249 250 AutoLocker<BLooper> locker(this); 251 252 fTerminating = true; 253 254 if (fDebuggerInterface != NULL) { 255 fDebuggerInterface->Close(fKillTeamOnQuit); 256 fDebuggerInterface->ReleaseReference(); 257 } 258 259 if (fWorker != NULL) 260 fWorker->ShutDown(); 261 262 locker.Unlock(); 263 264 if (fDebugEventListener >= 0) 265 wait_for_thread(fDebugEventListener, NULL); 266 267 // terminate UI 268 if (fUserInterface != NULL) { 269 fUserInterface->Terminate(); 270 fUserInterface->ReleaseReference(); 271 } 272 273 ThreadHandler* threadHandler = fThreadHandlers.Clear(true); 274 while (threadHandler != NULL) { 275 ThreadHandler* next = threadHandler->fNext; 276 threadHandler->ReleaseReference(); 277 threadHandler = next; 278 } 279 280 if (fImageHandlers != NULL) { 281 ImageHandler* imageHandler = fImageHandlers->Clear(true); 282 while (imageHandler != NULL) { 283 ImageHandler* next = imageHandler->fNext; 284 imageHandler->ReleaseReference(); 285 imageHandler = next; 286 } 287 } 288 289 delete fImageHandlers; 290 291 if (fImageInfoPendingThreads != NULL) { 292 ImageInfoPendingThread* thread = fImageInfoPendingThreads->Clear(true); 293 while (thread != NULL) { 294 ImageInfoPendingThread* next = thread->fNext; 295 delete thread; 296 thread = next; 297 } 298 } 299 300 if (fReportGenerator != NULL) { 301 fReportGenerator->Lock(); 302 fReportGenerator->Quit(); 303 } 304 305 delete fWorker; 306 307 delete fImageInfoPendingThreads; 308 309 delete fBreakpointManager; 310 delete fWatchpointManager; 311 delete fMemoryBlockManager; 312 delete fTeam; 313 delete fFileManager; 314 315 for (int i = 0; i < fCommandLineArgc; i++) { 316 if (fCommandLineArgv[i] != NULL) 317 free(const_cast<char*>(fCommandLineArgv[i])); 318 } 319 320 delete [] fCommandLineArgv; 321 322 fListener->TeamDebuggerQuit(this); 323 } 324 325 326 status_t 327 TeamDebugger::Init(DebuggerInterface* interface, thread_id threadID, int argc, 328 const char* const* argv, bool stopInMain) 329 { 330 bool targetIsLocal = true; 331 // TODO: Support non-local targets! 332 333 // the first thing we want to do when running 334 PostMessage(MSG_LOAD_SETTINGS); 335 336 status_t error = _HandleSetArguments(argc, argv); 337 if (error != B_OK) 338 return error; 339 340 if (fSettingsManager == NULL) { 341 // if we have not been provided with a settings manager, 342 // simply use the no-op manager by default. 343 fSettingsManager = new(std::nothrow) NoOpSettingsManager; 344 if (fSettingsManager == NULL) 345 return B_NO_MEMORY; 346 } 347 348 fDebuggerInterface = interface; 349 fDebuggerInterface->AcquireReference(); 350 fTeamID = interface->TeamID(); 351 fIsPostMortem = interface->IsPostMortem(); 352 353 354 // create file manager 355 fFileManager = new(std::nothrow) FileManager; 356 if (fFileManager == NULL) 357 return B_NO_MEMORY; 358 359 error = fFileManager->Init(targetIsLocal); 360 if (error != B_OK) 361 return error; 362 363 // create team debug info 364 TeamDebugInfo* teamDebugInfo = new(std::nothrow) TeamDebugInfo( 365 fDebuggerInterface, fDebuggerInterface->GetArchitecture(), 366 fFileManager); 367 if (teamDebugInfo == NULL) 368 return B_NO_MEMORY; 369 BReference<TeamDebugInfo> teamDebugInfoReference(teamDebugInfo); 370 371 error = teamDebugInfo->Init(); 372 if (error != B_OK) 373 return error; 374 375 // check whether the team exists at all 376 TeamInfo teamInfo; 377 error = fDebuggerInterface->GetTeamInfo(teamInfo); 378 if (error != B_OK) 379 return error; 380 381 // create a team object 382 fTeam = new(std::nothrow) ::Team(fTeamID, fDebuggerInterface, 383 fDebuggerInterface->GetArchitecture(), teamDebugInfo, 384 teamDebugInfo); 385 if (fTeam == NULL) 386 return B_NO_MEMORY; 387 388 error = fTeam->Init(); 389 if (error != B_OK) 390 return error; 391 fTeam->SetName(teamInfo.Arguments()); 392 // TODO: Set a better name! 393 394 fTeam->AddListener(this); 395 396 // init thread handler table 397 error = fThreadHandlers.Init(); 398 if (error != B_OK) 399 return error; 400 401 // create image handler table 402 fImageHandlers = new(std::nothrow) ImageHandlerTable; 403 if (fImageHandlers == NULL) 404 return B_NO_MEMORY; 405 406 error = fImageHandlers->Init(); 407 if (error != B_OK) 408 return error; 409 410 fImageInfoPendingThreads = new(std::nothrow) ImageInfoPendingThreadTable; 411 if (fImageInfoPendingThreads == NULL) 412 return B_NO_MEMORY; 413 414 // create our worker 415 fWorker = new(std::nothrow) Worker; 416 if (fWorker == NULL) 417 return B_NO_MEMORY; 418 419 error = fWorker->Init(); 420 if (error != B_OK) 421 return error; 422 423 // create the breakpoint manager 424 fBreakpointManager = new(std::nothrow) BreakpointManager(fTeam, 425 fDebuggerInterface); 426 if (fBreakpointManager == NULL) 427 return B_NO_MEMORY; 428 429 error = fBreakpointManager->Init(); 430 if (error != B_OK) 431 return error; 432 433 // create the watchpoint manager 434 fWatchpointManager = new(std::nothrow) WatchpointManager(fTeam, 435 fDebuggerInterface); 436 if (fWatchpointManager == NULL) 437 return B_NO_MEMORY; 438 439 error = fWatchpointManager->Init(); 440 if (error != B_OK) 441 return error; 442 443 // create the memory block manager 444 fMemoryBlockManager = new(std::nothrow) TeamMemoryBlockManager(); 445 if (fMemoryBlockManager == NULL) 446 return B_NO_MEMORY; 447 448 error = fMemoryBlockManager->Init(); 449 if (error != B_OK) 450 return error; 451 452 // create the debug report generator 453 fReportGenerator = new(std::nothrow) DebugReportGenerator(fTeam, this, 454 fDebuggerInterface); 455 if (fReportGenerator == NULL) 456 return B_NO_MEMORY; 457 458 error = fReportGenerator->Init(); 459 if (error != B_OK) 460 return error; 461 462 // set team debugging flags 463 fDebuggerInterface->SetTeamDebuggingFlags( 464 B_TEAM_DEBUG_THREADS | B_TEAM_DEBUG_IMAGES 465 | B_TEAM_DEBUG_POST_SYSCALL | B_TEAM_DEBUG_SIGNALS 466 | B_TEAM_DEBUG_TEAM_CREATION); 467 468 // get the initial state of the team 469 AutoLocker< ::Team> teamLocker(fTeam); 470 471 ThreadHandler* mainThreadHandler = NULL; 472 { 473 BObjectList<ThreadInfo> threadInfos(20, true); 474 status_t error = fDebuggerInterface->GetThreadInfos(threadInfos); 475 for (int32 i = 0; ThreadInfo* info = threadInfos.ItemAt(i); i++) { 476 ::Thread* thread; 477 error = fTeam->AddThread(*info, &thread); 478 if (error != B_OK) 479 return error; 480 481 ThreadHandler* handler = new(std::nothrow) ThreadHandler(thread, 482 fWorker, fDebuggerInterface, this, fBreakpointManager); 483 if (handler == NULL) 484 return B_NO_MEMORY; 485 486 fThreadHandlers.Insert(handler); 487 488 if (thread->IsMainThread()) 489 mainThreadHandler = handler; 490 491 handler->Init(); 492 } 493 } 494 495 Image* appImage = NULL; 496 { 497 BObjectList<ImageInfo> imageInfos(20, true); 498 status_t error = fDebuggerInterface->GetImageInfos(imageInfos); 499 for (int32 i = 0; ImageInfo* info = imageInfos.ItemAt(i); i++) { 500 Image* image; 501 error = _AddImage(*info, &image); 502 if (error != B_OK) 503 return error; 504 if (image->Type() == B_APP_IMAGE) 505 appImage = image; 506 507 ImageDebugInfoRequested(image); 508 } 509 } 510 511 // create the debug event listener (for live debugging only) 512 if (!fDebuggerInterface->IsPostMortem()) { 513 char buffer[128]; 514 snprintf(buffer, sizeof(buffer), "team %" B_PRId32 " debug listener", 515 fTeamID); 516 fDebugEventListener = spawn_thread(_DebugEventListenerEntry, buffer, 517 B_NORMAL_PRIORITY, this); 518 if (fDebugEventListener < 0) 519 return fDebugEventListener; 520 521 resume_thread(fDebugEventListener); 522 } 523 524 // run looper 525 thread_id looperThread = Run(); 526 if (looperThread < 0) 527 return looperThread; 528 529 // init the UI 530 error = fUserInterface->Init(fTeam, this); 531 if (error != B_OK) { 532 ERROR("Error: Failed to init the UI: %s\n", strerror(error)); 533 return error; 534 } 535 536 // if requested, stop the given thread 537 if (threadID >= 0 && !fDebuggerInterface->IsPostMortem()) { 538 if (stopInMain) { 539 SymbolInfo symbolInfo; 540 if (appImage != NULL && mainThreadHandler != NULL 541 && fDebuggerInterface->GetSymbolInfo( 542 fTeam->ID(), appImage->ID(), "main", B_SYMBOL_TYPE_TEXT, 543 symbolInfo) == B_OK) { 544 mainThreadHandler->SetBreakpointAndRun(symbolInfo.Address()); 545 } 546 } else { 547 debug_thread(threadID); 548 // TODO: Superfluous, if the thread is already stopped. 549 } 550 } 551 552 fListener->TeamDebuggerStarted(this); 553 554 return B_OK; 555 } 556 557 558 void 559 TeamDebugger::Activate() 560 { 561 fUserInterface->Show(); 562 } 563 564 565 void 566 TeamDebugger::MessageReceived(BMessage* message) 567 { 568 switch (message->what) { 569 case MSG_THREAD_RUN: 570 case MSG_THREAD_SET_ADDRESS: 571 case MSG_THREAD_STOP: 572 case MSG_THREAD_STEP_OVER: 573 case MSG_THREAD_STEP_INTO: 574 case MSG_THREAD_STEP_OUT: 575 { 576 int32 threadID; 577 target_addr_t address; 578 if (message->FindInt32("thread", &threadID) != B_OK) 579 break; 580 581 if (message->FindUInt64("address", &address) != B_OK) 582 address = 0; 583 584 if (ThreadHandler* handler = _GetThreadHandler(threadID)) { 585 handler->HandleThreadAction(message->what, address); 586 handler->ReleaseReference(); 587 } 588 break; 589 } 590 591 case MSG_SET_BREAKPOINT: 592 case MSG_CLEAR_BREAKPOINT: 593 { 594 UserBreakpoint* breakpoint = NULL; 595 BReference<UserBreakpoint> breakpointReference; 596 uint64 address = 0; 597 598 if (message->FindPointer("breakpoint", (void**)&breakpoint) 599 == B_OK) { 600 breakpointReference.SetTo(breakpoint, true); 601 } else if (message->FindUInt64("address", &address) != B_OK) 602 break; 603 604 if (message->what == MSG_SET_BREAKPOINT) { 605 bool enabled; 606 if (message->FindBool("enabled", &enabled) != B_OK) 607 enabled = true; 608 609 bool hidden; 610 if (message->FindBool("hidden", &hidden) != B_OK) 611 hidden = false; 612 613 if (breakpoint != NULL) 614 _HandleSetUserBreakpoint(breakpoint, enabled); 615 else 616 _HandleSetUserBreakpoint(address, enabled, hidden); 617 } else { 618 if (breakpoint != NULL) 619 _HandleClearUserBreakpoint(breakpoint); 620 else 621 _HandleClearUserBreakpoint(address); 622 } 623 624 break; 625 } 626 627 case MSG_SET_BREAKPOINT_CONDITION: 628 { 629 UserBreakpoint* breakpoint = NULL; 630 BReference<UserBreakpoint> breakpointReference; 631 if (message->FindPointer("breakpoint", (void**)&breakpoint) 632 != B_OK) { 633 break; 634 } 635 636 breakpointReference.SetTo(breakpoint, true); 637 638 const char* condition; 639 if (message->FindString("condition", &condition) != B_OK) 640 break; 641 642 AutoLocker< ::Team> teamLocker(fTeam); 643 breakpoint->SetCondition(condition); 644 fTeam->NotifyUserBreakpointChanged(breakpoint); 645 646 break; 647 } 648 649 case MSG_CLEAR_BREAKPOINT_CONDITION: 650 { 651 UserBreakpoint* breakpoint = NULL; 652 BReference<UserBreakpoint> breakpointReference; 653 if (message->FindPointer("breakpoint", (void**)&breakpoint) 654 != B_OK) 655 break; 656 657 breakpointReference.SetTo(breakpoint, true); 658 659 AutoLocker< ::Team> teamLocker(fTeam); 660 breakpoint->SetCondition(NULL); 661 fTeam->NotifyUserBreakpointChanged(breakpoint); 662 663 break; 664 } 665 666 case MSG_STOP_ON_IMAGE_LOAD: 667 { 668 bool enabled; 669 bool useNames; 670 if (message->FindBool("enabled", &enabled) != B_OK) 671 break; 672 673 if (message->FindBool("useNames", &useNames) != B_OK) 674 break; 675 676 AutoLocker< ::Team> teamLocker(fTeam); 677 fTeam->SetStopOnImageLoad(enabled, useNames); 678 break; 679 } 680 681 case MSG_ADD_STOP_IMAGE_NAME: 682 { 683 BString imageName; 684 if (message->FindString("name", &imageName) != B_OK) 685 break; 686 687 AutoLocker< ::Team> teamLocker(fTeam); 688 fTeam->AddStopImageName(imageName); 689 break; 690 } 691 692 case MSG_REMOVE_STOP_IMAGE_NAME: 693 { 694 BString imageName; 695 if (message->FindString("name", &imageName) != B_OK) 696 break; 697 698 AutoLocker< ::Team> teamLocker(fTeam); 699 fTeam->RemoveStopImageName(imageName); 700 break; 701 } 702 703 case MSG_SET_DEFAULT_SIGNAL_DISPOSITION: 704 { 705 int32 disposition; 706 if (message->FindInt32("disposition", &disposition) != B_OK) 707 break; 708 709 AutoLocker< ::Team> teamLocker(fTeam); 710 fTeam->SetDefaultSignalDisposition(disposition); 711 break; 712 } 713 714 case MSG_SET_CUSTOM_SIGNAL_DISPOSITION: 715 { 716 int32 signal; 717 int32 disposition; 718 if (message->FindInt32("signal", &signal) != B_OK 719 || message->FindInt32("disposition", &disposition) != B_OK) { 720 break; 721 } 722 723 AutoLocker< ::Team> teamLocker(fTeam); 724 fTeam->SetCustomSignalDisposition(signal, disposition); 725 break; 726 } 727 728 case MSG_REMOVE_CUSTOM_SIGNAL_DISPOSITION: 729 { 730 int32 signal; 731 if (message->FindInt32("signal", &signal) != B_OK) 732 break; 733 734 AutoLocker< ::Team> teamLocker(fTeam); 735 fTeam->RemoveCustomSignalDisposition(signal); 736 break; 737 } 738 739 case MSG_SET_WATCHPOINT: 740 case MSG_CLEAR_WATCHPOINT: 741 { 742 Watchpoint* watchpoint = NULL; 743 BReference<Watchpoint> watchpointReference; 744 uint64 address = 0; 745 uint32 type = 0; 746 int32 length = 0; 747 748 if (message->FindPointer("watchpoint", (void**)&watchpoint) 749 == B_OK) { 750 watchpointReference.SetTo(watchpoint, true); 751 } else if (message->FindUInt64("address", &address) != B_OK) 752 break; 753 754 if (message->what == MSG_SET_WATCHPOINT) { 755 if (watchpoint == NULL && (message->FindUInt32("type", &type) 756 != B_OK 757 || message->FindInt32("length", &length) != B_OK)) { 758 break; 759 } 760 761 bool enabled; 762 if (message->FindBool("enabled", &enabled) != B_OK) 763 enabled = true; 764 765 if (watchpoint != NULL) 766 _HandleSetWatchpoint(watchpoint, enabled); 767 else 768 _HandleSetWatchpoint(address, type, length, enabled); 769 } else { 770 if (watchpoint != NULL) 771 _HandleClearWatchpoint(watchpoint); 772 else 773 _HandleClearWatchpoint(address); 774 } 775 776 break; 777 } 778 779 case MSG_INSPECT_ADDRESS: 780 { 781 TeamMemoryBlock::Listener* listener; 782 if (message->FindPointer("listener", 783 reinterpret_cast<void **>(&listener)) != B_OK) { 784 break; 785 } 786 787 target_addr_t address; 788 if (message->FindUInt64("address", 789 &address) == B_OK) { 790 _HandleInspectAddress(address, listener); 791 } 792 break; 793 } 794 795 case MSG_WRITE_TARGET_MEMORY: 796 { 797 target_addr_t address; 798 if (message->FindUInt64("address", &address) != B_OK) 799 break; 800 801 void* data; 802 if (message->FindPointer("data", &data) != B_OK) 803 break; 804 805 target_size_t size; 806 if (message->FindUInt64("size", &size) != B_OK) 807 break; 808 809 _HandleWriteMemory(address, data, size); 810 break; 811 } 812 813 case MSG_EVALUATE_EXPRESSION: 814 { 815 SourceLanguage* language; 816 if (message->FindPointer("language", 817 reinterpret_cast<void**>(&language)) != B_OK) { 818 break; 819 } 820 821 // ExpressionEvaluationRequested() acquires a reference 822 // to both the language and the expression info on our behalf. 823 BReference<SourceLanguage> reference(language, true); 824 825 ExpressionInfo* info; 826 if (message->FindPointer("info", 827 reinterpret_cast<void**>(&info)) != B_OK) { 828 break; 829 } 830 831 BReference<ExpressionInfo> infoReference(info, true); 832 833 StackFrame* frame; 834 if (message->FindPointer("frame", 835 reinterpret_cast<void**>(&frame)) != B_OK) { 836 // the stack frame isn't needed, unless variable 837 // evaluation is desired. 838 frame = NULL; 839 } 840 841 ::Thread* thread; 842 if (message->FindPointer("thread", 843 reinterpret_cast<void**>(&thread)) != B_OK) { 844 // the thread isn't needed, unless variable 845 // evaluation is desired. 846 thread = NULL; 847 } 848 849 _HandleEvaluateExpression(language, info, frame, thread); 850 break; 851 } 852 853 case MSG_GENERATE_DEBUG_REPORT: 854 { 855 fReportGenerator->PostMessage(message); 856 break; 857 } 858 859 case MSG_WRITE_CORE_FILE: 860 { 861 entry_ref ref; 862 if (message->FindRef("target", &ref) != B_OK) 863 break; 864 865 _HandleWriteCoreFile(ref); 866 break; 867 } 868 869 case MSG_THREAD_STATE_CHANGED: 870 { 871 int32 threadID; 872 if (message->FindInt32("thread", &threadID) != B_OK) 873 break; 874 875 if (ThreadHandler* handler = _GetThreadHandler(threadID)) { 876 handler->HandleThreadStateChanged(); 877 handler->ReleaseReference(); 878 } 879 break; 880 } 881 case MSG_THREAD_CPU_STATE_CHANGED: 882 { 883 int32 threadID; 884 if (message->FindInt32("thread", &threadID) != B_OK) 885 break; 886 887 if (ThreadHandler* handler = _GetThreadHandler(threadID)) { 888 handler->HandleCpuStateChanged(); 889 handler->ReleaseReference(); 890 } 891 break; 892 } 893 case MSG_THREAD_STACK_TRACE_CHANGED: 894 { 895 int32 threadID; 896 if (message->FindInt32("thread", &threadID) != B_OK) 897 break; 898 899 if (ThreadHandler* handler = _GetThreadHandler(threadID)) { 900 handler->HandleStackTraceChanged(); 901 handler->ReleaseReference(); 902 } 903 break; 904 } 905 906 case MSG_IMAGE_DEBUG_INFO_CHANGED: 907 { 908 int32 imageID; 909 if (message->FindInt32("image", &imageID) != B_OK) 910 break; 911 912 _HandleImageDebugInfoChanged(imageID); 913 break; 914 } 915 916 case MSG_IMAGE_FILE_CHANGED: 917 { 918 int32 imageID; 919 if (message->FindInt32("image", &imageID) != B_OK) 920 break; 921 922 _HandleImageFileChanged(imageID); 923 break; 924 } 925 926 case MSG_DEBUGGER_EVENT: 927 { 928 DebugEvent* event; 929 if (message->FindPointer("event", (void**)&event) != B_OK) 930 break; 931 932 _HandleDebuggerMessage(event); 933 delete event; 934 break; 935 } 936 937 case MSG_LOAD_SETTINGS: 938 _LoadSettings(); 939 Activate(); 940 break; 941 942 case MSG_TEAM_RESTART_REQUESTED: 943 { 944 if (fCommandLineArgc == 0) 945 break; 946 947 _SaveSettings(); 948 fListener->TeamDebuggerRestartRequested(this); 949 break; 950 } 951 952 case MSG_DEBUG_INFO_NEEDS_USER_INPUT: 953 { 954 Job* job; 955 ImageDebugInfoLoadingState* state; 956 if (message->FindPointer("job", (void**)&job) != B_OK) 957 break; 958 if (message->FindPointer("state", (void**)&state) != B_OK) 959 break; 960 961 _HandleDebugInfoJobUserInput(state); 962 fWorker->ResumeJob(job); 963 break; 964 } 965 966 default: 967 BLooper::MessageReceived(message); 968 break; 969 } 970 } 971 972 973 void 974 TeamDebugger::SourceEntryLocateRequested(const char* sourcePath, 975 const char* locatedPath) 976 { 977 AutoLocker<FileManager> locker(fFileManager); 978 fFileManager->SourceEntryLocated(sourcePath, locatedPath); 979 } 980 981 982 void 983 TeamDebugger::SourceEntryInvalidateRequested(LocatableFile* sourceFile) 984 { 985 AutoLocker< ::Team> locker(fTeam); 986 987 fTeam->DebugInfo()->ClearSourceCode(sourceFile); 988 } 989 990 991 void 992 TeamDebugger::FunctionSourceCodeRequested(FunctionInstance* functionInstance, 993 bool forceDisassembly) 994 { 995 Function* function = functionInstance->GetFunction(); 996 997 // mark loading 998 AutoLocker< ::Team> locker(fTeam); 999 1000 if (forceDisassembly && functionInstance->SourceCodeState() 1001 != FUNCTION_SOURCE_NOT_LOADED) { 1002 return; 1003 } else if (!forceDisassembly && function->SourceCodeState() 1004 == FUNCTION_SOURCE_LOADED) { 1005 return; 1006 } 1007 1008 functionInstance->SetSourceCode(NULL, FUNCTION_SOURCE_LOADING); 1009 1010 bool loadForFunction = false; 1011 if (!forceDisassembly && function->SourceCodeState() 1012 == FUNCTION_SOURCE_NOT_LOADED) { 1013 loadForFunction = true; 1014 function->SetSourceCode(NULL, FUNCTION_SOURCE_LOADING); 1015 } 1016 1017 locker.Unlock(); 1018 1019 // schedule the job 1020 if (fWorker->ScheduleJob( 1021 new(std::nothrow) LoadSourceCodeJob(fDebuggerInterface, 1022 fDebuggerInterface->GetArchitecture(), fTeam, functionInstance, 1023 loadForFunction), 1024 this) != B_OK) { 1025 // scheduling failed -- mark unavailable 1026 locker.Lock(); 1027 function->SetSourceCode(NULL, FUNCTION_SOURCE_UNAVAILABLE); 1028 locker.Unlock(); 1029 } 1030 } 1031 1032 1033 void 1034 TeamDebugger::ImageDebugInfoRequested(Image* image) 1035 { 1036 LoadImageDebugInfoJob::ScheduleIfNecessary(fWorker, image, this); 1037 } 1038 1039 1040 void 1041 TeamDebugger::ValueNodeValueRequested(CpuState* cpuState, 1042 ValueNodeContainer* container, ValueNode* valueNode) 1043 { 1044 AutoLocker<ValueNodeContainer> containerLocker(container); 1045 if (valueNode->Container() != container) 1046 return; 1047 1048 // check whether a job is already in progress 1049 AutoLocker<Worker> workerLocker(fWorker); 1050 SimpleJobKey jobKey(valueNode, JOB_TYPE_RESOLVE_VALUE_NODE_VALUE); 1051 if (fWorker->GetJob(jobKey) != NULL) 1052 return; 1053 workerLocker.Unlock(); 1054 1055 // schedule the job 1056 status_t error = fWorker->ScheduleJob( 1057 new(std::nothrow) ResolveValueNodeValueJob(fDebuggerInterface, 1058 fDebuggerInterface->GetArchitecture(), cpuState, 1059 fTeam->GetTeamTypeInformation(), container, valueNode), this); 1060 if (error != B_OK) { 1061 // scheduling failed -- set the value to invalid 1062 valueNode->SetLocationAndValue(NULL, NULL, error); 1063 } 1064 } 1065 1066 void 1067 TeamDebugger::ValueNodeWriteRequested(ValueNode* node, CpuState* state, 1068 Value* newValue) 1069 { 1070 // schedule the job 1071 status_t error = fWorker->ScheduleJob( 1072 new(std::nothrow) WriteValueNodeValueJob(fDebuggerInterface, 1073 fDebuggerInterface->GetArchitecture(), state, 1074 fTeam->GetTeamTypeInformation(), node, newValue), this); 1075 if (error != B_OK) { 1076 BString message; 1077 message.SetToFormat("Request to write new value for variable %s " 1078 "failed: %s.\n", node->Name().String(), strerror(error)); 1079 fUserInterface->NotifyUser("Error", message.String(), 1080 USER_NOTIFICATION_ERROR); 1081 } 1082 } 1083 1084 1085 void 1086 TeamDebugger::ThreadActionRequested(thread_id threadID, 1087 uint32 action, target_addr_t address) 1088 { 1089 BMessage message(action); 1090 message.AddInt32("thread", threadID); 1091 message.AddUInt64("address", address); 1092 PostMessage(&message); 1093 } 1094 1095 1096 void 1097 TeamDebugger::SetBreakpointRequested(target_addr_t address, bool enabled, 1098 bool hidden) 1099 { 1100 BMessage message(MSG_SET_BREAKPOINT); 1101 message.AddUInt64("address", (uint64)address); 1102 message.AddBool("enabled", enabled); 1103 message.AddBool("hidden", hidden); 1104 PostMessage(&message); 1105 } 1106 1107 1108 void 1109 TeamDebugger::SetBreakpointEnabledRequested(UserBreakpoint* breakpoint, 1110 bool enabled) 1111 { 1112 BMessage message(MSG_SET_BREAKPOINT); 1113 BReference<UserBreakpoint> breakpointReference(breakpoint); 1114 if (message.AddPointer("breakpoint", breakpoint) == B_OK 1115 && message.AddBool("enabled", enabled) == B_OK 1116 && PostMessage(&message) == B_OK) { 1117 breakpointReference.Detach(); 1118 } 1119 } 1120 1121 1122 void 1123 TeamDebugger::SetBreakpointConditionRequested(UserBreakpoint* breakpoint, 1124 const char* condition) 1125 { 1126 BMessage message(MSG_SET_BREAKPOINT_CONDITION); 1127 BReference<UserBreakpoint> breakpointReference(breakpoint); 1128 if (message.AddPointer("breakpoint", breakpoint) == B_OK 1129 && message.AddString("condition", condition) == B_OK 1130 && PostMessage(&message) == B_OK) { 1131 breakpointReference.Detach(); 1132 } 1133 } 1134 1135 1136 void 1137 TeamDebugger::ClearBreakpointConditionRequested(UserBreakpoint* breakpoint) 1138 { 1139 BMessage message(MSG_CLEAR_BREAKPOINT_CONDITION); 1140 BReference<UserBreakpoint> breakpointReference(breakpoint); 1141 if (message.AddPointer("breakpoint", breakpoint) == B_OK 1142 && PostMessage(&message) == B_OK) { 1143 breakpointReference.Detach(); 1144 } 1145 } 1146 1147 1148 void 1149 TeamDebugger::ClearBreakpointRequested(target_addr_t address) 1150 { 1151 BMessage message(MSG_CLEAR_BREAKPOINT); 1152 message.AddUInt64("address", (uint64)address); 1153 PostMessage(&message); 1154 } 1155 1156 1157 void 1158 TeamDebugger::SetStopOnImageLoadRequested(bool enabled, bool useImageNames) 1159 { 1160 BMessage message(MSG_STOP_ON_IMAGE_LOAD); 1161 message.AddBool("enabled", enabled); 1162 message.AddBool("useNames", useImageNames); 1163 PostMessage(&message); 1164 } 1165 1166 1167 void 1168 TeamDebugger::AddStopImageNameRequested(const char* name) 1169 { 1170 BMessage message(MSG_ADD_STOP_IMAGE_NAME); 1171 message.AddString("name", name); 1172 PostMessage(&message); 1173 } 1174 1175 1176 void 1177 TeamDebugger::RemoveStopImageNameRequested(const char* name) 1178 { 1179 BMessage message(MSG_REMOVE_STOP_IMAGE_NAME); 1180 message.AddString("name", name); 1181 PostMessage(&message); 1182 } 1183 1184 1185 void 1186 TeamDebugger::SetDefaultSignalDispositionRequested(int32 disposition) 1187 { 1188 BMessage message(MSG_SET_DEFAULT_SIGNAL_DISPOSITION); 1189 message.AddInt32("disposition", disposition); 1190 PostMessage(&message); 1191 } 1192 1193 1194 void 1195 TeamDebugger::SetCustomSignalDispositionRequested(int32 signal, 1196 int32 disposition) 1197 { 1198 BMessage message(MSG_SET_CUSTOM_SIGNAL_DISPOSITION); 1199 message.AddInt32("signal", signal); 1200 message.AddInt32("disposition", disposition); 1201 PostMessage(&message); 1202 } 1203 1204 1205 void 1206 TeamDebugger::RemoveCustomSignalDispositionRequested(int32 signal) 1207 { 1208 BMessage message(MSG_REMOVE_CUSTOM_SIGNAL_DISPOSITION); 1209 message.AddInt32("signal", signal); 1210 PostMessage(&message); 1211 } 1212 1213 1214 void 1215 TeamDebugger::ClearBreakpointRequested(UserBreakpoint* breakpoint) 1216 { 1217 BMessage message(MSG_CLEAR_BREAKPOINT); 1218 BReference<UserBreakpoint> breakpointReference(breakpoint); 1219 if (message.AddPointer("breakpoint", breakpoint) == B_OK 1220 && PostMessage(&message) == B_OK) { 1221 breakpointReference.Detach(); 1222 } 1223 } 1224 1225 1226 void 1227 TeamDebugger::SetWatchpointRequested(target_addr_t address, uint32 type, 1228 int32 length, bool enabled) 1229 { 1230 BMessage message(MSG_SET_WATCHPOINT); 1231 message.AddUInt64("address", (uint64)address); 1232 message.AddUInt32("type", type); 1233 message.AddInt32("length", length); 1234 message.AddBool("enabled", enabled); 1235 PostMessage(&message); 1236 } 1237 1238 1239 void 1240 TeamDebugger::SetWatchpointEnabledRequested(Watchpoint* watchpoint, 1241 bool enabled) 1242 { 1243 BMessage message(MSG_SET_WATCHPOINT); 1244 BReference<Watchpoint> watchpointReference(watchpoint); 1245 if (message.AddPointer("watchpoint", watchpoint) == B_OK 1246 && message.AddBool("enabled", enabled) == B_OK 1247 && PostMessage(&message) == B_OK) { 1248 watchpointReference.Detach(); 1249 } 1250 } 1251 1252 1253 void 1254 TeamDebugger::ClearWatchpointRequested(target_addr_t address) 1255 { 1256 BMessage message(MSG_CLEAR_WATCHPOINT); 1257 message.AddUInt64("address", (uint64)address); 1258 PostMessage(&message); 1259 } 1260 1261 1262 void 1263 TeamDebugger::ClearWatchpointRequested(Watchpoint* watchpoint) 1264 { 1265 BMessage message(MSG_CLEAR_WATCHPOINT); 1266 BReference<Watchpoint> watchpointReference(watchpoint); 1267 if (message.AddPointer("watchpoint", watchpoint) == B_OK 1268 && PostMessage(&message) == B_OK) { 1269 watchpointReference.Detach(); 1270 } 1271 } 1272 1273 1274 void 1275 TeamDebugger::InspectRequested(target_addr_t address, 1276 TeamMemoryBlock::Listener *listener) 1277 { 1278 BMessage message(MSG_INSPECT_ADDRESS); 1279 message.AddUInt64("address", address); 1280 message.AddPointer("listener", listener); 1281 PostMessage(&message); 1282 } 1283 1284 1285 void 1286 TeamDebugger::MemoryWriteRequested(target_addr_t address, const void* data, 1287 target_size_t size) 1288 { 1289 BMessage message(MSG_WRITE_TARGET_MEMORY); 1290 message.AddUInt64("address", address); 1291 message.AddPointer("data", data); 1292 message.AddUInt64("size", size); 1293 PostMessage(&message); 1294 } 1295 1296 1297 void 1298 TeamDebugger::ExpressionEvaluationRequested(SourceLanguage* language, 1299 ExpressionInfo* info, StackFrame* frame, ::Thread* thread) 1300 { 1301 BMessage message(MSG_EVALUATE_EXPRESSION); 1302 message.AddPointer("language", language); 1303 message.AddPointer("info", info); 1304 if (frame != NULL) 1305 message.AddPointer("frame", frame); 1306 if (thread != NULL) 1307 message.AddPointer("thread", thread); 1308 1309 BReference<SourceLanguage> languageReference(language); 1310 BReference<ExpressionInfo> infoReference(info); 1311 if (PostMessage(&message) == B_OK) { 1312 languageReference.Detach(); 1313 infoReference.Detach(); 1314 } 1315 } 1316 1317 1318 void 1319 TeamDebugger::DebugReportRequested(entry_ref* targetPath) 1320 { 1321 BMessage message(MSG_GENERATE_DEBUG_REPORT); 1322 message.AddRef("target", targetPath); 1323 PostMessage(&message); 1324 } 1325 1326 1327 void 1328 TeamDebugger::WriteCoreFileRequested(entry_ref* targetPath) 1329 { 1330 BMessage message(MSG_WRITE_CORE_FILE); 1331 message.AddRef("target", targetPath); 1332 PostMessage(&message); 1333 } 1334 1335 1336 void 1337 TeamDebugger::TeamRestartRequested() 1338 { 1339 PostMessage(MSG_TEAM_RESTART_REQUESTED); 1340 } 1341 1342 1343 bool 1344 TeamDebugger::UserInterfaceQuitRequested(QuitOption quitOption) 1345 { 1346 bool askUser = false; 1347 switch (quitOption) { 1348 case QUIT_OPTION_ASK_USER: 1349 askUser = true; 1350 break; 1351 1352 case QUIT_OPTION_ASK_KILL_TEAM: 1353 fKillTeamOnQuit = true; 1354 break; 1355 1356 case QUIT_OPTION_ASK_RESUME_TEAM: 1357 break; 1358 } 1359 1360 if (askUser) { 1361 AutoLocker< ::Team> locker(fTeam); 1362 BString name(fTeam->Name()); 1363 locker.Unlock(); 1364 1365 BString message; 1366 message << "What shall be done about the debugged team '"; 1367 message << name; 1368 message << "'?"; 1369 1370 name.Remove(0, name.FindLast('/') + 1); 1371 1372 BString killLabel("Kill "); 1373 killLabel << name; 1374 1375 BString resumeLabel("Resume "); 1376 resumeLabel << name; 1377 1378 int32 choice = fUserInterface->SynchronouslyAskUser("Quit Debugger", 1379 message, killLabel, "Cancel", resumeLabel); 1380 1381 switch (choice) { 1382 case 0: 1383 fKillTeamOnQuit = true; 1384 break; 1385 case 1: 1386 case -1: 1387 return false; 1388 case 2: 1389 // Detach from the team and resume and stopped threads. 1390 break; 1391 } 1392 } 1393 1394 PostMessage(B_QUIT_REQUESTED); 1395 1396 return true; 1397 } 1398 1399 1400 void 1401 TeamDebugger::JobStarted(Job* job) 1402 { 1403 BString description(job->GetDescription()); 1404 if (!description.IsEmpty()) { 1405 description.Append(B_UTF8_ELLIPSIS); 1406 fUserInterface->NotifyBackgroundWorkStatus(description.String()); 1407 } 1408 } 1409 1410 1411 void 1412 TeamDebugger::JobDone(Job* job) 1413 { 1414 TRACE_JOBS("TeamDebugger::JobDone(%p)\n", job); 1415 _ResetUserBackgroundStatusIfNeeded(); 1416 } 1417 1418 1419 void 1420 TeamDebugger::JobWaitingForInput(Job* job) 1421 { 1422 LoadImageDebugInfoJob* infoJob = dynamic_cast<LoadImageDebugInfoJob*>(job); 1423 1424 if (infoJob == NULL) 1425 return; 1426 1427 BMessage message(MSG_DEBUG_INFO_NEEDS_USER_INPUT); 1428 message.AddPointer("job", infoJob); 1429 message.AddPointer("state", infoJob->GetLoadingState()); 1430 PostMessage(&message); 1431 } 1432 1433 1434 void 1435 TeamDebugger::JobFailed(Job* job) 1436 { 1437 TRACE_JOBS("TeamDebugger::JobFailed(%p)\n", job); 1438 // TODO: notify user 1439 _ResetUserBackgroundStatusIfNeeded(); 1440 } 1441 1442 1443 void 1444 TeamDebugger::JobAborted(Job* job) 1445 { 1446 TRACE_JOBS("TeamDebugger::JobAborted(%p)\n", job); 1447 // TODO: For a stack frame source loader thread we should reset the 1448 // loading state! Asynchronously due to locking order. 1449 _ResetUserBackgroundStatusIfNeeded(); 1450 } 1451 1452 1453 void 1454 TeamDebugger::ThreadStateChanged(const ::Team::ThreadEvent& event) 1455 { 1456 BMessage message(MSG_THREAD_STATE_CHANGED); 1457 message.AddInt32("thread", event.GetThread()->ID()); 1458 PostMessage(&message); 1459 } 1460 1461 1462 void 1463 TeamDebugger::ThreadCpuStateChanged(const ::Team::ThreadEvent& event) 1464 { 1465 BMessage message(MSG_THREAD_CPU_STATE_CHANGED); 1466 message.AddInt32("thread", event.GetThread()->ID()); 1467 PostMessage(&message); 1468 } 1469 1470 1471 void 1472 TeamDebugger::ThreadStackTraceChanged(const ::Team::ThreadEvent& event) 1473 { 1474 BMessage message(MSG_THREAD_STACK_TRACE_CHANGED); 1475 message.AddInt32("thread", event.GetThread()->ID()); 1476 PostMessage(&message); 1477 } 1478 1479 1480 void 1481 TeamDebugger::ImageDebugInfoChanged(const ::Team::ImageEvent& event) 1482 { 1483 BMessage message(MSG_IMAGE_DEBUG_INFO_CHANGED); 1484 message.AddInt32("image", event.GetImage()->ID()); 1485 PostMessage(&message); 1486 } 1487 1488 1489 /*static*/ status_t 1490 TeamDebugger::_DebugEventListenerEntry(void* data) 1491 { 1492 return ((TeamDebugger*)data)->_DebugEventListener(); 1493 } 1494 1495 1496 status_t 1497 TeamDebugger::_DebugEventListener() 1498 { 1499 while (!fTerminating) { 1500 // get the next event 1501 DebugEvent* event; 1502 status_t error = fDebuggerInterface->GetNextDebugEvent(event); 1503 if (error != B_OK) 1504 break; 1505 // TODO: Error handling! 1506 1507 if (event->Team() != fTeamID) { 1508 TRACE_EVENTS("TeamDebugger for team %" B_PRId32 ": received event " 1509 "from team %" B_PRId32 "!\n", fTeamID, event->Team()); 1510 continue; 1511 } 1512 1513 BMessage message(MSG_DEBUGGER_EVENT); 1514 if (message.AddPointer("event", event) != B_OK 1515 || PostMessage(&message) != B_OK) { 1516 // TODO: Continue thread if necessary! 1517 delete event; 1518 } 1519 } 1520 1521 return B_OK; 1522 } 1523 1524 1525 void 1526 TeamDebugger::_HandleDebuggerMessage(DebugEvent* event) 1527 { 1528 TRACE_EVENTS("TeamDebugger::_HandleDebuggerMessage(): %" B_PRId32 "\n", 1529 event->EventType()); 1530 1531 bool handled = false; 1532 1533 ThreadHandler* handler = _GetThreadHandler(event->Thread()); 1534 BReference<ThreadHandler> handlerReference(handler); 1535 1536 switch (event->EventType()) { 1537 case B_DEBUGGER_MESSAGE_THREAD_DEBUGGED: 1538 TRACE_EVENTS("B_DEBUGGER_MESSAGE_THREAD_DEBUGGED: thread: %" 1539 B_PRId32 "\n", event->Thread()); 1540 1541 if (handler != NULL) { 1542 handled = handler->HandleThreadDebugged( 1543 dynamic_cast<ThreadDebuggedEvent*>(event)); 1544 } 1545 break; 1546 case B_DEBUGGER_MESSAGE_DEBUGGER_CALL: 1547 TRACE_EVENTS("B_DEBUGGER_MESSAGE_DEBUGGER_CALL: thread: %" B_PRId32 1548 "\n", event->Thread()); 1549 1550 if (handler != NULL) { 1551 handled = handler->HandleDebuggerCall( 1552 dynamic_cast<DebuggerCallEvent*>(event)); 1553 } 1554 break; 1555 case B_DEBUGGER_MESSAGE_BREAKPOINT_HIT: 1556 TRACE_EVENTS("B_DEBUGGER_MESSAGE_BREAKPOINT_HIT: thread: %" B_PRId32 1557 "\n", event->Thread()); 1558 1559 if (handler != NULL) { 1560 handled = handler->HandleBreakpointHit( 1561 dynamic_cast<BreakpointHitEvent*>(event)); 1562 } 1563 break; 1564 case B_DEBUGGER_MESSAGE_WATCHPOINT_HIT: 1565 TRACE_EVENTS("B_DEBUGGER_MESSAGE_WATCHPOINT_HIT: thread: %" B_PRId32 1566 "\n", event->Thread()); 1567 1568 if (handler != NULL) { 1569 handled = handler->HandleWatchpointHit( 1570 dynamic_cast<WatchpointHitEvent*>(event)); 1571 } 1572 break; 1573 case B_DEBUGGER_MESSAGE_SINGLE_STEP: 1574 TRACE_EVENTS("B_DEBUGGER_MESSAGE_SINGLE_STEP: thread: %" B_PRId32 1575 "\n", event->Thread()); 1576 1577 if (handler != NULL) { 1578 handled = handler->HandleSingleStep( 1579 dynamic_cast<SingleStepEvent*>(event)); 1580 } 1581 break; 1582 case B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED: 1583 TRACE_EVENTS("B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED: thread: %" 1584 B_PRId32 "\n", event->Thread()); 1585 1586 if (handler != NULL) { 1587 handled = handler->HandleExceptionOccurred( 1588 dynamic_cast<ExceptionOccurredEvent*>(event)); 1589 } 1590 break; 1591 // case B_DEBUGGER_MESSAGE_TEAM_CREATED: 1592 //printf("B_DEBUGGER_MESSAGE_TEAM_CREATED: team: %ld\n", message.team_created.new_team); 1593 // break; 1594 case B_DEBUGGER_MESSAGE_TEAM_DELETED: 1595 { 1596 TRACE_EVENTS("B_DEBUGGER_MESSAGE_TEAM_DELETED: team: %" B_PRId32 1597 "\n", event->Team()); 1598 TeamDeletedEvent* teamEvent 1599 = dynamic_cast<TeamDeletedEvent*>(event); 1600 handled = _HandleTeamDeleted(teamEvent); 1601 break; 1602 } 1603 case B_DEBUGGER_MESSAGE_TEAM_EXEC: 1604 { 1605 TRACE_EVENTS("B_DEBUGGER_MESSAGE_TEAM_EXEC: team: %" B_PRId32 "\n", 1606 event->Team()); 1607 1608 TeamExecEvent* teamEvent 1609 = dynamic_cast<TeamExecEvent*>(event); 1610 _PrepareForTeamExec(teamEvent); 1611 break; 1612 } 1613 case B_DEBUGGER_MESSAGE_THREAD_CREATED: 1614 { 1615 ThreadCreatedEvent* threadEvent 1616 = dynamic_cast<ThreadCreatedEvent*>(event); 1617 TRACE_EVENTS("B_DEBUGGER_MESSAGE_THREAD_CREATED: thread: %" B_PRId32 1618 "\n", threadEvent->NewThread()); 1619 handled = _HandleThreadCreated(threadEvent); 1620 break; 1621 } 1622 case DEBUGGER_MESSAGE_THREAD_RENAMED: 1623 { 1624 ThreadRenamedEvent* threadEvent 1625 = dynamic_cast<ThreadRenamedEvent*>(event); 1626 TRACE_EVENTS("DEBUGGER_MESSAGE_THREAD_RENAMED: thread: %" B_PRId32 1627 " (\"%s\")\n", 1628 threadEvent->RenamedThread(), threadEvent->NewName()); 1629 handled = _HandleThreadRenamed(threadEvent); 1630 break; 1631 } 1632 case DEBUGGER_MESSAGE_THREAD_PRIORITY_CHANGED: 1633 { 1634 ThreadPriorityChangedEvent* threadEvent 1635 = dynamic_cast<ThreadPriorityChangedEvent*>(event); 1636 TRACE_EVENTS("B_DEBUGGER_MESSAGE_THREAD_PRIORITY_CHANGED: thread:" 1637 " %" B_PRId32 "\n", threadEvent->ChangedThread()); 1638 handled = _HandleThreadPriorityChanged(threadEvent); 1639 break; 1640 } 1641 case B_DEBUGGER_MESSAGE_THREAD_DELETED: 1642 TRACE_EVENTS("B_DEBUGGER_MESSAGE_THREAD_DELETED: thread: %" B_PRId32 1643 "\n", event->Thread()); 1644 handled = _HandleThreadDeleted( 1645 dynamic_cast<ThreadDeletedEvent*>(event)); 1646 break; 1647 case B_DEBUGGER_MESSAGE_IMAGE_CREATED: 1648 { 1649 ImageCreatedEvent* imageEvent 1650 = dynamic_cast<ImageCreatedEvent*>(event); 1651 TRACE_EVENTS("B_DEBUGGER_MESSAGE_IMAGE_CREATED: image: \"%s\" " 1652 "(%" B_PRId32 ")\n", imageEvent->GetImageInfo().Name().String(), 1653 imageEvent->GetImageInfo().ImageID()); 1654 handled = _HandleImageCreated(imageEvent); 1655 break; 1656 } 1657 case B_DEBUGGER_MESSAGE_IMAGE_DELETED: 1658 { 1659 ImageDeletedEvent* imageEvent 1660 = dynamic_cast<ImageDeletedEvent*>(event); 1661 TRACE_EVENTS("B_DEBUGGER_MESSAGE_IMAGE_DELETED: image: \"%s\" " 1662 "(%" B_PRId32 ")\n", imageEvent->GetImageInfo().Name().String(), 1663 imageEvent->GetImageInfo().ImageID()); 1664 handled = _HandleImageDeleted(imageEvent); 1665 break; 1666 } 1667 case B_DEBUGGER_MESSAGE_POST_SYSCALL: 1668 { 1669 PostSyscallEvent* postSyscallEvent 1670 = dynamic_cast<PostSyscallEvent*>(event); 1671 TRACE_EVENTS("B_DEBUGGER_MESSAGE_POST_SYSCALL: syscall: %" 1672 B_PRIu32 "\n", postSyscallEvent->GetSyscallInfo().Syscall()); 1673 handled = _HandlePostSyscall(postSyscallEvent); 1674 1675 // if a thread was blocked in a syscall when we requested to 1676 // stop it for debugging, then that request will interrupt 1677 // said call, and the post syscall event will be all we get 1678 // in response. Consequently, we need to treat this case as 1679 // equivalent to having received a thread debugged event. 1680 AutoLocker< ::Team> teamLocker(fTeam); 1681 ::Thread* thread = fTeam->ThreadByID(event->Thread()); 1682 if (handler != NULL && thread != NULL 1683 && thread->StopRequestPending()) { 1684 handled = handler->HandleThreadDebugged(NULL); 1685 } 1686 break; 1687 } 1688 case B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED: 1689 { 1690 TRACE_EVENTS("B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED: thread: %" 1691 B_PRId32 "\n", event->Thread()); 1692 1693 if (handler != NULL) { 1694 handled = handler->HandleSignalReceived( 1695 dynamic_cast<SignalReceivedEvent*>(event)); 1696 } 1697 break; 1698 } 1699 case B_DEBUGGER_MESSAGE_PRE_SYSCALL: 1700 case B_DEBUGGER_MESSAGE_PROFILER_UPDATE: 1701 case B_DEBUGGER_MESSAGE_HANDED_OVER: 1702 // not interested 1703 break; 1704 default: 1705 WARNING("TeamDebugger for team %" B_PRId32 ": unknown event type: " 1706 "%" B_PRId32 "\n", fTeamID, event->EventType()); 1707 break; 1708 } 1709 1710 if (!handled && event->ThreadStopped()) 1711 fDebuggerInterface->ContinueThread(event->Thread()); 1712 } 1713 1714 1715 bool 1716 TeamDebugger::_HandleTeamDeleted(TeamDeletedEvent* event) 1717 { 1718 char message[64]; 1719 fDebuggerInterface->Close(false); 1720 1721 snprintf(message, sizeof(message), "Team %" B_PRId32 " has terminated. ", 1722 event->Team()); 1723 1724 int32 result = fUserInterface->SynchronouslyAskUser("Team terminated", 1725 message, "Do nothing", "Quit", fCommandLineArgc != 0 1726 ? "Restart team" : NULL); 1727 1728 switch (result) { 1729 case 1: 1730 case -1: 1731 { 1732 PostMessage(B_QUIT_REQUESTED); 1733 break; 1734 } 1735 case 2: 1736 { 1737 _SaveSettings(); 1738 fListener->TeamDebuggerRestartRequested(this); 1739 break; 1740 } 1741 default: 1742 break; 1743 } 1744 1745 return true; 1746 } 1747 1748 1749 bool 1750 TeamDebugger::_HandleThreadCreated(ThreadCreatedEvent* event) 1751 { 1752 AutoLocker< ::Team> locker(fTeam); 1753 1754 ThreadInfo info; 1755 status_t error = fDebuggerInterface->GetThreadInfo(event->NewThread(), 1756 info); 1757 if (error == B_OK) { 1758 ::Thread* thread; 1759 fTeam->AddThread(info, &thread); 1760 1761 ThreadHandler* handler = new(std::nothrow) ThreadHandler(thread, 1762 fWorker, fDebuggerInterface, this, fBreakpointManager); 1763 if (handler != NULL) { 1764 fThreadHandlers.Insert(handler); 1765 handler->Init(); 1766 } 1767 } 1768 1769 return false; 1770 } 1771 1772 1773 bool 1774 TeamDebugger::_HandleThreadRenamed(ThreadRenamedEvent* event) 1775 { 1776 AutoLocker< ::Team> locker(fTeam); 1777 1778 ::Thread* thread = fTeam->ThreadByID(event->RenamedThread()); 1779 1780 if (thread != NULL) 1781 thread->SetName(event->NewName()); 1782 1783 return false; 1784 } 1785 1786 1787 bool 1788 TeamDebugger::_HandleThreadPriorityChanged(ThreadPriorityChangedEvent*) 1789 { 1790 // TODO: implement once we actually track thread priorities 1791 1792 return false; 1793 } 1794 1795 1796 bool 1797 TeamDebugger::_HandleThreadDeleted(ThreadDeletedEvent* event) 1798 { 1799 AutoLocker< ::Team> locker(fTeam); 1800 if (ThreadHandler* handler = fThreadHandlers.Lookup(event->Thread())) { 1801 fThreadHandlers.Remove(handler); 1802 handler->ReleaseReference(); 1803 } 1804 fTeam->RemoveThread(event->Thread()); 1805 return false; 1806 } 1807 1808 1809 bool 1810 TeamDebugger::_HandleImageCreated(ImageCreatedEvent* event) 1811 { 1812 AutoLocker< ::Team> locker(fTeam); 1813 _AddImage(event->GetImageInfo()); 1814 1815 ImageInfoPendingThread* info = new(std::nothrow) ImageInfoPendingThread( 1816 event->GetImageInfo().ImageID(), event->Thread()); 1817 if (info == NULL) 1818 return false; 1819 1820 fImageInfoPendingThreads->Insert(info); 1821 return true; 1822 } 1823 1824 1825 bool 1826 TeamDebugger::_HandleImageDeleted(ImageDeletedEvent* event) 1827 { 1828 AutoLocker< ::Team> locker(fTeam); 1829 fTeam->RemoveImage(event->GetImageInfo().ImageID()); 1830 1831 ImageHandler* imageHandler = fImageHandlers->Lookup( 1832 event->GetImageInfo().ImageID()); 1833 if (imageHandler == NULL) 1834 return false; 1835 1836 fImageHandlers->Remove(imageHandler); 1837 BReference<ImageHandler> imageHandlerReference(imageHandler, true); 1838 locker.Unlock(); 1839 1840 // remove breakpoints in the image 1841 fBreakpointManager->RemoveImageBreakpoints(imageHandler->GetImage()); 1842 1843 return false; 1844 } 1845 1846 1847 bool 1848 TeamDebugger::_HandlePostSyscall(PostSyscallEvent* event) 1849 { 1850 const SyscallInfo& info = event->GetSyscallInfo(); 1851 1852 switch (info.Syscall()) { 1853 case SYSCALL_WRITE: 1854 { 1855 if ((ssize_t)info.ReturnValue() <= 0) 1856 break; 1857 1858 int32 fd; 1859 target_addr_t address; 1860 size_t size; 1861 // TODO: decoding the syscall arguments should probably be 1862 // factored out into an Architecture method of its own, since 1863 // there's no guarantee the target architecture has the same 1864 // endianness as the host. This could re-use the syscall 1865 // argument parser that strace uses, though that would need to 1866 // be adapted to handle the aforementioned endian differences. 1867 // This works for x86{-64} for now though. 1868 if (fTeam->GetArchitecture()->AddressSize() == 4) { 1869 const uint32* args = (const uint32*)info.Arguments(); 1870 fd = args[0]; 1871 address = args[3]; 1872 size = args[4]; 1873 } else { 1874 const uint64* args = (const uint64*)info.Arguments(); 1875 fd = args[0]; 1876 address = args[2]; 1877 size = args[3]; 1878 } 1879 1880 if (fd == 1 || fd == 2) { 1881 BString data; 1882 1883 ssize_t result = fDebuggerInterface->ReadMemoryString( 1884 address, size, data); 1885 if (result >= 0) 1886 fTeam->NotifyConsoleOutputReceived(fd, data); 1887 } 1888 break; 1889 } 1890 case SYSCALL_WRITEV: 1891 { 1892 // TODO: handle 1893 } 1894 default: 1895 break; 1896 } 1897 1898 return false; 1899 } 1900 1901 1902 void 1903 TeamDebugger::_PrepareForTeamExec(TeamExecEvent* event) 1904 { 1905 // NB: must be called with team lock held. 1906 1907 _SaveSettings(); 1908 1909 // when notified of exec, we need to clear out data related 1910 // to the old team. 1911 const ImageList& images = fTeam->Images(); 1912 1913 for (ImageList::ConstIterator it = images.GetIterator(); 1914 Image* image = it.Next();) { 1915 fBreakpointManager->RemoveImageBreakpoints(image); 1916 } 1917 1918 BObjectList<UserBreakpoint> breakpointsToRemove(20, false); 1919 const UserBreakpointList& breakpoints = fTeam->UserBreakpoints(); 1920 for (UserBreakpointList::ConstIterator it = breakpoints.GetIterator(); 1921 UserBreakpoint* breakpoint = it.Next();) { 1922 breakpointsToRemove.AddItem(breakpoint); 1923 breakpoint->AcquireReference(); 1924 } 1925 1926 for (int32 i = 0; i < breakpointsToRemove.CountItems(); i++) { 1927 UserBreakpoint* breakpoint = breakpointsToRemove.ItemAt(i); 1928 fTeam->RemoveUserBreakpoint(breakpoint); 1929 fTeam->NotifyUserBreakpointChanged(breakpoint); 1930 breakpoint->ReleaseReference(); 1931 } 1932 1933 fTeam->ClearImages(); 1934 fTeam->ClearSignalDispositionMappings(); 1935 fExecPending = true; 1936 } 1937 1938 1939 void 1940 TeamDebugger::_HandleImageDebugInfoChanged(image_id imageID) 1941 { 1942 // get the image (via the image handler) 1943 AutoLocker< ::Team> locker(fTeam); 1944 ImageHandler* imageHandler = fImageHandlers->Lookup(imageID); 1945 if (imageHandler == NULL) 1946 return; 1947 1948 Image* image = imageHandler->GetImage(); 1949 BReference<Image> imageReference(image); 1950 image_debug_info_state state = image->ImageDebugInfoState(); 1951 1952 bool handlePostExecSetup = fExecPending && image->Type() == B_APP_IMAGE 1953 && state != IMAGE_DEBUG_INFO_LOADING; 1954 // this needs to be done first so that breakpoints are loaded. 1955 // otherwise, UpdateImageBreakpoints() won't find the appropriate 1956 // UserBreakpoints to create/install instances for. 1957 if (handlePostExecSetup) { 1958 fTeam->SetName(image->Name()); 1959 _LoadSettings(); 1960 fExecPending = false; 1961 } 1962 1963 locker.Unlock(); 1964 1965 if (state == IMAGE_DEBUG_INFO_LOADED 1966 || state == IMAGE_DEBUG_INFO_UNAVAILABLE) { 1967 1968 // update breakpoints in the image 1969 fBreakpointManager->UpdateImageBreakpoints(image); 1970 1971 ImageInfoPendingThread* thread = fImageInfoPendingThreads 1972 ->Lookup(imageID); 1973 if (thread != NULL) { 1974 fImageInfoPendingThreads->Remove(thread); 1975 ObjectDeleter<ImageInfoPendingThread> threadDeleter(thread); 1976 locker.Lock(); 1977 ThreadHandler* handler = _GetThreadHandler(thread->ThreadID()); 1978 BReference<ThreadHandler> handlerReference(handler); 1979 if (fTeam->StopOnImageLoad()) { 1980 1981 bool stop = true; 1982 const BString& imageName = image->Name(); 1983 // only match on the image filename itself 1984 const char* rawImageName = imageName.String() 1985 + imageName.FindLast('/') + 1; 1986 if (fTeam->StopImageNameListEnabled()) { 1987 const BStringList& nameList = fTeam->StopImageNames(); 1988 stop = nameList.HasString(rawImageName); 1989 } 1990 1991 if (stop && handler != NULL) { 1992 BString stopReason; 1993 stopReason.SetToFormat("Image '%s' loaded.", 1994 rawImageName); 1995 locker.Unlock(); 1996 1997 if (handler->HandleThreadDebugged(NULL, stopReason)) 1998 return; 1999 } else 2000 locker.Unlock(); 2001 } else if (handlePostExecSetup) { 2002 // in the case of an exec(), we can't stop in main() until 2003 // the new app image has been loaded, so we know where to 2004 // set the main breakpoint at. 2005 SymbolInfo symbolInfo; 2006 if (fDebuggerInterface->GetSymbolInfo(fTeam->ID(), image->ID(), 2007 "main", B_SYMBOL_TYPE_TEXT, symbolInfo) == B_OK) { 2008 handler->SetBreakpointAndRun(symbolInfo.Address()); 2009 } 2010 } else { 2011 locker.Unlock(); 2012 fDebuggerInterface->ContinueThread(thread->ThreadID()); 2013 } 2014 } 2015 } 2016 } 2017 2018 2019 void 2020 TeamDebugger::_HandleImageFileChanged(image_id imageID) 2021 { 2022 TRACE_IMAGES("TeamDebugger::_HandleImageFileChanged(%" B_PRId32 ")\n", 2023 imageID); 2024 // TODO: Reload the debug info! 2025 } 2026 2027 2028 void 2029 TeamDebugger::_HandleSetUserBreakpoint(target_addr_t address, bool enabled, 2030 bool hidden) 2031 { 2032 TRACE_CONTROL("TeamDebugger::_HandleSetUserBreakpoint(%#" B_PRIx64 2033 ", %d, %d)\n", address, enabled, hidden); 2034 2035 // check whether there already is a breakpoint 2036 AutoLocker< ::Team> locker(fTeam); 2037 2038 Breakpoint* breakpoint = fTeam->BreakpointAtAddress(address); 2039 UserBreakpoint* userBreakpoint = NULL; 2040 if (breakpoint != NULL && breakpoint->FirstUserBreakpoint() != NULL) 2041 userBreakpoint = breakpoint->FirstUserBreakpoint()->GetUserBreakpoint(); 2042 BReference<UserBreakpoint> userBreakpointReference(userBreakpoint); 2043 2044 if (userBreakpoint == NULL) { 2045 TRACE_CONTROL(" no breakpoint yet\n"); 2046 2047 // get the function at the address 2048 Image* image = fTeam->ImageByAddress(address); 2049 2050 TRACE_CONTROL(" image: %p\n", image); 2051 2052 if (image == NULL) 2053 return; 2054 ImageDebugInfo* imageDebugInfo = image->GetImageDebugInfo(); 2055 2056 TRACE_CONTROL(" image debug info: %p\n", imageDebugInfo); 2057 2058 if (imageDebugInfo == NULL) 2059 return; 2060 // TODO: Handle this case by loading the debug info, if possible! 2061 FunctionInstance* functionInstance 2062 = imageDebugInfo->FunctionAtAddress(address); 2063 2064 TRACE_CONTROL(" function instance: %p\n", functionInstance); 2065 2066 if (functionInstance == NULL) 2067 return; 2068 Function* function = functionInstance->GetFunction(); 2069 2070 TRACE_CONTROL(" function: %p\n", function); 2071 2072 // get the source location for the address 2073 FunctionDebugInfo* functionDebugInfo 2074 = functionInstance->GetFunctionDebugInfo(); 2075 SourceLocation sourceLocation; 2076 Statement* breakpointStatement = NULL; 2077 if (functionDebugInfo->GetSpecificImageDebugInfo()->GetStatement( 2078 functionDebugInfo, address, breakpointStatement) != B_OK) { 2079 return; 2080 } 2081 2082 sourceLocation = breakpointStatement->StartSourceLocation(); 2083 breakpointStatement->ReleaseReference(); 2084 2085 target_addr_t relativeAddress = address - functionInstance->Address(); 2086 2087 TRACE_CONTROL(" relative address: %#" B_PRIx64 ", source location: " 2088 "(%" B_PRId32 ", %" B_PRId32 ")\n", relativeAddress, 2089 sourceLocation.Line(), sourceLocation.Column()); 2090 2091 // get function id 2092 FunctionID* functionID = functionInstance->GetFunctionID(); 2093 if (functionID == NULL) 2094 return; 2095 BReference<FunctionID> functionIDReference(functionID, true); 2096 2097 // create the user breakpoint 2098 userBreakpoint = new(std::nothrow) UserBreakpoint( 2099 UserBreakpointLocation(functionID, function->SourceFile(), 2100 sourceLocation, relativeAddress)); 2101 if (userBreakpoint == NULL) 2102 return; 2103 userBreakpointReference.SetTo(userBreakpoint, true); 2104 2105 userBreakpoint->SetHidden(hidden); 2106 2107 TRACE_CONTROL(" created user breakpoint: %p\n", userBreakpoint); 2108 2109 // iterate through all function instances and create 2110 // UserBreakpointInstances 2111 for (FunctionInstanceList::ConstIterator it 2112 = function->Instances().GetIterator(); 2113 FunctionInstance* instance = it.Next();) { 2114 TRACE_CONTROL(" function instance %p: range: %#" B_PRIx64 " - %#" 2115 B_PRIx64 "\n", instance, instance->Address(), 2116 instance->Address() + instance->Size()); 2117 2118 // get the breakpoint address for the instance 2119 target_addr_t instanceAddress = 0; 2120 if (instance == functionInstance) { 2121 instanceAddress = address; 2122 } else if (functionInstance->SourceFile() != NULL) { 2123 // We have a source file, so get the address for the source 2124 // location. 2125 Statement* statement = NULL; 2126 functionDebugInfo = instance->GetFunctionDebugInfo(); 2127 functionDebugInfo->GetSpecificImageDebugInfo() 2128 ->GetStatementAtSourceLocation(functionDebugInfo, 2129 sourceLocation, statement); 2130 if (statement != NULL) { 2131 instanceAddress = statement->CoveringAddressRange().Start(); 2132 // TODO: What about BreakpointAllowed()? 2133 statement->ReleaseReference(); 2134 } 2135 } 2136 2137 TRACE_CONTROL(" breakpoint address using source info: %" B_PRIx64 2138 "\n", instanceAddress); 2139 2140 if (instanceAddress == 0) { 2141 // No source file (or we failed getting the statement), so try 2142 // to use the same relative address. 2143 if (relativeAddress > instance->Size()) 2144 continue; 2145 instanceAddress = instance->Address() + relativeAddress; 2146 } 2147 2148 TRACE_CONTROL(" final breakpoint address: %" B_PRIx64 "\n", 2149 instanceAddress); 2150 2151 UserBreakpointInstance* breakpointInstance = new(std::nothrow) 2152 UserBreakpointInstance(userBreakpoint, instanceAddress); 2153 if (breakpointInstance == NULL 2154 || !userBreakpoint->AddInstance(breakpointInstance)) { 2155 delete breakpointInstance; 2156 return; 2157 } 2158 2159 TRACE_CONTROL(" breakpoint instance: %p\n", breakpointInstance); 2160 } 2161 } 2162 2163 locker.Unlock(); 2164 2165 _HandleSetUserBreakpoint(userBreakpoint, enabled); 2166 } 2167 2168 2169 void 2170 TeamDebugger::_HandleSetUserBreakpoint(UserBreakpoint* breakpoint, bool enabled) 2171 { 2172 status_t error = fBreakpointManager->InstallUserBreakpoint(breakpoint, 2173 enabled); 2174 if (error != B_OK) { 2175 _NotifyUser("Install Breakpoint", "Failed to install breakpoint: %s", 2176 strerror(error)); 2177 } 2178 } 2179 2180 2181 void 2182 TeamDebugger::_HandleClearUserBreakpoint(target_addr_t address) 2183 { 2184 TRACE_CONTROL("TeamDebugger::_HandleClearUserBreakpoint(%#" B_PRIx64 ")\n", 2185 address); 2186 2187 AutoLocker< ::Team> locker(fTeam); 2188 2189 Breakpoint* breakpoint = fTeam->BreakpointAtAddress(address); 2190 if (breakpoint == NULL || breakpoint->FirstUserBreakpoint() == NULL) 2191 return; 2192 UserBreakpoint* userBreakpoint 2193 = breakpoint->FirstUserBreakpoint()->GetUserBreakpoint(); 2194 BReference<UserBreakpoint> userBreakpointReference(userBreakpoint); 2195 2196 locker.Unlock(); 2197 2198 _HandleClearUserBreakpoint(userBreakpoint); 2199 } 2200 2201 2202 void 2203 TeamDebugger::_HandleClearUserBreakpoint(UserBreakpoint* breakpoint) 2204 { 2205 fBreakpointManager->UninstallUserBreakpoint(breakpoint); 2206 } 2207 2208 2209 void 2210 TeamDebugger::_HandleSetWatchpoint(target_addr_t address, uint32 type, 2211 int32 length, bool enabled) 2212 { 2213 Watchpoint* watchpoint = new(std::nothrow) Watchpoint(address, type, 2214 length); 2215 2216 if (watchpoint == NULL) 2217 return; 2218 BReference<Watchpoint> watchpointRef(watchpoint, true); 2219 2220 _HandleSetWatchpoint(watchpoint, enabled); 2221 } 2222 2223 2224 void 2225 TeamDebugger::_HandleSetWatchpoint(Watchpoint* watchpoint, bool enabled) 2226 { 2227 status_t error = fWatchpointManager->InstallWatchpoint(watchpoint, 2228 enabled); 2229 if (error != B_OK) { 2230 _NotifyUser("Install Watchpoint", "Failed to install watchpoint: %s", 2231 strerror(error)); 2232 } 2233 } 2234 2235 2236 void 2237 TeamDebugger::_HandleClearWatchpoint(target_addr_t address) 2238 { 2239 TRACE_CONTROL("TeamDebugger::_HandleClearWatchpoint(%#" B_PRIx64 ")\n", 2240 address); 2241 2242 AutoLocker< ::Team> locker(fTeam); 2243 2244 Watchpoint* watchpoint = fTeam->WatchpointAtAddress(address); 2245 if (watchpoint == NULL) 2246 return; 2247 BReference<Watchpoint> watchpointReference(watchpoint); 2248 2249 locker.Unlock(); 2250 2251 _HandleClearWatchpoint(watchpoint); 2252 } 2253 2254 2255 void 2256 TeamDebugger::_HandleClearWatchpoint(Watchpoint* watchpoint) 2257 { 2258 fWatchpointManager->UninstallWatchpoint(watchpoint); 2259 } 2260 2261 2262 void 2263 TeamDebugger::_HandleInspectAddress(target_addr_t address, 2264 TeamMemoryBlock::Listener* listener) 2265 { 2266 TRACE_CONTROL("TeamDebugger::_HandleInspectAddress(%" B_PRIx64 ", %p)\n", 2267 address, listener); 2268 2269 TeamMemoryBlock* memoryBlock = fMemoryBlockManager 2270 ->GetMemoryBlock(address); 2271 2272 if (memoryBlock == NULL) { 2273 _NotifyUser("Inspect Address", "Failed to allocate memory block"); 2274 return; 2275 } 2276 2277 if (!memoryBlock->IsValid()) { 2278 AutoLocker< ::Team> teamLocker(fTeam); 2279 2280 if (!memoryBlock->HasListener(listener)) 2281 memoryBlock->AddListener(listener); 2282 2283 TeamMemory* memory = fTeam->GetTeamMemory(); 2284 // schedule the job 2285 status_t result; 2286 if ((result = fWorker->ScheduleJob( 2287 new(std::nothrow) RetrieveMemoryBlockJob(fTeam, memory, 2288 memoryBlock), 2289 this)) != B_OK) { 2290 2291 memoryBlock->NotifyDataRetrieved(result); 2292 memoryBlock->ReleaseReference(); 2293 2294 _NotifyUser("Inspect Address", "Failed to retrieve memory data: %s", 2295 strerror(result)); 2296 } 2297 } else 2298 memoryBlock->NotifyDataRetrieved(); 2299 2300 } 2301 2302 2303 void 2304 TeamDebugger::_HandleWriteMemory(target_addr_t address, void* data, 2305 target_size_t size) 2306 { 2307 TRACE_CONTROL("TeamDebugger::_HandleWriteTargetMemory(%" B_PRIx64 ", %p, " 2308 "%" B_PRIu64 ")\n", address, data, size); 2309 2310 AutoLocker< ::Team> teamLocker(fTeam); 2311 TeamMemory* memory = fTeam->GetTeamMemory(); 2312 // schedule the job 2313 status_t result; 2314 if ((result = fWorker->ScheduleJob( 2315 new(std::nothrow) WriteMemoryJob(fTeam, memory, address, data, size), 2316 this)) != B_OK) { 2317 _NotifyUser("Write Memory", "Failed to write memory data: %s", 2318 strerror(result)); 2319 } 2320 } 2321 2322 2323 void 2324 TeamDebugger::_HandleEvaluateExpression(SourceLanguage* language, 2325 ExpressionInfo* info, StackFrame* frame, ::Thread* thread) 2326 { 2327 status_t result = fWorker->ScheduleJob( 2328 new(std::nothrow) ExpressionEvaluationJob(fTeam, fDebuggerInterface, 2329 language, info, frame, thread)); 2330 if (result != B_OK) { 2331 _NotifyUser("Evaluate Expression", "Failed to evaluate expression: %s", 2332 strerror(result)); 2333 } 2334 } 2335 2336 2337 void 2338 TeamDebugger::_HandleWriteCoreFile(const entry_ref& targetPath) 2339 { 2340 status_t result = fWorker->ScheduleJob( 2341 new(std::nothrow) WriteCoreFileJob(fTeam, fDebuggerInterface, 2342 targetPath)); 2343 if (result != B_OK) { 2344 _NotifyUser("Write Core File", "Failed to write core file: %s", 2345 strerror(result)); 2346 } 2347 } 2348 2349 2350 status_t 2351 TeamDebugger::_HandleSetArguments(int argc, const char* const* argv) 2352 { 2353 fCommandLineArgc = argc; 2354 fCommandLineArgv = new(std::nothrow) const char*[argc]; 2355 if (fCommandLineArgv == NULL) 2356 return B_NO_MEMORY; 2357 2358 memset(const_cast<char **>(fCommandLineArgv), 0, sizeof(char*) * argc); 2359 2360 for (int i = 0; i < argc; i++) { 2361 fCommandLineArgv[i] = strdup(argv[i]); 2362 if (fCommandLineArgv[i] == NULL) 2363 return B_NO_MEMORY; 2364 } 2365 2366 return B_OK; 2367 } 2368 2369 2370 void 2371 TeamDebugger::_HandleDebugInfoJobUserInput(ImageDebugInfoLoadingState* state) 2372 { 2373 SpecificImageDebugInfoLoadingState* specificState 2374 = state->GetSpecificDebugInfoLoadingState(); 2375 2376 ImageDebugLoadingStateHandler* handler; 2377 if (ImageDebugLoadingStateHandlerRoster::Default() 2378 ->FindStateHandler(specificState, handler) != B_OK) { 2379 TRACE_JOBS("TeamDebugger::_HandleDebugInfoJobUserInput(): " 2380 "Failed to find appropriate information handler, aborting."); 2381 return; 2382 } 2383 2384 handler->HandleState(specificState, fUserInterface); 2385 } 2386 2387 2388 ThreadHandler* 2389 TeamDebugger::_GetThreadHandler(thread_id threadID) 2390 { 2391 AutoLocker< ::Team> locker(fTeam); 2392 2393 ThreadHandler* handler = fThreadHandlers.Lookup(threadID); 2394 if (handler != NULL) 2395 handler->AcquireReference(); 2396 return handler; 2397 } 2398 2399 2400 status_t 2401 TeamDebugger::_AddImage(const ImageInfo& imageInfo, Image** _image) 2402 { 2403 LocatableFile* file = NULL; 2404 if (strchr(imageInfo.Name(), '/') != NULL) 2405 file = fFileManager->GetTargetFile(imageInfo.Name()); 2406 BReference<LocatableFile> imageFileReference(file, true); 2407 2408 Image* image; 2409 status_t error = fTeam->AddImage(imageInfo, file, &image); 2410 if (error != B_OK) 2411 return error; 2412 2413 ImageDebugInfoRequested(image); 2414 2415 ImageHandler* imageHandler = new(std::nothrow) ImageHandler(this, image); 2416 if (imageHandler != NULL) 2417 fImageHandlers->Insert(imageHandler); 2418 2419 if (_image != NULL) 2420 *_image = image; 2421 2422 return B_OK; 2423 } 2424 2425 2426 void 2427 TeamDebugger::_LoadSettings() 2428 { 2429 // get the team name 2430 AutoLocker< ::Team> locker(fTeam); 2431 BString teamName = fTeam->Name(); 2432 locker.Unlock(); 2433 2434 // load the settings 2435 if (fSettingsManager->LoadTeamSettings(teamName, fTeamSettings) != B_OK) 2436 return; 2437 2438 // create the saved breakpoints 2439 for (int32 i = 0; const BreakpointSetting* breakpointSetting 2440 = fTeamSettings.BreakpointAt(i); i++) { 2441 if (breakpointSetting->GetFunctionID() == NULL) 2442 continue; 2443 2444 // get the source file, if any 2445 LocatableFile* sourceFile = NULL; 2446 if (breakpointSetting->SourceFile().Length() > 0) { 2447 sourceFile = fFileManager->GetSourceFile( 2448 breakpointSetting->SourceFile()); 2449 if (sourceFile == NULL) 2450 continue; 2451 } 2452 BReference<LocatableFile> sourceFileReference(sourceFile, true); 2453 2454 // create the breakpoint 2455 UserBreakpointLocation location(breakpointSetting->GetFunctionID(), 2456 sourceFile, breakpointSetting->GetSourceLocation(), 2457 breakpointSetting->RelativeAddress()); 2458 2459 UserBreakpoint* breakpoint = new(std::nothrow) UserBreakpoint(location); 2460 if (breakpoint == NULL) 2461 return; 2462 BReference<UserBreakpoint> breakpointReference(breakpoint, true); 2463 2464 breakpoint->SetHidden(breakpointSetting->IsHidden()); 2465 breakpoint->SetCondition(breakpointSetting->Condition()); 2466 2467 // install it 2468 fBreakpointManager->InstallUserBreakpoint(breakpoint, 2469 breakpointSetting->IsEnabled()); 2470 } 2471 2472 fFileManager->LoadLocationMappings(fTeamSettings.FileManagerSettings()); 2473 2474 const TeamUiSettings* uiSettings = fTeamSettings.UiSettingFor( 2475 fUserInterface->ID()); 2476 if (uiSettings != NULL) 2477 fUserInterface->LoadSettings(uiSettings); 2478 2479 const TeamSignalSettings* signalSettings = fTeamSettings.SignalSettings(); 2480 if (signalSettings != NULL) { 2481 fTeam->SetDefaultSignalDisposition( 2482 signalSettings->DefaultSignalDisposition()); 2483 2484 int32 signal; 2485 int32 disposition; 2486 for (int32 i = 0; i < signalSettings->CountCustomSignalDispositions(); 2487 i++) { 2488 if (signalSettings->GetCustomSignalDispositionAt(i, signal, 2489 disposition) == B_OK) { 2490 fTeam->SetCustomSignalDisposition(signal, disposition); 2491 } 2492 } 2493 } 2494 } 2495 2496 2497 void 2498 TeamDebugger::_SaveSettings() 2499 { 2500 // get the settings 2501 AutoLocker< ::Team> locker(fTeam); 2502 TeamSettings settings; 2503 if (settings.SetTo(fTeam) != B_OK) 2504 return; 2505 2506 TeamUiSettings* uiSettings = NULL; 2507 if (fUserInterface->SaveSettings(uiSettings) != B_OK) 2508 return; 2509 if (uiSettings != NULL) 2510 settings.AddUiSettings(uiSettings); 2511 2512 // preserve the UI settings from our cached copy. 2513 for (int32 i = 0; i < fTeamSettings.CountUiSettings(); i++) { 2514 const TeamUiSettings* oldUiSettings = fTeamSettings.UiSettingAt(i); 2515 if (strcmp(oldUiSettings->ID(), fUserInterface->ID()) != 0) { 2516 TeamUiSettings* clonedSettings = oldUiSettings->Clone(); 2517 if (clonedSettings != NULL) 2518 settings.AddUiSettings(clonedSettings); 2519 } 2520 } 2521 2522 fFileManager->SaveLocationMappings(settings.FileManagerSettings()); 2523 locker.Unlock(); 2524 2525 // save the settings 2526 fSettingsManager->SaveTeamSettings(settings); 2527 } 2528 2529 2530 void 2531 TeamDebugger::_NotifyUser(const char* title, const char* text,...) 2532 { 2533 // print the message 2534 char buffer[1024]; 2535 va_list args; 2536 va_start(args, text); 2537 vsnprintf(buffer, sizeof(buffer), text, args); 2538 va_end(args); 2539 2540 // notify the user 2541 fUserInterface->NotifyUser(title, buffer, USER_NOTIFICATION_WARNING); 2542 } 2543 2544 2545 void 2546 TeamDebugger::_ResetUserBackgroundStatusIfNeeded() 2547 { 2548 if (!fWorker->HasPendingJobs()) 2549 fUserInterface->NotifyBackgroundWorkStatus("Ready."); 2550 } 2551 2552 2553 // #pragma mark - Listener 2554 2555 2556 TeamDebugger::Listener::~Listener() 2557 { 2558 } 2559