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