Browse Source

Plan 9 from Bell Labs 2010-10-05

David du Colombier 13 years ago
parent
commit
05680540d8

+ 1 - 0
lib/face/48x48x4/.dict

@@ -140,6 +140,7 @@ research.att.com/llc l/llc.1
 research.att.com/rsc r/rsc.1
 research.att.com/rvc r/rvc.1
 rs-components.com/unknown u/unknown.rs-components.com
+sandia.gov/rminnich r/rminnich.1
 snellwilcox.com/unknown u/unknown.snellwilcox.com
 spam.com/unknowm s/spam.1
 swtch.com/rsc r/rsc.1

+ 4 - 0
lib/ndb/common

@@ -236,6 +236,8 @@ tcp=guard port=566
 tcp=ticket port=567
 tcp=ldaps port=636
 tcp=fmclient port=729
+tcp=ftps-data port=989
+tcp=ftps port=990
 tcp=imaps port=993
 tcp=pop3s port=995
 tcp=ingreslock port=1524
@@ -298,6 +300,7 @@ udp=portmap port=111
 udp=ntp port=123
 udp=netbios-ns port=137
 udp=snmp port=161
+udp=ha port=434			# mobile ip home agent
 udp=ikev2 port=500
 udp=syslog port=514
 udp=rip port=520
@@ -326,6 +329,7 @@ gre=ppp port=34827
 # for geoff
 auth=www.9netics.com authdom=9netics.com
 auth=newcpu.9netics.net authdom=9netics.net
+auth=mordor.tip9ug.jp authdom=tip9ug.jp
 
 # for geoff's ipv6 testing
 auth=9grid.hamnavoe.com

+ 1 - 0
sys/games/lib/fortunes

@@ -4275,3 +4275,4 @@ As low as possible isn't a number yet - Ron Minnich
 Tip: Save time by hitting the return key instead of clicking on "search".
 what bug does this fix that you think you've fixed that addresses this particular bug?  - erik quanstrom
 With functional programming languages, you can never make small mistakes, only very large ones. - Kedar Namjoshi
+Subject: Departs: 7:00 PM Thu Dec 02 2010 Washington, DC - Union Station (WAS) Station News Arrives: 9:16 PM Thu Dec 02 2010 Metropark- Iselin, NJ  (MET) Metropark-Iselin, NJ Metropark-Iselin (MET) Station News PT2H16M Duration: 2 hr, 16 min (Internal Document ITD-10-49997V)

+ 2 - 0
sys/lib/tmac/tmac.srefs

@@ -22,6 +22,8 @@
 .if t .ds <. .
 .if n .ds >, ,
 .if t .ds <, ,
+.\" default separator for authors
+.ds [a ,
 .de [5 \" tm style
 .FS
 .IP "\\*([F.\0"

+ 57 - 0
sys/man/1/ratrace

@@ -0,0 +1,57 @@
+.TH RATRACE 1
+.SH NAME
+ratrace \- trace process system calls
+.SH SYNOPSIS
+.B ratrace
+[
+.I pid
+] | [
+.I -c command
+]
+.SH DESCRIPTION
+.I Ratrace
+shows the system calls executed by a process,
+either the one with
+.I pid
+or a fresh invocation of
+.IR command .
+.PP
+Trace output is determined by the kernel, not
+.IR ratrace .
+Certain fixed rules apply.
+The first four fields of the output are
+pid, text name, system call name, and the PC of the user program.
+Data is always printed as
+.IB pointer /\c
+"\fIstring\fP",
+where the
+.I string
+is the first 32 bytes of the data, with
+.L \&.
+replacing non-printing ASCII characters
+(printing characters are those between ASCII space (SP) and delete (DEL), exclusive).
+Return values follow an
+.LR = ,
+and include the integer return value,
+the
+.I errstr
+(with "" if there is no
+.IR errstr ),
+and
+the start and stop times for the system call in nanoseconds.
+The times are exclusive of the overhead for tracing.
+.SH FILES
+.BI /proc/ pid /syscalltrace
+.br
+.BI /proc/ pid /ctl
+.SH SOURCE
+.B /sys/src/cmd/ratrace.c
+.SH "SEE ALSO"
+.IR acid (1),
+.IR db (1),
+.IR proc (3)
+.SH BUGS
+The printing of the data is too limited in length;
+printing
+.L \&.
+instead of something more sensible is limiting.

+ 2 - 0
sys/src/9/kw/fns.h

@@ -70,6 +70,8 @@ void	procsave(Proc*);
 void	procsetup(Proc*);
 extern void _reset(void);
 extern void setr13(int, u32int*);
+extern void syscallfmt(int syscallno, ulong pc, va_list list);
+extern void sysretfmt(int syscallno, va_list list, long ret, uvlong start, uvlong stop);
 extern int tas(void *);
 extern u32int ttbget(void);
 extern void ttbput(u32int);

+ 1 - 0
sys/src/9/kw/mkfile

@@ -35,6 +35,7 @@ PORT=\
 	qlock.$O\
 	segment.$O\
 	swap.$O\
+	syscallfmt.$O\
 	sysfile.$O\
 	sysproc.$O\
 	taslock.$O\

+ 27 - 6
sys/src/9/kw/syscall.c

@@ -186,6 +186,7 @@ syscall(Ureg* ureg)
 	ulong sp;
 	long ret;
 	int i, scallnr;
+	vlong startns, stopns;
 
 	if(!userureg(ureg))
 		panic("syscall: from kernel: pc %#lux r14 %#lux psr %#lux",
@@ -198,20 +199,35 @@ syscall(Ureg* ureg)
 	up->pc = ureg->pc;
 	up->dbgreg = ureg;
 
-	if(up->procctl == Proc_tracesyscall){
-		up->procctl = Proc_stopme;
-		procctl(up);
-	}
-
 	scallnr = ureg->r0;
 	up->scallnr = scallnr;
 	if(scallnr == RFORK)
 		fpusysrfork(ureg);
 	spllo();
-
 	sp = ureg->sp;
+
+	if(up->procctl == Proc_tracesyscall){
+		/*
+		 * Redundant validaddr.  Do we care?
+		 * Tracing syscalls is not exactly a fast path...
+		 * Beware, validaddr currently does a pexit rather
+		 * than an error if there's a problem; that might
+		 * change in the future.
+		 */
+		if(sp < (USTKTOP-BY2PG) || sp > (USTKTOP-sizeof(Sargs)-BY2WD))
+			validaddr(sp, sizeof(Sargs)+BY2WD, 0);
+
+		syscallfmt(scallnr, ureg->pc, (va_list)(sp+BY2SE));
+		up->procctl = Proc_stopme;
+		procctl(up);
+		if (up->syscalltrace) 
+			free(up->syscalltrace);
+		up->syscalltrace = nil;
+	}
+
 	up->nerrlab = 0;
 	ret = -1;
+	startns = todget(nil);
 	if(!waserror()){
 		if(scallnr >= nsyscall){
 			pprint("bad sys call number %d pc %#lux\n",
@@ -253,10 +269,15 @@ syscall(Ureg* ureg)
 	ureg->r0 = ret;
 
 	if(up->procctl == Proc_tracesyscall){
+		stopns = todget(nil);
 		up->procctl = Proc_stopme;
+		sysretfmt(scallnr, (va_list)(sp+BY2SE), ret, startns, stopns);
 		s = splhi();
 		procctl(up);
 		splx(s);
+		if(up->syscalltrace)
+			free(up->syscalltrace);
+		up->syscalltrace = nil;
 	}
 
 	up->insyscall = 0;

+ 1 - 2
sys/src/9/pc/boot.fs

@@ -27,8 +27,7 @@ bind -a '#¤' /dev
 bind -a '#S' /dev
 bind -a '#k' /dev
 bind -a '#æ' /dev
-bind -a '#u' /dev	>[2]/dev/null
-bind -a '#U' /dev	>[2]/dev/null	# old usb implementation
+bind -a '#u' /dev
 bind '#p' /proc
 bind '#d' /fd
 bind -c '#s' /srv

+ 2 - 2
sys/src/9/pc/fns.h

@@ -151,8 +151,8 @@ void	realmode(Ureg*);
 void	screeninit(void);
 void	(*screenputs)(char*, int);
 void	syncclock(void);
-void	syscallprint(Ureg *ureg);
-void	syscallretprint(Ureg *ureg, int syscallno, uvlong start, uvlong stop);
+void	syscallfmt(int syscallno, ulong pc, va_list list);
+void	sysretfmt(int syscallno, va_list list, long ret, uvlong start, uvlong stop);
 void*	tmpmap(Page*);
 void	tmpunmap(void*);
 void	touser(void*);

+ 3 - 0
sys/src/9/pc/mem.h

@@ -2,6 +2,9 @@
  * Memory and machine-specific definitions.  Used in C and assembler.
  */
 
+#define MIN(a, b)	((a) < (b)? (a): (b))
+#define MAX(a, b)	((a) > (b)? (a): (b))
+
 /*
  * Sizes
  */

+ 0 - 347
sys/src/9/pc/syscallfmt.c

@@ -1,347 +0,0 @@
-/*
- * Print functions for system call tracing.
- *
- * TODO: pass ureg->usp and ureg->ax into common code.
- */
-#include "u.h"
-#include "ureg.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-
-#include "/sys/src/libc/9syscall/sys.h"
-
-extern char *sysctab[];
-
-extern	int	fmtstrinit(Fmt*);
-extern	char*	fmtstrflush(Fmt*);
-
-static void
-fmtrwdata(Fmt *f, ulong s, int n, char *suffix)
-{
-	char *t, *src;
-	int i;
-
-	if (!s) {
-		fmtprint(f, "0x0%s", suffix);
-		return;
-	}
-	src = (char*)s;
-	validaddr(s, n, 0);
-	t = smalloc(n+1);
-	for(i = 0; i < n; i++)
-		if(src[i] > 0x20 && src[i] < 0x7f)
-			t[i] = src[i];
-		else
-			t[i] = '.';
-
-	fmtprint(f, "%ulx/\"%s\"%s", s, t, suffix);
-	free(t);
-}
-
-static void
-fmtuserstring(Fmt *f, ulong s, char *suffix)
-{
-	char *es, *t, *src;
-	int n;
-
-	if (!s){
-		fmtprint(f, "0/\"\"%s", suffix);
-		return;
-	}
-	src = (char*)s;
-	validaddr(s, 1, 0);
-	es = vmemchr(src, 0, 1<<16);
-	n = es - src;
-	t = smalloc(n + 1);
-	memmove(t, src, n);
-	t[n] = 0;
-	fmtprint(f, "%#ulx/\"%s\"%s", s, t, suffix);
-	free(t);
-}
-
-void
-syscallprint(Ureg *ureg)
-{
-	ulong *sp;
-	int syscallno;
-	vlong offset;
-	Fmt fmt;
-	int len;
-	char* a;
-	char** argp;
-
-	sp = (ulong*)ureg->usp;
-	syscallno = ureg->ax;
-	offset = 0;
-	fmtstrinit(&fmt);
-	fmtprint(&fmt, "%ld %s ", up->pid, up->text);
-	/* accomodate process-private system calls */
-
-	if(syscallno > nsyscall)
-		fmtprint(&fmt, " %d %#lx ", syscallno, sp[0]);
-	else
-		fmtprint(&fmt, "%s %#ulx ", sysctab[syscallno], sp[0]);
-
-	if(up->syscalltrace)
-		free(up->syscalltrace);
-
-	switch(syscallno) {
-	case SYSR1:
-		fmtprint(&fmt, "%#ulx %#ulx %#ulx", sp[1], sp[2], sp[3]);
-		break;
-	case _ERRSTR:
-		fmtuserstring(&fmt, sp[1], "");
-		break;
-	case BIND:
-		fmtuserstring(&fmt, sp[1], " ");
-		fmtuserstring(&fmt, sp[2], " ");
-		fmtprint(&fmt, "%#ulx",  sp[3]);
-		break;
-	case CHDIR:
-		fmtuserstring(&fmt, sp[1], "");
-		break;
-	case CLOSE:
-		fmtprint(&fmt, "%ld", sp[1]);
-		break;
-	case DUP:
-		fmtprint(&fmt, "%#ulx %#ulx", sp[1], sp[2]);
-		break;
-	case ALARM:
-		fmtprint(&fmt, "%#ulx ", sp[1]);
-		break;
-	case EXEC:
-		fmtuserstring(&fmt, sp[1], "");
-		evenaddr(sp[2]);
-		argp = (char**)sp[2];
-		validaddr((ulong)argp, BY2WD, 0);
-		while(*argp){
-			a = *argp++;
-			if(((ulong)argp & (BY2PG-1)) < BY2WD)
-				validaddr((ulong)argp, BY2WD, 0);
-			if(a == 0)
-				break;
-			fmtprint(&fmt, " ");
-			fmtuserstring(&fmt, (ulong)a, "");
-		}
-		break;
-	case EXITS:
-		fmtuserstring(&fmt, sp[1], "");
-		break;
-	case _FSESSION:
-		fmtprint(&fmt, "%#ulx %#ulx %#ulx", sp[1], sp[2], sp[3]);
-		break;
-	case FAUTH:
-		fmtprint(&fmt, "%#ulx", sp[1]);
-		fmtuserstring(&fmt, sp[2], "");
-		break;
-	case _FSTAT:
-		fmtprint(&fmt, "%#ulx %#ulx %#ulx", sp[1], sp[2], sp[3]);
-		break;
-	case SEGBRK:
-		fmtprint(&fmt, "%#ulx %#ulx", sp[1], sp[2]);
-		break;
-	case _MOUNT:
-		fmtprint(&fmt, "%ld %ld ", sp[1], sp[2]);
-		fmtuserstring(&fmt, sp[3], " ");
-		fmtprint(&fmt, "%#ulx ", sp[4]);
-		fmtuserstring(&fmt, sp[5], "");
-		break;
-	case OPEN:
-		fmtuserstring(&fmt, sp[1], " ");
-		fmtprint(&fmt, "%#ulx", sp[2]);
-		break;
-	case OSEEK:
-		fmtprint(&fmt, "%#ulx %#ulx", sp[1], sp[2]);
-		break;
-	case SLEEP:
-		fmtprint(&fmt, "%ld", sp[1]);
-		break;
-	case _STAT:
-		fmtuserstring(&fmt, sp[1], " ");
-		fmtprint(&fmt, "%#ulx %ld", sp[2], sp[3]);
-		break;
-	case RFORK:
-		fmtprint(&fmt, "%#ulx", sp[1] );
-		break;
-	case PIPE:
-		break;
-	case CREATE:
-		fmtuserstring(&fmt, sp[1], " ");
-		fmtprint(&fmt, "%#ulx %#ulx", sp[2], sp[3]);
-		break;
-	case FD2PATH:
-		fmtprint(&fmt, "%ld ", sp[1]);
-		break;
-	case BRK_:
-		fmtprint(&fmt, "%#ulx %#ulx %#ulx", sp[1], sp[2], sp[3]);
-		break;
-	case REMOVE:
-		fmtuserstring(&fmt, sp[1], " ");
-		break;
-	/* deprecated */
-	case _WSTAT:
-		fmtprint(&fmt, "%#ulx %#ulx %#ulx", sp[1], sp[2], sp[3]);
-		break;
-	case _FWSTAT:
-		fmtprint(&fmt, "%#ulx %#ulx %#ulx", sp[1], sp[2], sp[3]);
-		break;
-	case NOTIFY:
-		fmtprint(&fmt, "%#ulx %#ulx %#ulx", sp[1], sp[2], sp[3]);
-		break;
-	case NOTED:
-		fmtprint(&fmt, "%#ulx %#ulx %#ulx", sp[1], sp[2], sp[3]);
-		break;
-	case SEGATTACH:
-		fmtprint(&fmt, "%#ulx %#ulx %#ulx", sp[1], sp[2], sp[3]);
-		break;
-	case SEGDETACH:
-		fmtprint(&fmt, "%#ulx %#ulx %#ulx", sp[1], sp[2], sp[3]);
-		break;
-	case SEGFREE:
-		fmtprint(&fmt, "%#ulx %#ulx %#ulx", sp[1], sp[2], sp[3]);
-		break;
-	case SEGFLUSH:
-		fmtprint(&fmt, "%#ulx %#ulx %#ulx", sp[1], sp[2], sp[3]);
-		break;
-	case RENDEZVOUS:
-		fmtprint(&fmt, "%#ulx %#ulx %#ulx", sp[1], sp[2], sp[3]);
-		break;
-	case UNMOUNT:
-		fmtuserstring(&fmt, sp[1], " ");
-		break;
-	case _WAIT:
-		fmtprint(&fmt, "%#ulx %#ulx %#ulx", sp[1], sp[2], sp[3]);
-		break;
-	case SEMACQUIRE:
-		fmtprint(&fmt, "%#ulx %#ulx %ld", sp[1], sp[2], sp[3]);
-		break;
-	case SEMRELEASE:
-		fmtprint(&fmt, "%#ulx %#ulx %ld", sp[1], sp[2], sp[3]);
-		break;
-	case SEEK:
-		fmtprint(&fmt, "%#ulx %#ullx %#ulx", sp[1], *(vlong *)&sp[2], sp[4]);
-		break;
-	case FVERSION:
-		fmtprint(&fmt, "%#ulx %#ulx ", sp[1], sp[2]);
-		fmtuserstring(&fmt, sp[5], "");
-		break;
-	case ERRSTR:
-		fmtprint(&fmt, "%#ulx/", sp[1]);
-		break;
-	case WSTAT:
-	case STAT:
-		fmtprint(&fmt, "%#ulx ", sp[1]);
-		fmtuserstring(&fmt, sp[2], " ");
-		fmtprint(&fmt, "%#ulx", sp[3]);
-		break;
-	case FSTAT:
-	case FWSTAT:
-		fmtprint(&fmt, "%#ulx %#ulx %#ulx", sp[1], sp[2], sp[3]);
-		break;
-	case MOUNT:
-		fmtprint(&fmt, "%ld %ld ", sp[1], sp[3]);
-		fmtuserstring(&fmt, sp[3], " ");
-		fmtprint(&fmt, "%#ulx", sp[4]);
-		fmtuserstring(&fmt, sp[5], "");
-		break;
-	case AWAIT:
-		break;
-	case _READ:
-	case PREAD:
-		fmtprint(&fmt, "%ld ", sp[1]);
-		break;
-	case _WRITE:
-		offset = -1;
-		/* fall through */
-	case PWRITE:
-		fmtprint(&fmt, "%ld ", sp[1]);
-		if (sp[3] < 64)
-			len = sp[3];
-		else
-			len = 64;
-		fmtrwdata(&fmt, sp[2], len, " ");
-		if(!offset)
-			offset = *(vlong *)&sp[4];
-		fmtprint(&fmt, "%ld %#llx", sp[3], offset);
-		break;
-	}
-	up->syscalltrace = fmtstrflush(&fmt);
-}
-
-void
-syscallretprint(Ureg *ureg, int syscallno, uvlong start, uvlong stop)
-{
-	int errstrlen, len;
-	vlong offset;
-	char *errstr;
-	Fmt fmt;
-
-	fmtstrinit(&fmt);
-	errstrlen = 0;
-	offset = 0;
-	if (ureg->ax != -1)
-		errstr = "\"\"";
-	else
-		errstr = up->errstr;
-
-	if(up->syscalltrace)
-		free(up->syscalltrace);
-
-	switch(syscallno) {
-	case AWAIT:
-		if(ureg->ax > 0){
-			fmtuserstring(&fmt, up->s.args[0], " ");
-			fmtprint(&fmt, "%ld", up->s.args[1]);
-		} else
-			fmtprint(&fmt, "%#ulx/\"\" %ld", up->s.args[0],
-				up->s.args[1]);
-		break;
-	case _ERRSTR:
-		errstrlen = 64;
-	case ERRSTR:
-		if(!errstrlen)
-			errstrlen = up->s.args[1];
-		if(ureg->ax > 0){
-			fmtuserstring(&fmt, up->s.args[0], " ");
-			fmtprint(&fmt, "%d", errstrlen);
-		} else
-			fmtprint(&fmt, "\"\" %d", errstrlen);
-		break;
-	case FD2PATH:
-		if(ureg->ax == -1)
-			fmtprint(&fmt, "\"\" %ld", up->s.args[2]);
-		else {
-			fmtuserstring(&fmt, up->s.args[1], " ");
-			fmtprint(&fmt, "%d", errstrlen);
-		}
-		break;
-	case _READ:
-		offset = -1;
-		/* fall through */
-	case PREAD:
-		if(ureg->ax == -1)
-			fmtprint(&fmt, "/\"\" %ld 0x%ullx", up->s.args[2],
-				*(vlong *)&up->s.args[3]);
-		else {
-			if (ureg->ax > 64)
-				len = 64;
-			else
-				len = ureg->ax;
-			fmtrwdata(&fmt, up->s.args[1], len, " ");
-			if(!offset)
-				offset = *(vlong *)&up->s.args[3];
-			fmtprint(&fmt, "%ld %#llx", up->s.args[2], offset);
-		}
-		break;
-	}
-	if(syscallno == EXEC)
-		fmtprint(&fmt, " = %p %s %#ullx %#ullx\n", ureg->ax,
-			errstr, start, stop);
-	else
-		fmtprint(&fmt, " = %ld %s %#ullx %#ullx\n", ureg->ax,
-			errstr, start, stop);
-
-	up->syscalltrace = fmtstrflush(&fmt);
-}

+ 27 - 16
sys/src/9/pc/trap.c

@@ -85,7 +85,7 @@ intrdisable(int irq, void (*f)(Ureg *, void *), void *a, int tbdf, char *name)
 	vno = arch->intrvecno(irq);
 	ilock(&vctllock);
 	pv = &vctl[vno];
-	while (*pv && 
+	while (*pv &&
 		  ((*pv)->irq != irq || (*pv)->tbdf != tbdf || (*pv)->f != f || (*pv)->a != a ||
 		   strcmp((*pv)->name, name)))
 		pv = &((*pv)->next);
@@ -93,7 +93,7 @@ intrdisable(int irq, void (*f)(Ureg *, void *), void *a, int tbdf, char *name)
 
 	v = *pv;
 	*pv = (*pv)->next;	/* Link out the entry */
-	
+
 	if(vctl[vno] == nil && arch->intrdisable != nil)
 		arch->intrdisable(irq);
 	iunlock(&vctllock);
@@ -134,7 +134,7 @@ irqallocread(Chan*, void *vbuf, long n, vlong offset)
 
 				if(n == 0)
 					return oldn;
-			}	
+			}
 		}
 	}
 	return oldn - n;
@@ -179,7 +179,7 @@ nmienable(void)
 
 /*
  * Minimal trap setup.  Just enough so that we can panic
- * on traps (bugs) during kernel initialization.  
+ * on traps (bugs) during kernel initialization.
  * Called very early - malloc is not yet available.
  */
 void
@@ -664,7 +664,7 @@ syscall(Ureg* ureg)
 	long	ret;
 	int	i, s;
 	ulong scallnr;
-	vlong startnsec, stopnsec;
+	vlong startns, stopns;
 
 	if((ureg->cs & 0xFFFF) != UESEL)
 		panic("syscall: cs 0x%4.4luX", ureg->cs);
@@ -676,25 +676,36 @@ syscall(Ureg* ureg)
 	up->pc = ureg->pc;
 	up->dbgreg = ureg;
 
+	sp = ureg->usp;
+	scallnr = ureg->ax;
+	up->scallnr = scallnr;
+
 	if(up->procctl == Proc_tracesyscall){
+		/*
+		 * Redundant validaddr.  Do we care?
+		 * Tracing syscalls is not exactly a fast path...
+		 * Beware, validaddr currently does a pexit rather
+		 * than an error if there's a problem; that might
+		 * change in the future.
+		 */
+		if(sp < (USTKTOP-BY2PG) || sp > (USTKTOP-sizeof(Sargs)-BY2WD))
+			validaddr(sp, sizeof(Sargs)+BY2WD, 0);
+
+		syscallfmt(scallnr, ureg->pc, (va_list)(sp+BY2WD));
 		up->procctl = Proc_stopme;
-		syscallprint(ureg);
 		procctl(up);
 		if(up->syscalltrace)
 			free(up->syscalltrace);
 		up->syscalltrace = nil;
-		startnsec = todget(nil);
+		startns = todget(nil);
 	}
 
-	scallnr = ureg->ax;
-	up->scallnr = scallnr;
 	if(scallnr == RFORK && up->fpstate == FPactive){
 		fpsave(&up->fpsave);
 		up->fpstate = FPinactive;
 	}
 	spllo();
 
-	sp = ureg->usp;
 	up->nerrlab = 0;
 	ret = -1;
 	if(!waserror()){
@@ -738,9 +749,9 @@ syscall(Ureg* ureg)
 	ureg->ax = ret;
 
 	if(up->procctl == Proc_tracesyscall){
-		stopnsec = todget(nil);
+		stopns = todget(nil);
 		up->procctl = Proc_stopme;
-		syscallretprint(ureg, scallnr, startnsec, stopnsec);
+		sysretfmt(scallnr, (va_list)(sp+BY2WD), ret, startns, stopns);
 		s = splhi();
 		procctl(up);
 		splx(s);
@@ -818,7 +829,7 @@ notify(Ureg* ureg)
 	sp = ureg->usp;
 	sp -= 256;	/* debugging: preserve context causing problem */
 	sp -= sizeof(Ureg);
-if(0) print("%s %lud: notify %.8lux %.8lux %.8lux %s\n", 
+if(0) print("%s %lud: notify %.8lux %.8lux %.8lux %s\n",
 	up->text, up->pid, ureg->pc, ureg->usp, sp, n->msg);
 
 	if(!okaddr((ulong)up->notify, 1, 0)
@@ -901,7 +912,7 @@ noted(Ureg* ureg, ulong arg0)
 	switch(arg0){
 	case NCONT:
 	case NRSTR:
-if(0) print("%s %lud: noted %.8lux %.8lux\n", 
+if(0) print("%s %lud: noted %.8lux %.8lux\n",
 	up->text, up->pid, nureg->pc, nureg->usp);
 		if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->usp, BY2WD, 0)){
 			qunlock(&up->debug);
@@ -931,9 +942,9 @@ if(0) print("%s %lud: noted %.8lux %.8lux\n",
 		pprint("unknown noted arg 0x%lux\n", arg0);
 		up->lastnote.flag = NDebug;
 		/* fall through */
-		
+
 	case NDFLT:
-		if(up->lastnote.flag == NDebug){ 
+		if(up->lastnote.flag == NDebug){
 			qunlock(&up->debug);
 			pprint("suicide: %s\n", up->lastnote.msg);
 		} else

+ 3 - 2
sys/src/9/port/devcons.c

@@ -936,9 +936,10 @@ consread(Chan *c, void *buf, long n, vlong off)
 		b = malloc(READSTR);
 		if(b == nil)
 			error(Enomem);
-		n = 0;
+		k = 0;
 		for(i = 0; devtab[i] != nil; i++)
-			n += snprint(b+n, READSTR-n, "#%C %s\n", devtab[i]->dc,  devtab[i]->name);
+			k += snprint(b+k, READSTR-k, "#%C %s\n",
+				devtab[i]->dc, devtab[i]->name);
 		if(waserror()){
 			free(b);
 			nexterror();

+ 2 - 0
sys/src/9/port/lib.h

@@ -109,10 +109,12 @@ extern	int	sprint(char*, char*, ...);
 #pragma	varargck	type	"p"	void*
 #pragma	varargck	flag	','
 
+extern	int	fmtstrinit(Fmt*);
 extern	int	fmtinstall(int, int (*)(Fmt*));
 extern	void	quotefmtinstall(void);
 extern	int	fmtprint(Fmt*, char*, ...);
 extern	int	fmtstrcpy(Fmt*, char*);
+extern	char*	fmtstrflush(Fmt*);
 
 /*
  * one-of-a-kind

+ 405 - 0
sys/src/9/port/syscallfmt.c

@@ -0,0 +1,405 @@
+/*
+ * Print functions for system call tracing.
+ */
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+
+#include "/sys/src/libc/9syscall/sys.h"
+
+// WE ARE OVERRUNNING SOMEHOW
+static void
+fmtrwdata(Fmt* f, char* a, int n, char* suffix)
+{
+	int i;
+	char *t;
+
+	if(a == nil){
+		fmtprint(f, "0x0%s", suffix);
+		return;
+	}
+	validaddr((ulong)a, n, 0);
+	t = smalloc(n+1);
+	for(i = 0; i < n; i++)
+		if(a[i] > 0x20 && a[i] < 0x7f)	/* printable ascii? */
+			t[i] = a[i];
+		else
+			t[i] = '.';
+
+	fmtprint(f, " %#p/\"%s\"%s", a, t, suffix);
+	free(t);
+}
+
+static void
+fmtuserstring(Fmt* f, char* a, char* suffix)
+{
+	int n;
+	char *t;
+
+	if(a == nil){
+		fmtprint(f, "0/\"\"%s", suffix);
+		return;
+	}
+	validaddr((ulong)a, 1, 0);
+	n = ((char*)vmemchr(a, 0, 0x7fffffff) - a) + 1;
+	t = smalloc(n+1);
+	memmove(t, a, n);
+	t[n] = 0;
+	fmtprint(f, "%#p/\"%s\"%s", a, t, suffix);
+	free(t);
+}
+
+void
+syscallfmt(int syscallno, ulong pc, va_list list)
+{
+	long l;
+	Fmt fmt;
+	void *v;
+	vlong vl;
+	uintptr p;
+	int i[2], len;
+	char *a, **argv;
+
+	fmtstrinit(&fmt);
+	fmtprint(&fmt, "%uld %s ", up->pid, up->text);
+
+	if(syscallno > nsyscall)
+		fmtprint(&fmt, " %d ", syscallno);
+	else
+		fmtprint(&fmt, "%s ", sysctab[syscallno]?
+			sysctab[syscallno]: "huh?");
+
+	fmtprint(&fmt, "%ulx ", pc);
+	if(up->syscalltrace != nil)
+		free(up->syscalltrace);
+
+	switch(syscallno){
+	case SYSR1:
+		p = va_arg(list, uintptr);
+		fmtprint(&fmt, "%#p", p);
+		break;
+	case _ERRSTR:					/* deprecated */
+	case CHDIR:
+	case EXITS:
+	case REMOVE:
+		a = va_arg(list, char*);
+		fmtuserstring(&fmt, a, "");
+		break;
+	case BIND:
+		a = va_arg(list, char*);
+		fmtuserstring(&fmt, a, " ");
+		a = va_arg(list, char*);
+		fmtuserstring(&fmt, a, " ");
+		i[0] = va_arg(list, int);
+		fmtprint(&fmt, "%#ux",  i[0]);
+		break;
+	case CLOSE:
+	case NOTED:
+		i[0] = va_arg(list, int);
+		fmtprint(&fmt, "%d", i[0]);
+		break;
+	case DUP:
+		i[0] = va_arg(list, int);
+		i[1] = va_arg(list, int);
+		fmtprint(&fmt, "%d %d", i[0], i[1]);
+		break;
+	case ALARM:
+		l = va_arg(list, unsigned long);
+		fmtprint(&fmt, "%#lud ", l);
+		break;
+	case EXEC:
+		a = va_arg(list, char*);
+		fmtuserstring(&fmt, a, "");
+		argv = va_arg(list, char**);
+		evenaddr(PTR2UINT(argv));
+		for(;;){
+			validaddr((ulong)argv, sizeof(char**), 0);
+			a = *(char **)argv;
+			if(a == nil)
+				break;
+			fmtprint(&fmt, " ");
+			fmtuserstring(&fmt, a, "");
+			argv++;
+		}
+		break;
+	case _FSESSION:					/* deprecated */
+	case _FSTAT:					/* deprecated */
+	case _FWSTAT:					/* obsolete */
+		i[0] = va_arg(list, int);
+		a = va_arg(list, char*);
+		fmtprint(&fmt, "%d %#p", i[0], a);
+		break;
+	case FAUTH:
+		i[0] = va_arg(list, int);
+		a = va_arg(list, char*);
+		fmtprint(&fmt, "%d", i[0]);
+		fmtuserstring(&fmt, a, "");
+		break;
+	case SEGBRK:
+	case RENDEZVOUS:
+		v = va_arg(list, void*);
+		fmtprint(&fmt, "%#p ", v);
+		v = va_arg(list, void*);
+		fmtprint(&fmt, "%#p", v);
+		break;
+	case _MOUNT:					/* deprecated */
+		i[0] = va_arg(list, int);
+		fmtprint(&fmt, "%d ", i[0]);
+		a = va_arg(list, char*);
+		fmtuserstring(&fmt, a, " ");
+		i[0] = va_arg(list, int);
+		fmtprint(&fmt, "%#ux ", i[0]);
+		a = va_arg(list, char*);
+		fmtuserstring(&fmt, a, "");
+		break;
+	case OPEN:
+		a = va_arg(list, char*);
+		fmtuserstring(&fmt, a, " ");
+		i[0] = va_arg(list, int);
+		fmtprint(&fmt, "%#ux", i[0]);
+		break;
+	case OSEEK:					/* deprecated */
+		i[0] = va_arg(list, int);
+		l = va_arg(list, long);
+		i[1] = va_arg(list, int);
+		fmtprint(&fmt, "%d %ld %d", i[0], l, i[1]);
+		break;
+	case SLEEP:
+		l = va_arg(list, long);
+		fmtprint(&fmt, "%ld", l);
+		break;
+	case _STAT:					/* obsolete */
+	case _WSTAT:					/* obsolete */
+		a = va_arg(list, char*);
+		fmtuserstring(&fmt, a, " ");
+		a = va_arg(list, char*);
+		fmtprint(&fmt, "%#p", a);
+		break;
+	case RFORK:
+		i[0] = va_arg(list, int);
+		fmtprint(&fmt, "%#ux", i[0]);
+		break;
+	case PIPE:
+	case BRK_:
+		v = va_arg(list, int*);
+		fmtprint(&fmt, "%#p", v);
+		break;
+	case CREATE:
+		a = va_arg(list, char*);
+		fmtuserstring(&fmt, a, " ");
+		i[0] = va_arg(list, int);
+		i[1] = va_arg(list, int);
+		fmtprint(&fmt, "%#ux %#ux", i[0], i[1]);
+		break;
+	case FD2PATH:
+	case FSTAT:
+	case FWSTAT:
+		i[0] = va_arg(list, int);
+		a = va_arg(list, char*);
+		l = va_arg(list, unsigned long);
+		fmtprint(&fmt, "%d %#p %lud", i[0], a, l);
+		break;
+	case NOTIFY:
+	case SEGDETACH:
+	case _WAIT:					/* deprecated */
+		v = va_arg(list, void*);
+		fmtprint(&fmt, "%#p", v);
+		break;
+	case SEGATTACH:
+		i[0] = va_arg(list, int);
+		fmtprint(&fmt, "%d ", i[0]);
+		a = va_arg(list, char*);
+		fmtuserstring(&fmt, a, " ");
+		/*FALLTHROUGH*/
+	case SEGFREE:
+	case SEGFLUSH:
+		v = va_arg(list, void*);
+		l = va_arg(list, unsigned long);
+		fmtprint(&fmt, "%#p %lud", v, l);
+		break;
+	case UNMOUNT:
+		a = va_arg(list, char*);
+		fmtuserstring(&fmt, a, " ");
+		a = va_arg(list, char*);
+		fmtuserstring(&fmt, a, "");
+		break;
+	case SEMACQUIRE:
+	case SEMRELEASE:
+		v = va_arg(list, int*);
+		i[0] = va_arg(list, int);
+		fmtprint(&fmt, "%#p %d", v, i[0]);
+		break;
+	case SEEK:
+		v = va_arg(list, vlong*);
+		i[0] = va_arg(list, int);
+		vl = va_arg(list, vlong);
+		i[1] = va_arg(list, int);
+		fmtprint(&fmt, "%#p %d %#llux %d", v, i[0], vl, i[1]);
+		break;
+	case FVERSION:
+		i[0] = va_arg(list, int);
+		i[1] = va_arg(list, int);
+		fmtprint(&fmt, "%d %d ", i[0], i[1]);
+		a = va_arg(list, char*);
+		fmtuserstring(&fmt, a, " ");
+		l = va_arg(list, unsigned long);
+		fmtprint(&fmt, "%lud", l);
+		break;
+	case WSTAT:
+	case STAT:
+		a = va_arg(list, char*);
+		fmtuserstring(&fmt, a, " ");
+		/*FALLTHROUGH*/
+	case ERRSTR:
+	case AWAIT:
+		a = va_arg(list, char*);
+		l = va_arg(list, unsigned long);
+		fmtprint(&fmt, "%#p %lud", a, l);
+		break;
+	case MOUNT:
+		i[0] = va_arg(list, int);
+		i[1] = va_arg(list, int);
+		fmtprint(&fmt, "%d %d ", i[0], i[1]);
+		a = va_arg(list, char*);
+		fmtuserstring(&fmt, a, " ");
+		i[0] = va_arg(list, int);
+		fmtprint(&fmt, "%#ux ", i[0]);
+		a = va_arg(list, char*);
+		fmtuserstring(&fmt, a, "");
+		break;
+	case _READ:					/* deprecated */
+	case PREAD:
+		i[0] = va_arg(list, int);
+		v = va_arg(list, void*);
+		l = va_arg(list, long);
+		fmtprint(&fmt, "%d %#p %ld", i[0], v, l);
+		if(syscallno == PREAD){
+			vl = va_arg(list, vlong);
+			fmtprint(&fmt, " %lld", vl);
+		}
+		break;
+	case _WRITE:					/* deprecated */
+	case PWRITE:
+		i[0] = va_arg(list, int);
+		v = va_arg(list, void*);
+		l = va_arg(list, long);
+		fmtprint(&fmt, "%d ", i[0]);
+		len = MIN(l, 64);
+		fmtrwdata(&fmt, v, len, " ");
+		fmtprint(&fmt, "%ld", l);
+		if(syscallno == PWRITE){
+			vl = va_arg(list, vlong);
+			fmtprint(&fmt, " %lld", vl);
+		}
+		break;
+	}
+
+	up->syscalltrace = fmtstrflush(&fmt);
+}
+
+void
+sysretfmt(int syscallno, va_list list, long ret, uvlong start, uvlong stop)
+{
+	long l;
+	void* v;
+	Fmt fmt;
+	vlong vl;
+	int i, len;
+	char *a, *errstr;
+
+	fmtstrinit(&fmt);
+
+	if(up->syscalltrace)
+		free(up->syscalltrace);
+
+	errstr = "\"\"";
+	switch(syscallno){
+	default:
+		if(ret == -1)
+			errstr = up->errstr;
+		fmtprint(&fmt, " = %ld", ret);
+		break;
+	case ALARM:
+	case _WRITE:
+	case PWRITE:
+		if(ret == -1)
+			errstr = up->errstr;
+		fmtprint(&fmt, " = %ld", ret);
+		break;
+	case EXEC:
+	case SEGBRK:
+	case SEGATTACH:
+	case RENDEZVOUS:
+		if((void *)ret == (void*)-1)
+			errstr = up->errstr;
+		fmtprint(&fmt, " = %#p", (void *)ret);
+		break;
+	case AWAIT:
+		a = va_arg(list, char*);
+		l = va_arg(list, unsigned long);
+		if(ret > 0){
+			fmtuserstring(&fmt, a, " ");
+			fmtprint(&fmt, "%lud = %ld", l, ret);
+		}
+		else{
+			fmtprint(&fmt, "%#p/\"\" %lud = %ld", a, l, ret);
+			errstr = up->errstr;
+		}
+		break;
+	case _ERRSTR:
+	case ERRSTR:
+		a = va_arg(list, char*);
+		if(syscallno == _ERRSTR)
+			l = 64;
+		else
+			l = va_arg(list, unsigned long);
+		if(ret > 0){
+			fmtuserstring(&fmt, a, " ");
+			fmtprint(&fmt, "%lud = %ld", l, ret);
+		}
+		else{
+			fmtprint(&fmt, "\"\" %lud = %ld", l, ret);
+			errstr = up->errstr;
+		}
+		break;
+	case FD2PATH:
+		i = va_arg(list, int);
+		USED(i);
+		a = va_arg(list, char*);
+		l = va_arg(list, unsigned long);
+		if(ret > 0){
+			fmtuserstring(&fmt, a, " ");
+			fmtprint(&fmt, "%lud = %ld", l, ret);
+		}
+		else{
+			fmtprint(&fmt, "\"\" %lud = %ld", l, ret);
+			errstr = up->errstr;
+		}
+		break;
+	case _READ:
+	case PREAD:
+		i = va_arg(list, int);
+		USED(i);
+		v = va_arg(list, void*);
+		l = va_arg(list, long);
+		if(ret > 0){
+			len = MIN(ret, 64);
+			fmtrwdata(&fmt, v, len, "");
+		}
+		else{
+			fmtprint(&fmt, "/\"\"");
+			errstr = up->errstr;
+		}
+		fmtprint(&fmt, " %ld", l);
+		if(syscallno == PREAD){
+			vl = va_arg(list, vlong);
+			fmtprint(&fmt, " %lld", vl);
+		}
+		fmtprint(&fmt, " = %ld", ret);
+		break;
+	}
+	fmtprint(&fmt, " %s %#llud %#llud\n", errstr, start, stop);
+	up->syscalltrace = fmtstrflush(&fmt);
+}

+ 1 - 2
sys/src/boot/pc/load.c

@@ -395,7 +395,6 @@ main(void)
 	mode = Mauto;
 
 	p = getconf("bootfile");
-
 	if(p != 0) {
 		mode = Manual;
 		for(i = 0; i < NMode; i++){
@@ -427,7 +426,7 @@ done:
 		print("end final probe\n");
 
 	if(p = getconf("bootdef"))
-		strcpy(def, p);
+		strncpy(def, p, sizeof def);
 
 	/* print possible boot methods */
 	flag = 0;

+ 9 - 17
sys/src/cmd/ndb/dnsquery.c

@@ -21,24 +21,16 @@ setup(int argc, char **argv)
 
 	fd = open(dns, ORDWR);
 	if(fd < 0){
-		if(domount == 0){
-			fprint(2, "can't open %s: %r\n", mtpt);
-			exits(0);
-		}
+		if(domount == 0)
+			sysfatal("can't open %s: %r", dns);
 		fd = open(srv, ORDWR);
-		if(fd < 0){
-			print("can't open %s: %r\n", srv);
-			exits(0);
-		}
-		if(mount(fd, -1, mtpt, MBEFORE, "") < 0){
-			print("can't mount(%s, %s): %r\n", srv, mtpt);
-			exits(0);
-		}
-		fd = open(mtpt, ORDWR);
-		if(fd < 0){
-			print("can't open %s: %r\n", mtpt);
-			exits(0);
-		}
+		if(fd < 0)
+			sysfatal("can't open %s: %r", srv);
+		if(mount(fd, -1, mtpt, MBEFORE, "") < 0)
+			sysfatal("can't mount(%s, %s): %r", srv, mtpt);
+		fd = open(dns, ORDWR);
+		if(fd < 0)
+			sysfatal("can't open %s: %r", dns);
 	}
 	return fd;
 }

+ 189 - 0
sys/src/cmd/ratrace.c

@@ -0,0 +1,189 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <thread.h>
+
+enum {
+	Stacksize	= 8*1024,
+	Bufsize		= 8*1024,
+};
+
+Channel *out;
+Channel *quit;
+Channel *forkc;
+int nread = 0;
+
+typedef struct Str Str;
+struct Str {
+	char	*buf;
+	int	len;
+};
+
+void
+die(char *s)
+{
+	fprint(2, "%s\n", s);
+	exits(s);
+}
+
+void
+cwrite(int fd, char *path, char *cmd, int len)
+{
+	if (write(fd, cmd, len) < len) {
+		fprint(2, "cwrite: %s: failed %d bytes: %r\n", path, len);
+		sendp(quit, nil);
+		threadexits(nil);
+	}
+}
+
+void
+reader(void *v)
+{
+	int cfd, tfd, forking = 0, pid, newpid;
+	char *ctl, *truss;
+	Str *s;
+
+	pid = (int)(uintptr)v;
+	ctl = smprint("/proc/%d/ctl", pid);
+	if ((cfd = open(ctl, OWRITE)) < 0)
+		die(smprint("%s: %r", ctl));
+	truss = smprint("/proc/%d/syscall", pid);
+	if ((tfd = open(truss, OREAD)) < 0)
+		die(smprint("%s: %r", truss));
+
+	cwrite(cfd, ctl, "stop", 4);
+	cwrite(cfd, truss, "startsyscall", 12);
+
+	s = mallocz(sizeof(Str) + Bufsize, 1);
+	s->buf = (char *)&s[1];
+	while((s->len = pread(tfd, s->buf, Bufsize - 1, 0)) > 0){
+		if (forking && s->buf[1] == '=' && s->buf[3] != '-') {
+			forking = 0;
+			newpid = strtol(&s->buf[3], 0, 0);
+			sendp(forkc, (void*)newpid);
+			procrfork(reader, (void*)newpid, Stacksize, 0);
+		}
+
+		/*
+		 * There are three tests here and they (I hope) guarantee
+		 * no false positives.
+		 */
+		if (strstr(s->buf, " Rfork") != nil) {
+			char *a[8];
+			char *rf;
+
+			rf = strdup(s->buf);
+         		if (tokenize(rf, a, 8) == 5) {
+				ulong flags;
+
+				flags = strtoul(a[4], 0, 16);
+				if (flags & RFPROC)
+					forking = 1;
+			}
+			free(rf);
+		}
+		sendp(out, s);
+		cwrite(cfd, truss, "startsyscall", 12);
+		s = mallocz(sizeof(Str) + Bufsize, 1);
+		s->buf = (char *)&s[1];
+	}
+	sendp(quit, nil);
+	threadexitsall(nil);
+}
+
+void
+writer(void *)
+{
+	int newpid;
+	Alt a[4];
+	Str *s;
+
+	a[0].op = CHANRCV;
+	a[0].c = quit;
+	a[0].v = nil;
+	a[1].op = CHANRCV;
+	a[1].c = out;
+	a[1].v = &s;
+	a[2].op = CHANRCV;
+	a[2].c = forkc;
+	a[2].v = &newpid;
+	a[3].op = CHANEND;
+
+	for(;;)
+		switch(alt(a)){
+		case 0:
+			nread--;
+			if(nread <= 0)
+				goto done;
+			break;
+		case 1:
+			/* it's a nice null terminated thing */
+			fprint(2, "%s", s->buf);
+			free(s);
+			break;
+		case 2:
+			// procrfork(reader, (void*)newpid, Stacksize, 0);
+			nread++;
+			break;
+		}
+done:
+	exits(nil);
+}
+
+void
+usage(void)
+{
+	fprint(2, "Usage: ratrace [-c cmd [arg...]] | [pid]\n");
+	exits("usage");
+}
+
+void
+threadmain(int argc, char **argv)
+{
+	int pid;
+	char *cmd = nil;
+	char **args = nil;
+
+	/*
+	 * don't bother with fancy arg processing, because it picks up options
+	 * for the command you are starting.  Just check for -c as argv[1]
+	 * and then take it from there.
+	 */
+	if (argc < 2)
+		usage();
+	if (argv[1][0] == '-')
+		switch(argv[1][1]) {
+		case 'c':
+			if (argc < 3)
+				usage();
+			cmd = strdup(argv[2]);
+			args = &argv[2];
+			break;
+		default:
+			usage();
+		}
+
+	/* run a command? */
+	if(cmd) {
+		pid = fork();
+		if (pid < 0)
+			sysfatal("fork failed: %r");
+		if(pid == 0) {
+			exec(cmd, args);
+			if(cmd[0] != '/')
+				exec(smprint("/bin/%s", cmd), args);
+			sysfatal("exec %s failed: %r", cmd);
+		}
+	} else {
+		if(argc != 2)
+			usage();
+		pid = atoi(argv[1]);
+	}
+
+	out   = chancreate(sizeof(char*), 0);
+	quit  = chancreate(sizeof(char*), 0);
+	forkc = chancreate(sizeof(ulong *), 0);
+	nread++;
+	procrfork(writer, nil, Stacksize, 0);
+	reader((void*)pid);
+}