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