1 /* 2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2010-2012, 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 <Button.h> 13 #include <FilePanel.h> 14 #include <LayoutBuilder.h> 15 #include <Menu.h> 16 #include <MenuBar.h> 17 #include <MenuItem.h> 18 #include <Message.h> 19 #include <MessageFilter.h> 20 #include <Path.h> 21 #include <StringView.h> 22 #include <TabView.h> 23 #include <ScrollView.h> 24 #include <SplitView.h> 25 #include <TextView.h> 26 27 #include <AutoLocker.h> 28 29 #include "Breakpoint.h" 30 #include "CpuState.h" 31 #include "DisassembledCode.h" 32 #include "FileSourceCode.h" 33 #include "GuiSettingsUtils.h" 34 #include "GuiTeamUiSettings.h" 35 #include "Image.h" 36 #include "ImageDebugInfo.h" 37 #include "InspectorWindow.h" 38 #include "LocatableFile.h" 39 #include "MessageCodes.h" 40 #include "RegistersView.h" 41 #include "StackTrace.h" 42 #include "StackTraceView.h" 43 #include "Tracing.h" 44 #include "TypeComponentPath.h" 45 #include "UserInterface.h" 46 #include "Variable.h" 47 48 49 enum { 50 MAIN_TAB_INDEX_THREADS = 0, 51 MAIN_TAB_INDEX_IMAGES = 1 52 }; 53 54 55 enum { 56 MSG_LOCATE_SOURCE_IF_NEEDED = 'lsin' 57 }; 58 59 60 class PathViewMessageFilter : public BMessageFilter { 61 public: 62 PathViewMessageFilter(BMessenger teamWindow) 63 : 64 BMessageFilter(B_MOUSE_UP), 65 fTeamWindowMessenger(teamWindow) 66 { 67 } 68 69 virtual filter_result Filter(BMessage*, BHandler**) 70 { 71 fTeamWindowMessenger.SendMessage(MSG_LOCATE_SOURCE_IF_NEEDED); 72 73 return B_DISPATCH_MESSAGE; 74 } 75 76 private: 77 BMessenger fTeamWindowMessenger; 78 }; 79 80 81 // #pragma mark - TeamWindow 82 83 84 TeamWindow::TeamWindow(::Team* team, UserInterfaceListener* listener) 85 : 86 BWindow(BRect(100, 100, 899, 699), "Team", B_TITLED_WINDOW, 87 B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS), 88 fTeam(team), 89 fActiveThread(NULL), 90 fActiveImage(NULL), 91 fActiveStackTrace(NULL), 92 fActiveStackFrame(NULL), 93 fActiveBreakpoint(NULL), 94 fActiveFunction(NULL), 95 fActiveSourceCode(NULL), 96 fActiveSourceObject(ACTIVE_SOURCE_NONE), 97 fListener(listener), 98 fTabView(NULL), 99 fLocalsTabView(NULL), 100 fThreadListView(NULL), 101 fImageListView(NULL), 102 fImageFunctionsView(NULL), 103 fBreakpointsView(NULL), 104 fVariablesView(NULL), 105 fRegistersView(NULL), 106 fStackTraceView(NULL), 107 fSourceView(NULL), 108 fRunButton(NULL), 109 fStepOverButton(NULL), 110 fStepIntoButton(NULL), 111 fStepOutButton(NULL), 112 fInspectorWindow(NULL), 113 fSourceLocatePanel(NULL) 114 { 115 fTeam->Lock(); 116 BString name = fTeam->Name(); 117 fTeam->Unlock(); 118 if (fTeam->ID() >= 0) 119 name << " (" << fTeam->ID() << ")"; 120 SetTitle(name.String()); 121 122 fTeam->AddListener(this); 123 } 124 125 126 TeamWindow::~TeamWindow() 127 { 128 if (fThreadListView != NULL) 129 fThreadListView->UnsetListener(); 130 if (fStackTraceView != NULL) 131 fStackTraceView->UnsetListener(); 132 if (fSourceView != NULL) 133 fSourceView->UnsetListener(); 134 135 fTeam->RemoveListener(this); 136 137 _SetActiveSourceCode(NULL); 138 _SetActiveFunction(NULL); 139 _SetActiveBreakpoint(NULL); 140 _SetActiveStackFrame(NULL); 141 _SetActiveStackTrace(NULL); 142 _SetActiveImage(NULL); 143 _SetActiveThread(NULL); 144 145 delete fSourceLocatePanel; 146 } 147 148 149 /*static*/ TeamWindow* 150 TeamWindow::Create(::Team* team, UserInterfaceListener* listener) 151 { 152 TeamWindow* self = new TeamWindow(team, listener); 153 154 try { 155 self->_Init(); 156 } catch (...) { 157 delete self; 158 throw; 159 } 160 161 return self; 162 } 163 164 165 void 166 TeamWindow::DispatchMessage(BMessage* message, BHandler* handler) 167 { 168 // Handle function key shortcuts for stepping 169 switch (message->what) { 170 case B_KEY_DOWN: 171 if (fActiveThread != NULL) { 172 int32 key; 173 uint32 modifiers; 174 if (message->FindInt32("key", &key) == B_OK 175 && message->FindInt32("modifiers", (int32*)&modifiers) 176 == B_OK) { 177 switch (key) { 178 case B_F5_KEY: 179 fListener->ThreadActionRequested( 180 fActiveThread->ID(), MSG_THREAD_RUN); 181 break; 182 case B_F10_KEY: 183 fListener->ThreadActionRequested( 184 fActiveThread->ID(), MSG_THREAD_STEP_OVER); 185 break; 186 case B_F11_KEY: 187 if ((modifiers & B_SHIFT_KEY) != 0) { 188 fListener->ThreadActionRequested( 189 fActiveThread->ID(), MSG_THREAD_STEP_OUT); 190 } else { 191 fListener->ThreadActionRequested( 192 fActiveThread->ID(), MSG_THREAD_STEP_INTO); 193 } 194 break; 195 default: 196 break; 197 } 198 } 199 } 200 break; 201 202 case B_COPY: 203 case B_SELECT_ALL: 204 BView* focusView = CurrentFocus(); 205 if (focusView != NULL) 206 focusView->MessageReceived(message); 207 break; 208 } 209 BWindow::DispatchMessage(message, handler); 210 } 211 212 213 void 214 TeamWindow::MessageReceived(BMessage* message) 215 { 216 switch (message->what) { 217 case MSG_SHOW_INSPECTOR_WINDOW: 218 { 219 if (fInspectorWindow) { 220 fInspectorWindow->Activate(true); 221 } else { 222 try { 223 fInspectorWindow = InspectorWindow::Create(fTeam, 224 fListener, this); 225 if (fInspectorWindow != NULL) { 226 BMessage settings; 227 fInspectorWindow->LoadSettings(fUiSettings); 228 fInspectorWindow->Show(); 229 } 230 } catch (...) { 231 // TODO: notify user 232 } 233 } 234 235 target_addr_t address; 236 if (message->FindUInt64("address", &address) == B_OK) { 237 BMessage addressMessage(MSG_INSPECT_ADDRESS); 238 addressMessage.AddUInt64("address", address); 239 fInspectorWindow->PostMessage(&addressMessage); 240 } 241 break; 242 } 243 case MSG_INSPECTOR_WINDOW_CLOSED: 244 { 245 _SaveInspectorSettings(CurrentMessage()); 246 fInspectorWindow = NULL; 247 break; 248 249 } 250 case B_REFS_RECEIVED: 251 { 252 entry_ref locatedPath; 253 message->FindRef("refs", &locatedPath); 254 _HandleResolveMissingSourceFile(locatedPath); 255 break; 256 } 257 case MSG_LOCATE_SOURCE_IF_NEEDED: 258 { 259 if (fActiveFunction != NULL 260 && fActiveFunction->GetFunctionDebugInfo() 261 ->SourceFile() != NULL && fActiveSourceCode != NULL 262 && fActiveSourceCode->GetSourceFile() == NULL) { 263 try { 264 if (fSourceLocatePanel == NULL) { 265 fSourceLocatePanel = new BFilePanel(B_OPEN_PANEL, 266 new BMessenger(this)); 267 } 268 fSourceLocatePanel->Show(); 269 } catch (...) { 270 delete fSourceLocatePanel; 271 fSourceLocatePanel = NULL; 272 } 273 } 274 break; 275 } 276 case MSG_THREAD_RUN: 277 case MSG_THREAD_STOP: 278 case MSG_THREAD_STEP_OVER: 279 case MSG_THREAD_STEP_INTO: 280 case MSG_THREAD_STEP_OUT: 281 if (fActiveThread != NULL) { 282 fListener->ThreadActionRequested(fActiveThread->ID(), 283 message->what); 284 } 285 break; 286 287 case MSG_THREAD_STATE_CHANGED: 288 { 289 int32 threadID; 290 if (message->FindInt32("thread", &threadID) != B_OK) 291 break; 292 293 _HandleThreadStateChanged(threadID); 294 break; 295 } 296 case MSG_THREAD_CPU_STATE_CHANGED: 297 { 298 int32 threadID; 299 if (message->FindInt32("thread", &threadID) != B_OK) 300 break; 301 302 _HandleCpuStateChanged(threadID); 303 break; 304 } 305 306 case MSG_THREAD_STACK_TRACE_CHANGED: 307 { 308 int32 threadID; 309 if (message->FindInt32("thread", &threadID) != B_OK) 310 break; 311 312 _HandleStackTraceChanged(threadID); 313 break; 314 } 315 316 case MSG_IMAGE_DEBUG_INFO_CHANGED: 317 { 318 int32 imageID; 319 if (message->FindInt32("image", &imageID) != B_OK) 320 break; 321 322 _HandleImageDebugInfoChanged(imageID); 323 break; 324 } 325 326 case MSG_USER_BREAKPOINT_CHANGED: 327 { 328 UserBreakpoint* breakpoint; 329 if (message->FindPointer("breakpoint", (void**)&breakpoint) != B_OK) 330 break; 331 BReference<UserBreakpoint> breakpointReference(breakpoint, true); 332 333 _HandleUserBreakpointChanged(breakpoint); 334 break; 335 } 336 337 case MSG_FUNCTION_SOURCE_CODE_CHANGED: 338 { 339 _HandleSourceCodeChanged(); 340 break; 341 } 342 343 default: 344 BWindow::MessageReceived(message); 345 break; 346 } 347 } 348 349 350 bool 351 TeamWindow::QuitRequested() 352 { 353 fListener->UserInterfaceQuitRequested(); 354 355 return false; 356 } 357 358 359 status_t 360 TeamWindow::LoadSettings(const GuiTeamUiSettings* settings) 361 { 362 AutoLocker<BWindow> lock(this); 363 if (!lock.IsLocked()) 364 return B_ERROR; 365 366 BMessage teamWindowSettings; 367 // no settings stored yet 368 if (settings->Settings("teamWindow", teamWindowSettings) != B_OK) 369 return B_OK; 370 371 BRect frame; 372 if (teamWindowSettings.FindRect("frame", &frame) == B_OK) { 373 ResizeTo(frame.Width(), frame.Height()); 374 MoveTo(frame.left, frame.top); 375 } 376 377 BMessage archive; 378 if (teamWindowSettings.FindMessage("sourceSplit", &archive) == B_OK) 379 GuiSettingsUtils::UnarchiveSplitView(archive, fSourceSplitView); 380 381 if (teamWindowSettings.FindMessage("functionSplit", &archive) == B_OK) 382 GuiSettingsUtils::UnarchiveSplitView(archive, fFunctionSplitView); 383 384 if (teamWindowSettings.FindMessage("imageSplit", &archive) == B_OK) 385 GuiSettingsUtils::UnarchiveSplitView(archive, fImageSplitView); 386 387 if (teamWindowSettings.FindMessage("threadSplit", &archive) == B_OK) 388 GuiSettingsUtils::UnarchiveSplitView(archive, fThreadSplitView); 389 390 if (teamWindowSettings.FindMessage("imageListView", &archive) == B_OK) 391 fImageListView->LoadSettings(archive); 392 393 if (teamWindowSettings.FindMessage("imageFunctionsView", &archive) == B_OK) 394 fImageFunctionsView->LoadSettings(archive); 395 396 if (teamWindowSettings.FindMessage("threadListView", &archive) == B_OK) 397 fThreadListView->LoadSettings(archive); 398 399 if (teamWindowSettings.FindMessage("variablesView", &archive) == B_OK) 400 fVariablesView->LoadSettings(archive); 401 402 if (teamWindowSettings.FindMessage("registersView", &archive) == B_OK) 403 fRegistersView->LoadSettings(archive); 404 405 if (teamWindowSettings.FindMessage("stackTraceView", &archive) == B_OK) 406 fStackTraceView->LoadSettings(archive); 407 408 if (teamWindowSettings.FindMessage("breakpointsView", &archive) == B_OK) 409 fBreakpointsView->LoadSettings(archive); 410 411 fUiSettings = *settings; 412 413 return B_OK; 414 } 415 416 417 status_t 418 TeamWindow::SaveSettings(GuiTeamUiSettings* settings) 419 { 420 AutoLocker<BWindow> lock(this); 421 if (!lock.IsLocked()) 422 return B_ERROR; 423 424 BMessage inspectorSettings; 425 if (fUiSettings.Settings("inspectorWindow", inspectorSettings) == B_OK) { 426 if (!settings->AddSettings("inspectorWindow", inspectorSettings)) 427 return B_NO_MEMORY; 428 } 429 430 BMessage archive; 431 BMessage teamWindowSettings; 432 if (teamWindowSettings.AddRect("frame", Frame()) != B_OK) 433 return B_NO_MEMORY; 434 435 if (GuiSettingsUtils::ArchiveSplitView(archive, fSourceSplitView) != B_OK) 436 return B_NO_MEMORY; 437 if (teamWindowSettings.AddMessage("sourceSplit", &archive) != B_OK) 438 return B_NO_MEMORY; 439 440 if (GuiSettingsUtils::ArchiveSplitView(archive, fFunctionSplitView) != B_OK) 441 return B_NO_MEMORY; 442 if (teamWindowSettings.AddMessage("functionSplit", &archive) != B_OK) 443 return B_NO_MEMORY; 444 445 if (GuiSettingsUtils::ArchiveSplitView(archive, fImageSplitView) != B_OK) 446 return B_NO_MEMORY; 447 if (teamWindowSettings.AddMessage("imageSplit", &archive)) 448 return B_NO_MEMORY; 449 450 if (GuiSettingsUtils::ArchiveSplitView(archive, fThreadSplitView) != B_OK) 451 return B_NO_MEMORY; 452 if (teamWindowSettings.AddMessage("threadSplit", &archive)) 453 return B_NO_MEMORY; 454 455 if (fImageListView->SaveSettings(archive) != B_OK) 456 return B_NO_MEMORY; 457 if (teamWindowSettings.AddMessage("imageListView", &archive)) 458 return B_NO_MEMORY; 459 460 if (fImageFunctionsView->SaveSettings(archive) != B_OK) 461 return B_NO_MEMORY; 462 if (teamWindowSettings.AddMessage("imageFunctionsView", &archive)) 463 return B_NO_MEMORY; 464 465 if (fThreadListView->SaveSettings(archive) != B_OK) 466 return B_NO_MEMORY; 467 if (teamWindowSettings.AddMessage("threadListView", &archive)) 468 return B_NO_MEMORY; 469 470 if (fVariablesView->SaveSettings(archive) != B_OK) 471 return B_NO_MEMORY; 472 if (teamWindowSettings.AddMessage("variablesView", &archive)) 473 return B_NO_MEMORY; 474 475 if (fRegistersView->SaveSettings(archive) != B_OK) 476 return B_NO_MEMORY; 477 if (teamWindowSettings.AddMessage("registersView", &archive)) 478 return B_NO_MEMORY; 479 480 if (fStackTraceView->SaveSettings(archive) != B_OK) 481 return B_NO_MEMORY; 482 if (teamWindowSettings.AddMessage("stackTraceView", &archive)) 483 return B_NO_MEMORY; 484 485 if (fBreakpointsView->SaveSettings(archive) != B_OK) 486 return B_NO_MEMORY; 487 if (teamWindowSettings.AddMessage("breakpointsView", &archive)) 488 return B_NO_MEMORY; 489 490 if (!settings->AddSettings("teamWindow", teamWindowSettings)) 491 return B_NO_MEMORY; 492 493 return B_OK; 494 } 495 496 497 void 498 TeamWindow::ThreadSelectionChanged(::Thread* thread) 499 { 500 _SetActiveThread(thread); 501 } 502 503 504 void 505 TeamWindow::ImageSelectionChanged(Image* image) 506 { 507 _SetActiveImage(image); 508 } 509 510 511 void 512 TeamWindow::StackFrameSelectionChanged(StackFrame* frame) 513 { 514 _SetActiveStackFrame(frame); 515 } 516 517 518 void 519 TeamWindow::FunctionSelectionChanged(FunctionInstance* function) 520 { 521 // If the function wasn't already active, it was just selected by the user. 522 if (function != NULL && function != fActiveFunction) 523 fActiveSourceObject = ACTIVE_SOURCE_FUNCTION; 524 525 _SetActiveFunction(function); 526 } 527 528 529 void 530 TeamWindow::BreakpointSelectionChanged(UserBreakpoint* breakpoint) 531 { 532 _SetActiveBreakpoint(breakpoint); 533 } 534 535 536 void 537 TeamWindow::SetBreakpointEnabledRequested(UserBreakpoint* breakpoint, 538 bool enabled) 539 { 540 fListener->SetBreakpointEnabledRequested(breakpoint, enabled); 541 } 542 543 544 void 545 TeamWindow::ClearBreakpointRequested(UserBreakpoint* breakpoint) 546 { 547 fListener->ClearBreakpointRequested(breakpoint); 548 } 549 550 551 void 552 TeamWindow::SetBreakpointRequested(target_addr_t address, bool enabled) 553 { 554 fListener->SetBreakpointRequested(address, enabled); 555 } 556 557 558 void 559 TeamWindow::ClearBreakpointRequested(target_addr_t address) 560 { 561 fListener->ClearBreakpointRequested(address); 562 } 563 564 565 void 566 TeamWindow::ValueNodeValueRequested(CpuState* cpuState, 567 ValueNodeContainer* container, ValueNode* valueNode) 568 { 569 fListener->ValueNodeValueRequested(cpuState, container, valueNode); 570 } 571 572 573 void 574 TeamWindow::ThreadStateChanged(const Team::ThreadEvent& event) 575 { 576 BMessage message(MSG_THREAD_STATE_CHANGED); 577 message.AddInt32("thread", event.GetThread()->ID()); 578 PostMessage(&message); 579 } 580 581 582 void 583 TeamWindow::ThreadCpuStateChanged(const Team::ThreadEvent& event) 584 { 585 BMessage message(MSG_THREAD_CPU_STATE_CHANGED); 586 message.AddInt32("thread", event.GetThread()->ID()); 587 PostMessage(&message); 588 } 589 590 591 void 592 TeamWindow::ThreadStackTraceChanged(const Team::ThreadEvent& event) 593 { 594 BMessage message(MSG_THREAD_STACK_TRACE_CHANGED); 595 message.AddInt32("thread", event.GetThread()->ID()); 596 PostMessage(&message); 597 } 598 599 600 void 601 TeamWindow::ImageDebugInfoChanged(const Team::ImageEvent& event) 602 { 603 BMessage message(MSG_IMAGE_DEBUG_INFO_CHANGED); 604 message.AddInt32("image", event.GetImage()->ID()); 605 PostMessage(&message); 606 } 607 608 609 void 610 TeamWindow::UserBreakpointChanged(const Team::UserBreakpointEvent& event) 611 { 612 BMessage message(MSG_USER_BREAKPOINT_CHANGED); 613 BReference<UserBreakpoint> breakpointReference(event.GetBreakpoint()); 614 if (message.AddPointer("breakpoint", event.GetBreakpoint()) == B_OK 615 && PostMessage(&message) == B_OK) { 616 breakpointReference.Detach(); 617 } 618 } 619 620 621 void 622 TeamWindow::FunctionSourceCodeChanged(Function* function) 623 { 624 TRACE_GUI("TeamWindow::FunctionSourceCodeChanged(%p): source: %p, " 625 "state: %d\n", function, function->GetSourceCode(), 626 function->SourceCodeState()); 627 628 PostMessage(MSG_FUNCTION_SOURCE_CODE_CHANGED); 629 } 630 631 632 void 633 TeamWindow::_Init() 634 { 635 BScrollView* sourceScrollView; 636 637 BLayoutBuilder::Group<>(this, B_VERTICAL) 638 .Add(fMenuBar = new BMenuBar("Menu")) 639 .AddSplit(B_VERTICAL, 3.0f) 640 .GetSplitView(&fFunctionSplitView) 641 .SetInsets(4.0f, 4.0f, 4.0f, 4.0f) 642 .Add(fTabView = new BTabView("tab view"), 0.4f) 643 .AddGroup(B_VERTICAL, 4.0f) 644 .AddGroup(B_HORIZONTAL, 4.0f) 645 .Add(fRunButton = new BButton("Run")) 646 .Add(fStepOverButton = new BButton("Step Over")) 647 .Add(fStepIntoButton = new BButton("Step Into")) 648 .Add(fStepOutButton = new BButton("Step Out")) 649 .AddGlue() 650 .End() 651 .Add(fSourcePathView = new BStringView( 652 "source path", 653 "Source path unavailable."), 4.0f) 654 .AddSplit(B_HORIZONTAL, 3.0f) 655 .GetSplitView(&fSourceSplitView) 656 .Add(sourceScrollView = new BScrollView("source scroll", 657 NULL, 0, true, true), 3.0f) 658 .Add(fLocalsTabView = new BTabView("locals view")) 659 .End() 660 .End() 661 .End(); 662 663 // add source view 664 sourceScrollView->SetTarget(fSourceView = SourceView::Create(fTeam, this)); 665 666 // add threads tab 667 BSplitView* threadGroup = new BSplitView(B_HORIZONTAL); 668 threadGroup->SetName("Threads"); 669 fTabView->AddTab(threadGroup); 670 BLayoutBuilder::Split<>(threadGroup) 671 .GetSplitView(&fThreadSplitView) 672 .Add(fThreadListView = ThreadListView::Create(fTeam, this)) 673 .Add(fStackTraceView = StackTraceView::Create(this)); 674 675 // add images tab 676 BSplitView* imagesGroup = new BSplitView(B_HORIZONTAL); 677 imagesGroup->SetName("Images"); 678 fTabView->AddTab(imagesGroup); 679 BLayoutBuilder::Split<>(imagesGroup) 680 .GetSplitView(&fImageSplitView) 681 .Add(fImageListView = ImageListView::Create(fTeam, this)) 682 .Add(fImageFunctionsView = ImageFunctionsView::Create(this)); 683 684 // add breakpoints tab 685 BGroupView* breakpointsGroup = new BGroupView(B_HORIZONTAL, 4.0f); 686 breakpointsGroup->SetName("Breakpoints"); 687 fTabView->AddTab(breakpointsGroup); 688 BLayoutBuilder::Group<>(breakpointsGroup) 689 .SetInsets(4.0f, 4.0f, 4.0f, 4.0f) 690 .Add(fBreakpointsView = BreakpointsView::Create(fTeam, this)); 691 692 // add local variables tab 693 BView* tab = fVariablesView = VariablesView::Create(this); 694 fLocalsTabView->AddTab(tab); 695 696 // add registers tab 697 tab = fRegistersView = RegistersView::Create(fTeam->GetArchitecture()); 698 fLocalsTabView->AddTab(tab); 699 700 fRunButton->SetMessage(new BMessage(MSG_THREAD_RUN)); 701 fStepOverButton->SetMessage(new BMessage(MSG_THREAD_STEP_OVER)); 702 fStepIntoButton->SetMessage(new BMessage(MSG_THREAD_STEP_INTO)); 703 fStepOutButton->SetMessage(new BMessage(MSG_THREAD_STEP_OUT)); 704 fRunButton->SetTarget(this); 705 fStepOverButton->SetTarget(this); 706 fStepIntoButton->SetTarget(this); 707 fStepOutButton->SetTarget(this); 708 709 fSourcePathView->SetExplicitMinSize(BSize(100.0, B_SIZE_UNSET)); 710 fSourcePathView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); 711 BMessageFilter* filter = new(std::nothrow) PathViewMessageFilter( 712 BMessenger(this)); 713 if (filter != NULL) 714 fSourcePathView->AddFilter(filter); 715 716 // add menus and menu items 717 BMenu* menu = new BMenu("File"); 718 fMenuBar->AddItem(menu); 719 BMenuItem* item = new BMenuItem("Quit", new BMessage(B_QUIT_REQUESTED), 720 'Q'); 721 menu->AddItem(item); 722 item->SetTarget(this); 723 menu = new BMenu("Edit"); 724 fMenuBar->AddItem(menu); 725 item = new BMenuItem("Copy", new BMessage(B_COPY), 'C'); 726 menu->AddItem(item); 727 item->SetTarget(this); 728 item = new BMenuItem("Select All", new BMessage(B_SELECT_ALL), 'A'); 729 menu->AddItem(item); 730 item->SetTarget(this); 731 menu = new BMenu("Tools"); 732 fMenuBar->AddItem(menu); 733 item = new BMenuItem("Inspect Memory", 734 new BMessage(MSG_SHOW_INSPECTOR_WINDOW), 'I'); 735 menu->AddItem(item); 736 item->SetTarget(this); 737 738 AutoLocker< ::Team> locker(fTeam); 739 _UpdateRunButtons(); 740 } 741 742 743 void 744 TeamWindow::_SetActiveThread(::Thread* thread) 745 { 746 if (thread == fActiveThread) 747 return; 748 749 if (fActiveThread != NULL) 750 fActiveThread->ReleaseReference(); 751 752 fActiveThread = thread; 753 754 if (fActiveThread != NULL) 755 fActiveThread->AcquireReference(); 756 757 AutoLocker< ::Team> locker(fTeam); 758 _UpdateRunButtons(); 759 760 StackTrace* stackTrace = fActiveThread != NULL 761 ? fActiveThread->GetStackTrace() : NULL; 762 BReference<StackTrace> stackTraceReference(stackTrace); 763 // hold a reference until we've set it 764 765 locker.Unlock(); 766 767 fThreadListView->SetThread(fActiveThread); 768 769 _SetActiveStackTrace(stackTrace); 770 _UpdateCpuState(); 771 } 772 773 774 void 775 TeamWindow::_SetActiveImage(Image* image) 776 { 777 if (image == fActiveImage) 778 return; 779 780 if (fActiveImage != NULL) 781 fActiveImage->ReleaseReference(); 782 783 fActiveImage = image; 784 785 AutoLocker< ::Team> locker(fTeam); 786 787 ImageDebugInfo* imageDebugInfo = NULL; 788 BReference<ImageDebugInfo> imageDebugInfoReference; 789 790 if (fActiveImage != NULL) { 791 fActiveImage->AcquireReference(); 792 793 imageDebugInfo = fActiveImage->GetImageDebugInfo(); 794 imageDebugInfoReference.SetTo(imageDebugInfo); 795 796 // If the debug info is not loaded yet, request it. 797 if (fActiveImage->ImageDebugInfoState() == IMAGE_DEBUG_INFO_NOT_LOADED) 798 fListener->ImageDebugInfoRequested(fActiveImage); 799 } 800 801 locker.Unlock(); 802 803 fImageListView->SetImage(fActiveImage); 804 fImageFunctionsView->SetImageDebugInfo(imageDebugInfo); 805 } 806 807 808 void 809 TeamWindow::_SetActiveStackTrace(StackTrace* stackTrace) 810 { 811 if (stackTrace == fActiveStackTrace) 812 return; 813 814 if (fActiveStackTrace != NULL) 815 fActiveStackTrace->ReleaseReference(); 816 817 fActiveStackTrace = stackTrace; 818 819 if (fActiveStackTrace != NULL) 820 fActiveStackTrace->AcquireReference(); 821 822 fStackTraceView->SetStackTrace(fActiveStackTrace); 823 fSourceView->SetStackTrace(fActiveStackTrace); 824 825 if (fActiveStackTrace != NULL) 826 _SetActiveStackFrame(fActiveStackTrace->FrameAt(0)); 827 } 828 829 830 void 831 TeamWindow::_SetActiveStackFrame(StackFrame* frame) 832 { 833 if (frame == fActiveStackFrame) 834 return; 835 836 if (fActiveStackFrame != NULL) { 837 AutoLocker< ::Team> locker(fTeam); 838 fActiveStackFrame->RemoveListener(this); 839 locker.Unlock(); 840 841 fActiveStackFrame->ReleaseReference(); 842 } 843 844 fActiveStackFrame = frame; 845 846 if (fActiveStackFrame != NULL) { 847 fActiveStackFrame->AcquireReference(); 848 849 AutoLocker< ::Team> locker(fTeam); 850 fActiveStackFrame->AddListener(this); 851 locker.Unlock(); 852 853 fActiveSourceObject = ACTIVE_SOURCE_STACK_FRAME; 854 855 _SetActiveFunction(fActiveStackFrame->Function()); 856 } 857 858 _UpdateCpuState(); 859 860 fStackTraceView->SetStackFrame(fActiveStackFrame); 861 if (fActiveStackFrame != NULL) 862 fVariablesView->SetStackFrame(fActiveThread, fActiveStackFrame); 863 else 864 fVariablesView->SetStackFrame(NULL, NULL); 865 fSourceView->SetStackFrame(fActiveStackFrame); 866 } 867 868 869 void 870 TeamWindow::_SetActiveBreakpoint(UserBreakpoint* breakpoint) 871 { 872 if (breakpoint == fActiveBreakpoint) 873 return; 874 875 if (fActiveBreakpoint != NULL) 876 fActiveBreakpoint->ReleaseReference(); 877 878 fActiveBreakpoint = breakpoint; 879 880 if (fActiveBreakpoint != NULL) { 881 fActiveBreakpoint->AcquireReference(); 882 883 // get the breakpoint's function (more exactly: some function instance) 884 AutoLocker< ::Team> locker(fTeam); 885 886 Function* function = fTeam->FunctionByID( 887 breakpoint->Location().GetFunctionID()); 888 FunctionInstance* functionInstance = function != NULL 889 ? function->FirstInstance() : NULL; 890 BReference<FunctionInstance> functionInstanceReference( 891 functionInstance); 892 893 locker.Unlock(); 894 895 fActiveSourceObject = ACTIVE_SOURCE_BREAKPOINT; 896 897 _SetActiveFunction(functionInstance); 898 899 // scroll to the breakpoint's source code line number (it is not done 900 // automatically, if the active function remains the same) 901 _ScrollToActiveFunction(); 902 } 903 904 fBreakpointsView->SetBreakpoint(fActiveBreakpoint); 905 } 906 907 908 void 909 TeamWindow::_SetActiveFunction(FunctionInstance* functionInstance) 910 { 911 if (functionInstance == fActiveFunction) 912 return; 913 914 AutoLocker< ::Team> locker(fTeam); 915 916 if (fActiveFunction != NULL) { 917 fActiveFunction->GetFunction()->RemoveListener(this); 918 fActiveFunction->ReleaseReference(); 919 } 920 921 // to avoid listener feedback problems, first unset the active function and 922 // set the new image, if any 923 locker.Unlock(); 924 925 fActiveFunction = NULL; 926 927 if (functionInstance != NULL) 928 _SetActiveImage(fTeam->ImageByAddress(functionInstance->Address())); 929 930 fActiveFunction = functionInstance; 931 932 locker.Lock(); 933 934 SourceCode* sourceCode = NULL; 935 BReference<SourceCode> sourceCodeReference; 936 937 if (fActiveFunction != NULL) { 938 fActiveFunction->AcquireReference(); 939 fActiveFunction->GetFunction()->AddListener(this); 940 941 Function* function = fActiveFunction->GetFunction(); 942 sourceCode = function->GetSourceCode(); 943 if (sourceCode == NULL) 944 sourceCode = fActiveFunction->GetSourceCode(); 945 sourceCodeReference.SetTo(sourceCode); 946 947 // If the source code is not loaded yet, request it. 948 if (function->SourceCodeState() == FUNCTION_SOURCE_NOT_LOADED) 949 fListener->FunctionSourceCodeRequested(fActiveFunction); 950 } 951 952 locker.Unlock(); 953 954 _SetActiveSourceCode(sourceCode); 955 956 fImageFunctionsView->SetFunction(fActiveFunction); 957 958 locker.Lock(); 959 960 // look if our current stack trace has a frame matching the selected 961 // function. If so, set it to match. 962 StackFrame* matchingFrame = NULL; 963 BReference<StackFrame> frameRef; 964 965 if (fActiveStackTrace != NULL) { 966 for (int32 i = 0; i < fActiveStackTrace->CountFrames(); i++) { 967 StackFrame* frame = fActiveStackTrace->FrameAt(i); 968 if (frame->Function() == fActiveFunction) { 969 matchingFrame = frame; 970 frameRef.SetTo(frame); 971 break; 972 } 973 } 974 } 975 976 locker.Unlock(); 977 978 if (matchingFrame != NULL) 979 _SetActiveStackFrame(matchingFrame); 980 } 981 982 983 void 984 TeamWindow::_SetActiveSourceCode(SourceCode* sourceCode) 985 { 986 if (sourceCode == fActiveSourceCode) { 987 _ScrollToActiveFunction(); 988 return; 989 } 990 991 if (fActiveSourceCode != NULL) 992 fActiveSourceCode->ReleaseReference(); 993 994 fActiveSourceCode = sourceCode; 995 996 if (fActiveSourceCode != NULL) 997 fActiveSourceCode->AcquireReference(); 998 999 fSourceView->SetSourceCode(fActiveSourceCode); 1000 1001 _UpdateSourcePathState(); 1002 _ScrollToActiveFunction(); 1003 } 1004 1005 void 1006 TeamWindow::_UpdateCpuState() 1007 { 1008 // get the CPU state 1009 CpuState* cpuState = NULL; 1010 BReference<CpuState> cpuStateReference; 1011 // hold a reference until the register view has one 1012 1013 if (fActiveThread != NULL) { 1014 // Get the CPU state from the active stack frame or the thread directly. 1015 if (fActiveStackFrame == NULL) { 1016 AutoLocker< ::Team> locker(fTeam); 1017 cpuState = fActiveThread->GetCpuState(); 1018 cpuStateReference.SetTo(cpuState); 1019 locker.Unlock(); 1020 } else 1021 cpuState = fActiveStackFrame->GetCpuState(); 1022 } 1023 1024 fRegistersView->SetCpuState(cpuState); 1025 } 1026 1027 1028 void 1029 TeamWindow::_UpdateRunButtons() 1030 { 1031 uint32 threadState = fActiveThread != NULL 1032 ? fActiveThread->State() : THREAD_STATE_UNKNOWN; 1033 1034 switch (threadState) { 1035 case THREAD_STATE_UNKNOWN: 1036 fRunButton->SetEnabled(false); 1037 fStepOverButton->SetEnabled(false); 1038 fStepIntoButton->SetEnabled(false); 1039 fStepOutButton->SetEnabled(false); 1040 break; 1041 case THREAD_STATE_RUNNING: 1042 fRunButton->SetLabel("Debug"); 1043 fRunButton->SetMessage(new BMessage(MSG_THREAD_STOP)); 1044 fRunButton->SetEnabled(true); 1045 fStepOverButton->SetEnabled(false); 1046 fStepIntoButton->SetEnabled(false); 1047 fStepOutButton->SetEnabled(false); 1048 break; 1049 case THREAD_STATE_STOPPED: 1050 fRunButton->SetLabel("Run"); 1051 fRunButton->SetMessage(new BMessage(MSG_THREAD_RUN)); 1052 fRunButton->SetEnabled(true); 1053 fStepOverButton->SetEnabled(true); 1054 fStepIntoButton->SetEnabled(true); 1055 fStepOutButton->SetEnabled(true); 1056 break; 1057 } 1058 } 1059 1060 1061 void 1062 TeamWindow::_UpdateSourcePathState() 1063 { 1064 LocatableFile* sourceFile = NULL; 1065 BString sourceText = "Source file unavailable."; 1066 BString truncatedText; 1067 1068 if (fActiveSourceCode != NULL) { 1069 sourceFile = fActiveFunction->GetFunctionDebugInfo()->SourceFile(); 1070 1071 if (sourceFile != NULL && !sourceFile->GetLocatedPath(sourceText)) 1072 sourceFile->GetPath(sourceText); 1073 1074 if (fActiveSourceCode->GetSourceFile() == NULL && sourceFile != NULL) { 1075 sourceText.Prepend("Click to locate source file '"); 1076 sourceText += "'"; 1077 truncatedText = sourceText; 1078 fSourcePathView->TruncateString(&truncatedText, B_TRUNCATE_MIDDLE, 1079 fSourcePathView->Bounds().Width()); 1080 } else if (sourceFile != NULL) { 1081 sourceText.Prepend("File: "); 1082 } 1083 } 1084 1085 if (!truncatedText.IsEmpty() && truncatedText != sourceText) { 1086 fSourcePathView->SetToolTip(sourceText); 1087 fSourcePathView->SetText(truncatedText); 1088 } else 1089 fSourcePathView->SetText(sourceText); 1090 } 1091 1092 1093 void 1094 TeamWindow::_ScrollToActiveFunction() 1095 { 1096 // Scroll to the active function, if it has been selected manually. 1097 if (fActiveFunction == NULL || fActiveSourceCode == NULL) 1098 return; 1099 1100 switch (fActiveSourceObject) { 1101 case ACTIVE_SOURCE_FUNCTION: 1102 fSourceView->ScrollToAddress(fActiveFunction->Address()); 1103 break; 1104 case ACTIVE_SOURCE_BREAKPOINT: 1105 { 1106 if (fActiveBreakpoint == NULL) 1107 break; 1108 1109 const UserBreakpointLocation& location 1110 = fActiveBreakpoint->Location(); 1111 int32 line = location.GetSourceLocation().Line(); 1112 1113 if (location.SourceFile() != NULL && line >= 0 1114 && fActiveSourceCode->GetSourceFile() 1115 == location.SourceFile()) { 1116 fSourceView->ScrollToLine(line); 1117 } else { 1118 fSourceView->ScrollToAddress( 1119 fActiveFunction->Address() 1120 + location.RelativeAddress()); 1121 } 1122 break; 1123 } 1124 case ACTIVE_SOURCE_NONE: 1125 case ACTIVE_SOURCE_STACK_FRAME: 1126 break; 1127 } 1128 } 1129 1130 1131 void 1132 TeamWindow::_HandleThreadStateChanged(thread_id threadID) 1133 { 1134 AutoLocker< ::Team> locker(fTeam); 1135 1136 ::Thread* thread = fTeam->ThreadByID(threadID); 1137 if (thread == NULL) 1138 return; 1139 1140 // If the thread has been stopped and we don't have an active thread yet 1141 // (or it isn't stopped), switch to this thread. Otherwise ignore the event. 1142 if (thread->State() == THREAD_STATE_STOPPED 1143 && (fActiveThread == NULL 1144 || (thread != fActiveThread 1145 && fActiveThread->State() != THREAD_STATE_STOPPED))) { 1146 _SetActiveThread(thread); 1147 } else if (thread != fActiveThread) { 1148 // otherwise ignore the event, if the thread is not the active one 1149 return; 1150 } 1151 1152 // Switch to the threads tab view when the thread has stopped. 1153 if (thread->State() == THREAD_STATE_STOPPED) 1154 fTabView->Select(MAIN_TAB_INDEX_THREADS); 1155 1156 _UpdateRunButtons(); 1157 } 1158 1159 1160 void 1161 TeamWindow::_HandleCpuStateChanged(thread_id threadID) 1162 { 1163 // We're only interested in the currently selected thread 1164 if (fActiveThread == NULL || threadID != fActiveThread->ID()) 1165 return; 1166 1167 _UpdateCpuState(); 1168 } 1169 1170 1171 void 1172 TeamWindow::_HandleStackTraceChanged(thread_id threadID) 1173 { 1174 // We're only interested in the currently selected thread 1175 if (fActiveThread == NULL || threadID != fActiveThread->ID()) 1176 return; 1177 1178 AutoLocker< ::Team> locker(fTeam); 1179 1180 StackTrace* stackTrace = fActiveThread != NULL 1181 ? fActiveThread->GetStackTrace() : NULL; 1182 BReference<StackTrace> stackTraceReference(stackTrace); 1183 // hold a reference until the register view has one 1184 1185 locker.Unlock(); 1186 1187 _SetActiveStackTrace(stackTrace); 1188 } 1189 1190 1191 void 1192 TeamWindow::_HandleImageDebugInfoChanged(image_id imageID) 1193 { 1194 TRACE_GUI("TeamWindow::_HandleImageDebugInfoChanged(%ld)\n", imageID); 1195 1196 // We're only interested in the currently selected thread 1197 if (fActiveImage == NULL || imageID != fActiveImage->ID()) 1198 return; 1199 1200 AutoLocker< ::Team> locker(fTeam); 1201 1202 ImageDebugInfo* imageDebugInfo = fActiveImage != NULL 1203 ? fActiveImage->GetImageDebugInfo() : NULL; 1204 1205 TRACE_GUI(" image debug info: %p\n", imageDebugInfo); 1206 1207 BReference<ImageDebugInfo> imageDebugInfoReference(imageDebugInfo); 1208 // hold a reference until we've set it 1209 1210 locker.Unlock(); 1211 1212 fImageFunctionsView->SetImageDebugInfo(imageDebugInfo); 1213 } 1214 1215 1216 void 1217 TeamWindow::_HandleSourceCodeChanged() 1218 { 1219 // If we don't have an active function anymore, the message is obsolete. 1220 if (fActiveFunction == NULL) 1221 return; 1222 1223 // get a reference to the source code 1224 AutoLocker< ::Team> locker(fTeam); 1225 1226 SourceCode* sourceCode = fActiveFunction->GetFunction()->GetSourceCode(); 1227 if (sourceCode == NULL) 1228 sourceCode = fActiveFunction->GetSourceCode(); 1229 1230 BReference<SourceCode> sourceCodeReference(sourceCode); 1231 1232 locker.Unlock(); 1233 1234 _SetActiveSourceCode(sourceCode); 1235 } 1236 1237 1238 void 1239 TeamWindow::_HandleUserBreakpointChanged(UserBreakpoint* breakpoint) 1240 { 1241 fSourceView->UserBreakpointChanged(breakpoint); 1242 fBreakpointsView->UserBreakpointChanged(breakpoint); 1243 } 1244 1245 1246 void 1247 TeamWindow::_HandleResolveMissingSourceFile(entry_ref& locatedPath) 1248 { 1249 if (fActiveFunction != NULL) { 1250 LocatableFile* sourceFile = fActiveFunction->GetFunctionDebugInfo() 1251 ->SourceFile(); 1252 if (sourceFile != NULL) { 1253 BString sourcePath; 1254 BString targetPath; 1255 sourceFile->GetPath(sourcePath); 1256 BPath path(&locatedPath); 1257 targetPath = path.Path(); 1258 fListener->SourceEntryLocateRequested(sourcePath, targetPath); 1259 fListener->FunctionSourceCodeRequested(fActiveFunction); 1260 } 1261 } 1262 } 1263 1264 1265 status_t 1266 TeamWindow::_SaveInspectorSettings(const BMessage* settings) 1267 { 1268 if (fUiSettings.AddSettings("inspectorWindow", *settings) != B_OK) 1269 return B_NO_MEMORY; 1270 1271 return B_OK; 1272 } 1273