[PATCH] more robustness against ptrace errors

Denys Vlasenko dvlasenk at redhat.com
Fri Feb 13 10:37:07 UTC 2009


Hi,

this patch is not yet in cvs.

It replaces many more bare ptrace calls with calls to wrappers
which do proper error-checking and set tcp->ptrace_errno.
Incidentally, it makes many callsites simpler:

-	ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOP);
-	if (errno) {
-		perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
+	if (do_ptrace(PTRACE_POKETEXT, tcp, (char *) tcp->baddr, LOOP, "POKETEXT") < 0) {
 		return -1;
 	}

In some cases, missing error checking is added.

Error handling for trace_syscall() failures and other cases
where tcp->ptrace_errno is nonzero is cleaned up a bit
and made more verbose if we see error other than ESRC.

Some comments are added or expanded.

test/sigkill_rain.c testcase is a good example how to trigger
this code en masse.

Please review.
--
vda


diff -d -urpN strace.1/defs.h strace.2/defs.h
--- strace.1/defs.h	2009-02-10 15:25:50.000000000 +0100
+++ strace.2/defs.h	2009-02-13 11:17:55.000000000 +0100
@@ -485,7 +485,7 @@ extern void set_overhead P((int));
 extern void qualify P((char *));
 extern int get_scno P((struct tcb *));
 extern long known_scno P((struct tcb *));
-extern long do_ptrace P((int request, struct tcb *tcp, void *addr, void *data));
+extern long do_ptrace P((int request, struct tcb *tcp, void *addr, long data, const char *msg));
 extern int ptrace_restart P((int request, struct tcb *tcp, int sig));
 extern int trace_syscall P((struct tcb *));
 extern int count_syscall P((struct tcb *, struct timeval *));
diff -d -urpN strace.1/process.c strace.2/process.c
--- strace.1/process.c	2009-02-10 15:55:29.000000000 +0100
+++ strace.2/process.c	2009-02-13 11:17:55.000000000 +0100
@@ -771,7 +771,7 @@ change_syscall(struct tcb *tcp, int new)
 #  define PTRACE_SET_SYSCALL 23
 # endif
 
-	if (ptrace (PTRACE_SET_SYSCALL, tcp->pid, 0, new) != 0)
+	if (do_ptrace(PTRACE_SET_SYSCALL, tcp, NULL, new, "SET_SYSCALL") != 0)
 		return -1;
 
 	return 0;
diff -d -urpN strace.1/signal.c strace.2/signal.c
--- strace.1/signal.c	2009-01-13 19:30:55.000000000 +0100
+++ strace.2/signal.c	2009-02-13 11:17:55.000000000 +0100
@@ -1409,14 +1409,13 @@ struct tcb *tcp;
 	struct regs regs;
 	m_siginfo_t si;
 
-	if(ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
-		perror("sigreturn: PTRACE_GETREGS ");
+	if (do_ptrace(PTRACE_GETREGS, tcp, (char *)&regs, 0, "GETREGS") < 0) {
 		return 0;
 	}
-	if(entering(tcp)) {
+	if (entering(tcp)) {
 		tcp->u_arg[0] = 0;
 		i1 = regs.r_o1;
-		if(umove(tcp, i1, &si) < 0) {
+		if (umove(tcp, i1, &si) < 0) {
 			perror("sigreturn: umove ");
 			return 0;
 		}
diff -d -urpN strace.1/strace.c strace.2/strace.c
--- strace.1/strace.c	2009-02-10 15:41:45.000000000 +0100
+++ strace.2/strace.c	2009-02-13 11:17:55.000000000 +0100
@@ -2712,27 +2712,28 @@ handle_stopped_tcbs(struct tcb *tcp)
 		/* we handled the STATUS, we are permitted to interrupt now. */
 		if (interrupted)
 			return 0;
-		if (trace_syscall(tcp) < 0 && !tcp->ptrace_errno) {
-			/* ptrace() failed in trace_syscall() with ESRCH.
-			 * Likely a result of process disappearing mid-flight.
-			 * Observed case: exit_group() terminating
-			 * all processes in thread group. In this case, threads
-			 * "disappear" in an unpredictable moment without any
-			 * notification to strace via wait().
+		if (trace_syscall(tcp) < 0) {
+			/* trace_syscall printed incompletely decoded syscall,
+			 * add error indicator.
+			 * NB: modulo bugs, errno must be nonzero, do not add
+			 * "if (err != 0)", this will hide bugs.
 			 */
+			int err = tcp->ptrace_errno;
+			tcp->ptrace_errno = 0;
+			if (err == ESRCH)
+				tprintf(" <unavailable>");
+			else
+				tprintf(" <ptrace error %d (%s)>", err, strerror(err));
+			printtrailer();
+			if (err == ESRCH)
+				/* Want to get death report anyway. */
+				goto tracing;
+			/* Strange error, we dare not continue. */
 			if (tcp->flags & TCB_ATTACHED) {
-				if (tcp_last) {
-					/* Do we have dangling line "syscall(param, param"?
-					 * Finish the line then. We cannot
-					 */
-					tcp_last->flags |= TCB_REPRINT;
-					tprintf(" <unfinished ...>");
-					printtrailer();
-				}
 				detach(tcp, 0);
 			} else {
-				ptrace(PTRACE_KILL,
-					tcp->pid, (char *) 1, SIGTERM);
+				ptrace(PTRACE_KILL, tcp->pid, (char *) 1, SIGTERM);
+				/* [why SIGTERM? why not also kill(SIGKILL)?] */
 				droptcb(tcp);
 			}
 			continue;
@@ -2838,13 +2839,25 @@ void
 printleader(struct tcb *tcp)
 {
 	if (tcp_last) {
-		if (tcp_last->ptrace_errno) {
+		int err = tcp_last->ptrace_errno;
+		if (err) {
 			tcp_last->ptrace_errno = 0;
 			if (tcp_last->flags & TCB_INSYSCALL) {
-				tprintf(" <unavailable ...>\n");
+				if (err == ESRCH)
+					tprintf(" <unavailable ...>\n");
+				else
+					tprintf(" <ptrace error %d (%s) ...>\n", err, strerror(err));
 				tcp_last->flags |= TCB_REPRINT;
 			} else {
-				tprintf("= ? <unavailable>\n");
+				/* Not sure this branch can ever be reached.
+				 * Oh well. Using subtly different format
+				 * (without "?" after "=") to make it
+				 * noticeable (grep for '= <' in straces).
+				 */
+				if (err == ESRCH)
+					tprintf("= <unavailable>\n");
+				else
+					tprintf("= <ptrace error %d (%s)>\n", err, strerror(err));
 			}
 		} else if (!outfname || followfork < 2 || tcp_last == tcp) {
 			tprintf(" <unfinished ...>\n");
diff -d -urpN strace.1/syscall.c strace.2/syscall.c
--- strace.1/syscall.c	2009-02-10 15:38:39.000000000 +0100
+++ strace.2/syscall.c	2009-02-13 11:17:55.000000000 +0100
@@ -1103,7 +1103,7 @@ get_scno(struct tcb *tcp)
 #elif defined (LINUX_MIPSN32)
 	unsigned long long regs[38];
 
-	if (ptrace (PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
+	if (do_ptrace(PTRACE_GETREGS, tcp, NULL, (long) &regs, "GETREGS") < 0)
 		return -1;
 	a3 = regs[REG_A3];
 	r2 = regs[REG_V0];
@@ -1351,11 +1351,11 @@ struct tcb *tcp;
 	return scno;
 }
 
-/* Called in trace_syscall() at each syscall entry and exit.
+/* Called in trace_syscall at each syscall entry and exit.
  * Returns:
- * 0: "ignore this syscall", bail out of trace_syscall() silently.
- * 1: ok, continue in trace_syscall().
- * other: error, trace_syscall() should print error indicator
+ * 0: "ignore this syscall", bail out of trace_syscall silently.
+ * 1: ok, continue in trace_syscall.
+ * other: error, trace_syscall should print error indicator
  *    ("????" etc) and bail out.
  */
 static int
@@ -1937,10 +1937,11 @@ force_result(tcp, error, rval)
 #endif /* S390 || S390X */
 #endif /* LINUX */
 #ifdef SUNOS4
-	if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
-		   error << 24) < 0 ||
-	    ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
+	if (do_ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error), error << 24, "POKEUSER") < 0
+	 || do_ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval, "POKEUSER") < 0
+	) {
 		return -1;
+	}
 #endif /* SUNOS4 */
 #ifdef SVR4
 	/* XXX no clue */
@@ -2071,10 +2072,10 @@ struct tcb *tcp;
 		else
      	        	nargs = tcp->u_nargs = MAX_ARGS;
 
-		if (ptrace (PTRACE_GETREGS, pid, NULL, (long) &regs) < 0)
+		if (do_ptrace(PTRACE_GETREGS, tcp, NULL, (long) &regs, "GETREGS") < 0)
 			return -1;
 
-		for(i = 0; i < nargs; i++) {
+		for (i = 0; i < nargs; i++) {
 			tcp->u_arg[i] = regs[REG_A0 + i];
 # if defined (LINUX_MIPSN32)
 			tcp->ext_arg[i] = regs[REG_A0 + i];
@@ -2090,17 +2091,17 @@ struct tcb *tcp;
 			nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
 		else
      	        	nargs = tcp->u_nargs = MAX_ARGS;
-		if(nargs > 4) {
-		  	if(upeek(tcp, REG_SP, &sp) < 0)
+		if (nargs > 4) {
+		  	if (upeek(tcp, REG_SP, &sp) < 0)
 			  	return -1;
-			for(i = 0; i < 4; i++) {
+			for (i = 0; i < 4; i++) {
 			  	if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i])<0)
 				  	return -1;
 			}
 			umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
 			       (char *)(tcp->u_arg + 4));
 		} else {
-		  	for(i = 0; i < nargs; i++) {
+		  	for (i = 0; i < nargs; i++) {
 			  	if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
 				  	return -1;
 			}
@@ -2349,7 +2350,12 @@ trace_syscall(struct tcb *tcp)
 		if (dtime)
 			gettimeofday(&tv, NULL);
 
-		/* BTW, why we don't just memorize syscall no. on entry
+		/* In code below,
+		 * res = 1: no error, continue
+		 * res = 0: return 0 at once (not an error)
+		 * any other value: error, complain and return the value
+		 *
+		 * BTW, why we don't just memorize syscall no. on entry
 		 * in tcp->something?
 		 */
 		scno_good = res = get_scno(tcp);
@@ -2374,14 +2380,15 @@ trace_syscall(struct tcb *tcp)
 
 		if (tcp->flags & TCB_REPRINT) {
 			printleader(tcp);
-			tprintf("<... ");
-			if (scno_good != 1)
-				tprintf("????");
-			else if (tcp->scno >= nsyscalls || tcp->scno < 0)
-				tprintf("syscall_%lu", tcp->scno);
-			else
-				tprintf("%s", sysent[tcp->scno].sys_name);
-			tprintf(" resumed> ");
+			if (scno_good != 1) {
+				tprintf("<... syscall_?? resumed> ");
+			} else {
+				if (tcp->scno >= nsyscalls || tcp->scno < 0)
+					tprintf("<... syscall_%lu resumed> ", tcp->scno);
+				else
+					tprintf("<... %s resumed> ", sysent[tcp->scno].sys_name);
+			}
+			/* [do we need to clear TCB_REPRINT?...] */
 		}
 
 		if (cflag)
@@ -2390,8 +2397,8 @@ trace_syscall(struct tcb *tcp)
 		if (res != 1) {
 			tprintf(") ");
 			tabto(acolumn);
-			tprintf("= ? <unavailable>");
-			printtrailer();
+			tprintf("= ?");
+			/* line will be finished by error handling code */
 			tcp->flags &= ~TCB_INSYSCALL;
 			return res;
 		}
@@ -2514,18 +2521,15 @@ trace_syscall(struct tcb *tcp)
 
 	if (res != 1) {
 		printleader(tcp);
-		tcp->flags &= ~TCB_REPRINT;
+		tcp->flags &= ~TCB_REPRINT; /* why? */
 		tcp_last = tcp;
 		if (scno_good != 1)
-			tprintf("????" /* anti-trigraph gap */ "(");
+			tprintf("syscall_??" /* anti-trigraph gap */ "(");
 		else if (tcp->scno >= nsyscalls || tcp->scno < 0)
 			tprintf("syscall_%lu(", tcp->scno);
 		else
 			tprintf("%s(", sysent[tcp->scno].sys_name);
-		/*
-		 * " <unavailable>" will be added later by the code which
-		 * detects ptrace errors.
-		 */
+		/* Line will be finished by error handling code. */
 		tcp->flags |= TCB_INSYSCALL;
 		return res;
 	}
@@ -2679,7 +2683,7 @@ struct tcb *tcp;
 #ifdef LINUX
 #if defined (SPARC) || defined (SPARC64)
 	struct regs regs;
-	if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
+	if (do_ptrace(PTRACE_GETREGS, tcp, (char *)&regs, 0, "GETREGS") < 0)
 		return -1;
 	val = regs.r_o1;
 #elif defined(SH)
diff -d -urpN strace.1/util.c strace.2/util.c
--- strace.1/util.c	2009-02-09 19:51:40.000000000 +0100
+++ strace.2/util.c	2009-02-13 11:17:55.000000000 +0100
@@ -241,30 +241,83 @@ xlookup(const struct xlat *xlat, int val
 }
 
 /*
- * Generic ptrace wrapper which tracks ESRCH errors
- * by setting tcp->ptrace_errno to ESRCH.
+ * Generic ptrace wrapper which tracks ptrace errors
+ * by setting tcp->ptrace_errno.
  *
  * We assume that ESRCH indicates likely process death (SIGKILL?),
  * modulo bugs where process somehow ended up not stopped.
  * Unfortunately kernel uses ESRCH for that case too. Oh well.
- *
- * Currently used by upeek() only.
- * TODO: use this in all other ptrace() calls while decoding.
  */
 long
-do_ptrace(int request, struct tcb *tcp, void *addr, void *data)
+do_ptrace(int request, struct tcb *tcp, void *addr, long data, const char *msg)
 {
+	int err;
 	long l;
 
 	errno = 0;
 	l = ptrace(request, tcp->pid, addr, data);
-	/* Non-ESRCH errors might be our invalid reg/mem accesses,
-	 * we do not record them. */
-	if (errno == ESRCH)
-		tcp->ptrace_errno = ESRCH;
+	err = errno;
+	if (err) {
+		tcp->ptrace_errno = err;
+		if (err != ESRCH) {
+			fprintf(stderr, "strace: ptrace(PTRACE_%s,%u,%p,%lu): %s\n",
+				msg, (int) tcp->pid, addr, data, strerror(err));
+		}
+		return -1;
+	}
+	return l;
+}
+
+static long
+do_ptrace_peekdata(struct tcb *tcp, void *addr, int started)
+{
+	int err;
+	long l;
+
+	errno = 0;
+	l = ptrace(PTRACE_PEEKDATA, tcp->pid, addr, 0);
+	err = errno;
+	if (err) {
+		if (started && (err == EPERM || err == EIO)) {
+			/* Ran into 'end of memory' - not an error */
+			return 0;
+		}
+		/* If error happens at first call, we have a bogus address. */
+		if (addr != NULL && err != EIO) {
+			if (errno != ESRCH) {
+				fprintf(stderr, "strace: ptrace(PTRACE_PEEKDATA,%u,%p,0): %s\n",
+					(int) tcp->pid, addr, strerror(err));
+				perror("ptrace: umoven");
+			}
+			tcp->ptrace_errno = errno;
+			return -1;
+		}
+	}
 	return l;
 }
 
+#ifdef SUNOS4
+static long
+do_ptrace5(int request, struct tcb *tcp, void *addr, long data, char *data2, const char *msg)
+{
+	int err;
+	long l;
+
+	errno = 0;
+	l = ptrace(request, tcp->pid, addr, data, data2);
+	err = errno;
+	if (err) {
+		tcp->ptrace_errno = err;
+		if (err != ESRCH) {
+			fprintf(stderr, "strace: ptrace(PTRACE_%s,%u,%p,%lu,%p): %s\n",
+				msg, (int) tcp->pid, addr, data, data2, strerror(err));
+		}
+		return -1;
+	}
+	return l;
+}
+#endif
+
 /*
  * Used when we want to unblock stopped traced process.
  * Should be only used with PTRACE_CONT, PTRACE_DETACH and PTRACE_SYSCALL.
@@ -279,7 +332,7 @@ ptrace_restart(int op, struct tcb *tcp, 
 	const char *msg;
 
 	errno = 0;
-	ptrace(op, tcp->pid, (void *) 1, (void *) (long) sig);
+	ptrace(op, tcp->pid, (void *) 1, (long) sig);
 	err = errno;
 	if (!err || err == ESRCH)
 		return 0;
@@ -290,8 +343,8 @@ ptrace_restart(int op, struct tcb *tcp, 
 		msg = "CONT";
 	if (op == PTRACE_DETACH)
 		msg = "DETACH";
-	fprintf(stderr, "strace: ptrace(PTRACE_%s,1,%d): %s\n",
-			msg, sig, strerror(err));
+	fprintf(stderr, "strace: ptrace(PTRACE_%s,%u,1,%d): %s\n",
+			msg, (int)tcp->pid, sig, strerror(err));
 	return -1;
 }
 
@@ -788,7 +841,6 @@ int
 umoven(struct tcb *tcp, long addr, int len, char *laddr)
 {
 #ifdef LINUX
-	int pid = tcp->pid;
 	int n, m;
 	int started = 0;
 	union {
@@ -800,34 +852,17 @@ umoven(struct tcb *tcp, long addr, int l
 		/* addr not a multiple of sizeof(long) */
 		n = addr - (addr & -sizeof(long)); /* residue */
 		addr &= -sizeof(long); /* residue */
-		errno = 0;
-		u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
-		if (errno) {
-			if (started && (errno==EPERM || errno==EIO)) {
-				/* Ran into 'end of memory' - stupid "printpath" */
-				return 0;
-			}
-			/* But if not started, we had a bogus address. */
-			if (addr != 0 && errno != EIO && errno != ESRCH)
-				perror("ptrace: umoven");
-			return -1;
-		}
+		u.val = do_ptrace_peekdata(tcp, (char *) addr, started);
+		if (errno)
+			return u.val; /* 0 or -1 */
 		started = 1;
 		memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
 		addr += sizeof(long), laddr += m, len -= m;
 	}
 	while (len) {
-		errno = 0;
-		u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
-		if (errno) {
-			if (started && (errno==EPERM || errno==EIO)) {
-				/* Ran into 'end of memory' - stupid "printpath" */
-				return 0;
-			}
-			if (addr != 0 && errno != EIO && errno != ESRCH)
-				perror("ptrace: umoven");
-			return -1;
-		}
+		u.val = do_ptrace_peekdata(tcp, (char *) addr, started);
+		if (errno)
+			return u.val; /* 0 or -1 */
 		started = 1;
 		memcpy(laddr, u.x, m = MIN(sizeof(long), len));
 		addr += sizeof(long), laddr += m, len -= m;
@@ -847,24 +882,16 @@ umoven(struct tcb *tcp, long addr, int l
 		/* addr not a multiple of sizeof(long) */
 		n = addr - (addr & -sizeof(long)); /* residue */
 		addr &= -sizeof(long); /* residue */
-		errno = 0;
-		u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
-		if (errno) {
-			if (errno != ESRCH)
-				perror("umoven");
+		u.val = do_ptrace(PTRACE_PEEKDATA, tcp, (char *) addr, 0, "PEEKDATA");
+		if (errno)
 			return -1;
-		}
 		memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
 		addr += sizeof(long), laddr += m, len -= m;
 	}
 	while (len) {
-		errno = 0;
-		u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
-		if (errno) {
-			if (errno != ESRCH)
-				perror("umoven");
+		u.val = do_ptrace(PTRACE_PEEKDATA, tcp, (char *) addr, 0, "PEEKDATA");
+		if (errno)
 			return -1;
-		}
 		memcpy(laddr, u.x, m = MIN(sizeof(long), len));
 		addr += sizeof(long), laddr += m, len -= m;
 	}
@@ -874,12 +901,7 @@ umoven(struct tcb *tcp, long addr, int l
 	while (len) {
 		n = MIN(len, PAGSIZ);
 		n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
-		if (ptrace(PTRACE_READDATA, pid,
-			   (char *) addr, len, laddr) < 0) {
-			if (errno != ESRCH) {
-				perror("umoven: ptrace(PTRACE_READDATA, ...)");
-				abort();
-			}
+		if (do_ptrace5(PTRACE_READDATA, tcp, (char *) addr, len, laddr, "READDATA") < 0) {
 			return -1;
 		}
 		len -= n;
@@ -941,7 +963,6 @@ umovestr(struct tcb *tcp, long addr, int
 	}
 #else /* !USE_PROCFS */
 	int started = 0;
-	int pid = tcp->pid;
 	int i, n, m;
 	union {
 		long val;
@@ -952,17 +973,9 @@ umovestr(struct tcb *tcp, long addr, int
 		/* addr not a multiple of sizeof(long) */
 		n = addr - (addr & -sizeof(long)); /* residue */
 		addr &= -sizeof(long); /* residue */
-		errno = 0;
-		u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
-		if (errno) {
-			if (started && (errno==EPERM || errno==EIO)) {
-				/* Ran into 'end of memory' - stupid "printpath" */
-				return 0;
-			}
-			if (addr != 0 && errno != EIO && errno != ESRCH)
-				perror("umovestr");
-			return -1;
-		}
+		u.val = do_ptrace_peekdata(tcp, (char *)addr, started);
+		if (errno)
+			return u.val; /* 0 or -1 */
 		started = 1;
 		memcpy(laddr, &u.x[n], m = MIN(sizeof(long)-n,len));
 		while (n & (sizeof(long) - 1))
@@ -971,17 +984,9 @@ umovestr(struct tcb *tcp, long addr, int
 		addr += sizeof(long), laddr += m, len -= m;
 	}
 	while (len) {
-		errno = 0;
-		u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
-		if (errno) {
-			if (started && (errno==EPERM || errno==EIO)) {
-				/* Ran into 'end of memory' - stupid "printpath" */
-				return 0;
-			}
-			if (addr != 0 && errno != EIO && errno != ESRCH)
-				perror("umovestr");
-			return -1;
-		}
+		u.val = do_ptrace_peekdata(tcp, (char *)addr, started);
+		if (errno)
+			return u.val; /* 0 or -1 */
 		started = 1;
 		memcpy(laddr, u.x, m = MIN(sizeof(long), len));
 		for (i = 0; i < sizeof(long); i++)
@@ -1004,12 +1009,7 @@ umovestr(struct tcb *tcp, long addr, int
 #ifdef SUNOS4
 
 static int
-uload(cmd, pid, addr, len, laddr)
-int cmd;
-int pid;
-long addr;
-int len;
-char *laddr;
+uload(int cmd, struct tcb *tcp, long addr, int len, char *laddr)
 {
 # if 0
 	int n;
@@ -1017,8 +1017,7 @@ char *laddr;
 	while (len) {
 		n = MIN(len, PAGSIZ);
 		n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
-		if (ptrace(cmd, pid, (char *)addr, n, laddr) < 0) {
-			perror("uload: ptrace(PTRACE_WRITE, ...)");
+		if (do_ptrace5(cmd, tcp, (char *)addr, n, laddr, "WRITE") < 0) {
 			return -1;
 		}
 		len -= n;
@@ -1045,50 +1044,39 @@ char *laddr;
 		/* addr not a multiple of sizeof(long) */
 		n = addr - (addr & -sizeof(long)); /* residue */
 		addr &= -sizeof(long);
-		errno = 0;
-		u.val = ptrace(peek, pid, (char *) addr, 0);
-		if (errno) {
-			perror("uload: POKE");
+		u.val = do_ptrace(peek, tcp, (char *) addr, 0, "PEEK");
+		if (errno)
 			return -1;
-		}
-		memcpy(&u.x[n], laddr, m = MIN(sizeof(long) - n, len));
-		if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
-			perror("uload: POKE");
+		m = MIN(sizeof(long) - n;
+		memcpy(&u.x[n], laddr, m, len));
+		if (do_ptrace(poke, tcp, (char *)addr, u.val, "POKE") < 0) {
 			return -1;
 		}
-		addr += sizeof(long), laddr += m, len -= m;
+		addr += sizeof(long);
+		laddr += m;
+		len -= m;
 	}
+	errno = 0;
 	while (len) {
 		if (len < sizeof(long))
-			u.val = ptrace(peek, pid, (char *) addr, 0);
-		memcpy(u.x, laddr, m = MIN(sizeof(long), len));
-		if (ptrace(poke, pid, (char *) addr, u.val) < 0) {
-			perror("uload: POKE");
+			u.val = do_ptrace(peek, tcp, (char *) addr, 0, "PEEK");
+		m = MIN(sizeof(long), len);
+		memcpy(u.x, laddr, m);
+		if (errno || do_ptrace(poke, tcp, (char *) addr, u.val, "POKE") < 0) {
 			return -1;
 		}
-		addr += sizeof(long), laddr += m, len -= m;
+		addr += sizeof(long);
+		laddr += m;
+		len -= m;
 	}
 # endif
 	return 0;
 }
 
-int
-tload(pid, addr, len, laddr)
-int pid;
-int addr, len;
-char *laddr;
-{
-	return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
-}
-
-int
-dload(pid, addr, len, laddr)
-int pid;
-int addr;
-int len;
-char *laddr;
+static int
+tload(struct tcb *tcp, int addr, int len, char *laddr)
 {
-	return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
+	return uload(PTRACE_WRITETEXT, tcp, addr, len, laddr);
 }
 
 #endif /* SUNOS4 */
@@ -1096,10 +1084,7 @@ char *laddr;
 #ifndef USE_PROCFS
 
 int
-upeek(tcp, off, res)
-struct tcb *tcp;
-long off;
-long *res;
+upeek(struct tcb *tcp, long off, long *res)
 {
 	long val;
 
@@ -1126,16 +1111,9 @@ long *res;
 			off += 1024;
 	}
 # endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
-	errno = 0;
-	val = do_ptrace(PTRACE_PEEKUSER, tcp, (char *) off, 0);
-	if (val == -1 && errno) {
-		if (errno != ESRCH) {
-			char buf[60];
-			sprintf(buf,"upeek: ptrace(PTRACE_PEEKUSER,%d,%lu,0)", tcp->pid, off);
-			perror(buf);
-		}
+	val = do_ptrace(PTRACE_PEEKUSER, tcp, (char *) off, 0, "PEEKUSER");
+	if (errno)
 		return -1;
-	}
 	*res = val;
 	return 0;
 }
@@ -1179,17 +1157,17 @@ struct tcb *tcp;
 		return -1;
 # elif defined(SPARC) || defined(SPARC64)
 	struct regs regs;
-	if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
+	if (do_ptrace(PTRACE_GETREGS, tcp, (char *) &regs, 0, "GETREGS") < 0)
 		return -1;
 	pc = regs.r_pc;
 # elif defined(S390) || defined(S390X)
-	if(upeek(tcp,PT_PSWADDR,&pc) < 0)
+	if (upeek(tcp, PT_PSWADDR, &pc) < 0)
 		return -1;
 # elif defined(HPPA)
-	if(upeek(tcp,PT_IAOQ0,&pc) < 0)
+	if (upeek(tcp, PT_IAOQ0, &pc) < 0)
 		return -1;
 # elif defined(SH)
-	if (upeek(tcp, 4*REG_PC ,&pc) < 0)
+	if (upeek(tcp, 4*REG_PC, &pc) < 0)
 		return -1;
 # elif defined(SH64)
 	if (upeek(tcp, REG_PC ,&pc) < 0)
@@ -1205,10 +1183,8 @@ struct tcb *tcp;
 	 */
 	struct regs regs;
 
-	if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
-		perror("getpc: ptrace(PTRACE_GETREGS, ...)");
+	if (do_ptrace(PTRACE_GETREGS, tcp, (char *) &regs, 0, "GETREGS") < 0)
 		return -1;
-	}
 	return regs.r_pc;
 #endif /* SUNOS4 */
 
@@ -1245,7 +1221,7 @@ struct tcb *tcp;
 
 # elif defined(S390) || defined(S390X)
 	long psw;
-	if(upeek(tcp,PT_PSWADDR,&psw) < 0) {
+	if (upeek(tcp, PT_PSWADDR, &psw) < 0) {
 		PRINTBADPC;
 		return;
 	}
@@ -1297,7 +1273,7 @@ struct tcb *tcp;
 	tprintf("[%08lx] ", pc);
 # elif defined(SPARC) || defined(SPARC64)
 	struct regs regs;
-	if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0) {
+	if (do_ptrace(PTRACE_GETREGS, tcp, (char *) &regs, 0, "GETREGS") < 0) {
 		PRINTBADPC;
 		return;
 	}
@@ -1305,7 +1281,7 @@ struct tcb *tcp;
 # elif defined(HPPA)
 	long pc;
 
-	if(upeek(tcp,PT_IAOQ0,&pc) < 0) {
+	if (upeek(tcp, PT_IAOQ0, &pc) < 0) {
 		tprintf ("[????????] ");
 		return;
 	}
@@ -1356,8 +1332,7 @@ struct tcb *tcp;
 #ifdef SUNOS4
 	struct regs regs;
 
-	if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
-		perror("printcall: ptrace(PTRACE_GETREGS, ...)");
+	if (do_ptrace(PTRACE_GETREGS, tcp, (char *) &regs, 0, "GETREGS") < 0) {
 		PRINTBADPC;
 		return;
 	}
@@ -1478,9 +1453,9 @@ set_arg0 (struct tcb *tcp, arg_setup_sta
 		req = PTRACE_POKEUSER;
 	} else
 		ap = ia64_rse_skip_regs(*state, 0);
-	errno = 0;
-	ptrace(req, tcp->pid, ap, val);
-	return errno ? -1 : 0;
+	if (do_ptrace(req, tcp, ap, val, "POKE") < 0)
+		return -1;
+	return 0;
 }
 
 static int
@@ -1494,9 +1469,9 @@ set_arg1 (struct tcb *tcp, arg_setup_sta
 		req = PTRACE_POKEUSER;
 	} else
 		ap = ia64_rse_skip_regs(*state, 1);
-	errno = 0;
-	ptrace(req, tcp->pid, ap, val);
-	return errno ? -1 : 0;
+	if (do_ptrace(req, tcp, ap, val, "POKE") < 0)
+		return -1;
+	return 0;
 }
 
 /* ia64 does not return the input arguments from functions (and syscalls)
@@ -1510,9 +1485,9 @@ set_arg1 (struct tcb *tcp, arg_setup_sta
 typedef struct regs arg_setup_state;
 
 #   define arg_setup(tcp, state) \
-    (ptrace (PTRACE_GETREGS, tcp->pid, (char *) (state), 0))
+    (do_ptrace(PTRACE_GETREGS, tcp, (char *) (state), 0, "GETREGS"))
 #   define arg_finish_change(tcp, state) \
-    (ptrace (PTRACE_SETREGS, tcp->pid, (char *) (state), 0))
+    (do_ptrace(PTRACE_SETREGS, tcp, (char *) (state), 0, "SETREGS"))
 
 #   define get_arg0(tcp, state, valp) (*(valp) = (state)->r_o0, 0)
 #   define get_arg1(tcp, state, valp) (*(valp) = (state)->r_o1, 0)
@@ -1572,15 +1547,15 @@ typedef int arg_setup_state;
     (upeek ((tcp), arg1_offset, (valp)))
 
 static int
-set_arg0 (struct tcb *tcp, void *cookie, long val)
+set_arg0(struct tcb *tcp, void *cookie, long val)
 {
-	return ptrace (PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
+	return do_ptrace(PTRACE_POKEUSER, tcp, (char*)arg0_offset, val, "POKEUSER");
 }
 
 static int
-set_arg1 (struct tcb *tcp, void *cookie, long val)
+set_arg1(struct tcb *tcp, void *cookie, long val)
 {
-	return ptrace (PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
+	return do_ptrace(PTRACE_POKEUSER, tcp, (char*)arg1_offset, val, "POKEUSER");
 }
 
 #  endif /* architectures */
@@ -1710,17 +1685,13 @@ struct tcb *tcp;
 		fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
 		return -1;
 	}
-	if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
-		perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
+	if (do_ptrace(PTRACE_GETREGS, tcp, (char *)&regs, 0, "GETREGS") < 0) {
 		return -1;
 	}
 	tcp->baddr = regs.r_o7 + 8;
-	errno = 0;
-	tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)tcp->baddr, 0);
-	if(errno) {
-		perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
+	tcp->inst[0] = do_ptrace(PTRACE_PEEKTEXT, tcp, (char *)tcp->baddr, 0, "PEEKTEXT");
+	if (errno)
 		return -1;
-	}
 
 	/*
 	 * XXX - BRUTAL MODE ON
@@ -1738,11 +1709,8 @@ struct tcb *tcp;
 	inst <<= 32;
 	inst |= (tcp->inst[0] & 0xffffffffUL);
 #    endif
-	ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, inst);
-	if(errno) {
-		perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
+	if (do_ptrace(PTRACE_POKETEXT, tcp, (char *) tcp->baddr, inst, "POKETEXT") < 0)
 		return -1;
-	}
 	tcp->flags |= TCB_BPTSET;
 
 #   else /* !SPARC && !SPARC64 */
@@ -1759,17 +1727,11 @@ struct tcb *tcp;
 		if (debug)
 			fprintf(stderr, "[%d] setting bpt at %lx\n",
 				tcp->pid, tcp->baddr);
-		tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid,
-				      (char *) tcp->baddr, 0);
-		if (errno) {
-			perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
+		tcp->inst[0] = do_ptrace(PTRACE_PEEKTEXT, tcp, (char *) tcp->baddr, 0, "PEEKTEXT");
+		if (errno)
 			return -1;
-		}
-		ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOP);
-		if (errno) {
-			perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
+		if (do_ptrace(PTRACE_POKETEXT, tcp, (char *) tcp->baddr, LOOP, "POKETEXT") < 0)
 			return -1;
-		}
 		tcp->flags |= TCB_BPTSET;
 	} else {
 		/*
@@ -1795,21 +1757,15 @@ struct tcb *tcp;
 		/* store "ri" in low two bits */
 		tcp->baddr = addr | ((ipsr >> 41) & 0x3);
 
-		errno = 0;
-		tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, pid, (char *) addr + 0,
-				      0);
-		tcp->inst[1] = ptrace(PTRACE_PEEKTEXT, pid, (char *) addr + 8,
-				      0);
-		if (errno) {
-			perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
+		tcp->inst[0] = do_ptrace(PTRACE_PEEKTEXT, tcp, (char *) addr + 0, 0, "PEEKTEXT");
+		if (!errno)
+			tcp->inst[1] = do_ptrace(PTRACE_PEEKTEXT, tcp, (char *) addr + 8, 0, "PEEKTEXT");
+		if (errno)
 			return -1;
-		}
 
-		errno = 0;
-		ptrace(PTRACE_POKETEXT, pid, (char *) addr + 0, LOOP0);
-		ptrace(PTRACE_POKETEXT, pid, (char *) addr + 8, LOOP1);
-		if (errno) {
-			perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
+		if (do_ptrace(PTRACE_POKETEXT, tcp, (char *) addr + 0, LOOP0, "POKETEXT") < 0
+		 || do_ptrace(PTRACE_POKETEXT, tcp, (char *) addr + 8, LOOP1, "POKETEXT") < 0
+		) {
 			return -1;
 		}
 		tcp->flags |= TCB_BPTSET;
@@ -1881,14 +1837,10 @@ struct tcb *tcp;
 #     endif
 	if (debug)
 		fprintf(stderr, "[%d] setting bpt at %lx\n", tcp->pid, tcp->baddr);
-	tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *) tcp->baddr, 0);
-	if (errno) {
-		perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
+	tcp->inst[0] = do_ptrace(PTRACE_PEEKTEXT, tcp, (char *) tcp->baddr, 0, "PEEKTEXT");
+	if (errno)
 		return -1;
-	}
-	ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOP);
-	if (errno) {
-		perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
+	if (do_ptrace(PTRACE_POKETEXT, tcp, (char *) tcp->baddr, LOOP, "POKETEXT") < 0) {
 		return -1;
 	}
 	tcp->flags |= TCB_BPTSET;
@@ -1915,14 +1867,12 @@ struct tcb *tcp;
 		fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
 		return -1;
 	}
-	if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
-		perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
+	if (do_ptrace(PTRACE_GETREGS, tcp, (char *)&regs, 0, "GETREGS") < 0) {
 		return -1;
 	}
 	tcp->baddr = regs.r_o7 + 8;
-	if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
-				sizeof tcp->inst, (char *)tcp->inst) < 0) {
-		perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
+	if (do_ptrace5(PTRACE_READTEXT, tcp, (char *)tcp->baddr,
+				sizeof tcp->inst, (char *)tcp->inst, "READTEXT") < 0) {
 		return -1;
 	}
 
@@ -1936,9 +1886,8 @@ struct tcb *tcp;
 	 * generated by out PTRACE_ATTACH.
 	 * Of cause, if we evaporate ourselves in the middle of all this...
 	 */
-	if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
-			sizeof loopdeloop, (char *) loopdeloop) < 0) {
-		perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
+	if (do_ptrace5(PTRACE_WRITETEXT, tcp, (char *) tcp->baddr,
+			sizeof loopdeloop, (char *) loopdeloop, "WRITETEXT") < 0) {
 		return -1;
 	}
 	tcp->flags |= TCB_BPTSET;
@@ -1976,10 +1925,7 @@ struct tcb *tcp;
 		fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
 		return -1;
 	}
-	errno = 0;
-	ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
-	if(errno) {
-		perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
+	if (do_ptrace(PTRACE_POKETEXT, tcp, (char *) tcp->baddr, tcp->inst[0], "POKETEXT") < 0) {
 		return -1;
 	}
 	tcp->flags &= ~TCB_BPTSET;
@@ -1993,10 +1939,7 @@ struct tcb *tcp;
 			fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
 			return -1;
 		}
-		errno = 0;
-		ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
-		if (errno) {
-			perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
+		if (do_ptrace(PTRACE_POKETEXT, tcp, (char *) tcp->baddr, tcp->inst[0], "POKETEXT") < 0) {
 			return -1;
 		}
 		tcp->flags &= ~TCB_BPTSET;
@@ -2023,20 +1966,15 @@ struct tcb *tcp;
 			return -1;
 
 		/* restore original bundle: */
-		errno = 0;
-		ptrace(PTRACE_POKETEXT, pid, (char *) addr + 0, tcp->inst[0]);
-		ptrace(PTRACE_POKETEXT, pid, (char *) addr + 8, tcp->inst[1]);
-		if (errno) {
-			perror("clearbpt: ptrace(PTRACE_POKETEXT, ...)");
+		if (do_ptrace(PTRACE_POKETEXT, tcp, (char *) addr + 0, tcp->inst[0], "POKETEXT") < 0
+		 || do_ptrace(PTRACE_POKETEXT, tcp, (char *) addr + 8, tcp->inst[1], "POKETEXT") < 0
+		) {
 			return -1;
 		}
 
 		/* restore original "ri" in ipsr: */
 		ipsr = (ipsr & ~(0x3ul << 41)) | ((tcp->baddr & 0x3) << 41);
-		errno = 0;
-		ptrace(PTRACE_POKEUSER, pid, (char *) PT_CR_IPSR, ipsr);
-		if (errno) {
-			perror("clrbpt: ptrace(PTRACE_POKEUSER, ...)");
+		if (do_ptrace(PTRACE_POKEUSER, tcp, (char *) PT_CR_IPSR, ipsr, "POKEUSER") < 0) {
 			return -1;
 		}
 
@@ -2058,10 +1996,7 @@ struct tcb *tcp;
 		fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
 		return -1;
 	}
-	errno = 0;
-	ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
-	if (errno) {
-		perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
+	if (do_ptrace(PTRACE_POKETEXT, tcp, (char *) tcp->baddr, tcp->inst[0], "POKETEXT") < 0) {
 		return -1;
 	}
 	tcp->flags &= ~TCB_BPTSET;
@@ -2134,8 +2069,11 @@ struct tcb *tcp;
 	 * safe to set both IAOQ0 and IAOQ1 to that so the PSW N bit
 	 * has no significant effect.
 	 */
-	ptrace(PTRACE_POKEUSER, tcp->pid, (void *)PT_IAOQ0, iaoq);
-	ptrace(PTRACE_POKEUSER, tcp->pid, (void *)PT_IAOQ1, iaoq);
+	if (do_ptrace(PTRACE_POKEUSER, tcp, (void *)PT_IAOQ0, iaoq, "POKEUSER") < 0
+	 || do_ptrace(PTRACE_POKEUSER, tcp, (void *)PT_IAOQ1, iaoq, "POKEUSER") < 0
+	) {
+		return -1;
+	}
 #    elif defined(SH)
 	if (upeek(tcp, 4*REG_PC, &pc) < 0)
 		return -1;
@@ -2162,9 +2100,8 @@ struct tcb *tcp;
 		fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
 		return -1;
 	}
-	if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
-				sizeof tcp->inst, (char *) tcp->inst) < 0) {
-		perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
+	if (do_ptrace5(PTRACE_WRITETEXT, tcp, (char *) tcp->baddr,
+				sizeof tcp->inst, (char *) tcp->inst, "WRITETEXT") < 0) {
 		return -1;
 	}
 	tcp->flags &= ~TCB_BPTSET;
@@ -2174,12 +2111,10 @@ struct tcb *tcp;
 	 * Since we don't have a single instruction breakpoint, we may have
 	 * to adjust the program counter after removing our `breakpoint'.
 	 */
-	if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
-		perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
+	if (do_ptrace(PTRACE_GETREGS, tcp, (char *)&regs, 0, "GETREGS") < 0) {
 		return -1;
 	}
-	if ((regs.r_pc < tcp->baddr) ||
-				(regs.r_pc > tcp->baddr + 4)) {
+	if ((regs.r_pc < tcp->baddr) ||	(regs.r_pc > tcp->baddr + 4)) {
 		/* The breakpoint has not been reached yet */
 		if (debug)
 			fprintf(stderr,
@@ -2193,8 +2128,7 @@ struct tcb *tcp;
 				regs.r_pc, tcp->baddr);
 
 	regs.r_pc = tcp->baddr;
-	if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
-		perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
+	if (do_ptrace(PTRACE_SETREGS, tcp, (char *)&regs, 0, "SETREGS") < 0) {
 		return -1;
 	}
 #    endif /* LOOPA */
@@ -2265,7 +2199,7 @@ struct tcb *tcp;
 		fprintf(stderr, "out of memory\n");
 		return -1;
 	}
-	if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
+	if (umoven(tcp, (int)ld.ld_symbols + (int)N_TXTADDR(hdr),
 					(int)ld.ld_symb_size, strtab) < 0)
 		goto err;
 
@@ -2290,7 +2224,7 @@ struct tcb *tcp;
 		 * Write entire symbol table back to avoid
 		 * memory alignment bugs in ptrace
 		 */
-		if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
+		if (tload(tcp, (int)ld.ld_symbols + (int)N_TXTADDR(hdr),
 					(int)ld.ld_symb_size, strtab) < 0)
 			goto err;
 






More information about the Strace-devel mailing list