xref: /haiku/src/servers/debug/DebugServer.cpp (revision 546208a53940a26c6379c48a7854ade1a8250fc5)
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 		int32 result = alert->Go();
693 		kill = (result == 1);
694 		_NotifyRegistrar(fTeam, false, !kill);
695 	}
696 
697 	return kill;
698 }
699 
700 
701 void
702 TeamDebugHandler::_LookupSymbolAddress(
703 	debug_symbol_lookup_context *lookupContext, const void *address,
704 	char *buffer, int32 bufferSize)
705 {
706 	// lookup the symbol
707 	void *baseAddress;
708 	char symbolName[1024];
709 	char imageName[B_PATH_NAME_LENGTH];
710 	bool exactMatch;
711 	bool lookupSucceeded = false;
712 	if (lookupContext) {
713 		status_t error = debug_lookup_symbol_address(lookupContext, address,
714 			&baseAddress, symbolName, sizeof(symbolName), imageName,
715 			sizeof(imageName), &exactMatch);
716 		lookupSucceeded = (error == B_OK);
717 	}
718 
719 	if (lookupSucceeded) {
720 		// we were able to look something up
721 		if (strlen(symbolName) > 0) {
722 			// we even got a symbol
723 			snprintf(buffer, bufferSize, "%s + %#lx%s", symbolName,
724 				(addr_t)address - (addr_t)baseAddress,
725 				(exactMatch ? "" : " (closest symbol)"));
726 
727 		} else {
728 			// no symbol: image relative address
729 			snprintf(buffer, bufferSize, "(%s + %#lx)", imageName,
730 				(addr_t)address - (addr_t)baseAddress);
731 		}
732 
733 	} else {
734 		// lookup failed: find area containing the IP
735 		bool useAreaInfo = false;
736 		area_info info;
737 		int32 cookie = 0;
738 		while (get_next_area_info(fTeam, &cookie, &info) == B_OK) {
739 			if ((addr_t)info.address <= (addr_t)address
740 				&& (addr_t)info.address + info.size > (addr_t)address) {
741 				useAreaInfo = true;
742 				break;
743 			}
744 		}
745 
746 		if (useAreaInfo) {
747 			snprintf(buffer, bufferSize, "(%s + %#lx)", info.name,
748 				(addr_t)address - (addr_t)info.address);
749 		} else if (bufferSize > 0)
750 			buffer[0] = '\0';
751 	}
752 }
753 
754 
755 void
756 TeamDebugHandler::_PrintStackTrace(thread_id thread)
757 {
758 	// print a stacktrace
759 	void *ip = NULL;
760 	void *stackFrameAddress = NULL;
761 	status_t error = debug_get_instruction_pointer(&fDebugContext, thread, &ip,
762 		&stackFrameAddress);
763 
764 	if (error == B_OK) {
765 		// create a symbol lookup context
766 		debug_symbol_lookup_context *lookupContext = NULL;
767 		error = debug_create_symbol_lookup_context(fTeam, &lookupContext);
768 		if (error != B_OK) {
769 			debug_printf("debug_server: Failed to create symbol lookup "
770 				"context: %s\n", strerror(error));
771 		}
772 
773 		// lookup the IP
774 		char symbolBuffer[2048];
775 		_LookupSymbolAddress(lookupContext, ip, symbolBuffer,
776 			sizeof(symbolBuffer) - 1);
777 
778 		debug_printf("stack trace, current PC %p  %s:\n", ip, symbolBuffer);
779 
780 		for (int32 i = 0; i < 50; i++) {
781 			debug_stack_frame_info stackFrameInfo;
782 
783 			error = debug_get_stack_frame(&fDebugContext, stackFrameAddress,
784 				&stackFrameInfo);
785 			if (error < B_OK || stackFrameInfo.parent_frame == NULL)
786 				break;
787 
788 			// lookup the return address
789 			_LookupSymbolAddress(lookupContext, stackFrameInfo.return_address,
790 				symbolBuffer, sizeof(symbolBuffer) - 1);
791 
792 			debug_printf("  (%p)  %p  %s\n", stackFrameInfo.frame,
793 				stackFrameInfo.return_address, symbolBuffer);
794 
795 			stackFrameAddress = stackFrameInfo.parent_frame;
796 		}
797 
798 		// delete the symbol lookup context
799 		if (lookupContext)
800 			debug_delete_symbol_lookup_context(lookupContext);
801 	}
802 }
803 
804 
805 void
806 TeamDebugHandler::_NotifyAppServer(team_id team)
807 {
808 	// This will remove any kWindowScreenFeels of the application, so that
809 	// the debugger alert is visible on screen
810 	BRoster::Private roster;
811 	roster.ApplicationCrashed(team);
812 }
813 
814 
815 void
816 TeamDebugHandler::_NotifyRegistrar(team_id team, bool openAlert,
817 	bool stopShutdown)
818 {
819 	BMessage notify(BPrivate::B_REG_TEAM_DEBUGGER_ALERT);
820 	notify.AddInt32("team", team);
821 	notify.AddBool("open", openAlert);
822 	notify.AddBool("stop shutdown", stopShutdown);
823 
824 	BRoster::Private roster;
825 	BMessage reply;
826 	roster.SendTo(&notify, &reply, false);
827 }
828 
829 
830 status_t
831 TeamDebugHandler::_InitGUI()
832 {
833 	DebugServer *app = dynamic_cast<DebugServer*>(be_app);
834 	BAutolock _(app);
835 	return app->InitGUIContext();
836 }
837 
838 
839 status_t
840 TeamDebugHandler::_HandlerThreadEntry(void *data)
841 {
842 	return ((TeamDebugHandler*)data)->_HandlerThread();
843 }
844 
845 
846 status_t
847 TeamDebugHandler::_HandlerThread()
848 {
849 	TRACE(("debug_server: TeamDebugHandler::_HandlerThread(): team %ld\n",
850 		fTeam));
851 
852 	// get initial message
853 	TRACE(("debug_server: TeamDebugHandler::_HandlerThread(): team %ld: "
854 		"getting message...\n", fTeam));
855 
856 	DebugMessage *message;
857 	status_t error = _PopMessage(message);
858 	bool kill;
859 	if (error == B_OK) {
860 		// handle the message
861 		kill = _HandleMessage(message);
862 		delete message;
863 	} else {
864 		debug_printf("TeamDebugHandler::_HandlerThread(): Failed to pop "
865 			"initial message: %s", strerror(error));
866 		kill = true;
867 	}
868 
869 	bool isGuiServer = _IsGUIServer();
870 
871 	// kill the team or hand it over to the debugger
872 	thread_id debuggerThread = -1;
873 	if (kill) {
874 		// The team shall be killed. Since that is also the handling in case
875 		// an error occurs while handing over the team to the debugger, we do
876 		// nothing here.
877 	} else if ((debuggerThread = _EnterDebugger()) >= 0) {
878 		// wait for the "handed over" or a "team deleted" message
879 		bool terminate = false;
880 		do {
881 			error = _PopMessage(message);
882 			if (error != B_OK) {
883 				debug_printf("TeamDebugHandler::_HandlerThread(): Failed to "
884 					"pop message: %s", strerror(error));
885 				kill = true;
886 				break;
887 			}
888 
889 			if (message->Code() == B_DEBUGGER_MESSAGE_HANDED_OVER) {
890 				// The team has successfully been handed over to the debugger.
891 				// Nothing to do.
892 				terminate = true;
893 			} else if (message->Code() == B_DEBUGGER_MESSAGE_TEAM_DELETED) {
894 				// The team died. Nothing to do.
895 				terminate = true;
896 			} else {
897 				// Some message we can ignore. The debugger will take care of
898 				// it.
899 
900 				// check whether the debugger thread still lives
901 				thread_info threadInfo;
902 				if (get_thread_info(debuggerThread, &threadInfo) != B_OK) {
903 					// the debugger is gone
904 					debug_printf("debug_server: The debugger for team %ld "
905 						"seems to be gone.", fTeam);
906 
907 					kill = true;
908 					terminate = true;
909 				}
910 			}
911 
912 			delete message;
913 		} while (!terminate);
914 	} else
915 		kill = true;
916 
917 	if (kill) {
918 		// kill the team
919 		_KillTeam();
920 	}
921 
922 	// remove this handler from the roster and delete it
923 	TeamDebugHandlerRoster::Default()->RemoveHandler(fTeam);
924 
925 	if (isGuiServer) {
926 		// wait till debugging is done
927 		status_t dummy;
928 		wait_for_thread(debuggerThread, &dummy);
929 
930 		// find the registrar port
931 		port_id rosterPort = find_port(BPrivate::get_roster_port_name());
932 		port_info info;
933 		BMessenger messenger;
934 		if (rosterPort >= 0 && get_port_info(rosterPort, &info) == B_OK) {
935 			BMessenger::Private(messenger).SetTo(info.team, rosterPort,
936 				B_PREFERRED_TOKEN);
937 		}
938 		messenger.SendMessage(kMsgRestartAppServer);
939 	}
940 
941 	delete this;
942 
943 	return B_OK;
944 }
945 
946 
947 bool
948 TeamDebugHandler::_ExecutableNameEquals(const char *name) const
949 {
950 	return strcmp(_LastPathComponent(fExecutablePath), name) == 0;
951 }
952 
953 
954 bool
955 TeamDebugHandler::_IsAppServer() const
956 {
957 	return _ExecutableNameEquals("app_server");
958 }
959 
960 
961 bool
962 TeamDebugHandler::_IsInputServer() const
963 {
964 	return _ExecutableNameEquals("input_server");
965 }
966 
967 
968 bool
969 TeamDebugHandler::_IsRegistrar() const
970 {
971 	return _ExecutableNameEquals("registrar");
972 }
973 
974 
975 bool
976 TeamDebugHandler::_IsGUIServer() const
977 {
978 	// app or input server
979 	return _IsAppServer() || _IsInputServer() || _IsRegistrar();
980 }
981 
982 
983 const char *
984 TeamDebugHandler::_LastPathComponent(const char *path)
985 {
986 	const char *lastSlash = strrchr(path, '/');
987 	return lastSlash ? lastSlash + 1 : path;
988 }
989 
990 
991 team_id
992 TeamDebugHandler::_FindTeam(const char *name)
993 {
994 	// Iterate through all teams and check their executable name.
995 	int32 cookie = 0;
996 	team_info teamInfo;
997 	while (get_next_team_info(&cookie, &teamInfo) == B_OK) {
998 		entry_ref ref;
999 		if (BPrivate::get_app_ref(teamInfo.team, &ref) == B_OK) {
1000 			if (strcmp(ref.name, name) == 0)
1001 				return teamInfo.team;
1002 		}
1003 	}
1004 
1005 	return B_ENTRY_NOT_FOUND;
1006 }
1007 
1008 
1009 bool
1010 TeamDebugHandler::_AreGUIServersAlive()
1011 {
1012 	return _FindTeam("app_server") >= 0 && _FindTeam("input_server") >= 0
1013 		&& _FindTeam("registrar");
1014 }
1015 
1016 
1017 // #pragma mark -
1018 
1019 
1020 DebugServer::DebugServer(status_t &error)
1021 	:
1022 	BServer(kSignature, false, &error),
1023 	fListenerPort(-1),
1024 	fListener(-1),
1025 	fTerminating(false)
1026 {
1027 }
1028 
1029 
1030 status_t
1031 DebugServer::Init()
1032 {
1033 	// create listener port
1034 	fListenerPort = create_port(10, "kernel listener");
1035 	if (fListenerPort < 0)
1036 		return fListenerPort;
1037 
1038 	// spawn the listener thread
1039 	fListener = spawn_thread(_ListenerEntry, "kernel listener",
1040 		B_NORMAL_PRIORITY, this);
1041 	if (fListener < 0)
1042 		return fListener;
1043 
1044 	// register as default debugger
1045 	// TODO: could set default flags
1046 	status_t error = install_default_debugger(fListenerPort);
1047 	if (error != B_OK)
1048 		return error;
1049 
1050 	// resume the listener
1051 	resume_thread(fListener);
1052 
1053 	return B_OK;
1054 }
1055 
1056 
1057 bool
1058 DebugServer::QuitRequested()
1059 {
1060 	// Never give up, never surrender. ;-)
1061 	return false;
1062 }
1063 
1064 
1065 status_t
1066 DebugServer::_ListenerEntry(void *data)
1067 {
1068 	return ((DebugServer*)data)->_Listener();
1069 }
1070 
1071 
1072 status_t
1073 DebugServer::_Listener()
1074 {
1075 	while (!fTerminating) {
1076 		// receive the next debug message
1077 		DebugMessage *message = new DebugMessage;
1078 		int32 code;
1079 		ssize_t bytesRead;
1080 		do {
1081 			bytesRead = read_port(fListenerPort, &code, &message->Data(),
1082 				sizeof(debug_debugger_message_data));
1083 		} while (bytesRead == B_INTERRUPTED);
1084 
1085 		if (bytesRead < 0) {
1086 			debug_printf("debug_server: Failed to read from listener port: "
1087 				"%s. Terminating!\n", strerror(bytesRead));
1088 			exit(1);
1089 		}
1090 TRACE(("debug_server: Got debug message: team: %ld, code: %ld\n",
1091 message->Data().origin.team, code));
1092 
1093 		message->SetCode((debug_debugger_message)code);
1094 
1095 		// dispatch the message
1096 		TeamDebugHandlerRoster::Default()->DispatchMessage(message);
1097 	}
1098 
1099 	return B_OK;
1100 }
1101 
1102 
1103 // #pragma mark -
1104 
1105 
1106 int
1107 main()
1108 {
1109 	status_t error;
1110 
1111 	// for the time being let the debug server print to the syslog
1112 	int console = open("/dev/dprintf", O_RDONLY);
1113 	if (console < 0) {
1114 		debug_printf("debug_server: Failed to open console: %s\n",
1115 			strerror(errno));
1116 	}
1117 	dup2(console, STDOUT_FILENO);
1118 	dup2(console, STDERR_FILENO);
1119 	close(console);
1120 
1121 	// create the team debug handler roster
1122 	if (!TeamDebugHandlerRoster::CreateDefault()) {
1123 		debug_printf("debug_server: Failed to create team debug handler "
1124 			"roster.\n");
1125 		exit(1);
1126 	}
1127 
1128 	// create application
1129 	DebugServer server(error);
1130 	if (error != B_OK) {
1131 		debug_printf("debug_server: Failed to create BApplication: %s\n",
1132 			strerror(error));
1133 		exit(1);
1134 	}
1135 
1136 	// init application
1137 	error = server.Init();
1138 	if (error != B_OK) {
1139 		debug_printf("debug_server: Failed to init application: %s\n",
1140 			strerror(error));
1141 		exit(1);
1142 	}
1143 
1144 	server.Run();
1145 
1146 	return 0;
1147 }
1148