xref: /haiku/src/servers/debug/DebugServer.cpp (revision 89755088d790ff4fe36f8aa77dacb2bd15507108)
1 /*
2  * Copyright 2005-2006, 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/beos/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 
423 thread_id
424 TeamDebugHandler::_EnterDebugger()
425 {
426 	TRACE(("debug_server: TeamDebugHandler::_EnterDebugger(): team %ld\n",
427 		fTeam));
428 
429 	bool debugInConsoled = _IsGUIServer() || !_AreGUIServersAlive();
430 
431 	// prepare a debugger handover
432 	TRACE(("debug_server: TeamDebugHandler::_EnterDebugger(): preparing "
433 		"debugger handover for team %ld...\n", fTeam));
434 
435 	status_t error = send_debug_message(&fDebugContext,
436 		B_DEBUG_MESSAGE_PREPARE_HANDOVER, NULL, 0, NULL, 0);
437 	if (error != B_OK) {
438 		debug_printf("debug_server: Failed to prepare debugger handover: %s\n",
439 			strerror(error));
440 		return error;
441 	}
442 
443 	// prepare the argument vector
444 	char teamString[32];
445 	snprintf(teamString, sizeof(teamString), "--pid=%ld", fTeam);
446 
447 	const char *terminal = (debugInConsoled ? kConsoledPath : kTerminalPath);
448 
449 	const char *argv[16];
450 	int argc = 0;
451 
452 	argv[argc++] = terminal;
453 
454 	if (!debugInConsoled) {
455 		char windowTitle[64];
456 		snprintf(windowTitle, sizeof(windowTitle), "Debug of Team %ld: %s",
457 			fTeam, _LastPathComponent(fExecutablePath));
458 		argv[argc++] = "-t";
459 		argv[argc++] = windowTitle;
460 	}
461 
462 	argv[argc++] = kGDBPath;
463 	argv[argc++] = teamString;
464 	if (strlen(fExecutablePath) > 0)
465 		argv[argc++] = fExecutablePath;
466 	argv[argc] = NULL;
467 
468 	// start the terminal
469 	TRACE(("debug_server: TeamDebugHandler::_EnterDebugger(): starting  "
470 		"terminal (debugger) for team %ld...\n", fTeam));
471 
472 	thread_id thread = load_image(argc, argv, (const char**)environ);
473 	if (thread < 0) {
474 		debug_printf("debug_server: Failed to start consoled + gdb: %s\n",
475 			strerror(thread));
476 		return thread;
477 	}
478 	resume_thread(thread);
479 
480 	TRACE(("debug_server: TeamDebugHandler::_EnterDebugger(): debugger started "
481 		"for team %ld: thread: %ld\n", fTeam, thread));
482 
483 	return thread;
484 }
485 
486 // _KillTeam
487 void
488 TeamDebugHandler::_KillTeam()
489 {
490 	KillTeam(fTeam, fTeamInfo.args);
491 }
492 
493 // _HandleMessage
494 bool
495 TeamDebugHandler::_HandleMessage(DebugMessage *message)
496 {
497 	// This method is called only for the first message the debugger gets for
498 	// a team. That means only a few messages are actually possible, while
499 	// others wouldn't trigger the debugger in the first place. So we deal with
500 	// all of them the same way, by popping up an alert.
501 	TRACE(("debug_server: TeamDebugHandler::_HandleMessage(): team %ld, code: "
502 		"%ld\n", fTeam, (int32)message->Code()));
503 
504 	thread_id thread = message->Data().origin.thread;
505 
506 	// get some user-readable message
507 	char buffer[512];
508 	switch (message->Code()) {
509 		case B_DEBUGGER_MESSAGE_TEAM_DELETED:
510 			// This shouldn't happen.
511 			debug_printf("debug_server: Got a spurious "
512 				"B_DEBUGGER_MESSAGE_TEAM_DELETED message for team %ld\n",
513 				fTeam);
514 			return true;
515 
516 		case B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED:
517 			get_debug_exception_string(
518 				message->Data().exception_occurred.exception, buffer,
519 				sizeof(buffer));
520 			break;
521 
522 		case B_DEBUGGER_MESSAGE_DEBUGGER_CALL:
523 		{
524 			// get the debugger() message
525 			void *messageAddress = message->Data().debugger_call.message;
526 			char messageBuffer[128];
527 			status_t error = B_OK;
528 			ssize_t bytesRead = debug_read_string(&fDebugContext,
529 				messageAddress, messageBuffer, sizeof(messageBuffer));
530 			if (bytesRead < 0)
531 				error = bytesRead;
532 
533 			if (error == B_OK) {
534 				sprintf(buffer, "Debugger call: `%s'", messageBuffer);
535 			} else {
536 				snprintf(buffer, sizeof(buffer), "Debugger call: %p "
537 					"(Failed to read message: %s)", messageAddress,
538 					strerror(error));
539 			}
540 			break;
541 		}
542 
543 		default:
544 			get_debug_message_string(message->Code(), buffer, sizeof(buffer));
545 			break;
546 	}
547 
548 	debug_printf("debug_server: Thread %ld entered the debugger: %s\n", thread,
549 		buffer);
550 
551 	_PrintStackTrace(thread);
552 
553 	bool kill = true;
554 
555 	// ask the user whether to debug or kill the team
556 	if (_IsGUIServer()) {
557 		// App server, input server, or registrar. We always debug those.
558 		kill = false;
559 	} else if (USE_GUI && _AreGUIServersAlive() && _InitGUI() == B_OK) {
560 		// normal app -- tell the user
561 		_NotifyAppServer(fTeam);
562 		_NotifyRegistrar(fTeam, true, false);
563 
564 		char buffer[1024];
565 		snprintf(buffer, sizeof(buffer), "The application:\n\n      %s\n\n"
566 			"has encountered an error which prevents it from continuing. Haiku "
567 			"will terminate the application and clean up.", fTeamInfo.args);
568 
569 		// TODO: It would be nice if the alert would go away automatically
570 		// if someone else kills our teams.
571 		BAlert *alert = new BAlert(NULL, buffer, "Debug", "OK", NULL,
572 			B_WIDTH_AS_USUAL, B_WARNING_ALERT);
573 		int32 result = alert->Go();
574 		kill = (result == 1);
575 		_NotifyRegistrar(fTeam, false, !kill);
576 	}
577 
578 	return kill;
579 }
580 
581 // _LookupSymbolAddress
582 void
583 TeamDebugHandler::_LookupSymbolAddress(
584 	debug_symbol_lookup_context *lookupContext, const void *address,
585 	char *buffer, int32 bufferSize)
586 {
587 	// lookup the symbol
588 	void *baseAddress;
589 	char symbolName[1024];
590 	char imageName[B_PATH_NAME_LENGTH];
591 	bool exactMatch;
592 	bool lookupSucceeded = false;
593 	if (lookupContext) {
594 		status_t error = debug_lookup_symbol_address(lookupContext, address,
595 			&baseAddress, symbolName, sizeof(symbolName), imageName,
596 			sizeof(imageName), &exactMatch);
597 		lookupSucceeded = (error == B_OK);
598 	}
599 
600 	if (lookupSucceeded) {
601 		// we were able to look something up
602 		if (strlen(symbolName) > 0) {
603 			// we even got a symbol
604 			snprintf(buffer, bufferSize, "%s + %#lx%s", symbolName,
605 				(addr_t)address - (addr_t)baseAddress,
606 				(exactMatch ? "" : " (closest symbol)"));
607 
608 		} else {
609 			// no symbol: image relative address
610 			snprintf(buffer, bufferSize, "(%s + %#lx)", imageName,
611 				(addr_t)address - (addr_t)baseAddress);
612 		}
613 
614 	} else {
615 		// lookup failed: find area containing the IP
616 		bool useAreaInfo = false;
617 		area_info info;
618 		int32 cookie = 0;
619 		while (get_next_area_info(fTeam, &cookie, &info) == B_OK) {
620 			if ((addr_t)info.address <= (addr_t)address
621 				&& (addr_t)info.address + info.size > (addr_t)address) {
622 				useAreaInfo = true;
623 				break;
624 			}
625 		}
626 
627 		if (useAreaInfo) {
628 			snprintf(buffer, bufferSize, "(%s + %#lx)", info.name,
629 				(addr_t)address - (addr_t)info.address);
630 		} else if (bufferSize > 0)
631 			buffer[0] = '\0';
632 	}
633 }
634 
635 // _PrintStackTrace
636 void
637 TeamDebugHandler::_PrintStackTrace(thread_id thread)
638 {
639 	// print a stacktrace
640 	void *ip = NULL;
641 	void *stackFrameAddress = NULL;
642 	status_t error = debug_get_instruction_pointer(&fDebugContext, thread, &ip,
643 		&stackFrameAddress);
644 
645 	if (error == B_OK) {
646 		// create a symbol lookup context
647 		debug_symbol_lookup_context *lookupContext = NULL;
648 		error = debug_create_symbol_lookup_context(&fDebugContext,
649 			&lookupContext);
650 		if (error != B_OK) {
651 			debug_printf("debug_server: Failed to create symbol lookup "
652 				"context: %s\n", strerror(error));
653 		}
654 
655 		// lookup the IP
656 		char symbolBuffer[2048];
657 		_LookupSymbolAddress(lookupContext, ip, symbolBuffer,
658 			sizeof(symbolBuffer) - 1);
659 
660 		debug_printf("stack trace, current PC %p  %s:\n", ip, symbolBuffer);
661 
662 		for (int32 i = 0; i < 50; i++) {
663 			debug_stack_frame_info stackFrameInfo;
664 
665 			error = debug_get_stack_frame(&fDebugContext, stackFrameAddress,
666 				&stackFrameInfo);
667 			if (error < B_OK || stackFrameInfo.parent_frame == NULL)
668 				break;
669 
670 			// lookup the return address
671 			_LookupSymbolAddress(lookupContext, stackFrameInfo.return_address,
672 				symbolBuffer, sizeof(symbolBuffer) - 1);
673 
674 			debug_printf("  (%p)  %p  %s\n", stackFrameInfo.frame,
675 				stackFrameInfo.return_address, symbolBuffer);
676 
677 			stackFrameAddress = stackFrameInfo.parent_frame;
678 		}
679 
680 		// delete the symbol lookup context
681 		if (lookupContext)
682 			debug_delete_symbol_lookup_context(lookupContext);
683 	}
684 }
685 
686 
687 void
688 TeamDebugHandler::_NotifyAppServer(team_id team)
689 {
690 	// This will remove any kWindowScreenFeels of the application, so that
691 	// the debugger alert is visible on screen
692 	BRoster::Private roster;
693 	roster.ApplicationCrashed(team);
694 }
695 
696 
697 void
698 TeamDebugHandler::_NotifyRegistrar(team_id team, bool openAlert,
699 	bool stopShutdown)
700 {
701 	BMessage notify(BPrivate::B_REG_TEAM_DEBUGGER_ALERT);
702 	notify.AddInt32("team", team);
703 	notify.AddBool("open", openAlert);
704 	notify.AddBool("stop shutdown", stopShutdown);
705 
706 	BRoster::Private roster;
707 	BMessage reply;
708 	roster.SendTo(&notify, &reply, false);
709 }
710 
711 
712 // _InitGUI
713 status_t
714 TeamDebugHandler::_InitGUI()
715 {
716 	DebugServer *app = dynamic_cast<DebugServer*>(be_app);
717 	BAutolock _(app);
718 	return app->InitGUIContext();
719 }
720 
721 // _HandlerThreadEntry
722 status_t
723 TeamDebugHandler::_HandlerThreadEntry(void *data)
724 {
725 	return ((TeamDebugHandler*)data)->_HandlerThread();
726 }
727 
728 // _HandlerThread
729 status_t
730 TeamDebugHandler::_HandlerThread()
731 {
732 	TRACE(("debug_server: TeamDebugHandler::_HandlerThread(): team %ld\n",
733 		fTeam));
734 
735 	// get initial message
736 	TRACE(("debug_server: TeamDebugHandler::_HandlerThread(): team %ld: "
737 		"getting message...\n", fTeam));
738 
739 	DebugMessage *message;
740 	status_t error = _PopMessage(message);
741 	bool kill;
742 	if (error == B_OK) {
743 		// handle the message
744 		kill = _HandleMessage(message);
745 		delete message;
746 	} else {
747 		debug_printf("TeamDebugHandler::_HandlerThread(): Failed to pop "
748 			"initial message: %s", strerror(error));
749 		kill = true;
750 	}
751 
752 	// kill the team or hand it over to the debugger
753 	thread_id debuggerThread;
754 	if (kill) {
755 		// The team shall be killed. Since that is also the handling in case
756 		// an error occurs while handing over the team to the debugger, we do
757 		// nothing here.
758 	} else if ((debuggerThread = _EnterDebugger()) >= 0) {
759 		// wait for the "handed over" or a "team deleted" message
760 		bool terminate = false;
761 		do {
762 			error = _PopMessage(message);
763 			if (error != B_OK) {
764 				debug_printf("TeamDebugHandler::_HandlerThread(): Failed to "
765 					"pop message: %s", strerror(error));
766 				kill = true;
767 				break;
768 			}
769 
770 			if (message->Code() == B_DEBUGGER_MESSAGE_HANDED_OVER) {
771 				// The team has successfully been handed over to the debugger.
772 				// Nothing to do.
773 				terminate = true;
774 			} else if (message->Code() == B_DEBUGGER_MESSAGE_TEAM_DELETED) {
775 				// The team died. Nothing to do.
776 				terminate = true;
777 			} else {
778 				// Some message we can ignore. The debugger will take care of
779 				// it.
780 
781 				// check whether the debugger thread still lives
782 				thread_info threadInfo;
783 				if (get_thread_info(debuggerThread, &threadInfo) != B_OK) {
784 					// the debugger is gone
785 					debug_printf("debug_server: The debugger for team %ld "
786 						"seems to be gone.", fTeam);
787 
788 					kill = true;
789 					terminate = true;
790 				}
791 			}
792 
793 			delete message;
794 		} while (!terminate);
795 	} else
796 		kill = true;
797 
798 	if (kill) {
799 		// kill the team
800 		_KillTeam();
801 
802 		// remove this handler from the roster and delete it
803 		TeamDebugHandlerRoster::Default()->RemoveHandler(fTeam);
804 
805 		delete this;
806 	}
807 
808 	return B_OK;
809 }
810 
811 // _ExecutableNameEquals
812 bool
813 TeamDebugHandler::_ExecutableNameEquals(const char *name) const
814 {
815 	return strcmp(_LastPathComponent(fExecutablePath), name) == 0;
816 }
817 
818 // _IsAppServer
819 bool
820 TeamDebugHandler::_IsAppServer() const
821 {
822 	return _ExecutableNameEquals("app_server");
823 }
824 
825 // _IsInputServer
826 bool
827 TeamDebugHandler::_IsInputServer() const
828 {
829 	return _ExecutableNameEquals("input_server");
830 }
831 
832 // _IsRegistrar
833 bool
834 TeamDebugHandler::_IsRegistrar() const
835 {
836 	return _ExecutableNameEquals("registrar");
837 }
838 
839 // _IsGUIServer
840 bool
841 TeamDebugHandler::_IsGUIServer() const
842 {
843 	// app or input server
844 	return _IsAppServer() || _IsInputServer() || _IsRegistrar();
845 }
846 
847 // _LastPathComponent
848 const char *
849 TeamDebugHandler::_LastPathComponent(const char *path)
850 {
851 	const char *lastSlash = strrchr(path, '/');
852 	return lastSlash ? lastSlash + 1 : path;
853 }
854 
855 // _FindTeam
856 team_id
857 TeamDebugHandler::_FindTeam(const char *name)
858 {
859 	// Iterate through all teams and check their executable name.
860 	int32 cookie = 0;
861 	team_info teamInfo;
862 	while (get_next_team_info(&cookie, &teamInfo) == B_OK) {
863 		entry_ref ref;
864 		if (BPrivate::get_app_ref(teamInfo.team, &ref) == B_OK) {
865 			if (strcmp(ref.name, name) == 0)
866 				return teamInfo.team;
867 		}
868 	}
869 
870 	return B_ENTRY_NOT_FOUND;
871 }
872 
873 // _AreGUIServersAlive
874 bool
875 TeamDebugHandler::_AreGUIServersAlive()
876 {
877 	return _FindTeam("app_server") >= 0 && _FindTeam("input_server") >= 0
878 		&& _FindTeam("registrar");
879 }
880 
881 
882 // #pragma mark -
883 
884 // constructor
885 DebugServer::DebugServer(status_t &error)
886 	: BServer(kSignature, false, &error),
887 	  fListenerPort(-1),
888 	  fListener(-1),
889 	  fTerminating(false)
890 {
891 }
892 
893 // Init
894 status_t
895 DebugServer::Init()
896 {
897 	// create listener port
898 	fListenerPort = create_port(10, "kernel listener");
899 	if (fListenerPort < 0)
900 		return fListenerPort;
901 
902 	// spawn the listener thread
903 	fListener = spawn_thread(_ListenerEntry, "kernel listener",
904 		B_NORMAL_PRIORITY, this);
905 	if (fListener < 0)
906 		return fListener;
907 
908 	// register as default debugger
909 	status_t error = install_default_debugger(fListenerPort);
910 	if (error != B_OK)
911 		return error;
912 
913 	// resume the listener
914 	resume_thread(fListener);
915 
916 	return B_OK;
917 }
918 
919 
920 bool
921 DebugServer::QuitRequested()
922 {
923 	// Never give up, never surrender. ;-)
924 	return false;
925 }
926 
927 // _ListenerEntry
928 status_t
929 DebugServer::_ListenerEntry(void *data)
930 {
931 	return ((DebugServer*)data)->_Listener();
932 }
933 
934 // _Listener
935 status_t
936 DebugServer::_Listener()
937 {
938 	while (!fTerminating) {
939 		// receive the next debug message
940 		DebugMessage *message = new DebugMessage;
941 		int32 code;
942 		ssize_t bytesRead;
943 		do {
944 			bytesRead = read_port(fListenerPort, &code, &message->Data(),
945 				sizeof(debug_debugger_message_data));
946 		} while (bytesRead == B_INTERRUPTED);
947 
948 		if (bytesRead < 0) {
949 			debug_printf("debug_server: Failed to read from listener port: "
950 				"%s. Terminating!\n", strerror(bytesRead));
951 			exit(1);
952 		}
953 TRACE(("debug_server: Got debug message: team: %ld, code: %ld\n",
954 message->Data().origin.team, code));
955 
956 		message->SetCode((debug_debugger_message)code);
957 
958 		// dispatch the message
959 		TeamDebugHandlerRoster::Default()->DispatchMessage(message);
960 	}
961 
962 	return B_OK;
963 }
964 
965 
966 // #pragma mark -
967 
968 // main
969 int
970 main()
971 {
972 	status_t error;
973 
974 	// for the time being let the debug server print to the syslog
975 	int console = open("/dev/dprintf", O_RDONLY);
976 	if (console < 0) {
977 		debug_printf("debug_server: Failed to open console: %s\n",
978 			strerror(errno));
979 	}
980 	dup2(console, STDOUT_FILENO);
981 	dup2(console, STDERR_FILENO);
982 	close(console);
983 
984 	// create the team debug handler roster
985 	if (!TeamDebugHandlerRoster::CreateDefault()) {
986 		debug_printf("debug_server: Failed to create team debug handler "
987 			"roster.\n");
988 		exit(1);
989 	}
990 
991 	// create application
992 	DebugServer server(error);
993 	if (error != B_OK) {
994 		debug_printf("debug_server: Failed to create BApplication: %s\n",
995 			strerror(error));
996 		exit(1);
997 	}
998 
999 	// init application
1000 	error = server.Init();
1001 	if (error != B_OK) {
1002 		debug_printf("debug_server: Failed to init application: %s\n",
1003 			strerror(error));
1004 		exit(1);
1005 	}
1006 
1007 	server.Run();
1008 
1009 	return 0;
1010 }
1011