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