diff --git a/ChangeLog b/ChangeLog index e7886a02..d833dd59 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,25 @@ +2009-02-24 Denys Vlasenko + + Replace many more bare ptrace calls with calls to wrappers + which do proper error-checking and set tcp->ptrace_errno. + 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. + * defs.h: Declare ptrace_cmds[]. Modify do_ptrace + declaration (last parameter is long, not void *). + * process.c: Make ptrace_cmds[] non-static. + (change_syscall): Use do_ptrace() instead of bare ptrace(). + * signal.c: Use do_ptrace() instead of bare ptrace(). + * strace.c: Update trace_syscall() failure handling. + * syscall.c: Use do_ptrace() instead of bare ptrace(). + * util.c: Use do_ptrace() instead of bare ptrace(). + Update do_ptrace() wrapper. + (str_PTRACE_xxx): New function - helper returning "PTRACE_xxx". + (do_ptrace_peekdata): New function - wrapper for PTRACE_PEEKDATA + (do_ptrace5): New function - wrapper for 5-argument ptrace calls. + 2009-02-24 Denys Vlasenko * process.c: Indent preprocessor directives so that nesting diff --git a/defs.h b/defs.h index 7b327af6..7c88a1c4 100644 --- a/defs.h +++ b/defs.h @@ -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 --git a/process.c b/process.c index 29e57d5e..cf538808 100644 --- a/process.c +++ b/process.c @@ -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; @@ -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 --git a/signal.c b/signal.c index 9f4edd91..179b7f4b 100644 --- a/signal.c +++ b/signal.c @@ -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 --git a/strace.c b/strace.c index 2f56b879..cded401e 100644 --- a/strace.c +++ b/strace.c @@ -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(" "); + else + tprintf(" ", 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(" "); - 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(" \n"); + if (err == ESRCH) + tprintf(" \n"); + else + tprintf(" \n", err, strerror(err)); tcp_last->flags |= TCB_REPRINT; } else { - tprintf("= ? \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("= \n"); + else + tprintf("= \n", err, strerror(err)); } } else if (!outfname || followfork < 2 || tcp_last == tcp) { tprintf(" \n"); diff --git a/syscall.c b/syscall.c index 99b85161..9722519f 100644 --- a/syscall.c +++ b/syscall.c @@ -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("= ? "); - 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); - /* - * " " 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 --git a/util.c b/util.c index ca38f1d1..4a17d40e 100644 --- a/util.c +++ b/util.c @@ -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. */ -long -do_ptrace(int request, struct tcb *tcp, void *addr, void *data) +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, 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, void *addr, void *data) * 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 len, char *laddr) /* 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 len, char *laddr) /* 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 len, char *laddr) 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 len, char *laddr) } #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 len, char *laddr) /* 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 len, char *laddr) 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 len, char *laddr) #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; + m = MIN(sizeof(long) - n; + memcpy(&u.x[n], laddr, m, len)); + if (do_ptrace(poke, tcp, (char *)addr, u.val) < 0) { 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"); - 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; +static int +tload(struct tcb *tcp, int addr, int 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; -{ - 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_state *state, long val) 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_state *state, long val) 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_state *state, long val) 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;