1 /* 2 * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2010-2014, Rene Gollent, rene@gollent.com. 4 * Distributed under the terms of the MIT License. 5 */ 6 7 8 #include "TeamWindow.h" 9 10 #include <stdio.h> 11 12 #include <Alert.h> 13 #include <Button.h> 14 #include <FilePanel.h> 15 #include <FindDirectory.h> 16 #include <LayoutBuilder.h> 17 #include <Menu.h> 18 #include <MenuBar.h> 19 #include <MenuItem.h> 20 #include <Message.h> 21 #include <MessageFilter.h> 22 #include <MessageRunner.h> 23 #include <Path.h> 24 #include <PopUpMenu.h> 25 #include <Query.h> 26 #include <StringView.h> 27 #include <TabView.h> 28 #include <ScrollView.h> 29 #include <SplitView.h> 30 #include <TextView.h> 31 #include <VolumeRoster.h> 32 33 #include <AutoDeleter.h> 34 #include <AutoLocker.h> 35 36 #include "Breakpoint.h" 37 #include "ConsoleOutputView.h" 38 #include "CpuState.h" 39 #include "DisassembledCode.h" 40 #include "BreakConditionConfigWindow.h" 41 #include "FileSourceCode.h" 42 #include "GuiSettingsUtils.h" 43 #include "GuiTeamUiSettings.h" 44 #include "Image.h" 45 #include "ImageDebugInfo.h" 46 #include "InspectorWindow.h" 47 #include "LocatableFile.h" 48 #include "MessageCodes.h" 49 #include "RegistersView.h" 50 #include "StackTrace.h" 51 #include "StackTraceView.h" 52 #include "Tracing.h" 53 #include "TypeComponentPath.h" 54 #include "UiUtils.h" 55 #include "UserInterface.h" 56 #include "Variable.h" 57 #include "WatchPromptWindow.h" 58 59 60 enum { 61 MAIN_TAB_INDEX_THREADS = 0, 62 MAIN_TAB_INDEX_IMAGES = 1 63 }; 64 65 66 enum { 67 MSG_CHOOSE_DEBUG_REPORT_LOCATION = 'ccrl', 68 MSG_DEBUG_REPORT_SAVED = 'drsa', 69 MSG_LOCATE_SOURCE_IF_NEEDED = 'lsin', 70 MSG_SOURCE_ENTRY_QUERY_COMPLETE = 'seqc', 71 MSG_CLEAR_STACK_TRACE = 'clst' 72 }; 73 74 75 class PathViewMessageFilter : public BMessageFilter { 76 public: 77 PathViewMessageFilter(BMessenger teamWindow) 78 : 79 BMessageFilter(B_MOUSE_UP), 80 fTeamWindowMessenger(teamWindow) 81 { 82 } 83 84 virtual filter_result Filter(BMessage*, BHandler**) 85 { 86 fTeamWindowMessenger.SendMessage(MSG_LOCATE_SOURCE_IF_NEEDED); 87 88 return B_DISPATCH_MESSAGE; 89 } 90 91 private: 92 BMessenger fTeamWindowMessenger; 93 }; 94 95 96 // #pragma mark - TeamWindow 97 98 99 TeamWindow::TeamWindow(::Team* team, UserInterfaceListener* listener) 100 : 101 BWindow(BRect(100, 100, 899, 699), "Team", B_TITLED_WINDOW, 102 B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS), 103 fTeam(team), 104 fActiveThread(NULL), 105 fActiveImage(NULL), 106 fActiveStackTrace(NULL), 107 fActiveStackFrame(NULL), 108 fActiveBreakpoint(NULL), 109 fActiveFunction(NULL), 110 fActiveSourceCode(NULL), 111 fActiveSourceObject(ACTIVE_SOURCE_NONE), 112 fListener(listener), 113 fTraceUpdateRunner(NULL), 114 fTabView(NULL), 115 fLocalsTabView(NULL), 116 fThreadListView(NULL), 117 fImageListView(NULL), 118 fImageFunctionsView(NULL), 119 fBreakpointsView(NULL), 120 fVariablesView(NULL), 121 fRegistersView(NULL), 122 fStackTraceView(NULL), 123 fSourceView(NULL), 124 fRunButton(NULL), 125 fStepOverButton(NULL), 126 fStepIntoButton(NULL), 127 fStepOutButton(NULL), 128 fMenuBar(NULL), 129 fSourcePathView(NULL), 130 fConsoleOutputView(NULL), 131 fFunctionSplitView(NULL), 132 fSourceSplitView(NULL), 133 fImageSplitView(NULL), 134 fThreadSplitView(NULL), 135 fConsoleSplitView(NULL), 136 fBreakConditionConfigWindow(NULL), 137 fInspectorWindow(NULL), 138 fFilePanel(NULL), 139 fActiveSourceWorker(-1) 140 { 141 fTeam->Lock(); 142 BString name = fTeam->Name(); 143 fTeam->Unlock(); 144 if (fTeam->ID() >= 0) 145 name << " (" << fTeam->ID() << ")"; 146 SetTitle(name.String()); 147 148 fTeam->AddListener(this); 149 } 150 151 152 TeamWindow::~TeamWindow() 153 { 154 if (fThreadListView != NULL) 155 fThreadListView->UnsetListener(); 156 if (fStackTraceView != NULL) 157 fStackTraceView->UnsetListener(); 158 if (fSourceView != NULL) 159 fSourceView->UnsetListener(); 160 if (fInspectorWindow != NULL) { 161 BMessenger messenger(fInspectorWindow); 162 if (messenger.LockTarget()) 163 fInspectorWindow->Quit(); 164 } 165 166 fTeam->RemoveListener(this); 167 168 _SetActiveSourceCode(NULL); 169 _SetActiveFunction(NULL); 170 _SetActiveBreakpoint(NULL); 171 _SetActiveStackFrame(NULL); 172 _SetActiveStackTrace(NULL); 173 _SetActiveImage(NULL); 174 _SetActiveThread(NULL); 175 176 delete fFilePanel; 177 178 if (fActiveSourceWorker > 0) 179 wait_for_thread(fActiveSourceWorker, NULL); 180 } 181 182 183 /*static*/ TeamWindow* 184 TeamWindow::Create(::Team* team, UserInterfaceListener* listener) 185 { 186 TeamWindow* self = new TeamWindow(team, listener); 187 188 try { 189 self->_Init(); 190 } catch (...) { 191 delete self; 192 throw; 193 } 194 195 return self; 196 } 197 198 199 void 200 TeamWindow::DispatchMessage(BMessage* message, BHandler* handler) 201 { 202 // Handle function key shortcuts for stepping 203 switch (message->what) { 204 case B_KEY_DOWN: 205 if (fActiveThread != NULL && fTraceUpdateRunner == NULL) { 206 int32 key; 207 uint32 modifiers; 208 if (message->FindInt32("key", &key) == B_OK 209 && message->FindInt32("modifiers", (int32*)&modifiers) 210 == B_OK) { 211 switch (key) { 212 case B_F5_KEY: 213 fListener->ThreadActionRequested( 214 fActiveThread->ID(), MSG_THREAD_RUN); 215 break; 216 case B_F10_KEY: 217 fListener->ThreadActionRequested( 218 fActiveThread->ID(), MSG_THREAD_STEP_OVER); 219 break; 220 case B_F11_KEY: 221 if ((modifiers & B_SHIFT_KEY) != 0) { 222 fListener->ThreadActionRequested( 223 fActiveThread->ID(), MSG_THREAD_STEP_OUT); 224 } else { 225 fListener->ThreadActionRequested( 226 fActiveThread->ID(), MSG_THREAD_STEP_INTO); 227 } 228 break; 229 default: 230 break; 231 } 232 } 233 } 234 break; 235 236 case B_COPY: 237 case B_SELECT_ALL: 238 BView* focusView = CurrentFocus(); 239 if (focusView != NULL) { 240 focusView->MessageReceived(message); 241 return; 242 } 243 break; 244 } 245 BWindow::DispatchMessage(message, handler); 246 } 247 248 249 void 250 TeamWindow::MessageReceived(BMessage* message) 251 { 252 switch (message->what) { 253 case MSG_TEAM_RESTART_REQUESTED: 254 { 255 fListener->TeamRestartRequested(); 256 break; 257 } 258 case MSG_CHOOSE_DEBUG_REPORT_LOCATION: 259 { 260 try { 261 char filename[B_FILE_NAME_LENGTH]; 262 UiUtils::ReportNameForTeam(fTeam, filename, sizeof(filename)); 263 BMessenger msgr(this); 264 fFilePanel = new BFilePanel(B_SAVE_PANEL, &msgr, 265 NULL, 0, false, new BMessage(MSG_GENERATE_DEBUG_REPORT)); 266 fFilePanel->SetSaveText(filename); 267 fFilePanel->Show(); 268 } catch (...) { 269 delete fFilePanel; 270 fFilePanel = NULL; 271 } 272 break; 273 } 274 case MSG_GENERATE_DEBUG_REPORT: 275 { 276 delete fFilePanel; 277 fFilePanel = NULL; 278 279 BPath path; 280 entry_ref ref; 281 if (message->FindRef("directory", &ref) == B_OK 282 && message->HasString("name")) { 283 path.SetTo(&ref); 284 path.Append(message->FindString("name")); 285 if (get_ref_for_path(path.Path(), &ref) == B_OK) 286 fListener->DebugReportRequested(&ref); 287 } 288 break; 289 } 290 case MSG_DEBUG_REPORT_SAVED: 291 { 292 BString data; 293 data.SetToFormat("Debug report successfully saved to '%s'", 294 message->FindString("path")); 295 BAlert *alert = new(std::nothrow) BAlert("Report saved", 296 data.String(), "Close"); 297 if (alert == NULL) 298 break; 299 300 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 301 alert->Go(); 302 break; 303 } 304 case MSG_SHOW_INSPECTOR_WINDOW: 305 { 306 if (fInspectorWindow) { 307 fInspectorWindow->Activate(true); 308 } else { 309 try { 310 fInspectorWindow = InspectorWindow::Create(fTeam, 311 fListener, this); 312 if (fInspectorWindow != NULL) { 313 BMessage settings; 314 fInspectorWindow->LoadSettings(fUiSettings); 315 fInspectorWindow->Show(); 316 } 317 } catch (...) { 318 // TODO: notify user 319 } 320 } 321 322 target_addr_t address; 323 if (message->FindUInt64("address", &address) == B_OK) { 324 BMessage addressMessage(MSG_INSPECT_ADDRESS); 325 addressMessage.AddUInt64("address", address); 326 fInspectorWindow->PostMessage(&addressMessage); 327 } 328 break; 329 } 330 case MSG_INSPECTOR_WINDOW_CLOSED: 331 { 332 _SaveInspectorSettings(CurrentMessage()); 333 fInspectorWindow = NULL; 334 break; 335 336 } 337 case MSG_SHOW_BREAK_CONDITION_CONFIG_WINDOW: 338 { 339 if (fBreakConditionConfigWindow) { 340 fBreakConditionConfigWindow->Activate(true); 341 } else { 342 try { 343 fBreakConditionConfigWindow 344 = BreakConditionConfigWindow::Create( 345 fTeam, fListener, this); 346 if (fBreakConditionConfigWindow != NULL) 347 fBreakConditionConfigWindow->Show(); 348 } catch (...) { 349 // TODO: notify user 350 } 351 } 352 break; 353 } 354 case MSG_BREAK_CONDITION_CONFIG_WINDOW_CLOSED: 355 { 356 fBreakConditionConfigWindow = NULL; 357 break; 358 } 359 case MSG_SHOW_WATCH_VARIABLE_PROMPT: 360 { 361 target_addr_t address; 362 uint32 type; 363 int32 length; 364 365 if (message->FindUInt64("address", &address) != B_OK 366 || message->FindUInt32("type", &type) != B_OK 367 || message->FindInt32("length", &length) != B_OK) { 368 break; 369 } 370 371 try { 372 WatchPromptWindow* window = WatchPromptWindow::Create( 373 fTeam->GetArchitecture(), address, type, length, 374 fListener); 375 window->Show(); 376 } catch (...) { 377 // TODO: notify user 378 } 379 break; 380 } 381 case B_REFS_RECEIVED: 382 { 383 entry_ref locatedPath; 384 if (message->FindRef("refs", &locatedPath) != B_OK) 385 break; 386 387 _HandleResolveMissingSourceFile(locatedPath); 388 break; 389 } 390 case MSG_LOCATE_SOURCE_IF_NEEDED: 391 { 392 _HandleLocateSourceRequest(); 393 break; 394 } 395 case MSG_SOURCE_ENTRY_QUERY_COMPLETE: 396 { 397 BStringList* entries; 398 if (message->FindPointer("entries", (void**)&entries) != B_OK) 399 break; 400 ObjectDeleter<BStringList> entryDeleter(entries); 401 _HandleLocateSourceRequest(entries); 402 fActiveSourceWorker = -1; 403 break; 404 } 405 case MSG_THREAD_RUN: 406 case MSG_THREAD_STOP: 407 case MSG_THREAD_STEP_OVER: 408 case MSG_THREAD_STEP_INTO: 409 case MSG_THREAD_STEP_OUT: 410 if (fActiveThread != NULL && fTraceUpdateRunner == NULL) { 411 fListener->ThreadActionRequested(fActiveThread->ID(), 412 message->what); 413 } 414 break; 415 416 case MSG_CLEAR_STACK_TRACE: 417 { 418 if (fTraceUpdateRunner != NULL) { 419 _SetActiveStackTrace(NULL); 420 _UpdateRunButtons(); 421 } 422 break; 423 } 424 case MSG_THREAD_STATE_CHANGED: 425 { 426 int32 threadID; 427 if (message->FindInt32("thread", &threadID) != B_OK) 428 break; 429 430 _HandleThreadStateChanged(threadID); 431 break; 432 } 433 case MSG_THREAD_CPU_STATE_CHANGED: 434 { 435 int32 threadID; 436 if (message->FindInt32("thread", &threadID) != B_OK) 437 break; 438 439 _HandleCpuStateChanged(threadID); 440 break; 441 } 442 443 case MSG_THREAD_STACK_TRACE_CHANGED: 444 { 445 int32 threadID; 446 if (message->FindInt32("thread", &threadID) != B_OK) 447 break; 448 449 _HandleStackTraceChanged(threadID); 450 break; 451 } 452 453 case MSG_IMAGE_DEBUG_INFO_CHANGED: 454 { 455 int32 imageID; 456 if (message->FindInt32("image", &imageID) != B_OK) 457 break; 458 459 _HandleImageDebugInfoChanged(imageID); 460 break; 461 } 462 463 case MSG_CONSOLE_OUTPUT_RECEIVED: 464 { 465 int32 fd; 466 BString output; 467 if (message->FindInt32("fd", &fd) != B_OK 468 || message->FindString("output", &output) != B_OK) { 469 break; 470 } 471 fConsoleOutputView->ConsoleOutputReceived(fd, output); 472 break; 473 } 474 475 case MSG_USER_BREAKPOINT_CHANGED: 476 { 477 UserBreakpoint* breakpoint; 478 if (message->FindPointer("breakpoint", (void**)&breakpoint) != B_OK) 479 break; 480 BReference<UserBreakpoint> breakpointReference(breakpoint, true); 481 482 _HandleUserBreakpointChanged(breakpoint); 483 break; 484 } 485 486 case MSG_WATCHPOINT_CHANGED: 487 { 488 Watchpoint* watchpoint; 489 if (message->FindPointer("watchpoint", (void**)&watchpoint) != B_OK) 490 break; 491 BReference<Watchpoint> watchpointReference(watchpoint, true); 492 493 _HandleWatchpointChanged(watchpoint); 494 break; 495 496 } 497 498 case MSG_FUNCTION_SOURCE_CODE_CHANGED: 499 { 500 _HandleSourceCodeChanged(); 501 break; 502 } 503 504 default: 505 BWindow::MessageReceived(message); 506 break; 507 } 508 } 509 510 511 bool 512 TeamWindow::QuitRequested() 513 { 514 fListener->UserInterfaceQuitRequested(); 515 516 return false; 517 } 518 519 520 status_t 521 TeamWindow::LoadSettings(const GuiTeamUiSettings* settings) 522 { 523 AutoLocker<BWindow> lock(this); 524 if (!lock.IsLocked()) 525 return B_ERROR; 526 527 BMessage teamWindowSettings; 528 // no settings stored yet 529 if (settings->Settings("teamWindow", teamWindowSettings) != B_OK) 530 return B_OK; 531 532 BRect frame; 533 if (teamWindowSettings.FindRect("frame", &frame) == B_OK) { 534 ResizeTo(frame.Width(), frame.Height()); 535 MoveTo(frame.left, frame.top); 536 } 537 538 BMessage archive; 539 if (teamWindowSettings.FindMessage("sourceSplit", &archive) == B_OK) 540 GuiSettingsUtils::UnarchiveSplitView(archive, fSourceSplitView); 541 542 if (teamWindowSettings.FindMessage("functionSplit", &archive) == B_OK) 543 GuiSettingsUtils::UnarchiveSplitView(archive, fFunctionSplitView); 544 545 if (teamWindowSettings.FindMessage("imageSplit", &archive) == B_OK) 546 GuiSettingsUtils::UnarchiveSplitView(archive, fImageSplitView); 547 548 if (teamWindowSettings.FindMessage("threadSplit", &archive) == B_OK) 549 GuiSettingsUtils::UnarchiveSplitView(archive, fThreadSplitView); 550 551 if (teamWindowSettings.FindMessage("consoleSplit", &archive) == B_OK) 552 GuiSettingsUtils::UnarchiveSplitView(archive, fConsoleSplitView); 553 554 if (teamWindowSettings.FindMessage("imageListView", &archive) == B_OK) 555 fImageListView->LoadSettings(archive); 556 557 if (teamWindowSettings.FindMessage("imageFunctionsView", &archive) == B_OK) 558 fImageFunctionsView->LoadSettings(archive); 559 560 if (teamWindowSettings.FindMessage("threadListView", &archive) == B_OK) 561 fThreadListView->LoadSettings(archive); 562 563 if (teamWindowSettings.FindMessage("variablesView", &archive) == B_OK) 564 fVariablesView->LoadSettings(archive); 565 566 if (teamWindowSettings.FindMessage("registersView", &archive) == B_OK) 567 fRegistersView->LoadSettings(archive); 568 569 if (teamWindowSettings.FindMessage("stackTraceView", &archive) == B_OK) 570 fStackTraceView->LoadSettings(archive); 571 572 if (teamWindowSettings.FindMessage("breakpointsView", &archive) == B_OK) 573 fBreakpointsView->LoadSettings(archive); 574 575 if (teamWindowSettings.FindMessage("consoleOutputView", &archive) == B_OK) 576 fConsoleOutputView->LoadSettings(archive); 577 578 fUiSettings = *settings; 579 580 return B_OK; 581 } 582 583 584 status_t 585 TeamWindow::SaveSettings(GuiTeamUiSettings* settings) 586 { 587 AutoLocker<BWindow> lock(this); 588 if (!lock.IsLocked()) 589 return B_ERROR; 590 591 BMessage inspectorSettings; 592 if (fUiSettings.Settings("inspectorWindow", inspectorSettings) == B_OK) { 593 if (!settings->AddSettings("inspectorWindow", inspectorSettings)) 594 return B_NO_MEMORY; 595 } 596 597 BMessage archive; 598 BMessage teamWindowSettings; 599 if (teamWindowSettings.AddRect("frame", Frame()) != B_OK) 600 return B_NO_MEMORY; 601 602 if (GuiSettingsUtils::ArchiveSplitView(archive, fSourceSplitView) != B_OK) 603 return B_NO_MEMORY; 604 if (teamWindowSettings.AddMessage("sourceSplit", &archive) != B_OK) 605 return B_NO_MEMORY; 606 607 if (GuiSettingsUtils::ArchiveSplitView(archive, fFunctionSplitView) != B_OK) 608 return B_NO_MEMORY; 609 if (teamWindowSettings.AddMessage("functionSplit", &archive) != B_OK) 610 return B_NO_MEMORY; 611 612 if (GuiSettingsUtils::ArchiveSplitView(archive, fImageSplitView) != B_OK) 613 return B_NO_MEMORY; 614 if (teamWindowSettings.AddMessage("imageSplit", &archive)) 615 return B_NO_MEMORY; 616 617 if (GuiSettingsUtils::ArchiveSplitView(archive, fThreadSplitView) != B_OK) 618 return B_NO_MEMORY; 619 if (teamWindowSettings.AddMessage("threadSplit", &archive)) 620 return B_NO_MEMORY; 621 622 if (GuiSettingsUtils::ArchiveSplitView(archive, fConsoleSplitView) != B_OK) 623 return B_NO_MEMORY; 624 if (teamWindowSettings.AddMessage("consoleSplit", &archive)) 625 return B_NO_MEMORY; 626 627 if (fImageListView->SaveSettings(archive) != B_OK) 628 return B_NO_MEMORY; 629 if (teamWindowSettings.AddMessage("imageListView", &archive)) 630 return B_NO_MEMORY; 631 632 if (fImageFunctionsView->SaveSettings(archive) != B_OK) 633 return B_NO_MEMORY; 634 if (teamWindowSettings.AddMessage("imageFunctionsView", &archive)) 635 return B_NO_MEMORY; 636 637 if (fThreadListView->SaveSettings(archive) != B_OK) 638 return B_NO_MEMORY; 639 if (teamWindowSettings.AddMessage("threadListView", &archive)) 640 return B_NO_MEMORY; 641 642 if (fVariablesView->SaveSettings(archive) != B_OK) 643 return B_NO_MEMORY; 644 if (teamWindowSettings.AddMessage("variablesView", &archive)) 645 return B_NO_MEMORY; 646 647 if (fRegistersView->SaveSettings(archive) != B_OK) 648 return B_NO_MEMORY; 649 if (teamWindowSettings.AddMessage("registersView", &archive)) 650 return B_NO_MEMORY; 651 652 if (fStackTraceView->SaveSettings(archive) != B_OK) 653 return B_NO_MEMORY; 654 if (teamWindowSettings.AddMessage("stackTraceView", &archive)) 655 return B_NO_MEMORY; 656 657 if (fBreakpointsView->SaveSettings(archive) != B_OK) 658 return B_NO_MEMORY; 659 if (teamWindowSettings.AddMessage("breakpointsView", &archive)) 660 return B_NO_MEMORY; 661 662 if (fConsoleOutputView->SaveSettings(archive) != B_OK) 663 return B_NO_MEMORY; 664 if (teamWindowSettings.AddMessage("consoleOutputView", &archive)) 665 return B_NO_MEMORY; 666 667 if (!settings->AddSettings("teamWindow", teamWindowSettings)) 668 return B_NO_MEMORY; 669 670 return B_OK; 671 } 672 673 674 void 675 TeamWindow::ThreadSelectionChanged(::Thread* thread) 676 { 677 _SetActiveThread(thread); 678 } 679 680 681 void 682 TeamWindow::ImageSelectionChanged(Image* image) 683 { 684 _SetActiveImage(image); 685 } 686 687 688 void 689 TeamWindow::StackFrameSelectionChanged(StackFrame* frame) 690 { 691 _SetActiveStackFrame(frame); 692 } 693 694 695 void 696 TeamWindow::FunctionSelectionChanged(FunctionInstance* function) 697 { 698 // If the function wasn't already active, it was just selected by the user. 699 if (function != NULL && function != fActiveFunction) 700 fActiveSourceObject = ACTIVE_SOURCE_FUNCTION; 701 702 _SetActiveFunction(function); 703 } 704 705 706 void 707 TeamWindow::BreakpointSelectionChanged(BreakpointProxyList &proxies) 708 { 709 if (proxies.CountItems() == 0 && fActiveBreakpoint != NULL) { 710 fActiveBreakpoint->ReleaseReference(); 711 fActiveBreakpoint = NULL; 712 } else if (proxies.CountItems() == 1) { 713 BreakpointProxy* proxy = proxies.ItemAt(0); 714 if (proxy->Type() == BREAKPOINT_PROXY_TYPE_BREAKPOINT) 715 _SetActiveBreakpoint(proxy->GetBreakpoint()); 716 } 717 // if more than one item is selected, do nothing. 718 } 719 720 721 void 722 TeamWindow::SetBreakpointEnabledRequested(UserBreakpoint* breakpoint, 723 bool enabled) 724 { 725 fListener->SetBreakpointEnabledRequested(breakpoint, enabled); 726 } 727 728 729 void 730 TeamWindow::ClearBreakpointRequested(UserBreakpoint* breakpoint) 731 { 732 fListener->ClearBreakpointRequested(breakpoint); 733 } 734 735 736 void 737 TeamWindow::SetBreakpointRequested(target_addr_t address, bool enabled) 738 { 739 fListener->SetBreakpointRequested(address, enabled); 740 } 741 742 743 void 744 TeamWindow::ClearBreakpointRequested(target_addr_t address) 745 { 746 fListener->ClearBreakpointRequested(address); 747 } 748 749 750 void 751 TeamWindow::ThreadActionRequested(::Thread* thread, uint32 action, 752 target_addr_t address) 753 { 754 if (fTraceUpdateRunner == NULL) 755 fListener->ThreadActionRequested(thread->ID(), action, address); 756 } 757 758 759 void 760 TeamWindow::FunctionSourceCodeRequested(FunctionInstance* function, 761 bool forceDisassembly) 762 { 763 fListener->FunctionSourceCodeRequested(function, forceDisassembly); 764 } 765 766 767 void 768 TeamWindow::SetWatchpointEnabledRequested(Watchpoint* watchpoint, 769 bool enabled) 770 { 771 fListener->SetWatchpointEnabledRequested(watchpoint, enabled); 772 } 773 774 775 void 776 TeamWindow::ClearWatchpointRequested(Watchpoint* watchpoint) 777 { 778 fListener->ClearWatchpointRequested(watchpoint); 779 } 780 781 782 void 783 TeamWindow::ValueNodeValueRequested(CpuState* cpuState, 784 ValueNodeContainer* container, ValueNode* valueNode) 785 { 786 fListener->ValueNodeValueRequested(cpuState, container, valueNode); 787 } 788 789 790 void 791 TeamWindow::ThreadStateChanged(const Team::ThreadEvent& event) 792 { 793 BMessage message(MSG_THREAD_STATE_CHANGED); 794 message.AddInt32("thread", event.GetThread()->ID()); 795 PostMessage(&message); 796 } 797 798 799 void 800 TeamWindow::ThreadCpuStateChanged(const Team::ThreadEvent& event) 801 { 802 BMessage message(MSG_THREAD_CPU_STATE_CHANGED); 803 message.AddInt32("thread", event.GetThread()->ID()); 804 PostMessage(&message); 805 } 806 807 808 void 809 TeamWindow::ThreadStackTraceChanged(const Team::ThreadEvent& event) 810 { 811 BMessage message(MSG_THREAD_STACK_TRACE_CHANGED); 812 message.AddInt32("thread", event.GetThread()->ID()); 813 PostMessage(&message); 814 } 815 816 817 void 818 TeamWindow::ImageDebugInfoChanged(const Team::ImageEvent& event) 819 { 820 BMessage message(MSG_IMAGE_DEBUG_INFO_CHANGED); 821 message.AddInt32("image", event.GetImage()->ID()); 822 PostMessage(&message); 823 } 824 825 826 void 827 TeamWindow::ConsoleOutputReceived(const Team::ConsoleOutputEvent& event) 828 { 829 BMessage message(MSG_CONSOLE_OUTPUT_RECEIVED); 830 message.AddInt32("fd", event.Descriptor()); 831 message.AddString("output", event.Output()); 832 PostMessage(&message); 833 } 834 835 836 void 837 TeamWindow::UserBreakpointChanged(const Team::UserBreakpointEvent& event) 838 { 839 BMessage message(MSG_USER_BREAKPOINT_CHANGED); 840 BReference<UserBreakpoint> breakpointReference(event.GetBreakpoint()); 841 if (message.AddPointer("breakpoint", event.GetBreakpoint()) == B_OK 842 && PostMessage(&message) == B_OK) { 843 breakpointReference.Detach(); 844 } 845 } 846 847 848 void 849 TeamWindow::WatchpointChanged(const Team::WatchpointEvent& event) 850 { 851 BMessage message(MSG_WATCHPOINT_CHANGED); 852 BReference<Watchpoint> watchpointReference(event.GetWatchpoint()); 853 if (message.AddPointer("watchpoint", event.GetWatchpoint()) == B_OK 854 && PostMessage(&message) == B_OK) { 855 watchpointReference.Detach(); 856 } 857 } 858 859 860 void 861 TeamWindow::DebugReportChanged(const Team::DebugReportEvent& event) 862 { 863 BMessage message(MSG_DEBUG_REPORT_SAVED); 864 message.AddString("path", event.GetReportPath()); 865 PostMessage(&message); 866 } 867 868 869 void 870 TeamWindow::FunctionSourceCodeChanged(Function* function) 871 { 872 TRACE_GUI("TeamWindow::FunctionSourceCodeChanged(%p): source: %p, " 873 "state: %d\n", function, function->GetSourceCode(), 874 function->SourceCodeState()); 875 876 PostMessage(MSG_FUNCTION_SOURCE_CODE_CHANGED); 877 } 878 879 880 void 881 TeamWindow::_Init() 882 { 883 BScrollView* sourceScrollView; 884 885 const float splitSpacing = 3.0f; 886 887 BLayoutBuilder::Group<>(this, B_VERTICAL, 0.0f) 888 .Add(fMenuBar = new BMenuBar("Menu")) 889 .AddSplit(B_VERTICAL, splitSpacing) 890 .GetSplitView(&fFunctionSplitView) 891 .SetInsets(B_USE_SMALL_INSETS) 892 .Add(fTabView = new BTabView("tab view"), 0.4f) 893 .AddSplit(B_HORIZONTAL, splitSpacing) 894 .GetSplitView(&fSourceSplitView) 895 .AddGroup(B_VERTICAL, B_USE_SMALL_SPACING) 896 .AddGroup(B_HORIZONTAL, B_USE_SMALL_SPACING) 897 .Add(fRunButton = new BButton("Run")) 898 .Add(fStepOverButton = new BButton("Step over")) 899 .Add(fStepIntoButton = new BButton("Step into")) 900 .Add(fStepOutButton = new BButton("Step out")) 901 .AddGlue() 902 .End() 903 .Add(fSourcePathView = new BStringView( 904 "source path", 905 "Source path unavailable."), 4.0f) 906 .Add(sourceScrollView = new BScrollView("source scroll", 907 NULL, 0, true, true), splitSpacing) 908 .End() 909 .Add(fLocalsTabView = new BTabView("locals view")) 910 .End() 911 .AddSplit(B_VERTICAL, splitSpacing) 912 .GetSplitView(&fConsoleSplitView) 913 .SetInsets(0.0) 914 .Add(fConsoleOutputView = ConsoleOutputView::Create()) 915 .End() 916 .End(); 917 918 // add source view 919 sourceScrollView->SetTarget(fSourceView = SourceView::Create(fTeam, this)); 920 921 // add threads tab 922 BSplitView* threadGroup = new BSplitView(B_HORIZONTAL, splitSpacing); 923 threadGroup->SetName("Threads"); 924 fTabView->AddTab(threadGroup); 925 BLayoutBuilder::Split<>(threadGroup) 926 .GetSplitView(&fThreadSplitView) 927 .Add(fThreadListView = ThreadListView::Create(fTeam, this)) 928 .Add(fStackTraceView = StackTraceView::Create(this)); 929 930 // add images tab 931 BSplitView* imagesGroup = new BSplitView(B_HORIZONTAL, splitSpacing); 932 imagesGroup->SetName("Images"); 933 fTabView->AddTab(imagesGroup); 934 BLayoutBuilder::Split<>(imagesGroup) 935 .GetSplitView(&fImageSplitView) 936 .Add(fImageListView = ImageListView::Create(fTeam, this)) 937 .Add(fImageFunctionsView = ImageFunctionsView::Create(this)); 938 939 // add breakpoints tab 940 BGroupView* breakpointsGroup = new BGroupView(B_HORIZONTAL, 941 B_USE_SMALL_SPACING); 942 breakpointsGroup->SetName("Breakpoints"); 943 fTabView->AddTab(breakpointsGroup); 944 BLayoutBuilder::Group<>(breakpointsGroup) 945 // .SetInsets(0.0f) 946 .Add(fBreakpointsView = BreakpointsView::Create(fTeam, this)); 947 948 // add local variables tab 949 BView* tab = fVariablesView = VariablesView::Create(this); 950 fLocalsTabView->AddTab(tab); 951 952 // add registers tab 953 tab = fRegistersView = RegistersView::Create(fTeam->GetArchitecture()); 954 fLocalsTabView->AddTab(tab); 955 956 fRunButton->SetMessage(new BMessage(MSG_THREAD_RUN)); 957 fStepOverButton->SetMessage(new BMessage(MSG_THREAD_STEP_OVER)); 958 fStepIntoButton->SetMessage(new BMessage(MSG_THREAD_STEP_INTO)); 959 fStepOutButton->SetMessage(new BMessage(MSG_THREAD_STEP_OUT)); 960 fRunButton->SetTarget(this); 961 fStepOverButton->SetTarget(this); 962 fStepIntoButton->SetTarget(this); 963 fStepOutButton->SetTarget(this); 964 965 fSourcePathView->SetExplicitMinSize(BSize(100.0, B_SIZE_UNSET)); 966 fSourcePathView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); 967 BMessageFilter* filter = new(std::nothrow) PathViewMessageFilter( 968 BMessenger(this)); 969 if (filter != NULL) 970 fSourcePathView->AddFilter(filter); 971 972 // add menus and menu items 973 BMenu* menu = new BMenu("Team"); 974 fMenuBar->AddItem(menu); 975 BMenuItem* item = new BMenuItem("Restart", new BMessage( 976 MSG_TEAM_RESTART_REQUESTED), 'R', B_SHIFT_KEY); 977 menu->AddItem(item); 978 item->SetTarget(this); 979 item = new BMenuItem("Close", new BMessage(B_QUIT_REQUESTED), 980 'W'); 981 menu->AddItem(item); 982 item->SetTarget(this); 983 menu = new BMenu("Edit"); 984 fMenuBar->AddItem(menu); 985 item = new BMenuItem("Copy", new BMessage(B_COPY), 'C'); 986 menu->AddItem(item); 987 item->SetTarget(this); 988 item = new BMenuItem("Select all", new BMessage(B_SELECT_ALL), 'A'); 989 menu->AddItem(item); 990 item->SetTarget(this); 991 menu = new BMenu("Tools"); 992 fMenuBar->AddItem(menu); 993 item = new BMenuItem("Save debug report", 994 new BMessage(MSG_CHOOSE_DEBUG_REPORT_LOCATION)); 995 menu->AddItem(item); 996 item->SetTarget(this); 997 item = new BMenuItem("Inspect memory", 998 new BMessage(MSG_SHOW_INSPECTOR_WINDOW), 'I'); 999 menu->AddItem(item); 1000 item->SetTarget(this); 1001 1002 AutoLocker< ::Team> locker(fTeam); 1003 _UpdateRunButtons(); 1004 } 1005 1006 1007 void 1008 TeamWindow::_SetActiveThread(::Thread* thread) 1009 { 1010 if (thread == fActiveThread) 1011 return; 1012 1013 if (fActiveThread != NULL) 1014 fActiveThread->ReleaseReference(); 1015 1016 fActiveThread = thread; 1017 1018 if (fActiveThread != NULL) 1019 fActiveThread->AcquireReference(); 1020 1021 AutoLocker< ::Team> locker(fTeam); 1022 _UpdateRunButtons(); 1023 1024 StackTrace* stackTrace = fActiveThread != NULL 1025 ? fActiveThread->GetStackTrace() : NULL; 1026 BReference<StackTrace> stackTraceReference(stackTrace); 1027 // hold a reference until we've set it 1028 1029 locker.Unlock(); 1030 1031 fThreadListView->SetThread(fActiveThread); 1032 1033 _SetActiveStackTrace(stackTrace); 1034 _UpdateCpuState(); 1035 } 1036 1037 1038 void 1039 TeamWindow::_SetActiveImage(Image* image) 1040 { 1041 if (image == fActiveImage) 1042 return; 1043 1044 if (fActiveImage != NULL) 1045 fActiveImage->ReleaseReference(); 1046 1047 fActiveImage = image; 1048 1049 AutoLocker< ::Team> locker(fTeam); 1050 1051 ImageDebugInfo* imageDebugInfo = NULL; 1052 BReference<ImageDebugInfo> imageDebugInfoReference; 1053 1054 if (fActiveImage != NULL) { 1055 fActiveImage->AcquireReference(); 1056 1057 imageDebugInfo = fActiveImage->GetImageDebugInfo(); 1058 imageDebugInfoReference.SetTo(imageDebugInfo); 1059 1060 // If the debug info is not loaded yet, request it. 1061 if (fActiveImage->ImageDebugInfoState() == IMAGE_DEBUG_INFO_NOT_LOADED) 1062 fListener->ImageDebugInfoRequested(fActiveImage); 1063 } 1064 1065 locker.Unlock(); 1066 1067 fImageListView->SetImage(fActiveImage); 1068 fImageFunctionsView->SetImageDebugInfo(imageDebugInfo); 1069 } 1070 1071 1072 void 1073 TeamWindow::_SetActiveStackTrace(StackTrace* stackTrace) 1074 { 1075 delete fTraceUpdateRunner; 1076 fTraceUpdateRunner = NULL; 1077 1078 if (stackTrace == fActiveStackTrace) 1079 return; 1080 1081 if (fActiveStackTrace != NULL) 1082 fActiveStackTrace->ReleaseReference(); 1083 1084 fActiveStackTrace = stackTrace; 1085 1086 if (fActiveStackTrace != NULL) 1087 fActiveStackTrace->AcquireReference(); 1088 1089 fStackTraceView->SetStackTrace(fActiveStackTrace); 1090 fSourceView->SetStackTrace(fActiveStackTrace, fActiveThread); 1091 1092 if (fActiveStackTrace != NULL) 1093 _SetActiveStackFrame(fActiveStackTrace->FrameAt(0)); 1094 else 1095 _SetActiveStackFrame(NULL); 1096 } 1097 1098 1099 void 1100 TeamWindow::_SetActiveStackFrame(StackFrame* frame) 1101 { 1102 if (frame == fActiveStackFrame) 1103 return; 1104 1105 if (fActiveStackFrame != NULL) { 1106 AutoLocker< ::Team> locker(fTeam); 1107 fActiveStackFrame->RemoveListener(this); 1108 locker.Unlock(); 1109 1110 fActiveStackFrame->ReleaseReference(); 1111 } 1112 1113 fActiveStackFrame = frame; 1114 1115 if (fActiveStackFrame != NULL) { 1116 fActiveStackFrame->AcquireReference(); 1117 1118 AutoLocker< ::Team> locker(fTeam); 1119 fActiveStackFrame->AddListener(this); 1120 locker.Unlock(); 1121 1122 fActiveSourceObject = ACTIVE_SOURCE_STACK_FRAME; 1123 1124 _SetActiveFunction(fActiveStackFrame->Function()); 1125 } 1126 1127 _UpdateCpuState(); 1128 1129 fStackTraceView->SetStackFrame(fActiveStackFrame); 1130 if (fActiveStackFrame != NULL) 1131 fVariablesView->SetStackFrame(fActiveThread, fActiveStackFrame); 1132 else 1133 fVariablesView->SetStackFrame(NULL, NULL); 1134 fSourceView->SetStackFrame(fActiveStackFrame); 1135 } 1136 1137 1138 void 1139 TeamWindow::_SetActiveBreakpoint(UserBreakpoint* breakpoint) 1140 { 1141 if (breakpoint == fActiveBreakpoint) 1142 return; 1143 1144 if (fActiveBreakpoint != NULL) 1145 fActiveBreakpoint->ReleaseReference(); 1146 1147 fActiveBreakpoint = breakpoint; 1148 1149 if (fActiveBreakpoint != NULL) { 1150 fActiveBreakpoint->AcquireReference(); 1151 1152 // get the breakpoint's function (more exactly: some function instance) 1153 AutoLocker< ::Team> locker(fTeam); 1154 1155 Function* function = fTeam->FunctionByID( 1156 breakpoint->Location().GetFunctionID()); 1157 FunctionInstance* functionInstance = function != NULL 1158 ? function->FirstInstance() : NULL; 1159 BReference<FunctionInstance> functionInstanceReference( 1160 functionInstance); 1161 1162 locker.Unlock(); 1163 1164 fActiveSourceObject = ACTIVE_SOURCE_BREAKPOINT; 1165 1166 _SetActiveFunction(functionInstance); 1167 1168 // scroll to the breakpoint's source code line number (it is not done 1169 // automatically, if the active function remains the same) 1170 _ScrollToActiveFunction(); 1171 } 1172 } 1173 1174 1175 void 1176 TeamWindow::_SetActiveFunction(FunctionInstance* functionInstance) 1177 { 1178 if (functionInstance == fActiveFunction) 1179 return; 1180 1181 AutoLocker< ::Team> locker(fTeam); 1182 1183 if (fActiveFunction != NULL) { 1184 fActiveFunction->GetFunction()->RemoveListener(this); 1185 fActiveFunction->ReleaseReference(); 1186 } 1187 1188 // to avoid listener feedback problems, first unset the active function and 1189 // set the new image, if any 1190 locker.Unlock(); 1191 1192 fActiveFunction = NULL; 1193 1194 if (functionInstance != NULL) 1195 _SetActiveImage(fTeam->ImageByAddress(functionInstance->Address())); 1196 1197 fActiveFunction = functionInstance; 1198 1199 locker.Lock(); 1200 1201 SourceCode* sourceCode = NULL; 1202 BReference<SourceCode> sourceCodeReference; 1203 1204 if (fActiveFunction != NULL) { 1205 fActiveFunction->AcquireReference(); 1206 fActiveFunction->GetFunction()->AddListener(this); 1207 1208 Function* function = fActiveFunction->GetFunction(); 1209 sourceCode = function->GetSourceCode(); 1210 if (sourceCode == NULL) 1211 sourceCode = fActiveFunction->GetSourceCode(); 1212 sourceCodeReference.SetTo(sourceCode); 1213 1214 // If the source code is not loaded yet, request it. 1215 if (function->SourceCodeState() == FUNCTION_SOURCE_NOT_LOADED) 1216 fListener->FunctionSourceCodeRequested(fActiveFunction); 1217 } 1218 1219 locker.Unlock(); 1220 1221 _SetActiveSourceCode(sourceCode); 1222 1223 fImageFunctionsView->SetFunction(fActiveFunction); 1224 1225 locker.Lock(); 1226 1227 // look if our current stack trace has a frame matching the selected 1228 // function. If so, set it to match. 1229 StackFrame* matchingFrame = NULL; 1230 BReference<StackFrame> frameRef; 1231 1232 if (fActiveStackTrace != NULL) { 1233 for (int32 i = 0; i < fActiveStackTrace->CountFrames(); i++) { 1234 StackFrame* frame = fActiveStackTrace->FrameAt(i); 1235 if (frame->Function() == fActiveFunction) { 1236 matchingFrame = frame; 1237 frameRef.SetTo(frame); 1238 break; 1239 } 1240 } 1241 } 1242 1243 locker.Unlock(); 1244 1245 if (matchingFrame != NULL) 1246 _SetActiveStackFrame(matchingFrame); 1247 } 1248 1249 1250 void 1251 TeamWindow::_SetActiveSourceCode(SourceCode* sourceCode) 1252 { 1253 if (sourceCode == fActiveSourceCode) { 1254 _ScrollToActiveFunction(); 1255 return; 1256 } 1257 1258 if (fActiveSourceCode != NULL) 1259 fActiveSourceCode->ReleaseReference(); 1260 1261 fActiveSourceCode = sourceCode; 1262 1263 if (fActiveSourceCode != NULL) 1264 fActiveSourceCode->AcquireReference(); 1265 1266 fSourceView->SetSourceCode(fActiveSourceCode); 1267 1268 _UpdateSourcePathState(); 1269 _ScrollToActiveFunction(); 1270 } 1271 1272 void 1273 TeamWindow::_UpdateCpuState() 1274 { 1275 // get the CPU state 1276 CpuState* cpuState = NULL; 1277 BReference<CpuState> cpuStateReference; 1278 // hold a reference until the register view has one 1279 1280 if (fActiveThread != NULL) { 1281 // Get the CPU state from the active stack frame or the thread directly. 1282 if (fActiveStackFrame == NULL) { 1283 AutoLocker< ::Team> locker(fTeam); 1284 cpuState = fActiveThread->GetCpuState(); 1285 cpuStateReference.SetTo(cpuState); 1286 locker.Unlock(); 1287 } else 1288 cpuState = fActiveStackFrame->GetCpuState(); 1289 } 1290 1291 fRegistersView->SetCpuState(cpuState); 1292 } 1293 1294 1295 void 1296 TeamWindow::_UpdateRunButtons() 1297 { 1298 uint32 threadState = fActiveThread != NULL 1299 ? fActiveThread->State() : THREAD_STATE_UNKNOWN; 1300 1301 switch (threadState) { 1302 case THREAD_STATE_UNKNOWN: 1303 fRunButton->SetEnabled(false); 1304 fStepOverButton->SetEnabled(false); 1305 fStepIntoButton->SetEnabled(false); 1306 fStepOutButton->SetEnabled(false); 1307 break; 1308 case THREAD_STATE_RUNNING: 1309 if (fTraceUpdateRunner == NULL) { 1310 fRunButton->SetLabel("Debug"); 1311 fRunButton->SetMessage(new BMessage(MSG_THREAD_STOP)); 1312 fRunButton->SetEnabled(true); 1313 fStepOverButton->SetEnabled(false); 1314 fStepIntoButton->SetEnabled(false); 1315 fStepOutButton->SetEnabled(false); 1316 } 1317 break; 1318 case THREAD_STATE_STOPPED: 1319 fRunButton->SetLabel("Run"); 1320 fRunButton->SetMessage(new BMessage(MSG_THREAD_RUN)); 1321 fRunButton->SetEnabled(true); 1322 fStepOverButton->SetEnabled(true); 1323 fStepIntoButton->SetEnabled(true); 1324 fStepOutButton->SetEnabled(true); 1325 break; 1326 } 1327 } 1328 1329 1330 void 1331 TeamWindow::_UpdateSourcePathState() 1332 { 1333 LocatableFile* sourceFile = NULL; 1334 BString sourceText = "Source file unavailable."; 1335 BString truncatedText; 1336 1337 if (fActiveSourceCode != NULL) { 1338 sourceFile = fActiveFunction->GetFunctionDebugInfo()->SourceFile(); 1339 1340 if (sourceFile != NULL && !sourceFile->GetLocatedPath(sourceText)) 1341 sourceFile->GetPath(sourceText); 1342 1343 if (fActiveFunction->GetFunction()->SourceCodeState() 1344 != FUNCTION_SOURCE_NOT_LOADED 1345 && fActiveSourceCode->GetSourceFile() == NULL 1346 && sourceFile != NULL) { 1347 sourceText.Prepend("Click to locate source file '"); 1348 sourceText += "'"; 1349 truncatedText = sourceText; 1350 fSourcePathView->TruncateString(&truncatedText, B_TRUNCATE_MIDDLE, 1351 fSourcePathView->Bounds().Width()); 1352 } else if (sourceFile != NULL) 1353 sourceText.Prepend("File: "); 1354 } 1355 1356 if (!truncatedText.IsEmpty() && truncatedText != sourceText) { 1357 fSourcePathView->SetToolTip(sourceText); 1358 fSourcePathView->SetText(truncatedText); 1359 } else 1360 fSourcePathView->SetText(sourceText); 1361 } 1362 1363 1364 void 1365 TeamWindow::_ScrollToActiveFunction() 1366 { 1367 // Scroll to the active function, if it has been selected manually. 1368 if (fActiveFunction == NULL || fActiveSourceCode == NULL) 1369 return; 1370 1371 switch (fActiveSourceObject) { 1372 case ACTIVE_SOURCE_FUNCTION: 1373 fSourceView->ScrollToAddress(fActiveFunction->Address()); 1374 break; 1375 case ACTIVE_SOURCE_BREAKPOINT: 1376 { 1377 if (fActiveBreakpoint == NULL) 1378 break; 1379 1380 const UserBreakpointLocation& location 1381 = fActiveBreakpoint->Location(); 1382 int32 line = location.GetSourceLocation().Line(); 1383 1384 if (location.SourceFile() != NULL && line >= 0 1385 && fActiveSourceCode->GetSourceFile() 1386 == location.SourceFile()) { 1387 fSourceView->ScrollToLine(line); 1388 } else { 1389 fSourceView->ScrollToAddress( 1390 fActiveFunction->Address() 1391 + location.RelativeAddress()); 1392 } 1393 break; 1394 } 1395 case ACTIVE_SOURCE_NONE: 1396 case ACTIVE_SOURCE_STACK_FRAME: 1397 break; 1398 } 1399 } 1400 1401 1402 void 1403 TeamWindow::_HandleThreadStateChanged(thread_id threadID) 1404 { 1405 AutoLocker< ::Team> locker(fTeam); 1406 1407 ::Thread* thread = fTeam->ThreadByID(threadID); 1408 if (thread == NULL) 1409 return; 1410 1411 // If the thread has been stopped and we don't have an active thread yet 1412 // (or it isn't stopped), switch to this thread. Otherwise ignore the event. 1413 if (thread->State() == THREAD_STATE_STOPPED 1414 && (fActiveThread == NULL 1415 || (thread != fActiveThread 1416 && fActiveThread->State() != THREAD_STATE_STOPPED))) { 1417 _SetActiveThread(thread); 1418 } else if (thread != fActiveThread) { 1419 // otherwise ignore the event, if the thread is not the active one 1420 return; 1421 } 1422 1423 // Switch to the threads tab view when the thread has stopped. 1424 if (thread->State() == THREAD_STATE_STOPPED) { 1425 fTabView->Select(MAIN_TAB_INDEX_THREADS); 1426 1427 // if we hit a breakpoint or exception, raise the window to the 1428 // foreground, since if this occurs while e.g. debugging a GUI 1429 // app, it might not be immediately obvious that such an event 1430 // occurred as the app may simply appear to hang. 1431 Activate(); 1432 } 1433 1434 _UpdateRunButtons(); 1435 } 1436 1437 1438 void 1439 TeamWindow::_HandleCpuStateChanged(thread_id threadID) 1440 { 1441 // We're only interested in the currently selected thread 1442 if (fActiveThread == NULL || threadID != fActiveThread->ID()) 1443 return; 1444 1445 _UpdateCpuState(); 1446 } 1447 1448 1449 void 1450 TeamWindow::_HandleStackTraceChanged(thread_id threadID) 1451 { 1452 // We're only interested in the currently selected thread 1453 if (fActiveThread == NULL || threadID != fActiveThread->ID()) 1454 return; 1455 1456 AutoLocker< ::Team> locker(fTeam); 1457 1458 StackTrace* stackTrace = fActiveThread != NULL 1459 ? fActiveThread->GetStackTrace() : NULL; 1460 BReference<StackTrace> stackTraceReference(stackTrace); 1461 // hold a reference until the register view has one 1462 1463 locker.Unlock(); 1464 1465 if (stackTrace == NULL) { 1466 if (fTraceUpdateRunner != NULL) 1467 return; 1468 1469 BMessage message(MSG_CLEAR_STACK_TRACE); 1470 fTraceUpdateRunner = new(std::nothrow) BMessageRunner(this, 1471 message, 250000, 1); 1472 if (fTraceUpdateRunner != NULL 1473 && fTraceUpdateRunner->InitCheck() == B_OK) { 1474 fStackTraceView->SetStackTraceClearPending(); 1475 fVariablesView->SetStackFrameClearPending(); 1476 return; 1477 } 1478 } 1479 1480 _SetActiveStackTrace(stackTrace); 1481 } 1482 1483 1484 void 1485 TeamWindow::_HandleImageDebugInfoChanged(image_id imageID) 1486 { 1487 TRACE_GUI("TeamWindow::_HandleImageDebugInfoChanged(%" B_PRId32 ")\n", 1488 imageID); 1489 1490 // We're only interested in the currently selected thread 1491 if (fActiveImage == NULL || imageID != fActiveImage->ID()) 1492 return; 1493 1494 AutoLocker< ::Team> locker(fTeam); 1495 1496 ImageDebugInfo* imageDebugInfo = fActiveImage != NULL 1497 ? fActiveImage->GetImageDebugInfo() : NULL; 1498 1499 TRACE_GUI(" image debug info: %p\n", imageDebugInfo); 1500 1501 BReference<ImageDebugInfo> imageDebugInfoReference(imageDebugInfo); 1502 // hold a reference until we've set it 1503 1504 locker.Unlock(); 1505 1506 fImageFunctionsView->SetImageDebugInfo(imageDebugInfo); 1507 } 1508 1509 1510 void 1511 TeamWindow::_HandleSourceCodeChanged() 1512 { 1513 // If we don't have an active function anymore, the message is obsolete. 1514 if (fActiveFunction == NULL) 1515 return; 1516 1517 // get a reference to the source code 1518 AutoLocker< ::Team> locker(fTeam); 1519 1520 SourceCode* sourceCode = NULL; 1521 if (fActiveFunction->GetFunction()->SourceCodeState() 1522 == FUNCTION_SOURCE_LOADED) { 1523 sourceCode = fActiveFunction->GetFunction()->GetSourceCode(); 1524 } else 1525 sourceCode = fActiveFunction->GetSourceCode(); 1526 1527 BReference<SourceCode> sourceCodeReference(sourceCode); 1528 1529 locker.Unlock(); 1530 1531 _SetActiveSourceCode(sourceCode); 1532 } 1533 1534 1535 void 1536 TeamWindow::_HandleUserBreakpointChanged(UserBreakpoint* breakpoint) 1537 { 1538 fSourceView->UserBreakpointChanged(breakpoint); 1539 fBreakpointsView->UserBreakpointChanged(breakpoint); 1540 } 1541 1542 1543 void 1544 TeamWindow::_HandleWatchpointChanged(Watchpoint* watchpoint) 1545 { 1546 fBreakpointsView->WatchpointChanged(watchpoint); 1547 } 1548 1549 1550 status_t 1551 TeamWindow::_RetrieveMatchingSourceWorker(void* arg) 1552 { 1553 TeamWindow* window = (TeamWindow*)arg; 1554 1555 BStringList* entries = new(std::nothrow) BStringList(); 1556 if (entries == NULL) 1557 return B_NO_MEMORY; 1558 ObjectDeleter<BStringList> stringListDeleter(entries); 1559 1560 if (!window->Lock()) 1561 return B_BAD_VALUE; 1562 1563 BString path; 1564 window->fActiveFunction->GetFunctionDebugInfo()->SourceFile() 1565 ->GetPath(path); 1566 window->Unlock(); 1567 1568 status_t error = window->_RetrieveMatchingSourceEntries(path, entries); 1569 if (error != B_OK) 1570 return error; 1571 1572 entries->Sort(); 1573 BMessenger messenger(window); 1574 if (messenger.IsValid() && messenger.LockTarget()) { 1575 if (window->fActiveSourceWorker == find_thread(NULL)) { 1576 BMessage message(MSG_SOURCE_ENTRY_QUERY_COMPLETE); 1577 message.AddPointer("entries", entries); 1578 if (messenger.SendMessage(&message) == B_OK) 1579 stringListDeleter.Detach(); 1580 } 1581 window->Unlock(); 1582 } 1583 1584 return B_OK; 1585 } 1586 1587 1588 void 1589 TeamWindow::_HandleResolveMissingSourceFile(entry_ref& locatedPath) 1590 { 1591 if (fActiveFunction != NULL) { 1592 LocatableFile* sourceFile = fActiveFunction->GetFunctionDebugInfo() 1593 ->SourceFile(); 1594 if (sourceFile != NULL) { 1595 BString sourcePath; 1596 sourceFile->GetPath(sourcePath); 1597 BString sourceFileName(sourcePath); 1598 int32 index = sourcePath.FindLast('/'); 1599 if (index >= 0) 1600 sourceFileName.Remove(0, index + 1); 1601 1602 BPath targetFilePath(&locatedPath); 1603 if (targetFilePath.InitCheck() != B_OK) 1604 return; 1605 1606 if (strcmp(sourceFileName.String(), targetFilePath.Leaf()) != 0) { 1607 BString message; 1608 message.SetToFormat("The names of source file '%s' and located" 1609 " file '%s' differ. Use file anyway?", 1610 sourceFileName.String(), targetFilePath.Leaf()); 1611 BAlert* alert = new(std::nothrow) BAlert( 1612 "Source path mismatch", message.String(), "Cancel", "Use"); 1613 if (alert == NULL) 1614 return; 1615 1616 int32 choice = alert->Go(); 1617 if (choice <= 0) 1618 return; 1619 } 1620 fListener->SourceEntryLocateRequested(sourcePath, 1621 targetFilePath.Path()); 1622 fListener->FunctionSourceCodeRequested(fActiveFunction); 1623 } 1624 } 1625 } 1626 1627 1628 void 1629 TeamWindow::_HandleLocateSourceRequest(BStringList* entries) 1630 { 1631 if (fActiveFunction == NULL) 1632 return; 1633 else if (fActiveFunction->GetFunctionDebugInfo()->SourceFile() == NULL) 1634 return; 1635 else if (fActiveSourceCode == NULL) 1636 return; 1637 else if (fActiveSourceCode->GetSourceFile() != NULL) 1638 return; 1639 else if (fActiveFunction->GetFunction()->SourceCodeState() 1640 == FUNCTION_SOURCE_NOT_LOADED) { 1641 return; 1642 } 1643 1644 if (entries == NULL) { 1645 if (fActiveSourceWorker < 0) { 1646 fActiveSourceWorker = spawn_thread(&_RetrieveMatchingSourceWorker, 1647 "source file query worker", B_NORMAL_PRIORITY, this); 1648 if (fActiveSourceWorker > 0) 1649 resume_thread(fActiveSourceWorker); 1650 } 1651 return; 1652 } 1653 1654 int32 count = entries->CountStrings(); 1655 if (count > 0) { 1656 BPopUpMenu* menu = new(std::nothrow) BPopUpMenu(""); 1657 if (menu == NULL) 1658 return; 1659 1660 BPrivate::ObjectDeleter<BPopUpMenu> menuDeleter(menu); 1661 BMenuItem* item = NULL; 1662 for (int32 i = 0; i < count; i++) { 1663 item = new(std::nothrow) BMenuItem(entries->StringAt(i).String(), 1664 NULL); 1665 if (item == NULL || !menu->AddItem(item)) { 1666 delete item; 1667 return; 1668 } 1669 } 1670 1671 menu->AddSeparatorItem(); 1672 BMenuItem* manualItem = new(std::nothrow) BMenuItem( 1673 "Locate manually" B_UTF8_ELLIPSIS, NULL); 1674 if (manualItem == NULL || !menu->AddItem(manualItem)) { 1675 delete manualItem; 1676 return; 1677 } 1678 1679 BPoint point; 1680 fSourcePathView->GetMouse(&point, NULL, false); 1681 fSourcePathView->ConvertToScreen(&point); 1682 item = menu->Go(point, false, true); 1683 if (item == NULL) 1684 return; 1685 else if (item != manualItem) { 1686 // if the user picks to locate the entry manually, 1687 // then fall through to the usual file panel logic 1688 // as if we'd found no matches at all. 1689 entry_ref ref; 1690 if (get_ref_for_path(item->Label(), &ref) == B_OK) { 1691 _HandleResolveMissingSourceFile(ref); 1692 return; 1693 } 1694 } 1695 } 1696 1697 try { 1698 if (fFilePanel == NULL) { 1699 fFilePanel = new BFilePanel(B_OPEN_PANEL, 1700 new BMessenger(this)); 1701 } 1702 fFilePanel->Show(); 1703 } catch (...) { 1704 delete fFilePanel; 1705 fFilePanel = NULL; 1706 } 1707 } 1708 1709 1710 status_t 1711 TeamWindow::_RetrieveMatchingSourceEntries(const BString& path, 1712 BStringList* _entries) 1713 { 1714 BPath filePath(path); 1715 status_t error = filePath.InitCheck(); 1716 if (error != B_OK) 1717 return error; 1718 1719 _entries->MakeEmpty(); 1720 1721 BQuery query; 1722 BString predicate; 1723 query.PushAttr("name"); 1724 query.PushString(filePath.Leaf()); 1725 query.PushOp(B_EQ); 1726 1727 error = query.GetPredicate(&predicate); 1728 if (error != B_OK) 1729 return error; 1730 1731 BVolumeRoster roster; 1732 BVolume volume; 1733 while (roster.GetNextVolume(&volume) == B_OK) { 1734 if (!volume.KnowsQuery()) 1735 continue; 1736 1737 if (query.SetVolume(&volume) != B_OK) 1738 continue; 1739 1740 error = query.SetPredicate(predicate.String()); 1741 if (error != B_OK) 1742 continue; 1743 1744 if (query.Fetch() != B_OK) 1745 continue; 1746 1747 entry_ref ref; 1748 while (query.GetNextRef(&ref) == B_OK) { 1749 filePath.SetTo(&ref); 1750 _entries->Add(filePath.Path()); 1751 } 1752 1753 query.Clear(); 1754 } 1755 1756 return B_OK; 1757 } 1758 1759 1760 status_t 1761 TeamWindow::_SaveInspectorSettings(const BMessage* settings) 1762 { 1763 if (fUiSettings.AddSettings("inspectorWindow", *settings) != B_OK) 1764 return B_NO_MEMORY; 1765 1766 return B_OK; 1767 } 1768