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