xref: /haiku/src/kits/debugger/controllers/TeamDebugger.cpp (revision 385ee03ba83b7a40d315e17b03031b3ca37820c0)
1 /*
2  * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Copyright 2010-2016, 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 
71 struct TeamDebugger::ImageHandler : public BReferenceable,
72 	private LocatableFile::Listener {
73 public:
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 
101 private:
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 
110 private:
111 	TeamDebugger*	fTeamDebugger;
112 	Image*			fImage;
113 
114 public:
115 	ImageHandler*	fNext;
116 };
117 
118 
119 // #pragma mark - ImageHandlerHashDefinition
120 
121 
122 struct 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 
151 struct TeamDebugger::ImageInfoPendingThread {
152 public:
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 
174 private:
175 	image_id				fImage;
176 	thread_id				fThread;
177 
178 public:
179 	ImageInfoPendingThread*	fNext;
180 };
181 
182 
183 // #pragma mark - ImageHandlerHashDefinition
184 
185 
186 struct 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 
215 TeamDebugger::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 
245 TeamDebugger::~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 
326 status_t
327 TeamDebugger::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);
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 
558 void
559 TeamDebugger::Activate()
560 {
561 	fUserInterface->Show();
562 }
563 
564 
565 void
566 TeamDebugger::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 		default:
967 			BLooper::MessageReceived(message);
968 			break;
969 	}
970 }
971 
972 
973 void
974 TeamDebugger::SourceEntryLocateRequested(const char* sourcePath,
975 	const char* locatedPath)
976 {
977 	AutoLocker<FileManager> locker(fFileManager);
978 	fFileManager->SourceEntryLocated(sourcePath, locatedPath);
979 }
980 
981 
982 void
983 TeamDebugger::SourceEntryInvalidateRequested(LocatableFile* sourceFile)
984 {
985 	AutoLocker< ::Team> locker(fTeam);
986 
987 	fTeam->DebugInfo()->ClearSourceCode(sourceFile);
988 }
989 
990 
991 void
992 TeamDebugger::FunctionSourceCodeRequested(FunctionInstance* functionInstance,
993 	bool forceDisassembly)
994 {
995 	Function* function = functionInstance->GetFunction();
996 
997 	// mark loading
998 	AutoLocker< ::Team> locker(fTeam);
999 
1000 	if (forceDisassembly && functionInstance->SourceCodeState()
1001 			!= FUNCTION_SOURCE_NOT_LOADED) {
1002 		return;
1003 	} else if (!forceDisassembly && function->SourceCodeState()
1004 			== FUNCTION_SOURCE_LOADED) {
1005 		return;
1006 	}
1007 
1008 	functionInstance->SetSourceCode(NULL, FUNCTION_SOURCE_LOADING);
1009 
1010 	bool loadForFunction = false;
1011 	if (!forceDisassembly && function->SourceCodeState()
1012 			== FUNCTION_SOURCE_NOT_LOADED) {
1013 		loadForFunction = true;
1014 		function->SetSourceCode(NULL, FUNCTION_SOURCE_LOADING);
1015 	}
1016 
1017 	locker.Unlock();
1018 
1019 	// schedule the job
1020 	if (fWorker->ScheduleJob(
1021 			new(std::nothrow) LoadSourceCodeJob(fDebuggerInterface,
1022 				fDebuggerInterface->GetArchitecture(), fTeam, functionInstance,
1023 					loadForFunction),
1024 			this) != B_OK) {
1025 		// scheduling failed -- mark unavailable
1026 		locker.Lock();
1027 		function->SetSourceCode(NULL, FUNCTION_SOURCE_UNAVAILABLE);
1028 		locker.Unlock();
1029 	}
1030 }
1031 
1032 
1033 void
1034 TeamDebugger::ImageDebugInfoRequested(Image* image)
1035 {
1036 	LoadImageDebugInfoJob::ScheduleIfNecessary(fWorker, image, this);
1037 }
1038 
1039 
1040 void
1041 TeamDebugger::ValueNodeValueRequested(CpuState* cpuState,
1042 	ValueNodeContainer* container, ValueNode* valueNode)
1043 {
1044 	AutoLocker<ValueNodeContainer> containerLocker(container);
1045 	if (valueNode->Container() != container)
1046 		return;
1047 
1048 	// check whether a job is already in progress
1049 	AutoLocker<Worker> workerLocker(fWorker);
1050 	SimpleJobKey jobKey(valueNode, JOB_TYPE_RESOLVE_VALUE_NODE_VALUE);
1051 	if (fWorker->GetJob(jobKey) != NULL)
1052 		return;
1053 	workerLocker.Unlock();
1054 
1055 	// schedule the job
1056 	status_t error = fWorker->ScheduleJob(
1057 		new(std::nothrow) ResolveValueNodeValueJob(fDebuggerInterface,
1058 			fDebuggerInterface->GetArchitecture(), cpuState,
1059 			fTeam->GetTeamTypeInformation(), container,	valueNode), this);
1060 	if (error != B_OK) {
1061 		// scheduling failed -- set the value to invalid
1062 		valueNode->SetLocationAndValue(NULL, NULL, error);
1063 	}
1064 }
1065 
1066 void
1067 TeamDebugger::ValueNodeWriteRequested(ValueNode* node, CpuState* state,
1068 	Value* newValue)
1069 {
1070 	// schedule the job
1071 	status_t error = fWorker->ScheduleJob(
1072 		new(std::nothrow) WriteValueNodeValueJob(fDebuggerInterface,
1073 			fDebuggerInterface->GetArchitecture(), state,
1074 			fTeam->GetTeamTypeInformation(), node, newValue), this);
1075 	if (error != B_OK) {
1076 		BString message;
1077 		message.SetToFormat("Request to write new value for variable %s "
1078 			"failed: %s.\n", node->Name().String(), strerror(error));
1079 		fUserInterface->NotifyUser("Error", message.String(),
1080 			USER_NOTIFICATION_ERROR);
1081 	}
1082 }
1083 
1084 
1085 void
1086 TeamDebugger::ThreadActionRequested(thread_id threadID,
1087 	uint32 action, target_addr_t address)
1088 {
1089 	BMessage message(action);
1090 	message.AddInt32("thread", threadID);
1091 	message.AddUInt64("address", address);
1092 	PostMessage(&message);
1093 }
1094 
1095 
1096 void
1097 TeamDebugger::SetBreakpointRequested(target_addr_t address, bool enabled,
1098 	bool hidden)
1099 {
1100 	BMessage message(MSG_SET_BREAKPOINT);
1101 	message.AddUInt64("address", (uint64)address);
1102 	message.AddBool("enabled", enabled);
1103 	message.AddBool("hidden", hidden);
1104 	PostMessage(&message);
1105 }
1106 
1107 
1108 void
1109 TeamDebugger::SetBreakpointEnabledRequested(UserBreakpoint* breakpoint,
1110 	bool enabled)
1111 {
1112 	BMessage message(MSG_SET_BREAKPOINT);
1113 	BReference<UserBreakpoint> breakpointReference(breakpoint);
1114 	if (message.AddPointer("breakpoint", breakpoint) == B_OK
1115 		&& message.AddBool("enabled", enabled) == B_OK
1116 		&& PostMessage(&message) == B_OK) {
1117 		breakpointReference.Detach();
1118 	}
1119 }
1120 
1121 
1122 void
1123 TeamDebugger::SetBreakpointConditionRequested(UserBreakpoint* breakpoint,
1124 	const char* condition)
1125 {
1126 	BMessage message(MSG_SET_BREAKPOINT_CONDITION);
1127 	BReference<UserBreakpoint> breakpointReference(breakpoint);
1128 	if (message.AddPointer("breakpoint", breakpoint) == B_OK
1129 		&& message.AddString("condition", condition) == B_OK
1130 		&& PostMessage(&message) == B_OK) {
1131 		breakpointReference.Detach();
1132 	}
1133 }
1134 
1135 
1136 void
1137 TeamDebugger::ClearBreakpointConditionRequested(UserBreakpoint* breakpoint)
1138 {
1139 	BMessage message(MSG_CLEAR_BREAKPOINT_CONDITION);
1140 	BReference<UserBreakpoint> breakpointReference(breakpoint);
1141 	if (message.AddPointer("breakpoint", breakpoint) == B_OK
1142 		&& PostMessage(&message) == B_OK) {
1143 		breakpointReference.Detach();
1144 	}
1145 }
1146 
1147 
1148 void
1149 TeamDebugger::ClearBreakpointRequested(target_addr_t address)
1150 {
1151 	BMessage message(MSG_CLEAR_BREAKPOINT);
1152 	message.AddUInt64("address", (uint64)address);
1153 	PostMessage(&message);
1154 }
1155 
1156 
1157 void
1158 TeamDebugger::SetStopOnImageLoadRequested(bool enabled, bool useImageNames)
1159 {
1160 	BMessage message(MSG_STOP_ON_IMAGE_LOAD);
1161 	message.AddBool("enabled", enabled);
1162 	message.AddBool("useNames", useImageNames);
1163 	PostMessage(&message);
1164 }
1165 
1166 
1167 void
1168 TeamDebugger::AddStopImageNameRequested(const char* name)
1169 {
1170 	BMessage message(MSG_ADD_STOP_IMAGE_NAME);
1171 	message.AddString("name", name);
1172 	PostMessage(&message);
1173 }
1174 
1175 
1176 void
1177 TeamDebugger::RemoveStopImageNameRequested(const char* name)
1178 {
1179 	BMessage message(MSG_REMOVE_STOP_IMAGE_NAME);
1180 	message.AddString("name", name);
1181 	PostMessage(&message);
1182 }
1183 
1184 
1185 void
1186 TeamDebugger::SetDefaultSignalDispositionRequested(int32 disposition)
1187 {
1188 	BMessage message(MSG_SET_DEFAULT_SIGNAL_DISPOSITION);
1189 	message.AddInt32("disposition", disposition);
1190 	PostMessage(&message);
1191 }
1192 
1193 
1194 void
1195 TeamDebugger::SetCustomSignalDispositionRequested(int32 signal,
1196 	int32 disposition)
1197 {
1198 	BMessage message(MSG_SET_CUSTOM_SIGNAL_DISPOSITION);
1199 	message.AddInt32("signal", signal);
1200 	message.AddInt32("disposition", disposition);
1201 	PostMessage(&message);
1202 }
1203 
1204 
1205 void
1206 TeamDebugger::RemoveCustomSignalDispositionRequested(int32 signal)
1207 {
1208 	BMessage message(MSG_REMOVE_CUSTOM_SIGNAL_DISPOSITION);
1209 	message.AddInt32("signal", signal);
1210 	PostMessage(&message);
1211 }
1212 
1213 
1214 void
1215 TeamDebugger::ClearBreakpointRequested(UserBreakpoint* breakpoint)
1216 {
1217 	BMessage message(MSG_CLEAR_BREAKPOINT);
1218 	BReference<UserBreakpoint> breakpointReference(breakpoint);
1219 	if (message.AddPointer("breakpoint", breakpoint) == B_OK
1220 		&& PostMessage(&message) == B_OK) {
1221 		breakpointReference.Detach();
1222 	}
1223 }
1224 
1225 
1226 void
1227 TeamDebugger::SetWatchpointRequested(target_addr_t address, uint32 type,
1228 	int32 length, bool enabled)
1229 {
1230 	BMessage message(MSG_SET_WATCHPOINT);
1231 	message.AddUInt64("address", (uint64)address);
1232 	message.AddUInt32("type", type);
1233 	message.AddInt32("length", length);
1234 	message.AddBool("enabled", enabled);
1235 	PostMessage(&message);
1236 }
1237 
1238 
1239 void
1240 TeamDebugger::SetWatchpointEnabledRequested(Watchpoint* watchpoint,
1241 	bool enabled)
1242 {
1243 	BMessage message(MSG_SET_WATCHPOINT);
1244 	BReference<Watchpoint> watchpointReference(watchpoint);
1245 	if (message.AddPointer("watchpoint", watchpoint) == B_OK
1246 		&& message.AddBool("enabled", enabled) == B_OK
1247 		&& PostMessage(&message) == B_OK) {
1248 		watchpointReference.Detach();
1249 	}
1250 }
1251 
1252 
1253 void
1254 TeamDebugger::ClearWatchpointRequested(target_addr_t address)
1255 {
1256 	BMessage message(MSG_CLEAR_WATCHPOINT);
1257 	message.AddUInt64("address", (uint64)address);
1258 	PostMessage(&message);
1259 }
1260 
1261 
1262 void
1263 TeamDebugger::ClearWatchpointRequested(Watchpoint* watchpoint)
1264 {
1265 	BMessage message(MSG_CLEAR_WATCHPOINT);
1266 	BReference<Watchpoint> watchpointReference(watchpoint);
1267 	if (message.AddPointer("watchpoint", watchpoint) == B_OK
1268 		&& PostMessage(&message) == B_OK) {
1269 		watchpointReference.Detach();
1270 	}
1271 }
1272 
1273 
1274 void
1275 TeamDebugger::InspectRequested(target_addr_t address,
1276 	TeamMemoryBlock::Listener *listener)
1277 {
1278 	BMessage message(MSG_INSPECT_ADDRESS);
1279 	message.AddUInt64("address", address);
1280 	message.AddPointer("listener", listener);
1281 	PostMessage(&message);
1282 }
1283 
1284 
1285 void
1286 TeamDebugger::MemoryWriteRequested(target_addr_t address, const void* data,
1287 	target_size_t size)
1288 {
1289 	BMessage message(MSG_WRITE_TARGET_MEMORY);
1290 	message.AddUInt64("address", address);
1291 	message.AddPointer("data", data);
1292 	message.AddUInt64("size", size);
1293 	PostMessage(&message);
1294 }
1295 
1296 
1297 void
1298 TeamDebugger::ExpressionEvaluationRequested(SourceLanguage* language,
1299 	ExpressionInfo* info, StackFrame* frame, ::Thread* thread)
1300 {
1301 	BMessage message(MSG_EVALUATE_EXPRESSION);
1302 	message.AddPointer("language", language);
1303 	message.AddPointer("info", info);
1304 	if (frame != NULL)
1305 		message.AddPointer("frame", frame);
1306 	if (thread != NULL)
1307 		message.AddPointer("thread", thread);
1308 
1309 	BReference<SourceLanguage> languageReference(language);
1310 	BReference<ExpressionInfo> infoReference(info);
1311 	if (PostMessage(&message) == B_OK) {
1312 		languageReference.Detach();
1313 		infoReference.Detach();
1314 	}
1315 }
1316 
1317 
1318 void
1319 TeamDebugger::DebugReportRequested(entry_ref* targetPath)
1320 {
1321 	BMessage message(MSG_GENERATE_DEBUG_REPORT);
1322 	message.AddRef("target", targetPath);
1323 	PostMessage(&message);
1324 }
1325 
1326 
1327 void
1328 TeamDebugger::WriteCoreFileRequested(entry_ref* targetPath)
1329 {
1330 	BMessage message(MSG_WRITE_CORE_FILE);
1331 	message.AddRef("target", targetPath);
1332 	PostMessage(&message);
1333 }
1334 
1335 
1336 void
1337 TeamDebugger::TeamRestartRequested()
1338 {
1339 	PostMessage(MSG_TEAM_RESTART_REQUESTED);
1340 }
1341 
1342 
1343 bool
1344 TeamDebugger::UserInterfaceQuitRequested(QuitOption quitOption)
1345 {
1346 	bool askUser = false;
1347 	switch (quitOption) {
1348 		case QUIT_OPTION_ASK_USER:
1349 			askUser = true;
1350 			break;
1351 
1352 		case QUIT_OPTION_ASK_KILL_TEAM:
1353 			fKillTeamOnQuit = true;
1354 			break;
1355 
1356 		case QUIT_OPTION_ASK_RESUME_TEAM:
1357 			break;
1358 	}
1359 
1360 	if (askUser) {
1361 		AutoLocker< ::Team> locker(fTeam);
1362 		BString name(fTeam->Name());
1363 		locker.Unlock();
1364 
1365 		BString message;
1366 		message << "What shall be done about the debugged team '";
1367 		message << name;
1368 		message << "'?";
1369 
1370 		name.Remove(0, name.FindLast('/') + 1);
1371 
1372 		BString killLabel("Kill ");
1373 		killLabel << name;
1374 
1375 		BString resumeLabel("Resume ");
1376 		resumeLabel << name;
1377 
1378 		int32 choice = fUserInterface->SynchronouslyAskUser("Quit Debugger",
1379 			message, killLabel, "Cancel", resumeLabel);
1380 
1381 		switch (choice) {
1382 			case 0:
1383 				fKillTeamOnQuit = true;
1384 				break;
1385 			case 1:
1386 			case -1:
1387 				return false;
1388 			case 2:
1389 				// Detach from the team and resume and stopped threads.
1390 				break;
1391 		}
1392 	}
1393 
1394 	PostMessage(B_QUIT_REQUESTED);
1395 
1396 	return true;
1397 }
1398 
1399 
1400 void
1401 TeamDebugger::JobStarted(Job* job)
1402 {
1403 	BString description(job->GetDescription());
1404 	if (!description.IsEmpty()) {
1405 		description.Append(B_UTF8_ELLIPSIS);
1406 		fUserInterface->NotifyBackgroundWorkStatus(description.String());
1407 	}
1408 }
1409 
1410 
1411 void
1412 TeamDebugger::JobDone(Job* job)
1413 {
1414 	TRACE_JOBS("TeamDebugger::JobDone(%p)\n", job);
1415 	_ResetUserBackgroundStatusIfNeeded();
1416 }
1417 
1418 
1419 void
1420 TeamDebugger::JobWaitingForInput(Job* job)
1421 {
1422 	LoadImageDebugInfoJob* infoJob = dynamic_cast<LoadImageDebugInfoJob*>(job);
1423 
1424 	if (infoJob == NULL)
1425 		return;
1426 
1427 	BMessage message(MSG_DEBUG_INFO_NEEDS_USER_INPUT);
1428 	message.AddPointer("job", infoJob);
1429 	message.AddPointer("state", infoJob->GetLoadingState());
1430 	PostMessage(&message);
1431 }
1432 
1433 
1434 void
1435 TeamDebugger::JobFailed(Job* job)
1436 {
1437 	TRACE_JOBS("TeamDebugger::JobFailed(%p)\n", job);
1438 	// TODO: notify user
1439 	_ResetUserBackgroundStatusIfNeeded();
1440 }
1441 
1442 
1443 void
1444 TeamDebugger::JobAborted(Job* job)
1445 {
1446 	TRACE_JOBS("TeamDebugger::JobAborted(%p)\n", job);
1447 	// TODO: For a stack frame source loader thread we should reset the
1448 	// loading state! Asynchronously due to locking order.
1449 	_ResetUserBackgroundStatusIfNeeded();
1450 }
1451 
1452 
1453 void
1454 TeamDebugger::ThreadStateChanged(const ::Team::ThreadEvent& event)
1455 {
1456 	BMessage message(MSG_THREAD_STATE_CHANGED);
1457 	message.AddInt32("thread", event.GetThread()->ID());
1458 	PostMessage(&message);
1459 }
1460 
1461 
1462 void
1463 TeamDebugger::ThreadCpuStateChanged(const ::Team::ThreadEvent& event)
1464 {
1465 	BMessage message(MSG_THREAD_CPU_STATE_CHANGED);
1466 	message.AddInt32("thread", event.GetThread()->ID());
1467 	PostMessage(&message);
1468 }
1469 
1470 
1471 void
1472 TeamDebugger::ThreadStackTraceChanged(const ::Team::ThreadEvent& event)
1473 {
1474 	BMessage message(MSG_THREAD_STACK_TRACE_CHANGED);
1475 	message.AddInt32("thread", event.GetThread()->ID());
1476 	PostMessage(&message);
1477 }
1478 
1479 
1480 void
1481 TeamDebugger::ImageDebugInfoChanged(const ::Team::ImageEvent& event)
1482 {
1483 	BMessage message(MSG_IMAGE_DEBUG_INFO_CHANGED);
1484 	message.AddInt32("image", event.GetImage()->ID());
1485 	PostMessage(&message);
1486 }
1487 
1488 
1489 /*static*/ status_t
1490 TeamDebugger::_DebugEventListenerEntry(void* data)
1491 {
1492 	return ((TeamDebugger*)data)->_DebugEventListener();
1493 }
1494 
1495 
1496 status_t
1497 TeamDebugger::_DebugEventListener()
1498 {
1499 	while (!fTerminating) {
1500 		// get the next event
1501 		DebugEvent* event;
1502 		status_t error = fDebuggerInterface->GetNextDebugEvent(event);
1503 		if (error != B_OK)
1504 			break;
1505 				// TODO: Error handling!
1506 
1507 		if (event->Team() != fTeamID) {
1508 			TRACE_EVENTS("TeamDebugger for team %" B_PRId32 ": received event "
1509 				"from team %" B_PRId32 "!\n", fTeamID, event->Team());
1510 			continue;
1511 		}
1512 
1513 		BMessage message(MSG_DEBUGGER_EVENT);
1514 		if (message.AddPointer("event", event) != B_OK
1515 			|| PostMessage(&message) != B_OK) {
1516 			// TODO: Continue thread if necessary!
1517 			delete event;
1518 		}
1519 	}
1520 
1521 	return B_OK;
1522 }
1523 
1524 
1525 void
1526 TeamDebugger::_HandleDebuggerMessage(DebugEvent* event)
1527 {
1528 	TRACE_EVENTS("TeamDebugger::_HandleDebuggerMessage(): %" B_PRId32 "\n",
1529 		event->EventType());
1530 
1531 	bool handled = false;
1532 
1533 	ThreadHandler* handler = _GetThreadHandler(event->Thread());
1534 	BReference<ThreadHandler> handlerReference(handler);
1535 
1536 	switch (event->EventType()) {
1537 		case B_DEBUGGER_MESSAGE_THREAD_DEBUGGED:
1538 			TRACE_EVENTS("B_DEBUGGER_MESSAGE_THREAD_DEBUGGED: thread: %"
1539 				B_PRId32 "\n", event->Thread());
1540 
1541 			if (handler != NULL) {
1542 				handled = handler->HandleThreadDebugged(
1543 					dynamic_cast<ThreadDebuggedEvent*>(event));
1544 			}
1545 			break;
1546 		case B_DEBUGGER_MESSAGE_DEBUGGER_CALL:
1547 			TRACE_EVENTS("B_DEBUGGER_MESSAGE_DEBUGGER_CALL: thread: %" B_PRId32
1548 				"\n", event->Thread());
1549 
1550 			if (handler != NULL) {
1551 				handled = handler->HandleDebuggerCall(
1552 					dynamic_cast<DebuggerCallEvent*>(event));
1553 			}
1554 			break;
1555 		case B_DEBUGGER_MESSAGE_BREAKPOINT_HIT:
1556 			TRACE_EVENTS("B_DEBUGGER_MESSAGE_BREAKPOINT_HIT: thread: %" B_PRId32
1557 				"\n", event->Thread());
1558 
1559 			if (handler != NULL) {
1560 				handled = handler->HandleBreakpointHit(
1561 					dynamic_cast<BreakpointHitEvent*>(event));
1562 			}
1563 			break;
1564 		case B_DEBUGGER_MESSAGE_WATCHPOINT_HIT:
1565 			TRACE_EVENTS("B_DEBUGGER_MESSAGE_WATCHPOINT_HIT: thread: %" B_PRId32
1566 				"\n", event->Thread());
1567 
1568 			if (handler != NULL) {
1569 				handled = handler->HandleWatchpointHit(
1570 					dynamic_cast<WatchpointHitEvent*>(event));
1571 			}
1572 			break;
1573 		case B_DEBUGGER_MESSAGE_SINGLE_STEP:
1574 			TRACE_EVENTS("B_DEBUGGER_MESSAGE_SINGLE_STEP: thread: %" B_PRId32
1575 				"\n", event->Thread());
1576 
1577 			if (handler != NULL) {
1578 				handled = handler->HandleSingleStep(
1579 					dynamic_cast<SingleStepEvent*>(event));
1580 			}
1581 			break;
1582 		case B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED:
1583 			TRACE_EVENTS("B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED: thread: %"
1584 				B_PRId32 "\n", event->Thread());
1585 
1586 			if (handler != NULL) {
1587 				handled = handler->HandleExceptionOccurred(
1588 					dynamic_cast<ExceptionOccurredEvent*>(event));
1589 			}
1590 			break;
1591 //		case B_DEBUGGER_MESSAGE_TEAM_CREATED:
1592 //printf("B_DEBUGGER_MESSAGE_TEAM_CREATED: team: %ld\n", message.team_created.new_team);
1593 //			break;
1594 		case B_DEBUGGER_MESSAGE_TEAM_DELETED:
1595 		{
1596 			TRACE_EVENTS("B_DEBUGGER_MESSAGE_TEAM_DELETED: team: %" B_PRId32
1597 				"\n", event->Team());
1598 			TeamDeletedEvent* teamEvent
1599 				= dynamic_cast<TeamDeletedEvent*>(event);
1600 			handled = _HandleTeamDeleted(teamEvent);
1601 			break;
1602 		}
1603 		case B_DEBUGGER_MESSAGE_TEAM_EXEC:
1604 		{
1605 			TRACE_EVENTS("B_DEBUGGER_MESSAGE_TEAM_EXEC: team: %" B_PRId32 "\n",
1606 				event->Team());
1607 
1608 			TeamExecEvent* teamEvent
1609 				= dynamic_cast<TeamExecEvent*>(event);
1610 			_PrepareForTeamExec(teamEvent);
1611 			break;
1612 		}
1613 		case B_DEBUGGER_MESSAGE_THREAD_CREATED:
1614 		{
1615 			ThreadCreatedEvent* threadEvent
1616 				= dynamic_cast<ThreadCreatedEvent*>(event);
1617 			TRACE_EVENTS("B_DEBUGGER_MESSAGE_THREAD_CREATED: thread: %" B_PRId32
1618 				"\n", threadEvent->NewThread());
1619 			handled = _HandleThreadCreated(threadEvent);
1620 			break;
1621 		}
1622 		case DEBUGGER_MESSAGE_THREAD_RENAMED:
1623 		{
1624 			ThreadRenamedEvent* threadEvent
1625 				= dynamic_cast<ThreadRenamedEvent*>(event);
1626 			TRACE_EVENTS("DEBUGGER_MESSAGE_THREAD_RENAMED: thread: %" B_PRId32
1627 				" (\"%s\")\n",
1628 				threadEvent->RenamedThread(), threadEvent->NewName());
1629 			handled = _HandleThreadRenamed(threadEvent);
1630 			break;
1631 		}
1632 		case DEBUGGER_MESSAGE_THREAD_PRIORITY_CHANGED:
1633 		{
1634 			ThreadPriorityChangedEvent* threadEvent
1635 				= dynamic_cast<ThreadPriorityChangedEvent*>(event);
1636 			TRACE_EVENTS("B_DEBUGGER_MESSAGE_THREAD_PRIORITY_CHANGED: thread:"
1637 				" %" B_PRId32 "\n", threadEvent->ChangedThread());
1638 			handled = _HandleThreadPriorityChanged(threadEvent);
1639 			break;
1640 		}
1641 		case B_DEBUGGER_MESSAGE_THREAD_DELETED:
1642 			TRACE_EVENTS("B_DEBUGGER_MESSAGE_THREAD_DELETED: thread: %" B_PRId32
1643 				"\n", event->Thread());
1644 			handled = _HandleThreadDeleted(
1645 				dynamic_cast<ThreadDeletedEvent*>(event));
1646 			break;
1647 		case B_DEBUGGER_MESSAGE_IMAGE_CREATED:
1648 		{
1649 			ImageCreatedEvent* imageEvent
1650 				= dynamic_cast<ImageCreatedEvent*>(event);
1651 			TRACE_EVENTS("B_DEBUGGER_MESSAGE_IMAGE_CREATED: image: \"%s\" "
1652 				"(%" B_PRId32 ")\n", imageEvent->GetImageInfo().Name().String(),
1653 				imageEvent->GetImageInfo().ImageID());
1654 			handled = _HandleImageCreated(imageEvent);
1655 			break;
1656 		}
1657 		case B_DEBUGGER_MESSAGE_IMAGE_DELETED:
1658 		{
1659 			ImageDeletedEvent* imageEvent
1660 				= dynamic_cast<ImageDeletedEvent*>(event);
1661 			TRACE_EVENTS("B_DEBUGGER_MESSAGE_IMAGE_DELETED: image: \"%s\" "
1662 				"(%" B_PRId32 ")\n", imageEvent->GetImageInfo().Name().String(),
1663 				imageEvent->GetImageInfo().ImageID());
1664 			handled = _HandleImageDeleted(imageEvent);
1665 			break;
1666 		}
1667 		case B_DEBUGGER_MESSAGE_POST_SYSCALL:
1668 		{
1669 			PostSyscallEvent* postSyscallEvent
1670 				= dynamic_cast<PostSyscallEvent*>(event);
1671 			TRACE_EVENTS("B_DEBUGGER_MESSAGE_POST_SYSCALL: syscall: %"
1672 				B_PRIu32 "\n", postSyscallEvent->GetSyscallInfo().Syscall());
1673 			handled = _HandlePostSyscall(postSyscallEvent);
1674 
1675 			// if a thread was blocked in a syscall when we requested to
1676 			// stop it for debugging, then that request will interrupt
1677 			// said call, and the post syscall event will be all we get
1678 			// in response. Consequently, we need to treat this case as
1679 			// equivalent to having received a thread debugged event.
1680 			AutoLocker< ::Team> teamLocker(fTeam);
1681 			::Thread* thread = fTeam->ThreadByID(event->Thread());
1682 			if (handler != NULL && thread != NULL
1683 				&& thread->StopRequestPending()) {
1684 				handled = handler->HandleThreadDebugged(NULL);
1685 			}
1686 			break;
1687 		}
1688 		case B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED:
1689 		{
1690 			TRACE_EVENTS("B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED: thread: %"
1691 				B_PRId32 "\n", event->Thread());
1692 
1693 			if (handler != NULL) {
1694 				handled = handler->HandleSignalReceived(
1695 					dynamic_cast<SignalReceivedEvent*>(event));
1696 			}
1697 			break;
1698 		}
1699 		case B_DEBUGGER_MESSAGE_PRE_SYSCALL:
1700 		case B_DEBUGGER_MESSAGE_PROFILER_UPDATE:
1701 		case B_DEBUGGER_MESSAGE_HANDED_OVER:
1702 			// not interested
1703 			break;
1704 		default:
1705 			WARNING("TeamDebugger for team %" B_PRId32 ": unknown event type: "
1706 				"%" B_PRId32 "\n", fTeamID, event->EventType());
1707 			break;
1708 	}
1709 
1710 	if (!handled && event->ThreadStopped())
1711 		fDebuggerInterface->ContinueThread(event->Thread());
1712 }
1713 
1714 
1715 bool
1716 TeamDebugger::_HandleTeamDeleted(TeamDeletedEvent* event)
1717 {
1718 	char message[64];
1719 	fDebuggerInterface->Close(false);
1720 
1721 	snprintf(message, sizeof(message), "Team %" B_PRId32 " has terminated. ",
1722 		event->Team());
1723 
1724 	int32 result = fUserInterface->SynchronouslyAskUser("Team terminated",
1725 		message, "Do nothing", "Quit", fCommandLineArgc != 0
1726 			? "Restart team" : NULL);
1727 
1728 	switch (result) {
1729 		case 1:
1730 		case -1:
1731 		{
1732 			PostMessage(B_QUIT_REQUESTED);
1733 			break;
1734 		}
1735 		case 2:
1736 		{
1737 			_SaveSettings();
1738 			fListener->TeamDebuggerRestartRequested(this);
1739 			break;
1740 		}
1741 		default:
1742 			break;
1743 	}
1744 
1745 	return true;
1746 }
1747 
1748 
1749 bool
1750 TeamDebugger::_HandleThreadCreated(ThreadCreatedEvent* event)
1751 {
1752 	AutoLocker< ::Team> locker(fTeam);
1753 
1754 	ThreadInfo info;
1755 	status_t error = fDebuggerInterface->GetThreadInfo(event->NewThread(),
1756 		info);
1757 	if (error == B_OK) {
1758 		::Thread* thread;
1759 		fTeam->AddThread(info, &thread);
1760 
1761 		ThreadHandler* handler = new(std::nothrow) ThreadHandler(thread,
1762 			fWorker, fDebuggerInterface, this, fBreakpointManager);
1763 		if (handler != NULL) {
1764 			fThreadHandlers.Insert(handler);
1765 			handler->Init();
1766 		}
1767 	}
1768 
1769 	return false;
1770 }
1771 
1772 
1773 bool
1774 TeamDebugger::_HandleThreadRenamed(ThreadRenamedEvent* event)
1775 {
1776 	AutoLocker< ::Team> locker(fTeam);
1777 
1778 	::Thread* thread = fTeam->ThreadByID(event->RenamedThread());
1779 
1780 	if (thread != NULL)
1781 		thread->SetName(event->NewName());
1782 
1783 	return false;
1784 }
1785 
1786 
1787 bool
1788 TeamDebugger::_HandleThreadPriorityChanged(ThreadPriorityChangedEvent*)
1789 {
1790 	// TODO: implement once we actually track thread priorities
1791 
1792 	return false;
1793 }
1794 
1795 
1796 bool
1797 TeamDebugger::_HandleThreadDeleted(ThreadDeletedEvent* event)
1798 {
1799 	AutoLocker< ::Team> locker(fTeam);
1800 	if (ThreadHandler* handler = fThreadHandlers.Lookup(event->Thread())) {
1801 		fThreadHandlers.Remove(handler);
1802 		handler->ReleaseReference();
1803 	}
1804 	fTeam->RemoveThread(event->Thread());
1805 	return false;
1806 }
1807 
1808 
1809 bool
1810 TeamDebugger::_HandleImageCreated(ImageCreatedEvent* event)
1811 {
1812 	AutoLocker< ::Team> locker(fTeam);
1813 	_AddImage(event->GetImageInfo());
1814 
1815 	ImageInfoPendingThread* info = new(std::nothrow) ImageInfoPendingThread(
1816 		event->GetImageInfo().ImageID(), event->Thread());
1817 	if (info == NULL)
1818 		return false;
1819 
1820 	fImageInfoPendingThreads->Insert(info);
1821 	return true;
1822 }
1823 
1824 
1825 bool
1826 TeamDebugger::_HandleImageDeleted(ImageDeletedEvent* event)
1827 {
1828 	AutoLocker< ::Team> locker(fTeam);
1829 	fTeam->RemoveImage(event->GetImageInfo().ImageID());
1830 
1831 	ImageHandler* imageHandler = fImageHandlers->Lookup(
1832 		event->GetImageInfo().ImageID());
1833 	if (imageHandler == NULL)
1834 		return false;
1835 
1836 	fImageHandlers->Remove(imageHandler);
1837 	BReference<ImageHandler> imageHandlerReference(imageHandler, true);
1838 	locker.Unlock();
1839 
1840 	// remove breakpoints in the image
1841 	fBreakpointManager->RemoveImageBreakpoints(imageHandler->GetImage());
1842 
1843 	return false;
1844 }
1845 
1846 
1847 bool
1848 TeamDebugger::_HandlePostSyscall(PostSyscallEvent* event)
1849 {
1850 	const SyscallInfo& info = event->GetSyscallInfo();
1851 
1852 	switch (info.Syscall()) {
1853 		case SYSCALL_WRITE:
1854 		{
1855 			if ((ssize_t)info.ReturnValue() <= 0)
1856 				break;
1857 
1858 			int32 fd;
1859 			target_addr_t address;
1860 			size_t size;
1861 			// TODO: decoding the syscall arguments should probably be
1862 			// factored out into an Architecture method of its own, since
1863 			// there's no guarantee the target architecture has the same
1864 			// endianness as the host. This could re-use the syscall
1865 			// argument parser that strace uses, though that would need to
1866 			// be adapted to handle the aforementioned endian differences.
1867 			// This works for x86{-64} for now though.
1868 			if (fTeam->GetArchitecture()->AddressSize() == 4) {
1869 				const uint32* args = (const uint32*)info.Arguments();
1870 				fd = args[0];
1871 				address = args[3];
1872 				size = args[4];
1873 			} else {
1874 				const uint64* args = (const uint64*)info.Arguments();
1875 				fd = args[0];
1876 				address = args[2];
1877 				size = args[3];
1878 			}
1879 
1880 			if (fd == 1 || fd == 2) {
1881 				BString data;
1882 
1883 				ssize_t result = fDebuggerInterface->ReadMemoryString(
1884 					address, size, data);
1885 				if (result >= 0)
1886 					fTeam->NotifyConsoleOutputReceived(fd, data);
1887 			}
1888 			break;
1889 		}
1890 		case SYSCALL_WRITEV:
1891 		{
1892 			// TODO: handle
1893 		}
1894 		default:
1895 			break;
1896 	}
1897 
1898 	return false;
1899 }
1900 
1901 
1902 void
1903 TeamDebugger::_PrepareForTeamExec(TeamExecEvent* event)
1904 {
1905 	// NB: must be called with team lock held.
1906 
1907 	_SaveSettings();
1908 
1909 	// when notified of exec, we need to clear out data related
1910 	// to the old team.
1911 	const ImageList& images = fTeam->Images();
1912 
1913 	for (ImageList::ConstIterator it = images.GetIterator();
1914 			Image* image = it.Next();) {
1915 		fBreakpointManager->RemoveImageBreakpoints(image);
1916 	}
1917 
1918 	BObjectList<UserBreakpoint> breakpointsToRemove(20, false);
1919 	const UserBreakpointList& breakpoints = fTeam->UserBreakpoints();
1920 	for (UserBreakpointList::ConstIterator it = breakpoints.GetIterator();
1921 			UserBreakpoint* breakpoint = it.Next();) {
1922 		breakpointsToRemove.AddItem(breakpoint);
1923 		breakpoint->AcquireReference();
1924 	}
1925 
1926 	for (int32 i = 0; i < breakpointsToRemove.CountItems(); i++) {
1927 		UserBreakpoint* breakpoint = breakpointsToRemove.ItemAt(i);
1928 		fTeam->RemoveUserBreakpoint(breakpoint);
1929 		fTeam->NotifyUserBreakpointChanged(breakpoint);
1930 		breakpoint->ReleaseReference();
1931 	}
1932 
1933 	fTeam->ClearImages();
1934 	fTeam->ClearSignalDispositionMappings();
1935 	fExecPending = true;
1936 }
1937 
1938 
1939 void
1940 TeamDebugger::_HandleImageDebugInfoChanged(image_id imageID)
1941 {
1942 	// get the image (via the image handler)
1943 	AutoLocker< ::Team> locker(fTeam);
1944 	ImageHandler* imageHandler = fImageHandlers->Lookup(imageID);
1945 	if (imageHandler == NULL)
1946 		return;
1947 
1948 	Image* image = imageHandler->GetImage();
1949 	BReference<Image> imageReference(image);
1950 	image_debug_info_state state = image->ImageDebugInfoState();
1951 
1952 	bool handlePostExecSetup = fExecPending && image->Type() == B_APP_IMAGE
1953 		&& state != IMAGE_DEBUG_INFO_LOADING;
1954 	// this needs to be done first so that breakpoints are loaded.
1955 	// otherwise, UpdateImageBreakpoints() won't find the appropriate
1956 	// UserBreakpoints to create/install instances for.
1957 	if (handlePostExecSetup) {
1958 		fTeam->SetName(image->Name());
1959 		_LoadSettings();
1960 		fExecPending = false;
1961 	}
1962 
1963 	locker.Unlock();
1964 
1965 	if (state == IMAGE_DEBUG_INFO_LOADED
1966 		|| state == IMAGE_DEBUG_INFO_UNAVAILABLE) {
1967 
1968 		// update breakpoints in the image
1969 		fBreakpointManager->UpdateImageBreakpoints(image);
1970 
1971 		ImageInfoPendingThread* thread =  fImageInfoPendingThreads
1972 			->Lookup(imageID);
1973 		if (thread != NULL) {
1974 			fImageInfoPendingThreads->Remove(thread);
1975 			ObjectDeleter<ImageInfoPendingThread> threadDeleter(thread);
1976 			locker.Lock();
1977 			ThreadHandler* handler = _GetThreadHandler(thread->ThreadID());
1978 			BReference<ThreadHandler> handlerReference(handler);
1979 			if (fTeam->StopOnImageLoad()) {
1980 
1981 				bool stop = true;
1982 				const BString& imageName = image->Name();
1983 				// only match on the image filename itself
1984 				const char* rawImageName = imageName.String()
1985 					+ imageName.FindLast('/') + 1;
1986 				if (fTeam->StopImageNameListEnabled()) {
1987 					const BStringList& nameList = fTeam->StopImageNames();
1988 					stop = nameList.HasString(rawImageName);
1989 				}
1990 
1991 				if (stop && handler != NULL) {
1992 					BString stopReason;
1993 					stopReason.SetToFormat("Image '%s' loaded.",
1994 						rawImageName);
1995 					locker.Unlock();
1996 
1997 					if (handler->HandleThreadDebugged(NULL, stopReason))
1998 						return;
1999 				} else
2000 					locker.Unlock();
2001 			} else if (handlePostExecSetup) {
2002 				// in the case of an exec(), we can't stop in main() until
2003 				// the new app image has been loaded, so we know where to
2004 				// set the main breakpoint at.
2005 				SymbolInfo symbolInfo;
2006 				if (fDebuggerInterface->GetSymbolInfo(fTeam->ID(), image->ID(),
2007 						"main", B_SYMBOL_TYPE_TEXT, symbolInfo) == B_OK) {
2008 					handler->SetBreakpointAndRun(symbolInfo.Address());
2009 				}
2010 			} else {
2011 				locker.Unlock();
2012 				fDebuggerInterface->ContinueThread(thread->ThreadID());
2013 			}
2014 		}
2015 	}
2016 }
2017 
2018 
2019 void
2020 TeamDebugger::_HandleImageFileChanged(image_id imageID)
2021 {
2022 	TRACE_IMAGES("TeamDebugger::_HandleImageFileChanged(%" B_PRId32 ")\n",
2023 		imageID);
2024 // TODO: Reload the debug info!
2025 }
2026 
2027 
2028 void
2029 TeamDebugger::_HandleSetUserBreakpoint(target_addr_t address, bool enabled,
2030 	bool hidden)
2031 {
2032 	TRACE_CONTROL("TeamDebugger::_HandleSetUserBreakpoint(%#" B_PRIx64
2033 		", %d, %d)\n", address, enabled, hidden);
2034 
2035 	// check whether there already is a breakpoint
2036 	AutoLocker< ::Team> locker(fTeam);
2037 
2038 	Breakpoint* breakpoint = fTeam->BreakpointAtAddress(address);
2039 	UserBreakpoint* userBreakpoint = NULL;
2040 	if (breakpoint != NULL && breakpoint->FirstUserBreakpoint() != NULL)
2041 		userBreakpoint = breakpoint->FirstUserBreakpoint()->GetUserBreakpoint();
2042 	BReference<UserBreakpoint> userBreakpointReference(userBreakpoint);
2043 
2044 	if (userBreakpoint == NULL) {
2045 		TRACE_CONTROL("  no breakpoint yet\n");
2046 
2047 		// get the function at the address
2048 		Image* image = fTeam->ImageByAddress(address);
2049 
2050 		TRACE_CONTROL("  image: %p\n", image);
2051 
2052 		if (image == NULL)
2053 			return;
2054 		ImageDebugInfo* imageDebugInfo = image->GetImageDebugInfo();
2055 
2056 		TRACE_CONTROL("  image debug info: %p\n", imageDebugInfo);
2057 
2058 		if (imageDebugInfo == NULL)
2059 			return;
2060 			// TODO: Handle this case by loading the debug info, if possible!
2061 		FunctionInstance* functionInstance
2062 			= imageDebugInfo->FunctionAtAddress(address);
2063 
2064 		TRACE_CONTROL("  function instance: %p\n", functionInstance);
2065 
2066 		if (functionInstance == NULL)
2067 			return;
2068 		Function* function = functionInstance->GetFunction();
2069 
2070 		TRACE_CONTROL("  function: %p\n", function);
2071 
2072 		// get the source location for the address
2073 		FunctionDebugInfo* functionDebugInfo
2074 			= functionInstance->GetFunctionDebugInfo();
2075 		SourceLocation sourceLocation;
2076 		Statement* breakpointStatement = NULL;
2077 		if (functionDebugInfo->GetSpecificImageDebugInfo()->GetStatement(
2078 				functionDebugInfo, address, breakpointStatement) != B_OK) {
2079 			return;
2080 		}
2081 
2082 		sourceLocation = breakpointStatement->StartSourceLocation();
2083 		breakpointStatement->ReleaseReference();
2084 
2085 		target_addr_t relativeAddress = address - functionInstance->Address();
2086 
2087 		TRACE_CONTROL("  relative address: %#" B_PRIx64 ", source location: "
2088 			"(%" B_PRId32 ", %" B_PRId32 ")\n", relativeAddress,
2089 			sourceLocation.Line(), sourceLocation.Column());
2090 
2091 		// get function id
2092 		FunctionID* functionID = functionInstance->GetFunctionID();
2093 		if (functionID == NULL)
2094 			return;
2095 		BReference<FunctionID> functionIDReference(functionID, true);
2096 
2097 		// create the user breakpoint
2098 		userBreakpoint = new(std::nothrow) UserBreakpoint(
2099 			UserBreakpointLocation(functionID, function->SourceFile(),
2100 				sourceLocation, relativeAddress));
2101 		if (userBreakpoint == NULL)
2102 			return;
2103 		userBreakpointReference.SetTo(userBreakpoint, true);
2104 
2105 		userBreakpoint->SetHidden(hidden);
2106 
2107 		TRACE_CONTROL("  created user breakpoint: %p\n", userBreakpoint);
2108 
2109 		// iterate through all function instances and create
2110 		// UserBreakpointInstances
2111 		for (FunctionInstanceList::ConstIterator it
2112 					= function->Instances().GetIterator();
2113 				FunctionInstance* instance = it.Next();) {
2114 			TRACE_CONTROL("  function instance %p: range: %#" B_PRIx64 " - %#"
2115 				B_PRIx64 "\n", instance, instance->Address(),
2116 				instance->Address() + instance->Size());
2117 
2118 			// get the breakpoint address for the instance
2119 			target_addr_t instanceAddress = 0;
2120 			if (instance == functionInstance) {
2121 				instanceAddress = address;
2122 			} else if (functionInstance->SourceFile() != NULL) {
2123 				// We have a source file, so get the address for the source
2124 				// location.
2125 				Statement* statement = NULL;
2126 				functionDebugInfo = instance->GetFunctionDebugInfo();
2127 				functionDebugInfo->GetSpecificImageDebugInfo()
2128 					->GetStatementAtSourceLocation(functionDebugInfo,
2129 						sourceLocation, statement);
2130 				if (statement != NULL) {
2131 					instanceAddress = statement->CoveringAddressRange().Start();
2132 						// TODO: What about BreakpointAllowed()?
2133 					statement->ReleaseReference();
2134 				}
2135 			}
2136 
2137 			TRACE_CONTROL("    breakpoint address using source info: %" B_PRIx64
2138 				"\n", instanceAddress);
2139 
2140 			if (instanceAddress == 0) {
2141 				// No source file (or we failed getting the statement), so try
2142 				// to use the same relative address.
2143 				if (relativeAddress > instance->Size())
2144 					continue;
2145 				instanceAddress = instance->Address() + relativeAddress;
2146 			}
2147 
2148 			TRACE_CONTROL("    final breakpoint address: %" B_PRIx64 "\n",
2149 				instanceAddress);
2150 
2151 			UserBreakpointInstance* breakpointInstance = new(std::nothrow)
2152 				UserBreakpointInstance(userBreakpoint, instanceAddress);
2153 			if (breakpointInstance == NULL
2154 				|| !userBreakpoint->AddInstance(breakpointInstance)) {
2155 				delete breakpointInstance;
2156 				return;
2157 			}
2158 
2159 			TRACE_CONTROL("  breakpoint instance: %p\n", breakpointInstance);
2160 		}
2161 	}
2162 
2163 	locker.Unlock();
2164 
2165 	_HandleSetUserBreakpoint(userBreakpoint, enabled);
2166 }
2167 
2168 
2169 void
2170 TeamDebugger::_HandleSetUserBreakpoint(UserBreakpoint* breakpoint, bool enabled)
2171 {
2172 	status_t error = fBreakpointManager->InstallUserBreakpoint(breakpoint,
2173 		enabled);
2174 	if (error != B_OK) {
2175 		_NotifyUser("Install Breakpoint", "Failed to install breakpoint: %s",
2176 			strerror(error));
2177 	}
2178 }
2179 
2180 
2181 void
2182 TeamDebugger::_HandleClearUserBreakpoint(target_addr_t address)
2183 {
2184 	TRACE_CONTROL("TeamDebugger::_HandleClearUserBreakpoint(%#" B_PRIx64 ")\n",
2185 		address);
2186 
2187 	AutoLocker< ::Team> locker(fTeam);
2188 
2189 	Breakpoint* breakpoint = fTeam->BreakpointAtAddress(address);
2190 	if (breakpoint == NULL || breakpoint->FirstUserBreakpoint() == NULL)
2191 		return;
2192 	UserBreakpoint* userBreakpoint
2193 		= breakpoint->FirstUserBreakpoint()->GetUserBreakpoint();
2194 	BReference<UserBreakpoint> userBreakpointReference(userBreakpoint);
2195 
2196 	locker.Unlock();
2197 
2198 	_HandleClearUserBreakpoint(userBreakpoint);
2199 }
2200 
2201 
2202 void
2203 TeamDebugger::_HandleClearUserBreakpoint(UserBreakpoint* breakpoint)
2204 {
2205 	fBreakpointManager->UninstallUserBreakpoint(breakpoint);
2206 }
2207 
2208 
2209 void
2210 TeamDebugger::_HandleSetWatchpoint(target_addr_t address, uint32 type,
2211 	int32 length, bool enabled)
2212 {
2213 	Watchpoint* watchpoint = new(std::nothrow) Watchpoint(address, type,
2214 		length);
2215 
2216 	if (watchpoint == NULL)
2217 		return;
2218 	BReference<Watchpoint> watchpointRef(watchpoint, true);
2219 
2220 	_HandleSetWatchpoint(watchpoint, enabled);
2221 }
2222 
2223 
2224 void
2225 TeamDebugger::_HandleSetWatchpoint(Watchpoint* watchpoint, bool enabled)
2226 {
2227 	status_t error = fWatchpointManager->InstallWatchpoint(watchpoint,
2228 		enabled);
2229 	if (error != B_OK) {
2230 		_NotifyUser("Install Watchpoint", "Failed to install watchpoint: %s",
2231 			strerror(error));
2232 	}
2233 }
2234 
2235 
2236 void
2237 TeamDebugger::_HandleClearWatchpoint(target_addr_t address)
2238 {
2239 	TRACE_CONTROL("TeamDebugger::_HandleClearWatchpoint(%#" B_PRIx64 ")\n",
2240 		address);
2241 
2242 	AutoLocker< ::Team> locker(fTeam);
2243 
2244 	Watchpoint* watchpoint = fTeam->WatchpointAtAddress(address);
2245 	if (watchpoint == NULL)
2246 		return;
2247 	BReference<Watchpoint> watchpointReference(watchpoint);
2248 
2249 	locker.Unlock();
2250 
2251 	_HandleClearWatchpoint(watchpoint);
2252 }
2253 
2254 
2255 void
2256 TeamDebugger::_HandleClearWatchpoint(Watchpoint* watchpoint)
2257 {
2258 	fWatchpointManager->UninstallWatchpoint(watchpoint);
2259 }
2260 
2261 
2262 void
2263 TeamDebugger::_HandleInspectAddress(target_addr_t address,
2264 	TeamMemoryBlock::Listener* listener)
2265 {
2266 	TRACE_CONTROL("TeamDebugger::_HandleInspectAddress(%" B_PRIx64 ", %p)\n",
2267 		address, listener);
2268 
2269 	TeamMemoryBlock* memoryBlock = fMemoryBlockManager
2270 		->GetMemoryBlock(address);
2271 
2272 	if (memoryBlock == NULL) {
2273 		_NotifyUser("Inspect Address", "Failed to allocate memory block");
2274 		return;
2275 	}
2276 
2277 	if (!memoryBlock->IsValid()) {
2278 		AutoLocker< ::Team> teamLocker(fTeam);
2279 
2280 		if (!memoryBlock->HasListener(listener))
2281 			memoryBlock->AddListener(listener);
2282 
2283 		TeamMemory* memory = fTeam->GetTeamMemory();
2284 		// schedule the job
2285 		status_t result;
2286 		if ((result = fWorker->ScheduleJob(
2287 			new(std::nothrow) RetrieveMemoryBlockJob(fTeam, memory,
2288 				memoryBlock),
2289 			this)) != B_OK) {
2290 
2291 			memoryBlock->NotifyDataRetrieved(result);
2292 			memoryBlock->ReleaseReference();
2293 
2294 			_NotifyUser("Inspect Address", "Failed to retrieve memory data: %s",
2295 				strerror(result));
2296 		}
2297 	} else
2298 		memoryBlock->NotifyDataRetrieved();
2299 
2300 }
2301 
2302 
2303 void
2304 TeamDebugger::_HandleWriteMemory(target_addr_t address, void* data,
2305 	target_size_t size)
2306 {
2307 	TRACE_CONTROL("TeamDebugger::_HandleWriteTargetMemory(%" B_PRIx64 ", %p, "
2308 		"%" B_PRIu64 ")\n", address, data, size);
2309 
2310 	AutoLocker< ::Team> teamLocker(fTeam);
2311 	TeamMemory* memory = fTeam->GetTeamMemory();
2312 	// schedule the job
2313 	status_t result;
2314 	if ((result = fWorker->ScheduleJob(
2315 		new(std::nothrow) WriteMemoryJob(fTeam, memory, address, data, size),
2316 		this)) != B_OK) {
2317 		_NotifyUser("Write Memory", "Failed to write memory data: %s",
2318 			strerror(result));
2319 	}
2320 }
2321 
2322 
2323 void
2324 TeamDebugger::_HandleEvaluateExpression(SourceLanguage* language,
2325 	ExpressionInfo* info, StackFrame* frame, ::Thread* thread)
2326 {
2327 	status_t result = fWorker->ScheduleJob(
2328 		new(std::nothrow) ExpressionEvaluationJob(fTeam, fDebuggerInterface,
2329 			language, info, frame, thread));
2330 	if (result != B_OK) {
2331 		_NotifyUser("Evaluate Expression", "Failed to evaluate expression: %s",
2332 			strerror(result));
2333 	}
2334 }
2335 
2336 
2337 void
2338 TeamDebugger::_HandleWriteCoreFile(const entry_ref& targetPath)
2339 {
2340 	status_t result = fWorker->ScheduleJob(
2341 		new(std::nothrow) WriteCoreFileJob(fTeam, fDebuggerInterface,
2342 			targetPath));
2343 	if (result != B_OK) {
2344 		_NotifyUser("Write Core File", "Failed to write core file: %s",
2345 			strerror(result));
2346 	}
2347 }
2348 
2349 
2350 status_t
2351 TeamDebugger::_HandleSetArguments(int argc, const char* const* argv)
2352 {
2353 	fCommandLineArgc = argc;
2354 	fCommandLineArgv = new(std::nothrow) const char*[argc];
2355 	if (fCommandLineArgv == NULL)
2356 		return B_NO_MEMORY;
2357 
2358 	memset(const_cast<char **>(fCommandLineArgv), 0, sizeof(char*) * argc);
2359 
2360 	for (int i = 0; i < argc; i++) {
2361 		fCommandLineArgv[i] = strdup(argv[i]);
2362 		if (fCommandLineArgv[i] == NULL)
2363 			return B_NO_MEMORY;
2364 	}
2365 
2366 	return B_OK;
2367 }
2368 
2369 
2370 void
2371 TeamDebugger::_HandleDebugInfoJobUserInput(ImageDebugInfoLoadingState* state)
2372 {
2373 	SpecificImageDebugInfoLoadingState* specificState
2374 		= state->GetSpecificDebugInfoLoadingState();
2375 
2376 	ImageDebugLoadingStateHandler* handler;
2377 	if (ImageDebugLoadingStateHandlerRoster::Default()
2378 			->FindStateHandler(specificState, handler) != B_OK) {
2379 		TRACE_JOBS("TeamDebugger::_HandleDebugInfoJobUserInput(): "
2380 			"Failed to find appropriate information handler, aborting.");
2381 		return;
2382 	}
2383 
2384 	handler->HandleState(specificState, fUserInterface);
2385 }
2386 
2387 
2388 ThreadHandler*
2389 TeamDebugger::_GetThreadHandler(thread_id threadID)
2390 {
2391 	AutoLocker< ::Team> locker(fTeam);
2392 
2393 	ThreadHandler* handler = fThreadHandlers.Lookup(threadID);
2394 	if (handler != NULL)
2395 		handler->AcquireReference();
2396 	return handler;
2397 }
2398 
2399 
2400 status_t
2401 TeamDebugger::_AddImage(const ImageInfo& imageInfo, Image** _image)
2402 {
2403 	LocatableFile* file = NULL;
2404 	if (strchr(imageInfo.Name(), '/') != NULL)
2405 		file = fFileManager->GetTargetFile(imageInfo.Name());
2406 	BReference<LocatableFile> imageFileReference(file, true);
2407 
2408 	Image* image;
2409 	status_t error = fTeam->AddImage(imageInfo, file, &image);
2410 	if (error != B_OK)
2411 		return error;
2412 
2413 	ImageDebugInfoRequested(image);
2414 
2415 	ImageHandler* imageHandler = new(std::nothrow) ImageHandler(this, image);
2416 	if (imageHandler != NULL)
2417 		fImageHandlers->Insert(imageHandler);
2418 
2419 	if (_image != NULL)
2420 		*_image = image;
2421 
2422 	return B_OK;
2423 }
2424 
2425 
2426 void
2427 TeamDebugger::_LoadSettings()
2428 {
2429 	// get the team name
2430 	AutoLocker< ::Team> locker(fTeam);
2431 	BString teamName = fTeam->Name();
2432 	locker.Unlock();
2433 
2434 	// load the settings
2435 	if (fSettingsManager->LoadTeamSettings(teamName, fTeamSettings) != B_OK)
2436 		return;
2437 
2438 	// create the saved breakpoints
2439 	for (int32 i = 0; const BreakpointSetting* breakpointSetting
2440 			= fTeamSettings.BreakpointAt(i); i++) {
2441 		if (breakpointSetting->GetFunctionID() == NULL)
2442 			continue;
2443 
2444 		// get the source file, if any
2445 		LocatableFile* sourceFile = NULL;
2446 		if (breakpointSetting->SourceFile().Length() > 0) {
2447 			sourceFile = fFileManager->GetSourceFile(
2448 				breakpointSetting->SourceFile());
2449 			if (sourceFile == NULL)
2450 				continue;
2451 		}
2452 		BReference<LocatableFile> sourceFileReference(sourceFile, true);
2453 
2454 		// create the breakpoint
2455 		UserBreakpointLocation location(breakpointSetting->GetFunctionID(),
2456 			sourceFile, breakpointSetting->GetSourceLocation(),
2457 			breakpointSetting->RelativeAddress());
2458 
2459 		UserBreakpoint* breakpoint = new(std::nothrow) UserBreakpoint(location);
2460 		if (breakpoint == NULL)
2461 			return;
2462 		BReference<UserBreakpoint> breakpointReference(breakpoint, true);
2463 
2464 		breakpoint->SetHidden(breakpointSetting->IsHidden());
2465 		breakpoint->SetCondition(breakpointSetting->Condition());
2466 
2467 		// install it
2468 		fBreakpointManager->InstallUserBreakpoint(breakpoint,
2469 			breakpointSetting->IsEnabled());
2470 	}
2471 
2472 	fFileManager->LoadLocationMappings(fTeamSettings.FileManagerSettings());
2473 
2474 	const TeamUiSettings* uiSettings = fTeamSettings.UiSettingFor(
2475 		fUserInterface->ID());
2476 	if (uiSettings != NULL)
2477 			fUserInterface->LoadSettings(uiSettings);
2478 
2479 	const TeamSignalSettings* signalSettings = fTeamSettings.SignalSettings();
2480 	if (signalSettings != NULL) {
2481 		fTeam->SetDefaultSignalDisposition(
2482 			signalSettings->DefaultSignalDisposition());
2483 
2484 		int32 signal;
2485 		int32 disposition;
2486 		for (int32 i = 0; i < signalSettings->CountCustomSignalDispositions();
2487 			i++) {
2488 			if (signalSettings->GetCustomSignalDispositionAt(i, signal,
2489 				disposition) == B_OK) {
2490 				fTeam->SetCustomSignalDisposition(signal, disposition);
2491 			}
2492 		}
2493 	}
2494 }
2495 
2496 
2497 void
2498 TeamDebugger::_SaveSettings()
2499 {
2500 	// get the settings
2501 	AutoLocker< ::Team> locker(fTeam);
2502 	TeamSettings settings;
2503 	if (settings.SetTo(fTeam) != B_OK)
2504 		return;
2505 
2506 	TeamUiSettings* uiSettings = NULL;
2507 	if (fUserInterface->SaveSettings(uiSettings) != B_OK)
2508 		return;
2509 	if (uiSettings != NULL)
2510 		settings.AddUiSettings(uiSettings);
2511 
2512 	// preserve the UI settings from our cached copy.
2513 	for (int32 i = 0; i < fTeamSettings.CountUiSettings(); i++) {
2514 		const TeamUiSettings* oldUiSettings = fTeamSettings.UiSettingAt(i);
2515 		if (strcmp(oldUiSettings->ID(), fUserInterface->ID()) != 0) {
2516 			TeamUiSettings* clonedSettings = oldUiSettings->Clone();
2517 			if (clonedSettings != NULL)
2518 				settings.AddUiSettings(clonedSettings);
2519 		}
2520 	}
2521 
2522 	fFileManager->SaveLocationMappings(settings.FileManagerSettings());
2523 	locker.Unlock();
2524 
2525 	// save the settings
2526 	fSettingsManager->SaveTeamSettings(settings);
2527 }
2528 
2529 
2530 void
2531 TeamDebugger::_NotifyUser(const char* title, const char* text,...)
2532 {
2533 	// print the message
2534 	char buffer[1024];
2535 	va_list args;
2536 	va_start(args, text);
2537 	vsnprintf(buffer, sizeof(buffer), text, args);
2538 	va_end(args);
2539 
2540 	// notify the user
2541 	fUserInterface->NotifyUser(title, buffer, USER_NOTIFICATION_WARNING);
2542 }
2543 
2544 
2545 void
2546 TeamDebugger::_ResetUserBackgroundStatusIfNeeded()
2547 {
2548 	if (!fWorker->HasPendingJobs())
2549 		fUserInterface->NotifyBackgroundWorkStatus("Ready.");
2550 }
2551 
2552 
2553 // #pragma mark - Listener
2554 
2555 
2556 TeamDebugger::Listener::~Listener()
2557 {
2558 }
2559