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