1 /* 2 * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2010-2017, 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, true); 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 case MSG_RESET_USER_BACKGROUND_STATUS: 967 { 968 fUserInterface->NotifyBackgroundWorkStatus("Ready."); 969 break; 970 } 971 972 default: 973 BLooper::MessageReceived(message); 974 break; 975 } 976 } 977 978 979 void 980 TeamDebugger::SourceEntryLocateRequested(const char* sourcePath, 981 const char* locatedPath) 982 { 983 AutoLocker<FileManager> locker(fFileManager); 984 fFileManager->SourceEntryLocated(sourcePath, locatedPath); 985 } 986 987 988 void 989 TeamDebugger::SourceEntryInvalidateRequested(LocatableFile* sourceFile) 990 { 991 AutoLocker< ::Team> locker(fTeam); 992 993 fTeam->DebugInfo()->ClearSourceCode(sourceFile); 994 } 995 996 997 void 998 TeamDebugger::FunctionSourceCodeRequested(FunctionInstance* functionInstance, 999 bool forceDisassembly) 1000 { 1001 Function* function = functionInstance->GetFunction(); 1002 1003 // mark loading 1004 AutoLocker< ::Team> locker(fTeam); 1005 1006 if (forceDisassembly && functionInstance->SourceCodeState() 1007 != FUNCTION_SOURCE_NOT_LOADED) { 1008 return; 1009 } else if (!forceDisassembly && function->SourceCodeState() 1010 == FUNCTION_SOURCE_LOADED) { 1011 return; 1012 } 1013 1014 functionInstance->SetSourceCode(NULL, FUNCTION_SOURCE_LOADING); 1015 1016 bool loadForFunction = false; 1017 if (!forceDisassembly && (function->SourceCodeState() 1018 == FUNCTION_SOURCE_NOT_LOADED 1019 || function->SourceCodeState() == FUNCTION_SOURCE_SUPPRESSED)) { 1020 loadForFunction = true; 1021 function->SetSourceCode(NULL, FUNCTION_SOURCE_LOADING); 1022 } 1023 1024 locker.Unlock(); 1025 1026 // schedule the job 1027 if (fWorker->ScheduleJob( 1028 new(std::nothrow) LoadSourceCodeJob(fDebuggerInterface, 1029 fDebuggerInterface->GetArchitecture(), fTeam, functionInstance, 1030 loadForFunction), 1031 this) != B_OK) { 1032 // scheduling failed -- mark unavailable 1033 locker.Lock(); 1034 function->SetSourceCode(NULL, FUNCTION_SOURCE_UNAVAILABLE); 1035 locker.Unlock(); 1036 } 1037 } 1038 1039 1040 void 1041 TeamDebugger::ImageDebugInfoRequested(Image* image) 1042 { 1043 LoadImageDebugInfoJob::ScheduleIfNecessary(fWorker, image, this); 1044 } 1045 1046 1047 void 1048 TeamDebugger::ValueNodeValueRequested(CpuState* cpuState, 1049 ValueNodeContainer* container, ValueNode* valueNode) 1050 { 1051 AutoLocker<ValueNodeContainer> containerLocker(container); 1052 if (valueNode->Container() != container) 1053 return; 1054 1055 // check whether a job is already in progress 1056 AutoLocker<Worker> workerLocker(fWorker); 1057 SimpleJobKey jobKey(valueNode, JOB_TYPE_RESOLVE_VALUE_NODE_VALUE); 1058 if (fWorker->GetJob(jobKey) != NULL) 1059 return; 1060 workerLocker.Unlock(); 1061 1062 // schedule the job 1063 status_t error = fWorker->ScheduleJob( 1064 new(std::nothrow) ResolveValueNodeValueJob(fDebuggerInterface, 1065 fDebuggerInterface->GetArchitecture(), cpuState, 1066 fTeam->GetTeamTypeInformation(), container, valueNode), this); 1067 if (error != B_OK) { 1068 // scheduling failed -- set the value to invalid 1069 valueNode->SetLocationAndValue(NULL, NULL, error); 1070 } 1071 } 1072 1073 void 1074 TeamDebugger::ValueNodeWriteRequested(ValueNode* node, CpuState* state, 1075 Value* newValue) 1076 { 1077 // schedule the job 1078 status_t error = fWorker->ScheduleJob( 1079 new(std::nothrow) WriteValueNodeValueJob(fDebuggerInterface, 1080 fDebuggerInterface->GetArchitecture(), state, 1081 fTeam->GetTeamTypeInformation(), node, newValue), this); 1082 if (error != B_OK) { 1083 BString message; 1084 message.SetToFormat("Request to write new value for variable %s " 1085 "failed: %s.\n", node->Name().String(), strerror(error)); 1086 fUserInterface->NotifyUser("Error", message.String(), 1087 USER_NOTIFICATION_ERROR); 1088 } 1089 } 1090 1091 1092 void 1093 TeamDebugger::ThreadActionRequested(thread_id threadID, 1094 uint32 action, target_addr_t address) 1095 { 1096 BMessage message(action); 1097 message.AddInt32("thread", threadID); 1098 message.AddUInt64("address", address); 1099 PostMessage(&message); 1100 } 1101 1102 1103 void 1104 TeamDebugger::SetBreakpointRequested(target_addr_t address, bool enabled, 1105 bool hidden) 1106 { 1107 BMessage message(MSG_SET_BREAKPOINT); 1108 message.AddUInt64("address", (uint64)address); 1109 message.AddBool("enabled", enabled); 1110 message.AddBool("hidden", hidden); 1111 PostMessage(&message); 1112 } 1113 1114 1115 void 1116 TeamDebugger::SetBreakpointEnabledRequested(UserBreakpoint* breakpoint, 1117 bool enabled) 1118 { 1119 BMessage message(MSG_SET_BREAKPOINT); 1120 BReference<UserBreakpoint> breakpointReference(breakpoint); 1121 if (message.AddPointer("breakpoint", breakpoint) == B_OK 1122 && message.AddBool("enabled", enabled) == B_OK 1123 && PostMessage(&message) == B_OK) { 1124 breakpointReference.Detach(); 1125 } 1126 } 1127 1128 1129 void 1130 TeamDebugger::SetBreakpointConditionRequested(UserBreakpoint* breakpoint, 1131 const char* condition) 1132 { 1133 BMessage message(MSG_SET_BREAKPOINT_CONDITION); 1134 BReference<UserBreakpoint> breakpointReference(breakpoint); 1135 if (message.AddPointer("breakpoint", breakpoint) == B_OK 1136 && message.AddString("condition", condition) == B_OK 1137 && PostMessage(&message) == B_OK) { 1138 breakpointReference.Detach(); 1139 } 1140 } 1141 1142 1143 void 1144 TeamDebugger::ClearBreakpointConditionRequested(UserBreakpoint* breakpoint) 1145 { 1146 BMessage message(MSG_CLEAR_BREAKPOINT_CONDITION); 1147 BReference<UserBreakpoint> breakpointReference(breakpoint); 1148 if (message.AddPointer("breakpoint", breakpoint) == B_OK 1149 && PostMessage(&message) == B_OK) { 1150 breakpointReference.Detach(); 1151 } 1152 } 1153 1154 1155 void 1156 TeamDebugger::ClearBreakpointRequested(target_addr_t address) 1157 { 1158 BMessage message(MSG_CLEAR_BREAKPOINT); 1159 message.AddUInt64("address", (uint64)address); 1160 PostMessage(&message); 1161 } 1162 1163 1164 void 1165 TeamDebugger::SetStopOnImageLoadRequested(bool enabled, bool useImageNames) 1166 { 1167 BMessage message(MSG_STOP_ON_IMAGE_LOAD); 1168 message.AddBool("enabled", enabled); 1169 message.AddBool("useNames", useImageNames); 1170 PostMessage(&message); 1171 } 1172 1173 1174 void 1175 TeamDebugger::AddStopImageNameRequested(const char* name) 1176 { 1177 BMessage message(MSG_ADD_STOP_IMAGE_NAME); 1178 message.AddString("name", name); 1179 PostMessage(&message); 1180 } 1181 1182 1183 void 1184 TeamDebugger::RemoveStopImageNameRequested(const char* name) 1185 { 1186 BMessage message(MSG_REMOVE_STOP_IMAGE_NAME); 1187 message.AddString("name", name); 1188 PostMessage(&message); 1189 } 1190 1191 1192 void 1193 TeamDebugger::SetDefaultSignalDispositionRequested(int32 disposition) 1194 { 1195 BMessage message(MSG_SET_DEFAULT_SIGNAL_DISPOSITION); 1196 message.AddInt32("disposition", disposition); 1197 PostMessage(&message); 1198 } 1199 1200 1201 void 1202 TeamDebugger::SetCustomSignalDispositionRequested(int32 signal, 1203 int32 disposition) 1204 { 1205 BMessage message(MSG_SET_CUSTOM_SIGNAL_DISPOSITION); 1206 message.AddInt32("signal", signal); 1207 message.AddInt32("disposition", disposition); 1208 PostMessage(&message); 1209 } 1210 1211 1212 void 1213 TeamDebugger::RemoveCustomSignalDispositionRequested(int32 signal) 1214 { 1215 BMessage message(MSG_REMOVE_CUSTOM_SIGNAL_DISPOSITION); 1216 message.AddInt32("signal", signal); 1217 PostMessage(&message); 1218 } 1219 1220 1221 void 1222 TeamDebugger::ClearBreakpointRequested(UserBreakpoint* breakpoint) 1223 { 1224 BMessage message(MSG_CLEAR_BREAKPOINT); 1225 BReference<UserBreakpoint> breakpointReference(breakpoint); 1226 if (message.AddPointer("breakpoint", breakpoint) == B_OK 1227 && PostMessage(&message) == B_OK) { 1228 breakpointReference.Detach(); 1229 } 1230 } 1231 1232 1233 void 1234 TeamDebugger::SetWatchpointRequested(target_addr_t address, uint32 type, 1235 int32 length, bool enabled) 1236 { 1237 BMessage message(MSG_SET_WATCHPOINT); 1238 message.AddUInt64("address", (uint64)address); 1239 message.AddUInt32("type", type); 1240 message.AddInt32("length", length); 1241 message.AddBool("enabled", enabled); 1242 PostMessage(&message); 1243 } 1244 1245 1246 void 1247 TeamDebugger::SetWatchpointEnabledRequested(Watchpoint* watchpoint, 1248 bool enabled) 1249 { 1250 BMessage message(MSG_SET_WATCHPOINT); 1251 BReference<Watchpoint> watchpointReference(watchpoint); 1252 if (message.AddPointer("watchpoint", watchpoint) == B_OK 1253 && message.AddBool("enabled", enabled) == B_OK 1254 && PostMessage(&message) == B_OK) { 1255 watchpointReference.Detach(); 1256 } 1257 } 1258 1259 1260 void 1261 TeamDebugger::ClearWatchpointRequested(target_addr_t address) 1262 { 1263 BMessage message(MSG_CLEAR_WATCHPOINT); 1264 message.AddUInt64("address", (uint64)address); 1265 PostMessage(&message); 1266 } 1267 1268 1269 void 1270 TeamDebugger::ClearWatchpointRequested(Watchpoint* watchpoint) 1271 { 1272 BMessage message(MSG_CLEAR_WATCHPOINT); 1273 BReference<Watchpoint> watchpointReference(watchpoint); 1274 if (message.AddPointer("watchpoint", watchpoint) == B_OK 1275 && PostMessage(&message) == B_OK) { 1276 watchpointReference.Detach(); 1277 } 1278 } 1279 1280 1281 void 1282 TeamDebugger::InspectRequested(target_addr_t address, 1283 TeamMemoryBlock::Listener *listener) 1284 { 1285 BMessage message(MSG_INSPECT_ADDRESS); 1286 message.AddUInt64("address", address); 1287 message.AddPointer("listener", listener); 1288 PostMessage(&message); 1289 } 1290 1291 1292 void 1293 TeamDebugger::MemoryWriteRequested(target_addr_t address, const void* data, 1294 target_size_t size) 1295 { 1296 BMessage message(MSG_WRITE_TARGET_MEMORY); 1297 message.AddUInt64("address", address); 1298 message.AddPointer("data", data); 1299 message.AddUInt64("size", size); 1300 PostMessage(&message); 1301 } 1302 1303 1304 void 1305 TeamDebugger::ExpressionEvaluationRequested(SourceLanguage* language, 1306 ExpressionInfo* info, StackFrame* frame, ::Thread* thread) 1307 { 1308 BMessage message(MSG_EVALUATE_EXPRESSION); 1309 message.AddPointer("language", language); 1310 message.AddPointer("info", info); 1311 if (frame != NULL) 1312 message.AddPointer("frame", frame); 1313 if (thread != NULL) 1314 message.AddPointer("thread", thread); 1315 1316 BReference<SourceLanguage> languageReference(language); 1317 BReference<ExpressionInfo> infoReference(info); 1318 if (PostMessage(&message) == B_OK) { 1319 languageReference.Detach(); 1320 infoReference.Detach(); 1321 } 1322 } 1323 1324 1325 void 1326 TeamDebugger::DebugReportRequested(entry_ref* targetPath) 1327 { 1328 BMessage message(MSG_GENERATE_DEBUG_REPORT); 1329 message.AddRef("target", targetPath); 1330 PostMessage(&message); 1331 } 1332 1333 1334 void 1335 TeamDebugger::WriteCoreFileRequested(entry_ref* targetPath) 1336 { 1337 BMessage message(MSG_WRITE_CORE_FILE); 1338 message.AddRef("target", targetPath); 1339 PostMessage(&message); 1340 } 1341 1342 1343 void 1344 TeamDebugger::TeamRestartRequested() 1345 { 1346 PostMessage(MSG_TEAM_RESTART_REQUESTED); 1347 } 1348 1349 1350 bool 1351 TeamDebugger::UserInterfaceQuitRequested(QuitOption quitOption) 1352 { 1353 bool askUser = false; 1354 switch (quitOption) { 1355 case QUIT_OPTION_ASK_USER: 1356 askUser = true; 1357 break; 1358 1359 case QUIT_OPTION_ASK_KILL_TEAM: 1360 fKillTeamOnQuit = true; 1361 break; 1362 1363 case QUIT_OPTION_ASK_RESUME_TEAM: 1364 break; 1365 } 1366 1367 if (askUser) { 1368 AutoLocker< ::Team> locker(fTeam); 1369 BString name(fTeam->Name()); 1370 locker.Unlock(); 1371 1372 BString message; 1373 message << "What shall be done about the debugged team '"; 1374 message << name; 1375 message << "'?"; 1376 1377 name.Remove(0, name.FindLast('/') + 1); 1378 1379 BString killLabel("Kill "); 1380 killLabel << name; 1381 1382 BString resumeLabel("Resume "); 1383 resumeLabel << name; 1384 1385 int32 choice = fUserInterface->SynchronouslyAskUser("Quit Debugger", 1386 message, killLabel, "Cancel", resumeLabel); 1387 1388 switch (choice) { 1389 case 0: 1390 fKillTeamOnQuit = true; 1391 break; 1392 case 1: 1393 case -1: 1394 return false; 1395 case 2: 1396 // Detach from the team and resume and stopped threads. 1397 break; 1398 } 1399 } 1400 1401 PostMessage(B_QUIT_REQUESTED); 1402 1403 return true; 1404 } 1405 1406 1407 void 1408 TeamDebugger::JobStarted(Job* job) 1409 { 1410 BString description(job->GetDescription()); 1411 if (!description.IsEmpty()) { 1412 description.Append(B_UTF8_ELLIPSIS); 1413 fUserInterface->NotifyBackgroundWorkStatus(description.String()); 1414 } 1415 } 1416 1417 1418 void 1419 TeamDebugger::JobDone(Job* job) 1420 { 1421 TRACE_JOBS("TeamDebugger::JobDone(%p)\n", job); 1422 _ResetUserBackgroundStatusIfNeeded(); 1423 } 1424 1425 1426 void 1427 TeamDebugger::JobWaitingForInput(Job* job) 1428 { 1429 LoadImageDebugInfoJob* infoJob = dynamic_cast<LoadImageDebugInfoJob*>(job); 1430 1431 if (infoJob == NULL) 1432 return; 1433 1434 BMessage message(MSG_DEBUG_INFO_NEEDS_USER_INPUT); 1435 message.AddPointer("job", infoJob); 1436 message.AddPointer("state", infoJob->GetLoadingState()); 1437 PostMessage(&message); 1438 } 1439 1440 1441 void 1442 TeamDebugger::JobFailed(Job* job) 1443 { 1444 TRACE_JOBS("TeamDebugger::JobFailed(%p)\n", job); 1445 // TODO: notify user 1446 _ResetUserBackgroundStatusIfNeeded(); 1447 } 1448 1449 1450 void 1451 TeamDebugger::JobAborted(Job* job) 1452 { 1453 TRACE_JOBS("TeamDebugger::JobAborted(%p)\n", job); 1454 // TODO: For a stack frame source loader thread we should reset the 1455 // loading state! Asynchronously due to locking order. 1456 _ResetUserBackgroundStatusIfNeeded(); 1457 } 1458 1459 1460 void 1461 TeamDebugger::ThreadStateChanged(const ::Team::ThreadEvent& event) 1462 { 1463 BMessage message(MSG_THREAD_STATE_CHANGED); 1464 message.AddInt32("thread", event.GetThread()->ID()); 1465 PostMessage(&message); 1466 } 1467 1468 1469 void 1470 TeamDebugger::ThreadCpuStateChanged(const ::Team::ThreadEvent& event) 1471 { 1472 BMessage message(MSG_THREAD_CPU_STATE_CHANGED); 1473 message.AddInt32("thread", event.GetThread()->ID()); 1474 PostMessage(&message); 1475 } 1476 1477 1478 void 1479 TeamDebugger::ThreadStackTraceChanged(const ::Team::ThreadEvent& event) 1480 { 1481 BMessage message(MSG_THREAD_STACK_TRACE_CHANGED); 1482 message.AddInt32("thread", event.GetThread()->ID()); 1483 PostMessage(&message); 1484 } 1485 1486 1487 void 1488 TeamDebugger::ImageDebugInfoChanged(const ::Team::ImageEvent& event) 1489 { 1490 BMessage message(MSG_IMAGE_DEBUG_INFO_CHANGED); 1491 message.AddInt32("image", event.GetImage()->ID()); 1492 PostMessage(&message); 1493 } 1494 1495 1496 /*static*/ status_t 1497 TeamDebugger::_DebugEventListenerEntry(void* data) 1498 { 1499 return ((TeamDebugger*)data)->_DebugEventListener(); 1500 } 1501 1502 1503 status_t 1504 TeamDebugger::_DebugEventListener() 1505 { 1506 while (!fTerminating) { 1507 // get the next event 1508 DebugEvent* event; 1509 status_t error = fDebuggerInterface->GetNextDebugEvent(event); 1510 if (error != B_OK) 1511 break; 1512 // TODO: Error handling! 1513 1514 if (event->Team() != fTeamID) { 1515 TRACE_EVENTS("TeamDebugger for team %" B_PRId32 ": received event " 1516 "from team %" B_PRId32 "!\n", fTeamID, event->Team()); 1517 continue; 1518 } 1519 1520 BMessage message(MSG_DEBUGGER_EVENT); 1521 if (message.AddPointer("event", event) != B_OK 1522 || PostMessage(&message) != B_OK) { 1523 // TODO: Continue thread if necessary! 1524 delete event; 1525 } 1526 } 1527 1528 return B_OK; 1529 } 1530 1531 1532 void 1533 TeamDebugger::_HandleDebuggerMessage(DebugEvent* event) 1534 { 1535 TRACE_EVENTS("TeamDebugger::_HandleDebuggerMessage(): %" B_PRId32 "\n", 1536 event->EventType()); 1537 1538 bool handled = false; 1539 1540 ThreadHandler* handler = _GetThreadHandler(event->Thread()); 1541 BReference<ThreadHandler> handlerReference(handler, true); 1542 1543 switch (event->EventType()) { 1544 case B_DEBUGGER_MESSAGE_THREAD_DEBUGGED: 1545 TRACE_EVENTS("B_DEBUGGER_MESSAGE_THREAD_DEBUGGED: thread: %" 1546 B_PRId32 "\n", event->Thread()); 1547 1548 if (handler != NULL) { 1549 handled = handler->HandleThreadDebugged( 1550 dynamic_cast<ThreadDebuggedEvent*>(event)); 1551 } 1552 break; 1553 case B_DEBUGGER_MESSAGE_DEBUGGER_CALL: 1554 TRACE_EVENTS("B_DEBUGGER_MESSAGE_DEBUGGER_CALL: thread: %" B_PRId32 1555 "\n", event->Thread()); 1556 1557 if (handler != NULL) { 1558 handled = handler->HandleDebuggerCall( 1559 dynamic_cast<DebuggerCallEvent*>(event)); 1560 } 1561 break; 1562 case B_DEBUGGER_MESSAGE_BREAKPOINT_HIT: 1563 TRACE_EVENTS("B_DEBUGGER_MESSAGE_BREAKPOINT_HIT: thread: %" B_PRId32 1564 "\n", event->Thread()); 1565 1566 if (handler != NULL) { 1567 handled = handler->HandleBreakpointHit( 1568 dynamic_cast<BreakpointHitEvent*>(event)); 1569 } 1570 break; 1571 case B_DEBUGGER_MESSAGE_WATCHPOINT_HIT: 1572 TRACE_EVENTS("B_DEBUGGER_MESSAGE_WATCHPOINT_HIT: thread: %" B_PRId32 1573 "\n", event->Thread()); 1574 1575 if (handler != NULL) { 1576 handled = handler->HandleWatchpointHit( 1577 dynamic_cast<WatchpointHitEvent*>(event)); 1578 } 1579 break; 1580 case B_DEBUGGER_MESSAGE_SINGLE_STEP: 1581 TRACE_EVENTS("B_DEBUGGER_MESSAGE_SINGLE_STEP: thread: %" B_PRId32 1582 "\n", event->Thread()); 1583 1584 if (handler != NULL) { 1585 handled = handler->HandleSingleStep( 1586 dynamic_cast<SingleStepEvent*>(event)); 1587 } 1588 break; 1589 case B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED: 1590 TRACE_EVENTS("B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED: thread: %" 1591 B_PRId32 "\n", event->Thread()); 1592 1593 if (handler != NULL) { 1594 handled = handler->HandleExceptionOccurred( 1595 dynamic_cast<ExceptionOccurredEvent*>(event)); 1596 } 1597 break; 1598 // case B_DEBUGGER_MESSAGE_TEAM_CREATED: 1599 //printf("B_DEBUGGER_MESSAGE_TEAM_CREATED: team: %ld\n", message.team_created.new_team); 1600 // break; 1601 case B_DEBUGGER_MESSAGE_TEAM_DELETED: 1602 { 1603 TRACE_EVENTS("B_DEBUGGER_MESSAGE_TEAM_DELETED: team: %" B_PRId32 1604 "\n", event->Team()); 1605 TeamDeletedEvent* teamEvent 1606 = dynamic_cast<TeamDeletedEvent*>(event); 1607 handled = _HandleTeamDeleted(teamEvent); 1608 break; 1609 } 1610 case B_DEBUGGER_MESSAGE_TEAM_EXEC: 1611 { 1612 TRACE_EVENTS("B_DEBUGGER_MESSAGE_TEAM_EXEC: team: %" B_PRId32 "\n", 1613 event->Team()); 1614 1615 TeamExecEvent* teamEvent 1616 = dynamic_cast<TeamExecEvent*>(event); 1617 _PrepareForTeamExec(teamEvent); 1618 break; 1619 } 1620 case B_DEBUGGER_MESSAGE_THREAD_CREATED: 1621 { 1622 ThreadCreatedEvent* threadEvent 1623 = dynamic_cast<ThreadCreatedEvent*>(event); 1624 TRACE_EVENTS("B_DEBUGGER_MESSAGE_THREAD_CREATED: thread: %" B_PRId32 1625 "\n", threadEvent->NewThread()); 1626 handled = _HandleThreadCreated(threadEvent); 1627 break; 1628 } 1629 case DEBUGGER_MESSAGE_THREAD_RENAMED: 1630 { 1631 ThreadRenamedEvent* threadEvent 1632 = dynamic_cast<ThreadRenamedEvent*>(event); 1633 TRACE_EVENTS("DEBUGGER_MESSAGE_THREAD_RENAMED: thread: %" B_PRId32 1634 " (\"%s\")\n", 1635 threadEvent->RenamedThread(), threadEvent->NewName()); 1636 handled = _HandleThreadRenamed(threadEvent); 1637 break; 1638 } 1639 case DEBUGGER_MESSAGE_THREAD_PRIORITY_CHANGED: 1640 { 1641 ThreadPriorityChangedEvent* threadEvent 1642 = dynamic_cast<ThreadPriorityChangedEvent*>(event); 1643 TRACE_EVENTS("B_DEBUGGER_MESSAGE_THREAD_PRIORITY_CHANGED: thread:" 1644 " %" B_PRId32 "\n", threadEvent->ChangedThread()); 1645 handled = _HandleThreadPriorityChanged(threadEvent); 1646 break; 1647 } 1648 case B_DEBUGGER_MESSAGE_THREAD_DELETED: 1649 TRACE_EVENTS("B_DEBUGGER_MESSAGE_THREAD_DELETED: thread: %" B_PRId32 1650 "\n", event->Thread()); 1651 handled = _HandleThreadDeleted( 1652 dynamic_cast<ThreadDeletedEvent*>(event)); 1653 break; 1654 case B_DEBUGGER_MESSAGE_IMAGE_CREATED: 1655 { 1656 ImageCreatedEvent* imageEvent 1657 = dynamic_cast<ImageCreatedEvent*>(event); 1658 TRACE_EVENTS("B_DEBUGGER_MESSAGE_IMAGE_CREATED: image: \"%s\" " 1659 "(%" B_PRId32 ")\n", imageEvent->GetImageInfo().Name().String(), 1660 imageEvent->GetImageInfo().ImageID()); 1661 handled = _HandleImageCreated(imageEvent); 1662 break; 1663 } 1664 case B_DEBUGGER_MESSAGE_IMAGE_DELETED: 1665 { 1666 ImageDeletedEvent* imageEvent 1667 = dynamic_cast<ImageDeletedEvent*>(event); 1668 TRACE_EVENTS("B_DEBUGGER_MESSAGE_IMAGE_DELETED: image: \"%s\" " 1669 "(%" B_PRId32 ")\n", imageEvent->GetImageInfo().Name().String(), 1670 imageEvent->GetImageInfo().ImageID()); 1671 handled = _HandleImageDeleted(imageEvent); 1672 break; 1673 } 1674 case B_DEBUGGER_MESSAGE_POST_SYSCALL: 1675 { 1676 PostSyscallEvent* postSyscallEvent 1677 = dynamic_cast<PostSyscallEvent*>(event); 1678 TRACE_EVENTS("B_DEBUGGER_MESSAGE_POST_SYSCALL: syscall: %" 1679 B_PRIu32 "\n", postSyscallEvent->GetSyscallInfo().Syscall()); 1680 handled = _HandlePostSyscall(postSyscallEvent); 1681 1682 // if a thread was blocked in a syscall when we requested to 1683 // stop it for debugging, then that request will interrupt 1684 // said call, and the post syscall event will be all we get 1685 // in response. Consequently, we need to treat this case as 1686 // equivalent to having received a thread debugged event. 1687 AutoLocker< ::Team> teamLocker(fTeam); 1688 ::Thread* thread = fTeam->ThreadByID(event->Thread()); 1689 if (handler != NULL && thread != NULL 1690 && thread->StopRequestPending()) { 1691 handled = handler->HandleThreadDebugged(NULL); 1692 } 1693 break; 1694 } 1695 case B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED: 1696 { 1697 TRACE_EVENTS("B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED: thread: %" 1698 B_PRId32 "\n", event->Thread()); 1699 1700 if (handler != NULL) { 1701 handled = handler->HandleSignalReceived( 1702 dynamic_cast<SignalReceivedEvent*>(event)); 1703 } 1704 break; 1705 } 1706 case B_DEBUGGER_MESSAGE_PRE_SYSCALL: 1707 case B_DEBUGGER_MESSAGE_PROFILER_UPDATE: 1708 case B_DEBUGGER_MESSAGE_HANDED_OVER: 1709 // not interested 1710 break; 1711 default: 1712 WARNING("TeamDebugger for team %" B_PRId32 ": unknown event type: " 1713 "%" B_PRId32 "\n", fTeamID, event->EventType()); 1714 break; 1715 } 1716 1717 if (!handled && event->ThreadStopped()) 1718 fDebuggerInterface->ContinueThread(event->Thread()); 1719 } 1720 1721 1722 bool 1723 TeamDebugger::_HandleTeamDeleted(TeamDeletedEvent* event) 1724 { 1725 char message[64]; 1726 fDebuggerInterface->Close(false); 1727 1728 snprintf(message, sizeof(message), "Team %" B_PRId32 " has terminated. ", 1729 event->Team()); 1730 1731 int32 result = fUserInterface->SynchronouslyAskUser("Team terminated", 1732 message, "Do nothing", "Quit", fCommandLineArgc != 0 1733 ? "Restart team" : NULL); 1734 1735 switch (result) { 1736 case 1: 1737 case -1: 1738 { 1739 PostMessage(B_QUIT_REQUESTED); 1740 break; 1741 } 1742 case 2: 1743 { 1744 _SaveSettings(); 1745 fListener->TeamDebuggerRestartRequested(this); 1746 break; 1747 } 1748 default: 1749 break; 1750 } 1751 1752 return true; 1753 } 1754 1755 1756 bool 1757 TeamDebugger::_HandleThreadCreated(ThreadCreatedEvent* event) 1758 { 1759 AutoLocker< ::Team> locker(fTeam); 1760 1761 ThreadInfo info; 1762 status_t error = fDebuggerInterface->GetThreadInfo(event->NewThread(), 1763 info); 1764 if (error == B_OK) { 1765 ::Thread* thread; 1766 fTeam->AddThread(info, &thread); 1767 1768 ThreadHandler* handler = new(std::nothrow) ThreadHandler(thread, 1769 fWorker, fDebuggerInterface, this, fBreakpointManager); 1770 if (handler != NULL) { 1771 fThreadHandlers.Insert(handler); 1772 handler->Init(); 1773 } 1774 } 1775 1776 return false; 1777 } 1778 1779 1780 bool 1781 TeamDebugger::_HandleThreadRenamed(ThreadRenamedEvent* event) 1782 { 1783 AutoLocker< ::Team> locker(fTeam); 1784 1785 ::Thread* thread = fTeam->ThreadByID(event->RenamedThread()); 1786 1787 if (thread != NULL) 1788 thread->SetName(event->NewName()); 1789 1790 return false; 1791 } 1792 1793 1794 bool 1795 TeamDebugger::_HandleThreadPriorityChanged(ThreadPriorityChangedEvent*) 1796 { 1797 // TODO: implement once we actually track thread priorities 1798 1799 return false; 1800 } 1801 1802 1803 bool 1804 TeamDebugger::_HandleThreadDeleted(ThreadDeletedEvent* event) 1805 { 1806 AutoLocker< ::Team> locker(fTeam); 1807 if (ThreadHandler* handler = fThreadHandlers.Lookup(event->Thread())) { 1808 fThreadHandlers.Remove(handler); 1809 handler->ReleaseReference(); 1810 } 1811 fTeam->RemoveThread(event->Thread()); 1812 return false; 1813 } 1814 1815 1816 bool 1817 TeamDebugger::_HandleImageCreated(ImageCreatedEvent* event) 1818 { 1819 AutoLocker< ::Team> locker(fTeam); 1820 _AddImage(event->GetImageInfo()); 1821 1822 ImageInfoPendingThread* info = new(std::nothrow) ImageInfoPendingThread( 1823 event->GetImageInfo().ImageID(), event->Thread()); 1824 if (info == NULL) 1825 return false; 1826 1827 fImageInfoPendingThreads->Insert(info); 1828 return true; 1829 } 1830 1831 1832 bool 1833 TeamDebugger::_HandleImageDeleted(ImageDeletedEvent* event) 1834 { 1835 AutoLocker< ::Team> locker(fTeam); 1836 fTeam->RemoveImage(event->GetImageInfo().ImageID()); 1837 1838 ImageHandler* imageHandler = fImageHandlers->Lookup( 1839 event->GetImageInfo().ImageID()); 1840 if (imageHandler == NULL) 1841 return false; 1842 1843 fImageHandlers->Remove(imageHandler); 1844 BReference<ImageHandler> imageHandlerReference(imageHandler, true); 1845 locker.Unlock(); 1846 1847 // remove breakpoints in the image 1848 fBreakpointManager->RemoveImageBreakpoints(imageHandler->GetImage()); 1849 1850 return false; 1851 } 1852 1853 1854 bool 1855 TeamDebugger::_HandlePostSyscall(PostSyscallEvent* event) 1856 { 1857 const SyscallInfo& info = event->GetSyscallInfo(); 1858 1859 switch (info.Syscall()) { 1860 case SYSCALL_WRITE: 1861 { 1862 if ((ssize_t)info.ReturnValue() <= 0) 1863 break; 1864 1865 int32 fd; 1866 target_addr_t address; 1867 size_t size; 1868 // TODO: decoding the syscall arguments should probably be 1869 // factored out into an Architecture method of its own, since 1870 // there's no guarantee the target architecture has the same 1871 // endianness as the host. This could re-use the syscall 1872 // argument parser that strace uses, though that would need to 1873 // be adapted to handle the aforementioned endian differences. 1874 // This works for x86{-64} for now though. 1875 if (fTeam->GetArchitecture()->AddressSize() == 4) { 1876 const uint32* args = (const uint32*)info.Arguments(); 1877 fd = args[0]; 1878 address = args[3]; 1879 size = args[4]; 1880 } else { 1881 const uint64* args = (const uint64*)info.Arguments(); 1882 fd = args[0]; 1883 address = args[2]; 1884 size = args[3]; 1885 } 1886 1887 if (fd == 1 || fd == 2) { 1888 BString data; 1889 1890 ssize_t result = fDebuggerInterface->ReadMemoryString( 1891 address, size, data); 1892 if (result >= 0) 1893 fTeam->NotifyConsoleOutputReceived(fd, data); 1894 } 1895 break; 1896 } 1897 case SYSCALL_WRITEV: 1898 { 1899 // TODO: handle 1900 } 1901 default: 1902 break; 1903 } 1904 1905 return false; 1906 } 1907 1908 1909 void 1910 TeamDebugger::_PrepareForTeamExec(TeamExecEvent* event) 1911 { 1912 // NB: must be called with team lock held. 1913 1914 _SaveSettings(); 1915 1916 // when notified of exec, we need to clear out data related 1917 // to the old team. 1918 const ImageList& images = fTeam->Images(); 1919 1920 for (ImageList::ConstIterator it = images.GetIterator(); 1921 Image* image = it.Next();) { 1922 fBreakpointManager->RemoveImageBreakpoints(image); 1923 } 1924 1925 BObjectList<UserBreakpoint> breakpointsToRemove(20, false); 1926 const UserBreakpointList& breakpoints = fTeam->UserBreakpoints(); 1927 for (UserBreakpointList::ConstIterator it = breakpoints.GetIterator(); 1928 UserBreakpoint* breakpoint = it.Next();) { 1929 breakpointsToRemove.AddItem(breakpoint); 1930 breakpoint->AcquireReference(); 1931 } 1932 1933 for (int32 i = 0; i < breakpointsToRemove.CountItems(); i++) { 1934 UserBreakpoint* breakpoint = breakpointsToRemove.ItemAt(i); 1935 fTeam->RemoveUserBreakpoint(breakpoint); 1936 fTeam->NotifyUserBreakpointChanged(breakpoint); 1937 breakpoint->ReleaseReference(); 1938 } 1939 1940 fTeam->ClearImages(); 1941 fTeam->ClearSignalDispositionMappings(); 1942 fExecPending = true; 1943 } 1944 1945 1946 void 1947 TeamDebugger::_HandleImageDebugInfoChanged(image_id imageID) 1948 { 1949 // get the image (via the image handler) 1950 AutoLocker< ::Team> locker(fTeam); 1951 ImageHandler* imageHandler = fImageHandlers->Lookup(imageID); 1952 if (imageHandler == NULL) 1953 return; 1954 1955 Image* image = imageHandler->GetImage(); 1956 BReference<Image> imageReference(image); 1957 image_debug_info_state state = image->ImageDebugInfoState(); 1958 1959 bool handlePostExecSetup = fExecPending && image->Type() == B_APP_IMAGE 1960 && state != IMAGE_DEBUG_INFO_LOADING; 1961 // this needs to be done first so that breakpoints are loaded. 1962 // otherwise, UpdateImageBreakpoints() won't find the appropriate 1963 // UserBreakpoints to create/install instances for. 1964 if (handlePostExecSetup) { 1965 fTeam->SetName(image->Name()); 1966 _LoadSettings(); 1967 fExecPending = false; 1968 } 1969 1970 locker.Unlock(); 1971 1972 if (state == IMAGE_DEBUG_INFO_LOADED 1973 || state == IMAGE_DEBUG_INFO_UNAVAILABLE) { 1974 1975 // update breakpoints in the image 1976 fBreakpointManager->UpdateImageBreakpoints(image); 1977 1978 ImageInfoPendingThread* thread = fImageInfoPendingThreads 1979 ->Lookup(imageID); 1980 if (thread != NULL) { 1981 fImageInfoPendingThreads->Remove(thread); 1982 ObjectDeleter<ImageInfoPendingThread> threadDeleter(thread); 1983 locker.Lock(); 1984 ThreadHandler* handler = _GetThreadHandler(thread->ThreadID()); 1985 BReference<ThreadHandler> handlerReference(handler, true); 1986 if (fTeam->StopOnImageLoad()) { 1987 1988 bool stop = true; 1989 const BString& imageName = image->Name(); 1990 // only match on the image filename itself 1991 const char* rawImageName = imageName.String() 1992 + imageName.FindLast('/') + 1; 1993 if (fTeam->StopImageNameListEnabled()) { 1994 const BStringList& nameList = fTeam->StopImageNames(); 1995 stop = nameList.HasString(rawImageName); 1996 } 1997 1998 if (stop && handler != NULL) { 1999 BString stopReason; 2000 stopReason.SetToFormat("Image '%s' loaded.", 2001 rawImageName); 2002 locker.Unlock(); 2003 2004 if (handler->HandleThreadDebugged(NULL, stopReason)) 2005 return; 2006 } else 2007 locker.Unlock(); 2008 } else if (handlePostExecSetup) { 2009 // in the case of an exec(), we can't stop in main() until 2010 // the new app image has been loaded, so we know where to 2011 // set the main breakpoint at. 2012 SymbolInfo symbolInfo; 2013 if (fDebuggerInterface->GetSymbolInfo(fTeam->ID(), image->ID(), 2014 "main", B_SYMBOL_TYPE_TEXT, symbolInfo) == B_OK) { 2015 handler->SetBreakpointAndRun(symbolInfo.Address()); 2016 } 2017 } else { 2018 locker.Unlock(); 2019 fDebuggerInterface->ContinueThread(thread->ThreadID()); 2020 } 2021 } 2022 } 2023 } 2024 2025 2026 void 2027 TeamDebugger::_HandleImageFileChanged(image_id imageID) 2028 { 2029 TRACE_IMAGES("TeamDebugger::_HandleImageFileChanged(%" B_PRId32 ")\n", 2030 imageID); 2031 // TODO: Reload the debug info! 2032 } 2033 2034 2035 void 2036 TeamDebugger::_HandleSetUserBreakpoint(target_addr_t address, bool enabled, 2037 bool hidden) 2038 { 2039 TRACE_CONTROL("TeamDebugger::_HandleSetUserBreakpoint(%#" B_PRIx64 2040 ", %d, %d)\n", address, enabled, hidden); 2041 2042 // check whether there already is a breakpoint 2043 AutoLocker< ::Team> locker(fTeam); 2044 2045 Breakpoint* breakpoint = fTeam->BreakpointAtAddress(address); 2046 UserBreakpoint* userBreakpoint = NULL; 2047 if (breakpoint != NULL && breakpoint->FirstUserBreakpoint() != NULL) 2048 userBreakpoint = breakpoint->FirstUserBreakpoint()->GetUserBreakpoint(); 2049 BReference<UserBreakpoint> userBreakpointReference(userBreakpoint); 2050 2051 if (userBreakpoint == NULL) { 2052 TRACE_CONTROL(" no breakpoint yet\n"); 2053 2054 // get the function at the address 2055 Image* image = fTeam->ImageByAddress(address); 2056 2057 TRACE_CONTROL(" image: %p\n", image); 2058 2059 if (image == NULL) 2060 return; 2061 ImageDebugInfo* imageDebugInfo = image->GetImageDebugInfo(); 2062 2063 TRACE_CONTROL(" image debug info: %p\n", imageDebugInfo); 2064 2065 if (imageDebugInfo == NULL) 2066 return; 2067 // TODO: Handle this case by loading the debug info, if possible! 2068 FunctionInstance* functionInstance 2069 = imageDebugInfo->FunctionAtAddress(address); 2070 2071 TRACE_CONTROL(" function instance: %p\n", functionInstance); 2072 2073 if (functionInstance == NULL) 2074 return; 2075 Function* function = functionInstance->GetFunction(); 2076 2077 TRACE_CONTROL(" function: %p\n", function); 2078 2079 // get the source location for the address 2080 FunctionDebugInfo* functionDebugInfo 2081 = functionInstance->GetFunctionDebugInfo(); 2082 SourceLocation sourceLocation; 2083 Statement* breakpointStatement = NULL; 2084 if (functionDebugInfo->GetSpecificImageDebugInfo()->GetStatement( 2085 functionDebugInfo, address, breakpointStatement) != B_OK) { 2086 return; 2087 } 2088 2089 sourceLocation = breakpointStatement->StartSourceLocation(); 2090 breakpointStatement->ReleaseReference(); 2091 2092 target_addr_t relativeAddress = address - functionInstance->Address(); 2093 2094 TRACE_CONTROL(" relative address: %#" B_PRIx64 ", source location: " 2095 "(%" B_PRId32 ", %" B_PRId32 ")\n", relativeAddress, 2096 sourceLocation.Line(), sourceLocation.Column()); 2097 2098 // get function id 2099 FunctionID* functionID = functionInstance->GetFunctionID(); 2100 if (functionID == NULL) 2101 return; 2102 BReference<FunctionID> functionIDReference(functionID, true); 2103 2104 // create the user breakpoint 2105 userBreakpoint = new(std::nothrow) UserBreakpoint( 2106 UserBreakpointLocation(functionID, function->SourceFile(), 2107 sourceLocation, relativeAddress)); 2108 if (userBreakpoint == NULL) 2109 return; 2110 userBreakpointReference.SetTo(userBreakpoint, true); 2111 2112 userBreakpoint->SetHidden(hidden); 2113 2114 TRACE_CONTROL(" created user breakpoint: %p\n", userBreakpoint); 2115 2116 // iterate through all function instances and create 2117 // UserBreakpointInstances 2118 for (FunctionInstanceList::ConstIterator it 2119 = function->Instances().GetIterator(); 2120 FunctionInstance* instance = it.Next();) { 2121 TRACE_CONTROL(" function instance %p: range: %#" B_PRIx64 " - %#" 2122 B_PRIx64 "\n", instance, instance->Address(), 2123 instance->Address() + instance->Size()); 2124 2125 // get the breakpoint address for the instance 2126 target_addr_t instanceAddress = 0; 2127 if (instance == functionInstance) { 2128 instanceAddress = address; 2129 } else if (functionInstance->SourceFile() != NULL) { 2130 // We have a source file, so get the address for the source 2131 // location. 2132 Statement* statement = NULL; 2133 functionDebugInfo = instance->GetFunctionDebugInfo(); 2134 functionDebugInfo->GetSpecificImageDebugInfo() 2135 ->GetStatementAtSourceLocation(functionDebugInfo, 2136 sourceLocation, statement); 2137 if (statement != NULL) { 2138 instanceAddress = statement->CoveringAddressRange().Start(); 2139 // TODO: What about BreakpointAllowed()? 2140 statement->ReleaseReference(); 2141 } 2142 } 2143 2144 TRACE_CONTROL(" breakpoint address using source info: %" B_PRIx64 2145 "\n", instanceAddress); 2146 2147 if (instanceAddress == 0) { 2148 // No source file (or we failed getting the statement), so try 2149 // to use the same relative address. 2150 if (relativeAddress > instance->Size()) 2151 continue; 2152 instanceAddress = instance->Address() + relativeAddress; 2153 } 2154 2155 TRACE_CONTROL(" final breakpoint address: %" B_PRIx64 "\n", 2156 instanceAddress); 2157 2158 UserBreakpointInstance* breakpointInstance = new(std::nothrow) 2159 UserBreakpointInstance(userBreakpoint, instanceAddress); 2160 if (breakpointInstance == NULL 2161 || !userBreakpoint->AddInstance(breakpointInstance)) { 2162 delete breakpointInstance; 2163 return; 2164 } 2165 2166 TRACE_CONTROL(" breakpoint instance: %p\n", breakpointInstance); 2167 } 2168 } 2169 2170 locker.Unlock(); 2171 2172 _HandleSetUserBreakpoint(userBreakpoint, enabled); 2173 } 2174 2175 2176 void 2177 TeamDebugger::_HandleSetUserBreakpoint(UserBreakpoint* breakpoint, bool enabled) 2178 { 2179 status_t error = fBreakpointManager->InstallUserBreakpoint(breakpoint, 2180 enabled); 2181 if (error != B_OK) { 2182 _NotifyUser("Install Breakpoint", "Failed to install breakpoint: %s", 2183 strerror(error)); 2184 } 2185 } 2186 2187 2188 void 2189 TeamDebugger::_HandleClearUserBreakpoint(target_addr_t address) 2190 { 2191 TRACE_CONTROL("TeamDebugger::_HandleClearUserBreakpoint(%#" B_PRIx64 ")\n", 2192 address); 2193 2194 AutoLocker< ::Team> locker(fTeam); 2195 2196 Breakpoint* breakpoint = fTeam->BreakpointAtAddress(address); 2197 if (breakpoint == NULL || breakpoint->FirstUserBreakpoint() == NULL) 2198 return; 2199 UserBreakpoint* userBreakpoint 2200 = breakpoint->FirstUserBreakpoint()->GetUserBreakpoint(); 2201 BReference<UserBreakpoint> userBreakpointReference(userBreakpoint); 2202 2203 locker.Unlock(); 2204 2205 _HandleClearUserBreakpoint(userBreakpoint); 2206 } 2207 2208 2209 void 2210 TeamDebugger::_HandleClearUserBreakpoint(UserBreakpoint* breakpoint) 2211 { 2212 fBreakpointManager->UninstallUserBreakpoint(breakpoint); 2213 } 2214 2215 2216 void 2217 TeamDebugger::_HandleSetWatchpoint(target_addr_t address, uint32 type, 2218 int32 length, bool enabled) 2219 { 2220 Watchpoint* watchpoint = new(std::nothrow) Watchpoint(address, type, 2221 length); 2222 2223 if (watchpoint == NULL) 2224 return; 2225 BReference<Watchpoint> watchpointRef(watchpoint, true); 2226 2227 _HandleSetWatchpoint(watchpoint, enabled); 2228 } 2229 2230 2231 void 2232 TeamDebugger::_HandleSetWatchpoint(Watchpoint* watchpoint, bool enabled) 2233 { 2234 status_t error = fWatchpointManager->InstallWatchpoint(watchpoint, 2235 enabled); 2236 if (error != B_OK) { 2237 _NotifyUser("Install Watchpoint", "Failed to install watchpoint: %s", 2238 strerror(error)); 2239 } 2240 } 2241 2242 2243 void 2244 TeamDebugger::_HandleClearWatchpoint(target_addr_t address) 2245 { 2246 TRACE_CONTROL("TeamDebugger::_HandleClearWatchpoint(%#" B_PRIx64 ")\n", 2247 address); 2248 2249 AutoLocker< ::Team> locker(fTeam); 2250 2251 Watchpoint* watchpoint = fTeam->WatchpointAtAddress(address); 2252 if (watchpoint == NULL) 2253 return; 2254 BReference<Watchpoint> watchpointReference(watchpoint); 2255 2256 locker.Unlock(); 2257 2258 _HandleClearWatchpoint(watchpoint); 2259 } 2260 2261 2262 void 2263 TeamDebugger::_HandleClearWatchpoint(Watchpoint* watchpoint) 2264 { 2265 fWatchpointManager->UninstallWatchpoint(watchpoint); 2266 } 2267 2268 2269 void 2270 TeamDebugger::_HandleInspectAddress(target_addr_t address, 2271 TeamMemoryBlock::Listener* listener) 2272 { 2273 TRACE_CONTROL("TeamDebugger::_HandleInspectAddress(%" B_PRIx64 ", %p)\n", 2274 address, listener); 2275 2276 TeamMemoryBlock* memoryBlock = fMemoryBlockManager 2277 ->GetMemoryBlock(address); 2278 2279 if (memoryBlock == NULL) { 2280 _NotifyUser("Inspect Address", "Failed to allocate memory block"); 2281 return; 2282 } 2283 2284 if (!memoryBlock->IsValid()) { 2285 AutoLocker< ::Team> teamLocker(fTeam); 2286 2287 if (!memoryBlock->HasListener(listener)) 2288 memoryBlock->AddListener(listener); 2289 2290 TeamMemory* memory = fTeam->GetTeamMemory(); 2291 // schedule the job 2292 status_t result; 2293 if ((result = fWorker->ScheduleJob( 2294 new(std::nothrow) RetrieveMemoryBlockJob(fTeam, memory, 2295 memoryBlock), 2296 this)) != B_OK) { 2297 2298 memoryBlock->NotifyDataRetrieved(result); 2299 memoryBlock->ReleaseReference(); 2300 2301 _NotifyUser("Inspect Address", "Failed to retrieve memory data: %s", 2302 strerror(result)); 2303 } 2304 } else 2305 memoryBlock->NotifyDataRetrieved(); 2306 2307 } 2308 2309 2310 void 2311 TeamDebugger::_HandleWriteMemory(target_addr_t address, void* data, 2312 target_size_t size) 2313 { 2314 TRACE_CONTROL("TeamDebugger::_HandleWriteTargetMemory(%" B_PRIx64 ", %p, " 2315 "%" B_PRIu64 ")\n", address, data, size); 2316 2317 AutoLocker< ::Team> teamLocker(fTeam); 2318 TeamMemory* memory = fTeam->GetTeamMemory(); 2319 // schedule the job 2320 status_t result; 2321 if ((result = fWorker->ScheduleJob( 2322 new(std::nothrow) WriteMemoryJob(fTeam, memory, address, data, size), 2323 this)) != B_OK) { 2324 _NotifyUser("Write Memory", "Failed to write memory data: %s", 2325 strerror(result)); 2326 } 2327 } 2328 2329 2330 void 2331 TeamDebugger::_HandleEvaluateExpression(SourceLanguage* language, 2332 ExpressionInfo* info, StackFrame* frame, ::Thread* thread) 2333 { 2334 status_t result = fWorker->ScheduleJob( 2335 new(std::nothrow) ExpressionEvaluationJob(fTeam, fDebuggerInterface, 2336 language, info, frame, thread)); 2337 if (result != B_OK) { 2338 _NotifyUser("Evaluate Expression", "Failed to evaluate expression: %s", 2339 strerror(result)); 2340 } 2341 } 2342 2343 2344 void 2345 TeamDebugger::_HandleWriteCoreFile(const entry_ref& targetPath) 2346 { 2347 status_t result = fWorker->ScheduleJob( 2348 new(std::nothrow) WriteCoreFileJob(fTeam, fDebuggerInterface, 2349 targetPath)); 2350 if (result != B_OK) { 2351 _NotifyUser("Write Core File", "Failed to write core file: %s", 2352 strerror(result)); 2353 } 2354 } 2355 2356 2357 status_t 2358 TeamDebugger::_HandleSetArguments(int argc, const char* const* argv) 2359 { 2360 fCommandLineArgc = argc; 2361 fCommandLineArgv = new(std::nothrow) const char*[argc]; 2362 if (fCommandLineArgv == NULL) 2363 return B_NO_MEMORY; 2364 2365 memset(const_cast<char **>(fCommandLineArgv), 0, sizeof(char*) * argc); 2366 2367 for (int i = 0; i < argc; i++) { 2368 fCommandLineArgv[i] = strdup(argv[i]); 2369 if (fCommandLineArgv[i] == NULL) 2370 return B_NO_MEMORY; 2371 } 2372 2373 return B_OK; 2374 } 2375 2376 2377 void 2378 TeamDebugger::_HandleDebugInfoJobUserInput(ImageDebugInfoLoadingState* state) 2379 { 2380 SpecificImageDebugInfoLoadingState* specificState 2381 = state->GetSpecificDebugInfoLoadingState(); 2382 2383 ImageDebugLoadingStateHandler* handler; 2384 if (ImageDebugLoadingStateHandlerRoster::Default() 2385 ->FindStateHandler(specificState, handler) != B_OK) { 2386 TRACE_JOBS("TeamDebugger::_HandleDebugInfoJobUserInput(): " 2387 "Failed to find appropriate information handler, aborting."); 2388 return; 2389 } 2390 2391 handler->HandleState(specificState, fUserInterface); 2392 } 2393 2394 2395 ThreadHandler* 2396 TeamDebugger::_GetThreadHandler(thread_id threadID) 2397 { 2398 AutoLocker< ::Team> locker(fTeam); 2399 2400 ThreadHandler* handler = fThreadHandlers.Lookup(threadID); 2401 if (handler != NULL) 2402 handler->AcquireReference(); 2403 return handler; 2404 } 2405 2406 2407 status_t 2408 TeamDebugger::_AddImage(const ImageInfo& imageInfo, Image** _image) 2409 { 2410 LocatableFile* file = NULL; 2411 if (strchr(imageInfo.Name(), '/') != NULL) 2412 file = fFileManager->GetTargetFile(imageInfo.Name()); 2413 BReference<LocatableFile> imageFileReference(file, true); 2414 2415 Image* image; 2416 status_t error = fTeam->AddImage(imageInfo, file, &image); 2417 if (error != B_OK) 2418 return error; 2419 2420 ImageDebugInfoRequested(image); 2421 2422 ImageHandler* imageHandler = new(std::nothrow) ImageHandler(this, image); 2423 if (imageHandler != NULL) 2424 fImageHandlers->Insert(imageHandler); 2425 2426 if (_image != NULL) 2427 *_image = image; 2428 2429 return B_OK; 2430 } 2431 2432 2433 void 2434 TeamDebugger::_LoadSettings() 2435 { 2436 // get the team name 2437 AutoLocker< ::Team> locker(fTeam); 2438 BString teamName = fTeam->Name(); 2439 locker.Unlock(); 2440 2441 // load the settings 2442 if (fSettingsManager->LoadTeamSettings(teamName, fTeamSettings) != B_OK) 2443 return; 2444 2445 // create the saved breakpoints 2446 for (int32 i = 0; const BreakpointSetting* breakpointSetting 2447 = fTeamSettings.BreakpointAt(i); i++) { 2448 if (breakpointSetting->GetFunctionID() == NULL) 2449 continue; 2450 2451 // get the source file, if any 2452 LocatableFile* sourceFile = NULL; 2453 if (breakpointSetting->SourceFile().Length() > 0) { 2454 sourceFile = fFileManager->GetSourceFile( 2455 breakpointSetting->SourceFile()); 2456 if (sourceFile == NULL) 2457 continue; 2458 } 2459 BReference<LocatableFile> sourceFileReference(sourceFile, true); 2460 2461 // create the breakpoint 2462 UserBreakpointLocation location(breakpointSetting->GetFunctionID(), 2463 sourceFile, breakpointSetting->GetSourceLocation(), 2464 breakpointSetting->RelativeAddress()); 2465 2466 UserBreakpoint* breakpoint = new(std::nothrow) UserBreakpoint(location); 2467 if (breakpoint == NULL) 2468 return; 2469 BReference<UserBreakpoint> breakpointReference(breakpoint, true); 2470 2471 breakpoint->SetHidden(breakpointSetting->IsHidden()); 2472 breakpoint->SetCondition(breakpointSetting->Condition()); 2473 2474 // install it 2475 fBreakpointManager->InstallUserBreakpoint(breakpoint, 2476 breakpointSetting->IsEnabled()); 2477 } 2478 2479 fFileManager->LoadLocationMappings(fTeamSettings.FileManagerSettings()); 2480 2481 const TeamUiSettings* uiSettings = fTeamSettings.UiSettingFor( 2482 fUserInterface->ID()); 2483 if (uiSettings != NULL) 2484 fUserInterface->LoadSettings(uiSettings); 2485 2486 const TeamSignalSettings* signalSettings = fTeamSettings.SignalSettings(); 2487 if (signalSettings != NULL) { 2488 fTeam->SetDefaultSignalDisposition( 2489 signalSettings->DefaultSignalDisposition()); 2490 2491 int32 signal; 2492 int32 disposition; 2493 for (int32 i = 0; i < signalSettings->CountCustomSignalDispositions(); 2494 i++) { 2495 if (signalSettings->GetCustomSignalDispositionAt(i, signal, 2496 disposition) == B_OK) { 2497 fTeam->SetCustomSignalDisposition(signal, disposition); 2498 } 2499 } 2500 } 2501 } 2502 2503 2504 void 2505 TeamDebugger::_SaveSettings() 2506 { 2507 // get the settings 2508 AutoLocker< ::Team> locker(fTeam); 2509 TeamSettings settings; 2510 if (settings.SetTo(fTeam) != B_OK) 2511 return; 2512 2513 TeamUiSettings* uiSettings = NULL; 2514 if (fUserInterface->SaveSettings(uiSettings) != B_OK) 2515 return; 2516 if (uiSettings != NULL) 2517 settings.AddUiSettings(uiSettings); 2518 2519 // preserve the UI settings from our cached copy. 2520 for (int32 i = 0; i < fTeamSettings.CountUiSettings(); i++) { 2521 const TeamUiSettings* oldUiSettings = fTeamSettings.UiSettingAt(i); 2522 if (strcmp(oldUiSettings->ID(), fUserInterface->ID()) != 0) { 2523 TeamUiSettings* clonedSettings = oldUiSettings->Clone(); 2524 if (clonedSettings != NULL) 2525 settings.AddUiSettings(clonedSettings); 2526 } 2527 } 2528 2529 fFileManager->SaveLocationMappings(settings.FileManagerSettings()); 2530 locker.Unlock(); 2531 2532 // save the settings 2533 fSettingsManager->SaveTeamSettings(settings); 2534 } 2535 2536 2537 void 2538 TeamDebugger::_NotifyUser(const char* title, const char* text,...) 2539 { 2540 // print the message 2541 char buffer[1024]; 2542 va_list args; 2543 va_start(args, text); 2544 vsnprintf(buffer, sizeof(buffer), text, args); 2545 va_end(args); 2546 2547 // notify the user 2548 fUserInterface->NotifyUser(title, buffer, USER_NOTIFICATION_WARNING); 2549 } 2550 2551 2552 void 2553 TeamDebugger::_ResetUserBackgroundStatusIfNeeded() 2554 { 2555 if (!fTerminating && !fWorker->HasPendingJobs()) 2556 PostMessage(MSG_RESET_USER_BACKGROUND_STATUS); 2557 } 2558 2559 2560 // #pragma mark - Listener 2561 2562 2563 TeamDebugger::Listener::~Listener() 2564 { 2565 } 2566