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