[PATCH] more robustness against ptrace errors
Denys Vlasenko
dvlasenk at redhat.com
Tue Feb 24 13:08:47 UTC 2009
On Tue, 2009-02-24 at 03:04 +0300, Dmitry V. Levin wrote:
> On Fri, Feb 13, 2009 at 11:37:07AM +0100, Denys Vlasenko wrote:
> [...]
> > Please review.
>
> Sorry for the long delay.
> The change looks good indeed. See my comments below, though.
>
> > + if (do_ptrace(PTRACE_SET_SYSCALL, tcp, NULL, new, "SET_SYSCALL") != 0)
>
> The "SET_SYSCALL" is deducable from PTRACE_SET_SYSCALL number, isn't it?
> Could we avoid this redundancy?
>
> > 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;
> > +}
>
> fprintf() may clobber errno, which is tested after do_ptrace() return
> several times in the code, so we have to either reset errno back to the
> value set by ptrace() call, or change *all* do_ptrace() callers to check
> its return value instead of errno.
>
> > +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;
> > }
>
> Previous comment about errno is applicable to this function as well.
Good ideas, please take a look at this:
--
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-24 14:02:51.000000000 +0100
@@ -424,6 +424,7 @@ extern const struct xlat open_mode_flags
extern const struct xlat addrfams[];
extern const struct xlat struct_user_offsets[];
extern const struct xlat open_access_modes[];
+extern const struct xlat ptrace_cmds[];
/* Format of syscall return values */
#define RVAL_DECIMAL 000 /* decimal format */
@@ -485,7 +486,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));
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-24 14:01:24.000000000 +0100
+++ strace.2/process.c 2009-02-24 14:02:51.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) != 0)
return -1;
return 0;
@@ -2263,8 +2263,8 @@ struct tcb *tcp;
#ifdef LINUX
#ifndef __GLIBC__
tprintf(", domainname=\"%s\"", uname.domainname);
-#endif /* __GLIBC__ */
-#endif /* LINUX */
+#endif
+#endif
tprintf("}");
}
else
@@ -2276,7 +2276,7 @@ struct tcb *tcp;
#ifndef SVR4
-static const struct xlat ptrace_cmds[] = {
+const struct xlat ptrace_cmds[] = {
# ifndef FREEBSD
{ PTRACE_TRACEME, "PTRACE_TRACEME" },
{ PTRACE_PEEKTEXT, "PTRACE_PEEKTEXT", },
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-24 14:02:51.000000000 +0100
@@ -1409,14 +1409,13 @@ struct tcb *tcp;
struct regs regs;
m_siginfo_t si;
- if(ptrace(PTRACE_GETREGS, tcp->pid, (char *)®s, 0) < 0) {
- perror("sigreturn: PTRACE_GETREGS ");
+ if (do_ptrace(PTRACE_GETREGS, tcp, (char *)®s, 0) < 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-24 14:02:51.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) ®s) < 0)
+ if (do_ptrace(PTRACE_GETREGS, tcp, NULL, (long) ®s) < 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) < 0
+ || do_ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 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) ®s) < 0)
+ if (do_ptrace(PTRACE_GETREGS, tcp, NULL, (long) ®s) < 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 *)®s,0) < 0)
+ if (do_ptrace(PTRACE_GETREGS, tcp, (char *)®s, 0) < 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-24 14:02:51.000000000 +0100
@@ -241,30 +241,103 @@ 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.
*/
+static const char *
+str_PTRACE_xxx(int request)
+{
+ const char *s;
+ static char msg[sizeof(int) * 3 + sizeof("PTRACE_<%d>")];
+
+ s = xlookup(ptrace_cmds, request);
+ if (s)
+ return s;
+ sprintf(msg, "PTRACE_<%d>", request);
+ return msg;
+}
+
long
-do_ptrace(int request, struct tcb *tcp, void *addr, void *data)
+do_ptrace(int request, struct tcb *tcp, void *addr, long data)
{
+ 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(%s,%u,%p,%lu): %s\n",
+ str_PTRACE_xxx(request),
+ (int) tcp->pid, addr, data, strerror(err));
+ errno = err; /* fprintf can clobber it, restore */
+ }
+ 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.
+ * NB: errno is nonzero, caller uses this to detect
+ * "end of string" condition.
+ */
+ return 0;
+ }
+ /* If error happens at first call, we have a bogus address. */
+ if (addr != NULL && err != EIO) {
+ if (err != ESRCH) {
+ fprintf(stderr, "strace: ptrace(PTRACE_PEEKDATA,%u,%p,0): %s\n",
+ (int) tcp->pid, addr, strerror(err));
+ errno = err; /* fprintf can clobber it, restore */
+ }
+ tcp->ptrace_errno = err;
+ return -1;
+ }
+ }
+ return l;
+}
+
+#ifdef SUNOS4
+static long
+do_ptrace5(int request, struct tcb *tcp, void *addr, long data, char *data2)
+{
+ 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(%s,%u,%p,%lu,%p): %s\n",
+ str_PTRACE_xxx(request),
+ (int) tcp->pid, addr, data, data2, strerror(err));
+ errno = err; /* fprintf can clobber it, restore */
+ }
+ 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.
@@ -273,25 +346,21 @@ do_ptrace(int request, struct tcb *tcp,
* Otherwise prints error message and returns -1.
*/
int
-ptrace_restart(int op, struct tcb *tcp, int sig)
+ptrace_restart(int request, struct tcb *tcp, int sig)
{
int err;
- const char *msg;
errno = 0;
- ptrace(op, tcp->pid, (void *) 1, (void *) (long) sig);
+ ptrace(request, tcp->pid, (void *) 1, (long) sig);
err = errno;
if (!err || err == ESRCH)
return 0;
tcp->ptrace_errno = err;
- msg = "SYSCALL";
- if (op == PTRACE_CONT)
- 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(%s,%u,1,%d): %s\n",
+ str_PTRACE_xxx(request),
+ (int)tcp->pid, sig, strerror(err));
+ errno = err; /* fprintf can clobber it, restore */
return -1;
}
@@ -788,7 +857,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 +868,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 +898,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);
+ 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);
+ if (errno)
return -1;
- }
memcpy(laddr, u.x, m = MIN(sizeof(long), len));
addr += sizeof(long), laddr += m, len -= m;
}
@@ -874,12 +917,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) < 0) {
return -1;
}
len -= n;
@@ -941,7 +979,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 +989,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 +1000,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 +1025,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 +1033,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) < 0) {
return -1;
}
len -= n;
@@ -1045,50 +1060,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);
+ 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) < 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);
+ m = MIN(sizeof(long), len);
+ memcpy(u.x, laddr, m);
+ if (errno || do_ptrace(poke, tcp, (char *) addr, u.val) < 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 +1100,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 +1127,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);
- }
+ if (errno)
return -1;
- }
*res = val;
return 0;
}
@@ -1179,17 +1173,17 @@ struct tcb *tcp;
return -1;
# elif defined(SPARC) || defined(SPARC64)
struct regs regs;
- if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)®s,0) < 0)
+ if (do_ptrace(PTRACE_GETREGS, tcp, (char *) ®s, 0) < 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 +1199,8 @@ struct tcb *tcp;
*/
struct regs regs;
- if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) ®s, 0) < 0) {
- perror("getpc: ptrace(PTRACE_GETREGS, ...)");
+ if (do_ptrace(PTRACE_GETREGS, tcp, (char *) ®s, 0) < 0)
return -1;
- }
return regs.r_pc;
#endif /* SUNOS4 */
@@ -1245,7 +1237,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 +1289,7 @@ struct tcb *tcp;
tprintf("[%08lx] ", pc);
# elif defined(SPARC) || defined(SPARC64)
struct regs regs;
- if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)®s,0) < 0) {
+ if (do_ptrace(PTRACE_GETREGS, tcp, (char *) ®s, 0) < 0) {
PRINTBADPC;
return;
}
@@ -1305,7 +1297,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 +1348,7 @@ struct tcb *tcp;
#ifdef SUNOS4
struct regs regs;
- if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) ®s, 0) < 0) {
- perror("printcall: ptrace(PTRACE_GETREGS, ...)");
+ if (do_ptrace(PTRACE_GETREGS, tcp, (char *) ®s, 0) < 0) {
PRINTBADPC;
return;
}
@@ -1478,9 +1469,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) < 0)
+ return -1;
+ return 0;
}
static int
@@ -1494,9 +1485,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) < 0)
+ return -1;
+ return 0;
}
/* ia64 does not return the input arguments from functions (and syscalls)
@@ -1510,9 +1501,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))
# define arg_finish_change(tcp, state) \
- (ptrace (PTRACE_SETREGS, tcp->pid, (char *) (state), 0))
+ (do_ptrace(PTRACE_SETREGS, tcp, (char *) (state), 0))
# define get_arg0(tcp, state, valp) (*(valp) = (state)->r_o0, 0)
# define get_arg1(tcp, state, valp) (*(valp) = (state)->r_o1, 0)
@@ -1572,15 +1563,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);
}
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);
}
# endif /* architectures */
@@ -1710,17 +1701,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 *)®s, 0) < 0) {
- perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
+ if (do_ptrace(PTRACE_GETREGS, tcp, (char *)®s, 0) < 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);
+ if (errno)
return -1;
- }
/*
* XXX - BRUTAL MODE ON
@@ -1738,11 +1725,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) < 0)
return -1;
- }
tcp->flags |= TCB_BPTSET;
# else /* !SPARC && !SPARC64 */
@@ -1759,17 +1743,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);
+ 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) < 0)
return -1;
- }
tcp->flags |= TCB_BPTSET;
} else {
/*
@@ -1795,21 +1773,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);
+ if (!errno)
+ tcp->inst[1] = do_ptrace(PTRACE_PEEKTEXT, tcp, (char *) addr + 8, 0);
+ 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) < 0
+ || do_ptrace(PTRACE_POKETEXT, tcp, (char *) addr + 8, LOOP1) < 0
+ ) {
return -1;
}
tcp->flags |= TCB_BPTSET;
@@ -1881,14 +1853,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);
+ 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) < 0) {
return -1;
}
tcp->flags |= TCB_BPTSET;
@@ -1915,14 +1883,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 *)®s, 0) < 0) {
- perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
+ if (do_ptrace(PTRACE_GETREGS, tcp, (char *)®s, 0) < 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 +1902,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,
+ if (do_ptrace5(PTRACE_WRITETEXT, tcp, (char *) tcp->baddr,
sizeof loopdeloop, (char *) loopdeloop) < 0) {
- perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
return -1;
}
tcp->flags |= TCB_BPTSET;
@@ -1976,10 +1941,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]) < 0) {
return -1;
}
tcp->flags &= ~TCB_BPTSET;
@@ -1993,10 +1955,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]) < 0) {
return -1;
}
tcp->flags &= ~TCB_BPTSET;
@@ -2023,20 +1982,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]) < 0
+ || do_ptrace(PTRACE_POKETEXT, tcp, (char *) addr + 8, tcp->inst[1]) < 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) < 0) {
return -1;
}
@@ -2058,10 +2012,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]) < 0) {
return -1;
}
tcp->flags &= ~TCB_BPTSET;
@@ -2134,8 +2085,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) < 0
+ || do_ptrace(PTRACE_POKEUSER, tcp, (void *)PT_IAOQ1, iaoq) < 0
+ ) {
+ return -1;
+ }
# elif defined(SH)
if (upeek(tcp, 4*REG_PC, &pc) < 0)
return -1;
@@ -2162,9 +2116,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,
+ if (do_ptrace5(PTRACE_WRITETEXT, tcp, (char *) tcp->baddr,
sizeof tcp->inst, (char *) tcp->inst) < 0) {
- perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
return -1;
}
tcp->flags &= ~TCB_BPTSET;
@@ -2174,12 +2127,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 *)®s, 0) < 0) {
- perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
+ if (do_ptrace(PTRACE_GETREGS, tcp, (char *)®s, 0) < 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 +2144,7 @@ struct tcb *tcp;
regs.r_pc, tcp->baddr);
regs.r_pc = tcp->baddr;
- if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)®s, 0) < 0) {
- perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
+ if (do_ptrace(PTRACE_SETREGS, tcp, (char *)®s, 0) < 0) {
return -1;
}
# endif /* LOOPA */
@@ -2265,7 +2215,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 +2240,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