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