1/* 2 * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2010-2011, Rene Gollent, rene@gollent.com. 4 * Distributed under the terms of the MIT License. 5 */ 6 7 8#include "TeamDebugger.h" 9 10#include <stdarg.h> 11#include <stdio.h> 12 13#include <new> 14 15#include <Entry.h> 16#include <Message.h> 17 18#include <AutoLocker.h> 19 20#include "debug_utils.h" 21 22#include "BreakpointManager.h" 23#include "BreakpointSetting.h" 24#include "CpuState.h" 25#include "DebuggerInterface.h" 26#include "DebugReportGenerator.h" 27#include "FileManager.h" 28#include "Function.h" 29#include "FunctionID.h" 30#include "ImageDebugInfo.h" 31#include "Jobs.h" 32#include "LocatableFile.h" 33#include "MessageCodes.h" 34#include "SettingsManager.h" 35#include "SourceCode.h" 36#include "SpecificImageDebugInfo.h" 37#include "StackFrame.h" 38#include "StackFrameValues.h" 39#include "Statement.h" 40#include "SymbolInfo.h" 41#include "TeamDebugInfo.h" 42#include "TeamMemoryBlock.h" 43#include "TeamMemoryBlockManager.h" 44#include "TeamSettings.h" 45#include "TeamUiSettings.h" 46#include "Tracing.h" 47#include "ValueNode.h" 48#include "ValueNodeContainer.h" 49#include "Variable.h" 50#include "WatchpointManager.h" 51 52 53// #pragma mark - ImageHandler 54 55 56struct TeamDebugger::ImageHandler : public BReferenceable, 57 private LocatableFile::Listener { 58public: 59 ImageHandler(TeamDebugger* teamDebugger, Image* image) 60 : 61 fTeamDebugger(teamDebugger), 62 fImage(image) 63 { 64 fImage->AcquireReference(); 65 if (fImage->ImageFile() != NULL) 66 fImage->ImageFile()->AddListener(this); 67 } 68 69 ~ImageHandler() 70 { 71 if (fImage->ImageFile() != NULL) 72 fImage->ImageFile()->RemoveListener(this); 73 fImage->ReleaseReference(); 74 } 75 76 Image* GetImage() const 77 { 78 return fImage; 79 } 80 81 image_id ImageID() const 82 { 83 return fImage->ID(); 84 } 85 86private: 87 // LocatableFile::Listener 88 virtual void LocatableFileChanged(LocatableFile* file) 89 { 90 BMessage message(MSG_IMAGE_FILE_CHANGED); 91 message.AddInt32("image", fImage->ID()); 92 fTeamDebugger->PostMessage(&message); 93 } 94 95private: 96 TeamDebugger* fTeamDebugger; 97 Image* fImage; 98 99public: 100 ImageHandler* fNext; 101}; 102 103 104// #pragma mark - ImageHandlerHashDefinition 105 106 107struct TeamDebugger::ImageHandlerHashDefinition { 108 typedef image_id KeyType; 109 typedef ImageHandler ValueType; 110 111 size_t HashKey(image_id key) const 112 { 113 return (size_t)key; 114 } 115 116 size_t Hash(const ImageHandler* value) const 117 { 118 return HashKey(value->ImageID()); 119 } 120 121 bool Compare(image_id key, const ImageHandler* value) const 122 { 123 return value->ImageID() == key; 124 } 125 126 ImageHandler*& GetLink(ImageHandler* value) const 127 { 128 return value->fNext; 129 } 130}; 131 132 133// #pragma mark - ImageInfoPendingThread 134 135 136struct TeamDebugger::ImageInfoPendingThread { 137public: 138 ImageInfoPendingThread(image_id image, thread_id thread) 139 : 140 fImage(image), 141 fThread(thread) 142 { 143 } 144 145 ~ImageInfoPendingThread() 146 { 147 } 148 149 image_id ImageID() const 150 { 151 return fImage; 152 } 153 154 thread_id ThreadID() const 155 { 156 return fThread; 157 } 158 159private: 160 image_id fImage; 161 thread_id fThread; 162 163public: 164 ImageInfoPendingThread* fNext; 165}; 166 167 168// #pragma mark - ImageHandlerHashDefinition 169 170 171struct TeamDebugger::ImageInfoPendingThreadHashDefinition { 172 typedef image_id KeyType; 173 typedef ImageInfoPendingThread ValueType; 174 175 size_t HashKey(image_id key) const 176 { 177 return (size_t)key; 178 } 179 180 size_t Hash(const ImageInfoPendingThread* value) const 181 { 182 return HashKey(value->ImageID()); 183 } 184 185 bool Compare(image_id key, const ImageInfoPendingThread* value) const 186 { 187 return value->ImageID() == key; 188 } 189 190 ImageInfoPendingThread*& GetLink(ImageInfoPendingThread* value) const 191 { 192 return value->fNext; 193 } 194}; 195 196 197// #pragma mark - TeamDebugger 198 199 200TeamDebugger::TeamDebugger(Listener* listener, UserInterface* userInterface, 201 SettingsManager* settingsManager) 202 : 203 BLooper("team debugger"), 204 fListener(listener), 205 fSettingsManager(settingsManager), 206 fTeam(NULL), 207 fTeamID(-1), 208 fImageHandlers(NULL), 209 fImageInfoPendingThreads(NULL), 210 fDebuggerInterface(NULL), 211 fFileManager(NULL), 212 fWorker(NULL), 213 fBreakpointManager(NULL), 214 fWatchpointManager(NULL), 215 fMemoryBlockManager(NULL), 216 fReportGenerator(NULL), 217 fDebugEventListener(-1), 218 fUserInterface(userInterface), 219 fTerminating(false), 220 fKillTeamOnQuit(false) 221{ 222 fUserInterface->AcquireReference(); 223} 224 225 226TeamDebugger::~TeamDebugger() 227{ 228 if (fTeam != NULL) 229 _SaveSettings(); 230 231 AutoLocker<BLooper> locker(this); 232 233 fTerminating = true; 234 235 if (fDebuggerInterface != NULL) { 236 fDebuggerInterface->Close(fKillTeamOnQuit); 237 fDebuggerInterface->ReleaseReference(); 238 } 239 240 if (fWorker != NULL) 241 fWorker->ShutDown(); 242 243 locker.Unlock(); 244 245 if (fDebugEventListener >= 0) 246 wait_for_thread(fDebugEventListener, NULL); 247 248 // terminate UI 249 if (fUserInterface != NULL) { 250 fUserInterface->Terminate(); 251 fUserInterface->ReleaseReference(); 252 } 253 254 ThreadHandler* threadHandler = fThreadHandlers.Clear(true); 255 while (threadHandler != NULL) { 256 ThreadHandler* next = threadHandler->fNext; 257 threadHandler->ReleaseReference(); 258 threadHandler = next; 259 } 260 261 if (fImageHandlers != NULL) { 262 ImageHandler* imageHandler = fImageHandlers->Clear(true); 263 while (imageHandler != NULL) { 264 ImageHandler* next = imageHandler->fNext; 265 imageHandler->ReleaseReference(); 266 imageHandler = next; 267 } 268 } 269 270 delete fImageHandlers; 271 272 if (fImageInfoPendingThreads != NULL) { 273 ImageInfoPendingThread* thread = fImageInfoPendingThreads->Clear(true); 274 while (thread != NULL) { 275 ImageInfoPendingThread* next = thread->fNext; 276 delete thread; 277 thread = next; 278 } 279 } 280 281 if (fReportGenerator != NULL) { 282 fReportGenerator->Lock(); 283 fReportGenerator->Quit(); 284 } 285 286 delete fImageInfoPendingThreads; 287 288 delete fBreakpointManager; 289 delete fWatchpointManager; 290 delete fMemoryBlockManager; 291 delete fWorker; 292 delete fTeam; 293 delete fFileManager; 294 295 fListener->TeamDebuggerQuit(this); 296} 297 298 299status_t 300TeamDebugger::Init(team_id teamID, thread_id threadID, bool stopInMain) 301{ 302 bool targetIsLocal = true; 303 // TODO: Support non-local targets! 304 305 // the first thing we want to do when running 306 PostMessage(MSG_LOAD_SETTINGS); 307 308 fTeamID = teamID; 309 310 // create debugger interface 311 fDebuggerInterface = new(std::nothrow) DebuggerInterface(fTeamID); 312 if (fDebuggerInterface == NULL) 313 return B_NO_MEMORY; 314 315 status_t error = fDebuggerInterface->Init(); 316 if (error != B_OK) 317 return error; 318 319 // create file manager 320 fFileManager = new(std::nothrow) FileManager; 321 if (fFileManager == NULL) 322 return B_NO_MEMORY; 323 324 error = fFileManager->Init(targetIsLocal); 325 if (error != B_OK) 326 return error; 327 328 // create team debug info 329 TeamDebugInfo* teamDebugInfo = new(std::nothrow) TeamDebugInfo( 330 fDebuggerInterface, fDebuggerInterface->GetArchitecture(), 331 fFileManager); 332 if (teamDebugInfo == NULL) 333 return B_NO_MEMORY; 334 BReference<TeamDebugInfo> teamDebugInfoReference(teamDebugInfo); 335 336 error = teamDebugInfo->Init(); 337 if (error != B_OK) 338 return error; 339 340 // check whether the team exists at all 341 // TODO: That should be done in the debugger interface! 342 team_info teamInfo; 343 error = get_team_info(fTeamID, &teamInfo); 344 if (error != B_OK) 345 return error; 346 347 // create a team object 348 fTeam = new(std::nothrow) ::Team(fTeamID, fDebuggerInterface, 349 fDebuggerInterface->GetArchitecture(), teamDebugInfo, 350 teamDebugInfo); 351 if (fTeam == NULL) 352 return B_NO_MEMORY; 353 354 error = fTeam->Init(); 355 if (error != B_OK) 356 return error; 357 fTeam->SetName(teamInfo.args); 358 // TODO: Set a better name! 359 360 fTeam->AddListener(this); 361 362 // init thread handler table 363 error = fThreadHandlers.Init(); 364 if (error != B_OK) 365 return error; 366 367 // create image handler table 368 fImageHandlers = new(std::nothrow) ImageHandlerTable; 369 if (fImageHandlers == NULL) 370 return B_NO_MEMORY; 371 372 error = fImageHandlers->Init(); 373 if (error != B_OK) 374 return error; 375 376 fImageInfoPendingThreads = new(std::nothrow) ImageInfoPendingThreadTable; 377 if (fImageInfoPendingThreads == NULL) 378 return B_NO_MEMORY; 379 380 // create our worker 381 fWorker = new(std::nothrow) Worker; 382 if (fWorker == NULL) 383 return B_NO_MEMORY; 384 385 error = fWorker->Init(); 386 if (error != B_OK) 387 return error; 388 389 // create the breakpoint manager 390 fBreakpointManager = new(std::nothrow) BreakpointManager(fTeam, 391 fDebuggerInterface); 392 if (fBreakpointManager == NULL) 393 return B_NO_MEMORY; 394 395 error = fBreakpointManager->Init(); 396 if (error != B_OK) 397 return error; 398 399 // create the watchpoint manager 400 fWatchpointManager = new(std::nothrow) WatchpointManager(fTeam, 401 fDebuggerInterface); 402 if (fWatchpointManager == NULL) 403 return B_NO_MEMORY; 404 405 error = fWatchpointManager->Init(); 406 if (error != B_OK) 407 return error; 408 409 // create the memory block manager 410 fMemoryBlockManager = new(std::nothrow) TeamMemoryBlockManager(); 411 if (fMemoryBlockManager == NULL) 412 return B_NO_MEMORY; 413 414 error = fMemoryBlockManager->Init(); 415 if (error != B_OK) 416 return error; 417 418 // create the debug report generator 419 fReportGenerator = new(std::nothrow) DebugReportGenerator(fTeam, this); 420 if (fReportGenerator == NULL) 421 return B_NO_MEMORY; 422 423 error = fReportGenerator->Init(); 424 if (error != B_OK) 425 return error; 426 427 // set team debugging flags 428 fDebuggerInterface->SetTeamDebuggingFlags( 429 B_TEAM_DEBUG_THREADS | B_TEAM_DEBUG_IMAGES); 430 431 // get the initial state of the team 432 AutoLocker< ::Team> teamLocker(fTeam); 433 434 ThreadHandler* mainThreadHandler = NULL; 435 { 436 BObjectList<ThreadInfo> threadInfos(20, true); 437 status_t error = fDebuggerInterface->GetThreadInfos(threadInfos); 438 for (int32 i = 0; ThreadInfo* info = threadInfos.ItemAt(i); i++) { 439 ::Thread* thread; 440 error = fTeam->AddThread(*info, &thread); 441 if (error != B_OK) 442 return error; 443 444 ThreadHandler* handler = new(std::nothrow) ThreadHandler(thread, 445 fWorker, fDebuggerInterface, 446 fBreakpointManager); 447 if (handler == NULL) 448 return B_NO_MEMORY; 449 450 fThreadHandlers.Insert(handler); 451 452 if (thread->IsMainThread()) 453 mainThreadHandler = handler; 454 455 handler->Init(); 456 } 457 } 458 459 Image* appImage = NULL; 460 { 461 BObjectList<ImageInfo> imageInfos(20, true); 462 status_t error = fDebuggerInterface->GetImageInfos(imageInfos); 463 for (int32 i = 0; ImageInfo* info = imageInfos.ItemAt(i); i++) { 464 Image* image; 465 error = _AddImage(*info, &image); 466 if (error != B_OK) 467 return error; 468 if (image->Type() == B_APP_IMAGE) 469 appImage = image; 470 471 ImageDebugInfoRequested(image); 472 } 473 } 474 475 // create the debug event listener 476 char buffer[128]; 477 snprintf(buffer, sizeof(buffer), "team %" B_PRId32 " debug listener", 478 fTeamID); 479 fDebugEventListener = spawn_thread(_DebugEventListenerEntry, buffer, 480 B_NORMAL_PRIORITY, this); 481 if (fDebugEventListener < 0) 482 return fDebugEventListener; 483 484 resume_thread(fDebugEventListener); 485 486 // run looper 487 thread_id looperThread = Run(); 488 if (looperThread < 0) 489 return looperThread; 490 491 // init the UI 492 error = fUserInterface->Init(fTeam, this); 493 if (error != B_OK) { 494 ERROR("Error: Failed to init the UI: %s\n", strerror(error)); 495 return error; 496 } 497 498 // if requested, stop the given thread 499 if (threadID >= 0) { 500 if (stopInMain) { 501 SymbolInfo symbolInfo; 502 if (appImage != NULL && mainThreadHandler != NULL 503 && fDebuggerInterface->GetSymbolInfo( 504 fTeam->ID(), appImage->ID(), "main", B_SYMBOL_TYPE_TEXT, 505 symbolInfo) == B_OK) { 506 mainThreadHandler->SetBreakpointAndRun(symbolInfo.Address()); 507 } 508 } else { 509 debug_thread(threadID); 510 // TODO: Superfluous, if the thread is already stopped. 511 } 512 } 513 514 fListener->TeamDebuggerStarted(this); 515 516 return B_OK; 517} 518 519 520void 521TeamDebugger::Activate() 522{ 523 fUserInterface->Show(); 524} 525 526 527void 528TeamDebugger::MessageReceived(BMessage* message) 529{ 530 switch (message->what) { 531 case MSG_THREAD_RUN: 532 case MSG_THREAD_STOP: 533 case MSG_THREAD_STEP_OVER: 534 case MSG_THREAD_STEP_INTO: 535 case MSG_THREAD_STEP_OUT: 536 { 537 int32 threadID; 538 if (message->FindInt32("thread", &threadID) != B_OK) 539 break; 540 541 if (ThreadHandler* handler = _GetThreadHandler(threadID)) { 542 handler->HandleThreadAction(message->what); 543 handler->ReleaseReference(); 544 } 545 break; 546 } 547 548 case MSG_SET_BREAKPOINT: 549 case MSG_CLEAR_BREAKPOINT: 550 { 551 UserBreakpoint* breakpoint = NULL; 552 BReference<UserBreakpoint> breakpointReference; 553 uint64 address = 0; 554 555 if (message->FindPointer("breakpoint", (void**)&breakpoint) == B_OK) 556 breakpointReference.SetTo(breakpoint, true); 557 else if (message->FindUInt64("address", &address) != B_OK) 558 break; 559 560 if (message->what == MSG_SET_BREAKPOINT) { 561 bool enabled; 562 if (message->FindBool("enabled", &enabled) != B_OK) 563 enabled = true; 564 565 if (breakpoint != NULL) 566 _HandleSetUserBreakpoint(breakpoint, enabled); 567 else 568 _HandleSetUserBreakpoint(address, enabled); 569 } else { 570 if (breakpoint != NULL) 571 _HandleClearUserBreakpoint(breakpoint); 572 else 573 _HandleClearUserBreakpoint(address); 574 } 575 576 break; 577 } 578 579 case MSG_SET_WATCHPOINT: 580 case MSG_CLEAR_WATCHPOINT: 581 { 582 Watchpoint* watchpoint = NULL; 583 BReference<Watchpoint> watchpointReference; 584 uint64 address = 0; 585 uint32 type = 0; 586 int32 length = 0; 587 588 if (message->FindPointer("watchpoint", (void**)&watchpoint) 589 == B_OK) { 590 watchpointReference.SetTo(watchpoint, true); 591 } else if (message->FindUInt64("address", &address) != B_OK) 592 break; 593 594 if (message->what == MSG_SET_WATCHPOINT) { 595 if (watchpoint == NULL && (message->FindUInt32("type", &type) 596 != B_OK 597 || message->FindInt32("length", &length) != B_OK)) { 598 break; 599 } 600 601 bool enabled; 602 if (message->FindBool("enabled", &enabled) != B_OK) 603 enabled = true; 604 605 if (watchpoint != NULL) 606 _HandleSetWatchpoint(watchpoint, enabled); 607 else 608 _HandleSetWatchpoint(address, type, length, enabled); 609 } else { 610 if (watchpoint != NULL) 611 _HandleClearWatchpoint(watchpoint); 612 else 613 _HandleClearWatchpoint(address); 614 } 615 616 break; 617 } 618 619 case MSG_INSPECT_ADDRESS: 620 { 621 TeamMemoryBlock::Listener* listener; 622 if (message->FindPointer("listener", 623 reinterpret_cast<void **>(&listener)) != B_OK) { 624 break; 625 } 626 627 target_addr_t address; 628 if (message->FindUInt64("address", 629 &address) == B_OK) { 630 _HandleInspectAddress(address, listener); 631 } 632 break; 633 } 634 635 case MSG_GENERATE_DEBUG_REPORT: 636 { 637 fReportGenerator->PostMessage(message); 638 break; 639 } 640 641 case MSG_THREAD_STATE_CHANGED: 642 { 643 int32 threadID; 644 if (message->FindInt32("thread", &threadID) != B_OK) 645 break; 646 647 if (ThreadHandler* handler = _GetThreadHandler(threadID)) { 648 handler->HandleThreadStateChanged(); 649 handler->ReleaseReference(); 650 } 651 break; 652 } 653 case MSG_THREAD_CPU_STATE_CHANGED: 654 { 655 int32 threadID; 656 if (message->FindInt32("thread", &threadID) != B_OK) 657 break; 658 659 if (ThreadHandler* handler = _GetThreadHandler(threadID)) { 660 handler->HandleCpuStateChanged(); 661 handler->ReleaseReference(); 662 } 663 break; 664 } 665 case MSG_THREAD_STACK_TRACE_CHANGED: 666 { 667 int32 threadID; 668 if (message->FindInt32("thread", &threadID) != B_OK) 669 break; 670 671 if (ThreadHandler* handler = _GetThreadHandler(threadID)) { 672 handler->HandleStackTraceChanged(); 673 handler->ReleaseReference(); 674 } 675 break; 676 } 677 678 case MSG_IMAGE_DEBUG_INFO_CHANGED: 679 { 680 int32 imageID; 681 if (message->FindInt32("image", &imageID) != B_OK) 682 break; 683 684 _HandleImageDebugInfoChanged(imageID); 685 break; 686 } 687 688 case MSG_IMAGE_FILE_CHANGED: 689 { 690 int32 imageID; 691 if (message->FindInt32("image", &imageID) != B_OK) 692 break; 693 694 _HandleImageFileChanged(imageID); 695 break; 696 } 697 698 case MSG_DEBUGGER_EVENT: 699 { 700 DebugEvent* event; 701 if (message->FindPointer("event", (void**)&event) != B_OK) 702 break; 703 704 _HandleDebuggerMessage(event); 705 delete event; 706 break; 707 } 708 709 case MSG_LOAD_SETTINGS: 710 _LoadSettings(); 711 Activate(); 712 break; 713 714 default: 715 BLooper::MessageReceived(message); 716 break; 717 } 718} 719 720 721void 722TeamDebugger::SourceEntryLocateRequested(const char* sourcePath, 723 const char* locatedPath) 724{ 725 AutoLocker<FileManager> locker(fFileManager); 726 fFileManager->SourceEntryLocated(sourcePath, locatedPath); 727} 728 729 730void 731TeamDebugger::FunctionSourceCodeRequested(FunctionInstance* functionInstance) 732{ 733 Function* function = functionInstance->GetFunction(); 734 735 // mark loading 736 AutoLocker< ::Team> locker(fTeam); 737 738 if (functionInstance->SourceCodeState() != FUNCTION_SOURCE_NOT_LOADED) 739 return; 740 if (function->SourceCodeState() == FUNCTION_SOURCE_LOADED) 741 return; 742 743 functionInstance->SetSourceCode(NULL, FUNCTION_SOURCE_LOADING); 744 745 bool loadForFunction = false; 746 if (function->SourceCodeState() == FUNCTION_SOURCE_NOT_LOADED) { 747 loadForFunction = true; 748 function->SetSourceCode(NULL, FUNCTION_SOURCE_LOADING); 749 } 750 751 locker.Unlock(); 752 753 // schedule the job 754 if (fWorker->ScheduleJob( 755 new(std::nothrow) LoadSourceCodeJob(fDebuggerInterface, 756 fDebuggerInterface->GetArchitecture(), fTeam, functionInstance, 757 loadForFunction), 758 this) != B_OK) { 759 // scheduling failed -- mark unavailable 760 locker.Lock(); 761 function->SetSourceCode(NULL, FUNCTION_SOURCE_UNAVAILABLE); 762 locker.Unlock(); 763 } 764} 765 766 767void 768TeamDebugger::ImageDebugInfoRequested(Image* image) 769{ 770 LoadImageDebugInfoJob::ScheduleIfNecessary(fWorker, image); 771} 772 773 774void 775TeamDebugger::ValueNodeValueRequested(CpuState* cpuState, 776 ValueNodeContainer* container, ValueNode* valueNode) 777{ 778 AutoLocker<ValueNodeContainer> containerLocker(container); 779 if (valueNode->Container() != container) 780 return; 781 782 // check whether a job is already in progress 783 AutoLocker<Worker> workerLocker(fWorker); 784 SimpleJobKey jobKey(valueNode, JOB_TYPE_RESOLVE_VALUE_NODE_VALUE); 785 if (fWorker->GetJob(jobKey) != NULL) 786 return; 787 workerLocker.Unlock(); 788 789 // schedule the job 790 status_t error = fWorker->ScheduleJob( 791 new(std::nothrow) ResolveValueNodeValueJob(fDebuggerInterface, 792 fDebuggerInterface->GetArchitecture(), cpuState, 793 fTeam->GetTeamTypeInformation(), container, valueNode), this); 794 if (error != B_OK) { 795 // scheduling failed -- set the value to invalid 796 valueNode->SetLocationAndValue(NULL, NULL, error); 797 } 798} 799 800 801void 802TeamDebugger::ThreadActionRequested(thread_id threadID, 803 uint32 action) 804{ 805 BMessage message(action); 806 message.AddInt32("thread", threadID); 807 PostMessage(&message); 808} 809 810 811void 812TeamDebugger::SetBreakpointRequested(target_addr_t address, bool enabled) 813{ 814 BMessage message(MSG_SET_BREAKPOINT); 815 message.AddUInt64("address", (uint64)address); 816 message.AddBool("enabled", enabled); 817 PostMessage(&message); 818} 819 820 821void 822TeamDebugger::SetBreakpointEnabledRequested(UserBreakpoint* breakpoint, 823 bool enabled) 824{ 825 BMessage message(MSG_SET_BREAKPOINT); 826 BReference<UserBreakpoint> breakpointReference(breakpoint); 827 if (message.AddPointer("breakpoint", breakpoint) == B_OK 828 && message.AddBool("enabled", enabled) == B_OK 829 && PostMessage(&message) == B_OK) { 830 breakpointReference.Detach(); 831 } 832} 833 834 835void 836TeamDebugger::ClearBreakpointRequested(target_addr_t address) 837{ 838 BMessage message(MSG_CLEAR_BREAKPOINT); 839 message.AddUInt64("address", (uint64)address); 840 PostMessage(&message); 841} 842 843 844void 845TeamDebugger::ClearBreakpointRequested(UserBreakpoint* breakpoint) 846{ 847 BMessage message(MSG_CLEAR_BREAKPOINT); 848 BReference<UserBreakpoint> breakpointReference(breakpoint); 849 if (message.AddPointer("breakpoint", breakpoint) == B_OK 850 && PostMessage(&message) == B_OK) { 851 breakpointReference.Detach(); 852 } 853} 854 855 856void 857TeamDebugger::SetWatchpointRequested(target_addr_t address, uint32 type, 858 int32 length, bool enabled) 859{ 860 BMessage message(MSG_SET_WATCHPOINT); 861 message.AddUInt64("address", (uint64)address); 862 message.AddUInt32("type", type); 863 message.AddInt32("length", length); 864 message.AddBool("enabled", enabled); 865 PostMessage(&message); 866} 867 868 869void 870TeamDebugger::SetWatchpointEnabledRequested(Watchpoint* watchpoint, 871 bool enabled) 872{ 873 BMessage message(MSG_SET_WATCHPOINT); 874 BReference<Watchpoint> watchpointReference(watchpoint); 875 if (message.AddPointer("watchpoint", watchpoint) == B_OK 876 && message.AddBool("enabled", enabled) == B_OK 877 && PostMessage(&message) == B_OK) { 878 watchpointReference.Detach(); 879 } 880} 881 882 883void 884TeamDebugger::ClearWatchpointRequested(target_addr_t address) 885{ 886 BMessage message(MSG_CLEAR_WATCHPOINT); 887 message.AddUInt64("address", (uint64)address); 888 PostMessage(&message); 889} 890 891 892void 893TeamDebugger::ClearWatchpointRequested(Watchpoint* watchpoint) 894{ 895 BMessage message(MSG_CLEAR_WATCHPOINT); 896 BReference<Watchpoint> watchpointReference(watchpoint); 897 if (message.AddPointer("watchpoint", watchpoint) == B_OK 898 && PostMessage(&message) == B_OK) { 899 watchpointReference.Detach(); 900 } 901} 902 903 904void 905TeamDebugger::InspectRequested(target_addr_t address, 906 TeamMemoryBlock::Listener *listener) 907{ 908 BMessage message(MSG_INSPECT_ADDRESS); 909 message.AddUInt64("address", address); 910 message.AddPointer("listener", listener); 911 PostMessage(&message); 912} 913 914 915void 916TeamDebugger::DebugReportRequested(entry_ref* targetPath) 917{ 918 BMessage message(MSG_GENERATE_DEBUG_REPORT); 919 message.AddRef("target", targetPath); 920 PostMessage(&message); 921} 922 923 924bool 925TeamDebugger::UserInterfaceQuitRequested(QuitOption quitOption) 926{ 927 bool askUser = false; 928 switch (quitOption) { 929 case QUIT_OPTION_ASK_USER: 930 askUser = true; 931 break; 932 933 case QUIT_OPTION_ASK_KILL_TEAM: 934 fKillTeamOnQuit = true; 935 break; 936 937 case QUIT_OPTION_ASK_RESUME_TEAM: 938 break; 939 } 940 941 if (askUser) { 942 AutoLocker< ::Team> locker(fTeam); 943 BString name(fTeam->Name()); 944 locker.Unlock(); 945 946 BString message; 947 message << "What shall be done about the debugged team '"; 948 message << name; 949 message << "'?"; 950 951 name.Remove(0, name.FindLast('/') + 1); 952 953 BString killLabel("Kill "); 954 killLabel << name; 955 956 BString resumeLabel("Resume "); 957 resumeLabel << name; 958 959 int32 choice = fUserInterface->SynchronouslyAskUser("Quit Debugger", 960 message, killLabel, "Cancel", resumeLabel); 961 962 switch (choice) { 963 case 0: 964 fKillTeamOnQuit = true; 965 break; 966 case 1: 967 case -1: 968 return false; 969 case 2: 970 // Detach from the team and resume and stopped threads. 971 break; 972 } 973 } 974 975 PostMessage(B_QUIT_REQUESTED); 976 977 return true; 978} 979 980 981void 982TeamDebugger::JobDone(Job* job) 983{ 984 TRACE_JOBS("TeamDebugger::JobDone(%p)\n", job); 985} 986 987 988void 989TeamDebugger::JobFailed(Job* job) 990{ 991 TRACE_JOBS("TeamDebugger::JobFailed(%p)\n", job); 992 // TODO: notify user 993} 994 995 996void 997TeamDebugger::JobAborted(Job* job) 998{ 999 TRACE_JOBS("TeamDebugger::JobAborted(%p)\n", job); 1000 // TODO: For a stack frame source loader thread we should reset the 1001 // loading state! Asynchronously due to locking order. 1002} 1003 1004 1005void 1006TeamDebugger::ThreadStateChanged(const ::Team::ThreadEvent& event) 1007{ 1008 BMessage message(MSG_THREAD_STATE_CHANGED); 1009 message.AddInt32("thread", event.GetThread()->ID()); 1010 PostMessage(&message); 1011} 1012 1013 1014void 1015TeamDebugger::ThreadCpuStateChanged(const ::Team::ThreadEvent& event) 1016{ 1017 BMessage message(MSG_THREAD_CPU_STATE_CHANGED); 1018 message.AddInt32("thread", event.GetThread()->ID()); 1019 PostMessage(&message); 1020} 1021 1022 1023void 1024TeamDebugger::ThreadStackTraceChanged(const ::Team::ThreadEvent& event) 1025{ 1026 BMessage message(MSG_THREAD_STACK_TRACE_CHANGED); 1027 message.AddInt32("thread", event.GetThread()->ID()); 1028 PostMessage(&message); 1029} 1030 1031 1032void 1033TeamDebugger::ImageDebugInfoChanged(const ::Team::ImageEvent& event) 1034{ 1035 BMessage message(MSG_IMAGE_DEBUG_INFO_CHANGED); 1036 message.AddInt32("image", event.GetImage()->ID()); 1037 PostMessage(&message); 1038} 1039 1040 1041/*static*/ status_t 1042TeamDebugger::_DebugEventListenerEntry(void* data) 1043{ 1044 return ((TeamDebugger*)data)->_DebugEventListener(); 1045} 1046 1047 1048status_t 1049TeamDebugger::_DebugEventListener() 1050{ 1051 while (!fTerminating) { 1052 // get the next event 1053 DebugEvent* event; 1054 status_t error = fDebuggerInterface->GetNextDebugEvent(event); 1055 if (error != B_OK) 1056 break; 1057 // TODO: Error handling! 1058 1059 if (event->Team() != fTeamID) { 1060 TRACE_EVENTS("TeamDebugger for team %" B_PRId32 ": received event " 1061 "from team %" B_PRId32 "!\n", fTeamID, event->Team()); 1062 continue; 1063 } 1064 1065 BMessage message(MSG_DEBUGGER_EVENT); 1066 if (message.AddPointer("event", event) != B_OK 1067 || PostMessage(&message) != B_OK) { 1068 // TODO: Continue thread if necessary! 1069 delete event; 1070 } 1071 } 1072 1073 return B_OK; 1074} 1075 1076 1077void 1078TeamDebugger::_HandleDebuggerMessage(DebugEvent* event) 1079{ 1080 TRACE_EVENTS("TeamDebugger::_HandleDebuggerMessage(): %" B_PRId32 "\n", 1081 event->EventType()); 1082 1083 bool handled = false; 1084 1085 ThreadHandler* handler = _GetThreadHandler(event->Thread()); 1086 BReference<ThreadHandler> handlerReference(handler); 1087 1088 switch (event->EventType()) { 1089 case B_DEBUGGER_MESSAGE_THREAD_DEBUGGED: 1090 TRACE_EVENTS("B_DEBUGGER_MESSAGE_THREAD_DEBUGGED: thread: %" 1091 B_PRId32 "\n", event->Thread()); 1092 1093 if (handler != NULL) { 1094 handled = handler->HandleThreadDebugged( 1095 dynamic_cast<ThreadDebuggedEvent*>(event)); 1096 } 1097 break; 1098 case B_DEBUGGER_MESSAGE_DEBUGGER_CALL: 1099 TRACE_EVENTS("B_DEBUGGER_MESSAGE_DEBUGGER_CALL: thread: %" B_PRId32 1100 "\n", event->Thread()); 1101 1102 if (handler != NULL) { 1103 handled = handler->HandleDebuggerCall( 1104 dynamic_cast<DebuggerCallEvent*>(event)); 1105 } 1106 break; 1107 case B_DEBUGGER_MESSAGE_BREAKPOINT_HIT: 1108 TRACE_EVENTS("B_DEBUGGER_MESSAGE_BREAKPOINT_HIT: thread: %" B_PRId32 1109 "\n", event->Thread()); 1110 1111 if (handler != NULL) { 1112 handled = handler->HandleBreakpointHit( 1113 dynamic_cast<BreakpointHitEvent*>(event)); 1114 } 1115 break; 1116 case B_DEBUGGER_MESSAGE_WATCHPOINT_HIT: 1117 TRACE_EVENTS("B_DEBUGGER_MESSAGE_WATCHPOINT_HIT: thread: %" B_PRId32 1118 "\n", event->Thread()); 1119 1120 if (handler != NULL) { 1121 handled = handler->HandleWatchpointHit( 1122 dynamic_cast<WatchpointHitEvent*>(event)); 1123 } 1124 break; 1125 case B_DEBUGGER_MESSAGE_SINGLE_STEP: 1126 TRACE_EVENTS("B_DEBUGGER_MESSAGE_SINGLE_STEP: thread: %" B_PRId32 1127 "\n", event->Thread()); 1128 1129 if (handler != NULL) { 1130 handled = handler->HandleSingleStep( 1131 dynamic_cast<SingleStepEvent*>(event)); 1132 } 1133 break; 1134 case B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED: 1135 TRACE_EVENTS("B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED: thread: %" 1136 B_PRId32 "\n", event->Thread()); 1137 1138 if (handler != NULL) { 1139 handled = handler->HandleExceptionOccurred( 1140 dynamic_cast<ExceptionOccurredEvent*>(event)); 1141 } 1142 break; 1143// case B_DEBUGGER_MESSAGE_TEAM_CREATED: 1144//printf("B_DEBUGGER_MESSAGE_TEAM_CREATED: team: %ld\n", message.team_created.new_team); 1145// break; 1146 case B_DEBUGGER_MESSAGE_TEAM_DELETED: 1147 // TODO: Handle! 1148 TRACE_EVENTS("B_DEBUGGER_MESSAGE_TEAM_DELETED: team: %" B_PRId32 1149 "\n", event->Team()); 1150 break; 1151 case B_DEBUGGER_MESSAGE_TEAM_EXEC: 1152 TRACE_EVENTS("B_DEBUGGER_MESSAGE_TEAM_EXEC: team: %" B_PRId32 "\n", 1153 event->Team()); 1154 // TODO: Handle! 1155 break; 1156 case B_DEBUGGER_MESSAGE_THREAD_CREATED: 1157 { 1158 ThreadCreatedEvent* threadEvent 1159 = dynamic_cast<ThreadCreatedEvent*>(event); 1160 TRACE_EVENTS("B_DEBUGGER_MESSAGE_THREAD_CREATED: thread: %" B_PRId32 1161 "\n", threadEvent->NewThread()); 1162 handled = _HandleThreadCreated(threadEvent); 1163 break; 1164 } 1165 case DEBUGGER_MESSAGE_THREAD_RENAMED: 1166 { 1167 ThreadRenamedEvent* threadEvent 1168 = dynamic_cast<ThreadRenamedEvent*>(event); 1169 TRACE_EVENTS("DEBUGGER_MESSAGE_THREAD_RENAMED: thread: %" B_PRId32 1170 " (\"%s\")\n", 1171 threadEvent->RenamedThread(), threadEvent->NewName()); 1172 handled = _HandleThreadRenamed(threadEvent); 1173 break; 1174 } 1175 case DEBUGGER_MESSAGE_THREAD_PRIORITY_CHANGED: 1176 { 1177 ThreadPriorityChangedEvent* threadEvent 1178 = dynamic_cast<ThreadPriorityChangedEvent*>(event); 1179 TRACE_EVENTS("B_DEBUGGER_MESSAGE_THREAD_PRIORITY_CHANGED: thread:" 1180 " %" B_PRId32 "\n", threadEvent->ChangedThread()); 1181 handled = _HandleThreadPriorityChanged(threadEvent); 1182 break; 1183 } 1184 case B_DEBUGGER_MESSAGE_THREAD_DELETED: 1185 TRACE_EVENTS("B_DEBUGGER_MESSAGE_THREAD_DELETED: thread: %" B_PRId32 1186 "\n", event->Thread()); 1187 handled = _HandleThreadDeleted( 1188 dynamic_cast<ThreadDeletedEvent*>(event)); 1189 break; 1190 case B_DEBUGGER_MESSAGE_IMAGE_CREATED: 1191 { 1192 ImageCreatedEvent* imageEvent 1193 = dynamic_cast<ImageCreatedEvent*>(event); 1194 TRACE_EVENTS("B_DEBUGGER_MESSAGE_IMAGE_CREATED: image: \"%s\" " 1195 "(%" B_PRId32 ")\n", imageEvent->GetImageInfo().Name().String(), 1196 imageEvent->GetImageInfo().ImageID()); 1197 handled = _HandleImageCreated(imageEvent); 1198 break; 1199 } 1200 case B_DEBUGGER_MESSAGE_IMAGE_DELETED: 1201 { 1202 ImageDeletedEvent* imageEvent 1203 = dynamic_cast<ImageDeletedEvent*>(event); 1204 TRACE_EVENTS("B_DEBUGGER_MESSAGE_IMAGE_DELETED: image: \"%s\" " 1205 "(%" B_PRId32 ")\n", imageEvent->GetImageInfo().Name().String(), 1206 imageEvent->GetImageInfo().ImageID()); 1207 handled = _HandleImageDeleted(imageEvent); 1208 break; 1209 } 1210 case B_DEBUGGER_MESSAGE_PRE_SYSCALL: 1211 case B_DEBUGGER_MESSAGE_POST_SYSCALL: 1212 case B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED: 1213 case B_DEBUGGER_MESSAGE_PROFILER_UPDATE: 1214 case B_DEBUGGER_MESSAGE_HANDED_OVER: 1215 // not interested 1216 break; 1217 default: 1218 WARNING("TeamDebugger for team %" B_PRId32 ": unknown event type: " 1219 "%" B_PRId32 "\n", fTeamID, event->EventType()); 1220 break; 1221 } 1222 1223 if (!handled && event->ThreadStopped()) 1224 fDebuggerInterface->ContinueThread(event->Thread()); 1225} 1226 1227 1228bool 1229TeamDebugger::_HandleThreadCreated(ThreadCreatedEvent* event) 1230{ 1231 AutoLocker< ::Team> locker(fTeam); 1232 1233 ThreadInfo info; 1234 status_t error = fDebuggerInterface->GetThreadInfo(event->NewThread(), 1235 info); 1236 if (error == B_OK) { 1237 ::Thread* thread; 1238 fTeam->AddThread(info, &thread); 1239 1240 ThreadHandler* handler = new(std::nothrow) ThreadHandler(thread, 1241 fWorker, fDebuggerInterface, 1242 fBreakpointManager); 1243 if (handler != NULL) { 1244 fThreadHandlers.Insert(handler); 1245 handler->Init(); 1246 } 1247 } 1248 1249 return false; 1250} 1251 1252 1253bool 1254TeamDebugger::_HandleThreadRenamed(ThreadRenamedEvent* event) 1255{ 1256 AutoLocker< ::Team> locker(fTeam); 1257 1258 ::Thread* thread = fTeam->ThreadByID(event->RenamedThread()); 1259 1260 if (thread != NULL) 1261 thread->SetName(event->NewName()); 1262 1263 return false; 1264} 1265 1266 1267bool 1268TeamDebugger::_HandleThreadPriorityChanged(ThreadPriorityChangedEvent*) 1269{ 1270 // TODO: implement once we actually track thread priorities 1271 1272 return false; 1273} 1274 1275 1276bool 1277TeamDebugger::_HandleThreadDeleted(ThreadDeletedEvent* event) 1278{ 1279 AutoLocker< ::Team> locker(fTeam); 1280 if (ThreadHandler* handler = fThreadHandlers.Lookup(event->Thread())) { 1281 fThreadHandlers.Remove(handler); 1282 handler->ReleaseReference(); 1283 } 1284 fTeam->RemoveThread(event->Thread()); 1285 return false; 1286} 1287 1288 1289bool 1290TeamDebugger::_HandleImageCreated(ImageCreatedEvent* event) 1291{ 1292 AutoLocker< ::Team> locker(fTeam); 1293 _AddImage(event->GetImageInfo()); 1294 1295 ImageInfoPendingThread* info = new(std::nothrow) ImageInfoPendingThread( 1296 event->GetImageInfo().ImageID(), event->Thread()); 1297 if (info == NULL) 1298 return false; 1299 1300 fImageInfoPendingThreads->Insert(info); 1301 return true; 1302} 1303 1304 1305bool 1306TeamDebugger::_HandleImageDeleted(ImageDeletedEvent* event) 1307{ 1308 AutoLocker< ::Team> locker(fTeam); 1309 fTeam->RemoveImage(event->GetImageInfo().ImageID()); 1310 1311 ImageHandler* imageHandler = fImageHandlers->Lookup( 1312 event->GetImageInfo().ImageID()); 1313 if (imageHandler == NULL) 1314 return false; 1315 1316 fImageHandlers->Remove(imageHandler); 1317 BReference<ImageHandler> imageHandlerReference(imageHandler, true); 1318 locker.Unlock(); 1319 1320 // remove breakpoints in the image 1321 fBreakpointManager->RemoveImageBreakpoints(imageHandler->GetImage()); 1322 1323 return false; 1324} 1325 1326 1327void 1328TeamDebugger::_HandleImageDebugInfoChanged(image_id imageID) 1329{ 1330 // get the image (via the image handler) 1331 AutoLocker< ::Team> locker(fTeam); 1332 ImageHandler* imageHandler = fImageHandlers->Lookup(imageID); 1333 if (imageHandler == NULL) 1334 return; 1335 1336 Image* image = imageHandler->GetImage(); 1337 BReference<Image> imageReference(image); 1338 1339 locker.Unlock(); 1340 1341 image_debug_info_state state = image->ImageDebugInfoState(); 1342 if (state == IMAGE_DEBUG_INFO_LOADED 1343 || state == IMAGE_DEBUG_INFO_UNAVAILABLE) { 1344 // update breakpoints in the image 1345 fBreakpointManager->UpdateImageBreakpoints(image); 1346 1347 ImageInfoPendingThread* thread = fImageInfoPendingThreads 1348 ->Lookup(imageID); 1349 if (thread != NULL) { 1350 fDebuggerInterface->ContinueThread(thread->ThreadID()); 1351 fImageInfoPendingThreads->Remove(thread); 1352 delete thread; 1353 } 1354 } 1355} 1356 1357 1358void 1359TeamDebugger::_HandleImageFileChanged(image_id imageID) 1360{ 1361 TRACE_IMAGES("TeamDebugger::_HandleImageFileChanged(%" B_PRId32 ")\n", 1362 imageID); 1363// TODO: Reload the debug info! 1364} 1365 1366 1367void 1368TeamDebugger::_HandleSetUserBreakpoint(target_addr_t address, bool enabled) 1369{ 1370 TRACE_CONTROL("TeamDebugger::_HandleSetUserBreakpoint(%#" B_PRIx64 1371 ", %d)\n", address, enabled); 1372 1373 // check whether there already is a breakpoint 1374 AutoLocker< ::Team> locker(fTeam); 1375 1376 Breakpoint* breakpoint = fTeam->BreakpointAtAddress(address); 1377 UserBreakpoint* userBreakpoint = NULL; 1378 if (breakpoint != NULL && breakpoint->FirstUserBreakpoint() != NULL) 1379 userBreakpoint = breakpoint->FirstUserBreakpoint()->GetUserBreakpoint(); 1380 BReference<UserBreakpoint> userBreakpointReference(userBreakpoint); 1381 1382 if (userBreakpoint == NULL) { 1383 TRACE_CONTROL(" no breakpoint yet\n"); 1384 1385 // get the function at the address 1386 Image* image = fTeam->ImageByAddress(address); 1387 1388 TRACE_CONTROL(" image: %p\n", image); 1389 1390 if (image == NULL) 1391 return; 1392 ImageDebugInfo* imageDebugInfo = image->GetImageDebugInfo(); 1393 1394 TRACE_CONTROL(" image debug info: %p\n", imageDebugInfo); 1395 1396 if (imageDebugInfo == NULL) 1397 return; 1398 // TODO: Handle this case by loading the debug info, if possible! 1399 FunctionInstance* functionInstance 1400 = imageDebugInfo->FunctionAtAddress(address); 1401 1402 TRACE_CONTROL(" function instance: %p\n", functionInstance); 1403 1404 if (functionInstance == NULL) 1405 return; 1406 Function* function = functionInstance->GetFunction(); 1407 1408 TRACE_CONTROL(" function: %p\n", function); 1409 1410 // get the source location for the address 1411 FunctionDebugInfo* functionDebugInfo 1412 = functionInstance->GetFunctionDebugInfo(); 1413 SourceLocation sourceLocation; 1414 Statement* breakpointStatement = NULL; 1415 if (functionDebugInfo->GetSpecificImageDebugInfo()->GetStatement( 1416 functionDebugInfo, address, breakpointStatement) != B_OK) { 1417 return; 1418 } 1419 1420 sourceLocation = breakpointStatement->StartSourceLocation(); 1421 breakpointStatement->ReleaseReference(); 1422 1423 target_addr_t relativeAddress = address - functionInstance->Address(); 1424 1425 TRACE_CONTROL(" relative address: %#" B_PRIx64 ", source location: " 1426 "(%" B_PRId32 ", %" B_PRId32 ")\n", relativeAddress, 1427 sourceLocation.Line(), sourceLocation.Column()); 1428 1429 // get function id 1430 FunctionID* functionID = functionInstance->GetFunctionID(); 1431 if (functionID == NULL) 1432 return; 1433 BReference<FunctionID> functionIDReference(functionID, true); 1434 1435 // create the user breakpoint 1436 userBreakpoint = new(std::nothrow) UserBreakpoint( 1437 UserBreakpointLocation(functionID, function->SourceFile(), 1438 sourceLocation, relativeAddress)); 1439 if (userBreakpoint == NULL) 1440 return; 1441 userBreakpointReference.SetTo(userBreakpoint, true); 1442 1443 TRACE_CONTROL(" created user breakpoint: %p\n", userBreakpoint); 1444 1445 // iterate through all function instances and create 1446 // UserBreakpointInstances 1447 for (FunctionInstanceList::ConstIterator it 1448 = function->Instances().GetIterator(); 1449 FunctionInstance* instance = it.Next();) { 1450 TRACE_CONTROL(" function instance %p: range: %#" B_PRIx64 " - %#" 1451 B_PRIx64 "\n", instance, instance->Address(), 1452 instance->Address() + instance->Size()); 1453 1454 // get the breakpoint address for the instance 1455 target_addr_t instanceAddress = 0; 1456 if (instance == functionInstance) { 1457 instanceAddress = address; 1458 } else if (functionInstance->SourceFile() != NULL) { 1459 // We have a source file, so get the address for the source 1460 // location. 1461 Statement* statement = NULL; 1462 functionDebugInfo = instance->GetFunctionDebugInfo(); 1463 functionDebugInfo->GetSpecificImageDebugInfo() 1464 ->GetStatementAtSourceLocation(functionDebugInfo, 1465 sourceLocation, statement); 1466 if (statement != NULL) { 1467 instanceAddress = statement->CoveringAddressRange().Start(); 1468 // TODO: What about BreakpointAllowed()? 1469 statement->ReleaseReference(); 1470 } 1471 } 1472 1473 TRACE_CONTROL(" breakpoint address using source info: %" B_PRIx64 1474 "\n", instanceAddress); 1475 1476 if (instanceAddress == 0) { 1477 // No source file (or we failed getting the statement), so try 1478 // to use the same relative address. 1479 if (relativeAddress > instance->Size()) 1480 continue; 1481 instanceAddress = instance->Address() + relativeAddress; 1482 } 1483 1484 TRACE_CONTROL(" final breakpoint address: %" B_PRIx64 "\n", 1485 instanceAddress); 1486 1487 UserBreakpointInstance* breakpointInstance = new(std::nothrow) 1488 UserBreakpointInstance(userBreakpoint, instanceAddress); 1489 if (breakpointInstance == NULL 1490 || !userBreakpoint->AddInstance(breakpointInstance)) { 1491 delete breakpointInstance; 1492 return; 1493 } 1494 1495 TRACE_CONTROL(" breakpoint instance: %p\n", breakpointInstance); 1496 } 1497 } 1498 1499 locker.Unlock(); 1500 1501 _HandleSetUserBreakpoint(userBreakpoint, enabled); 1502} 1503 1504 1505void 1506TeamDebugger::_HandleSetUserBreakpoint(UserBreakpoint* breakpoint, bool enabled) 1507{ 1508 status_t error = fBreakpointManager->InstallUserBreakpoint(breakpoint, 1509 enabled); 1510 if (error != B_OK) { 1511 _NotifyUser("Install Breakpoint", "Failed to install breakpoint: %s", 1512 strerror(error)); 1513 } 1514} 1515 1516 1517void 1518TeamDebugger::_HandleClearUserBreakpoint(target_addr_t address) 1519{ 1520 TRACE_CONTROL("TeamDebugger::_HandleClearUserBreakpoint(%#" B_PRIx64 ")\n", 1521 address); 1522 1523 AutoLocker< ::Team> locker(fTeam); 1524 1525 Breakpoint* breakpoint = fTeam->BreakpointAtAddress(address); 1526 if (breakpoint == NULL || breakpoint->FirstUserBreakpoint() == NULL) 1527 return; 1528 UserBreakpoint* userBreakpoint 1529 = breakpoint->FirstUserBreakpoint()->GetUserBreakpoint(); 1530 BReference<UserBreakpoint> userBreakpointReference(userBreakpoint); 1531 1532 locker.Unlock(); 1533 1534 _HandleClearUserBreakpoint(userBreakpoint); 1535} 1536 1537 1538void 1539TeamDebugger::_HandleClearUserBreakpoint(UserBreakpoint* breakpoint) 1540{ 1541 fBreakpointManager->UninstallUserBreakpoint(breakpoint); 1542} 1543 1544 1545void 1546TeamDebugger::_HandleSetWatchpoint(target_addr_t address, uint32 type, 1547 int32 length, bool enabled) 1548{ 1549 Watchpoint* watchpoint = new(std::nothrow) Watchpoint(address, type, 1550 length); 1551 1552 if (watchpoint == NULL) 1553 return; 1554 BReference<Watchpoint> watchpointRef(watchpoint, true); 1555 1556 _HandleSetWatchpoint(watchpoint, enabled); 1557} 1558 1559 1560void 1561TeamDebugger::_HandleSetWatchpoint(Watchpoint* watchpoint, bool enabled) 1562{ 1563 status_t error = fWatchpointManager->InstallWatchpoint(watchpoint, 1564 enabled); 1565 if (error != B_OK) { 1566 _NotifyUser("Install Watchpoint", "Failed to install watchpoint: %s", 1567 strerror(error)); 1568 } 1569} 1570 1571 1572void 1573TeamDebugger::_HandleClearWatchpoint(target_addr_t address) 1574{ 1575 TRACE_CONTROL("TeamDebugger::_HandleClearWatchpoint(%#" B_PRIx64 ")\n", 1576 address); 1577 1578 AutoLocker< ::Team> locker(fTeam); 1579 1580 Watchpoint* watchpoint = fTeam->WatchpointAtAddress(address); 1581 if (watchpoint == NULL) 1582 return; 1583 BReference<Watchpoint> watchpointReference(watchpoint); 1584 1585 locker.Unlock(); 1586 1587 _HandleClearWatchpoint(watchpoint); 1588} 1589 1590 1591void 1592TeamDebugger::_HandleClearWatchpoint(Watchpoint* watchpoint) 1593{ 1594 fWatchpointManager->UninstallWatchpoint(watchpoint); 1595} 1596 1597 1598void 1599TeamDebugger::_HandleInspectAddress(target_addr_t address, 1600 TeamMemoryBlock::Listener* listener) 1601{ 1602 TRACE_CONTROL("TeamDebugger::_HandleInspectAddress(%" B_PRIx64 ", %p)\n", 1603 address, listener); 1604 1605 TeamMemoryBlock* memoryBlock = fMemoryBlockManager 1606 ->GetMemoryBlock(address); 1607 1608 if (memoryBlock == NULL) { 1609 _NotifyUser("Inspect Address", "Failed to allocate memory block"); 1610 return; 1611 } 1612 1613 if (!memoryBlock->HasListener(listener)) 1614 memoryBlock->AddListener(listener); 1615 1616 if (!memoryBlock->IsValid()) { 1617 AutoLocker< ::Team> teamLocker(fTeam); 1618 1619 TeamMemory* memory = fTeam->GetTeamMemory(); 1620 // schedule the job 1621 status_t result; 1622 if ((result = fWorker->ScheduleJob( 1623 new(std::nothrow) RetrieveMemoryBlockJob(fTeam, memory, 1624 memoryBlock), 1625 this)) != B_OK) { 1626 memoryBlock->ReleaseReference(); 1627 _NotifyUser("Inspect Address", "Failed to retrieve memory data: %s", 1628 strerror(result)); 1629 } 1630 } else 1631 memoryBlock->NotifyDataRetrieved(); 1632 1633} 1634 1635 1636ThreadHandler* 1637TeamDebugger::_GetThreadHandler(thread_id threadID) 1638{ 1639 AutoLocker< ::Team> locker(fTeam); 1640 1641 ThreadHandler* handler = fThreadHandlers.Lookup(threadID); 1642 if (handler != NULL) 1643 handler->AcquireReference(); 1644 return handler; 1645} 1646 1647 1648status_t 1649TeamDebugger::_AddImage(const ImageInfo& imageInfo, Image** _image) 1650{ 1651 LocatableFile* file = NULL; 1652 if (strchr(imageInfo.Name(), '/') != NULL) 1653 file = fFileManager->GetTargetFile(imageInfo.Name()); 1654 BReference<LocatableFile> imageFileReference(file, true); 1655 1656 Image* image; 1657 status_t error = fTeam->AddImage(imageInfo, file, &image); 1658 if (error != B_OK) 1659 return error; 1660 1661 ImageDebugInfoRequested(image); 1662 1663 ImageHandler* imageHandler = new(std::nothrow) ImageHandler(this, image); 1664 if (imageHandler != NULL) 1665 fImageHandlers->Insert(imageHandler); 1666 1667 if (_image != NULL) 1668 *_image = image; 1669 1670 return B_OK; 1671} 1672 1673 1674void 1675TeamDebugger::_LoadSettings() 1676{ 1677 // get the team name 1678 AutoLocker< ::Team> locker(fTeam); 1679 BString teamName = fTeam->Name(); 1680 locker.Unlock(); 1681 1682 // load the settings 1683 if (fSettingsManager->LoadTeamSettings(teamName, fTeamSettings) != B_OK) 1684 return; 1685 1686 // create the saved breakpoints 1687 for (int32 i = 0; const BreakpointSetting* breakpointSetting 1688 = fTeamSettings.BreakpointAt(i); i++) { 1689 if (breakpointSetting->GetFunctionID() == NULL) 1690 continue; 1691 1692 // get the source file, if any 1693 LocatableFile* sourceFile = NULL; 1694 if (breakpointSetting->SourceFile().Length() > 0) { 1695 sourceFile = fFileManager->GetSourceFile( 1696 breakpointSetting->SourceFile()); 1697 if (sourceFile == NULL) 1698 continue; 1699 } 1700 BReference<LocatableFile> sourceFileReference(sourceFile, true); 1701 1702 // create the breakpoint 1703 UserBreakpointLocation location(breakpointSetting->GetFunctionID(), 1704 sourceFile, breakpointSetting->GetSourceLocation(), 1705 breakpointSetting->RelativeAddress()); 1706 1707 UserBreakpoint* breakpoint = new(std::nothrow) UserBreakpoint(location); 1708 if (breakpoint == NULL) 1709 return; 1710 BReference<UserBreakpoint> breakpointReference(breakpoint, true); 1711 1712 // install it 1713 fBreakpointManager->InstallUserBreakpoint(breakpoint, 1714 breakpointSetting->IsEnabled()); 1715 } 1716 1717 const TeamUiSettings* uiSettings = fTeamSettings.UiSettingFor( 1718 fUserInterface->ID()); 1719 if (uiSettings != NULL) 1720 fUserInterface->LoadSettings(uiSettings); 1721} 1722 1723 1724void 1725TeamDebugger::_SaveSettings() 1726{ 1727 // get the settings 1728 AutoLocker< ::Team> locker(fTeam); 1729 TeamSettings settings; 1730 if (settings.SetTo(fTeam) != B_OK) 1731 return; 1732 1733 TeamUiSettings* uiSettings = NULL; 1734 if (fUserInterface->SaveSettings(uiSettings) != B_OK) 1735 return; 1736 if (uiSettings != NULL) 1737 settings.AddUiSettings(uiSettings); 1738 1739 // preserve the UI settings from our cached copy. 1740 for (int32 i = 0; i < fTeamSettings.CountUiSettings(); i++) { 1741 const TeamUiSettings* oldUiSettings = fTeamSettings.UiSettingAt(i); 1742 if (strcmp(oldUiSettings->ID(), fUserInterface->ID()) != 0) { 1743 TeamUiSettings* clonedSettings = oldUiSettings->Clone(); 1744 if (clonedSettings != NULL) 1745 settings.AddUiSettings(clonedSettings); 1746 } 1747 } 1748 locker.Unlock(); 1749 1750 // save the settings 1751 fSettingsManager->SaveTeamSettings(settings); 1752} 1753 1754 1755void 1756TeamDebugger::_NotifyUser(const char* title, const char* text,...) 1757{ 1758 // print the message 1759 char buffer[1024]; 1760 va_list args; 1761 va_start(args, text); 1762 vsnprintf(buffer, sizeof(buffer), text, args); 1763 va_end(args); 1764 1765 // notify the user 1766 fUserInterface->NotifyUser(title, buffer, USER_NOTIFICATION_WARNING); 1767} 1768 1769 1770// #pragma mark - Listener 1771 1772 1773TeamDebugger::Listener::~Listener() 1774{ 1775} 1776