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