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