Debugger: Further work on memory leak hunting.
[haiku.git] / src / apps / debugger / user_interface / gui / team_window / TeamWindow.cpp
blob50f72f92e05691737d93013f3dad23a9783d1d71
1 /*
2 * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2010-2017, Rene Gollent, rene@gollent.com.
4 * Distributed under the terms of the MIT License.
5 */
8 #include "TeamWindow.h"
10 #include <stdio.h>
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>
33 #include <AutoDeleter.h>
34 #include <AutoLocker.h>
36 #include "AppMessageCodes.h"
37 #include "Breakpoint.h"
38 #include "BreakpointEditWindow.h"
39 #include "ConsoleOutputView.h"
40 #include "CppLanguage.h"
41 #include "CpuState.h"
42 #include "DisassembledCode.h"
43 #include "BreakpointEditWindow.h"
44 #include "ExpressionEvaluationWindow.h"
45 #include "ExpressionPromptWindow.h"
46 #include "FileSourceCode.h"
47 #include "GuiSettingsUtils.h"
48 #include "GuiTeamUiSettings.h"
49 #include "Image.h"
50 #include "ImageDebugInfo.h"
51 #include "InspectorWindow.h"
52 #include "LocatableFile.h"
53 #include "MessageCodes.h"
54 #include "RegistersView.h"
55 #include "StackTrace.h"
56 #include "StackTraceView.h"
57 #include "TeamSettingsWindow.h"
58 #include "Tracing.h"
59 #include "TypeComponentPath.h"
60 #include "UiUtils.h"
61 #include "UserInterface.h"
62 #include "ValueNodeManager.h"
63 #include "Value.h"
64 #include "Variable.h"
65 #include "WatchPromptWindow.h"
68 enum {
69 MAIN_TAB_INDEX_THREADS = 0,
70 MAIN_TAB_INDEX_IMAGES = 1
74 enum {
75 MSG_CHOOSE_DEBUG_REPORT_LOCATION = 'ccrl',
76 MSG_DEBUG_REPORT_SAVED = 'drsa',
77 MSG_LOCATE_SOURCE_IF_NEEDED = 'lsin',
78 MSG_SOURCE_ENTRY_QUERY_COMPLETE = 'seqc',
79 MSG_CLEAR_STACK_TRACE = 'clst',
80 MSG_HANDLE_LOAD_SETTINGS = 'hlst',
81 MSG_UPDATE_STATUS_BAR = 'upsb'
85 // #pragma mark - ThreadStackFrameSelectionKey
88 struct TeamWindow::ThreadStackFrameSelectionKey {
89 ::Thread* thread;
91 ThreadStackFrameSelectionKey(::Thread* thread)
93 thread(thread)
95 thread->AcquireReference();
98 ~ThreadStackFrameSelectionKey()
100 thread->ReleaseReference();
103 uint32 HashValue() const
105 return (uint32)thread->ID();
108 bool operator==(const ThreadStackFrameSelectionKey& other) const
110 return thread == other.thread;
115 // #pragma mark - ThreadStackFrameSelectionEntry
118 struct TeamWindow::ThreadStackFrameSelectionEntry
119 : ThreadStackFrameSelectionKey {
120 ThreadStackFrameSelectionEntry* next;
121 StackFrame* selectedFrame;
123 ThreadStackFrameSelectionEntry(::Thread* thread, StackFrame* frame)
125 ThreadStackFrameSelectionKey(thread),
126 selectedFrame(frame)
130 inline StackFrame* SelectedFrame() const
132 return selectedFrame;
135 void SetSelectedFrame(StackFrame* frame)
137 selectedFrame = frame;
142 // #pragma mark - ThreadStackFrameSelectionEntryHashDefinition
145 struct TeamWindow::ThreadStackFrameSelectionEntryHashDefinition {
146 typedef ThreadStackFrameSelectionKey KeyType;
147 typedef ThreadStackFrameSelectionEntry ValueType;
149 size_t HashKey(const ThreadStackFrameSelectionKey& key) const
151 return key.HashValue();
154 size_t Hash(const ThreadStackFrameSelectionKey* value) const
156 return value->HashValue();
159 bool Compare(const ThreadStackFrameSelectionKey& key,
160 const ThreadStackFrameSelectionKey* value) const
162 return key == *value;
165 ThreadStackFrameSelectionEntry*& GetLink(
166 ThreadStackFrameSelectionEntry* value) const
168 return value->next;
173 // #pragma mark - PathViewMessageFilter
176 class PathViewMessageFilter : public BMessageFilter {
177 public:
178 PathViewMessageFilter(BMessenger teamWindow)
180 BMessageFilter(B_MOUSE_UP),
181 fTeamWindowMessenger(teamWindow)
185 virtual filter_result Filter(BMessage*, BHandler**)
187 fTeamWindowMessenger.SendMessage(MSG_LOCATE_SOURCE_IF_NEEDED);
189 return B_DISPATCH_MESSAGE;
192 private:
193 BMessenger fTeamWindowMessenger;
197 // #pragma mark - TeamWindow
200 TeamWindow::TeamWindow(::Team* team, UserInterfaceListener* listener)
202 BWindow(BRect(100, 100, 899, 699), "Team", B_TITLED_WINDOW,
203 B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS),
204 fTeam(team),
205 fActiveThread(NULL),
206 fActiveImage(NULL),
207 fActiveStackTrace(NULL),
208 fActiveStackFrame(NULL),
209 fThreadSelectionInfoTable(NULL),
210 fActiveBreakpoint(NULL),
211 fActiveFunction(NULL),
212 fActiveSourceCode(NULL),
213 fActiveSourceObject(ACTIVE_SOURCE_NONE),
214 fListener(listener),
215 fTraceUpdateRunner(NULL),
216 fTabView(NULL),
217 fLocalsTabView(NULL),
218 fThreadListView(NULL),
219 fImageListView(NULL),
220 fImageFunctionsView(NULL),
221 fBreakpointsView(NULL),
222 fVariablesView(NULL),
223 fRegistersView(NULL),
224 fStackTraceView(NULL),
225 fSourceView(NULL),
226 fRunButton(NULL),
227 fStepOverButton(NULL),
228 fStepIntoButton(NULL),
229 fStepOutButton(NULL),
230 fMenuBar(NULL),
231 fSourcePathView(NULL),
232 fStatusBarView(NULL),
233 fConsoleOutputView(NULL),
234 fFunctionSplitView(NULL),
235 fSourceSplitView(NULL),
236 fImageSplitView(NULL),
237 fThreadSplitView(NULL),
238 fConsoleSplitView(NULL),
239 fTeamSettingsWindow(NULL),
240 fBreakpointEditWindow(NULL),
241 fInspectorWindow(NULL),
242 fExpressionEvalWindow(NULL),
243 fExpressionPromptWindow(NULL),
244 fFilePanel(NULL),
245 fActiveSourceWorker(-1)
247 _UpdateTitle();
249 fTeam->AddListener(this);
253 TeamWindow::~TeamWindow()
255 if (fThreadListView != NULL)
256 fThreadListView->UnsetListener();
257 if (fStackTraceView != NULL)
258 fStackTraceView->UnsetListener();
259 if (fSourceView != NULL)
260 fSourceView->UnsetListener();
261 if (fInspectorWindow != NULL) {
262 if (fInspectorWindow->Lock())
263 fInspectorWindow->Quit();
265 if (fExpressionEvalWindow != NULL) {
266 if (fExpressionEvalWindow->Lock())
267 fExpressionEvalWindow->Quit();
269 if (fExpressionPromptWindow != NULL) {
270 if (fExpressionPromptWindow->Lock())
271 fExpressionPromptWindow->Quit();
274 fTeam->RemoveListener(this);
276 _SetActiveSourceCode(NULL);
277 _SetActiveFunction(NULL);
278 _SetActiveBreakpoint(NULL);
279 _SetActiveStackFrame(NULL);
280 _SetActiveStackTrace(NULL);
281 _SetActiveImage(NULL);
282 _SetActiveThread(NULL);
284 delete fFilePanel;
286 ThreadStackFrameSelectionEntry* entry
287 = fThreadSelectionInfoTable->Clear(true);
289 while (entry != NULL) {
290 ThreadStackFrameSelectionEntry* next = entry->next;
291 delete entry;
292 entry = next;
295 delete fThreadSelectionInfoTable;
297 if (fActiveSourceWorker > 0)
298 wait_for_thread(fActiveSourceWorker, NULL);
302 /*static*/ TeamWindow*
303 TeamWindow::Create(::Team* team, UserInterfaceListener* listener)
305 TeamWindow* self = new TeamWindow(team, listener);
307 try {
308 self->_Init();
309 } catch (...) {
310 delete self;
311 throw;
314 return self;
318 void
319 TeamWindow::DispatchMessage(BMessage* message, BHandler* handler)
321 // Handle function key shortcuts for stepping
322 switch (message->what) {
323 case B_KEY_DOWN:
324 if (fActiveThread != NULL && fTraceUpdateRunner == NULL) {
325 int32 key;
326 uint32 modifiers;
327 if (message->FindInt32("key", &key) == B_OK
328 && message->FindInt32("modifiers", (int32*)&modifiers)
329 == B_OK) {
330 switch (key) {
331 case B_F5_KEY:
332 fListener->ThreadActionRequested(
333 fActiveThread->ID(), MSG_THREAD_RUN);
334 break;
335 case B_F10_KEY:
336 fListener->ThreadActionRequested(
337 fActiveThread->ID(), MSG_THREAD_STEP_OVER);
338 break;
339 case B_F11_KEY:
340 if ((modifiers & B_SHIFT_KEY) != 0) {
341 fListener->ThreadActionRequested(
342 fActiveThread->ID(), MSG_THREAD_STEP_OUT);
343 } else {
344 fListener->ThreadActionRequested(
345 fActiveThread->ID(), MSG_THREAD_STEP_INTO);
347 break;
348 default:
349 break;
353 break;
355 case B_COPY:
356 case B_SELECT_ALL:
357 BView* focusView = CurrentFocus();
358 if (focusView != NULL) {
359 focusView->MessageReceived(message);
360 return;
362 break;
364 BWindow::DispatchMessage(message, handler);
368 void
369 TeamWindow::MessageReceived(BMessage* message)
371 switch (message->what) {
372 case MSG_TEAM_RESTART_REQUESTED:
374 fListener->TeamRestartRequested();
375 break;
377 case MSG_CHOOSE_DEBUG_REPORT_LOCATION:
379 try {
380 char filename[B_FILE_NAME_LENGTH];
381 UiUtils::ReportNameForTeam(fTeam, filename, sizeof(filename));
382 BMessenger msgr(this);
383 fFilePanel = new BFilePanel(B_SAVE_PANEL, &msgr,
384 NULL, 0, false, new BMessage(MSG_GENERATE_DEBUG_REPORT));
385 fFilePanel->SetSaveText(filename);
386 fFilePanel->Show();
387 } catch (...) {
388 delete fFilePanel;
389 fFilePanel = NULL;
391 break;
393 case MSG_GENERATE_DEBUG_REPORT:
395 delete fFilePanel;
396 fFilePanel = NULL;
398 BPath path;
399 entry_ref ref;
400 if (message->FindRef("directory", &ref) == B_OK
401 && message->HasString("name")) {
402 path.SetTo(&ref);
403 path.Append(message->FindString("name"));
404 if (get_ref_for_path(path.Path(), &ref) == B_OK)
405 fListener->DebugReportRequested(&ref);
407 break;
409 case MSG_DEBUG_REPORT_SAVED:
411 status_t finalStatus = message->GetInt32("status", B_OK);
412 BString data;
413 if (finalStatus == B_OK) {
414 data.SetToFormat("Debug report successfully saved to '%s'",
415 message->FindString("path"));
416 } else {
417 data.SetToFormat("Failed to save debug report: '%s'",
418 strerror(finalStatus));
421 BAlert *alert = new(std::nothrow) BAlert("Report saved",
422 data.String(), "Close");
423 if (alert == NULL)
424 break;
426 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
427 alert->Go();
428 break;
430 case MSG_SHOW_INSPECTOR_WINDOW:
432 if (fInspectorWindow) {
433 AutoLocker<BWindow> lock(fInspectorWindow);
434 if (lock.IsLocked())
435 fInspectorWindow->Activate(true);
436 } else {
437 try {
438 fInspectorWindow = InspectorWindow::Create(fTeam,
439 fListener, this);
440 if (fInspectorWindow != NULL) {
441 fInspectorWindow->LoadSettings(fUiSettings);
442 fInspectorWindow->Show();
444 } catch (...) {
445 // TODO: notify user
449 target_addr_t address;
450 if (message->FindUInt64("address", &address) == B_OK) {
451 BMessage addressMessage(MSG_INSPECT_ADDRESS);
452 addressMessage.AddUInt64("address", address);
453 fInspectorWindow->PostMessage(&addressMessage);
455 break;
457 case MSG_INSPECTOR_WINDOW_CLOSED:
459 _SaveInspectorSettings(CurrentMessage());
460 fInspectorWindow = NULL;
461 break;
464 case MSG_SHOW_EXPRESSION_WINDOW:
466 if (fExpressionEvalWindow != NULL) {
467 AutoLocker<BWindow> lock(fExpressionEvalWindow);
468 if (lock.IsLocked())
469 fExpressionEvalWindow->Activate(true);
470 } else {
471 try {
472 fExpressionEvalWindow = ExpressionEvaluationWindow::Create(
473 this, fTeam, fListener);
474 if (fExpressionEvalWindow != NULL)
475 fExpressionEvalWindow->Show();
476 } catch (...) {
477 // TODO: notify user
480 break;
482 case MSG_EXPRESSION_WINDOW_CLOSED:
484 fExpressionEvalWindow = NULL;
485 break;
487 case MSG_SHOW_EXPRESSION_PROMPT_WINDOW:
489 if (fExpressionPromptWindow != NULL) {
490 AutoLocker<BWindow> lock(fExpressionPromptWindow);
491 if (lock.IsLocked())
492 fExpressionPromptWindow->Activate(true);
493 } else {
494 try {
495 fExpressionPromptWindow = ExpressionPromptWindow::Create(
496 fVariablesView, this);
497 if (fExpressionPromptWindow != NULL)
498 fExpressionPromptWindow->Show();
499 } catch (...) {
500 // TODO: notify user
503 break;
505 case MSG_EXPRESSION_PROMPT_WINDOW_CLOSED:
507 fExpressionPromptWindow = NULL;
508 break;
510 case MSG_SHOW_TEAM_SETTINGS_WINDOW:
512 if (fTeamSettingsWindow != NULL) {
513 AutoLocker<BWindow> lock(fTeamSettingsWindow);
514 if (lock.IsLocked())
515 fTeamSettingsWindow->Activate(true);
516 } else {
517 try {
518 fTeamSettingsWindow
519 = TeamSettingsWindow::Create(
520 fTeam, fListener, this);
521 if (fTeamSettingsWindow != NULL)
522 fTeamSettingsWindow->Show();
523 } catch (...) {
524 // TODO: notify user
527 break;
529 case MSG_TEAM_SETTINGS_WINDOW_CLOSED:
531 fTeamSettingsWindow = NULL;
532 break;
534 case MSG_SHOW_BREAKPOINT_EDIT_WINDOW:
536 if (fBreakpointEditWindow != NULL) {
537 AutoLocker<BWindow> lock(fBreakpointEditWindow);
538 if (lock.IsLocked())
539 fBreakpointEditWindow->Activate(true);
540 } else {
541 UserBreakpoint* breakpoint;
542 if (message->FindPointer("breakpoint",
543 reinterpret_cast<void**>(&breakpoint)) != B_OK) {
544 break;
547 try {
548 fBreakpointEditWindow
549 = BreakpointEditWindow::Create(
550 fTeam, breakpoint, fListener, this);
551 if (fBreakpointEditWindow != NULL)
552 fBreakpointEditWindow->Show();
553 } catch (...) {
554 // TODO: notify user
557 break;
559 case MSG_BREAKPOINT_EDIT_WINDOW_CLOSED:
561 fBreakpointEditWindow = NULL;
562 break;
564 case MSG_SHOW_WATCH_VARIABLE_PROMPT:
566 target_addr_t address;
567 uint32 type;
568 int32 length;
570 if (message->FindUInt64("address", &address) != B_OK
571 || message->FindUInt32("type", &type) != B_OK
572 || message->FindInt32("length", &length) != B_OK) {
573 break;
576 try {
577 WatchPromptWindow* window = WatchPromptWindow::Create(
578 fTeam->GetArchitecture(), address, type, length,
579 fListener);
580 window->Show();
581 } catch (...) {
582 // TODO: notify user
584 break;
586 case B_REFS_RECEIVED:
588 entry_ref locatedPath;
589 if (message->FindRef("refs", &locatedPath) != B_OK)
590 break;
592 _HandleResolveMissingSourceFile(locatedPath);
593 delete fFilePanel;
594 fFilePanel = NULL;
595 break;
597 case MSG_LOCATE_SOURCE_IF_NEEDED:
599 _HandleLocateSourceRequest();
600 break;
602 case MSG_SOURCE_ENTRY_QUERY_COMPLETE:
604 BStringList* entries;
605 if (message->FindPointer("entries", (void**)&entries) == B_OK) {
606 ObjectDeleter<BStringList> entryDeleter(entries);
607 _HandleLocateSourceRequest(entries);
609 fActiveSourceWorker = -1;
610 break;
612 case MSG_THREAD_RUN:
613 case MSG_THREAD_STOP:
614 case MSG_THREAD_STEP_OVER:
615 case MSG_THREAD_STEP_INTO:
616 case MSG_THREAD_STEP_OUT:
617 if (fActiveThread != NULL && fTraceUpdateRunner == NULL) {
618 fListener->ThreadActionRequested(fActiveThread->ID(),
619 message->what);
621 break;
623 case MSG_CLEAR_STACK_TRACE:
625 if (fTraceUpdateRunner != NULL) {
626 _SetActiveStackTrace(NULL);
627 _UpdateRunButtons();
629 break;
631 case MSG_HANDLE_LOAD_SETTINGS:
633 GuiTeamUiSettings* settings;
634 if (message->FindPointer("settings",
635 reinterpret_cast<void**>(&settings)) != B_OK) {
636 break;
639 _LoadSettings(settings);
640 break;
642 case MSG_UPDATE_STATUS_BAR:
644 const char* messageText;
645 if (message->FindString("message", &messageText) == B_OK)
646 fStatusBarView->SetText(messageText);
647 break;
649 case MSG_TEAM_RENAMED:
651 _UpdateTitle();
652 break;
654 case MSG_THREAD_STATE_CHANGED:
656 int32 threadID;
657 if (message->FindInt32("thread", &threadID) != B_OK)
658 break;
660 _HandleThreadStateChanged(threadID);
661 break;
663 case MSG_THREAD_CPU_STATE_CHANGED:
665 int32 threadID;
666 if (message->FindInt32("thread", &threadID) != B_OK)
667 break;
669 _HandleCpuStateChanged(threadID);
670 break;
673 case MSG_THREAD_STACK_TRACE_CHANGED:
675 int32 threadID;
676 if (message->FindInt32("thread", &threadID) != B_OK)
677 break;
679 _HandleStackTraceChanged(threadID);
680 break;
683 case MSG_IMAGE_DEBUG_INFO_CHANGED:
685 int32 imageID;
686 if (message->FindInt32("image", &imageID) != B_OK)
687 break;
689 _HandleImageDebugInfoChanged(imageID);
690 break;
693 case MSG_CONSOLE_OUTPUT_RECEIVED:
695 int32 fd;
696 BString output;
697 if (message->FindInt32("fd", &fd) != B_OK
698 || message->FindString("output", &output) != B_OK) {
699 break;
701 fConsoleOutputView->ConsoleOutputReceived(fd, output);
702 break;
705 case MSG_USER_BREAKPOINT_CHANGED:
707 UserBreakpoint* breakpoint;
708 if (message->FindPointer("breakpoint", (void**)&breakpoint) != B_OK)
709 break;
710 BReference<UserBreakpoint> breakpointReference(breakpoint, true);
712 _HandleUserBreakpointChanged(breakpoint);
713 break;
716 case MSG_WATCHPOINT_CHANGED:
718 Watchpoint* watchpoint;
719 if (message->FindPointer("watchpoint", (void**)&watchpoint) != B_OK)
720 break;
721 BReference<Watchpoint> watchpointReference(watchpoint, true);
723 _HandleWatchpointChanged(watchpoint);
724 break;
728 case MSG_FUNCTION_SOURCE_CODE_CHANGED:
730 _HandleSourceCodeChanged();
731 break;
734 default:
735 BWindow::MessageReceived(message);
736 break;
741 bool
742 TeamWindow::QuitRequested()
744 fListener->UserInterfaceQuitRequested();
746 return false;
750 status_t
751 TeamWindow::LoadSettings(const GuiTeamUiSettings* settings)
753 BMessage message(MSG_HANDLE_LOAD_SETTINGS);
754 message.AddPointer("settings", settings);
755 return PostMessage(&message);
759 status_t
760 TeamWindow::SaveSettings(GuiTeamUiSettings* settings)
762 AutoLocker<BWindow> lock(this);
763 if (!lock.IsLocked())
764 return B_ERROR;
766 BMessage inspectorSettings;
767 if (fUiSettings.Settings("inspectorWindow", inspectorSettings) == B_OK) {
768 if (!settings->AddSettings("inspectorWindow", inspectorSettings))
769 return B_NO_MEMORY;
772 BMessage archive;
773 BMessage teamWindowSettings;
774 if (teamWindowSettings.AddRect("frame", Frame()) != B_OK)
775 return B_NO_MEMORY;
777 if (GuiSettingsUtils::ArchiveSplitView(archive, fSourceSplitView) != B_OK)
778 return B_NO_MEMORY;
779 if (teamWindowSettings.AddMessage("sourceSplit", &archive) != B_OK)
780 return B_NO_MEMORY;
782 if (GuiSettingsUtils::ArchiveSplitView(archive, fFunctionSplitView) != B_OK)
783 return B_NO_MEMORY;
784 if (teamWindowSettings.AddMessage("functionSplit", &archive) != B_OK)
785 return B_NO_MEMORY;
787 if (GuiSettingsUtils::ArchiveSplitView(archive, fImageSplitView) != B_OK)
788 return B_NO_MEMORY;
789 if (teamWindowSettings.AddMessage("imageSplit", &archive))
790 return B_NO_MEMORY;
792 if (GuiSettingsUtils::ArchiveSplitView(archive, fThreadSplitView) != B_OK)
793 return B_NO_MEMORY;
794 if (teamWindowSettings.AddMessage("threadSplit", &archive))
795 return B_NO_MEMORY;
797 if (GuiSettingsUtils::ArchiveSplitView(archive, fConsoleSplitView) != B_OK)
798 return B_NO_MEMORY;
799 if (teamWindowSettings.AddMessage("consoleSplit", &archive))
800 return B_NO_MEMORY;
802 if (fImageListView->SaveSettings(archive) != B_OK)
803 return B_NO_MEMORY;
804 if (teamWindowSettings.AddMessage("imageListView", &archive))
805 return B_NO_MEMORY;
807 if (fImageFunctionsView->SaveSettings(archive) != B_OK)
808 return B_NO_MEMORY;
809 if (teamWindowSettings.AddMessage("imageFunctionsView", &archive))
810 return B_NO_MEMORY;
812 if (fThreadListView->SaveSettings(archive) != B_OK)
813 return B_NO_MEMORY;
814 if (teamWindowSettings.AddMessage("threadListView", &archive))
815 return B_NO_MEMORY;
817 if (fVariablesView->SaveSettings(archive) != B_OK)
818 return B_NO_MEMORY;
819 if (teamWindowSettings.AddMessage("variablesView", &archive))
820 return B_NO_MEMORY;
822 if (fRegistersView->SaveSettings(archive) != B_OK)
823 return B_NO_MEMORY;
824 if (teamWindowSettings.AddMessage("registersView", &archive))
825 return B_NO_MEMORY;
827 if (fStackTraceView->SaveSettings(archive) != B_OK)
828 return B_NO_MEMORY;
829 if (teamWindowSettings.AddMessage("stackTraceView", &archive))
830 return B_NO_MEMORY;
832 if (fBreakpointsView->SaveSettings(archive) != B_OK)
833 return B_NO_MEMORY;
834 if (teamWindowSettings.AddMessage("breakpointsView", &archive))
835 return B_NO_MEMORY;
837 if (fConsoleOutputView->SaveSettings(archive) != B_OK)
838 return B_NO_MEMORY;
839 if (teamWindowSettings.AddMessage("consoleOutputView", &archive))
840 return B_NO_MEMORY;
842 if (!settings->AddSettings("teamWindow", teamWindowSettings))
843 return B_NO_MEMORY;
845 return B_OK;
849 void
850 TeamWindow::DisplayBackgroundStatus(const char* message)
852 BMessage updateMessage(MSG_UPDATE_STATUS_BAR);
853 updateMessage.AddString("message", message);
854 PostMessage(&updateMessage);
858 void
859 TeamWindow::ThreadSelectionChanged(::Thread* thread)
861 _SetActiveThread(thread);
865 void
866 TeamWindow::ImageSelectionChanged(Image* image)
868 _SetActiveImage(image);
872 void
873 TeamWindow::StackFrameSelectionChanged(StackFrame* frame)
875 _SetActiveStackFrame(frame);
879 void
880 TeamWindow::FunctionSelectionChanged(FunctionInstance* function)
882 // If the function wasn't already active, it was just selected by the user.
883 if (function != NULL && function != fActiveFunction)
884 fActiveSourceObject = ACTIVE_SOURCE_FUNCTION;
886 _SetActiveFunction(function);
890 void
891 TeamWindow::BreakpointSelectionChanged(BreakpointProxyList &proxies)
893 if (proxies.CountItems() == 0 && fActiveBreakpoint != NULL) {
894 fActiveBreakpoint->ReleaseReference();
895 fActiveBreakpoint = NULL;
896 } else if (proxies.CountItems() == 1) {
897 BreakpointProxy* proxy = proxies.ItemAt(0);
898 if (proxy->Type() == BREAKPOINT_PROXY_TYPE_BREAKPOINT)
899 _SetActiveBreakpoint(proxy->GetBreakpoint());
901 // if more than one item is selected, do nothing.
905 void
906 TeamWindow::SetBreakpointEnabledRequested(UserBreakpoint* breakpoint,
907 bool enabled)
909 fListener->SetBreakpointEnabledRequested(breakpoint, enabled);
913 void
914 TeamWindow::ClearBreakpointRequested(UserBreakpoint* breakpoint)
916 fListener->ClearBreakpointRequested(breakpoint);
920 void
921 TeamWindow::SetBreakpointRequested(target_addr_t address, bool enabled)
923 fListener->SetBreakpointRequested(address, enabled);
927 void
928 TeamWindow::ClearBreakpointRequested(target_addr_t address)
930 fListener->ClearBreakpointRequested(address);
934 void
935 TeamWindow::ThreadActionRequested(::Thread* thread, uint32 action,
936 target_addr_t address)
938 if (fTraceUpdateRunner == NULL)
939 fListener->ThreadActionRequested(thread->ID(), action, address);
943 void
944 TeamWindow::FunctionSourceCodeRequested(FunctionInstance* function,
945 bool forceDisassembly)
947 fListener->FunctionSourceCodeRequested(function, forceDisassembly);
951 void
952 TeamWindow::SetWatchpointEnabledRequested(Watchpoint* watchpoint,
953 bool enabled)
955 fListener->SetWatchpointEnabledRequested(watchpoint, enabled);
959 void
960 TeamWindow::ClearWatchpointRequested(Watchpoint* watchpoint)
962 fListener->ClearWatchpointRequested(watchpoint);
966 void
967 TeamWindow::ValueNodeValueRequested(CpuState* cpuState,
968 ValueNodeContainer* container, ValueNode* valueNode)
970 fListener->ValueNodeValueRequested(cpuState, container, valueNode);
974 void
975 TeamWindow::ExpressionEvaluationRequested(ExpressionInfo* info,
976 StackFrame* frame, ::Thread* thread)
978 SourceLanguage* language;
979 if (_GetActiveSourceLanguage(language) != B_OK)
980 return;
982 BReference<SourceLanguage> languageReference(language, true);
983 fListener->ExpressionEvaluationRequested(language, info, frame, thread);
987 void
988 TeamWindow::ValueNodeWriteRequested(ValueNode* node, CpuState* state,
989 Value* newValue)
991 fListener->ValueNodeWriteRequested(node, state, newValue);
995 void
996 TeamWindow::TeamRenamed(const Team::Event& event)
998 PostMessage(MSG_TEAM_RENAMED);
1002 void
1003 TeamWindow::ThreadStateChanged(const Team::ThreadEvent& event)
1005 BMessage message(MSG_THREAD_STATE_CHANGED);
1006 message.AddInt32("thread", event.GetThread()->ID());
1007 PostMessage(&message);
1011 void
1012 TeamWindow::ThreadCpuStateChanged(const Team::ThreadEvent& event)
1014 BMessage message(MSG_THREAD_CPU_STATE_CHANGED);
1015 message.AddInt32("thread", event.GetThread()->ID());
1016 PostMessage(&message);
1020 void
1021 TeamWindow::ThreadStackTraceChanged(const Team::ThreadEvent& event)
1023 BMessage message(MSG_THREAD_STACK_TRACE_CHANGED);
1024 message.AddInt32("thread", event.GetThread()->ID());
1025 PostMessage(&message);
1029 void
1030 TeamWindow::ImageDebugInfoChanged(const Team::ImageEvent& event)
1032 BMessage message(MSG_IMAGE_DEBUG_INFO_CHANGED);
1033 message.AddInt32("image", event.GetImage()->ID());
1034 PostMessage(&message);
1038 void
1039 TeamWindow::ConsoleOutputReceived(const Team::ConsoleOutputEvent& event)
1041 BMessage message(MSG_CONSOLE_OUTPUT_RECEIVED);
1042 message.AddInt32("fd", event.Descriptor());
1043 message.AddString("output", event.Output());
1044 PostMessage(&message);
1048 void
1049 TeamWindow::UserBreakpointChanged(const Team::UserBreakpointEvent& event)
1051 BMessage message(MSG_USER_BREAKPOINT_CHANGED);
1052 BReference<UserBreakpoint> breakpointReference(event.GetBreakpoint());
1053 if (message.AddPointer("breakpoint", event.GetBreakpoint()) == B_OK
1054 && PostMessage(&message) == B_OK) {
1055 breakpointReference.Detach();
1060 void
1061 TeamWindow::WatchpointChanged(const Team::WatchpointEvent& event)
1063 BMessage message(MSG_WATCHPOINT_CHANGED);
1064 BReference<Watchpoint> watchpointReference(event.GetWatchpoint());
1065 if (message.AddPointer("watchpoint", event.GetWatchpoint()) == B_OK
1066 && PostMessage(&message) == B_OK) {
1067 watchpointReference.Detach();
1072 void
1073 TeamWindow::DebugReportChanged(const Team::DebugReportEvent& event)
1075 BMessage message(MSG_DEBUG_REPORT_SAVED);
1076 message.AddString("path", event.GetReportPath());
1077 message.AddInt32("status", event.GetFinalStatus());
1078 PostMessage(&message);
1082 void
1083 TeamWindow::FunctionSourceCodeChanged(Function* function)
1085 TRACE_GUI("TeamWindow::FunctionSourceCodeChanged(%p): source: %p, "
1086 "state: %d\n", function, function->GetSourceCode(),
1087 function->SourceCodeState());
1089 PostMessage(MSG_FUNCTION_SOURCE_CODE_CHANGED);
1093 void
1094 TeamWindow::_Init()
1096 fThreadSelectionInfoTable = new ThreadStackFrameSelectionInfoTable;
1097 if (fThreadSelectionInfoTable->Init() != B_OK) {
1098 delete fThreadSelectionInfoTable;
1099 fThreadSelectionInfoTable = NULL;
1100 throw std::bad_alloc();
1103 BScrollView* sourceScrollView;
1105 const float splitSpacing = 3.0f;
1107 BLayoutBuilder::Group<>(this, B_VERTICAL, 0.0f)
1108 .Add(fMenuBar = new BMenuBar("Menu"))
1109 .AddSplit(B_VERTICAL, splitSpacing)
1110 .GetSplitView(&fFunctionSplitView)
1111 .SetInsets(B_USE_SMALL_INSETS)
1112 .Add(fTabView = new BTabView("tab view"), 0.4f)
1113 .AddSplit(B_HORIZONTAL, splitSpacing)
1114 .GetSplitView(&fSourceSplitView)
1115 .AddGroup(B_VERTICAL, B_USE_SMALL_SPACING)
1116 .AddGroup(B_HORIZONTAL, B_USE_SMALL_SPACING)
1117 .Add(fRunButton = new BButton("Run"))
1118 .Add(fStepOverButton = new BButton("Step over"))
1119 .Add(fStepIntoButton = new BButton("Step into"))
1120 .Add(fStepOutButton = new BButton("Step out"))
1121 .AddGlue()
1122 .End()
1123 .Add(fSourcePathView = new BStringView(
1124 "source path",
1125 "Source path unavailable."), 4.0f)
1126 .Add(sourceScrollView = new BScrollView("source scroll",
1127 NULL, 0, true, true), splitSpacing)
1128 .End()
1129 .Add(fLocalsTabView = new BTabView("locals view"))
1130 .End()
1131 .AddSplit(B_VERTICAL, splitSpacing)
1132 .GetSplitView(&fConsoleSplitView)
1133 .SetInsets(0.0)
1134 .Add(fConsoleOutputView = ConsoleOutputView::Create())
1135 .End()
1136 .End()
1137 .Add(fStatusBarView = new BStringView("status", "Ready."));
1139 fStatusBarView->SetExplicitMinSize(BSize(50.0, B_SIZE_UNSET));
1140 fStatusBarView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
1142 // add source view
1143 sourceScrollView->SetTarget(fSourceView = SourceView::Create(fTeam, this));
1145 // add threads tab
1146 BSplitView* threadGroup = new BSplitView(B_HORIZONTAL, splitSpacing);
1147 threadGroup->SetName("Threads");
1148 fTabView->AddTab(threadGroup);
1149 BLayoutBuilder::Split<>(threadGroup)
1150 .GetSplitView(&fThreadSplitView)
1151 .Add(fThreadListView = ThreadListView::Create(fTeam, this))
1152 .Add(fStackTraceView = StackTraceView::Create(this));
1154 // add images tab
1155 BSplitView* imagesGroup = new BSplitView(B_HORIZONTAL, splitSpacing);
1156 imagesGroup->SetName("Images");
1157 fTabView->AddTab(imagesGroup);
1158 BLayoutBuilder::Split<>(imagesGroup)
1159 .GetSplitView(&fImageSplitView)
1160 .Add(fImageListView = ImageListView::Create(fTeam, this))
1161 .Add(fImageFunctionsView = ImageFunctionsView::Create(this));
1163 // add breakpoints tab
1164 BGroupView* breakpointsGroup = new BGroupView(B_HORIZONTAL,
1165 B_USE_SMALL_SPACING);
1166 breakpointsGroup->SetName("Breakpoints");
1167 fTabView->AddTab(breakpointsGroup);
1168 BLayoutBuilder::Group<>(breakpointsGroup)
1169 // .SetInsets(0.0f)
1170 .Add(fBreakpointsView = BreakpointsView::Create(fTeam, this));
1172 ValueNodeManager* manager = new ValueNodeManager;
1174 // add local variables tab
1175 BView* tab = fVariablesView = VariablesView::Create(this, manager);
1176 fLocalsTabView->AddTab(tab);
1178 // add registers tab
1179 tab = fRegistersView = RegistersView::Create(fTeam->GetArchitecture());
1180 fLocalsTabView->AddTab(tab);
1182 fRunButton->SetMessage(new BMessage(MSG_THREAD_RUN));
1183 fStepOverButton->SetMessage(new BMessage(MSG_THREAD_STEP_OVER));
1184 fStepIntoButton->SetMessage(new BMessage(MSG_THREAD_STEP_INTO));
1185 fStepOutButton->SetMessage(new BMessage(MSG_THREAD_STEP_OUT));
1186 fRunButton->SetTarget(this);
1187 fStepOverButton->SetTarget(this);
1188 fStepIntoButton->SetTarget(this);
1189 fStepOutButton->SetTarget(this);
1191 fSourcePathView->SetExplicitMinSize(BSize(100.0, B_SIZE_UNSET));
1192 fSourcePathView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
1193 BMessageFilter* filter = new(std::nothrow) PathViewMessageFilter(
1194 BMessenger(this));
1195 if (filter != NULL)
1196 fSourcePathView->AddFilter(filter);
1198 // add menus and menu items
1199 BMenu* menu = new BMenu("Debugger");
1200 fMenuBar->AddItem(menu);
1201 BMenuItem* item = new BMenuItem("Start new team" B_UTF8_ELLIPSIS,
1202 new BMessage(MSG_SHOW_START_TEAM_WINDOW));
1203 menu->AddItem(item);
1204 item->SetTarget(be_app);
1205 item = new BMenuItem("Show Teams window" B_UTF8_ELLIPSIS,
1206 new BMessage(MSG_SHOW_TEAMS_WINDOW));
1207 menu->AddItem(item);
1208 item->SetTarget(be_app);
1209 menu = new BMenu("Team");
1210 fMenuBar->AddItem(menu);
1211 item = new BMenuItem("Restart", new BMessage(
1212 MSG_TEAM_RESTART_REQUESTED), 'R', B_SHIFT_KEY);
1213 menu->AddItem(item);
1214 item->SetTarget(this);
1215 item = new BMenuItem("Close", new BMessage(B_QUIT_REQUESTED),
1216 'W');
1217 menu->AddItem(item);
1218 item->SetTarget(this);
1219 menu->AddSeparatorItem();
1220 item = new BMenuItem("Settings" B_UTF8_ELLIPSIS, new BMessage(
1221 MSG_SHOW_TEAM_SETTINGS_WINDOW));
1222 menu->AddItem(item);
1223 item->SetTarget(this);
1224 menu = new BMenu("Edit");
1225 fMenuBar->AddItem(menu);
1226 item = new BMenuItem("Copy", new BMessage(B_COPY), 'C');
1227 menu->AddItem(item);
1228 item->SetTarget(this);
1229 item = new BMenuItem("Select all", new BMessage(B_SELECT_ALL), 'A');
1230 menu->AddItem(item);
1231 item->SetTarget(this);
1232 menu = new BMenu("Tools");
1233 fMenuBar->AddItem(menu);
1234 item = new BMenuItem("Save debug report",
1235 new BMessage(MSG_CHOOSE_DEBUG_REPORT_LOCATION));
1236 menu->AddItem(item);
1237 item->SetTarget(this);
1238 item = new BMenuItem("Inspect memory",
1239 new BMessage(MSG_SHOW_INSPECTOR_WINDOW), 'I');
1240 menu->AddItem(item);
1241 item->SetTarget(this);
1242 item = new BMenuItem("Evaluate expression",
1243 new BMessage(MSG_SHOW_EXPRESSION_WINDOW), 'E');
1244 menu->AddItem(item);
1245 item->SetTarget(this);
1247 AutoLocker< ::Team> locker(fTeam);
1248 _UpdateRunButtons();
1252 void
1253 TeamWindow::_LoadSettings(const GuiTeamUiSettings* settings)
1255 BMessage teamWindowSettings;
1256 // no settings stored yet
1257 if (settings->Settings("teamWindow", teamWindowSettings) != B_OK)
1258 return;
1260 BRect frame;
1261 if (teamWindowSettings.FindRect("frame", &frame) == B_OK) {
1262 ResizeTo(frame.Width(), frame.Height());
1263 MoveTo(frame.left, frame.top);
1266 BMessage archive;
1267 if (teamWindowSettings.FindMessage("sourceSplit", &archive) == B_OK)
1268 GuiSettingsUtils::UnarchiveSplitView(archive, fSourceSplitView);
1270 if (teamWindowSettings.FindMessage("functionSplit", &archive) == B_OK)
1271 GuiSettingsUtils::UnarchiveSplitView(archive, fFunctionSplitView);
1273 if (teamWindowSettings.FindMessage("imageSplit", &archive) == B_OK)
1274 GuiSettingsUtils::UnarchiveSplitView(archive, fImageSplitView);
1276 if (teamWindowSettings.FindMessage("threadSplit", &archive) == B_OK)
1277 GuiSettingsUtils::UnarchiveSplitView(archive, fThreadSplitView);
1279 if (teamWindowSettings.FindMessage("consoleSplit", &archive) == B_OK)
1280 GuiSettingsUtils::UnarchiveSplitView(archive, fConsoleSplitView);
1282 if (teamWindowSettings.FindMessage("imageListView", &archive) == B_OK)
1283 fImageListView->LoadSettings(archive);
1285 if (teamWindowSettings.FindMessage("imageFunctionsView", &archive) == B_OK)
1286 fImageFunctionsView->LoadSettings(archive);
1288 if (teamWindowSettings.FindMessage("threadListView", &archive) == B_OK)
1289 fThreadListView->LoadSettings(archive);
1291 if (teamWindowSettings.FindMessage("variablesView", &archive) == B_OK)
1292 fVariablesView->LoadSettings(archive);
1294 if (teamWindowSettings.FindMessage("registersView", &archive) == B_OK)
1295 fRegistersView->LoadSettings(archive);
1297 if (teamWindowSettings.FindMessage("stackTraceView", &archive) == B_OK)
1298 fStackTraceView->LoadSettings(archive);
1300 if (teamWindowSettings.FindMessage("breakpointsView", &archive) == B_OK)
1301 fBreakpointsView->LoadSettings(archive);
1303 if (teamWindowSettings.FindMessage("consoleOutputView", &archive) == B_OK)
1304 fConsoleOutputView->LoadSettings(archive);
1306 fUiSettings = *settings;
1310 void
1311 TeamWindow::_UpdateTitle()
1313 AutoLocker< ::Team> lock(fTeam);
1314 BString name = fTeam->Name();
1315 if (fTeam->ID() >= 0)
1316 name << " (" << fTeam->ID() << ")";
1317 SetTitle(name.String());
1321 void
1322 TeamWindow::_SetActiveThread(::Thread* thread)
1324 if (thread == fActiveThread)
1325 return;
1327 if (fActiveThread != NULL)
1328 fActiveThread->ReleaseReference();
1330 fActiveThread = thread;
1332 if (fActiveThread != NULL)
1333 fActiveThread->AcquireReference();
1335 AutoLocker< ::Team> locker(fTeam);
1336 _UpdateRunButtons();
1338 StackTrace* stackTrace = fActiveThread != NULL
1339 ? fActiveThread->GetStackTrace() : NULL;
1340 BReference<StackTrace> stackTraceReference(stackTrace);
1341 // hold a reference until we've set it
1343 locker.Unlock();
1345 fThreadListView->SetThread(fActiveThread);
1347 _SetActiveStackTrace(stackTrace);
1348 _UpdateCpuState();
1352 void
1353 TeamWindow::_SetActiveImage(Image* image)
1355 if (image == fActiveImage)
1356 return;
1358 if (fActiveImage != NULL)
1359 fActiveImage->ReleaseReference();
1361 fActiveImage = image;
1363 AutoLocker< ::Team> locker(fTeam);
1365 ImageDebugInfo* imageDebugInfo = NULL;
1366 BReference<ImageDebugInfo> imageDebugInfoReference;
1368 if (fActiveImage != NULL) {
1369 fActiveImage->AcquireReference();
1371 imageDebugInfo = fActiveImage->GetImageDebugInfo();
1372 imageDebugInfoReference.SetTo(imageDebugInfo);
1374 // If the debug info is not loaded yet, request it.
1375 if (fActiveImage->ImageDebugInfoState() == IMAGE_DEBUG_INFO_NOT_LOADED)
1376 fListener->ImageDebugInfoRequested(fActiveImage);
1379 locker.Unlock();
1381 fImageListView->SetImage(fActiveImage);
1382 fImageFunctionsView->SetImageDebugInfo(imageDebugInfo);
1386 void
1387 TeamWindow::_SetActiveStackTrace(StackTrace* stackTrace)
1389 delete fTraceUpdateRunner;
1390 fTraceUpdateRunner = NULL;
1392 if (stackTrace == fActiveStackTrace)
1393 return;
1395 if (fActiveStackTrace != NULL)
1396 fActiveStackTrace->ReleaseReference();
1398 fActiveStackTrace = stackTrace;
1400 if (fActiveStackTrace != NULL)
1401 fActiveStackTrace->AcquireReference();
1403 fStackTraceView->SetStackTrace(fActiveStackTrace);
1404 fSourceView->SetStackTrace(fActiveStackTrace, fActiveThread);
1406 StackFrame* frame = NULL;
1407 if (fActiveStackTrace != NULL) {
1408 ThreadStackFrameSelectionEntry* entry
1409 = fThreadSelectionInfoTable->Lookup(fActiveThread);
1410 if (entry != NULL)
1411 frame = entry->SelectedFrame();
1412 else
1413 frame = fActiveStackTrace->FrameAt(0);
1416 _SetActiveStackFrame(frame);
1420 void
1421 TeamWindow::_SetActiveStackFrame(StackFrame* frame)
1423 if (frame == fActiveStackFrame)
1424 return;
1426 if (fActiveStackFrame != NULL) {
1427 AutoLocker< ::Team> locker(fTeam);
1428 fActiveStackFrame->RemoveListener(this);
1429 locker.Unlock();
1431 fActiveStackFrame->ReleaseReference();
1434 fActiveStackFrame = frame;
1436 if (fActiveStackFrame != NULL) {
1437 fActiveStackFrame->AcquireReference();
1439 AutoLocker< ::Team> locker(fTeam);
1440 fActiveStackFrame->AddListener(this);
1441 locker.Unlock();
1443 fActiveSourceObject = ACTIVE_SOURCE_STACK_FRAME;
1445 ThreadStackFrameSelectionEntry* entry
1446 = fThreadSelectionInfoTable->Lookup(fActiveThread);
1447 if (entry == NULL) {
1448 entry = new(std::nothrow) ThreadStackFrameSelectionEntry(
1449 fActiveThread, fActiveStackFrame);
1450 if (entry == NULL)
1451 return;
1453 ObjectDeleter<ThreadStackFrameSelectionEntry> entryDeleter(entry);
1454 if (fThreadSelectionInfoTable->Insert(entry) == B_OK)
1455 entryDeleter.Detach();
1456 } else
1457 entry->SetSelectedFrame(fActiveStackFrame);
1459 _SetActiveFunction(fActiveStackFrame->Function(), false);
1462 _UpdateCpuState();
1464 fStackTraceView->SetStackFrame(fActiveStackFrame);
1465 if (fActiveStackFrame != NULL)
1466 fVariablesView->SetStackFrame(fActiveThread, fActiveStackFrame);
1467 else
1468 fVariablesView->SetStackFrame(NULL, NULL);
1469 fSourceView->SetStackFrame(fActiveStackFrame);
1473 void
1474 TeamWindow::_SetActiveBreakpoint(UserBreakpoint* breakpoint)
1476 if (breakpoint == fActiveBreakpoint)
1477 return;
1479 if (fActiveBreakpoint != NULL)
1480 fActiveBreakpoint->ReleaseReference();
1482 fActiveBreakpoint = breakpoint;
1484 if (fActiveBreakpoint != NULL) {
1485 fActiveBreakpoint->AcquireReference();
1487 // get the breakpoint's function (more exactly: some function instance)
1488 AutoLocker< ::Team> locker(fTeam);
1490 Function* function = fTeam->FunctionByID(
1491 breakpoint->Location().GetFunctionID());
1492 FunctionInstance* functionInstance = function != NULL
1493 ? function->FirstInstance() : NULL;
1494 BReference<FunctionInstance> functionInstanceReference(
1495 functionInstance);
1497 locker.Unlock();
1499 fActiveSourceObject = ACTIVE_SOURCE_BREAKPOINT;
1501 _SetActiveFunction(functionInstance);
1503 // scroll to the breakpoint's source code line number (it is not done
1504 // automatically, if the active function remains the same)
1505 _ScrollToActiveFunction();
1510 void
1511 TeamWindow::_SetActiveFunction(FunctionInstance* functionInstance,
1512 bool searchForFrame)
1514 if (functionInstance == fActiveFunction)
1515 return;
1517 AutoLocker< ::Team> locker(fTeam);
1519 if (fActiveFunction != NULL) {
1520 fActiveFunction->GetFunction()->RemoveListener(this);
1521 fActiveFunction->ReleaseReference();
1524 // to avoid listener feedback problems, first unset the active function and
1525 // set the new image, if any
1526 locker.Unlock();
1528 fActiveFunction = NULL;
1530 if (functionInstance != NULL)
1531 _SetActiveImage(fTeam->ImageByAddress(functionInstance->Address()));
1533 fActiveFunction = functionInstance;
1535 locker.Lock();
1537 SourceCode* sourceCode = NULL;
1538 BReference<SourceCode> sourceCodeReference;
1540 if (fActiveFunction != NULL) {
1541 fActiveFunction->AcquireReference();
1542 fActiveFunction->GetFunction()->AddListener(this);
1544 Function* function = fActiveFunction->GetFunction();
1545 sourceCode = function->GetSourceCode();
1546 if (sourceCode == NULL)
1547 sourceCode = fActiveFunction->GetSourceCode();
1548 sourceCodeReference.SetTo(sourceCode);
1550 // If the source code is not loaded yet, request it.
1551 if (function->SourceCodeState() == FUNCTION_SOURCE_NOT_LOADED)
1552 fListener->FunctionSourceCodeRequested(fActiveFunction);
1555 locker.Unlock();
1557 _SetActiveSourceCode(sourceCode);
1559 fImageFunctionsView->SetFunction(fActiveFunction);
1561 locker.Lock();
1563 if (!searchForFrame || fActiveStackTrace == NULL)
1564 return;
1566 // look if our current stack trace has a frame matching the selected
1567 // function. If so, set it to match.
1568 StackFrame* matchingFrame = NULL;
1569 BReference<StackFrame> frameRef;
1571 for (int32 i = 0; i < fActiveStackTrace->CountFrames(); i++) {
1572 StackFrame* frame = fActiveStackTrace->FrameAt(i);
1573 if (frame->Function() == fActiveFunction) {
1574 matchingFrame = frame;
1575 frameRef.SetTo(frame);
1576 break;
1580 locker.Unlock();
1582 if (matchingFrame != NULL)
1583 _SetActiveStackFrame(matchingFrame);
1587 void
1588 TeamWindow::_SetActiveSourceCode(SourceCode* sourceCode)
1590 if (sourceCode == fActiveSourceCode) {
1591 _ScrollToActiveFunction();
1592 return;
1595 if (fActiveSourceCode != NULL)
1596 fActiveSourceCode->ReleaseReference();
1598 fActiveSourceCode = sourceCode;
1600 if (fActiveSourceCode != NULL)
1601 fActiveSourceCode->AcquireReference();
1603 fSourceView->SetSourceCode(fActiveSourceCode);
1605 _UpdateSourcePathState();
1606 _ScrollToActiveFunction();
1609 void
1610 TeamWindow::_UpdateCpuState()
1612 // get the CPU state
1613 CpuState* cpuState = NULL;
1614 BReference<CpuState> cpuStateReference;
1615 // hold a reference until the register view has one
1617 if (fActiveThread != NULL) {
1618 // Get the CPU state from the active stack frame or the thread directly.
1619 if (fActiveStackFrame == NULL) {
1620 AutoLocker< ::Team> locker(fTeam);
1621 cpuState = fActiveThread->GetCpuState();
1622 cpuStateReference.SetTo(cpuState);
1623 locker.Unlock();
1624 } else
1625 cpuState = fActiveStackFrame->GetCpuState();
1628 fRegistersView->SetCpuState(cpuState);
1632 void
1633 TeamWindow::_UpdateRunButtons()
1635 uint32 threadState = fActiveThread != NULL
1636 ? fActiveThread->State() : THREAD_STATE_UNKNOWN;
1638 switch (threadState) {
1639 case THREAD_STATE_UNKNOWN:
1640 fRunButton->SetEnabled(false);
1641 fStepOverButton->SetEnabled(false);
1642 fStepIntoButton->SetEnabled(false);
1643 fStepOutButton->SetEnabled(false);
1644 break;
1645 case THREAD_STATE_RUNNING:
1646 if (fTraceUpdateRunner == NULL) {
1647 fRunButton->SetLabel("Debug");
1648 fRunButton->SetMessage(new BMessage(MSG_THREAD_STOP));
1649 fRunButton->SetEnabled(true);
1650 fStepOverButton->SetEnabled(false);
1651 fStepIntoButton->SetEnabled(false);
1652 fStepOutButton->SetEnabled(false);
1654 break;
1655 case THREAD_STATE_STOPPED:
1656 fRunButton->SetLabel("Run");
1657 fRunButton->SetMessage(new BMessage(MSG_THREAD_RUN));
1658 fRunButton->SetEnabled(true);
1659 fStepOverButton->SetEnabled(true);
1660 fStepIntoButton->SetEnabled(true);
1661 fStepOutButton->SetEnabled(true);
1662 break;
1667 void
1668 TeamWindow::_UpdateSourcePathState()
1670 LocatableFile* sourceFile = NULL;
1671 BString sourceText = "Source file unavailable.";
1672 BString truncatedText;
1674 if (fActiveSourceCode != NULL) {
1675 sourceFile = fActiveFunction->GetFunctionDebugInfo()->SourceFile();
1677 if (sourceFile != NULL && !sourceFile->GetLocatedPath(sourceText))
1678 sourceFile->GetPath(sourceText);
1680 function_source_state state = fActiveFunction->GetFunction()
1681 ->SourceCodeState();
1682 if (state == FUNCTION_SOURCE_SUPPRESSED)
1683 sourceText.Prepend("Disassembly for: ");
1684 else if (state != FUNCTION_SOURCE_NOT_LOADED
1685 && fActiveSourceCode->GetSourceFile() == NULL
1686 && sourceFile != NULL) {
1687 sourceText.Prepend("Click to locate source file '");
1688 sourceText += "'";
1689 truncatedText = sourceText;
1690 fSourcePathView->TruncateString(&truncatedText, B_TRUNCATE_MIDDLE,
1691 fSourcePathView->Bounds().Width());
1692 } else if (sourceFile != NULL)
1693 sourceText.Prepend("File: ");
1696 if (!truncatedText.IsEmpty() && truncatedText != sourceText) {
1697 fSourcePathView->SetToolTip(sourceText);
1698 fSourcePathView->SetText(truncatedText);
1699 } else {
1700 fSourcePathView->SetText(sourceText);
1701 fSourcePathView->SetToolTip((const char*)NULL);
1706 void
1707 TeamWindow::_ScrollToActiveFunction()
1709 // Scroll to the active function, if it has been selected manually.
1710 if (fActiveFunction == NULL || fActiveSourceCode == NULL)
1711 return;
1713 switch (fActiveSourceObject) {
1714 case ACTIVE_SOURCE_FUNCTION:
1715 fSourceView->ScrollToAddress(fActiveFunction->Address());
1716 break;
1717 case ACTIVE_SOURCE_BREAKPOINT:
1719 if (fActiveBreakpoint == NULL)
1720 break;
1722 const UserBreakpointLocation& location
1723 = fActiveBreakpoint->Location();
1724 int32 line = location.GetSourceLocation().Line();
1726 if (location.SourceFile() != NULL && line >= 0
1727 && fActiveSourceCode->GetSourceFile()
1728 == location.SourceFile()) {
1729 fSourceView->ScrollToLine(line);
1730 } else {
1731 fSourceView->ScrollToAddress(
1732 fActiveFunction->Address()
1733 + location.RelativeAddress());
1735 break;
1737 case ACTIVE_SOURCE_NONE:
1738 case ACTIVE_SOURCE_STACK_FRAME:
1739 break;
1744 void
1745 TeamWindow::_HandleThreadStateChanged(thread_id threadID)
1747 AutoLocker< ::Team> locker(fTeam);
1749 ::Thread* thread = fTeam->ThreadByID(threadID);
1750 if (thread == NULL)
1751 return;
1753 if (thread->State() != THREAD_STATE_STOPPED) {
1754 ThreadStackFrameSelectionEntry* entry
1755 = fThreadSelectionInfoTable->Lookup(thread);
1756 if (entry != NULL) {
1757 fThreadSelectionInfoTable->Remove(entry);
1758 delete entry;
1762 // If the thread has been stopped and we don't have an active thread yet
1763 // (or it isn't stopped), switch to this thread. Otherwise ignore the event.
1764 if (thread->State() == THREAD_STATE_STOPPED
1765 && (fActiveThread == NULL
1766 || (thread != fActiveThread
1767 && fActiveThread->State() != THREAD_STATE_STOPPED))) {
1768 _SetActiveThread(thread);
1769 } else if (thread != fActiveThread) {
1770 // otherwise ignore the event, if the thread is not the active one
1771 return;
1774 // Switch to the threads tab view when the thread has stopped.
1775 if (thread->State() == THREAD_STATE_STOPPED) {
1776 fTabView->Select(MAIN_TAB_INDEX_THREADS);
1778 // if we hit a breakpoint or exception, raise the window to the
1779 // foreground, since if this occurs while e.g. debugging a GUI
1780 // app, it might not be immediately obvious that such an event
1781 // occurred as the app may simply appear to hang.
1782 Activate();
1785 _UpdateRunButtons();
1789 void
1790 TeamWindow::_HandleCpuStateChanged(thread_id threadID)
1792 // We're only interested in the currently selected thread
1793 if (fActiveThread == NULL || threadID != fActiveThread->ID())
1794 return;
1796 _UpdateCpuState();
1800 void
1801 TeamWindow::_HandleStackTraceChanged(thread_id threadID)
1803 // We're only interested in the currently selected thread
1804 if (fActiveThread == NULL || threadID != fActiveThread->ID())
1805 return;
1807 AutoLocker< ::Team> locker(fTeam);
1809 StackTrace* stackTrace = fActiveThread != NULL
1810 ? fActiveThread->GetStackTrace() : NULL;
1811 BReference<StackTrace> stackTraceReference(stackTrace);
1812 // hold a reference until the register view has one
1814 locker.Unlock();
1816 if (stackTrace == NULL) {
1817 if (fTraceUpdateRunner != NULL)
1818 return;
1820 BMessage message(MSG_CLEAR_STACK_TRACE);
1821 fTraceUpdateRunner = new(std::nothrow) BMessageRunner(this,
1822 message, 250000, 1);
1823 if (fTraceUpdateRunner != NULL
1824 && fTraceUpdateRunner->InitCheck() == B_OK) {
1825 fStackTraceView->SetStackTraceClearPending();
1826 fVariablesView->SetStackFrameClearPending();
1827 return;
1831 _SetActiveStackTrace(stackTrace);
1835 void
1836 TeamWindow::_HandleImageDebugInfoChanged(image_id imageID)
1838 TRACE_GUI("TeamWindow::_HandleImageDebugInfoChanged(%" B_PRId32 ")\n",
1839 imageID);
1841 // We're only interested in the currently selected thread
1842 if (fActiveImage == NULL || imageID != fActiveImage->ID())
1843 return;
1845 AutoLocker< ::Team> locker(fTeam);
1847 ImageDebugInfo* imageDebugInfo = fActiveImage != NULL
1848 ? fActiveImage->GetImageDebugInfo() : NULL;
1850 TRACE_GUI(" image debug info: %p\n", imageDebugInfo);
1852 BReference<ImageDebugInfo> imageDebugInfoReference(imageDebugInfo);
1853 // hold a reference until we've set it
1855 locker.Unlock();
1857 fImageFunctionsView->SetImageDebugInfo(imageDebugInfo);
1861 void
1862 TeamWindow::_HandleSourceCodeChanged()
1864 // If we don't have an active function anymore, the message is obsolete.
1865 if (fActiveFunction == NULL)
1866 return;
1868 // get a reference to the source code
1869 AutoLocker< ::Team> locker(fTeam);
1871 SourceCode* sourceCode = NULL;
1872 if (fActiveFunction->GetFunction()->SourceCodeState()
1873 == FUNCTION_SOURCE_LOADED) {
1874 sourceCode = fActiveFunction->GetFunction()->GetSourceCode();
1875 } else
1876 sourceCode = fActiveFunction->GetSourceCode();
1878 BReference<SourceCode> sourceCodeReference(sourceCode);
1880 locker.Unlock();
1882 _SetActiveSourceCode(sourceCode);
1886 void
1887 TeamWindow::_HandleUserBreakpointChanged(UserBreakpoint* breakpoint)
1889 fSourceView->UserBreakpointChanged(breakpoint);
1890 fBreakpointsView->UserBreakpointChanged(breakpoint);
1894 void
1895 TeamWindow::_HandleWatchpointChanged(Watchpoint* watchpoint)
1897 fBreakpointsView->WatchpointChanged(watchpoint);
1901 status_t
1902 TeamWindow::_RetrieveMatchingSourceWorker(void* arg)
1904 TeamWindow* window = (TeamWindow*)arg;
1906 BStringList* entries = new(std::nothrow) BStringList();
1907 if (entries == NULL)
1908 return B_NO_MEMORY;
1909 ObjectDeleter<BStringList> stringListDeleter(entries);
1911 if (!window->Lock())
1912 return B_BAD_VALUE;
1914 BString path;
1915 window->fActiveFunction->GetFunctionDebugInfo()->SourceFile()
1916 ->GetPath(path);
1917 window->Unlock();
1919 status_t error = window->_RetrieveMatchingSourceEntries(path, entries);
1921 entries->Sort();
1922 BMessenger messenger(window);
1923 if (messenger.IsValid() && messenger.LockTarget()) {
1924 if (window->fActiveSourceWorker == find_thread(NULL)) {
1925 BMessage message(MSG_SOURCE_ENTRY_QUERY_COMPLETE);
1926 message.AddInt32("error", error);
1927 message.AddPointer("entries", entries);
1928 if (messenger.SendMessage(&message) == B_OK)
1929 stringListDeleter.Detach();
1931 window->Unlock();
1934 return B_OK;
1938 void
1939 TeamWindow::_HandleResolveMissingSourceFile(entry_ref& locatedPath)
1941 if (fActiveFunction != NULL) {
1942 LocatableFile* sourceFile = fActiveFunction->GetFunctionDebugInfo()
1943 ->SourceFile();
1944 if (sourceFile != NULL) {
1945 BString sourcePath;
1946 sourceFile->GetPath(sourcePath);
1947 BString sourceFileName(sourcePath);
1948 int32 index = sourcePath.FindLast('/');
1949 if (index >= 0)
1950 sourceFileName.Remove(0, index + 1);
1952 BPath targetFilePath(&locatedPath);
1953 if (targetFilePath.InitCheck() != B_OK)
1954 return;
1956 if (strcmp(sourceFileName.String(), targetFilePath.Leaf()) != 0) {
1957 BString message;
1958 message.SetToFormat("The names of source file '%s' and located"
1959 " file '%s' differ. Use file anyway?",
1960 sourceFileName.String(), targetFilePath.Leaf());
1961 BAlert* alert = new(std::nothrow) BAlert(
1962 "Source path mismatch", message.String(), "Cancel", "Use");
1963 if (alert == NULL)
1964 return;
1966 int32 choice = alert->Go();
1967 if (choice <= 0)
1968 return;
1971 LocatableFile* foundSourceFile = fActiveSourceCode
1972 ->GetSourceFile();
1973 if (foundSourceFile != NULL)
1974 fListener->SourceEntryInvalidateRequested(foundSourceFile);
1975 fListener->SourceEntryLocateRequested(sourcePath,
1976 targetFilePath.Path());
1977 fListener->FunctionSourceCodeRequested(fActiveFunction);
1983 void
1984 TeamWindow::_HandleLocateSourceRequest(BStringList* entries)
1986 if (fActiveFunction == NULL)
1987 return;
1988 else if (fActiveFunction->GetFunctionDebugInfo()->SourceFile() == NULL)
1989 return;
1990 else if (fActiveSourceCode == NULL)
1991 return;
1992 else if (fActiveFunction->GetFunction()->SourceCodeState()
1993 == FUNCTION_SOURCE_NOT_LOADED) {
1994 return;
1997 if (entries == NULL) {
1998 if (fActiveSourceWorker < 0) {
1999 fActiveSourceWorker = spawn_thread(&_RetrieveMatchingSourceWorker,
2000 "source file query worker", B_NORMAL_PRIORITY, this);
2001 if (fActiveSourceWorker > 0)
2002 resume_thread(fActiveSourceWorker);
2004 return;
2007 int32 count = entries->CountStrings();
2008 if (count > 0) {
2009 BPopUpMenu* menu = new(std::nothrow) BPopUpMenu("");
2010 if (menu == NULL)
2011 return;
2013 BPrivate::ObjectDeleter<BPopUpMenu> menuDeleter(menu);
2014 BMenuItem* item = NULL;
2015 for (int32 i = 0; i < count; i++) {
2016 item = new(std::nothrow) BMenuItem(entries->StringAt(i).String(),
2017 NULL);
2018 if (item == NULL || !menu->AddItem(item)) {
2019 delete item;
2020 return;
2024 menu->AddSeparatorItem();
2025 BMenuItem* manualItem = new(std::nothrow) BMenuItem(
2026 "Locate manually" B_UTF8_ELLIPSIS, NULL);
2027 if (manualItem == NULL || !menu->AddItem(manualItem)) {
2028 delete manualItem;
2029 return;
2032 BPoint point;
2033 fSourcePathView->GetMouse(&point, NULL, false);
2034 fSourcePathView->ConvertToScreen(&point);
2035 item = menu->Go(point, false, true);
2036 if (item == NULL)
2037 return;
2038 else if (item != manualItem) {
2039 // if the user picks to locate the entry manually,
2040 // then fall through to the usual file panel logic
2041 // as if we'd found no matches at all.
2042 entry_ref ref;
2043 if (get_ref_for_path(item->Label(), &ref) == B_OK) {
2044 _HandleResolveMissingSourceFile(ref);
2045 return;
2050 try {
2051 if (fFilePanel == NULL) {
2052 fFilePanel = new BFilePanel(B_OPEN_PANEL,
2053 new BMessenger(this));
2055 fFilePanel->Show();
2056 } catch (...) {
2057 delete fFilePanel;
2058 fFilePanel = NULL;
2063 status_t
2064 TeamWindow::_RetrieveMatchingSourceEntries(const BString& path,
2065 BStringList* _entries)
2067 BPath filePath(path);
2068 status_t error = filePath.InitCheck();
2069 if (error != B_OK)
2070 return error;
2072 _entries->MakeEmpty();
2074 BQuery query;
2075 BString predicate;
2076 query.PushAttr("name");
2077 query.PushString(filePath.Leaf());
2078 query.PushOp(B_EQ);
2080 error = query.GetPredicate(&predicate);
2081 if (error != B_OK)
2082 return error;
2084 BVolumeRoster roster;
2085 BVolume volume;
2086 while (roster.GetNextVolume(&volume) == B_OK) {
2087 if (!volume.KnowsQuery())
2088 continue;
2090 if (query.SetVolume(&volume) != B_OK)
2091 continue;
2093 error = query.SetPredicate(predicate.String());
2094 if (error != B_OK)
2095 continue;
2097 if (query.Fetch() != B_OK)
2098 continue;
2100 entry_ref ref;
2101 while (query.GetNextRef(&ref) == B_OK) {
2102 filePath.SetTo(&ref);
2103 _entries->Add(filePath.Path());
2106 query.Clear();
2109 return B_OK;
2113 status_t
2114 TeamWindow::_SaveInspectorSettings(const BMessage* settings)
2116 if (fUiSettings.AddSettings("inspectorWindow", *settings) != B_OK)
2117 return B_NO_MEMORY;
2119 return B_OK;
2123 status_t
2124 TeamWindow::_GetActiveSourceLanguage(SourceLanguage*& _language)
2126 AutoLocker< ::Team> locker(fTeam);
2128 if (!locker.IsLocked())
2129 return B_ERROR;
2131 if (fActiveSourceCode != NULL) {
2132 _language = fActiveSourceCode->GetSourceLanguage();
2133 _language->AcquireReference();
2134 return B_OK;
2137 // if we made it this far, we were unable to acquire a source
2138 // language corresponding to the active function. As such,
2139 // try to fall back to the C++-style parser.
2140 _language = new(std::nothrow) CppLanguage();
2141 if (_language == NULL)
2142 return B_NO_MEMORY;
2144 return B_OK;