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