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 "controllers/TeamDebugger.h"
9
10#include <stdarg.h>
11#include <stdio.h>
12
13#include <new>
14
15#include <Entry.h>
16#include <InterfaceDefs.h>
17#include <Message.h>
18#include <StringList.h>
19
20#include <AutoDeleter.h>
21#include <AutoLocker.h>
22
23#include "debug_utils.h"
24#include "syscall_numbers.h"
25
26#include "Architecture.h"
27#include "BreakpointManager.h"
28#include "BreakpointSetting.h"
29#include "CpuState.h"
30#include "DebugEvent.h"
31#include "DebuggerInterface.h"
32#include "DebugReportGenerator.h"
33#include "ExpressionInfo.h"
34#include "FileManager.h"
35#include "Function.h"
36#include "FunctionID.h"
37#include "ImageDebugInfo.h"
38#include "ImageDebugInfoLoadingState.h"
39#include "ImageDebugLoadingStateHandler.h"
40#include "ImageDebugLoadingStateHandlerRoster.h"
41#include "Jobs.h"
42#include "LocatableFile.h"
43#include "MessageCodes.h"
44#include "NoOpSettingsManager.h"
45#include "SettingsManager.h"
46#include "SourceCode.h"
47#include "SourceLanguage.h"
48#include "SpecificImageDebugInfo.h"
49#include "SpecificImageDebugInfoLoadingState.h"
50#include "StackFrame.h"
51#include "StackFrameValues.h"
52#include "Statement.h"
53#include "SymbolInfo.h"
54#include "TeamDebugInfo.h"
55#include "TeamInfo.h"
56#include "TeamMemoryBlock.h"
57#include "TeamMemoryBlockManager.h"
58#include "TeamSettings.h"
59#include "TeamSignalSettings.h"
60#include "TeamUiSettings.h"
61#include "Tracing.h"
62#include "ValueNode.h"
63#include "ValueNodeContainer.h"
64#include "Variable.h"
65#include "WatchpointManager.h"
66
67
68// #pragma mark - ImageHandler
69
70
71struct TeamDebugger::ImageHandler : public BReferenceable,
72	private LocatableFile::Listener {
73public:
74	ImageHandler(TeamDebugger* teamDebugger, Image* image)
75		:
76		fTeamDebugger(teamDebugger),
77		fImage(image)
78	{
79		fImage->AcquireReference();
80		if (fImage->ImageFile() != NULL)
81			fImage->ImageFile()->AddListener(this);
82	}
83
84	~ImageHandler()
85	{
86		if (fImage->ImageFile() != NULL)
87			fImage->ImageFile()->RemoveListener(this);
88		fImage->ReleaseReference();
89	}
90
91	Image* GetImage() const
92	{
93		return fImage;
94	}
95
96	image_id ImageID() const
97	{
98		return fImage->ID();
99	}
100
101private:
102	// LocatableFile::Listener
103	virtual void LocatableFileChanged(LocatableFile* file)
104	{
105		BMessage message(MSG_IMAGE_FILE_CHANGED);
106		message.AddInt32("image", fImage->ID());
107		fTeamDebugger->PostMessage(&message);
108	}
109
110private:
111	TeamDebugger*	fTeamDebugger;
112	Image*			fImage;
113
114public:
115	ImageHandler*	fNext;
116};
117
118
119// #pragma mark - ImageHandlerHashDefinition
120
121
122struct TeamDebugger::ImageHandlerHashDefinition {
123	typedef image_id		KeyType;
124	typedef	ImageHandler	ValueType;
125
126	size_t HashKey(image_id key) const
127	{
128		return (size_t)key;
129	}
130
131	size_t Hash(const ImageHandler* value) const
132	{
133		return HashKey(value->ImageID());
134	}
135
136	bool Compare(image_id key, const ImageHandler* value) const
137	{
138		return value->ImageID() == key;
139	}
140
141	ImageHandler*& GetLink(ImageHandler* value) const
142	{
143		return value->fNext;
144	}
145};
146
147
148// #pragma mark - ImageInfoPendingThread
149
150
151struct TeamDebugger::ImageInfoPendingThread {
152public:
153	ImageInfoPendingThread(image_id image, thread_id thread)
154		:
155		fImage(image),
156		fThread(thread)
157	{
158	}
159
160	~ImageInfoPendingThread()
161	{
162	}
163
164	image_id ImageID() const
165	{
166		return fImage;
167	}
168
169	thread_id ThreadID() const
170	{
171		return fThread;
172	}
173
174private:
175	image_id				fImage;
176	thread_id				fThread;
177
178public:
179	ImageInfoPendingThread*	fNext;
180};
181
182
183// #pragma mark - ImageHandlerHashDefinition
184
185
186struct TeamDebugger::ImageInfoPendingThreadHashDefinition {
187	typedef image_id				KeyType;
188	typedef	ImageInfoPendingThread	ValueType;
189
190	size_t HashKey(image_id key) const
191	{
192		return (size_t)key;
193	}
194
195	size_t Hash(const ImageInfoPendingThread* value) const
196	{
197		return HashKey(value->ImageID());
198	}
199
200	bool Compare(image_id key, const ImageInfoPendingThread* value) const
201	{
202		return value->ImageID() == key;
203	}
204
205	ImageInfoPendingThread*& GetLink(ImageInfoPendingThread* value) const
206	{
207		return value->fNext;
208	}
209};
210
211
212// #pragma mark - TeamDebugger
213
214
215TeamDebugger::TeamDebugger(Listener* listener, UserInterface* userInterface,
216	SettingsManager* settingsManager)
217	:
218	BLooper("team debugger"),
219	fListener(listener),
220	fSettingsManager(settingsManager),
221	fTeam(NULL),
222	fTeamID(-1),
223	fIsPostMortem(false),
224	fImageHandlers(NULL),
225	fImageInfoPendingThreads(NULL),
226	fDebuggerInterface(NULL),
227	fFileManager(NULL),
228	fWorker(NULL),
229	fBreakpointManager(NULL),
230	fWatchpointManager(NULL),
231	fMemoryBlockManager(NULL),
232	fReportGenerator(NULL),
233	fDebugEventListener(-1),
234	fUserInterface(userInterface),
235	fTerminating(false),
236	fKillTeamOnQuit(false),
237	fCommandLineArgc(0),
238	fCommandLineArgv(NULL),
239	fExecPending(false)
240{
241	fUserInterface->AcquireReference();
242}
243
244
245TeamDebugger::~TeamDebugger()
246{
247	if (fTeam != NULL)
248		_SaveSettings();
249
250	AutoLocker<BLooper> locker(this);
251
252	fTerminating = true;
253
254	if (fDebuggerInterface != NULL) {
255		fDebuggerInterface->Close(fKillTeamOnQuit);
256		fDebuggerInterface->ReleaseReference();
257	}
258
259	if (fWorker != NULL)
260		fWorker->ShutDown();
261
262	locker.Unlock();
263
264	if (fDebugEventListener >= 0)
265		wait_for_thread(fDebugEventListener, NULL);
266
267	// terminate UI
268	if (fUserInterface != NULL) {
269		fUserInterface->Terminate();
270		fUserInterface->ReleaseReference();
271	}
272
273	ThreadHandler* threadHandler = fThreadHandlers.Clear(true);
274	while (threadHandler != NULL) {
275		ThreadHandler* next = threadHandler->fNext;
276		threadHandler->ReleaseReference();
277		threadHandler = next;
278	}
279
280	if (fImageHandlers != NULL) {
281		ImageHandler* imageHandler = fImageHandlers->Clear(true);
282		while (imageHandler != NULL) {
283			ImageHandler* next = imageHandler->fNext;
284			imageHandler->ReleaseReference();
285			imageHandler = next;
286		}
287	}
288
289	delete fImageHandlers;
290
291	if (fImageInfoPendingThreads != NULL) {
292		ImageInfoPendingThread* thread = fImageInfoPendingThreads->Clear(true);
293		while (thread != NULL) {
294			ImageInfoPendingThread* next = thread->fNext;
295			delete thread;
296			thread = next;
297		}
298	}
299
300	if (fReportGenerator != NULL) {
301		fReportGenerator->Lock();
302		fReportGenerator->Quit();
303	}
304
305	delete fWorker;
306
307	delete fImageInfoPendingThreads;
308
309	delete fBreakpointManager;
310	delete fWatchpointManager;
311	delete fMemoryBlockManager;
312	delete fTeam;
313	delete fFileManager;
314
315	for (int i = 0; i < fCommandLineArgc; i++) {
316		if (fCommandLineArgv[i] != NULL)
317			free(const_cast<char*>(fCommandLineArgv[i]));
318	}
319
320	delete [] fCommandLineArgv;
321
322	fListener->TeamDebuggerQuit(this);
323}
324
325
326status_t
327TeamDebugger::Init(DebuggerInterface* interface, thread_id threadID, int argc,
328	const char* const* argv, bool stopInMain)
329{
330	bool targetIsLocal = true;
331		// TODO: Support non-local targets!
332
333	// the first thing we want to do when running
334	PostMessage(MSG_LOAD_SETTINGS);
335
336	status_t error = _HandleSetArguments(argc, argv);
337	if (error != B_OK)
338		return error;
339
340	if (fSettingsManager == NULL) {
341		// if we have not been provided with a settings manager,
342		// simply use the no-op manager by default.
343		fSettingsManager = new(std::nothrow) NoOpSettingsManager;
344		if (fSettingsManager == NULL)
345			return B_NO_MEMORY;
346	}
347
348	fDebuggerInterface = interface;
349	fDebuggerInterface->AcquireReference();
350	fTeamID = interface->TeamID();
351	fIsPostMortem = interface->IsPostMortem();
352
353
354	// create file manager
355	fFileManager = new(std::nothrow) FileManager;
356	if (fFileManager == NULL)
357		return B_NO_MEMORY;
358
359	error = fFileManager->Init(targetIsLocal);
360	if (error != B_OK)
361		return error;
362
363	// create team debug info
364	TeamDebugInfo* teamDebugInfo = new(std::nothrow) TeamDebugInfo(
365		fDebuggerInterface, fDebuggerInterface->GetArchitecture(),
366		fFileManager);
367	if (teamDebugInfo == NULL)
368		return B_NO_MEMORY;
369	BReference<TeamDebugInfo> teamDebugInfoReference(teamDebugInfo, true);
370
371	error = teamDebugInfo->Init();
372	if (error != B_OK)
373		return error;
374
375	// check whether the team exists at all
376	TeamInfo teamInfo;
377	error = fDebuggerInterface->GetTeamInfo(teamInfo);
378	if (error != B_OK)
379		return error;
380
381	// create a team object
382	fTeam = new(std::nothrow) ::Team(fTeamID, fDebuggerInterface,
383		fDebuggerInterface->GetArchitecture(), teamDebugInfo,
384		teamDebugInfo);
385	if (fTeam == NULL)
386		return B_NO_MEMORY;
387
388	error = fTeam->Init();
389	if (error != B_OK)
390		return error;
391	fTeam->SetName(teamInfo.Arguments());
392		// TODO: Set a better name!
393
394	fTeam->AddListener(this);
395
396	// init thread handler table
397	error = fThreadHandlers.Init();
398	if (error != B_OK)
399		return error;
400
401	// create image handler table
402	fImageHandlers = new(std::nothrow) ImageHandlerTable;
403	if (fImageHandlers == NULL)
404		return B_NO_MEMORY;
405
406	error = fImageHandlers->Init();
407	if (error != B_OK)
408		return error;
409
410	fImageInfoPendingThreads = new(std::nothrow) ImageInfoPendingThreadTable;
411	if (fImageInfoPendingThreads == NULL)
412		return B_NO_MEMORY;
413
414	// create our worker
415	fWorker = new(std::nothrow) Worker;
416	if (fWorker == NULL)
417		return B_NO_MEMORY;
418
419	error = fWorker->Init();
420	if (error != B_OK)
421		return error;
422
423	// create the breakpoint manager
424	fBreakpointManager = new(std::nothrow) BreakpointManager(fTeam,
425		fDebuggerInterface);
426	if (fBreakpointManager == NULL)
427		return B_NO_MEMORY;
428
429	error = fBreakpointManager->Init();
430	if (error != B_OK)
431		return error;
432
433	// create the watchpoint manager
434	fWatchpointManager = new(std::nothrow) WatchpointManager(fTeam,
435		fDebuggerInterface);
436	if (fWatchpointManager == NULL)
437		return B_NO_MEMORY;
438
439	error = fWatchpointManager->Init();
440	if (error != B_OK)
441		return error;
442
443	// create the memory block manager
444	fMemoryBlockManager = new(std::nothrow) TeamMemoryBlockManager();
445	if (fMemoryBlockManager == NULL)
446		return B_NO_MEMORY;
447
448	error = fMemoryBlockManager->Init();
449	if (error != B_OK)
450		return error;
451
452	// create the debug report generator
453	fReportGenerator = new(std::nothrow) DebugReportGenerator(fTeam, this,
454		fDebuggerInterface);
455	if (fReportGenerator == NULL)
456		return B_NO_MEMORY;
457
458	error = fReportGenerator->Init();
459	if (error != B_OK)
460		return error;
461
462	// set team debugging flags
463	fDebuggerInterface->SetTeamDebuggingFlags(
464		B_TEAM_DEBUG_THREADS | B_TEAM_DEBUG_IMAGES
465			| B_TEAM_DEBUG_POST_SYSCALL | B_TEAM_DEBUG_SIGNALS
466			| B_TEAM_DEBUG_TEAM_CREATION);
467
468	// get the initial state of the team
469	AutoLocker< ::Team> teamLocker(fTeam);
470
471	ThreadHandler* mainThreadHandler = NULL;
472	{
473		BObjectList<ThreadInfo> threadInfos(20, true);
474		status_t error = fDebuggerInterface->GetThreadInfos(threadInfos);
475		for (int32 i = 0; ThreadInfo* info = threadInfos.ItemAt(i); i++) {
476			::Thread* thread;
477			error = fTeam->AddThread(*info, &thread);
478			if (error != B_OK)
479				return error;
480
481			ThreadHandler* handler = new(std::nothrow) ThreadHandler(thread,
482				fWorker, fDebuggerInterface, this, fBreakpointManager);
483			if (handler == NULL)
484				return B_NO_MEMORY;
485
486			fThreadHandlers.Insert(handler);
487
488			if (thread->IsMainThread())
489				mainThreadHandler = handler;
490
491			handler->Init();
492		}
493	}
494
495	Image* appImage = NULL;
496	{
497		BObjectList<ImageInfo> imageInfos(20, true);
498		status_t error = fDebuggerInterface->GetImageInfos(imageInfos);
499		for (int32 i = 0; ImageInfo* info = imageInfos.ItemAt(i); i++) {
500			Image* image;
501			error = _AddImage(*info, &image);
502			if (error != B_OK)
503				return error;
504			if (image->Type() == B_APP_IMAGE)
505				appImage = image;
506
507			ImageDebugInfoRequested(image);
508		}
509	}
510
511	// create the debug event listener (for live debugging only)
512	if (!fDebuggerInterface->IsPostMortem()) {
513		char buffer[128];
514		snprintf(buffer, sizeof(buffer), "team %" B_PRId32 " debug listener",
515			fTeamID);
516		fDebugEventListener = spawn_thread(_DebugEventListenerEntry, buffer,
517			B_NORMAL_PRIORITY, this);
518		if (fDebugEventListener < 0)
519			return fDebugEventListener;
520
521		resume_thread(fDebugEventListener);
522	}
523
524	// run looper
525	thread_id looperThread = Run();
526	if (looperThread < 0)
527		return looperThread;
528
529	// init the UI
530	error = fUserInterface->Init(fTeam, this);
531	if (error != B_OK) {
532		ERROR("Error: Failed to init the UI: %s\n", strerror(error));
533		return error;
534	}
535
536	// if requested, stop the given thread
537	if (threadID >= 0 && !fDebuggerInterface->IsPostMortem()) {
538		if (stopInMain) {
539			SymbolInfo symbolInfo;
540			if (appImage != NULL && mainThreadHandler != NULL
541				&& fDebuggerInterface->GetSymbolInfo(
542					fTeam->ID(), appImage->ID(), "main", B_SYMBOL_TYPE_TEXT,
543					symbolInfo) == B_OK) {
544				mainThreadHandler->SetBreakpointAndRun(symbolInfo.Address());
545			}
546		} else {
547			debug_thread(threadID);
548				// TODO: Superfluous, if the thread is already stopped.
549		}
550	}
551
552	fListener->TeamDebuggerStarted(this);
553
554	return B_OK;
555}
556
557
558void
559TeamDebugger::Activate()
560{
561	fUserInterface->Show();
562}
563
564
565void
566TeamDebugger::MessageReceived(BMessage* message)
567{
568	switch (message->what) {
569		case MSG_THREAD_RUN:
570		case MSG_THREAD_SET_ADDRESS:
571		case MSG_THREAD_STOP:
572		case MSG_THREAD_STEP_OVER:
573		case MSG_THREAD_STEP_INTO:
574		case MSG_THREAD_STEP_OUT:
575		{
576			int32 threadID;
577			target_addr_t address;
578			if (message->FindInt32("thread", &threadID) != B_OK)
579				break;
580
581			if (message->FindUInt64("address", &address) != B_OK)
582				address = 0;
583
584			if (ThreadHandler* handler = _GetThreadHandler(threadID)) {
585				handler->HandleThreadAction(message->what, address);
586				handler->ReleaseReference();
587			}
588			break;
589		}
590
591		case MSG_SET_BREAKPOINT:
592		case MSG_CLEAR_BREAKPOINT:
593		{
594			UserBreakpoint* breakpoint = NULL;
595			BReference<UserBreakpoint> breakpointReference;
596			uint64 address = 0;
597
598			if (message->FindPointer("breakpoint", (void**)&breakpoint)
599				== B_OK) {
600				breakpointReference.SetTo(breakpoint, true);
601			} else if (message->FindUInt64("address", &address) != B_OK)
602				break;
603
604			if (message->what == MSG_SET_BREAKPOINT) {
605				bool enabled;
606				if (message->FindBool("enabled", &enabled) != B_OK)
607					enabled = true;
608
609				bool hidden;
610				if (message->FindBool("hidden", &hidden) != B_OK)
611					hidden = false;
612
613				if (breakpoint != NULL)
614					_HandleSetUserBreakpoint(breakpoint, enabled);
615				else
616					_HandleSetUserBreakpoint(address, enabled, hidden);
617			} else {
618				if (breakpoint != NULL)
619					_HandleClearUserBreakpoint(breakpoint);
620				else
621					_HandleClearUserBreakpoint(address);
622			}
623
624			break;
625		}
626
627		case MSG_SET_BREAKPOINT_CONDITION:
628		{
629			UserBreakpoint* breakpoint = NULL;
630			BReference<UserBreakpoint> breakpointReference;
631			if (message->FindPointer("breakpoint", (void**)&breakpoint)
632				!= B_OK) {
633				break;
634			}
635
636			breakpointReference.SetTo(breakpoint, true);
637
638			const char* condition;
639			if (message->FindString("condition", &condition) != B_OK)
640				break;
641
642			AutoLocker< ::Team> teamLocker(fTeam);
643			breakpoint->SetCondition(condition);
644			fTeam->NotifyUserBreakpointChanged(breakpoint);
645
646			break;
647		}
648
649		case MSG_CLEAR_BREAKPOINT_CONDITION:
650		{
651			UserBreakpoint* breakpoint = NULL;
652			BReference<UserBreakpoint> breakpointReference;
653			if (message->FindPointer("breakpoint", (void**)&breakpoint)
654				!= B_OK)
655				break;
656
657			breakpointReference.SetTo(breakpoint, true);
658
659			AutoLocker< ::Team> teamLocker(fTeam);
660			breakpoint->SetCondition(NULL);
661			fTeam->NotifyUserBreakpointChanged(breakpoint);
662
663			break;
664		}
665
666		case MSG_STOP_ON_IMAGE_LOAD:
667		{
668			bool enabled;
669			bool useNames;
670			if (message->FindBool("enabled", &enabled) != B_OK)
671				break;
672
673			if (message->FindBool("useNames", &useNames) != B_OK)
674				break;
675
676			AutoLocker< ::Team> teamLocker(fTeam);
677			fTeam->SetStopOnImageLoad(enabled, useNames);
678			break;
679		}
680
681		case MSG_ADD_STOP_IMAGE_NAME:
682		{
683			BString imageName;
684			if (message->FindString("name", &imageName) != B_OK)
685				break;
686
687			AutoLocker< ::Team> teamLocker(fTeam);
688			fTeam->AddStopImageName(imageName);
689			break;
690		}
691
692		case MSG_REMOVE_STOP_IMAGE_NAME:
693		{
694			BString imageName;
695			if (message->FindString("name", &imageName) != B_OK)
696				break;
697
698			AutoLocker< ::Team> teamLocker(fTeam);
699			fTeam->RemoveStopImageName(imageName);
700			break;
701		}
702
703		case MSG_SET_DEFAULT_SIGNAL_DISPOSITION:
704		{
705			int32 disposition;
706			if (message->FindInt32("disposition", &disposition) != B_OK)
707				break;
708
709			AutoLocker< ::Team> teamLocker(fTeam);
710			fTeam->SetDefaultSignalDisposition(disposition);
711			break;
712		}
713
714		case MSG_SET_CUSTOM_SIGNAL_DISPOSITION:
715		{
716			int32 signal;
717			int32 disposition;
718			if (message->FindInt32("signal", &signal) != B_OK
719				|| message->FindInt32("disposition", &disposition) != B_OK) {
720				break;
721			}
722
723			AutoLocker< ::Team> teamLocker(fTeam);
724			fTeam->SetCustomSignalDisposition(signal, disposition);
725			break;
726		}
727
728		case MSG_REMOVE_CUSTOM_SIGNAL_DISPOSITION:
729		{
730			int32 signal;
731			if (message->FindInt32("signal", &signal) != B_OK)
732				break;
733
734			AutoLocker< ::Team> teamLocker(fTeam);
735			fTeam->RemoveCustomSignalDisposition(signal);
736			break;
737		}
738
739		case MSG_SET_WATCHPOINT:
740		case MSG_CLEAR_WATCHPOINT:
741		{
742			Watchpoint* watchpoint = NULL;
743			BReference<Watchpoint> watchpointReference;
744			uint64 address = 0;
745			uint32 type = 0;
746			int32 length = 0;
747
748			if (message->FindPointer("watchpoint", (void**)&watchpoint)
749					== B_OK) {
750				watchpointReference.SetTo(watchpoint, true);
751			} else if (message->FindUInt64("address", &address) != B_OK)
752				break;
753
754			if (message->what == MSG_SET_WATCHPOINT) {
755				if (watchpoint == NULL && (message->FindUInt32("type", &type)
756							!= B_OK
757						|| message->FindInt32("length", &length) != B_OK)) {
758					break;
759				}
760
761				bool enabled;
762				if (message->FindBool("enabled", &enabled) != B_OK)
763					enabled = true;
764
765				if (watchpoint != NULL)
766					_HandleSetWatchpoint(watchpoint, enabled);
767				else
768					_HandleSetWatchpoint(address, type, length, enabled);
769			} else {
770				if (watchpoint != NULL)
771					_HandleClearWatchpoint(watchpoint);
772				else
773					_HandleClearWatchpoint(address);
774			}
775
776			break;
777		}
778
779		case MSG_INSPECT_ADDRESS:
780		{
781			TeamMemoryBlock::Listener* listener;
782			if (message->FindPointer("listener",
783				reinterpret_cast<void **>(&listener)) != B_OK) {
784				break;
785			}
786
787			target_addr_t address;
788			if (message->FindUInt64("address",
789				&address) == B_OK) {
790				_HandleInspectAddress(address, listener);
791			}
792			break;
793		}
794
795		case MSG_WRITE_TARGET_MEMORY:
796		{
797			target_addr_t address;
798			if (message->FindUInt64("address", &address) != B_OK)
799				break;
800
801			void* data;
802			if (message->FindPointer("data", &data) != B_OK)
803				break;
804
805			target_size_t size;
806			if (message->FindUInt64("size", &size) != B_OK)
807				break;
808
809			_HandleWriteMemory(address, data, size);
810			break;
811		}
812
813		case MSG_EVALUATE_EXPRESSION:
814		{
815			SourceLanguage* language;
816			if (message->FindPointer("language",
817				reinterpret_cast<void**>(&language)) != B_OK) {
818				break;
819			}
820
821			// ExpressionEvaluationRequested() acquires a reference
822			// to both the language and the expression info on our behalf.
823			BReference<SourceLanguage> reference(language, true);
824
825			ExpressionInfo* info;
826			if (message->FindPointer("info",
827				reinterpret_cast<void**>(&info)) != B_OK) {
828				break;
829			}
830
831			BReference<ExpressionInfo> infoReference(info, true);
832
833			StackFrame* frame;
834			if (message->FindPointer("frame",
835				reinterpret_cast<void**>(&frame)) != B_OK) {
836				// the stack frame isn't needed, unless variable
837				// evaluation is desired.
838				frame = NULL;
839			}
840
841			::Thread* thread;
842			if (message->FindPointer("thread",
843				reinterpret_cast<void**>(&thread)) != B_OK) {
844				// the thread isn't needed, unless variable
845				// evaluation is desired.
846				thread = NULL;
847			}
848
849			_HandleEvaluateExpression(language, info, frame, thread);
850			break;
851		}
852
853		case MSG_GENERATE_DEBUG_REPORT:
854		{
855			fReportGenerator->PostMessage(message);
856			break;
857		}
858
859		case MSG_WRITE_CORE_FILE:
860		{
861			entry_ref ref;
862			if (message->FindRef("target", &ref) != B_OK)
863				break;
864
865			_HandleWriteCoreFile(ref);
866			break;
867		}
868
869		case MSG_THREAD_STATE_CHANGED:
870		{
871			int32 threadID;
872			if (message->FindInt32("thread", &threadID) != B_OK)
873				break;
874
875			if (ThreadHandler* handler = _GetThreadHandler(threadID)) {
876				handler->HandleThreadStateChanged();
877				handler->ReleaseReference();
878			}
879			break;
880		}
881		case MSG_THREAD_CPU_STATE_CHANGED:
882		{
883			int32 threadID;
884			if (message->FindInt32("thread", &threadID) != B_OK)
885				break;
886
887			if (ThreadHandler* handler = _GetThreadHandler(threadID)) {
888				handler->HandleCpuStateChanged();
889				handler->ReleaseReference();
890			}
891			break;
892		}
893		case MSG_THREAD_STACK_TRACE_CHANGED:
894		{
895			int32 threadID;
896			if (message->FindInt32("thread", &threadID) != B_OK)
897				break;
898
899			if (ThreadHandler* handler = _GetThreadHandler(threadID)) {
900				handler->HandleStackTraceChanged();
901				handler->ReleaseReference();
902			}
903			break;
904		}
905
906		case MSG_IMAGE_DEBUG_INFO_CHANGED:
907		{
908			int32 imageID;
909			if (message->FindInt32("image", &imageID) != B_OK)
910				break;
911
912			_HandleImageDebugInfoChanged(imageID);
913			break;
914		}
915
916		case MSG_IMAGE_FILE_CHANGED:
917		{
918			int32 imageID;
919			if (message->FindInt32("image", &imageID) != B_OK)
920				break;
921
922			_HandleImageFileChanged(imageID);
923			break;
924		}
925
926		case MSG_DEBUGGER_EVENT:
927		{
928			DebugEvent* event;
929			if (message->FindPointer("event", (void**)&event) != B_OK)
930				break;
931
932			_HandleDebuggerMessage(event);
933			delete event;
934			break;
935		}
936
937		case MSG_LOAD_SETTINGS:
938			_LoadSettings();
939			Activate();
940			break;
941
942		case MSG_TEAM_RESTART_REQUESTED:
943		{
944			if (fCommandLineArgc == 0)
945				break;
946
947			_SaveSettings();
948			fListener->TeamDebuggerRestartRequested(this);
949			break;
950		}
951
952		case MSG_DEBUG_INFO_NEEDS_USER_INPUT:
953		{
954			Job* job;
955			ImageDebugInfoLoadingState* state;
956			if (message->FindPointer("job", (void**)&job) != B_OK)
957				break;
958			if (message->FindPointer("state", (void**)&state) != B_OK)
959				break;
960
961			_HandleDebugInfoJobUserInput(state);
962			fWorker->ResumeJob(job);
963			break;
964		}
965
966		case MSG_RESET_USER_BACKGROUND_STATUS:
967		{
968			fUserInterface->NotifyBackgroundWorkStatus("Ready.");
969			break;
970		}
971
972		default:
973			BLooper::MessageReceived(message);
974			break;
975	}
976}
977
978
979void
980TeamDebugger::SourceEntryLocateRequested(const char* sourcePath,
981	const char* locatedPath)
982{
983	AutoLocker<FileManager> locker(fFileManager);
984	fFileManager->SourceEntryLocated(sourcePath, locatedPath);
985}
986
987
988void
989TeamDebugger::SourceEntryInvalidateRequested(LocatableFile* sourceFile)
990{
991	AutoLocker< ::Team> locker(fTeam);
992
993	fTeam->DebugInfo()->ClearSourceCode(sourceFile);
994}
995
996
997void
998TeamDebugger::FunctionSourceCodeRequested(FunctionInstance* functionInstance,
999	bool forceDisassembly)
1000{
1001	Function* function = functionInstance->GetFunction();
1002
1003	// mark loading
1004	AutoLocker< ::Team> locker(fTeam);
1005
1006	if (forceDisassembly && functionInstance->SourceCodeState()
1007			!= FUNCTION_SOURCE_NOT_LOADED) {
1008		return;
1009	} else if (!forceDisassembly && function->SourceCodeState()
1010			== FUNCTION_SOURCE_LOADED) {
1011		return;
1012	}
1013
1014	functionInstance->SetSourceCode(NULL, FUNCTION_SOURCE_LOADING);
1015
1016	bool loadForFunction = false;
1017	if (!forceDisassembly && (function->SourceCodeState()
1018				== FUNCTION_SOURCE_NOT_LOADED
1019			|| function->SourceCodeState() == FUNCTION_SOURCE_SUPPRESSED)) {
1020		loadForFunction = true;
1021		function->SetSourceCode(NULL, FUNCTION_SOURCE_LOADING);
1022	}
1023
1024	locker.Unlock();
1025
1026	// schedule the job
1027	if (fWorker->ScheduleJob(
1028			new(std::nothrow) LoadSourceCodeJob(fDebuggerInterface,
1029				fDebuggerInterface->GetArchitecture(), fTeam, functionInstance,
1030					loadForFunction),
1031			this) != B_OK) {
1032		// scheduling failed -- mark unavailable
1033		locker.Lock();
1034		function->SetSourceCode(NULL, FUNCTION_SOURCE_UNAVAILABLE);
1035		locker.Unlock();
1036	}
1037}
1038
1039
1040void
1041TeamDebugger::ImageDebugInfoRequested(Image* image)
1042{
1043	LoadImageDebugInfoJob::ScheduleIfNecessary(fWorker, image, this);
1044}
1045
1046
1047void
1048TeamDebugger::ValueNodeValueRequested(CpuState* cpuState,
1049	ValueNodeContainer* container, ValueNode* valueNode)
1050{
1051	AutoLocker<ValueNodeContainer> containerLocker(container);
1052	if (valueNode->Container() != container)
1053		return;
1054
1055	// check whether a job is already in progress
1056	AutoLocker<Worker> workerLocker(fWorker);
1057	SimpleJobKey jobKey(valueNode, JOB_TYPE_RESOLVE_VALUE_NODE_VALUE);
1058	if (fWorker->GetJob(jobKey) != NULL)
1059		return;
1060	workerLocker.Unlock();
1061
1062	// schedule the job
1063	status_t error = fWorker->ScheduleJob(
1064		new(std::nothrow) ResolveValueNodeValueJob(fDebuggerInterface,
1065			fDebuggerInterface->GetArchitecture(), cpuState,
1066			fTeam->GetTeamTypeInformation(), container,	valueNode), this);
1067	if (error != B_OK) {
1068		// scheduling failed -- set the value to invalid
1069		valueNode->SetLocationAndValue(NULL, NULL, error);
1070	}
1071}
1072
1073void
1074TeamDebugger::ValueNodeWriteRequested(ValueNode* node, CpuState* state,
1075	Value* newValue)
1076{
1077	// schedule the job
1078	status_t error = fWorker->ScheduleJob(
1079		new(std::nothrow) WriteValueNodeValueJob(fDebuggerInterface,
1080			fDebuggerInterface->GetArchitecture(), state,
1081			fTeam->GetTeamTypeInformation(), node, newValue), this);
1082	if (error != B_OK) {
1083		BString message;
1084		message.SetToFormat("Request to write new value for variable %s "
1085			"failed: %s.\n", node->Name().String(), strerror(error));
1086		fUserInterface->NotifyUser("Error", message.String(),
1087			USER_NOTIFICATION_ERROR);
1088	}
1089}
1090
1091
1092void
1093TeamDebugger::ThreadActionRequested(thread_id threadID,
1094	uint32 action, target_addr_t address)
1095{
1096	BMessage message(action);
1097	message.AddInt32("thread", threadID);
1098	message.AddUInt64("address", address);
1099	PostMessage(&message);
1100}
1101
1102
1103void
1104TeamDebugger::SetBreakpointRequested(target_addr_t address, bool enabled,
1105	bool hidden)
1106{
1107	BMessage message(MSG_SET_BREAKPOINT);
1108	message.AddUInt64("address", (uint64)address);
1109	message.AddBool("enabled", enabled);
1110	message.AddBool("hidden", hidden);
1111	PostMessage(&message);
1112}
1113
1114
1115void
1116TeamDebugger::SetBreakpointEnabledRequested(UserBreakpoint* breakpoint,
1117	bool enabled)
1118{
1119	BMessage message(MSG_SET_BREAKPOINT);
1120	BReference<UserBreakpoint> breakpointReference(breakpoint);
1121	if (message.AddPointer("breakpoint", breakpoint) == B_OK
1122		&& message.AddBool("enabled", enabled) == B_OK
1123		&& PostMessage(&message) == B_OK) {
1124		breakpointReference.Detach();
1125	}
1126}
1127
1128
1129void
1130TeamDebugger::SetBreakpointConditionRequested(UserBreakpoint* breakpoint,
1131	const char* condition)
1132{
1133	BMessage message(MSG_SET_BREAKPOINT_CONDITION);
1134	BReference<UserBreakpoint> breakpointReference(breakpoint);
1135	if (message.AddPointer("breakpoint", breakpoint) == B_OK
1136		&& message.AddString("condition", condition) == B_OK
1137		&& PostMessage(&message) == B_OK) {
1138		breakpointReference.Detach();
1139	}
1140}
1141
1142
1143void
1144TeamDebugger::ClearBreakpointConditionRequested(UserBreakpoint* breakpoint)
1145{
1146	BMessage message(MSG_CLEAR_BREAKPOINT_CONDITION);
1147	BReference<UserBreakpoint> breakpointReference(breakpoint);
1148	if (message.AddPointer("breakpoint", breakpoint) == B_OK
1149		&& PostMessage(&message) == B_OK) {
1150		breakpointReference.Detach();
1151	}
1152}
1153
1154
1155void
1156TeamDebugger::ClearBreakpointRequested(target_addr_t address)
1157{
1158	BMessage message(MSG_CLEAR_BREAKPOINT);
1159	message.AddUInt64("address", (uint64)address);
1160	PostMessage(&message);
1161}
1162
1163
1164void
1165TeamDebugger::SetStopOnImageLoadRequested(bool enabled, bool useImageNames)
1166{
1167	BMessage message(MSG_STOP_ON_IMAGE_LOAD);
1168	message.AddBool("enabled", enabled);
1169	message.AddBool("useNames", useImageNames);
1170	PostMessage(&message);
1171}
1172
1173
1174void
1175TeamDebugger::AddStopImageNameRequested(const char* name)
1176{
1177	BMessage message(MSG_ADD_STOP_IMAGE_NAME);
1178	message.AddString("name", name);
1179	PostMessage(&message);
1180}
1181
1182
1183void
1184TeamDebugger::RemoveStopImageNameRequested(const char* name)
1185{
1186	BMessage message(MSG_REMOVE_STOP_IMAGE_NAME);
1187	message.AddString("name", name);
1188	PostMessage(&message);
1189}
1190
1191
1192void
1193TeamDebugger::SetDefaultSignalDispositionRequested(int32 disposition)
1194{
1195	BMessage message(MSG_SET_DEFAULT_SIGNAL_DISPOSITION);
1196	message.AddInt32("disposition", disposition);
1197	PostMessage(&message);
1198}
1199
1200
1201void
1202TeamDebugger::SetCustomSignalDispositionRequested(int32 signal,
1203	int32 disposition)
1204{
1205	BMessage message(MSG_SET_CUSTOM_SIGNAL_DISPOSITION);
1206	message.AddInt32("signal", signal);
1207	message.AddInt32("disposition", disposition);
1208	PostMessage(&message);
1209}
1210
1211
1212void
1213TeamDebugger::RemoveCustomSignalDispositionRequested(int32 signal)
1214{
1215	BMessage message(MSG_REMOVE_CUSTOM_SIGNAL_DISPOSITION);
1216	message.AddInt32("signal", signal);
1217	PostMessage(&message);
1218}
1219
1220
1221void
1222TeamDebugger::ClearBreakpointRequested(UserBreakpoint* breakpoint)
1223{
1224	BMessage message(MSG_CLEAR_BREAKPOINT);
1225	BReference<UserBreakpoint> breakpointReference(breakpoint);
1226	if (message.AddPointer("breakpoint", breakpoint) == B_OK
1227		&& PostMessage(&message) == B_OK) {
1228		breakpointReference.Detach();
1229	}
1230}
1231
1232
1233void
1234TeamDebugger::SetWatchpointRequested(target_addr_t address, uint32 type,
1235	int32 length, bool enabled)
1236{
1237	BMessage message(MSG_SET_WATCHPOINT);
1238	message.AddUInt64("address", (uint64)address);
1239	message.AddUInt32("type", type);
1240	message.AddInt32("length", length);
1241	message.AddBool("enabled", enabled);
1242	PostMessage(&message);
1243}
1244
1245
1246void
1247TeamDebugger::SetWatchpointEnabledRequested(Watchpoint* watchpoint,
1248	bool enabled)
1249{
1250	BMessage message(MSG_SET_WATCHPOINT);
1251	BReference<Watchpoint> watchpointReference(watchpoint);
1252	if (message.AddPointer("watchpoint", watchpoint) == B_OK
1253		&& message.AddBool("enabled", enabled) == B_OK
1254		&& PostMessage(&message) == B_OK) {
1255		watchpointReference.Detach();
1256	}
1257}
1258
1259
1260void
1261TeamDebugger::ClearWatchpointRequested(target_addr_t address)
1262{
1263	BMessage message(MSG_CLEAR_WATCHPOINT);
1264	message.AddUInt64("address", (uint64)address);
1265	PostMessage(&message);
1266}
1267
1268
1269void
1270TeamDebugger::ClearWatchpointRequested(Watchpoint* watchpoint)
1271{
1272	BMessage message(MSG_CLEAR_WATCHPOINT);
1273	BReference<Watchpoint> watchpointReference(watchpoint);
1274	if (message.AddPointer("watchpoint", watchpoint) == B_OK
1275		&& PostMessage(&message) == B_OK) {
1276		watchpointReference.Detach();
1277	}
1278}
1279
1280
1281void
1282TeamDebugger::InspectRequested(target_addr_t address,
1283	TeamMemoryBlock::Listener *listener)
1284{
1285	BMessage message(MSG_INSPECT_ADDRESS);
1286	message.AddUInt64("address", address);
1287	message.AddPointer("listener", listener);
1288	PostMessage(&message);
1289}
1290
1291
1292void
1293TeamDebugger::MemoryWriteRequested(target_addr_t address, const void* data,
1294	target_size_t size)
1295{
1296	BMessage message(MSG_WRITE_TARGET_MEMORY);
1297	message.AddUInt64("address", address);
1298	message.AddPointer("data", data);
1299	message.AddUInt64("size", size);
1300	PostMessage(&message);
1301}
1302
1303
1304void
1305TeamDebugger::ExpressionEvaluationRequested(SourceLanguage* language,
1306	ExpressionInfo* info, StackFrame* frame, ::Thread* thread)
1307{
1308	BMessage message(MSG_EVALUATE_EXPRESSION);
1309	message.AddPointer("language", language);
1310	message.AddPointer("info", info);
1311	if (frame != NULL)
1312		message.AddPointer("frame", frame);
1313	if (thread != NULL)
1314		message.AddPointer("thread", thread);
1315
1316	BReference<SourceLanguage> languageReference(language);
1317	BReference<ExpressionInfo> infoReference(info);
1318	if (PostMessage(&message) == B_OK) {
1319		languageReference.Detach();
1320		infoReference.Detach();
1321	}
1322}
1323
1324
1325void
1326TeamDebugger::DebugReportRequested(entry_ref* targetPath)
1327{
1328	BMessage message(MSG_GENERATE_DEBUG_REPORT);
1329	message.AddRef("target", targetPath);
1330	PostMessage(&message);
1331}
1332
1333
1334void
1335TeamDebugger::WriteCoreFileRequested(entry_ref* targetPath)
1336{
1337	BMessage message(MSG_WRITE_CORE_FILE);
1338	message.AddRef("target", targetPath);
1339	PostMessage(&message);
1340}
1341
1342
1343void
1344TeamDebugger::TeamRestartRequested()
1345{
1346	PostMessage(MSG_TEAM_RESTART_REQUESTED);
1347}
1348
1349
1350bool
1351TeamDebugger::UserInterfaceQuitRequested(QuitOption quitOption)
1352{
1353	bool askUser = false;
1354	switch (quitOption) {
1355		case QUIT_OPTION_ASK_USER:
1356			askUser = true;
1357			break;
1358
1359		case QUIT_OPTION_ASK_KILL_TEAM:
1360			fKillTeamOnQuit = true;
1361			break;
1362
1363		case QUIT_OPTION_ASK_RESUME_TEAM:
1364			break;
1365	}
1366
1367	if (askUser) {
1368		AutoLocker< ::Team> locker(fTeam);
1369		BString name(fTeam->Name());
1370		locker.Unlock();
1371
1372		BString message;
1373		message << "What shall be done about the debugged team '";
1374		message << name;
1375		message << "'?";
1376
1377		name.Remove(0, name.FindLast('/') + 1);
1378
1379		BString killLabel("Kill ");
1380		killLabel << name;
1381
1382		BString resumeLabel("Resume ");
1383		resumeLabel << name;
1384
1385		int32 choice = fUserInterface->SynchronouslyAskUser("Quit Debugger",
1386			message, killLabel, "Cancel", resumeLabel);
1387
1388		switch (choice) {
1389			case 0:
1390				fKillTeamOnQuit = true;
1391				break;
1392			case 1:
1393			case -1:
1394				return false;
1395			case 2:
1396				// Detach from the team and resume and stopped threads.
1397				break;
1398		}
1399	}
1400
1401	PostMessage(B_QUIT_REQUESTED);
1402
1403	return true;
1404}
1405
1406
1407void
1408TeamDebugger::JobStarted(Job* job)
1409{
1410	BString description(job->GetDescription());
1411	if (!description.IsEmpty()) {
1412		description.Append(B_UTF8_ELLIPSIS);
1413		fUserInterface->NotifyBackgroundWorkStatus(description.String());
1414	}
1415}
1416
1417
1418void
1419TeamDebugger::JobDone(Job* job)
1420{
1421	TRACE_JOBS("TeamDebugger::JobDone(%p)\n", job);
1422	_ResetUserBackgroundStatusIfNeeded();
1423}
1424
1425
1426void
1427TeamDebugger::JobWaitingForInput(Job* job)
1428{
1429	LoadImageDebugInfoJob* infoJob = dynamic_cast<LoadImageDebugInfoJob*>(job);
1430
1431	if (infoJob == NULL)
1432		return;
1433
1434	BMessage message(MSG_DEBUG_INFO_NEEDS_USER_INPUT);
1435	message.AddPointer("job", infoJob);
1436	message.AddPointer("state", infoJob->GetLoadingState());
1437	PostMessage(&message);
1438}
1439
1440
1441void
1442TeamDebugger::JobFailed(Job* job)
1443{
1444	TRACE_JOBS("TeamDebugger::JobFailed(%p)\n", job);
1445	// TODO: notify user
1446	_ResetUserBackgroundStatusIfNeeded();
1447}
1448
1449
1450void
1451TeamDebugger::JobAborted(Job* job)
1452{
1453	TRACE_JOBS("TeamDebugger::JobAborted(%p)\n", job);
1454	// TODO: For a stack frame source loader thread we should reset the
1455	// loading state! Asynchronously due to locking order.
1456	_ResetUserBackgroundStatusIfNeeded();
1457}
1458
1459
1460void
1461TeamDebugger::ThreadStateChanged(const ::Team::ThreadEvent& event)
1462{
1463	BMessage message(MSG_THREAD_STATE_CHANGED);
1464	message.AddInt32("thread", event.GetThread()->ID());
1465	PostMessage(&message);
1466}
1467
1468
1469void
1470TeamDebugger::ThreadCpuStateChanged(const ::Team::ThreadEvent& event)
1471{
1472	BMessage message(MSG_THREAD_CPU_STATE_CHANGED);
1473	message.AddInt32("thread", event.GetThread()->ID());
1474	PostMessage(&message);
1475}
1476
1477
1478void
1479TeamDebugger::ThreadStackTraceChanged(const ::Team::ThreadEvent& event)
1480{
1481	BMessage message(MSG_THREAD_STACK_TRACE_CHANGED);
1482	message.AddInt32("thread", event.GetThread()->ID());
1483	PostMessage(&message);
1484}
1485
1486
1487void
1488TeamDebugger::ImageDebugInfoChanged(const ::Team::ImageEvent& event)
1489{
1490	BMessage message(MSG_IMAGE_DEBUG_INFO_CHANGED);
1491	message.AddInt32("image", event.GetImage()->ID());
1492	PostMessage(&message);
1493}
1494
1495
1496/*static*/ status_t
1497TeamDebugger::_DebugEventListenerEntry(void* data)
1498{
1499	return ((TeamDebugger*)data)->_DebugEventListener();
1500}
1501
1502
1503status_t
1504TeamDebugger::_DebugEventListener()
1505{
1506	while (!fTerminating) {
1507		// get the next event
1508		DebugEvent* event;
1509		status_t error = fDebuggerInterface->GetNextDebugEvent(event);
1510		if (error != B_OK)
1511			break;
1512				// TODO: Error handling!
1513
1514		if (event->Team() != fTeamID) {
1515			TRACE_EVENTS("TeamDebugger for team %" B_PRId32 ": received event "
1516				"from team %" B_PRId32 "!\n", fTeamID, event->Team());
1517			continue;
1518		}
1519
1520		BMessage message(MSG_DEBUGGER_EVENT);
1521		if (message.AddPointer("event", event) != B_OK
1522			|| PostMessage(&message) != B_OK) {
1523			// TODO: Continue thread if necessary!
1524			delete event;
1525		}
1526	}
1527
1528	return B_OK;
1529}
1530
1531
1532void
1533TeamDebugger::_HandleDebuggerMessage(DebugEvent* event)
1534{
1535	TRACE_EVENTS("TeamDebugger::_HandleDebuggerMessage(): %" B_PRId32 "\n",
1536		event->EventType());
1537
1538	bool handled = false;
1539
1540	ThreadHandler* handler = _GetThreadHandler(event->Thread());
1541	BReference<ThreadHandler> handlerReference(handler, true);
1542
1543	switch (event->EventType()) {
1544		case B_DEBUGGER_MESSAGE_THREAD_DEBUGGED:
1545			TRACE_EVENTS("B_DEBUGGER_MESSAGE_THREAD_DEBUGGED: thread: %"
1546				B_PRId32 "\n", event->Thread());
1547
1548			if (handler != NULL) {
1549				handled = handler->HandleThreadDebugged(
1550					dynamic_cast<ThreadDebuggedEvent*>(event));
1551			}
1552			break;
1553		case B_DEBUGGER_MESSAGE_DEBUGGER_CALL:
1554			TRACE_EVENTS("B_DEBUGGER_MESSAGE_DEBUGGER_CALL: thread: %" B_PRId32
1555				"\n", event->Thread());
1556
1557			if (handler != NULL) {
1558				handled = handler->HandleDebuggerCall(
1559					dynamic_cast<DebuggerCallEvent*>(event));
1560			}
1561			break;
1562		case B_DEBUGGER_MESSAGE_BREAKPOINT_HIT:
1563			TRACE_EVENTS("B_DEBUGGER_MESSAGE_BREAKPOINT_HIT: thread: %" B_PRId32
1564				"\n", event->Thread());
1565
1566			if (handler != NULL) {
1567				handled = handler->HandleBreakpointHit(
1568					dynamic_cast<BreakpointHitEvent*>(event));
1569			}
1570			break;
1571		case B_DEBUGGER_MESSAGE_WATCHPOINT_HIT:
1572			TRACE_EVENTS("B_DEBUGGER_MESSAGE_WATCHPOINT_HIT: thread: %" B_PRId32
1573				"\n", event->Thread());
1574
1575			if (handler != NULL) {
1576				handled = handler->HandleWatchpointHit(
1577					dynamic_cast<WatchpointHitEvent*>(event));
1578			}
1579			break;
1580		case B_DEBUGGER_MESSAGE_SINGLE_STEP:
1581			TRACE_EVENTS("B_DEBUGGER_MESSAGE_SINGLE_STEP: thread: %" B_PRId32
1582				"\n", event->Thread());
1583
1584			if (handler != NULL) {
1585				handled = handler->HandleSingleStep(
1586					dynamic_cast<SingleStepEvent*>(event));
1587			}
1588			break;
1589		case B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED:
1590			TRACE_EVENTS("B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED: thread: %"
1591				B_PRId32 "\n", event->Thread());
1592
1593			if (handler != NULL) {
1594				handled = handler->HandleExceptionOccurred(
1595					dynamic_cast<ExceptionOccurredEvent*>(event));
1596			}
1597			break;
1598//		case B_DEBUGGER_MESSAGE_TEAM_CREATED:
1599//printf("B_DEBUGGER_MESSAGE_TEAM_CREATED: team: %ld\n", message.team_created.new_team);
1600//			break;
1601		case B_DEBUGGER_MESSAGE_TEAM_DELETED:
1602		{
1603			TRACE_EVENTS("B_DEBUGGER_MESSAGE_TEAM_DELETED: team: %" B_PRId32
1604				"\n", event->Team());
1605			TeamDeletedEvent* teamEvent
1606				= dynamic_cast<TeamDeletedEvent*>(event);
1607			handled = _HandleTeamDeleted(teamEvent);
1608			break;
1609		}
1610		case B_DEBUGGER_MESSAGE_TEAM_EXEC:
1611		{
1612			TRACE_EVENTS("B_DEBUGGER_MESSAGE_TEAM_EXEC: team: %" B_PRId32 "\n",
1613				event->Team());
1614
1615			TeamExecEvent* teamEvent
1616				= dynamic_cast<TeamExecEvent*>(event);
1617			_PrepareForTeamExec(teamEvent);
1618			break;
1619		}
1620		case B_DEBUGGER_MESSAGE_THREAD_CREATED:
1621		{
1622			ThreadCreatedEvent* threadEvent
1623				= dynamic_cast<ThreadCreatedEvent*>(event);
1624			TRACE_EVENTS("B_DEBUGGER_MESSAGE_THREAD_CREATED: thread: %" B_PRId32
1625				"\n", threadEvent->NewThread());
1626			handled = _HandleThreadCreated(threadEvent);
1627			break;
1628		}
1629		case DEBUGGER_MESSAGE_THREAD_RENAMED:
1630		{
1631			ThreadRenamedEvent* threadEvent
1632				= dynamic_cast<ThreadRenamedEvent*>(event);
1633			TRACE_EVENTS("DEBUGGER_MESSAGE_THREAD_RENAMED: thread: %" B_PRId32
1634				" (\"%s\")\n",
1635				threadEvent->RenamedThread(), threadEvent->NewName());
1636			handled = _HandleThreadRenamed(threadEvent);
1637			break;
1638		}
1639		case DEBUGGER_MESSAGE_THREAD_PRIORITY_CHANGED:
1640		{
1641			ThreadPriorityChangedEvent* threadEvent
1642				= dynamic_cast<ThreadPriorityChangedEvent*>(event);
1643			TRACE_EVENTS("B_DEBUGGER_MESSAGE_THREAD_PRIORITY_CHANGED: thread:"
1644				" %" B_PRId32 "\n", threadEvent->ChangedThread());
1645			handled = _HandleThreadPriorityChanged(threadEvent);
1646			break;
1647		}
1648		case B_DEBUGGER_MESSAGE_THREAD_DELETED:
1649			TRACE_EVENTS("B_DEBUGGER_MESSAGE_THREAD_DELETED: thread: %" B_PRId32
1650				"\n", event->Thread());
1651			handled = _HandleThreadDeleted(
1652				dynamic_cast<ThreadDeletedEvent*>(event));
1653			break;
1654		case B_DEBUGGER_MESSAGE_IMAGE_CREATED:
1655		{
1656			ImageCreatedEvent* imageEvent
1657				= dynamic_cast<ImageCreatedEvent*>(event);
1658			TRACE_EVENTS("B_DEBUGGER_MESSAGE_IMAGE_CREATED: image: \"%s\" "
1659				"(%" B_PRId32 ")\n", imageEvent->GetImageInfo().Name().String(),
1660				imageEvent->GetImageInfo().ImageID());
1661			handled = _HandleImageCreated(imageEvent);
1662			break;
1663		}
1664		case B_DEBUGGER_MESSAGE_IMAGE_DELETED:
1665		{
1666			ImageDeletedEvent* imageEvent
1667				= dynamic_cast<ImageDeletedEvent*>(event);
1668			TRACE_EVENTS("B_DEBUGGER_MESSAGE_IMAGE_DELETED: image: \"%s\" "
1669				"(%" B_PRId32 ")\n", imageEvent->GetImageInfo().Name().String(),
1670				imageEvent->GetImageInfo().ImageID());
1671			handled = _HandleImageDeleted(imageEvent);
1672			break;
1673		}
1674		case B_DEBUGGER_MESSAGE_POST_SYSCALL:
1675		{
1676			PostSyscallEvent* postSyscallEvent
1677				= dynamic_cast<PostSyscallEvent*>(event);
1678			TRACE_EVENTS("B_DEBUGGER_MESSAGE_POST_SYSCALL: syscall: %"
1679				B_PRIu32 "\n", postSyscallEvent->GetSyscallInfo().Syscall());
1680			handled = _HandlePostSyscall(postSyscallEvent);
1681
1682			// if a thread was blocked in a syscall when we requested to
1683			// stop it for debugging, then that request will interrupt
1684			// said call, and the post syscall event will be all we get
1685			// in response. Consequently, we need to treat this case as
1686			// equivalent to having received a thread debugged event.
1687			AutoLocker< ::Team> teamLocker(fTeam);
1688			::Thread* thread = fTeam->ThreadByID(event->Thread());
1689			if (handler != NULL && thread != NULL
1690				&& thread->StopRequestPending()) {
1691				handled = handler->HandleThreadDebugged(NULL);
1692			}
1693			break;
1694		}
1695		case B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED:
1696		{
1697			TRACE_EVENTS("B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED: thread: %"
1698				B_PRId32 "\n", event->Thread());
1699
1700			if (handler != NULL) {
1701				handled = handler->HandleSignalReceived(
1702					dynamic_cast<SignalReceivedEvent*>(event));
1703			}
1704			break;
1705		}
1706		case B_DEBUGGER_MESSAGE_PRE_SYSCALL:
1707		case B_DEBUGGER_MESSAGE_PROFILER_UPDATE:
1708		case B_DEBUGGER_MESSAGE_HANDED_OVER:
1709			// not interested
1710			break;
1711		default:
1712			WARNING("TeamDebugger for team %" B_PRId32 ": unknown event type: "
1713				"%" B_PRId32 "\n", fTeamID, event->EventType());
1714			break;
1715	}
1716
1717	if (!handled && event->ThreadStopped())
1718		fDebuggerInterface->ContinueThread(event->Thread());
1719}
1720
1721
1722bool
1723TeamDebugger::_HandleTeamDeleted(TeamDeletedEvent* event)
1724{
1725	char message[64];
1726	fDebuggerInterface->Close(false);
1727
1728	snprintf(message, sizeof(message), "Team %" B_PRId32 " has terminated. ",
1729		event->Team());
1730
1731	int32 result = fUserInterface->SynchronouslyAskUser("Team terminated",
1732		message, "Do nothing", "Quit", fCommandLineArgc != 0
1733			? "Restart team" : NULL);
1734
1735	switch (result) {
1736		case 1:
1737		case -1:
1738		{
1739			PostMessage(B_QUIT_REQUESTED);
1740			break;
1741		}
1742		case 2:
1743		{
1744			_SaveSettings();
1745			fListener->TeamDebuggerRestartRequested(this);
1746			break;
1747		}
1748		default:
1749			break;
1750	}
1751
1752	return true;
1753}
1754
1755
1756bool
1757TeamDebugger::_HandleThreadCreated(ThreadCreatedEvent* event)
1758{
1759	AutoLocker< ::Team> locker(fTeam);
1760
1761	ThreadInfo info;
1762	status_t error = fDebuggerInterface->GetThreadInfo(event->NewThread(),
1763		info);
1764	if (error == B_OK) {
1765		::Thread* thread;
1766		fTeam->AddThread(info, &thread);
1767
1768		ThreadHandler* handler = new(std::nothrow) ThreadHandler(thread,
1769			fWorker, fDebuggerInterface, this, fBreakpointManager);
1770		if (handler != NULL) {
1771			fThreadHandlers.Insert(handler);
1772			handler->Init();
1773		}
1774	}
1775
1776	return false;
1777}
1778
1779
1780bool
1781TeamDebugger::_HandleThreadRenamed(ThreadRenamedEvent* event)
1782{
1783	AutoLocker< ::Team> locker(fTeam);
1784
1785	::Thread* thread = fTeam->ThreadByID(event->RenamedThread());
1786
1787	if (thread != NULL)
1788		thread->SetName(event->NewName());
1789
1790	return false;
1791}
1792
1793
1794bool
1795TeamDebugger::_HandleThreadPriorityChanged(ThreadPriorityChangedEvent*)
1796{
1797	// TODO: implement once we actually track thread priorities
1798
1799	return false;
1800}
1801
1802
1803bool
1804TeamDebugger::_HandleThreadDeleted(ThreadDeletedEvent* event)
1805{
1806	AutoLocker< ::Team> locker(fTeam);
1807	if (ThreadHandler* handler = fThreadHandlers.Lookup(event->Thread())) {
1808		fThreadHandlers.Remove(handler);
1809		handler->ReleaseReference();
1810	}
1811	fTeam->RemoveThread(event->Thread());
1812	return false;
1813}
1814
1815
1816bool
1817TeamDebugger::_HandleImageCreated(ImageCreatedEvent* event)
1818{
1819	AutoLocker< ::Team> locker(fTeam);
1820	_AddImage(event->GetImageInfo());
1821
1822	ImageInfoPendingThread* info = new(std::nothrow) ImageInfoPendingThread(
1823		event->GetImageInfo().ImageID(), event->Thread());
1824	if (info == NULL)
1825		return false;
1826
1827	fImageInfoPendingThreads->Insert(info);
1828	return true;
1829}
1830
1831
1832bool
1833TeamDebugger::_HandleImageDeleted(ImageDeletedEvent* event)
1834{
1835	AutoLocker< ::Team> locker(fTeam);
1836	fTeam->RemoveImage(event->GetImageInfo().ImageID());
1837
1838	ImageHandler* imageHandler = fImageHandlers->Lookup(
1839		event->GetImageInfo().ImageID());
1840	if (imageHandler == NULL)
1841		return false;
1842
1843	fImageHandlers->Remove(imageHandler);
1844	BReference<ImageHandler> imageHandlerReference(imageHandler, true);
1845	locker.Unlock();
1846
1847	// remove breakpoints in the image
1848	fBreakpointManager->RemoveImageBreakpoints(imageHandler->GetImage());
1849
1850	return false;
1851}
1852
1853
1854bool
1855TeamDebugger::_HandlePostSyscall(PostSyscallEvent* event)
1856{
1857	const SyscallInfo& info = event->GetSyscallInfo();
1858
1859	switch (info.Syscall()) {
1860		case SYSCALL_WRITE:
1861		{
1862			if ((ssize_t)info.ReturnValue() <= 0)
1863				break;
1864
1865			int32 fd;
1866			target_addr_t address;
1867			size_t size;
1868			// TODO: decoding the syscall arguments should probably be
1869			// factored out into an Architecture method of its own, since
1870			// there's no guarantee the target architecture has the same
1871			// endianness as the host. This could re-use the syscall
1872			// argument parser that strace uses, though that would need to
1873			// be adapted to handle the aforementioned endian differences.
1874			// This works for x86{-64} for now though.
1875			if (fTeam->GetArchitecture()->AddressSize() == 4) {
1876				const uint32* args = (const uint32*)info.Arguments();
1877				fd = args[0];
1878				address = args[3];
1879				size = args[4];
1880			} else {
1881				const uint64* args = (const uint64*)info.Arguments();
1882				fd = args[0];
1883				address = args[2];
1884				size = args[3];
1885			}
1886
1887			if (fd == 1 || fd == 2) {
1888				BString data;
1889
1890				ssize_t result = fDebuggerInterface->ReadMemoryString(
1891					address, size, data);
1892				if (result >= 0)
1893					fTeam->NotifyConsoleOutputReceived(fd, data);
1894			}
1895			break;
1896		}
1897		case SYSCALL_WRITEV:
1898		{
1899			// TODO: handle
1900		}
1901		default:
1902			break;
1903	}
1904
1905	return false;
1906}
1907
1908
1909void
1910TeamDebugger::_PrepareForTeamExec(TeamExecEvent* event)
1911{
1912	// NB: must be called with team lock held.
1913
1914	_SaveSettings();
1915
1916	// when notified of exec, we need to clear out data related
1917	// to the old team.
1918	const ImageList& images = fTeam->Images();
1919
1920	for (ImageList::ConstIterator it = images.GetIterator();
1921			Image* image = it.Next();) {
1922		fBreakpointManager->RemoveImageBreakpoints(image);
1923	}
1924
1925	BObjectList<UserBreakpoint> breakpointsToRemove(20, false);
1926	const UserBreakpointList& breakpoints = fTeam->UserBreakpoints();
1927	for (UserBreakpointList::ConstIterator it = breakpoints.GetIterator();
1928			UserBreakpoint* breakpoint = it.Next();) {
1929		breakpointsToRemove.AddItem(breakpoint);
1930		breakpoint->AcquireReference();
1931	}
1932
1933	for (int32 i = 0; i < breakpointsToRemove.CountItems(); i++) {
1934		UserBreakpoint* breakpoint = breakpointsToRemove.ItemAt(i);
1935		fTeam->RemoveUserBreakpoint(breakpoint);
1936		fTeam->NotifyUserBreakpointChanged(breakpoint);
1937		breakpoint->ReleaseReference();
1938	}
1939
1940	fTeam->ClearImages();
1941	fTeam->ClearSignalDispositionMappings();
1942	fExecPending = true;
1943}
1944
1945
1946void
1947TeamDebugger::_HandleImageDebugInfoChanged(image_id imageID)
1948{
1949	// get the image (via the image handler)
1950	AutoLocker< ::Team> locker(fTeam);
1951	ImageHandler* imageHandler = fImageHandlers->Lookup(imageID);
1952	if (imageHandler == NULL)
1953		return;
1954
1955	Image* image = imageHandler->GetImage();
1956	BReference<Image> imageReference(image);
1957	image_debug_info_state state = image->ImageDebugInfoState();
1958
1959	bool handlePostExecSetup = fExecPending && image->Type() == B_APP_IMAGE
1960		&& state != IMAGE_DEBUG_INFO_LOADING;
1961	// this needs to be done first so that breakpoints are loaded.
1962	// otherwise, UpdateImageBreakpoints() won't find the appropriate
1963	// UserBreakpoints to create/install instances for.
1964	if (handlePostExecSetup) {
1965		fTeam->SetName(image->Name());
1966		_LoadSettings();
1967		fExecPending = false;
1968	}
1969
1970	locker.Unlock();
1971
1972	if (state == IMAGE_DEBUG_INFO_LOADED
1973		|| state == IMAGE_DEBUG_INFO_UNAVAILABLE) {
1974
1975		// update breakpoints in the image
1976		fBreakpointManager->UpdateImageBreakpoints(image);
1977
1978		ImageInfoPendingThread* thread =  fImageInfoPendingThreads
1979			->Lookup(imageID);
1980		if (thread != NULL) {
1981			fImageInfoPendingThreads->Remove(thread);
1982			ObjectDeleter<ImageInfoPendingThread> threadDeleter(thread);
1983			locker.Lock();
1984			ThreadHandler* handler = _GetThreadHandler(thread->ThreadID());
1985			BReference<ThreadHandler> handlerReference(handler, true);
1986			if (fTeam->StopOnImageLoad()) {
1987
1988				bool stop = true;
1989				const BString& imageName = image->Name();
1990				// only match on the image filename itself
1991				const char* rawImageName = imageName.String()
1992					+ imageName.FindLast('/') + 1;
1993				if (fTeam->StopImageNameListEnabled()) {
1994					const BStringList& nameList = fTeam->StopImageNames();
1995					stop = nameList.HasString(rawImageName);
1996				}
1997
1998				if (stop && handler != NULL) {
1999					BString stopReason;
2000					stopReason.SetToFormat("Image '%s' loaded.",
2001						rawImageName);
2002					locker.Unlock();
2003
2004					if (handler->HandleThreadDebugged(NULL, stopReason))
2005						return;
2006				} else
2007					locker.Unlock();
2008			} else if (handlePostExecSetup) {
2009				// in the case of an exec(), we can't stop in main() until
2010				// the new app image has been loaded, so we know where to
2011				// set the main breakpoint at.
2012				SymbolInfo symbolInfo;
2013				if (fDebuggerInterface->GetSymbolInfo(fTeam->ID(), image->ID(),
2014						"main", B_SYMBOL_TYPE_TEXT, symbolInfo) == B_OK) {
2015					handler->SetBreakpointAndRun(symbolInfo.Address());
2016				}
2017			} else {
2018				locker.Unlock();
2019				fDebuggerInterface->ContinueThread(thread->ThreadID());
2020			}
2021		}
2022	}
2023}
2024
2025
2026void
2027TeamDebugger::_HandleImageFileChanged(image_id imageID)
2028{
2029	TRACE_IMAGES("TeamDebugger::_HandleImageFileChanged(%" B_PRId32 ")\n",
2030		imageID);
2031// TODO: Reload the debug info!
2032}
2033
2034
2035void
2036TeamDebugger::_HandleSetUserBreakpoint(target_addr_t address, bool enabled,
2037	bool hidden)
2038{
2039	TRACE_CONTROL("TeamDebugger::_HandleSetUserBreakpoint(%#" B_PRIx64
2040		", %d, %d)\n", address, enabled, hidden);
2041
2042	// check whether there already is a breakpoint
2043	AutoLocker< ::Team> locker(fTeam);
2044
2045	Breakpoint* breakpoint = fTeam->BreakpointAtAddress(address);
2046	UserBreakpoint* userBreakpoint = NULL;
2047	if (breakpoint != NULL && breakpoint->FirstUserBreakpoint() != NULL)
2048		userBreakpoint = breakpoint->FirstUserBreakpoint()->GetUserBreakpoint();
2049	BReference<UserBreakpoint> userBreakpointReference(userBreakpoint);
2050
2051	if (userBreakpoint == NULL) {
2052		TRACE_CONTROL("  no breakpoint yet\n");
2053
2054		// get the function at the address
2055		Image* image = fTeam->ImageByAddress(address);
2056
2057		TRACE_CONTROL("  image: %p\n", image);
2058
2059		if (image == NULL)
2060			return;
2061		ImageDebugInfo* imageDebugInfo = image->GetImageDebugInfo();
2062
2063		TRACE_CONTROL("  image debug info: %p\n", imageDebugInfo);
2064
2065		if (imageDebugInfo == NULL)
2066			return;
2067			// TODO: Handle this case by loading the debug info, if possible!
2068		FunctionInstance* functionInstance
2069			= imageDebugInfo->FunctionAtAddress(address);
2070
2071		TRACE_CONTROL("  function instance: %p\n", functionInstance);
2072
2073		if (functionInstance == NULL)
2074			return;
2075		Function* function = functionInstance->GetFunction();
2076
2077		TRACE_CONTROL("  function: %p\n", function);
2078
2079		// get the source location for the address
2080		FunctionDebugInfo* functionDebugInfo
2081			= functionInstance->GetFunctionDebugInfo();
2082		SourceLocation sourceLocation;
2083		Statement* breakpointStatement = NULL;
2084		if (functionDebugInfo->GetSpecificImageDebugInfo()->GetStatement(
2085				functionDebugInfo, address, breakpointStatement) != B_OK) {
2086			return;
2087		}
2088
2089		sourceLocation = breakpointStatement->StartSourceLocation();
2090		breakpointStatement->ReleaseReference();
2091
2092		target_addr_t relativeAddress = address - functionInstance->Address();
2093
2094		TRACE_CONTROL("  relative address: %#" B_PRIx64 ", source location: "
2095			"(%" B_PRId32 ", %" B_PRId32 ")\n", relativeAddress,
2096			sourceLocation.Line(), sourceLocation.Column());
2097
2098		// get function id
2099		FunctionID* functionID = functionInstance->GetFunctionID();
2100		if (functionID == NULL)
2101			return;
2102		BReference<FunctionID> functionIDReference(functionID, true);
2103
2104		// create the user breakpoint
2105		userBreakpoint = new(std::nothrow) UserBreakpoint(
2106			UserBreakpointLocation(functionID, function->SourceFile(),
2107				sourceLocation, relativeAddress));
2108		if (userBreakpoint == NULL)
2109			return;
2110		userBreakpointReference.SetTo(userBreakpoint, true);
2111
2112		userBreakpoint->SetHidden(hidden);
2113
2114		TRACE_CONTROL("  created user breakpoint: %p\n", userBreakpoint);
2115
2116		// iterate through all function instances and create
2117		// UserBreakpointInstances
2118		for (FunctionInstanceList::ConstIterator it
2119					= function->Instances().GetIterator();
2120				FunctionInstance* instance = it.Next();) {
2121			TRACE_CONTROL("  function instance %p: range: %#" B_PRIx64 " - %#"
2122				B_PRIx64 "\n", instance, instance->Address(),
2123				instance->Address() + instance->Size());
2124
2125			// get the breakpoint address for the instance
2126			target_addr_t instanceAddress = 0;
2127			if (instance == functionInstance) {
2128				instanceAddress = address;
2129			} else if (functionInstance->SourceFile() != NULL) {
2130				// We have a source file, so get the address for the source
2131				// location.
2132				Statement* statement = NULL;
2133				functionDebugInfo = instance->GetFunctionDebugInfo();
2134				functionDebugInfo->GetSpecificImageDebugInfo()
2135					->GetStatementAtSourceLocation(functionDebugInfo,
2136						sourceLocation, statement);
2137				if (statement != NULL) {
2138					instanceAddress = statement->CoveringAddressRange().Start();
2139						// TODO: What about BreakpointAllowed()?
2140					statement->ReleaseReference();
2141				}
2142			}
2143
2144			TRACE_CONTROL("    breakpoint address using source info: %" B_PRIx64
2145				"\n", instanceAddress);
2146
2147			if (instanceAddress == 0) {
2148				// No source file (or we failed getting the statement), so try
2149				// to use the same relative address.
2150				if (relativeAddress > instance->Size())
2151					continue;
2152				instanceAddress = instance->Address() + relativeAddress;
2153			}
2154
2155			TRACE_CONTROL("    final breakpoint address: %" B_PRIx64 "\n",
2156				instanceAddress);
2157
2158			UserBreakpointInstance* breakpointInstance = new(std::nothrow)
2159				UserBreakpointInstance(userBreakpoint, instanceAddress);
2160			if (breakpointInstance == NULL
2161				|| !userBreakpoint->AddInstance(breakpointInstance)) {
2162				delete breakpointInstance;
2163				return;
2164			}
2165
2166			TRACE_CONTROL("  breakpoint instance: %p\n", breakpointInstance);
2167		}
2168	}
2169
2170	locker.Unlock();
2171
2172	_HandleSetUserBreakpoint(userBreakpoint, enabled);
2173}
2174
2175
2176void
2177TeamDebugger::_HandleSetUserBreakpoint(UserBreakpoint* breakpoint, bool enabled)
2178{
2179	status_t error = fBreakpointManager->InstallUserBreakpoint(breakpoint,
2180		enabled);
2181	if (error != B_OK) {
2182		_NotifyUser("Install Breakpoint", "Failed to install breakpoint: %s",
2183			strerror(error));
2184	}
2185}
2186
2187
2188void
2189TeamDebugger::_HandleClearUserBreakpoint(target_addr_t address)
2190{
2191	TRACE_CONTROL("TeamDebugger::_HandleClearUserBreakpoint(%#" B_PRIx64 ")\n",
2192		address);
2193
2194	AutoLocker< ::Team> locker(fTeam);
2195
2196	Breakpoint* breakpoint = fTeam->BreakpointAtAddress(address);
2197	if (breakpoint == NULL || breakpoint->FirstUserBreakpoint() == NULL)
2198		return;
2199	UserBreakpoint* userBreakpoint
2200		= breakpoint->FirstUserBreakpoint()->GetUserBreakpoint();
2201	BReference<UserBreakpoint> userBreakpointReference(userBreakpoint);
2202
2203	locker.Unlock();
2204
2205	_HandleClearUserBreakpoint(userBreakpoint);
2206}
2207
2208
2209void
2210TeamDebugger::_HandleClearUserBreakpoint(UserBreakpoint* breakpoint)
2211{
2212	fBreakpointManager->UninstallUserBreakpoint(breakpoint);
2213}
2214
2215
2216void
2217TeamDebugger::_HandleSetWatchpoint(target_addr_t address, uint32 type,
2218	int32 length, bool enabled)
2219{
2220	Watchpoint* watchpoint = new(std::nothrow) Watchpoint(address, type,
2221		length);
2222
2223	if (watchpoint == NULL)
2224		return;
2225	BReference<Watchpoint> watchpointRef(watchpoint, true);
2226
2227	_HandleSetWatchpoint(watchpoint, enabled);
2228}
2229
2230
2231void
2232TeamDebugger::_HandleSetWatchpoint(Watchpoint* watchpoint, bool enabled)
2233{
2234	status_t error = fWatchpointManager->InstallWatchpoint(watchpoint,
2235		enabled);
2236	if (error != B_OK) {
2237		_NotifyUser("Install Watchpoint", "Failed to install watchpoint: %s",
2238			strerror(error));
2239	}
2240}
2241
2242
2243void
2244TeamDebugger::_HandleClearWatchpoint(target_addr_t address)
2245{
2246	TRACE_CONTROL("TeamDebugger::_HandleClearWatchpoint(%#" B_PRIx64 ")\n",
2247		address);
2248
2249	AutoLocker< ::Team> locker(fTeam);
2250
2251	Watchpoint* watchpoint = fTeam->WatchpointAtAddress(address);
2252	if (watchpoint == NULL)
2253		return;
2254	BReference<Watchpoint> watchpointReference(watchpoint);
2255
2256	locker.Unlock();
2257
2258	_HandleClearWatchpoint(watchpoint);
2259}
2260
2261
2262void
2263TeamDebugger::_HandleClearWatchpoint(Watchpoint* watchpoint)
2264{
2265	fWatchpointManager->UninstallWatchpoint(watchpoint);
2266}
2267
2268
2269void
2270TeamDebugger::_HandleInspectAddress(target_addr_t address,
2271	TeamMemoryBlock::Listener* listener)
2272{
2273	TRACE_CONTROL("TeamDebugger::_HandleInspectAddress(%" B_PRIx64 ", %p)\n",
2274		address, listener);
2275
2276	TeamMemoryBlock* memoryBlock = fMemoryBlockManager
2277		->GetMemoryBlock(address);
2278
2279	if (memoryBlock == NULL) {
2280		_NotifyUser("Inspect Address", "Failed to allocate memory block");
2281		return;
2282	}
2283
2284	if (!memoryBlock->IsValid()) {
2285		AutoLocker< ::Team> teamLocker(fTeam);
2286
2287		if (!memoryBlock->HasListener(listener))
2288			memoryBlock->AddListener(listener);
2289
2290		TeamMemory* memory = fTeam->GetTeamMemory();
2291		// schedule the job
2292		status_t result;
2293		if ((result = fWorker->ScheduleJob(
2294			new(std::nothrow) RetrieveMemoryBlockJob(fTeam, memory,
2295				memoryBlock),
2296			this)) != B_OK) {
2297
2298			memoryBlock->NotifyDataRetrieved(result);
2299			memoryBlock->ReleaseReference();
2300
2301			_NotifyUser("Inspect Address", "Failed to retrieve memory data: %s",
2302				strerror(result));
2303		}
2304	} else
2305		memoryBlock->NotifyDataRetrieved();
2306
2307}
2308
2309
2310void
2311TeamDebugger::_HandleWriteMemory(target_addr_t address, void* data,
2312	target_size_t size)
2313{
2314	TRACE_CONTROL("TeamDebugger::_HandleWriteTargetMemory(%" B_PRIx64 ", %p, "
2315		"%" B_PRIu64 ")\n", address, data, size);
2316
2317	AutoLocker< ::Team> teamLocker(fTeam);
2318	TeamMemory* memory = fTeam->GetTeamMemory();
2319	// schedule the job
2320	status_t result;
2321	if ((result = fWorker->ScheduleJob(
2322		new(std::nothrow) WriteMemoryJob(fTeam, memory, address, data, size),
2323		this)) != B_OK) {
2324		_NotifyUser("Write Memory", "Failed to write memory data: %s",
2325			strerror(result));
2326	}
2327}
2328
2329
2330void
2331TeamDebugger::_HandleEvaluateExpression(SourceLanguage* language,
2332	ExpressionInfo* info, StackFrame* frame, ::Thread* thread)
2333{
2334	status_t result = fWorker->ScheduleJob(
2335		new(std::nothrow) ExpressionEvaluationJob(fTeam, fDebuggerInterface,
2336			language, info, frame, thread));
2337	if (result != B_OK) {
2338		_NotifyUser("Evaluate Expression", "Failed to evaluate expression: %s",
2339			strerror(result));
2340	}
2341}
2342
2343
2344void
2345TeamDebugger::_HandleWriteCoreFile(const entry_ref& targetPath)
2346{
2347	status_t result = fWorker->ScheduleJob(
2348		new(std::nothrow) WriteCoreFileJob(fTeam, fDebuggerInterface,
2349			targetPath));
2350	if (result != B_OK) {
2351		_NotifyUser("Write Core File", "Failed to write core file: %s",
2352			strerror(result));
2353	}
2354}
2355
2356
2357status_t
2358TeamDebugger::_HandleSetArguments(int argc, const char* const* argv)
2359{
2360	fCommandLineArgc = argc;
2361	fCommandLineArgv = new(std::nothrow) const char*[argc];
2362	if (fCommandLineArgv == NULL)
2363		return B_NO_MEMORY;
2364
2365	memset(const_cast<char **>(fCommandLineArgv), 0, sizeof(char*) * argc);
2366
2367	for (int i = 0; i < argc; i++) {
2368		fCommandLineArgv[i] = strdup(argv[i]);
2369		if (fCommandLineArgv[i] == NULL)
2370			return B_NO_MEMORY;
2371	}
2372
2373	return B_OK;
2374}
2375
2376
2377void
2378TeamDebugger::_HandleDebugInfoJobUserInput(ImageDebugInfoLoadingState* state)
2379{
2380	SpecificImageDebugInfoLoadingState* specificState
2381		= state->GetSpecificDebugInfoLoadingState();
2382
2383	ImageDebugLoadingStateHandler* handler;
2384	if (ImageDebugLoadingStateHandlerRoster::Default()
2385			->FindStateHandler(specificState, handler) != B_OK) {
2386		TRACE_JOBS("TeamDebugger::_HandleDebugInfoJobUserInput(): "
2387			"Failed to find appropriate information handler, aborting.");
2388		return;
2389	}
2390
2391	handler->HandleState(specificState, fUserInterface);
2392}
2393
2394
2395ThreadHandler*
2396TeamDebugger::_GetThreadHandler(thread_id threadID)
2397{
2398	AutoLocker< ::Team> locker(fTeam);
2399
2400	ThreadHandler* handler = fThreadHandlers.Lookup(threadID);
2401	if (handler != NULL)
2402		handler->AcquireReference();
2403	return handler;
2404}
2405
2406
2407status_t
2408TeamDebugger::_AddImage(const ImageInfo& imageInfo, Image** _image)
2409{
2410	LocatableFile* file = NULL;
2411	if (strchr(imageInfo.Name(), '/') != NULL)
2412		file = fFileManager->GetTargetFile(imageInfo.Name());
2413	BReference<LocatableFile> imageFileReference(file, true);
2414
2415	Image* image;
2416	status_t error = fTeam->AddImage(imageInfo, file, &image);
2417	if (error != B_OK)
2418		return error;
2419
2420	ImageDebugInfoRequested(image);
2421
2422	ImageHandler* imageHandler = new(std::nothrow) ImageHandler(this, image);
2423	if (imageHandler != NULL)
2424		fImageHandlers->Insert(imageHandler);
2425
2426	if (_image != NULL)
2427		*_image = image;
2428
2429	return B_OK;
2430}
2431
2432
2433void
2434TeamDebugger::_LoadSettings()
2435{
2436	// get the team name
2437	AutoLocker< ::Team> locker(fTeam);
2438	BString teamName = fTeam->Name();
2439	locker.Unlock();
2440
2441	// load the settings
2442	if (fSettingsManager->LoadTeamSettings(teamName, fTeamSettings) != B_OK)
2443		return;
2444
2445	// create the saved breakpoints
2446	for (int32 i = 0; const BreakpointSetting* breakpointSetting
2447			= fTeamSettings.BreakpointAt(i); i++) {
2448		if (breakpointSetting->GetFunctionID() == NULL)
2449			continue;
2450
2451		// get the source file, if any
2452		LocatableFile* sourceFile = NULL;
2453		if (breakpointSetting->SourceFile().Length() > 0) {
2454			sourceFile = fFileManager->GetSourceFile(
2455				breakpointSetting->SourceFile());
2456			if (sourceFile == NULL)
2457				continue;
2458		}
2459		BReference<LocatableFile> sourceFileReference(sourceFile, true);
2460
2461		// create the breakpoint
2462		UserBreakpointLocation location(breakpointSetting->GetFunctionID(),
2463			sourceFile, breakpointSetting->GetSourceLocation(),
2464			breakpointSetting->RelativeAddress());
2465
2466		UserBreakpoint* breakpoint = new(std::nothrow) UserBreakpoint(location);
2467		if (breakpoint == NULL)
2468			return;
2469		BReference<UserBreakpoint> breakpointReference(breakpoint, true);
2470
2471		breakpoint->SetHidden(breakpointSetting->IsHidden());
2472		breakpoint->SetCondition(breakpointSetting->Condition());
2473
2474		// install it
2475		fBreakpointManager->InstallUserBreakpoint(breakpoint,
2476			breakpointSetting->IsEnabled());
2477	}
2478
2479	fFileManager->LoadLocationMappings(fTeamSettings.FileManagerSettings());
2480
2481	const TeamUiSettings* uiSettings = fTeamSettings.UiSettingFor(
2482		fUserInterface->ID());
2483	if (uiSettings != NULL)
2484			fUserInterface->LoadSettings(uiSettings);
2485
2486	const TeamSignalSettings* signalSettings = fTeamSettings.SignalSettings();
2487	if (signalSettings != NULL) {
2488		fTeam->SetDefaultSignalDisposition(
2489			signalSettings->DefaultSignalDisposition());
2490
2491		int32 signal;
2492		int32 disposition;
2493		for (int32 i = 0; i < signalSettings->CountCustomSignalDispositions();
2494			i++) {
2495			if (signalSettings->GetCustomSignalDispositionAt(i, signal,
2496				disposition) == B_OK) {
2497				fTeam->SetCustomSignalDisposition(signal, disposition);
2498			}
2499		}
2500	}
2501}
2502
2503
2504void
2505TeamDebugger::_SaveSettings()
2506{
2507	// get the settings
2508	AutoLocker< ::Team> locker(fTeam);
2509	TeamSettings settings;
2510	if (settings.SetTo(fTeam) != B_OK)
2511		return;
2512
2513	TeamUiSettings* uiSettings = NULL;
2514	if (fUserInterface->SaveSettings(uiSettings) != B_OK)
2515		return;
2516	if (uiSettings != NULL)
2517		settings.AddUiSettings(uiSettings);
2518
2519	// preserve the UI settings from our cached copy.
2520	for (int32 i = 0; i < fTeamSettings.CountUiSettings(); i++) {
2521		const TeamUiSettings* oldUiSettings = fTeamSettings.UiSettingAt(i);
2522		if (strcmp(oldUiSettings->ID(), fUserInterface->ID()) != 0) {
2523			TeamUiSettings* clonedSettings = oldUiSettings->Clone();
2524			if (clonedSettings != NULL)
2525				settings.AddUiSettings(clonedSettings);
2526		}
2527	}
2528
2529	fFileManager->SaveLocationMappings(settings.FileManagerSettings());
2530	locker.Unlock();
2531
2532	// save the settings
2533	fSettingsManager->SaveTeamSettings(settings);
2534}
2535
2536
2537void
2538TeamDebugger::_NotifyUser(const char* title, const char* text,...)
2539{
2540	// print the message
2541	char buffer[1024];
2542	va_list args;
2543	va_start(args, text);
2544	vsnprintf(buffer, sizeof(buffer), text, args);
2545	va_end(args);
2546
2547	// notify the user
2548	fUserInterface->NotifyUser(title, buffer, USER_NOTIFICATION_WARNING);
2549}
2550
2551
2552void
2553TeamDebugger::_ResetUserBackgroundStatusIfNeeded()
2554{
2555	if (!fTerminating && !fWorker->HasPendingJobs())
2556		PostMessage(MSG_RESET_USER_BACKGROUND_STATUS);
2557}
2558
2559
2560// #pragma mark - Listener
2561
2562
2563TeamDebugger::Listener::~Listener()
2564{
2565}
2566