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