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