xref: /haiku/src/servers/debug/DebugServer.cpp (revision 1b80286772b529a3d6de3bbeb0720c62e6a32fed)
1 /*
2  * Copyright 2005-2009, Ingo Weinhold, bonefish@users.sf.net.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #include <map>
7 
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <unistd.h>
13 
14 #include <Alert.h>
15 #include <AppMisc.h>
16 #include <AutoDeleter.h>
17 #include <Autolock.h>
18 #include <debug_support.h>
19 #include <Entry.h>
20 #include <Invoker.h>
21 
22 #include <RegistrarDefs.h>
23 #include <RosterPrivate.h>
24 #include <Server.h>
25 
26 #include <util/DoublyLinkedList.h>
27 
28 #define USE_GUI true
29 	// define to false if the debug server shouldn't use GUI (i.e. an alert)
30 
31 //#define TRACE_DEBUG_SERVER
32 #ifdef TRACE_DEBUG_SERVER
33 #	define TRACE(x) debug_printf x
34 #else
35 #	define TRACE(x) ;
36 #endif
37 
38 using std::map;
39 using std::nothrow;
40 
41 static const char *kSignature = "application/x-vnd.Haiku-debug_server";
42 
43 // paths to the apps used for debugging
44 static const char *kConsoledPath	= "/bin/consoled";
45 static const char *kTerminalPath	= "/boot/system/apps/Terminal";
46 static const char *kGDBPath			= "/bin/gdb";
47 
48 
49 // KillTeam
50 static void
51 KillTeam(team_id team, const char *appName = NULL)
52 {
53 	// get a team info to verify the team still lives
54 	team_info info;
55 	if (!appName) {
56 		status_t error = get_team_info(team, &info);
57 		if (error != B_OK) {
58 			debug_printf("debug_server: KillTeam(): Error getting info for "
59 				"team %ld: %s\n", team, strerror(error));
60 			info.args[0] = '\0';
61 		}
62 
63 		appName = info.args;
64 	}
65 
66 	debug_printf("debug_server: Killing team %ld (%s)\n", team, appName);
67 
68 	kill_team(team);
69 }
70 
71 
72 // #pragma mark -
73 
74 // DebugMessage
75 class DebugMessage : public DoublyLinkedListLinkImpl<DebugMessage> {
76 public:
77 	DebugMessage()
78 	{
79 	}
80 
81 	void SetCode(debug_debugger_message code)		{ fCode = code; }
82 	debug_debugger_message Code() const				{ return fCode; }
83 
84 	debug_debugger_message_data &Data()				{ return fData; }
85 	const debug_debugger_message_data &Data() const	{ return fData; }
86 
87 private:
88 	debug_debugger_message		fCode;
89 	debug_debugger_message_data	fData;
90 };
91 
92 typedef DoublyLinkedList<DebugMessage>	DebugMessageList;
93 
94 
95 // TeamDebugHandler
96 class TeamDebugHandler : public BLocker {
97 public:
98 	TeamDebugHandler(team_id team);
99 	~TeamDebugHandler();
100 
101 	status_t Init(port_id nubPort);
102 
103 	team_id Team() const;
104 
105 	status_t PushMessage(DebugMessage *message);
106 
107 private:
108 	status_t _PopMessage(DebugMessage *&message);
109 
110 	thread_id _EnterDebugger();
111 	void _KillTeam();
112 
113 	bool _HandleMessage(DebugMessage *message);
114 
115 	void _LookupSymbolAddress(debug_symbol_lookup_context *lookupContext,
116 		const void *address, char *buffer, int32 bufferSize);
117 	void _PrintStackTrace(thread_id thread);
118 	void _NotifyAppServer(team_id team);
119 	void _NotifyRegistrar(team_id team, bool openAlert, bool stopShutdown);
120 
121 	status_t _InitGUI();
122 
123 	static status_t _HandlerThreadEntry(void *data);
124 	status_t _HandlerThread();
125 
126 	bool _ExecutableNameEquals(const char *name) const;
127 	bool _IsAppServer() const;
128 	bool _IsInputServer() const;
129 	bool _IsRegistrar() const;
130 	bool _IsGUIServer() const;
131 
132 	static const char *_LastPathComponent(const char *path);
133 	static team_id _FindTeam(const char *name);
134 	static bool _AreGUIServersAlive();
135 
136 private:
137 	DebugMessageList		fMessages;
138 	sem_id					fMessageCountSem;
139 	team_id					fTeam;
140 	team_info				fTeamInfo;
141 	char					fExecutablePath[B_PATH_NAME_LENGTH];
142 	thread_id				fHandlerThread;
143 	debug_context			fDebugContext;
144 };
145 
146 
147 // TeamDebugHandlerRoster
148 class TeamDebugHandlerRoster : public BLocker {
149 private:
150 	TeamDebugHandlerRoster()
151 		: BLocker("team debug handler roster")
152 	{
153 	}
154 
155 public:
156 	static TeamDebugHandlerRoster *CreateDefault()
157 	{
158 		if (!sRoster)
159 			sRoster = new(nothrow) TeamDebugHandlerRoster;
160 
161 		return sRoster;
162 	}
163 
164 	static TeamDebugHandlerRoster *Default()
165 	{
166 		return sRoster;
167 	}
168 
169 	bool AddHandler(TeamDebugHandler *handler)
170 	{
171 		if (!handler)
172 			return false;
173 
174 		BAutolock _(this);
175 
176 		fHandlers[handler->Team()] = handler;
177 
178 		return true;
179 	}
180 
181 	TeamDebugHandler *RemoveHandler(team_id team)
182 	{
183 		BAutolock _(this);
184 
185 		TeamDebugHandler *handler = NULL;
186 
187 		TeamDebugHandlerMap::iterator it = fHandlers.find(team);
188 		if (it != fHandlers.end()) {
189 			handler = it->second;
190 			fHandlers.erase(it);
191 		}
192 
193 		return handler;
194 	}
195 
196 	TeamDebugHandler *HandlerFor(team_id team)
197 	{
198 		BAutolock _(this);
199 
200 		TeamDebugHandler *handler = NULL;
201 
202 		TeamDebugHandlerMap::iterator it = fHandlers.find(team);
203 		if (it != fHandlers.end())
204 			handler = it->second;
205 
206 		return handler;
207 	}
208 
209 	status_t DispatchMessage(DebugMessage *message)
210 	{
211 		if (!message)
212 			return B_BAD_VALUE;
213 
214 		ObjectDeleter<DebugMessage> messageDeleter(message);
215 
216 		team_id team = message->Data().origin.team;
217 
218 		// get the responsible team debug handler
219 		BAutolock _(this);
220 
221 		TeamDebugHandler *handler = HandlerFor(team);
222 		if (!handler) {
223 			// no handler yet, we need to create one
224 			handler = new(nothrow) TeamDebugHandler(team);
225 			if (!handler) {
226 				KillTeam(team);
227 				return B_NO_MEMORY;
228 			}
229 
230 			status_t error = handler->Init(message->Data().origin.nub_port);
231 			if (error != B_OK) {
232 				delete handler;
233 				KillTeam(team);
234 				return error;
235 			}
236 
237 			if (!AddHandler(handler)) {
238 				delete handler;
239 				KillTeam(team);
240 				return B_NO_MEMORY;
241 			}
242 		}
243 
244 		// hand over the message to it
245 		handler->PushMessage(message);
246 		messageDeleter.Detach();
247 
248 		return B_OK;
249 	}
250 
251 private:
252 	typedef map<team_id, TeamDebugHandler*>	TeamDebugHandlerMap;
253 
254 	static TeamDebugHandlerRoster	*sRoster;
255 
256 	TeamDebugHandlerMap				fHandlers;
257 };
258 
259 TeamDebugHandlerRoster *TeamDebugHandlerRoster::sRoster = NULL;
260 
261 
262 // DebugServer
263 class DebugServer : public BServer {
264 public:
265 	DebugServer(status_t &error);
266 
267 	status_t Init();
268 
269 	virtual bool QuitRequested();
270 
271 private:
272 	static status_t _ListenerEntry(void *data);
273 	status_t _Listener();
274 
275 	void _DeleteTeamDebugHandler(TeamDebugHandler *handler);
276 
277 private:
278 	typedef map<team_id, TeamDebugHandler*>	TeamDebugHandlerMap;
279 
280 	port_id				fListenerPort;
281 	thread_id			fListener;
282 	bool				fTerminating;
283 };
284 
285 
286 // #pragma mark -
287 
288 // constructor
289 TeamDebugHandler::TeamDebugHandler(team_id team)
290 	: BLocker("team debug handler"),
291 	  fMessages(),
292 	  fMessageCountSem(-1),
293 	  fTeam(team),
294 	  fHandlerThread(-1)
295 {
296 	fDebugContext.nub_port = -1;
297 	fDebugContext.reply_port = -1;
298 
299 	fExecutablePath[0] = '\0';
300 }
301 
302 // destructor
303 TeamDebugHandler::~TeamDebugHandler()
304 {
305 	// delete the message count semaphore and wait for the thread to die
306 	if (fMessageCountSem >= 0)
307 		delete_sem(fMessageCountSem);
308 
309 	if (fHandlerThread >= 0 && find_thread(NULL) != fHandlerThread) {
310 		status_t result;
311 		wait_for_thread(fHandlerThread, &result);
312 	}
313 
314 	// destroy debug context
315 	if (fDebugContext.nub_port >= 0)
316 		destroy_debug_context(&fDebugContext);
317 
318 	// delete the remaining messages
319 	while (DebugMessage *message = fMessages.Head()) {
320 		fMessages.Remove(message);
321 		delete message;
322 	}
323 }
324 
325 // Init
326 status_t
327 TeamDebugHandler::Init(port_id nubPort)
328 {
329 	// get the team info for the team
330 	status_t error = get_team_info(fTeam, &fTeamInfo);
331 	if (error != B_OK) {
332 		debug_printf("debug_server: TeamDebugHandler::Init(): Failed to get "
333 			"info for team %ld: %s\n", fTeam, strerror(error));
334 		return error;
335 	}
336 
337 	// get the executable path
338 	error = BPrivate::get_app_path(fTeam, fExecutablePath);
339 	if (error != B_OK) {
340 		debug_printf("debug_server: TeamDebugHandler::Init(): Failed to get "
341 			"executable path of team %ld: %s\n", fTeam, strerror(error));
342 
343 		fExecutablePath[0] = '\0';
344 	}
345 
346 	// init a debug context for the handler
347 	error = init_debug_context(&fDebugContext, fTeam, nubPort);
348 	if (error != B_OK) {
349 		debug_printf("debug_server: TeamDebugHandler::Init(): Failed to init "
350 			"debug context for team %ld, port %ld: %s\n", fTeam, nubPort,
351 			strerror(error));
352 		return error;
353 	}
354 
355 	// create the message count semaphore
356 	char name[B_OS_NAME_LENGTH];
357 	snprintf(name, sizeof(name), "team %ld message count", fTeam);
358 	fMessageCountSem = create_sem(0, name);
359 	if (fMessageCountSem < 0) {
360 		debug_printf("debug_server: TeamDebugHandler::Init(): Failed to create "
361 			"message count semaphore: %s\n", strerror(fMessageCountSem));
362 		return fMessageCountSem;
363 	}
364 
365 	// spawn the handler thread
366 	snprintf(name, sizeof(name), "team %ld handler", fTeam);
367 	fHandlerThread = spawn_thread(&_HandlerThreadEntry, name, B_NORMAL_PRIORITY,
368 		this);
369 	if (fHandlerThread < 0) {
370 		debug_printf("debug_server: TeamDebugHandler::Init(): Failed to spawn "
371 			"handler thread: %s\n", strerror(fHandlerThread));
372 		return fHandlerThread;
373 	}
374 
375 	resume_thread(fHandlerThread);
376 
377 	return B_OK;
378 }
379 
380 // Team
381 team_id
382 TeamDebugHandler::Team() const
383 {
384 	return fTeam;
385 }
386 
387 // PushMessage
388 status_t
389 TeamDebugHandler::PushMessage(DebugMessage *message)
390 {
391 	BAutolock _(this);
392 
393 	fMessages.Add(message);
394 	release_sem(fMessageCountSem);
395 
396 	return B_OK;
397 }
398 
399 // _PopMessage
400 status_t
401 TeamDebugHandler::_PopMessage(DebugMessage *&message)
402 {
403 	// acquire the semaphore
404 	status_t error;
405 	do {
406 		error = acquire_sem(fMessageCountSem);
407 	} while (error == B_INTERRUPTED);
408 
409 	if (error != B_OK)
410 		return error;
411 
412 	// get the message
413 	BAutolock _(this);
414 
415 	message = fMessages.Head();
416 	fMessages.Remove(message);
417 
418 	return B_OK;
419 }
420 
421 // _EnterDebugger
422 thread_id
423 TeamDebugHandler::_EnterDebugger()
424 {
425 	TRACE(("debug_server: TeamDebugHandler::_EnterDebugger(): team %ld\n",
426 		fTeam));
427 
428 	bool debugInConsoled = _IsGUIServer() || !_AreGUIServersAlive();
429 
430 	// prepare a debugger handover
431 	TRACE(("debug_server: TeamDebugHandler::_EnterDebugger(): preparing "
432 		"debugger handover for team %ld...\n", fTeam));
433 
434 	status_t error = send_debug_message(&fDebugContext,
435 		B_DEBUG_MESSAGE_PREPARE_HANDOVER, NULL, 0, NULL, 0);
436 	if (error != B_OK) {
437 		debug_printf("debug_server: Failed to prepare debugger handover: %s\n",
438 			strerror(error));
439 		return error;
440 	}
441 
442 	// prepare the argument vector
443 	char teamString[32];
444 	snprintf(teamString, sizeof(teamString), "--pid=%ld", fTeam);
445 
446 	const char *terminal = (debugInConsoled ? kConsoledPath : kTerminalPath);
447 
448 	const char *argv[16];
449 	int argc = 0;
450 
451 	argv[argc++] = terminal;
452 
453 	if (!debugInConsoled) {
454 		char windowTitle[64];
455 		snprintf(windowTitle, sizeof(windowTitle), "Debug of Team %ld: %s",
456 			fTeam, _LastPathComponent(fExecutablePath));
457 		argv[argc++] = "-t";
458 		argv[argc++] = windowTitle;
459 	}
460 
461 	argv[argc++] = kGDBPath;
462 	argv[argc++] = teamString;
463 	if (strlen(fExecutablePath) > 0)
464 		argv[argc++] = fExecutablePath;
465 	argv[argc] = NULL;
466 
467 	// start the terminal
468 	TRACE(("debug_server: TeamDebugHandler::_EnterDebugger(): starting  "
469 		"terminal (debugger) for team %ld...\n", fTeam));
470 
471 	thread_id thread = load_image(argc, argv, (const char**)environ);
472 	if (thread < 0) {
473 		debug_printf("debug_server: Failed to start consoled + gdb: %s\n",
474 			strerror(thread));
475 		return thread;
476 	}
477 	resume_thread(thread);
478 
479 	TRACE(("debug_server: TeamDebugHandler::_EnterDebugger(): debugger started "
480 		"for team %ld: thread: %ld\n", fTeam, thread));
481 
482 	return thread;
483 }
484 
485 // _KillTeam
486 void
487 TeamDebugHandler::_KillTeam()
488 {
489 	KillTeam(fTeam, fTeamInfo.args);
490 }
491 
492 // _HandleMessage
493 bool
494 TeamDebugHandler::_HandleMessage(DebugMessage *message)
495 {
496 	// This method is called only for the first message the debugger gets for
497 	// a team. That means only a few messages are actually possible, while
498 	// others wouldn't trigger the debugger in the first place. So we deal with
499 	// all of them the same way, by popping up an alert.
500 	TRACE(("debug_server: TeamDebugHandler::_HandleMessage(): team %ld, code: "
501 		"%ld\n", fTeam, (int32)message->Code()));
502 
503 	thread_id thread = message->Data().origin.thread;
504 
505 	// get some user-readable message
506 	char buffer[512];
507 	switch (message->Code()) {
508 		case B_DEBUGGER_MESSAGE_TEAM_DELETED:
509 			// This shouldn't happen.
510 			debug_printf("debug_server: Got a spurious "
511 				"B_DEBUGGER_MESSAGE_TEAM_DELETED message for team %ld\n",
512 				fTeam);
513 			return true;
514 
515 		case B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED:
516 			get_debug_exception_string(
517 				message->Data().exception_occurred.exception, buffer,
518 				sizeof(buffer));
519 			break;
520 
521 		case B_DEBUGGER_MESSAGE_DEBUGGER_CALL:
522 		{
523 			// get the debugger() message
524 			void *messageAddress = message->Data().debugger_call.message;
525 			char messageBuffer[128];
526 			status_t error = B_OK;
527 			ssize_t bytesRead = debug_read_string(&fDebugContext,
528 				messageAddress, messageBuffer, sizeof(messageBuffer));
529 			if (bytesRead < 0)
530 				error = bytesRead;
531 
532 			if (error == B_OK) {
533 				sprintf(buffer, "Debugger call: `%s'", messageBuffer);
534 			} else {
535 				snprintf(buffer, sizeof(buffer), "Debugger call: %p "
536 					"(Failed to read message: %s)", messageAddress,
537 					strerror(error));
538 			}
539 			break;
540 		}
541 
542 		default:
543 			get_debug_message_string(message->Code(), buffer, sizeof(buffer));
544 			break;
545 	}
546 
547 	debug_printf("debug_server: Thread %ld entered the debugger: %s\n", thread,
548 		buffer);
549 
550 	_PrintStackTrace(thread);
551 
552 	bool kill = true;
553 
554 	// ask the user whether to debug or kill the team
555 	if (_IsGUIServer()) {
556 		// App server, input server, or registrar. We always debug those.
557 		kill = false;
558 	} else if (USE_GUI && _AreGUIServersAlive() && _InitGUI() == B_OK) {
559 		// normal app -- tell the user
560 		_NotifyAppServer(fTeam);
561 		_NotifyRegistrar(fTeam, true, false);
562 
563 		char buffer[1024];
564 		snprintf(buffer, sizeof(buffer), "The application:\n\n      %s\n\n"
565 			"has encountered an error which prevents it from continuing. Haiku "
566 			"will terminate the application and clean up.", fTeamInfo.args);
567 
568 		// TODO: It would be nice if the alert would go away automatically
569 		// if someone else kills our teams.
570 		BAlert *alert = new BAlert(NULL, buffer, "Debug", "OK", NULL,
571 			B_WIDTH_AS_USUAL, B_WARNING_ALERT);
572 		int32 result = alert->Go();
573 		kill = (result == 1);
574 		_NotifyRegistrar(fTeam, false, !kill);
575 	}
576 
577 	return kill;
578 }
579 
580 // _LookupSymbolAddress
581 void
582 TeamDebugHandler::_LookupSymbolAddress(
583 	debug_symbol_lookup_context *lookupContext, const void *address,
584 	char *buffer, int32 bufferSize)
585 {
586 	// lookup the symbol
587 	void *baseAddress;
588 	char symbolName[1024];
589 	char imageName[B_PATH_NAME_LENGTH];
590 	bool exactMatch;
591 	bool lookupSucceeded = false;
592 	if (lookupContext) {
593 		status_t error = debug_lookup_symbol_address(lookupContext, address,
594 			&baseAddress, symbolName, sizeof(symbolName), imageName,
595 			sizeof(imageName), &exactMatch);
596 		lookupSucceeded = (error == B_OK);
597 	}
598 
599 	if (lookupSucceeded) {
600 		// we were able to look something up
601 		if (strlen(symbolName) > 0) {
602 			// we even got a symbol
603 			snprintf(buffer, bufferSize, "%s + %#lx%s", symbolName,
604 				(addr_t)address - (addr_t)baseAddress,
605 				(exactMatch ? "" : " (closest symbol)"));
606 
607 		} else {
608 			// no symbol: image relative address
609 			snprintf(buffer, bufferSize, "(%s + %#lx)", imageName,
610 				(addr_t)address - (addr_t)baseAddress);
611 		}
612 
613 	} else {
614 		// lookup failed: find area containing the IP
615 		bool useAreaInfo = false;
616 		area_info info;
617 		int32 cookie = 0;
618 		while (get_next_area_info(fTeam, &cookie, &info) == B_OK) {
619 			if ((addr_t)info.address <= (addr_t)address
620 				&& (addr_t)info.address + info.size > (addr_t)address) {
621 				useAreaInfo = true;
622 				break;
623 			}
624 		}
625 
626 		if (useAreaInfo) {
627 			snprintf(buffer, bufferSize, "(%s + %#lx)", info.name,
628 				(addr_t)address - (addr_t)info.address);
629 		} else if (bufferSize > 0)
630 			buffer[0] = '\0';
631 	}
632 }
633 
634 // _PrintStackTrace
635 void
636 TeamDebugHandler::_PrintStackTrace(thread_id thread)
637 {
638 	// print a stacktrace
639 	void *ip = NULL;
640 	void *stackFrameAddress = NULL;
641 	status_t error = debug_get_instruction_pointer(&fDebugContext, thread, &ip,
642 		&stackFrameAddress);
643 
644 	if (error == B_OK) {
645 		// create a symbol lookup context
646 		debug_symbol_lookup_context *lookupContext = NULL;
647 		error = debug_create_symbol_lookup_context(fTeam, &lookupContext);
648 		if (error != B_OK) {
649 			debug_printf("debug_server: Failed to create symbol lookup "
650 				"context: %s\n", strerror(error));
651 		}
652 
653 		// lookup the IP
654 		char symbolBuffer[2048];
655 		_LookupSymbolAddress(lookupContext, ip, symbolBuffer,
656 			sizeof(symbolBuffer) - 1);
657 
658 		debug_printf("stack trace, current PC %p  %s:\n", ip, symbolBuffer);
659 
660 		for (int32 i = 0; i < 50; i++) {
661 			debug_stack_frame_info stackFrameInfo;
662 
663 			error = debug_get_stack_frame(&fDebugContext, stackFrameAddress,
664 				&stackFrameInfo);
665 			if (error < B_OK || stackFrameInfo.parent_frame == NULL)
666 				break;
667 
668 			// lookup the return address
669 			_LookupSymbolAddress(lookupContext, stackFrameInfo.return_address,
670 				symbolBuffer, sizeof(symbolBuffer) - 1);
671 
672 			debug_printf("  (%p)  %p  %s\n", stackFrameInfo.frame,
673 				stackFrameInfo.return_address, symbolBuffer);
674 
675 			stackFrameAddress = stackFrameInfo.parent_frame;
676 		}
677 
678 		// delete the symbol lookup context
679 		if (lookupContext)
680 			debug_delete_symbol_lookup_context(lookupContext);
681 	}
682 }
683 
684 
685 void
686 TeamDebugHandler::_NotifyAppServer(team_id team)
687 {
688 	// This will remove any kWindowScreenFeels of the application, so that
689 	// the debugger alert is visible on screen
690 	BRoster::Private roster;
691 	roster.ApplicationCrashed(team);
692 }
693 
694 
695 void
696 TeamDebugHandler::_NotifyRegistrar(team_id team, bool openAlert,
697 	bool stopShutdown)
698 {
699 	BMessage notify(BPrivate::B_REG_TEAM_DEBUGGER_ALERT);
700 	notify.AddInt32("team", team);
701 	notify.AddBool("open", openAlert);
702 	notify.AddBool("stop shutdown", stopShutdown);
703 
704 	BRoster::Private roster;
705 	BMessage reply;
706 	roster.SendTo(&notify, &reply, false);
707 }
708 
709 
710 // _InitGUI
711 status_t
712 TeamDebugHandler::_InitGUI()
713 {
714 	DebugServer *app = dynamic_cast<DebugServer*>(be_app);
715 	BAutolock _(app);
716 	return app->InitGUIContext();
717 }
718 
719 // _HandlerThreadEntry
720 status_t
721 TeamDebugHandler::_HandlerThreadEntry(void *data)
722 {
723 	return ((TeamDebugHandler*)data)->_HandlerThread();
724 }
725 
726 // _HandlerThread
727 status_t
728 TeamDebugHandler::_HandlerThread()
729 {
730 	TRACE(("debug_server: TeamDebugHandler::_HandlerThread(): team %ld\n",
731 		fTeam));
732 
733 	// get initial message
734 	TRACE(("debug_server: TeamDebugHandler::_HandlerThread(): team %ld: "
735 		"getting message...\n", fTeam));
736 
737 	DebugMessage *message;
738 	status_t error = _PopMessage(message);
739 	bool kill;
740 	if (error == B_OK) {
741 		// handle the message
742 		kill = _HandleMessage(message);
743 		delete message;
744 	} else {
745 		debug_printf("TeamDebugHandler::_HandlerThread(): Failed to pop "
746 			"initial message: %s", strerror(error));
747 		kill = true;
748 	}
749 
750 	// kill the team or hand it over to the debugger
751 	thread_id debuggerThread;
752 	if (kill) {
753 		// The team shall be killed. Since that is also the handling in case
754 		// an error occurs while handing over the team to the debugger, we do
755 		// nothing here.
756 	} else if ((debuggerThread = _EnterDebugger()) >= 0) {
757 		// wait for the "handed over" or a "team deleted" message
758 		bool terminate = false;
759 		do {
760 			error = _PopMessage(message);
761 			if (error != B_OK) {
762 				debug_printf("TeamDebugHandler::_HandlerThread(): Failed to "
763 					"pop message: %s", strerror(error));
764 				kill = true;
765 				break;
766 			}
767 
768 			if (message->Code() == B_DEBUGGER_MESSAGE_HANDED_OVER) {
769 				// The team has successfully been handed over to the debugger.
770 				// Nothing to do.
771 				terminate = true;
772 			} else if (message->Code() == B_DEBUGGER_MESSAGE_TEAM_DELETED) {
773 				// The team died. Nothing to do.
774 				terminate = true;
775 			} else {
776 				// Some message we can ignore. The debugger will take care of
777 				// it.
778 
779 				// check whether the debugger thread still lives
780 				thread_info threadInfo;
781 				if (get_thread_info(debuggerThread, &threadInfo) != B_OK) {
782 					// the debugger is gone
783 					debug_printf("debug_server: The debugger for team %ld "
784 						"seems to be gone.", fTeam);
785 
786 					kill = true;
787 					terminate = true;
788 				}
789 			}
790 
791 			delete message;
792 		} while (!terminate);
793 	} else
794 		kill = true;
795 
796 	if (kill) {
797 		// kill the team
798 		_KillTeam();
799 	}
800 
801 	// remove this handler from the roster and delete it
802 	TeamDebugHandlerRoster::Default()->RemoveHandler(fTeam);
803 
804 	delete this;
805 
806 	return B_OK;
807 }
808 
809 // _ExecutableNameEquals
810 bool
811 TeamDebugHandler::_ExecutableNameEquals(const char *name) const
812 {
813 	return strcmp(_LastPathComponent(fExecutablePath), name) == 0;
814 }
815 
816 // _IsAppServer
817 bool
818 TeamDebugHandler::_IsAppServer() const
819 {
820 	return _ExecutableNameEquals("app_server");
821 }
822 
823 // _IsInputServer
824 bool
825 TeamDebugHandler::_IsInputServer() const
826 {
827 	return _ExecutableNameEquals("input_server");
828 }
829 
830 // _IsRegistrar
831 bool
832 TeamDebugHandler::_IsRegistrar() const
833 {
834 	return _ExecutableNameEquals("registrar");
835 }
836 
837 // _IsGUIServer
838 bool
839 TeamDebugHandler::_IsGUIServer() const
840 {
841 	// app or input server
842 	return _IsAppServer() || _IsInputServer() || _IsRegistrar();
843 }
844 
845 // _LastPathComponent
846 const char *
847 TeamDebugHandler::_LastPathComponent(const char *path)
848 {
849 	const char *lastSlash = strrchr(path, '/');
850 	return lastSlash ? lastSlash + 1 : path;
851 }
852 
853 // _FindTeam
854 team_id
855 TeamDebugHandler::_FindTeam(const char *name)
856 {
857 	// Iterate through all teams and check their executable name.
858 	int32 cookie = 0;
859 	team_info teamInfo;
860 	while (get_next_team_info(&cookie, &teamInfo) == B_OK) {
861 		entry_ref ref;
862 		if (BPrivate::get_app_ref(teamInfo.team, &ref) == B_OK) {
863 			if (strcmp(ref.name, name) == 0)
864 				return teamInfo.team;
865 		}
866 	}
867 
868 	return B_ENTRY_NOT_FOUND;
869 }
870 
871 // _AreGUIServersAlive
872 bool
873 TeamDebugHandler::_AreGUIServersAlive()
874 {
875 	return _FindTeam("app_server") >= 0 && _FindTeam("input_server") >= 0
876 		&& _FindTeam("registrar");
877 }
878 
879 
880 // #pragma mark -
881 
882 // constructor
883 DebugServer::DebugServer(status_t &error)
884 	: BServer(kSignature, false, &error),
885 	  fListenerPort(-1),
886 	  fListener(-1),
887 	  fTerminating(false)
888 {
889 }
890 
891 // Init
892 status_t
893 DebugServer::Init()
894 {
895 	// create listener port
896 	fListenerPort = create_port(10, "kernel listener");
897 	if (fListenerPort < 0)
898 		return fListenerPort;
899 
900 	// spawn the listener thread
901 	fListener = spawn_thread(_ListenerEntry, "kernel listener",
902 		B_NORMAL_PRIORITY, this);
903 	if (fListener < 0)
904 		return fListener;
905 
906 	// register as default debugger
907 	status_t error = install_default_debugger(fListenerPort);
908 	if (error != B_OK)
909 		return error;
910 
911 	// resume the listener
912 	resume_thread(fListener);
913 
914 	return B_OK;
915 }
916 
917 
918 bool
919 DebugServer::QuitRequested()
920 {
921 	// Never give up, never surrender. ;-)
922 	return false;
923 }
924 
925 // _ListenerEntry
926 status_t
927 DebugServer::_ListenerEntry(void *data)
928 {
929 	return ((DebugServer*)data)->_Listener();
930 }
931 
932 // _Listener
933 status_t
934 DebugServer::_Listener()
935 {
936 	while (!fTerminating) {
937 		// receive the next debug message
938 		DebugMessage *message = new DebugMessage;
939 		int32 code;
940 		ssize_t bytesRead;
941 		do {
942 			bytesRead = read_port(fListenerPort, &code, &message->Data(),
943 				sizeof(debug_debugger_message_data));
944 		} while (bytesRead == B_INTERRUPTED);
945 
946 		if (bytesRead < 0) {
947 			debug_printf("debug_server: Failed to read from listener port: "
948 				"%s. Terminating!\n", strerror(bytesRead));
949 			exit(1);
950 		}
951 TRACE(("debug_server: Got debug message: team: %ld, code: %ld\n",
952 message->Data().origin.team, code));
953 
954 		message->SetCode((debug_debugger_message)code);
955 
956 		// dispatch the message
957 		TeamDebugHandlerRoster::Default()->DispatchMessage(message);
958 	}
959 
960 	return B_OK;
961 }
962 
963 
964 // #pragma mark -
965 
966 // main
967 int
968 main()
969 {
970 	status_t error;
971 
972 	// for the time being let the debug server print to the syslog
973 	int console = open("/dev/dprintf", O_RDONLY);
974 	if (console < 0) {
975 		debug_printf("debug_server: Failed to open console: %s\n",
976 			strerror(errno));
977 	}
978 	dup2(console, STDOUT_FILENO);
979 	dup2(console, STDERR_FILENO);
980 	close(console);
981 
982 	// create the team debug handler roster
983 	if (!TeamDebugHandlerRoster::CreateDefault()) {
984 		debug_printf("debug_server: Failed to create team debug handler "
985 			"roster.\n");
986 		exit(1);
987 	}
988 
989 	// create application
990 	DebugServer server(error);
991 	if (error != B_OK) {
992 		debug_printf("debug_server: Failed to create BApplication: %s\n",
993 			strerror(error));
994 		exit(1);
995 	}
996 
997 	// init application
998 	error = server.Init();
999 	if (error != B_OK) {
1000 		debug_printf("debug_server: Failed to init application: %s\n",
1001 			strerror(error));
1002 		exit(1);
1003 	}
1004 
1005 	server.Run();
1006 
1007 	return 0;
1008 }
1009