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