139c9d198SIngo Weinhold/*
224df6592SIngo Weinhold * Copyright 2005-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
34dc355e9SRene Gollent * Copyright 2013, Rene Gollent, rene@gollent.com.
4e69a3a86SAxel Dörfler * Copyright 2015, Axel D��rfler, axeld@pinc-software.de.
539c9d198SIngo Weinhold * Distributed under the terms of the MIT License.
639c9d198SIngo Weinhold */
739c9d198SIngo Weinhold
824df6592SIngo Weinhold
939c9d198SIngo Weinhold#include <ctype.h>
1039c9d198SIngo Weinhold#include <stdio.h>
1139c9d198SIngo Weinhold#include <stdlib.h>
1239c9d198SIngo Weinhold#include <string.h>
133aeed660SJérôme Duval#include <strings.h>
1456805797SAxel Dörfler#include <errno.h>
155e3a8a4aSAxel Dörfler#include <signal.h>
1639c9d198SIngo Weinhold
17e69a3a86SAxel Dörfler#include <algorithm>
1839c9d198SIngo Weinhold#include <map>
1939c9d198SIngo Weinhold#include <string>
2039c9d198SIngo Weinhold#include <vector>
2139c9d198SIngo Weinhold
2239c9d198SIngo Weinhold#include <debugger.h>
2339c9d198SIngo Weinhold#include <image.h>
244ef509f0SIngo Weinhold#include <syscalls.h>
2539c9d198SIngo Weinhold
268df6a8dbSIngo Weinhold#include "debug_utils.h"
278df6a8dbSIngo Weinhold
2895ebbeb1SIngo Weinhold#include "Context.h"
2939c9d198SIngo Weinhold#include "MemoryReader.h"
3039c9d198SIngo Weinhold#include "Syscall.h"
3139c9d198SIngo Weinhold#include "TypeHandler.h"
3239c9d198SIngo Weinhold
3324df6592SIngo Weinhold
34758b1d0eSIngo Weinholdusing std::map;
35758b1d0eSIngo Weinholdusing std::string;
36758b1d0eSIngo Weinholdusing std::vector;
37758b1d0eSIngo Weinhold
3824df6592SIngo Weinhold
39e69a3a86SAxel Dörflerstruct syscall_stats {
40e69a3a86SAxel Dörfler	bigtime_t	time;
41e69a3a86SAxel Dörfler	uint32		count;
42e69a3a86SAxel Dörfler};
43e69a3a86SAxel Dörfler
44e69a3a86SAxel Dörfler
4539c9d198SIngo Weinholdextern void get_syscalls0(vector<Syscall*> &syscalls);
4639c9d198SIngo Weinholdextern void get_syscalls1(vector<Syscall*> &syscalls);
4739c9d198SIngo Weinholdextern void get_syscalls2(vector<Syscall*> &syscalls);
4839c9d198SIngo Weinholdextern void get_syscalls3(vector<Syscall*> &syscalls);
4939c9d198SIngo Weinholdextern void get_syscalls4(vector<Syscall*> &syscalls);
5039c9d198SIngo Weinholdextern void get_syscalls5(vector<Syscall*> &syscalls);
5139c9d198SIngo Weinholdextern void get_syscalls6(vector<Syscall*> &syscalls);
5239c9d198SIngo Weinholdextern void get_syscalls7(vector<Syscall*> &syscalls);
5339c9d198SIngo Weinholdextern void get_syscalls8(vector<Syscall*> &syscalls);
5439c9d198SIngo Weinholdextern void get_syscalls9(vector<Syscall*> &syscalls);
5539c9d198SIngo Weinholdextern void get_syscalls10(vector<Syscall*> &syscalls);
5639c9d198SIngo Weinholdextern void get_syscalls11(vector<Syscall*> &syscalls);
5739c9d198SIngo Weinholdextern void get_syscalls12(vector<Syscall*> &syscalls);
5839c9d198SIngo Weinholdextern void get_syscalls13(vector<Syscall*> &syscalls);
5939c9d198SIngo Weinholdextern void get_syscalls14(vector<Syscall*> &syscalls);
6039c9d198SIngo Weinholdextern void get_syscalls15(vector<Syscall*> &syscalls);
6139c9d198SIngo Weinholdextern void get_syscalls16(vector<Syscall*> &syscalls);
6239c9d198SIngo Weinholdextern void get_syscalls17(vector<Syscall*> &syscalls);
6339c9d198SIngo Weinholdextern void get_syscalls18(vector<Syscall*> &syscalls);
6439c9d198SIngo Weinholdextern void get_syscalls19(vector<Syscall*> &syscalls);
6539c9d198SIngo Weinhold
6624df6592SIngo Weinhold
670efd929eSAxel Dörflerextern const char *__progname;
680efd929eSAxel Dörflerstatic const char *kCommandName = __progname;
6939c9d198SIngo Weinhold
7024df6592SIngo Weinhold
7139c9d198SIngo Weinhold// usage
7239c9d198SIngo Weinholdstatic const char *kUsage =
7339c9d198SIngo Weinhold"Usage: %s [ <options> ] [ <thread or team ID> | <executable with args> ]\n"
7439c9d198SIngo Weinhold"\n"
75e69a3a86SAxel Dörfler"Traces the syscalls of a thread or a team. If an executable with\n"
7639c9d198SIngo Weinhold"arguments is supplied, it is loaded and it's main thread traced.\n"
7739c9d198SIngo Weinhold"\n"
7839c9d198SIngo Weinhold"Options:\n"
7939c9d198SIngo Weinhold"  -a             - Don't print syscall arguments.\n"
80e69a3a86SAxel Dörfler"  -c             - Record and dump syscall usage statistics.\n"
81e69a3a86SAxel Dörfler"  -C             - Same as -c, but also print syscalls as usual.\n"
82567638c6SIngo Weinhold"  -d <name>      - Filter the types that have their contents retrieved.\n"
83a71744baSIngo Weinhold"                   <name> is one of: strings, enums, simple, complex or\n"
84a71744baSIngo Weinhold"                                     pointer_values\n"
8539c9d198SIngo Weinhold"  -f             - Fast mode. Syscall arguments contents aren't retrieved.\n"
8639c9d198SIngo Weinhold"  -h, --help     - Print this text.\n"
87567638c6SIngo Weinhold"  -i             - Print integers in decimal format instead of hexadecimal.\n"
88869ca0ebSJérôme Duval"  -l             - Also trace loading the executable. Only considered when\n"
894ef509f0SIngo Weinhold"                   an executable is provided.\n"
90e69a3a86SAxel Dörfler"  --no-color     - Don't colorize output.\n"
9139c9d198SIngo Weinhold"  -r             - Don't print syscall return values.\n"
9239c9d198SIngo Weinhold"  -s             - Also trace all threads spawned by the supplied thread,\n"
9339c9d198SIngo Weinhold"                   respectively the loaded executable's main thread.\n"
9424df6592SIngo Weinhold"  -t             - Also recursively trace all teams created by a traced\n"
9524df6592SIngo Weinhold"                   thread or team.\n"
9639c9d198SIngo Weinhold"  -T             - Trace all threads of the supplied or loaded executable's\n"
9739c9d198SIngo Weinhold"                   team. If an ID is supplied, it is interpreted as a team\n"
9837f7862fSIngo Weinhold"                   ID.\n"
9956805797SAxel Dörfler"  -o <file>      - directs output into the specified file.\n"
10056805797SAxel Dörfler"  -S             - prints output to serial debug line.\n"
1015e3a8a4aSAxel Dörfler"  -g             - turns off signal tracing.\n"
10239c9d198SIngo Weinhold;
10339c9d198SIngo Weinhold
10424df6592SIngo Weinhold
105592cc301SIngo Weinhold// terminal color escape sequences
106592cc301SIngo Weinhold// (http://www.dee.ufcg.edu.br/~rrbrandt/tools/ansi.html)
107592cc301SIngo Weinholdstatic const char *kTerminalTextNormal	= "\33[0m";
108592cc301SIngo Weinholdstatic const char *kTerminalTextRed		= "\33[31m";
109592cc301SIngo Weinholdstatic const char *kTerminalTextMagenta	= "\33[35m";
1105e3a8a4aSAxel Dörflerstatic const char *kTerminalTextBlue	= "\33[34m";
1115e3a8a4aSAxel Dörfler
112592cc301SIngo Weinhold
11339c9d198SIngo Weinhold// command line args
11439c9d198SIngo Weinholdstatic int sArgc;
11539c9d198SIngo Weinholdstatic const char *const *sArgv;
11639c9d198SIngo Weinhold
11739c9d198SIngo Weinhold// syscalls
11839c9d198SIngo Weinholdstatic vector<Syscall*>			sSyscallVector;
11939c9d198SIngo Weinholdstatic map<string, Syscall*>	sSyscallMap;
12039c9d198SIngo Weinhold
121e69a3a86SAxel Dörfler// statistics
122e69a3a86SAxel Dörflertypedef map<string, syscall_stats> StatsMap;
123e69a3a86SAxel Dörflerstatic StatsMap sSyscallStats;
124e69a3a86SAxel Dörflerstatic bigtime_t sSyscallTime;
125e69a3a86SAxel Dörfler
12624df6592SIngo Weinhold
12724df6592SIngo Weinholdstruct Team {
12824df6592SIngo Weinhold	Team(team_id id)
12924df6592SIngo Weinhold		:
13024df6592SIngo Weinhold		fID(id),
13124df6592SIngo Weinhold		fNubPort(-1)
13224df6592SIngo Weinhold	{
13324df6592SIngo Weinhold	}
13424df6592SIngo Weinhold
13524df6592SIngo Weinhold	team_id ID() const
13624df6592SIngo Weinhold	{
13724df6592SIngo Weinhold		return fID;
13824df6592SIngo Weinhold	}
13924df6592SIngo Weinhold
14024df6592SIngo Weinhold	port_id NubPort() const
14124df6592SIngo Weinhold	{
14224df6592SIngo Weinhold		return fNubPort;
14324df6592SIngo Weinhold	}
14424df6592SIngo Weinhold
14524df6592SIngo Weinhold	MemoryReader& GetMemoryReader()
14624df6592SIngo Weinhold	{
14724df6592SIngo Weinhold		return fMemoryReader;
14824df6592SIngo Weinhold	}
14924df6592SIngo Weinhold
15024df6592SIngo Weinhold	status_t InstallDebugger(port_id debuggerPort, bool traceTeam,
15124df6592SIngo Weinhold		bool traceChildTeams, bool traceSignal)
15224df6592SIngo Weinhold	{
15324df6592SIngo Weinhold		fNubPort = install_team_debugger(fID, debuggerPort);
15424df6592SIngo Weinhold		if (fNubPort < 0) {
15524df6592SIngo Weinhold			fprintf(stderr, "%s: Failed to install team debugger: %s\n",
15624df6592SIngo Weinhold				kCommandName, strerror(fNubPort));
15724df6592SIngo Weinhold			return fNubPort;
15824df6592SIngo Weinhold		}
15924df6592SIngo Weinhold
16024df6592SIngo Weinhold		// set team debugging flags
16124df6592SIngo Weinhold		int32 teamDebugFlags = (traceTeam ? B_TEAM_DEBUG_POST_SYSCALL : 0)
16224df6592SIngo Weinhold			| (traceChildTeams ? B_TEAM_DEBUG_TEAM_CREATION : 0)
16324df6592SIngo Weinhold			| (traceSignal ? B_TEAM_DEBUG_SIGNALS : 0);
1644dc355e9SRene Gollent		if (set_team_debugging_flags(fNubPort, teamDebugFlags) != B_OK)
1654dc355e9SRene Gollent			exit(1);
16624df6592SIngo Weinhold
16724df6592SIngo Weinhold		return fMemoryReader.Init(fNubPort);
16824df6592SIngo Weinhold	}
16924df6592SIngo Weinhold
17024df6592SIngo Weinholdprivate:
17124df6592SIngo Weinhold	team_id			fID;
17224df6592SIngo Weinhold	port_id			fNubPort;
17324df6592SIngo Weinhold	MemoryReader	fMemoryReader;
17424df6592SIngo Weinhold};
17524df6592SIngo Weinhold
17624df6592SIngo Weinhold
17724df6592SIngo Weinholdstatic void
17839c9d198SIngo Weinholdprint_usage(bool error)
17939c9d198SIngo Weinhold{
18039c9d198SIngo Weinhold	// print usage
1810efd929eSAxel Dörfler	fprintf((error ? stderr : stdout), kUsage, kCommandName);
18239c9d198SIngo Weinhold}
18339c9d198SIngo Weinhold
18424df6592SIngo Weinhold
18524df6592SIngo Weinholdstatic void
18639c9d198SIngo Weinholdprint_usage_and_exit(bool error)
18739c9d198SIngo Weinhold{
18839c9d198SIngo Weinhold	print_usage(error);
18939c9d198SIngo Weinhold	exit(error ? 1 : 0);
19039c9d198SIngo Weinhold}
19139c9d198SIngo Weinhold
19224df6592SIngo Weinhold
19324df6592SIngo Weinholdstatic bool
19439c9d198SIngo Weinholdget_id(const char *str, int32 &id)
19539c9d198SIngo Weinhold{
19639c9d198SIngo Weinhold	int32 len = strlen(str);
19739c9d198SIngo Weinhold	for (int32 i = 0; i < len; i++) {
19839c9d198SIngo Weinhold		if (!isdigit(str[i]))
19939c9d198SIngo Weinhold			return false;
20039c9d198SIngo Weinhold	}
20139c9d198SIngo Weinhold
20239c9d198SIngo Weinhold	id = atol(str);
20339c9d198SIngo Weinhold	return true;
20439c9d198SIngo Weinhold}
20539c9d198SIngo Weinhold
20624df6592SIngo Weinhold
20795ebbeb1SIngo WeinholdSyscall *
20895ebbeb1SIngo Weinholdget_syscall(const char *name)
20995ebbeb1SIngo Weinhold{
21095ebbeb1SIngo Weinhold	map<string, Syscall *>::const_iterator i = sSyscallMap.find(name);
21195ebbeb1SIngo Weinhold	if (i == sSyscallMap.end())
21295ebbeb1SIngo Weinhold		return NULL;
21395ebbeb1SIngo Weinhold
21495ebbeb1SIngo Weinhold	return i->second;
21595ebbeb1SIngo Weinhold}
21695ebbeb1SIngo Weinhold
21724df6592SIngo Weinhold
218567638c6SIngo Weinholdstatic void
219567638c6SIngo Weinholdpatch_syscalls()
220567638c6SIngo Weinhold{
221567638c6SIngo Weinhold	// instead of having this done here manually we should either add the
222567638c6SIngo Weinhold	// patching step to gensyscalls also manually or add metadata to
223567638c6SIngo Weinhold	// kernel/syscalls.h and have it parsed automatically
224567638c6SIngo Weinhold	extern void patch_ioctl();
225567638c6SIngo Weinhold
226567638c6SIngo Weinhold	patch_ioctl();
227567638c6SIngo Weinhold}
228567638c6SIngo Weinhold
22924df6592SIngo Weinhold
23024df6592SIngo Weinholdstatic void
23139c9d198SIngo Weinholdinit_syscalls()
23239c9d198SIngo Weinhold{
23339c9d198SIngo Weinhold	// init the syscall vector
23439c9d198SIngo Weinhold	get_syscalls0(sSyscallVector);
23539c9d198SIngo Weinhold	get_syscalls1(sSyscallVector);
23639c9d198SIngo Weinhold	get_syscalls2(sSyscallVector);
23739c9d198SIngo Weinhold	get_syscalls3(sSyscallVector);
23839c9d198SIngo Weinhold	get_syscalls4(sSyscallVector);
23939c9d198SIngo Weinhold	get_syscalls5(sSyscallVector);
24039c9d198SIngo Weinhold	get_syscalls6(sSyscallVector);
24139c9d198SIngo Weinhold	get_syscalls7(sSyscallVector);
24239c9d198SIngo Weinhold	get_syscalls8(sSyscallVector);
24339c9d198SIngo Weinhold	get_syscalls9(sSyscallVector);
24439c9d198SIngo Weinhold	get_syscalls10(sSyscallVector);
24539c9d198SIngo Weinhold	get_syscalls11(sSyscallVector);
24639c9d198SIngo Weinhold	get_syscalls12(sSyscallVector);
24739c9d198SIngo Weinhold	get_syscalls13(sSyscallVector);
24839c9d198SIngo Weinhold	get_syscalls14(sSyscallVector);
24939c9d198SIngo Weinhold	get_syscalls15(sSyscallVector);
25039c9d198SIngo Weinhold	get_syscalls16(sSyscallVector);
25139c9d198SIngo Weinhold	get_syscalls17(sSyscallVector);
25239c9d198SIngo Weinhold	get_syscalls18(sSyscallVector);
25339c9d198SIngo Weinhold	get_syscalls19(sSyscallVector);
25439c9d198SIngo Weinhold
25539c9d198SIngo Weinhold	// init the syscall map
25639c9d198SIngo Weinhold	int32 count = sSyscallVector.size();
25739c9d198SIngo Weinhold	for (int32 i = 0; i < count; i++) {
25839c9d198SIngo Weinhold		Syscall *syscall = sSyscallVector[i];
25939c9d198SIngo Weinhold		sSyscallMap[syscall->Name()] = syscall;
26039c9d198SIngo Weinhold	}
261567638c6SIngo Weinhold
262567638c6SIngo Weinhold	patch_syscalls();
26339c9d198SIngo Weinhold}
26439c9d198SIngo Weinhold
26524df6592SIngo Weinhold
266e69a3a86SAxel Dörflerstatic void
267e69a3a86SAxel Dörflerrecord_syscall_stats(const Syscall& syscall, debug_post_syscall& message)
268e69a3a86SAxel Dörfler{
269e69a3a86SAxel Dörfler	syscall_stats& stats = sSyscallStats[syscall.Name()];
270e69a3a86SAxel Dörfler	stats.count++;
271e69a3a86SAxel Dörfler
272e69a3a86SAxel Dörfler	bigtime_t time = message.end_time - message.start_time;
273e69a3a86SAxel Dörfler	stats.time += time;
274e69a3a86SAxel Dörfler	sSyscallTime += time;
275e69a3a86SAxel Dörfler}
276e69a3a86SAxel Dörfler
277e69a3a86SAxel Dörfler
278e69a3a86SAxel Dörflerstatic void
279e69a3a86SAxel Dörflerprint_buffer(FILE *outputFile, char* buffer, int32 length)
280e69a3a86SAxel Dörfler{
281e69a3a86SAxel Dörfler	// output either to file or serial debug line
282e69a3a86SAxel Dörfler	if (outputFile != NULL)
283e69a3a86SAxel Dörfler		fwrite(buffer, length, 1, outputFile);
284e69a3a86SAxel Dörfler	else
285e69a3a86SAxel Dörfler		_kern_debug_output(buffer);
286e69a3a86SAxel Dörfler}
287e69a3a86SAxel Dörfler
288e69a3a86SAxel Dörfler
28924df6592SIngo Weinholdstatic void
29056805797SAxel Dörflerprint_to_string(char **_buffer, int32 *_length, const char *format, ...)
29156805797SAxel Dörfler{
29256805797SAxel Dörfler	va_list list;
29356805797SAxel Dörfler	va_start(list, format);
29456805797SAxel Dörfler	ssize_t length = vsnprintf(*_buffer, *_length, format, list);
29556805797SAxel Dörfler	va_end(list);
29656805797SAxel Dörfler
29756805797SAxel Dörfler	*_buffer += length;
29856805797SAxel Dörfler	*_length -= length;
29956805797SAxel Dörfler}
30056805797SAxel Dörfler
30124df6592SIngo Weinhold
30224df6592SIngo Weinholdstatic void
303e69a3a86SAxel Dörflerprint_syscall(FILE *outputFile, Syscall* syscall, debug_post_syscall &message,
304567638c6SIngo Weinhold	MemoryReader &memoryReader, bool printArguments, uint32 contentsFlags,
305567638c6SIngo Weinhold	bool printReturnValue, bool colorize, bool decimal)
30639c9d198SIngo Weinhold{
30756805797SAxel Dörfler	char buffer[4096], *string = buffer;
30856805797SAxel Dörfler	int32 length = (int32)sizeof(buffer);
30939c9d198SIngo Weinhold
310567638c6SIngo Weinhold	Context ctx(syscall, (char *)message.args, memoryReader,
311567638c6SIngo Weinhold		    contentsFlags, decimal);
312567638c6SIngo Weinhold
313da452ce2SAugustin Cavalier	// print syscall name, without the "_kern_"
314592cc301SIngo Weinhold	if (colorize) {
31556805797SAxel Dörfler		print_to_string(&string, &length, "[%6ld] %s%s%s(",
316da452ce2SAugustin Cavalier			message.origin.thread, kTerminalTextBlue,
317da452ce2SAugustin Cavalier			syscall->Name().c_str() + 6, kTerminalTextNormal);
318592cc301SIngo Weinhold	} else {
31956805797SAxel Dörfler		print_to_string(&string, &length, "[%6ld] %s(",
320da452ce2SAugustin Cavalier			message.origin.thread, syscall->Name().c_str() + 6);
321592cc301SIngo Weinhold	}
32239c9d198SIngo Weinhold
32339c9d198SIngo Weinhold	// print arguments
32439c9d198SIngo Weinhold	if (printArguments) {
32539c9d198SIngo Weinhold		int32 count = syscall->CountParameters();
32639c9d198SIngo Weinhold		for (int32 i = 0; i < count; i++) {
32739c9d198SIngo Weinhold			// get the value
32839c9d198SIngo Weinhold			Parameter *parameter = syscall->ParameterAt(i);
32939c9d198SIngo Weinhold			TypeHandler *handler = parameter->Handler();
330567638c6SIngo Weinhold			::string value =
331567638c6SIngo Weinhold				handler->GetParameterValue(ctx, parameter,
332567638c6SIngo Weinhold						ctx.GetValue(parameter));
33339c9d198SIngo Weinhold
33456805797SAxel Dörfler			print_to_string(&string, &length, (i > 0 ? ", %s" : "%s"),
33556805797SAxel Dörfler				value.c_str());
33639c9d198SIngo Weinhold		}
33739c9d198SIngo Weinhold	}
33839c9d198SIngo Weinhold
33956805797SAxel Dörfler	print_to_string(&string, &length, ")");
34039c9d198SIngo Weinhold
34139c9d198SIngo Weinhold	// print return value
34239c9d198SIngo Weinhold	if (printReturnValue) {
343592cc301SIngo Weinhold		Type *returnType = syscall->ReturnType();
344592cc301SIngo Weinhold		TypeHandler *handler = returnType->Handler();
345567638c6SIngo Weinhold		::string value = handler->GetReturnValue(ctx, message.return_value);
346592cc301SIngo Weinhold		if (value.length() > 0) {
34756805797SAxel Dörfler			print_to_string(&string, &length, " = %s", value.c_str());
348592cc301SIngo Weinhold
349592cc301SIngo Weinhold			// if the return type is status_t or ssize_t, print human-readable
350592cc301SIngo Weinhold			// error codes
351592cc301SIngo Weinhold			if (returnType->TypeName() == "status_t"
352e69a3a86SAxel Dörfler				|| ((returnType->TypeName() == "ssize_t"
353e69a3a86SAxel Dörfler						|| returnType->TypeName() == "int")
35464c68424SFrançois Revol					&& message.return_value < 0)) {
35556805797SAxel Dörfler				print_to_string(&string, &length, " %s", strerror(message.return_value));
356592cc301SIngo Weinhold			}
357592cc301SIngo Weinhold		}
35839c9d198SIngo Weinhold	}
35939c9d198SIngo Weinhold
360592cc301SIngo Weinhold	if (colorize) {
36156805797SAxel Dörfler		print_to_string(&string, &length, " %s(%lld us)%s\n", kTerminalTextMagenta,
362592cc301SIngo Weinhold			message.end_time - message.start_time, kTerminalTextNormal);
363592cc301SIngo Weinhold	} else {
36456805797SAxel Dörfler		print_to_string(&string, &length, " (%lld us)\n",
36556805797SAxel Dörfler			message.end_time - message.start_time);
366592cc301SIngo Weinhold	}
36739c9d198SIngo Weinhold
36839c9d198SIngo Weinhold//for (int32 i = 0; i < 16; i++) {
36939c9d198SIngo Weinhold//	if (i % 4 == 0) {
37039c9d198SIngo Weinhold//		if (i > 0)
37139c9d198SIngo Weinhold//			printf("\n");
37239c9d198SIngo Weinhold//		printf("  ");
37339c9d198SIngo Weinhold//	} else
37439c9d198SIngo Weinhold//		printf(" ");
37539c9d198SIngo Weinhold//	printf("%08lx", message.args[i]);
37639c9d198SIngo Weinhold//}
37739c9d198SIngo Weinhold//printf("\n");
378e69a3a86SAxel Dörfler	print_buffer(outputFile, buffer, sizeof(buffer) - length);
37939c9d198SIngo Weinhold}
38039c9d198SIngo Weinhold
38124df6592SIngo Weinhold
38224df6592SIngo Weinholdstatic const char *
3835e3a8a4aSAxel Dörflersignal_name(int signal)
3845e3a8a4aSAxel Dörfler{
3855e3a8a4aSAxel Dörfler	if (signal >= 0 && signal < NSIG)
38624df6592SIngo Weinhold		return strsignal(signal);
3875e3a8a4aSAxel Dörfler
3885e3a8a4aSAxel Dörfler	static char buffer[32];
3895e3a8a4aSAxel Dörfler	sprintf(buffer, "%d", signal);
3905e3a8a4aSAxel Dörfler	return buffer;
3915e3a8a4aSAxel Dörfler}
3925e3a8a4aSAxel Dörfler
39324df6592SIngo Weinhold
39424df6592SIngo Weinholdstatic void
3955e3a8a4aSAxel Dörflerprint_signal(FILE *outputFile, debug_signal_received &message,
3965e3a8a4aSAxel Dörfler	bool colorize)
3975e3a8a4aSAxel Dörfler{
3985e3a8a4aSAxel Dörfler	char buffer[4096], *string = buffer;
3995e3a8a4aSAxel Dörfler	int32 length = (int32)sizeof(buffer);
4005e3a8a4aSAxel Dörfler	int signalNumber = message.signal;
4015e3a8a4aSAxel Dörfler
4025e3a8a4aSAxel Dörfler	// print signal name
4035e3a8a4aSAxel Dörfler	if (colorize) {
4045e3a8a4aSAxel Dörfler		print_to_string(&string, &length, "[%6ld] --- %s%s (%s) %s---\n",
4055e3a8a4aSAxel Dörfler			message.origin.thread, kTerminalTextRed, signal_name(signalNumber),
4065e3a8a4aSAxel Dörfler			strsignal(signalNumber), kTerminalTextNormal);
4075e3a8a4aSAxel Dörfler	} else {
4085e3a8a4aSAxel Dörfler		print_to_string(&string, &length, "[%6ld] --- %s (%s) ---\n",
4095e3a8a4aSAxel Dörfler			message.origin.thread, signal_name(signalNumber),
4105e3a8a4aSAxel Dörfler			strsignal(signalNumber));
4115e3a8a4aSAxel Dörfler	}
4125e3a8a4aSAxel Dörfler
413e69a3a86SAxel Dörfler	print_buffer(outputFile, buffer, sizeof(buffer) - length);
414e69a3a86SAxel Dörfler}
415e69a3a86SAxel Dörfler
416e69a3a86SAxel Dörfler
417e69a3a86SAxel Dörflerstatic bool
418e69a3a86SAxel Dörflercompare_stats_by_time(
419e69a3a86SAxel Dörfler	const std::pair<const std::string*, const syscall_stats*>& a,
420e69a3a86SAxel Dörfler	const std::pair<const std::string*, const syscall_stats*>& b)
421e69a3a86SAxel Dörfler{
422e69a3a86SAxel Dörfler	return a.second->time > b.second->time;
423e69a3a86SAxel Dörfler}
424e69a3a86SAxel Dörfler
425e69a3a86SAxel Dörfler
426e69a3a86SAxel Dörflerstatic void
427e69a3a86SAxel Dörflerprint_stats(FILE* outputFile)
428e69a3a86SAxel Dörfler{
429e69a3a86SAxel Dörfler	char buffer[4096], *string = buffer;
430e69a3a86SAxel Dörfler	int32 length = (int32)sizeof(buffer);
431e69a3a86SAxel Dörfler
432e69a3a86SAxel Dörfler	typedef std::vector<std::pair<const std::string*, const syscall_stats*> >
433e69a3a86SAxel Dörfler		StatsRefVector;
434e69a3a86SAxel Dörfler	StatsRefVector calls;
435e69a3a86SAxel Dörfler	StatsMap::const_iterator iterator = sSyscallStats.begin();
436e69a3a86SAxel Dörfler	for (; iterator != sSyscallStats.end(); iterator++)
437e69a3a86SAxel Dörfler		calls.push_back(std::make_pair(&iterator->first, &iterator->second));
438e69a3a86SAxel Dörfler
439e69a3a86SAxel Dörfler	// Sort calls by time spent
440e69a3a86SAxel Dörfler	std::sort(calls.begin(), calls.end(), compare_stats_by_time);
441e69a3a86SAxel Dörfler
442e69a3a86SAxel Dörfler	print_to_string(&string, &length, "\n%-6s %-10s %-7s %-10s Syscall\n",
443e69a3a86SAxel Dörfler		"Time %", "Usecs", "Calls", "Usecs/call");
444e69a3a86SAxel Dörfler	print_to_string(&string, &length, "------ ---------- ------- ---------- "
445e69a3a86SAxel Dörfler		"--------------------\n");
446e69a3a86SAxel Dörfler
447e69a3a86SAxel Dörfler	StatsRefVector::const_iterator callIterator = calls.begin();
448e69a3a86SAxel Dörfler	for (; callIterator != calls.end(); callIterator++) {
449e69a3a86SAxel Dörfler		const syscall_stats& stats = *callIterator->second;
450e69a3a86SAxel Dörfler		double percent = stats.time * 100.0 / sSyscallTime;
451e69a3a86SAxel Dörfler		bigtime_t perCall = stats.time / stats.count;
452e69a3a86SAxel Dörfler
453e69a3a86SAxel Dörfler		print_to_string(&string, &length, "%6.2f %10" B_PRIu64 " %7" B_PRIu32
454e69a3a86SAxel Dörfler			" %10" B_PRIu64 " %s\n", percent, stats.time, stats.count, perCall,
455e69a3a86SAxel Dörfler			callIterator->first->c_str());
456e69a3a86SAxel Dörfler	}
457e69a3a86SAxel Dörfler
458e69a3a86SAxel Dörfler	print_buffer(outputFile, buffer, sizeof(buffer) - length);
4595e3a8a4aSAxel Dörfler}
46039c9d198SIngo Weinhold
46124df6592SIngo Weinhold
46239c9d198SIngo Weinholdint
46339c9d198SIngo Weinholdmain(int argc, const char *const *argv)
46439c9d198SIngo Weinhold{
46539c9d198SIngo Weinhold	sArgc = argc;
46639c9d198SIngo Weinhold	sArgv = argv;
46739c9d198SIngo Weinhold
46839c9d198SIngo Weinhold	// parameters
46939c9d198SIngo Weinhold	const char *const *programArgs = NULL;
47039c9d198SIngo Weinhold	int32 programArgCount = 0;
47139c9d198SIngo Weinhold	bool printArguments = true;
47239c9d198SIngo Weinhold	bool colorize = true;
473e69a3a86SAxel Dörfler	bool stats = false;
474e69a3a86SAxel Dörfler	bool trace = true;
475567638c6SIngo Weinhold	uint32 contentsFlags = 0;
476567638c6SIngo Weinhold	bool decimalFormat = false;
47739c9d198SIngo Weinhold	bool fastMode = false;
4784ef509f0SIngo Weinhold	bool traceLoading = false;
47939c9d198SIngo Weinhold	bool printReturnValues = true;
48039c9d198SIngo Weinhold	bool traceChildThreads = false;
48139c9d198SIngo Weinhold	bool traceTeam = false;
48224df6592SIngo Weinhold	bool traceChildTeams = false;
4835e3a8a4aSAxel Dörfler	bool traceSignal = true;
48456805797SAxel Dörfler	bool serialOutput = false;
48556805797SAxel Dörfler	FILE *outputFile = stdout;
48639c9d198SIngo Weinhold
48739c9d198SIngo Weinhold	// parse arguments
48839c9d198SIngo Weinhold	for (int argi = 1; argi < argc; argi++) {
48939c9d198SIngo Weinhold		const char *arg = argv[argi];
49039c9d198SIngo Weinhold		if (arg[0] == '-') {
49156805797SAxel Dörfler			// ToDo: improve option parsing so that ie. "-rsf" would also work
49239c9d198SIngo Weinhold			if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) {
49339c9d198SIngo Weinhold				print_usage_and_exit(false);
49439c9d198SIngo Weinhold			} else if (strcmp(arg, "-a") == 0) {
49539c9d198SIngo Weinhold				printArguments = false;
49639c9d198SIngo Weinhold			} else if (strcmp(arg, "-c") == 0) {
497e69a3a86SAxel Dörfler				stats = true;
498e69a3a86SAxel Dörfler				trace = false;
499e69a3a86SAxel Dörfler			} else if (strcmp(arg, "-C") == 0) {
500e69a3a86SAxel Dörfler				stats = true;
501e69a3a86SAxel Dörfler			} else if (strcmp(arg, "--no-color") == 0) {
50239c9d198SIngo Weinhold				colorize = false;
503567638c6SIngo Weinhold			} else if (strcmp(arg, "-d") == 0) {
504567638c6SIngo Weinhold				const char *what = NULL;
505567638c6SIngo Weinhold
506567638c6SIngo Weinhold				if (arg[2] == '\0'
507567638c6SIngo Weinhold					&& argi + 1 < argc && argv[argi + 1][0] != '-') {
508567638c6SIngo Weinhold					// next arg is what
509567638c6SIngo Weinhold					what = argv[++argi];
510567638c6SIngo Weinhold				} else
511567638c6SIngo Weinhold					print_usage_and_exit(true);
512567638c6SIngo Weinhold
513567638c6SIngo Weinhold				if (strcasecmp(what, "strings") == 0)
514567638c6SIngo Weinhold					contentsFlags |= Context::STRINGS;
515567638c6SIngo Weinhold				else if (strcasecmp(what, "enums") == 0)
516567638c6SIngo Weinhold					contentsFlags |= Context::ENUMERATIONS;
517567638c6SIngo Weinhold				else if (strcasecmp(what, "simple") == 0)
518567638c6SIngo Weinhold					contentsFlags |= Context::SIMPLE_STRUCTS;
519567638c6SIngo Weinhold				else if (strcasecmp(what, "complex") == 0)
520567638c6SIngo Weinhold					contentsFlags |= Context::COMPLEX_STRUCTS;
521a71744baSIngo Weinhold				else if (strcasecmp(what, "pointer_values") == 0)
522a71744baSIngo Weinhold					contentsFlags |= Context::POINTER_VALUES;
523567638c6SIngo Weinhold				else {
524567638c6SIngo Weinhold					fprintf(stderr, "%s: Unknown content filter `%s'\n",
525567638c6SIngo Weinhold						kCommandName, what);
526567638c6SIngo Weinhold					exit(1);
527567638c6SIngo Weinhold				}
52839c9d198SIngo Weinhold			} else if (strcmp(arg, "-f") == 0) {
52939c9d198SIngo Weinhold				fastMode = true;
530567638c6SIngo Weinhold			} else if (strcmp(arg, "-i") == 0) {
531567638c6SIngo Weinhold				decimalFormat = true;
5324ef509f0SIngo Weinhold			} else if (strcmp(arg, "-l") == 0) {
5334ef509f0SIngo Weinhold				traceLoading = true;
53439c9d198SIngo Weinhold			} else if (strcmp(arg, "-r") == 0) {
53539c9d198SIngo Weinhold				printReturnValues = false;
53639c9d198SIngo Weinhold			} else if (strcmp(arg, "-s") == 0) {
53739c9d198SIngo Weinhold				traceChildThreads = true;
53824df6592SIngo Weinhold			} else if (strcmp(arg, "-t") == 0) {
53924df6592SIngo Weinhold				traceChildTeams = true;
54039c9d198SIngo Weinhold			} else if (strcmp(arg, "-T") == 0) {
54139c9d198SIngo Weinhold				traceTeam = true;
5425e3a8a4aSAxel Dörfler			} else if (strcmp(arg, "-g") == 0) {
5435e3a8a4aSAxel Dörfler				traceSignal = false;
54456805797SAxel Dörfler			} else if (strcmp(arg, "-S") == 0) {
54556805797SAxel Dörfler				serialOutput = true;
54656805797SAxel Dörfler				outputFile = NULL;
54756805797SAxel Dörfler			} else if (strncmp(arg, "-o", 2) == 0) {
54856805797SAxel Dörfler				// read filename
54956805797SAxel Dörfler				const char *filename = NULL;
55056805797SAxel Dörfler				if (arg[2] == '=') {
55156805797SAxel Dörfler					// name follows
55256805797SAxel Dörfler					filename = arg + 3;
55356805797SAxel Dörfler				} else if (arg[2] == '\0'
55456805797SAxel Dörfler					&& argi + 1 < argc && argv[argi + 1][0] != '-') {
55556805797SAxel Dörfler					// next arg is name
55656805797SAxel Dörfler					filename = argv[++argi];
55756805797SAxel Dörfler				} else
55856805797SAxel Dörfler					print_usage_and_exit(true);
55956805797SAxel Dörfler
56056805797SAxel Dörfler				outputFile = fopen(filename, "w+");
56156805797SAxel Dörfler				if (outputFile == NULL) {
5620efd929eSAxel Dörfler					fprintf(stderr, "%s: Could not open `%s': %s\n",
5630efd929eSAxel Dörfler						kCommandName, filename, strerror(errno));
56456805797SAxel Dörfler					exit(1);
56556805797SAxel Dörfler				}
56639c9d198SIngo Weinhold			} else {
56739c9d198SIngo Weinhold				print_usage_and_exit(true);
56839c9d198SIngo Weinhold			}
56939c9d198SIngo Weinhold		} else {
57039c9d198SIngo Weinhold			programArgs = argv + argi;
57139c9d198SIngo Weinhold			programArgCount = argc - argi;
57239c9d198SIngo Weinhold			break;
57339c9d198SIngo Weinhold		}
57439c9d198SIngo Weinhold	}
57539c9d198SIngo Weinhold
57639c9d198SIngo Weinhold	// check parameters
57739c9d198SIngo Weinhold	if (!programArgs)
57839c9d198SIngo Weinhold		print_usage_and_exit(true);
57939c9d198SIngo Weinhold
580567638c6SIngo Weinhold	if (fastMode)
581567638c6SIngo Weinhold		contentsFlags = 0;
582567638c6SIngo Weinhold	else if (contentsFlags == 0)
583567638c6SIngo Weinhold		contentsFlags = Context::ALL;
584567638c6SIngo Weinhold
58539c9d198SIngo Weinhold	// initialize our syscalls vector and map
58639c9d198SIngo Weinhold	init_syscalls();
58739c9d198SIngo Weinhold
588592cc301SIngo Weinhold	// don't colorize the output, if we don't have a terminal
58956805797SAxel Dörfler	if (outputFile == stdout)
59056805797SAxel Dörfler		colorize = colorize && isatty(STDOUT_FILENO);
59156805797SAxel Dörfler	else if (outputFile)
59256805797SAxel Dörfler		colorize = false;
593592cc301SIngo Weinhold
59439c9d198SIngo Weinhold	// get thread/team to be debugged
59524df6592SIngo Weinhold	thread_id threadID = -1;
59624df6592SIngo Weinhold	team_id teamID = -1;
59739c9d198SIngo Weinhold	if (programArgCount > 1
59824df6592SIngo Weinhold		|| !get_id(*programArgs, (traceTeam ? teamID : threadID))) {
59939c9d198SIngo Weinhold		// we've been given an executable and need to load it
60024df6592SIngo Weinhold		threadID = load_program(programArgs, programArgCount, traceLoading);
60124df6592SIngo Weinhold		if (threadID < 0) {
6020efd929eSAxel Dörfler			fprintf(stderr, "%s: Failed to start `%s': %s\n", kCommandName,
60324df6592SIngo Weinhold				programArgs[0], strerror(threadID));
6044ef509f0SIngo Weinhold			exit(1);
6054ef509f0SIngo Weinhold		}
606567638c6SIngo Weinhold	}
60739c9d198SIngo Weinhold
60839c9d198SIngo Weinhold	// get the team ID, if we have none yet
60924df6592SIngo Weinhold	if (teamID < 0) {
61039c9d198SIngo Weinhold		thread_info threadInfo;
61124df6592SIngo Weinhold		status_t error = get_thread_info(threadID, &threadInfo);
61239c9d198SIngo Weinhold		if (error != B_OK) {
613a3802ca9SAlex Smith			fprintf(stderr, "%s: Failed to get info for thread %" B_PRId32
614a3802ca9SAlex Smith				": %s\n", kCommandName, threadID, strerror(error));
61539c9d198SIngo Weinhold			exit(1);
61639c9d198SIngo Weinhold		}
61724df6592SIngo Weinhold		teamID = threadInfo.team;
61839c9d198SIngo Weinhold	}
61939c9d198SIngo Weinhold
62039c9d198SIngo Weinhold	// create a debugger port
62139c9d198SIngo Weinhold	port_id debuggerPort = create_port(10, "debugger port");
62239c9d198SIngo Weinhold	if (debuggerPort < 0) {
6230efd929eSAxel Dörfler		fprintf(stderr, "%s: Failed to create debugger port: %s\n",
6240efd929eSAxel Dörfler			kCommandName, strerror(debuggerPort));
62539c9d198SIngo Weinhold		exit(1);
62639c9d198SIngo Weinhold	}
62739c9d198SIngo Weinhold
62839c9d198SIngo Weinhold	// install ourselves as the team debugger
62924df6592SIngo Weinhold	typedef map<team_id, Team*> TeamMap;
63024df6592SIngo Weinhold	TeamMap debuggedTeams;
63124df6592SIngo Weinhold	port_id nubPort;
63224df6592SIngo Weinhold
63324df6592SIngo Weinhold	{
63424df6592SIngo Weinhold		Team* team = new Team(teamID);
63524df6592SIngo Weinhold		status_t error = team->InstallDebugger(debuggerPort, traceTeam,
63624df6592SIngo Weinhold			traceChildTeams, traceSignal);
63724df6592SIngo Weinhold		if (error != B_OK)
63824df6592SIngo Weinhold			exit(1);
63924df6592SIngo Weinhold
64024df6592SIngo Weinhold		debuggedTeams[team->ID()] = team;
64139c9d198SIngo Weinhold
64224df6592SIngo Weinhold		nubPort = team->NubPort();
64324df6592SIngo Weinhold	}
64439c9d198SIngo Weinhold
64539c9d198SIngo Weinhold	// set thread debugging flags
64624df6592SIngo Weinhold	if (threadID >= 0) {
64739c9d198SIngo Weinhold		int32 threadDebugFlags = 0;
64839c9d198SIngo Weinhold		if (!traceTeam) {
64939c9d198SIngo Weinhold			threadDebugFlags = B_THREAD_DEBUG_POST_SYSCALL
65039c9d198SIngo Weinhold				| (traceChildThreads
65139c9d198SIngo Weinhold					? B_THREAD_DEBUG_SYSCALL_TRACE_CHILD_THREADS : 0);
65239c9d198SIngo Weinhold		}
6534dc355e9SRene Gollent		if (set_thread_debugging_flags(nubPort, threadID, threadDebugFlags)
6544dc355e9SRene Gollent				!= B_OK) {
6554dc355e9SRene Gollent			exit(1);
6564dc355e9SRene Gollent		}
65739c9d198SIngo Weinhold
65839c9d198SIngo Weinhold		// resume the target thread to be sure, it's running
65924df6592SIngo Weinhold		resume_thread(threadID);
66039c9d198SIngo Weinhold	}
66139c9d198SIngo Weinhold
66239c9d198SIngo Weinhold	// debug loop
66339c9d198SIngo Weinhold	while (true) {
6640efd929eSAxel Dörfler		bool quitLoop = false;
66539c9d198SIngo Weinhold		int32 code;
66639c9d198SIngo Weinhold		debug_debugger_message_data message;
66739c9d198SIngo Weinhold		ssize_t messageSize = read_port(debuggerPort, &code, &message,
66839c9d198SIngo Weinhold			sizeof(message));
66939c9d198SIngo Weinhold
67039c9d198SIngo Weinhold		if (messageSize < 0) {
67139c9d198SIngo Weinhold			if (messageSize == B_INTERRUPTED)
67239c9d198SIngo Weinhold				continue;
67339c9d198SIngo Weinhold
6740efd929eSAxel Dörfler			fprintf(stderr, "%s: Reading from debugger port failed: %s\n",
6750efd929eSAxel Dörfler				kCommandName, strerror(messageSize));
67639c9d198SIngo Weinhold			exit(1);
67739c9d198SIngo Weinhold		}
67839c9d198SIngo Weinhold
67939c9d198SIngo Weinhold		switch (code) {
680448e975cSIngo Weinhold			case B_DEBUGGER_MESSAGE_POST_SYSCALL:
68139c9d198SIngo Weinhold			{
68224df6592SIngo Weinhold				TeamMap::iterator it = debuggedTeams.find(message.origin.team);
68324df6592SIngo Weinhold				if (it == debuggedTeams.end())
68424df6592SIngo Weinhold					break;
68524df6592SIngo Weinhold
68624df6592SIngo Weinhold				Team* team = it->second;
68724df6592SIngo Weinhold				MemoryReader& memoryReader = team->GetMemoryReader();
68824df6592SIngo Weinhold
68949783dc8SAugustin Cavalier				uint32 syscallNumber = message.post_syscall.syscall;
69049783dc8SAugustin Cavalier				if (syscallNumber >= sSyscallVector.size()) {
69149783dc8SAugustin Cavalier					fprintf(stderr, "%s: invalid syscall %" B_PRIu32 " attempted\n",
69249783dc8SAugustin Cavalier						kCommandName, syscallNumber);
69349783dc8SAugustin Cavalier					break;
69449783dc8SAugustin Cavalier				}
695e69a3a86SAxel Dörfler				Syscall* syscall = sSyscallVector[syscallNumber];
696e69a3a86SAxel Dörfler
697e69a3a86SAxel Dörfler				if (stats)
698e69a3a86SAxel Dörfler					record_syscall_stats(*syscall, message.post_syscall);
699e69a3a86SAxel Dörfler
700e69a3a86SAxel Dörfler				if (trace) {
701e69a3a86SAxel Dörfler					print_syscall(outputFile, syscall, message.post_syscall,
702e69a3a86SAxel Dörfler						memoryReader, printArguments, contentsFlags,
703e69a3a86SAxel Dörfler						printReturnValues, colorize, decimalFormat);
704e69a3a86SAxel Dörfler				}
7055e3a8a4aSAxel Dörfler				break;
7065e3a8a4aSAxel Dörfler			}
70739c9d198SIngo Weinhold
7085e3a8a4aSAxel Dörfler			case B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED:
7095e3a8a4aSAxel Dörfler			{
710e69a3a86SAxel Dörfler				if (traceSignal && trace)
71124df6592SIngo Weinhold					print_signal(outputFile, message.signal_received, colorize);
71239c9d198SIngo Weinhold				break;
71339c9d198SIngo Weinhold			}
714448e975cSIngo Weinhold
715edc47dd5SIngo Weinhold			case B_DEBUGGER_MESSAGE_THREAD_DEBUGGED:
716edc47dd5SIngo Weinhold			case B_DEBUGGER_MESSAGE_DEBUGGER_CALL:
717edc47dd5SIngo Weinhold			case B_DEBUGGER_MESSAGE_BREAKPOINT_HIT:
718edc47dd5SIngo Weinhold			case B_DEBUGGER_MESSAGE_WATCHPOINT_HIT:
719edc47dd5SIngo Weinhold			case B_DEBUGGER_MESSAGE_SINGLE_STEP:
720448e975cSIngo Weinhold			case B_DEBUGGER_MESSAGE_PRE_SYSCALL:
721ebac278fSIngo Weinhold			case B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED:
722448e975cSIngo Weinhold			case B_DEBUGGER_MESSAGE_THREAD_CREATED:
723edc47dd5SIngo Weinhold			case B_DEBUGGER_MESSAGE_THREAD_DELETED:
724448e975cSIngo Weinhold			case B_DEBUGGER_MESSAGE_IMAGE_CREATED:
725448e975cSIngo Weinhold			case B_DEBUGGER_MESSAGE_IMAGE_DELETED:
72639c9d198SIngo Weinhold				break;
72739c9d198SIngo Weinhold
72824df6592SIngo Weinhold			case B_DEBUGGER_MESSAGE_TEAM_CREATED:
72924df6592SIngo Weinhold			{
73024df6592SIngo Weinhold				if (!traceChildTeams)
73124df6592SIngo Weinhold					break;
73224df6592SIngo Weinhold
73324df6592SIngo Weinhold				Team* team = new(std::nothrow) Team(
73424df6592SIngo Weinhold					message.team_created.new_team);
73524df6592SIngo Weinhold				if (team == NULL) {
73624df6592SIngo Weinhold					fprintf(stderr, "%s: Out of memory!\n", kCommandName);
73724df6592SIngo Weinhold					break;
73824df6592SIngo Weinhold				}
73924df6592SIngo Weinhold
74024df6592SIngo Weinhold				status_t error = team->InstallDebugger(debuggerPort, true, true,
74124df6592SIngo Weinhold					traceSignal);
74224df6592SIngo Weinhold				if (error != B_OK) {
74324df6592SIngo Weinhold					delete team;
74424df6592SIngo Weinhold					break;
74524df6592SIngo Weinhold				}
74624df6592SIngo Weinhold
74724df6592SIngo Weinhold				debuggedTeams[team->ID()] = team;
74824df6592SIngo Weinhold				break;
74924df6592SIngo Weinhold			}
75024df6592SIngo Weinhold
75139c9d198SIngo Weinhold			case B_DEBUGGER_MESSAGE_TEAM_DELETED:
75224df6592SIngo Weinhold			{
75324df6592SIngo Weinhold				// a debugged team is gone
75424df6592SIngo Weinhold				TeamMap::iterator it = debuggedTeams.find(message.origin.team);
75524df6592SIngo Weinhold				if (it == debuggedTeams.end())
75624df6592SIngo Weinhold					break;
75724df6592SIngo Weinhold
75824df6592SIngo Weinhold				Team* team = it->second;
75924df6592SIngo Weinhold				debuggedTeams.erase(it);
76024df6592SIngo Weinhold				delete team;
76124df6592SIngo Weinhold
76224df6592SIngo Weinhold				// if all debugged teams are gone, we're done
76324df6592SIngo Weinhold				quitLoop = debuggedTeams.empty();
7640efd929eSAxel Dörfler				break;
76524df6592SIngo Weinhold			}
76639c9d198SIngo Weinhold		}
76739c9d198SIngo Weinhold
7680efd929eSAxel Dörfler		if (quitLoop)
7690efd929eSAxel Dörfler			break;
7700efd929eSAxel Dörfler
771ebac278fSIngo Weinhold		// tell the thread to continue (only when there is a thread and the
772ebac278fSIngo Weinhold		// message was synchronous)
7734dc355e9SRene Gollent		if (message.origin.thread >= 0 && message.origin.nub_port >= 0) {
7744dc355e9SRene Gollent			if (continue_thread(message.origin.nub_port,
7754dc355e9SRene Gollent					message.origin.thread) != B_OK) {
7764dc355e9SRene Gollent				exit(1);
7774dc355e9SRene Gollent			}
7784dc355e9SRene Gollent		}
77939c9d198SIngo Weinhold	}
78056805797SAxel Dörfler
781e69a3a86SAxel Dörfler	if (stats) {
782e69a3a86SAxel Dörfler		// Dump recorded statistics
783e69a3a86SAxel Dörfler		print_stats(outputFile);
784e69a3a86SAxel Dörfler	}
785e69a3a86SAxel Dörfler
78656805797SAxel Dörfler	if (outputFile != NULL && outputFile != stdout)
78756805797SAxel Dörfler		fclose(outputFile);
78856805797SAxel Dörfler
78939c9d198SIngo Weinhold	return 0;
79039c9d198SIngo Weinhold}
791