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