1/*
2 * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2010-2011, Rene Gollent, rene@gollent.com.
4 * Distributed under the terms of the MIT License.
5 */
6
7
8#include "TeamDebugger.h"
9
10#include <stdarg.h>
11#include <stdio.h>
12
13#include <new>
14
15#include <Entry.h>
16#include <Message.h>
17
18#include <AutoLocker.h>
19
20#include "debug_utils.h"
21
22#include "BreakpointManager.h"
23#include "BreakpointSetting.h"
24#include "CpuState.h"
25#include "DebuggerInterface.h"
26#include "DebugReportGenerator.h"
27#include "FileManager.h"
28#include "Function.h"
29#include "FunctionID.h"
30#include "ImageDebugInfo.h"
31#include "Jobs.h"
32#include "LocatableFile.h"
33#include "MessageCodes.h"
34#include "SettingsManager.h"
35#include "SourceCode.h"
36#include "SpecificImageDebugInfo.h"
37#include "StackFrame.h"
38#include "StackFrameValues.h"
39#include "Statement.h"
40#include "SymbolInfo.h"
41#include "TeamDebugInfo.h"
42#include "TeamMemoryBlock.h"
43#include "TeamMemoryBlockManager.h"
44#include "TeamSettings.h"
45#include "TeamUiSettings.h"
46#include "Tracing.h"
47#include "ValueNode.h"
48#include "ValueNodeContainer.h"
49#include "Variable.h"
50#include "WatchpointManager.h"
51
52
53// #pragma mark - ImageHandler
54
55
56struct TeamDebugger::ImageHandler : public BReferenceable,
57	private LocatableFile::Listener {
58public:
59	ImageHandler(TeamDebugger* teamDebugger, Image* image)
60		:
61		fTeamDebugger(teamDebugger),
62		fImage(image)
63	{
64		fImage->AcquireReference();
65		if (fImage->ImageFile() != NULL)
66			fImage->ImageFile()->AddListener(this);
67	}
68
69	~ImageHandler()
70	{
71		if (fImage->ImageFile() != NULL)
72			fImage->ImageFile()->RemoveListener(this);
73		fImage->ReleaseReference();
74	}
75
76	Image* GetImage() const
77	{
78		return fImage;
79	}
80
81	image_id ImageID() const
82	{
83		return fImage->ID();
84	}
85
86private:
87	// LocatableFile::Listener
88	virtual void LocatableFileChanged(LocatableFile* file)
89	{
90		BMessage message(MSG_IMAGE_FILE_CHANGED);
91		message.AddInt32("image", fImage->ID());
92		fTeamDebugger->PostMessage(&message);
93	}
94
95private:
96	TeamDebugger*	fTeamDebugger;
97	Image*			fImage;
98
99public:
100	ImageHandler*	fNext;
101};
102
103
104// #pragma mark - ImageHandlerHashDefinition
105
106
107struct TeamDebugger::ImageHandlerHashDefinition {
108	typedef image_id		KeyType;
109	typedef	ImageHandler	ValueType;
110
111	size_t HashKey(image_id key) const
112	{
113		return (size_t)key;
114	}
115
116	size_t Hash(const ImageHandler* value) const
117	{
118		return HashKey(value->ImageID());
119	}
120
121	bool Compare(image_id key, const ImageHandler* value) const
122	{
123		return value->ImageID() == key;
124	}
125
126	ImageHandler*& GetLink(ImageHandler* value) const
127	{
128		return value->fNext;
129	}
130};
131
132
133// #pragma mark - ImageInfoPendingThread
134
135
136struct TeamDebugger::ImageInfoPendingThread {
137public:
138	ImageInfoPendingThread(image_id image, thread_id thread)
139		:
140		fImage(image),
141		fThread(thread)
142	{
143	}
144
145	~ImageInfoPendingThread()
146	{
147	}
148
149	image_id ImageID() const
150	{
151		return fImage;
152	}
153
154	thread_id ThreadID() const
155	{
156		return fThread;
157	}
158
159private:
160	image_id				fImage;
161	thread_id				fThread;
162
163public:
164	ImageInfoPendingThread*	fNext;
165};
166
167
168// #pragma mark - ImageHandlerHashDefinition
169
170
171struct TeamDebugger::ImageInfoPendingThreadHashDefinition {
172	typedef image_id				KeyType;
173	typedef	ImageInfoPendingThread	ValueType;
174
175	size_t HashKey(image_id key) const
176	{
177		return (size_t)key;
178	}
179
180	size_t Hash(const ImageInfoPendingThread* value) const
181	{
182		return HashKey(value->ImageID());
183	}
184
185	bool Compare(image_id key, const ImageInfoPendingThread* value) const
186	{
187		return value->ImageID() == key;
188	}
189
190	ImageInfoPendingThread*& GetLink(ImageInfoPendingThread* value) const
191	{
192		return value->fNext;
193	}
194};
195
196
197// #pragma mark - TeamDebugger
198
199
200TeamDebugger::TeamDebugger(Listener* listener, UserInterface* userInterface,
201	SettingsManager* settingsManager)
202	:
203	BLooper("team debugger"),
204	fListener(listener),
205	fSettingsManager(settingsManager),
206	fTeam(NULL),
207	fTeamID(-1),
208	fImageHandlers(NULL),
209	fImageInfoPendingThreads(NULL),
210	fDebuggerInterface(NULL),
211	fFileManager(NULL),
212	fWorker(NULL),
213	fBreakpointManager(NULL),
214	fWatchpointManager(NULL),
215	fMemoryBlockManager(NULL),
216	fReportGenerator(NULL),
217	fDebugEventListener(-1),
218	fUserInterface(userInterface),
219	fTerminating(false),
220	fKillTeamOnQuit(false)
221{
222	fUserInterface->AcquireReference();
223}
224
225
226TeamDebugger::~TeamDebugger()
227{
228	if (fTeam != NULL)
229		_SaveSettings();
230
231	AutoLocker<BLooper> locker(this);
232
233	fTerminating = true;
234
235	if (fDebuggerInterface != NULL) {
236		fDebuggerInterface->Close(fKillTeamOnQuit);
237		fDebuggerInterface->ReleaseReference();
238	}
239
240	if (fWorker != NULL)
241		fWorker->ShutDown();
242
243	locker.Unlock();
244
245	if (fDebugEventListener >= 0)
246		wait_for_thread(fDebugEventListener, NULL);
247
248	// terminate UI
249	if (fUserInterface != NULL) {
250		fUserInterface->Terminate();
251		fUserInterface->ReleaseReference();
252	}
253
254	ThreadHandler* threadHandler = fThreadHandlers.Clear(true);
255	while (threadHandler != NULL) {
256		ThreadHandler* next = threadHandler->fNext;
257		threadHandler->ReleaseReference();
258		threadHandler = next;
259	}
260
261	if (fImageHandlers != NULL) {
262		ImageHandler* imageHandler = fImageHandlers->Clear(true);
263		while (imageHandler != NULL) {
264			ImageHandler* next = imageHandler->fNext;
265			imageHandler->ReleaseReference();
266			imageHandler = next;
267		}
268	}
269
270	delete fImageHandlers;
271
272	if (fImageInfoPendingThreads != NULL) {
273		ImageInfoPendingThread* thread = fImageInfoPendingThreads->Clear(true);
274		while (thread != NULL) {
275			ImageInfoPendingThread* next = thread->fNext;
276			delete thread;
277			thread = next;
278		}
279	}
280
281	if (fReportGenerator != NULL) {
282		fReportGenerator->Lock();
283		fReportGenerator->Quit();
284	}
285
286	delete fImageInfoPendingThreads;
287
288	delete fBreakpointManager;
289	delete fWatchpointManager;
290	delete fMemoryBlockManager;
291	delete fWorker;
292	delete fTeam;
293	delete fFileManager;
294
295	fListener->TeamDebuggerQuit(this);
296}
297
298
299status_t
300TeamDebugger::Init(team_id teamID, thread_id threadID, bool stopInMain)
301{
302	bool targetIsLocal = true;
303		// TODO: Support non-local targets!
304
305	// the first thing we want to do when running
306	PostMessage(MSG_LOAD_SETTINGS);
307
308	fTeamID = teamID;
309
310	// create debugger interface
311	fDebuggerInterface = new(std::nothrow) DebuggerInterface(fTeamID);
312	if (fDebuggerInterface == NULL)
313		return B_NO_MEMORY;
314
315	status_t error = fDebuggerInterface->Init();
316	if (error != B_OK)
317		return error;
318
319	// create file manager
320	fFileManager = new(std::nothrow) FileManager;
321	if (fFileManager == NULL)
322		return B_NO_MEMORY;
323
324	error = fFileManager->Init(targetIsLocal);
325	if (error != B_OK)
326		return error;
327
328	// create team debug info
329	TeamDebugInfo* teamDebugInfo = new(std::nothrow) TeamDebugInfo(
330		fDebuggerInterface, fDebuggerInterface->GetArchitecture(),
331		fFileManager);
332	if (teamDebugInfo == NULL)
333		return B_NO_MEMORY;
334	BReference<TeamDebugInfo> teamDebugInfoReference(teamDebugInfo);
335
336	error = teamDebugInfo->Init();
337	if (error != B_OK)
338		return error;
339
340	// check whether the team exists at all
341	// TODO: That should be done in the debugger interface!
342	team_info teamInfo;
343	error = get_team_info(fTeamID, &teamInfo);
344	if (error != B_OK)
345		return error;
346
347	// create a team object
348	fTeam = new(std::nothrow) ::Team(fTeamID, fDebuggerInterface,
349		fDebuggerInterface->GetArchitecture(), teamDebugInfo,
350		teamDebugInfo);
351	if (fTeam == NULL)
352		return B_NO_MEMORY;
353
354	error = fTeam->Init();
355	if (error != B_OK)
356		return error;
357	fTeam->SetName(teamInfo.args);
358		// TODO: Set a better name!
359
360	fTeam->AddListener(this);
361
362	// init thread handler table
363	error = fThreadHandlers.Init();
364	if (error != B_OK)
365		return error;
366
367	// create image handler table
368	fImageHandlers = new(std::nothrow) ImageHandlerTable;
369	if (fImageHandlers == NULL)
370		return B_NO_MEMORY;
371
372	error = fImageHandlers->Init();
373	if (error != B_OK)
374		return error;
375
376	fImageInfoPendingThreads = new(std::nothrow) ImageInfoPendingThreadTable;
377	if (fImageInfoPendingThreads == NULL)
378		return B_NO_MEMORY;
379
380	// create our worker
381	fWorker = new(std::nothrow) Worker;
382	if (fWorker == NULL)
383		return B_NO_MEMORY;
384
385	error = fWorker->Init();
386	if (error != B_OK)
387		return error;
388
389	// create the breakpoint manager
390	fBreakpointManager = new(std::nothrow) BreakpointManager(fTeam,
391		fDebuggerInterface);
392	if (fBreakpointManager == NULL)
393		return B_NO_MEMORY;
394
395	error = fBreakpointManager->Init();
396	if (error != B_OK)
397		return error;
398
399	// create the watchpoint manager
400	fWatchpointManager = new(std::nothrow) WatchpointManager(fTeam,
401		fDebuggerInterface);
402	if (fWatchpointManager == NULL)
403		return B_NO_MEMORY;
404
405	error = fWatchpointManager->Init();
406	if (error != B_OK)
407		return error;
408
409	// create the memory block manager
410	fMemoryBlockManager = new(std::nothrow) TeamMemoryBlockManager();
411	if (fMemoryBlockManager == NULL)
412		return B_NO_MEMORY;
413
414	error = fMemoryBlockManager->Init();
415	if (error != B_OK)
416		return error;
417
418	// create the debug report generator
419	fReportGenerator = new(std::nothrow) DebugReportGenerator(fTeam, this);
420	if (fReportGenerator == NULL)
421		return B_NO_MEMORY;
422
423	error = fReportGenerator->Init();
424	if (error != B_OK)
425		return error;
426
427	// set team debugging flags
428	fDebuggerInterface->SetTeamDebuggingFlags(
429		B_TEAM_DEBUG_THREADS | B_TEAM_DEBUG_IMAGES);
430
431	// get the initial state of the team
432	AutoLocker< ::Team> teamLocker(fTeam);
433
434	ThreadHandler* mainThreadHandler = NULL;
435	{
436		BObjectList<ThreadInfo> threadInfos(20, true);
437		status_t error = fDebuggerInterface->GetThreadInfos(threadInfos);
438		for (int32 i = 0; ThreadInfo* info = threadInfos.ItemAt(i); i++) {
439			::Thread* thread;
440			error = fTeam->AddThread(*info, &thread);
441			if (error != B_OK)
442				return error;
443
444			ThreadHandler* handler = new(std::nothrow) ThreadHandler(thread,
445				fWorker, fDebuggerInterface,
446				fBreakpointManager);
447			if (handler == NULL)
448				return B_NO_MEMORY;
449
450			fThreadHandlers.Insert(handler);
451
452			if (thread->IsMainThread())
453				mainThreadHandler = handler;
454
455			handler->Init();
456		}
457	}
458
459	Image* appImage = NULL;
460	{
461		BObjectList<ImageInfo> imageInfos(20, true);
462		status_t error = fDebuggerInterface->GetImageInfos(imageInfos);
463		for (int32 i = 0; ImageInfo* info = imageInfos.ItemAt(i); i++) {
464			Image* image;
465			error = _AddImage(*info, &image);
466			if (error != B_OK)
467				return error;
468			if (image->Type() == B_APP_IMAGE)
469				appImage = image;
470
471			ImageDebugInfoRequested(image);
472		}
473	}
474
475	// create the debug event listener
476	char buffer[128];
477	snprintf(buffer, sizeof(buffer), "team %" B_PRId32 " debug listener",
478		fTeamID);
479	fDebugEventListener = spawn_thread(_DebugEventListenerEntry, buffer,
480		B_NORMAL_PRIORITY, this);
481	if (fDebugEventListener < 0)
482		return fDebugEventListener;
483
484	resume_thread(fDebugEventListener);
485
486	// run looper
487	thread_id looperThread = Run();
488	if (looperThread < 0)
489		return looperThread;
490
491	// init the UI
492	error = fUserInterface->Init(fTeam, this);
493	if (error != B_OK) {
494		ERROR("Error: Failed to init the UI: %s\n", strerror(error));
495		return error;
496	}
497
498	// if requested, stop the given thread
499	if (threadID >= 0) {
500		if (stopInMain) {
501			SymbolInfo symbolInfo;
502			if (appImage != NULL && mainThreadHandler != NULL
503				&& fDebuggerInterface->GetSymbolInfo(
504					fTeam->ID(), appImage->ID(), "main", B_SYMBOL_TYPE_TEXT,
505					symbolInfo) == B_OK) {
506				mainThreadHandler->SetBreakpointAndRun(symbolInfo.Address());
507			}
508		} else {
509			debug_thread(threadID);
510				// TODO: Superfluous, if the thread is already stopped.
511		}
512	}
513
514	fListener->TeamDebuggerStarted(this);
515
516	return B_OK;
517}
518
519
520void
521TeamDebugger::Activate()
522{
523	fUserInterface->Show();
524}
525
526
527void
528TeamDebugger::MessageReceived(BMessage* message)
529{
530	switch (message->what) {
531		case MSG_THREAD_RUN:
532		case MSG_THREAD_STOP:
533		case MSG_THREAD_STEP_OVER:
534		case MSG_THREAD_STEP_INTO:
535		case MSG_THREAD_STEP_OUT:
536		{
537			int32 threadID;
538			if (message->FindInt32("thread", &threadID) != B_OK)
539				break;
540
541			if (ThreadHandler* handler = _GetThreadHandler(threadID)) {
542				handler->HandleThreadAction(message->what);
543				handler->ReleaseReference();
544			}
545			break;
546		}
547
548		case MSG_SET_BREAKPOINT:
549		case MSG_CLEAR_BREAKPOINT:
550		{
551			UserBreakpoint* breakpoint = NULL;
552			BReference<UserBreakpoint> breakpointReference;
553			uint64 address = 0;
554
555			if (message->FindPointer("breakpoint", (void**)&breakpoint) == B_OK)
556				breakpointReference.SetTo(breakpoint, true);
557			else if (message->FindUInt64("address", &address) != B_OK)
558				break;
559
560			if (message->what == MSG_SET_BREAKPOINT) {
561				bool enabled;
562				if (message->FindBool("enabled", &enabled) != B_OK)
563					enabled = true;
564
565				if (breakpoint != NULL)
566					_HandleSetUserBreakpoint(breakpoint, enabled);
567				else
568					_HandleSetUserBreakpoint(address, enabled);
569			} else {
570				if (breakpoint != NULL)
571					_HandleClearUserBreakpoint(breakpoint);
572				else
573					_HandleClearUserBreakpoint(address);
574			}
575
576			break;
577		}
578
579		case MSG_SET_WATCHPOINT:
580		case MSG_CLEAR_WATCHPOINT:
581		{
582			Watchpoint* watchpoint = NULL;
583			BReference<Watchpoint> watchpointReference;
584			uint64 address = 0;
585			uint32 type = 0;
586			int32 length = 0;
587
588			if (message->FindPointer("watchpoint", (void**)&watchpoint)
589					== B_OK) {
590				watchpointReference.SetTo(watchpoint, true);
591			} else if (message->FindUInt64("address", &address) != B_OK)
592				break;
593
594			if (message->what == MSG_SET_WATCHPOINT) {
595				if (watchpoint == NULL && (message->FindUInt32("type", &type)
596							!= B_OK
597						|| message->FindInt32("length", &length) != B_OK)) {
598					break;
599				}
600
601				bool enabled;
602				if (message->FindBool("enabled", &enabled) != B_OK)
603					enabled = true;
604
605				if (watchpoint != NULL)
606					_HandleSetWatchpoint(watchpoint, enabled);
607				else
608					_HandleSetWatchpoint(address, type, length, enabled);
609			} else {
610				if (watchpoint != NULL)
611					_HandleClearWatchpoint(watchpoint);
612				else
613					_HandleClearWatchpoint(address);
614			}
615
616			break;
617		}
618
619		case MSG_INSPECT_ADDRESS:
620		{
621			TeamMemoryBlock::Listener* listener;
622			if (message->FindPointer("listener",
623				reinterpret_cast<void **>(&listener)) != B_OK) {
624				break;
625			}
626
627			target_addr_t address;
628			if (message->FindUInt64("address",
629				&address) == B_OK) {
630				_HandleInspectAddress(address, listener);
631			}
632			break;
633		}
634
635		case MSG_GENERATE_DEBUG_REPORT:
636		{
637			fReportGenerator->PostMessage(message);
638			break;
639		}
640
641		case MSG_THREAD_STATE_CHANGED:
642		{
643			int32 threadID;
644			if (message->FindInt32("thread", &threadID) != B_OK)
645				break;
646
647			if (ThreadHandler* handler = _GetThreadHandler(threadID)) {
648				handler->HandleThreadStateChanged();
649				handler->ReleaseReference();
650			}
651			break;
652		}
653		case MSG_THREAD_CPU_STATE_CHANGED:
654		{
655			int32 threadID;
656			if (message->FindInt32("thread", &threadID) != B_OK)
657				break;
658
659			if (ThreadHandler* handler = _GetThreadHandler(threadID)) {
660				handler->HandleCpuStateChanged();
661				handler->ReleaseReference();
662			}
663			break;
664		}
665		case MSG_THREAD_STACK_TRACE_CHANGED:
666		{
667			int32 threadID;
668			if (message->FindInt32("thread", &threadID) != B_OK)
669				break;
670
671			if (ThreadHandler* handler = _GetThreadHandler(threadID)) {
672				handler->HandleStackTraceChanged();
673				handler->ReleaseReference();
674			}
675			break;
676		}
677
678		case MSG_IMAGE_DEBUG_INFO_CHANGED:
679		{
680			int32 imageID;
681			if (message->FindInt32("image", &imageID) != B_OK)
682				break;
683
684			_HandleImageDebugInfoChanged(imageID);
685			break;
686		}
687
688		case MSG_IMAGE_FILE_CHANGED:
689		{
690			int32 imageID;
691			if (message->FindInt32("image", &imageID) != B_OK)
692				break;
693
694			_HandleImageFileChanged(imageID);
695			break;
696		}
697
698		case MSG_DEBUGGER_EVENT:
699		{
700			DebugEvent* event;
701			if (message->FindPointer("event", (void**)&event) != B_OK)
702				break;
703
704			_HandleDebuggerMessage(event);
705			delete event;
706			break;
707		}
708
709		case MSG_LOAD_SETTINGS:
710			_LoadSettings();
711			Activate();
712			break;
713
714		default:
715			BLooper::MessageReceived(message);
716			break;
717	}
718}
719
720
721void
722TeamDebugger::SourceEntryLocateRequested(const char* sourcePath,
723	const char* locatedPath)
724{
725	AutoLocker<FileManager> locker(fFileManager);
726	fFileManager->SourceEntryLocated(sourcePath, locatedPath);
727}
728
729
730void
731TeamDebugger::FunctionSourceCodeRequested(FunctionInstance* functionInstance)
732{
733	Function* function = functionInstance->GetFunction();
734
735	// mark loading
736	AutoLocker< ::Team> locker(fTeam);
737
738	if (functionInstance->SourceCodeState() != FUNCTION_SOURCE_NOT_LOADED)
739		return;
740	if (function->SourceCodeState() == FUNCTION_SOURCE_LOADED)
741		return;
742
743	functionInstance->SetSourceCode(NULL, FUNCTION_SOURCE_LOADING);
744
745	bool loadForFunction = false;
746	if (function->SourceCodeState() == FUNCTION_SOURCE_NOT_LOADED) {
747		loadForFunction = true;
748		function->SetSourceCode(NULL, FUNCTION_SOURCE_LOADING);
749	}
750
751	locker.Unlock();
752
753	// schedule the job
754	if (fWorker->ScheduleJob(
755			new(std::nothrow) LoadSourceCodeJob(fDebuggerInterface,
756				fDebuggerInterface->GetArchitecture(), fTeam, functionInstance,
757					loadForFunction),
758			this) != B_OK) {
759		// scheduling failed -- mark unavailable
760		locker.Lock();
761		function->SetSourceCode(NULL, FUNCTION_SOURCE_UNAVAILABLE);
762		locker.Unlock();
763	}
764}
765
766
767void
768TeamDebugger::ImageDebugInfoRequested(Image* image)
769{
770	LoadImageDebugInfoJob::ScheduleIfNecessary(fWorker, image);
771}
772
773
774void
775TeamDebugger::ValueNodeValueRequested(CpuState* cpuState,
776	ValueNodeContainer* container, ValueNode* valueNode)
777{
778	AutoLocker<ValueNodeContainer> containerLocker(container);
779	if (valueNode->Container() != container)
780		return;
781
782	// check whether a job is already in progress
783	AutoLocker<Worker> workerLocker(fWorker);
784	SimpleJobKey jobKey(valueNode, JOB_TYPE_RESOLVE_VALUE_NODE_VALUE);
785	if (fWorker->GetJob(jobKey) != NULL)
786		return;
787	workerLocker.Unlock();
788
789	// schedule the job
790	status_t error = fWorker->ScheduleJob(
791		new(std::nothrow) ResolveValueNodeValueJob(fDebuggerInterface,
792			fDebuggerInterface->GetArchitecture(), cpuState,
793			fTeam->GetTeamTypeInformation(), container,	valueNode),	this);
794	if (error != B_OK) {
795		// scheduling failed -- set the value to invalid
796		valueNode->SetLocationAndValue(NULL, NULL, error);
797	}
798}
799
800
801void
802TeamDebugger::ThreadActionRequested(thread_id threadID,
803	uint32 action)
804{
805	BMessage message(action);
806	message.AddInt32("thread", threadID);
807	PostMessage(&message);
808}
809
810
811void
812TeamDebugger::SetBreakpointRequested(target_addr_t address, bool enabled)
813{
814	BMessage message(MSG_SET_BREAKPOINT);
815	message.AddUInt64("address", (uint64)address);
816	message.AddBool("enabled", enabled);
817	PostMessage(&message);
818}
819
820
821void
822TeamDebugger::SetBreakpointEnabledRequested(UserBreakpoint* breakpoint,
823	bool enabled)
824{
825	BMessage message(MSG_SET_BREAKPOINT);
826	BReference<UserBreakpoint> breakpointReference(breakpoint);
827	if (message.AddPointer("breakpoint", breakpoint) == B_OK
828		&& message.AddBool("enabled", enabled) == B_OK
829		&& PostMessage(&message) == B_OK) {
830		breakpointReference.Detach();
831	}
832}
833
834
835void
836TeamDebugger::ClearBreakpointRequested(target_addr_t address)
837{
838	BMessage message(MSG_CLEAR_BREAKPOINT);
839	message.AddUInt64("address", (uint64)address);
840	PostMessage(&message);
841}
842
843
844void
845TeamDebugger::ClearBreakpointRequested(UserBreakpoint* breakpoint)
846{
847	BMessage message(MSG_CLEAR_BREAKPOINT);
848	BReference<UserBreakpoint> breakpointReference(breakpoint);
849	if (message.AddPointer("breakpoint", breakpoint) == B_OK
850		&& PostMessage(&message) == B_OK) {
851		breakpointReference.Detach();
852	}
853}
854
855
856void
857TeamDebugger::SetWatchpointRequested(target_addr_t address, uint32 type,
858	int32 length, bool enabled)
859{
860	BMessage message(MSG_SET_WATCHPOINT);
861	message.AddUInt64("address", (uint64)address);
862	message.AddUInt32("type", type);
863	message.AddInt32("length", length);
864	message.AddBool("enabled", enabled);
865	PostMessage(&message);
866}
867
868
869void
870TeamDebugger::SetWatchpointEnabledRequested(Watchpoint* watchpoint,
871	bool enabled)
872{
873	BMessage message(MSG_SET_WATCHPOINT);
874	BReference<Watchpoint> watchpointReference(watchpoint);
875	if (message.AddPointer("watchpoint", watchpoint) == B_OK
876		&& message.AddBool("enabled", enabled) == B_OK
877		&& PostMessage(&message) == B_OK) {
878		watchpointReference.Detach();
879	}
880}
881
882
883void
884TeamDebugger::ClearWatchpointRequested(target_addr_t address)
885{
886	BMessage message(MSG_CLEAR_WATCHPOINT);
887	message.AddUInt64("address", (uint64)address);
888	PostMessage(&message);
889}
890
891
892void
893TeamDebugger::ClearWatchpointRequested(Watchpoint* watchpoint)
894{
895	BMessage message(MSG_CLEAR_WATCHPOINT);
896	BReference<Watchpoint> watchpointReference(watchpoint);
897	if (message.AddPointer("watchpoint", watchpoint) == B_OK
898		&& PostMessage(&message) == B_OK) {
899		watchpointReference.Detach();
900	}
901}
902
903
904void
905TeamDebugger::InspectRequested(target_addr_t address,
906	TeamMemoryBlock::Listener *listener)
907{
908	BMessage message(MSG_INSPECT_ADDRESS);
909	message.AddUInt64("address", address);
910	message.AddPointer("listener", listener);
911	PostMessage(&message);
912}
913
914
915void
916TeamDebugger::DebugReportRequested(entry_ref* targetPath)
917{
918	BMessage message(MSG_GENERATE_DEBUG_REPORT);
919	message.AddRef("target", targetPath);
920	PostMessage(&message);
921}
922
923
924bool
925TeamDebugger::UserInterfaceQuitRequested(QuitOption quitOption)
926{
927	bool askUser = false;
928	switch (quitOption) {
929		case QUIT_OPTION_ASK_USER:
930			askUser = true;
931			break;
932
933		case QUIT_OPTION_ASK_KILL_TEAM:
934			fKillTeamOnQuit = true;
935			break;
936
937		case QUIT_OPTION_ASK_RESUME_TEAM:
938			break;
939	}
940
941	if (askUser) {
942		AutoLocker< ::Team> locker(fTeam);
943		BString name(fTeam->Name());
944		locker.Unlock();
945
946		BString message;
947		message << "What shall be done about the debugged team '";
948		message << name;
949		message << "'?";
950
951		name.Remove(0, name.FindLast('/') + 1);
952
953		BString killLabel("Kill ");
954		killLabel << name;
955
956		BString resumeLabel("Resume ");
957		resumeLabel << name;
958
959		int32 choice = fUserInterface->SynchronouslyAskUser("Quit Debugger",
960			message, killLabel, "Cancel", resumeLabel);
961
962		switch (choice) {
963			case 0:
964				fKillTeamOnQuit = true;
965				break;
966			case 1:
967			case -1:
968				return false;
969			case 2:
970				// Detach from the team and resume and stopped threads.
971				break;
972		}
973	}
974
975	PostMessage(B_QUIT_REQUESTED);
976
977	return true;
978}
979
980
981void
982TeamDebugger::JobDone(Job* job)
983{
984	TRACE_JOBS("TeamDebugger::JobDone(%p)\n", job);
985}
986
987
988void
989TeamDebugger::JobFailed(Job* job)
990{
991	TRACE_JOBS("TeamDebugger::JobFailed(%p)\n", job);
992	// TODO: notify user
993}
994
995
996void
997TeamDebugger::JobAborted(Job* job)
998{
999	TRACE_JOBS("TeamDebugger::JobAborted(%p)\n", job);
1000	// TODO: For a stack frame source loader thread we should reset the
1001	// loading state! Asynchronously due to locking order.
1002}
1003
1004
1005void
1006TeamDebugger::ThreadStateChanged(const ::Team::ThreadEvent& event)
1007{
1008	BMessage message(MSG_THREAD_STATE_CHANGED);
1009	message.AddInt32("thread", event.GetThread()->ID());
1010	PostMessage(&message);
1011}
1012
1013
1014void
1015TeamDebugger::ThreadCpuStateChanged(const ::Team::ThreadEvent& event)
1016{
1017	BMessage message(MSG_THREAD_CPU_STATE_CHANGED);
1018	message.AddInt32("thread", event.GetThread()->ID());
1019	PostMessage(&message);
1020}
1021
1022
1023void
1024TeamDebugger::ThreadStackTraceChanged(const ::Team::ThreadEvent& event)
1025{
1026	BMessage message(MSG_THREAD_STACK_TRACE_CHANGED);
1027	message.AddInt32("thread", event.GetThread()->ID());
1028	PostMessage(&message);
1029}
1030
1031
1032void
1033TeamDebugger::ImageDebugInfoChanged(const ::Team::ImageEvent& event)
1034{
1035	BMessage message(MSG_IMAGE_DEBUG_INFO_CHANGED);
1036	message.AddInt32("image", event.GetImage()->ID());
1037	PostMessage(&message);
1038}
1039
1040
1041/*static*/ status_t
1042TeamDebugger::_DebugEventListenerEntry(void* data)
1043{
1044	return ((TeamDebugger*)data)->_DebugEventListener();
1045}
1046
1047
1048status_t
1049TeamDebugger::_DebugEventListener()
1050{
1051	while (!fTerminating) {
1052		// get the next event
1053		DebugEvent* event;
1054		status_t error = fDebuggerInterface->GetNextDebugEvent(event);
1055		if (error != B_OK)
1056			break;
1057				// TODO: Error handling!
1058
1059		if (event->Team() != fTeamID) {
1060			TRACE_EVENTS("TeamDebugger for team %" B_PRId32 ": received event "
1061				"from team %" B_PRId32 "!\n", fTeamID, event->Team());
1062			continue;
1063		}
1064
1065		BMessage message(MSG_DEBUGGER_EVENT);
1066		if (message.AddPointer("event", event) != B_OK
1067			|| PostMessage(&message) != B_OK) {
1068			// TODO: Continue thread if necessary!
1069			delete event;
1070		}
1071	}
1072
1073	return B_OK;
1074}
1075
1076
1077void
1078TeamDebugger::_HandleDebuggerMessage(DebugEvent* event)
1079{
1080	TRACE_EVENTS("TeamDebugger::_HandleDebuggerMessage(): %" B_PRId32 "\n",
1081		event->EventType());
1082
1083	bool handled = false;
1084
1085	ThreadHandler* handler = _GetThreadHandler(event->Thread());
1086	BReference<ThreadHandler> handlerReference(handler);
1087
1088	switch (event->EventType()) {
1089		case B_DEBUGGER_MESSAGE_THREAD_DEBUGGED:
1090			TRACE_EVENTS("B_DEBUGGER_MESSAGE_THREAD_DEBUGGED: thread: %"
1091				B_PRId32 "\n", event->Thread());
1092
1093			if (handler != NULL) {
1094				handled = handler->HandleThreadDebugged(
1095					dynamic_cast<ThreadDebuggedEvent*>(event));
1096			}
1097			break;
1098		case B_DEBUGGER_MESSAGE_DEBUGGER_CALL:
1099			TRACE_EVENTS("B_DEBUGGER_MESSAGE_DEBUGGER_CALL: thread: %" B_PRId32
1100				"\n", event->Thread());
1101
1102			if (handler != NULL) {
1103				handled = handler->HandleDebuggerCall(
1104					dynamic_cast<DebuggerCallEvent*>(event));
1105			}
1106			break;
1107		case B_DEBUGGER_MESSAGE_BREAKPOINT_HIT:
1108			TRACE_EVENTS("B_DEBUGGER_MESSAGE_BREAKPOINT_HIT: thread: %" B_PRId32
1109				"\n", event->Thread());
1110
1111			if (handler != NULL) {
1112				handled = handler->HandleBreakpointHit(
1113					dynamic_cast<BreakpointHitEvent*>(event));
1114			}
1115			break;
1116		case B_DEBUGGER_MESSAGE_WATCHPOINT_HIT:
1117			TRACE_EVENTS("B_DEBUGGER_MESSAGE_WATCHPOINT_HIT: thread: %" B_PRId32
1118				"\n", event->Thread());
1119
1120			if (handler != NULL) {
1121				handled = handler->HandleWatchpointHit(
1122					dynamic_cast<WatchpointHitEvent*>(event));
1123			}
1124			break;
1125		case B_DEBUGGER_MESSAGE_SINGLE_STEP:
1126			TRACE_EVENTS("B_DEBUGGER_MESSAGE_SINGLE_STEP: thread: %" B_PRId32
1127				"\n", event->Thread());
1128
1129			if (handler != NULL) {
1130				handled = handler->HandleSingleStep(
1131					dynamic_cast<SingleStepEvent*>(event));
1132			}
1133			break;
1134		case B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED:
1135			TRACE_EVENTS("B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED: thread: %"
1136				B_PRId32 "\n", event->Thread());
1137
1138			if (handler != NULL) {
1139				handled = handler->HandleExceptionOccurred(
1140					dynamic_cast<ExceptionOccurredEvent*>(event));
1141			}
1142			break;
1143//		case B_DEBUGGER_MESSAGE_TEAM_CREATED:
1144//printf("B_DEBUGGER_MESSAGE_TEAM_CREATED: team: %ld\n", message.team_created.new_team);
1145//			break;
1146		case B_DEBUGGER_MESSAGE_TEAM_DELETED:
1147			// TODO: Handle!
1148			TRACE_EVENTS("B_DEBUGGER_MESSAGE_TEAM_DELETED: team: %" B_PRId32
1149				"\n", event->Team());
1150			break;
1151		case B_DEBUGGER_MESSAGE_TEAM_EXEC:
1152			TRACE_EVENTS("B_DEBUGGER_MESSAGE_TEAM_EXEC: team: %" B_PRId32 "\n",
1153				event->Team());
1154			// TODO: Handle!
1155			break;
1156		case B_DEBUGGER_MESSAGE_THREAD_CREATED:
1157		{
1158			ThreadCreatedEvent* threadEvent
1159				= dynamic_cast<ThreadCreatedEvent*>(event);
1160			TRACE_EVENTS("B_DEBUGGER_MESSAGE_THREAD_CREATED: thread: %" B_PRId32
1161				"\n", threadEvent->NewThread());
1162			handled = _HandleThreadCreated(threadEvent);
1163			break;
1164		}
1165		case DEBUGGER_MESSAGE_THREAD_RENAMED:
1166		{
1167			ThreadRenamedEvent* threadEvent
1168				= dynamic_cast<ThreadRenamedEvent*>(event);
1169			TRACE_EVENTS("DEBUGGER_MESSAGE_THREAD_RENAMED: thread: %" B_PRId32
1170				" (\"%s\")\n",
1171				threadEvent->RenamedThread(), threadEvent->NewName());
1172			handled = _HandleThreadRenamed(threadEvent);
1173			break;
1174		}
1175		case DEBUGGER_MESSAGE_THREAD_PRIORITY_CHANGED:
1176		{
1177			ThreadPriorityChangedEvent* threadEvent
1178				= dynamic_cast<ThreadPriorityChangedEvent*>(event);
1179			TRACE_EVENTS("B_DEBUGGER_MESSAGE_THREAD_PRIORITY_CHANGED: thread:"
1180				" %" B_PRId32 "\n", threadEvent->ChangedThread());
1181			handled = _HandleThreadPriorityChanged(threadEvent);
1182			break;
1183		}
1184		case B_DEBUGGER_MESSAGE_THREAD_DELETED:
1185			TRACE_EVENTS("B_DEBUGGER_MESSAGE_THREAD_DELETED: thread: %" B_PRId32
1186				"\n", event->Thread());
1187			handled = _HandleThreadDeleted(
1188				dynamic_cast<ThreadDeletedEvent*>(event));
1189			break;
1190		case B_DEBUGGER_MESSAGE_IMAGE_CREATED:
1191		{
1192			ImageCreatedEvent* imageEvent
1193				= dynamic_cast<ImageCreatedEvent*>(event);
1194			TRACE_EVENTS("B_DEBUGGER_MESSAGE_IMAGE_CREATED: image: \"%s\" "
1195				"(%" B_PRId32 ")\n", imageEvent->GetImageInfo().Name().String(),
1196				imageEvent->GetImageInfo().ImageID());
1197			handled = _HandleImageCreated(imageEvent);
1198			break;
1199		}
1200		case B_DEBUGGER_MESSAGE_IMAGE_DELETED:
1201		{
1202			ImageDeletedEvent* imageEvent
1203				= dynamic_cast<ImageDeletedEvent*>(event);
1204			TRACE_EVENTS("B_DEBUGGER_MESSAGE_IMAGE_DELETED: image: \"%s\" "
1205				"(%" B_PRId32 ")\n", imageEvent->GetImageInfo().Name().String(),
1206				imageEvent->GetImageInfo().ImageID());
1207			handled = _HandleImageDeleted(imageEvent);
1208			break;
1209		}
1210		case B_DEBUGGER_MESSAGE_PRE_SYSCALL:
1211		case B_DEBUGGER_MESSAGE_POST_SYSCALL:
1212		case B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED:
1213		case B_DEBUGGER_MESSAGE_PROFILER_UPDATE:
1214		case B_DEBUGGER_MESSAGE_HANDED_OVER:
1215			// not interested
1216			break;
1217		default:
1218			WARNING("TeamDebugger for team %" B_PRId32 ": unknown event type: "
1219				"%" B_PRId32 "\n", fTeamID, event->EventType());
1220			break;
1221	}
1222
1223	if (!handled && event->ThreadStopped())
1224		fDebuggerInterface->ContinueThread(event->Thread());
1225}
1226
1227
1228bool
1229TeamDebugger::_HandleThreadCreated(ThreadCreatedEvent* event)
1230{
1231	AutoLocker< ::Team> locker(fTeam);
1232
1233	ThreadInfo info;
1234	status_t error = fDebuggerInterface->GetThreadInfo(event->NewThread(),
1235		info);
1236	if (error == B_OK) {
1237		::Thread* thread;
1238		fTeam->AddThread(info, &thread);
1239
1240		ThreadHandler* handler = new(std::nothrow) ThreadHandler(thread,
1241			fWorker, fDebuggerInterface,
1242			fBreakpointManager);
1243		if (handler != NULL) {
1244			fThreadHandlers.Insert(handler);
1245			handler->Init();
1246		}
1247	}
1248
1249	return false;
1250}
1251
1252
1253bool
1254TeamDebugger::_HandleThreadRenamed(ThreadRenamedEvent* event)
1255{
1256	AutoLocker< ::Team> locker(fTeam);
1257
1258	::Thread* thread = fTeam->ThreadByID(event->RenamedThread());
1259
1260	if (thread != NULL)
1261		thread->SetName(event->NewName());
1262
1263	return false;
1264}
1265
1266
1267bool
1268TeamDebugger::_HandleThreadPriorityChanged(ThreadPriorityChangedEvent*)
1269{
1270	// TODO: implement once we actually track thread priorities
1271
1272	return false;
1273}
1274
1275
1276bool
1277TeamDebugger::_HandleThreadDeleted(ThreadDeletedEvent* event)
1278{
1279	AutoLocker< ::Team> locker(fTeam);
1280	if (ThreadHandler* handler = fThreadHandlers.Lookup(event->Thread())) {
1281		fThreadHandlers.Remove(handler);
1282		handler->ReleaseReference();
1283	}
1284	fTeam->RemoveThread(event->Thread());
1285	return false;
1286}
1287
1288
1289bool
1290TeamDebugger::_HandleImageCreated(ImageCreatedEvent* event)
1291{
1292	AutoLocker< ::Team> locker(fTeam);
1293	_AddImage(event->GetImageInfo());
1294
1295	ImageInfoPendingThread* info = new(std::nothrow) ImageInfoPendingThread(
1296		event->GetImageInfo().ImageID(), event->Thread());
1297	if (info == NULL)
1298		return false;
1299
1300	fImageInfoPendingThreads->Insert(info);
1301	return true;
1302}
1303
1304
1305bool
1306TeamDebugger::_HandleImageDeleted(ImageDeletedEvent* event)
1307{
1308	AutoLocker< ::Team> locker(fTeam);
1309	fTeam->RemoveImage(event->GetImageInfo().ImageID());
1310
1311	ImageHandler* imageHandler = fImageHandlers->Lookup(
1312		event->GetImageInfo().ImageID());
1313	if (imageHandler == NULL)
1314		return false;
1315
1316	fImageHandlers->Remove(imageHandler);
1317	BReference<ImageHandler> imageHandlerReference(imageHandler, true);
1318	locker.Unlock();
1319
1320	// remove breakpoints in the image
1321	fBreakpointManager->RemoveImageBreakpoints(imageHandler->GetImage());
1322
1323	return false;
1324}
1325
1326
1327void
1328TeamDebugger::_HandleImageDebugInfoChanged(image_id imageID)
1329{
1330	// get the image (via the image handler)
1331	AutoLocker< ::Team> locker(fTeam);
1332	ImageHandler* imageHandler = fImageHandlers->Lookup(imageID);
1333	if (imageHandler == NULL)
1334		return;
1335
1336	Image* image = imageHandler->GetImage();
1337	BReference<Image> imageReference(image);
1338
1339	locker.Unlock();
1340
1341	image_debug_info_state state = image->ImageDebugInfoState();
1342	if (state == IMAGE_DEBUG_INFO_LOADED
1343		|| state == IMAGE_DEBUG_INFO_UNAVAILABLE) {
1344		// update breakpoints in the image
1345		fBreakpointManager->UpdateImageBreakpoints(image);
1346
1347		ImageInfoPendingThread* thread =  fImageInfoPendingThreads
1348			->Lookup(imageID);
1349		if (thread != NULL) {
1350			fDebuggerInterface->ContinueThread(thread->ThreadID());
1351			fImageInfoPendingThreads->Remove(thread);
1352			delete thread;
1353		}
1354	}
1355}
1356
1357
1358void
1359TeamDebugger::_HandleImageFileChanged(image_id imageID)
1360{
1361	TRACE_IMAGES("TeamDebugger::_HandleImageFileChanged(%" B_PRId32 ")\n",
1362		imageID);
1363// TODO: Reload the debug info!
1364}
1365
1366
1367void
1368TeamDebugger::_HandleSetUserBreakpoint(target_addr_t address, bool enabled)
1369{
1370	TRACE_CONTROL("TeamDebugger::_HandleSetUserBreakpoint(%#" B_PRIx64
1371		", %d)\n", address, enabled);
1372
1373	// check whether there already is a breakpoint
1374	AutoLocker< ::Team> locker(fTeam);
1375
1376	Breakpoint* breakpoint = fTeam->BreakpointAtAddress(address);
1377	UserBreakpoint* userBreakpoint = NULL;
1378	if (breakpoint != NULL && breakpoint->FirstUserBreakpoint() != NULL)
1379		userBreakpoint = breakpoint->FirstUserBreakpoint()->GetUserBreakpoint();
1380	BReference<UserBreakpoint> userBreakpointReference(userBreakpoint);
1381
1382	if (userBreakpoint == NULL) {
1383		TRACE_CONTROL("  no breakpoint yet\n");
1384
1385		// get the function at the address
1386		Image* image = fTeam->ImageByAddress(address);
1387
1388		TRACE_CONTROL("  image: %p\n", image);
1389
1390		if (image == NULL)
1391			return;
1392		ImageDebugInfo* imageDebugInfo = image->GetImageDebugInfo();
1393
1394		TRACE_CONTROL("  image debug info: %p\n", imageDebugInfo);
1395
1396		if (imageDebugInfo == NULL)
1397			return;
1398			// TODO: Handle this case by loading the debug info, if possible!
1399		FunctionInstance* functionInstance
1400			= imageDebugInfo->FunctionAtAddress(address);
1401
1402		TRACE_CONTROL("  function instance: %p\n", functionInstance);
1403
1404		if (functionInstance == NULL)
1405			return;
1406		Function* function = functionInstance->GetFunction();
1407
1408		TRACE_CONTROL("  function: %p\n", function);
1409
1410		// get the source location for the address
1411		FunctionDebugInfo* functionDebugInfo
1412			= functionInstance->GetFunctionDebugInfo();
1413		SourceLocation sourceLocation;
1414		Statement* breakpointStatement = NULL;
1415		if (functionDebugInfo->GetSpecificImageDebugInfo()->GetStatement(
1416				functionDebugInfo, address, breakpointStatement) != B_OK) {
1417			return;
1418		}
1419
1420		sourceLocation = breakpointStatement->StartSourceLocation();
1421		breakpointStatement->ReleaseReference();
1422
1423		target_addr_t relativeAddress = address - functionInstance->Address();
1424
1425		TRACE_CONTROL("  relative address: %#" B_PRIx64 ", source location: "
1426			"(%" B_PRId32 ", %" B_PRId32 ")\n", relativeAddress,
1427			sourceLocation.Line(), sourceLocation.Column());
1428
1429		// get function id
1430		FunctionID* functionID = functionInstance->GetFunctionID();
1431		if (functionID == NULL)
1432			return;
1433		BReference<FunctionID> functionIDReference(functionID, true);
1434
1435		// create the user breakpoint
1436		userBreakpoint = new(std::nothrow) UserBreakpoint(
1437			UserBreakpointLocation(functionID, function->SourceFile(),
1438				sourceLocation, relativeAddress));
1439		if (userBreakpoint == NULL)
1440			return;
1441		userBreakpointReference.SetTo(userBreakpoint, true);
1442
1443		TRACE_CONTROL("  created user breakpoint: %p\n", userBreakpoint);
1444
1445		// iterate through all function instances and create
1446		// UserBreakpointInstances
1447		for (FunctionInstanceList::ConstIterator it
1448					= function->Instances().GetIterator();
1449				FunctionInstance* instance = it.Next();) {
1450			TRACE_CONTROL("  function instance %p: range: %#" B_PRIx64 " - %#"
1451				B_PRIx64 "\n", instance, instance->Address(),
1452				instance->Address() + instance->Size());
1453
1454			// get the breakpoint address for the instance
1455			target_addr_t instanceAddress = 0;
1456			if (instance == functionInstance) {
1457				instanceAddress = address;
1458			} else if (functionInstance->SourceFile() != NULL) {
1459				// We have a source file, so get the address for the source
1460				// location.
1461				Statement* statement = NULL;
1462				functionDebugInfo = instance->GetFunctionDebugInfo();
1463				functionDebugInfo->GetSpecificImageDebugInfo()
1464					->GetStatementAtSourceLocation(functionDebugInfo,
1465						sourceLocation, statement);
1466				if (statement != NULL) {
1467					instanceAddress = statement->CoveringAddressRange().Start();
1468						// TODO: What about BreakpointAllowed()?
1469					statement->ReleaseReference();
1470				}
1471			}
1472
1473			TRACE_CONTROL("    breakpoint address using source info: %" B_PRIx64
1474				"\n", instanceAddress);
1475
1476			if (instanceAddress == 0) {
1477				// No source file (or we failed getting the statement), so try
1478				// to use the same relative address.
1479				if (relativeAddress > instance->Size())
1480					continue;
1481				instanceAddress = instance->Address() + relativeAddress;
1482			}
1483
1484			TRACE_CONTROL("    final breakpoint address: %" B_PRIx64 "\n",
1485				instanceAddress);
1486
1487			UserBreakpointInstance* breakpointInstance = new(std::nothrow)
1488				UserBreakpointInstance(userBreakpoint, instanceAddress);
1489			if (breakpointInstance == NULL
1490				|| !userBreakpoint->AddInstance(breakpointInstance)) {
1491				delete breakpointInstance;
1492				return;
1493			}
1494
1495			TRACE_CONTROL("  breakpoint instance: %p\n", breakpointInstance);
1496		}
1497	}
1498
1499	locker.Unlock();
1500
1501	_HandleSetUserBreakpoint(userBreakpoint, enabled);
1502}
1503
1504
1505void
1506TeamDebugger::_HandleSetUserBreakpoint(UserBreakpoint* breakpoint, bool enabled)
1507{
1508	status_t error = fBreakpointManager->InstallUserBreakpoint(breakpoint,
1509		enabled);
1510	if (error != B_OK) {
1511		_NotifyUser("Install Breakpoint", "Failed to install breakpoint: %s",
1512			strerror(error));
1513	}
1514}
1515
1516
1517void
1518TeamDebugger::_HandleClearUserBreakpoint(target_addr_t address)
1519{
1520	TRACE_CONTROL("TeamDebugger::_HandleClearUserBreakpoint(%#" B_PRIx64 ")\n",
1521		address);
1522
1523	AutoLocker< ::Team> locker(fTeam);
1524
1525	Breakpoint* breakpoint = fTeam->BreakpointAtAddress(address);
1526	if (breakpoint == NULL || breakpoint->FirstUserBreakpoint() == NULL)
1527		return;
1528	UserBreakpoint* userBreakpoint
1529		= breakpoint->FirstUserBreakpoint()->GetUserBreakpoint();
1530	BReference<UserBreakpoint> userBreakpointReference(userBreakpoint);
1531
1532	locker.Unlock();
1533
1534	_HandleClearUserBreakpoint(userBreakpoint);
1535}
1536
1537
1538void
1539TeamDebugger::_HandleClearUserBreakpoint(UserBreakpoint* breakpoint)
1540{
1541	fBreakpointManager->UninstallUserBreakpoint(breakpoint);
1542}
1543
1544
1545void
1546TeamDebugger::_HandleSetWatchpoint(target_addr_t address, uint32 type,
1547	int32 length, bool enabled)
1548{
1549	Watchpoint* watchpoint = new(std::nothrow) Watchpoint(address, type,
1550		length);
1551
1552	if (watchpoint == NULL)
1553		return;
1554	BReference<Watchpoint> watchpointRef(watchpoint, true);
1555
1556	_HandleSetWatchpoint(watchpoint, enabled);
1557}
1558
1559
1560void
1561TeamDebugger::_HandleSetWatchpoint(Watchpoint* watchpoint, bool enabled)
1562{
1563	status_t error = fWatchpointManager->InstallWatchpoint(watchpoint,
1564		enabled);
1565	if (error != B_OK) {
1566		_NotifyUser("Install Watchpoint", "Failed to install watchpoint: %s",
1567			strerror(error));
1568	}
1569}
1570
1571
1572void
1573TeamDebugger::_HandleClearWatchpoint(target_addr_t address)
1574{
1575	TRACE_CONTROL("TeamDebugger::_HandleClearWatchpoint(%#" B_PRIx64 ")\n",
1576		address);
1577
1578	AutoLocker< ::Team> locker(fTeam);
1579
1580	Watchpoint* watchpoint = fTeam->WatchpointAtAddress(address);
1581	if (watchpoint == NULL)
1582		return;
1583	BReference<Watchpoint> watchpointReference(watchpoint);
1584
1585	locker.Unlock();
1586
1587	_HandleClearWatchpoint(watchpoint);
1588}
1589
1590
1591void
1592TeamDebugger::_HandleClearWatchpoint(Watchpoint* watchpoint)
1593{
1594	fWatchpointManager->UninstallWatchpoint(watchpoint);
1595}
1596
1597
1598void
1599TeamDebugger::_HandleInspectAddress(target_addr_t address,
1600	TeamMemoryBlock::Listener* listener)
1601{
1602	TRACE_CONTROL("TeamDebugger::_HandleInspectAddress(%" B_PRIx64 ", %p)\n",
1603		address, listener);
1604
1605	TeamMemoryBlock* memoryBlock = fMemoryBlockManager
1606		->GetMemoryBlock(address);
1607
1608	if (memoryBlock == NULL) {
1609		_NotifyUser("Inspect Address", "Failed to allocate memory block");
1610		return;
1611	}
1612
1613	if (!memoryBlock->HasListener(listener))
1614		memoryBlock->AddListener(listener);
1615
1616	if (!memoryBlock->IsValid()) {
1617		AutoLocker< ::Team> teamLocker(fTeam);
1618
1619		TeamMemory* memory = fTeam->GetTeamMemory();
1620		// schedule the job
1621		status_t result;
1622		if ((result = fWorker->ScheduleJob(
1623			new(std::nothrow) RetrieveMemoryBlockJob(fTeam, memory,
1624				memoryBlock),
1625			this)) != B_OK) {
1626			memoryBlock->ReleaseReference();
1627			_NotifyUser("Inspect Address", "Failed to retrieve memory data: %s",
1628				strerror(result));
1629		}
1630	} else
1631		memoryBlock->NotifyDataRetrieved();
1632
1633}
1634
1635
1636ThreadHandler*
1637TeamDebugger::_GetThreadHandler(thread_id threadID)
1638{
1639	AutoLocker< ::Team> locker(fTeam);
1640
1641	ThreadHandler* handler = fThreadHandlers.Lookup(threadID);
1642	if (handler != NULL)
1643		handler->AcquireReference();
1644	return handler;
1645}
1646
1647
1648status_t
1649TeamDebugger::_AddImage(const ImageInfo& imageInfo, Image** _image)
1650{
1651	LocatableFile* file = NULL;
1652	if (strchr(imageInfo.Name(), '/') != NULL)
1653		file = fFileManager->GetTargetFile(imageInfo.Name());
1654	BReference<LocatableFile> imageFileReference(file, true);
1655
1656	Image* image;
1657	status_t error = fTeam->AddImage(imageInfo, file, &image);
1658	if (error != B_OK)
1659		return error;
1660
1661	ImageDebugInfoRequested(image);
1662
1663	ImageHandler* imageHandler = new(std::nothrow) ImageHandler(this, image);
1664	if (imageHandler != NULL)
1665		fImageHandlers->Insert(imageHandler);
1666
1667	if (_image != NULL)
1668		*_image = image;
1669
1670	return B_OK;
1671}
1672
1673
1674void
1675TeamDebugger::_LoadSettings()
1676{
1677	// get the team name
1678	AutoLocker< ::Team> locker(fTeam);
1679	BString teamName = fTeam->Name();
1680	locker.Unlock();
1681
1682	// load the settings
1683	if (fSettingsManager->LoadTeamSettings(teamName, fTeamSettings) != B_OK)
1684		return;
1685
1686	// create the saved breakpoints
1687	for (int32 i = 0; const BreakpointSetting* breakpointSetting
1688			= fTeamSettings.BreakpointAt(i); i++) {
1689		if (breakpointSetting->GetFunctionID() == NULL)
1690			continue;
1691
1692		// get the source file, if any
1693		LocatableFile* sourceFile = NULL;
1694		if (breakpointSetting->SourceFile().Length() > 0) {
1695			sourceFile = fFileManager->GetSourceFile(
1696				breakpointSetting->SourceFile());
1697			if (sourceFile == NULL)
1698				continue;
1699		}
1700		BReference<LocatableFile> sourceFileReference(sourceFile, true);
1701
1702		// create the breakpoint
1703		UserBreakpointLocation location(breakpointSetting->GetFunctionID(),
1704			sourceFile, breakpointSetting->GetSourceLocation(),
1705			breakpointSetting->RelativeAddress());
1706
1707		UserBreakpoint* breakpoint = new(std::nothrow) UserBreakpoint(location);
1708		if (breakpoint == NULL)
1709			return;
1710		BReference<UserBreakpoint> breakpointReference(breakpoint, true);
1711
1712		// install it
1713		fBreakpointManager->InstallUserBreakpoint(breakpoint,
1714			breakpointSetting->IsEnabled());
1715	}
1716
1717	const TeamUiSettings* uiSettings = fTeamSettings.UiSettingFor(
1718		fUserInterface->ID());
1719	if (uiSettings != NULL)
1720			fUserInterface->LoadSettings(uiSettings);
1721}
1722
1723
1724void
1725TeamDebugger::_SaveSettings()
1726{
1727	// get the settings
1728	AutoLocker< ::Team> locker(fTeam);
1729	TeamSettings settings;
1730	if (settings.SetTo(fTeam) != B_OK)
1731		return;
1732
1733	TeamUiSettings* uiSettings = NULL;
1734	if (fUserInterface->SaveSettings(uiSettings) != B_OK)
1735		return;
1736	if (uiSettings != NULL)
1737		settings.AddUiSettings(uiSettings);
1738
1739	// preserve the UI settings from our cached copy.
1740	for (int32 i = 0; i < fTeamSettings.CountUiSettings(); i++) {
1741		const TeamUiSettings* oldUiSettings = fTeamSettings.UiSettingAt(i);
1742		if (strcmp(oldUiSettings->ID(), fUserInterface->ID()) != 0) {
1743			TeamUiSettings* clonedSettings = oldUiSettings->Clone();
1744			if (clonedSettings != NULL)
1745				settings.AddUiSettings(clonedSettings);
1746		}
1747	}
1748	locker.Unlock();
1749
1750	// save the settings
1751	fSettingsManager->SaveTeamSettings(settings);
1752}
1753
1754
1755void
1756TeamDebugger::_NotifyUser(const char* title, const char* text,...)
1757{
1758	// print the message
1759	char buffer[1024];
1760	va_list args;
1761	va_start(args, text);
1762	vsnprintf(buffer, sizeof(buffer), text, args);
1763	va_end(args);
1764
1765	// notify the user
1766	fUserInterface->NotifyUser(title, buffer, USER_NOTIFICATION_WARNING);
1767}
1768
1769
1770// #pragma mark - Listener
1771
1772
1773TeamDebugger::Listener::~Listener()
1774{
1775}
1776