diff --git a/ChangeLog b/ChangeLog index cea9670e..29e42db5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,8 +1,5 @@ 2009-06-01 Dmitry V. Levin - * strace.c (handle_stopped_tcbs): Fix cast for 4th argument - passed to ptrace(). - * bjm.c (sys_query_module): Fix format warning reported by gcc -Wformat-security. * file.c (tprint_open_modes): Likewise. @@ -24,11 +21,6 @@ Move NULL/error check for addr parameter so that it happens before printstatsol/printstat_sparc64 calls. -2009-04-20 Denys Vlasenko - - * strace.c (collect_stopped_tcbs): Do not enable/disable signals - multiple times, do it just once per collecting pass. - 2009-04-16 Denys Vlasenko * file.c (print_dirfd): Use int for file descriptor, not a long. @@ -62,12 +54,6 @@ * net.c (printcmsghdr): Fix improperly used %zu: struct cmsghdr::cmsg_len is not a size_t. -2009-03-17 Denys Vlasenko - - * strace.c (collect_stopped_tcbs): Check for ^C here too, - not only in trace(). - (trace): Tweak check for ^C to not set mask (not needed). - 2009-03-10 Denys Vlasenko Decode fcntl's F_{GET,SET}LEASE, F_NOTIFY, and F_DUPFD_CLOEXEC. @@ -115,28 +101,6 @@ (force_result): While at it, fix cpp directives indentation. * util.c (printcall): Add support for cris. -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 ESRCH. - 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 @@ -192,17 +156,6 @@ [HAVE_STRUCT_SIGCONTEXT]. From Muttley Meen . -2009-02-10 Denys Vlasenko - - Cleanup after tcb table expansion simplification. - There was code which was trying to continue tracing - even if table expansion fails. Now we treat it as fatal - failure, so this code is removed by this change. - * defs.h: Delete TCB_FOLLOWFORK constant. - * process.c: Delete fork_tcb() and all calls of it. - * strace.c (startup_attach): Remove usage of TCB_FOLLOWFORK. - * syscall.c: Indent preprocessor directives. - 2009-02-09 Denys Vlasenko * defs.h: Correct the comment about TCB_SUSPENDED. @@ -221,20 +174,6 @@ right before its death, it can legitimately happen. (handle_stopped_tcbs): Ditto. -2009-01-28 Denys Vlasenko - - * process.c (internal_clone): Check and complain if pid value - looks insane. - * strace.c (alloc_tcb): Clear *all* fields in reused tcb. - (main): Query and remember uname() info on startup. - (handle_stopped_tcbs): Do not use PTRACE_SETOPTIONS on Linux < 2.6.29. - (printleader): Correct printing of "" markers. - -2009-01-27 Denys Vlasenko - - * strace.c (collect_stopped_tcbs): Guard against the case when - waitpid() reports the same task multiple times. - 2009-01-26 Denys Vlasenko * process.c (printwaitn): Add comment about wait4() pid expansion. @@ -259,12 +198,6 @@ Format '%#08lx' expects type 'long unsigned int', but argument 2 was type 'unsigned int'. -2009-01-21 Denys Vlasenko - - * strace.c (collect_stopped_tcbs): Do not return NULL when ECHILD - is detected, return collected list instead. Fixes symptom when - the last "+++ killed by SIGxxx +++" is not printed. - 2009-01-17 Denys Vlasenko Two cleanups: tcb table expansion failure is not really a survivable @@ -287,28 +220,6 @@ (alloc_tcb): On failure to expand, print a message, clean up, and exit. * util.c (setbpt): Remove extern declaration from function body. -2009-01-17 Denys Vlasenko - - * defs.h: Update a comment. No code changes. - * strace.c (handle_stopped_tcbs): Discard all execve stops - and clear TCB_WAITEXECVE bit. - * syscall.c (get_scno): Add the code to not mistakenly - treat ptrace stop as execve stop (execve stops can be blocked - by traced program). - Fixes RH#477775 "strace hangs if the target process blocks SIGTRAP". - -2009-01-17 Denys Vlasenko - - * process.c: Add a comment. No code changes. - * strace.c (collect_stopped_tcbs): Stop reversing list of stopped - tcp's. I'm not totally convinced it is crucial, but this is surely - fits the concept of "least surprise". - Do not collect TCB_SUSPENDED tcp's (this is closer to how - it was before). - (handle_stopped_tcbs): Remove the code to reject TCB_SUSPENDED tcp's, - it's done earlier now. In an unobvious way, this was causing - SIGSTOPs from freshly attached children to be misinterpreted. - 2009-01-14 Denys Vlasenko * linux/bfin/syscallent.h: sys_futex has 6 parameters, not 5. @@ -318,8 +229,6 @@ Fixes for ptrace() argument parsing. * process.c: Add parsing of PTRACE_SETOPTIONS, PTRACE_GETEVENTMSG, PTRACE_GETSIGINFO, PTRACE_SETSIGINFO. - * strace.c (handle_stopped_tcbs): Make PTRACE_SETOPTIONS - define check more robust. * defs.h: Declare several "extern const struct xlat" arrays here. * desc.c: Remove open_mode_flags[] and open_access_modes[] extern declarations. @@ -328,19 +237,6 @@ * util.c: Remove struct_user_offsets[] extern declaration. * signal.c: Remove open_mode_flags[] extern declaration. -2009-01-09 Denys Vlasenko - - * defs.h: Add new struct tcb fields: wait_status, next_need_service. - make flags field wider (ints are easier to work with on many CPUs). - * strace.c (trace): Split this function into two: - collect_stopped_tcbs() and handle_stopped_tcbs(). - Now we collect *all* waitable tasks, then handle them all, - then repeat. - Fixes RH#478419 "Some threads stop when strace with -f option - is executed on a multi-thread process" - * test/many_looping_threads.c: example program which cna't be straced - successfully without this fix. - 2009-01-06 Denys Vlasenko Output format fixes, improving the situation after recent @@ -374,15 +270,6 @@ convert all remaining old style C parameter declarations in this file. -2009-01-02 Denys Vlasenko - - * strace.c: Fix compile failure: on some systems PTRACE_O_xxx - and PTRACE_EVENT_xxx constants are not defined because - those system have old kernel headers. - OTOH, if PT_SETOPTIONS is not defined too, - I don't risk using ptrace options, the kernel is too old. - I've seen problems on RHEL4 ia64 when I tried to. - 2008-11-13 Kirill A. Shutemov * linux/arm/syscallent.h: Update syscalls. @@ -428,29 +315,6 @@ * linux/syscallent.h: Mark sendfile(2) as network syscall. * linux/*/syscallent.h: Same, for all architectures. -2008-12-29 Denys Vlasenko - - * defs.h: Remove sigtrap80 field from struct tcb. - * strace.c: Add ptrace_stop_sig static variable - and use it in place of tcp->sigtrap80. - Add ptrace_opts_set static flag variable. - (trace): Set ptrace options once, not per-process. - If unexpected SIGTRAP is later received, - revert back to using SIGTRAP - (assume old, broken kernel). - -2008-12-22 Denys Vlasenko - - Make strace correctly handle SIGTRAP produced by e.g. - kill(2) and by trapping instruction. - * defs.h: Add sigtrap80 field to struct tcb. - * strace.c (alloc_tcb): Initialize it to SIGTRAP. - (detach): Use tcp->sigtrap80 instead of SIGTRAP constant. - (trace): Attempt to set PTRACE_O_TRACESYSGOOD and - PTRACE_O_TRACEEXEC options on each newly attached process, - distinquish between SIGTRAP and (SIGTRAP | 0x80) stops. - Fixes RH#162774 "strace ignores int3 SIGTRAP". - 2008-12-17 Denys Vlasenko Make strace detect when traced process suddenly disappeared diff --git a/defs.h b/defs.h index 2f5683be..769ed225 100644 --- a/defs.h +++ b/defs.h @@ -298,11 +298,8 @@ extern int mp_ioctl (int f, int c, void *a, int s); /* Trace Control Block */ struct tcb { - int flags; /* See below for TCB_ values */ + short flags; /* See below for TCB_ values */ int pid; /* Process Id of this entry */ - int wait_status; /* Status from last wait() */ - struct tcb *next_need_service; - /* Linked list of tracees found by wait()s */ long scno; /* System call number */ int u_nargs; /* System call arguments */ long u_arg[MAX_ARGS]; /* System call arguments */ @@ -328,8 +325,8 @@ struct tcb { int nclone_threads; /* # of nchildren with CLONE_THREAD */ int nclone_detached; /* # of nchildren with CLONE_DETACHED */ int nclone_waiting; /* clone threads in wait4 (TCB_SUSPENDED) */ - /* (1st arg of wait4()) */ #endif + /* (1st arg of wait4()) */ long baddr; /* `Breakpoint' address */ long inst[2]; /* Instructions on above */ int pfd; /* proc file descriptor */ @@ -359,19 +356,12 @@ struct tcb { #define TCB_SUSPENDED 00040 /* Process can not be allowed to resume just now */ #define TCB_BPTSET 00100 /* "Breakpoint" set after fork(2) */ #define TCB_SIGTRAPPED 00200 /* Process wanted to block SIGTRAP */ +#define TCB_FOLLOWFORK 00400 /* Process should have forks followed */ #define TCB_REPRINT 01000 /* We should reprint this syscall on exit */ #ifdef LINUX -/* TCB_WAITEXECVE bit means "ignore next SIGTRAP, it's execve exit stop". - * it is not reliable if traced program masks SIGTRAP. - * - * x86 does not need TCB_WAITEXECVE. +/* x86 does not need TCB_WAITEXECVE. * It can detect execve's SIGTRAP by looking at eax/rax. * See "stray syscall exit: eax = " message in syscall_fixup(). - * - * Note that on newer kernels, we use ptrace options and therefore - * can filter out execve stops reliably on any architecture, - * without using TCB_WAITEXECVE flag. - * I guess we can remove it from the source somewhere around year 2010 :) */ # if defined(ALPHA) || defined(AVR32) || defined(SPARC) || defined(SPARC64) \ || defined(POWERPC) || defined(IA64) || defined(HPPA) \ @@ -430,7 +420,6 @@ 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 */ @@ -492,7 +481,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, long data)); +extern long do_ptrace P((int request, struct tcb *tcp, void *addr, void *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/desc.c b/desc.c index 383107e3..e01b9acc 100644 --- a/desc.c +++ b/desc.c @@ -872,7 +872,7 @@ sys_io_cancel(struct tcb *tcp) tprintf("{%p, %p, %ld, %ld}", event.data, event.obj, event.res, event.res2); - else + else #endif tprintf("{...}"); } diff --git a/process.c b/process.c index 5119ede5..afd36bb8 100644 --- a/process.c +++ b/process.c @@ -484,6 +484,18 @@ struct tcb *tcp; return 0; } +/* TCP is creating a child we want to follow. + If there will be space in tcbtab for it, set TCB_FOLLOWFORK and return 0. + If not, clear TCB_FOLLOWFORK, print an error, and return 1. */ +static void +fork_tcb(struct tcb *tcp) +{ + if (nprocs == tcbtabsize) + expand_tcbtab(); + + tcp->flags |= TCB_FOLLOWFORK; +} + #ifdef USE_PROCFS int @@ -533,6 +545,7 @@ struct tcb *tcp; return 0; if (!followfork) return 0; + fork_tcb(tcp); if (syserror(tcp)) return 0; tcpchild = alloctcb(tcp->u_rval); @@ -779,7 +792,7 @@ change_syscall(struct tcb *tcp, int new) # define PTRACE_SET_SYSCALL 23 # endif - if (do_ptrace(PTRACE_SET_SYSCALL, tcp, NULL, new) != 0) + if (ptrace (PTRACE_SET_SYSCALL, tcp->pid, 0, new) != 0) return -1; return 0; @@ -899,18 +912,22 @@ setarg(tcp, argnum) #if defined SYS_clone || defined SYS_clone2 int -internal_clone(struct tcb *tcp) +internal_clone(tcp) +struct tcb *tcp; { struct tcb *tcpchild; - int pid, bpt; - - if (!followfork) - return 0; + int pid; if (entering(tcp)) { - setbpt(tcp); - return 0; + if (!followfork) + return 0; + fork_tcb(tcp); + if (setbpt(tcp) < 0) + return 0; } else { - bpt = tcp->flags & TCB_BPTSET; + int bpt = tcp->flags & TCB_BPTSET; + + if (!(tcp->flags & TCB_FOLLOWFORK)) + return 0; if (syserror(tcp)) { if (bpt) @@ -919,15 +936,6 @@ internal_clone(struct tcb *tcp) } pid = tcp->u_rval; - /* Should not happen, but bugs often cause bogus value here. */ - if (pid <= 1 - || (sizeof(pid) != sizeof(tcp->u_rval) && pid != tcp->u_rval) - ) { - if (bpt) - clearbpt(tcp); - fprintf(stderr, "bogus clone() return value %lx!\n", tcp->u_rval); - return 0; - } #ifdef CLONE_PTRACE /* See new setbpt code. */ tcpchild = pid2tcb(pid); @@ -944,6 +952,7 @@ internal_clone(struct tcb *tcp) else #endif { + fork_tcb(tcp); tcpchild = alloctcb(pid); } @@ -979,9 +988,6 @@ internal_clone(struct tcb *tcp) clearbpt(tcpchild); tcpchild->flags &= ~(TCB_SUSPENDED|TCB_STARTUP); - /* TCB_SUSPENDED tasks are not collected by waitpid - * loop, and left stopped. Restart it: - */ if (ptrace_restart(PTRACE_SYSCALL, tcpchild, 0) < 0) return -1; @@ -1045,25 +1051,27 @@ struct tcb *tcp; struct tcb *tcpchild; int pid; - int follow = 1; + int dont_follow = 0; #ifdef SYS_vfork if (known_scno(tcp) == SYS_vfork) { /* Attempt to make vfork into fork, which we can follow. */ if (change_syscall(tcp, SYS_fork) < 0) - follow = 0; + dont_follow = 1; } #endif - if (!followfork || !follow) - return 0; - if (entering(tcp)) { + if (!followfork || dont_follow) + return 0; + fork_tcb(tcp); if (setbpt(tcp) < 0) return 0; } else { int bpt = tcp->flags & TCB_BPTSET; + if (!(tcp->flags & TCB_FOLLOWFORK)) + return 0; if (bpt) clearbpt(tcp); @@ -1071,6 +1079,7 @@ struct tcb *tcp; return 0; pid = tcp->u_rval; + fork_tcb(tcp); tcpchild = alloctcb(pid); #ifdef LINUX #ifdef HPPA @@ -2313,7 +2322,7 @@ struct tcb *tcp; #ifndef SVR4 -const struct xlat ptrace_cmds[] = { +static const struct xlat ptrace_cmds[] = { # ifndef FREEBSD { PTRACE_TRACEME, "PTRACE_TRACEME" }, { PTRACE_PEEKTEXT, "PTRACE_PEEKTEXT", }, diff --git a/signal.c b/signal.c index 32036576..76504f60 100644 --- a/signal.c +++ b/signal.c @@ -1403,13 +1403,14 @@ sys_sigreturn(struct tcb *tcp) struct regs regs; m_siginfo_t si; - if (do_ptrace(PTRACE_GETREGS, tcp, (char *)®s, 0) < 0) { + if(ptrace(PTRACE_GETREGS, tcp->pid, (char *)®s, 0) < 0) { + perror("sigreturn: PTRACE_GETREGS "); 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 d351dc5e..da8cc4a5 100644 --- a/strace.c +++ b/strace.c @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include @@ -100,17 +99,12 @@ static int iflag = 0, interactive = 0, pflag_seen = 0, rflag = 0, tflag = 0; */ static bool daemonized_tracer = 0; -static struct utsname utsname_buf; - /* Sometimes we want to print only succeeding syscalls. */ int not_failing_only = 0; static int exit_code = 0; static int strace_child = 0; -static int ptrace_stop_sig = SIGTRAP; -#if defined LINUX && (defined PTRACE_SETOPTIONS || defined PT_SETOPTIONS) -static bool ptrace_opts_set; -#endif + static char *username = NULL; uid_t run_uid; gid_t run_gid; @@ -122,6 +116,7 @@ FILE *outf; struct tcb **tcbtab; unsigned int nprocs, tcbtabsize; char *progname; +extern char **environ; static int detach P((struct tcb *tcp, int sig)); static int trace P((void)); @@ -441,7 +436,7 @@ startup_attach(void) ++nerr; else if (tid != tcbtab[tcbi]->pid) { tcp = alloctcb(tid); - tcp->flags |= TCB_ATTACHED|TCB_CLONE_THREAD|TCB_CLONE_DETACHED; + tcp->flags |= TCB_ATTACHED|TCB_CLONE_THREAD|TCB_CLONE_DETACHED|TCB_FOLLOWFORK; tcbtab[tcbi]->nchildren++; tcbtab[tcbi]->nclone_threads++; tcbtab[tcbi]->nclone_detached++; @@ -694,8 +689,6 @@ main(int argc, char *argv[]) progname = argv[0] ? argv[0] : "strace"; - uname(&utsname_buf); - /* Allocate the initial tcbtab. */ tcbtabsize = argc; /* Surely enough for all -p args. */ if ((tcbtab = calloc(tcbtabsize, sizeof tcbtab[0])) == NULL) { @@ -1002,10 +995,18 @@ alloc_tcb(int pid, int command_options_parsed) for (i = 0; i < tcbtabsize; i++) { tcp = tcbtab[i]; if ((tcp->flags & TCB_INUSE) == 0) { - memset(tcp, 0, sizeof(*tcp)); tcp->pid = pid; + tcp->parent = NULL; + tcp->nchildren = 0; + tcp->nzombies = 0; +#ifdef TCB_CLONE_THREAD + tcp->nclone_threads = tcp->nclone_detached = 0; + tcp->nclone_waiting = 0; +#endif tcp->flags = TCB_INUSE | TCB_STARTUP; tcp->outf = outf; /* Initialise to current out file */ + tcp->stime.tv_sec = 0; + tcp->stime.tv_usec = 0; tcp->pfd = -1; nprocs++; if (command_options_parsed) @@ -1608,7 +1609,7 @@ int sig; break; } error = ptrace_restart(PTRACE_CONT, tcp, - WSTOPSIG(status) == ptrace_stop_sig ? 0 + WSTOPSIG(status) == SIGTRAP ? 0 : WSTOPSIG(status)); if (error < 0) break; @@ -2249,88 +2250,60 @@ handle_group_exit(struct tcb *tcp, int sig) } #endif -static struct tcb * -collect_stopped_tcbs(void) +static int +trace() { -#ifdef LINUX - static int remembered_pid; - static int remembered_status; -#endif int pid; int wait_errno; int status; struct tcb *tcp; - struct tcb *found_tcps; #ifdef LINUX - struct tcb **nextp; struct rusage ru; - struct rusage* ru_ptr = cflag ? &ru : NULL; - int wnohang = 0; #ifdef __WALL - int wait4_options = __WALL; + static int wait4_options = __WALL; #endif - - if (remembered_pid > 0) { - pid = remembered_pid; - remembered_pid = 0; - if (debug) - fprintf(stderr, " [remembered wait(%#x) = %u]\n", - remembered_status, pid); - tcp = pid2tcb(pid); /* can't be NULL */ - tcp->wait_status = remembered_status; - tcp->next_need_service = NULL; - return tcp; - } - nextp = &found_tcps; #endif /* LINUX */ - /* Make it possible to ^C strace while we wait */ - if (interactive) - sigprocmask(SIG_SETMASK, &empty_set, NULL); - - found_tcps = NULL; - while (1) { + while (nprocs != 0) { if (interrupted) - break; + return 0; + if (interactive) + sigprocmask(SIG_SETMASK, &empty_set, NULL); #ifdef LINUX #ifdef __WALL - pid = wait4(-1, &status, wait4_options | wnohang, ru_ptr); + pid = wait4(-1, &status, wait4_options, cflag ? &ru : NULL); if (pid < 0 && (wait4_options & __WALL) && errno == EINVAL) { /* this kernel does not support __WALL */ wait4_options &= ~__WALL; errno = 0; - pid = wait4(-1, &status, wait4_options | wnohang, ru_ptr); + pid = wait4(-1, &status, wait4_options, + cflag ? &ru : NULL); } if (pid < 0 && !(wait4_options & __WALL) && errno == ECHILD) { /* most likely a "cloned" process */ - pid = wait4(-1, &status, __WCLONE | wnohang, ru_ptr); - if (pid < 0 && errno != ECHILD) { - fprintf(stderr, "strace: wait4(WCLONE) " + pid = wait4(-1, &status, __WCLONE, + cflag ? &ru : NULL); + if (pid == -1) { + fprintf(stderr, "strace: clone wait4 " "failed: %s\n", strerror(errno)); } } -#else /* !__WALL */ - pid = wait4(-1, &status, wnohang, ru_ptr); -#endif +#else + pid = wait4(-1, &status, 0, cflag ? &ru : NULL); +#endif /* __WALL */ #endif /* LINUX */ #ifdef SUNOS4 pid = wait(&status); #endif /* SUNOS4 */ wait_errno = errno; + if (interactive) + sigprocmask(SIG_BLOCK, &blocked_set, NULL); - if (pid == 0 && wnohang) { - /* We had at least one successful - * wait() before. We waited - * with WNOHANG second time. - * Stop collecting more tracees, - * process what we already have. - */ - break; - } if (pid == -1) { - if (wait_errno == EINTR) + switch (wait_errno) { + case EINTR: continue; - if (wait_errno == ECHILD) { + case ECHILD: /* * We would like to verify this case * but sometimes a race in Solbourne's @@ -2338,16 +2311,17 @@ collect_stopped_tcbs(void) * ECHILD before sending us SIGCHILD. */ #if 0 - if (nprocs != 0) { - fprintf(stderr, "strace: proc miscount\n"); - exit(1); - } + if (nprocs == 0) + return 0; + fprintf(stderr, "strace: proc miscount\n"); + exit(1); #endif - break; + return 0; + default: + errno = wait_errno; + perror("strace: wait"); + return -1; } - errno = wait_errno; - perror("strace: wait"); - exit(1); } if (pid == popen_pid) { if (WIFEXITED(status) || WIFSIGNALED(status)) @@ -2357,14 +2331,6 @@ collect_stopped_tcbs(void) if (debug) fprintf(stderr, " [wait(%#x) = %u]\n", status, pid); - /* RHEL5 bug workaround. - * It can re-report stopped tasks. Happens on SIGSTOPs here. - * Second (bogus) report has signal# set to 0. - * Stop collecting and process what we have. - */ - if (WIFSTOPPED(status) && WSTOPSIG(status) == 0) - break; - /* Look up `pid' in our table. */ if ((tcp = pid2tcb(pid)) == NULL) { #ifdef LINUX @@ -2388,7 +2354,7 @@ Process %d attached (waiting for parent)\n", else /* This can happen if a clone call used CLONE_PTRACE itself. */ -#endif /* LINUX */ +#endif { fprintf(stderr, "unknown pid: %u\n", pid); if (WIFSTOPPED(status)) @@ -2396,13 +2362,15 @@ Process %d attached (waiting for parent)\n", exit(1); } } - -#ifdef LINUX + /* set current output file */ + outf = tcp->outf; if (cflag) { +#ifdef LINUX tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime); tcp->stime = ru.ru_stime; +#endif /* !LINUX */ } -#endif + if (tcp->flags & TCB_SUSPENDED) { /* * Apparently, doing any ptrace() call on a stopped @@ -2411,76 +2379,9 @@ Process %d attached (waiting for parent)\n", * process has not been actually restarted. * Since we have inspected the arguments of suspended * processes we end up here testing for this case. - * - * We also end up here when we catch new pid of - * CLONE_PTRACEd process. Do not process/restart it - * until we see corresponding clone() syscall exit - * in its parent. */ continue; } - -#ifdef LINUX - /* So far observed only on RHEL5 ia64, but I imagine this - * can legitimately happen elsewhere. - * If we waited and got a stopped task notification, - * subsequent wait may return the same pid again, for example, - * with SIGKILL notification. SIGKILL kills even stopped tasks. - * We must not add it to the list - * (one task can't be inserted twice in the list). - */ - { - struct tcb *f = found_tcps; - while (f) { - if (f == tcp) { - remembered_pid = pid; - remembered_status = status; - goto ret; - } - f = f->next_need_service; - } - } - /* It is important to not invert the order of tasks - * to process. For one, alloc_tcb() above picks newly forked - * threads in some order, processing of them and their parent - * should be in the same order, otherwise bad things happen - * (misinterpreted SIGSTOPs and such). - */ - tcp->wait_status = status; - *nextp = tcp; - nextp = &tcp->next_need_service; - *nextp = NULL; - wnohang = WNOHANG; -#endif -#ifdef SUNOS4 - /* Probably need to replace wait with waitpid - * and loop on Sun too, but I can't test it. Volunteers? - */ - tcp->wait_status = status; - tcp->next_need_service = NULL; - found_tcps = tcp; - break; -#endif - } /* while (1) - collecting all stopped/exited tracees */ - ret: - /* Disable ^C etc */ - if (interactive) - sigprocmask(SIG_BLOCK, &blocked_set, NULL); - - return found_tcps; -} - -static int -handle_stopped_tcbs(struct tcb *tcp) -{ - for (; tcp; tcp = tcp->next_need_service) { - int pid; - int status; - - outf = tcp->outf; - status = tcp->wait_status; - pid = tcp->pid; - if (WIFSIGNALED(status)) { if (pid == strace_child) exit_code = 0x100 | WTERMSIG(status); @@ -2542,7 +2443,7 @@ handle_stopped_tcbs(struct tcb *tcp) /* * Interestingly, the process may stop * with STOPSIG equal to some other signal - * than SIGSTOP if we happen to attach + * than SIGSTOP if we happend to attach * just before the process takes a signal. */ if ((tcp->flags & TCB_STARTUP) && WSTOPSIG(status) == SIGSTOP) { @@ -2563,100 +2464,10 @@ handle_stopped_tcbs(struct tcb *tcp) return -1; } } -/* Add more OSes after you verified it works for them. */ -/* PTRACE_SETOPTIONS may be an enum, not a #define. - * But sometimes we can test for it by checking PT_SETOPTIONS. - */ -#if defined LINUX && (defined PTRACE_SETOPTIONS || defined PT_SETOPTIONS) -# ifndef PTRACE_O_TRACESYSGOOD -# define PTRACE_O_TRACESYSGOOD 0x00000001 -# endif -# ifndef PTRACE_O_TRACEEXEC -# define PTRACE_O_TRACEEXEC 0x00000010 -# endif -# ifndef PTRACE_EVENT_EXEC -# define PTRACE_EVENT_EXEC 4 -# endif - /* - * Ask kernel to set signo to SIGTRAP | 0x80 - * on ptrace-generated SIGTRAPs, and mark - * execve's SIGTRAP with PTRACE_EVENT_EXEC. - */ - if (!ptrace_opts_set) { - char *p; - ptrace_opts_set = 1; - - /* RHEL 2.6.18 definitely has crippling bugs */ - /* Vanilla and Fedora 2.6.29 seems to work */ - p = utsname_buf.release; - if (strtoul(p, &p, 10) < 2 || *p != '.') - goto tracing; - if (strtoul(++p, &p, 10) < 6 || *p != '.') - goto tracing; - if (strtoul(++p, &p, 10) < 29) - goto tracing; - /* - * NB: even if this "succeeds", we can - * revert back to SIGTRAP if we later see - * that it didnt really work. - * Old kernels are known to lie here. - */ - if (ptrace(PTRACE_SETOPTIONS, pid, (char *) 0, - (long) (PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEEXEC)) == 0) - ptrace_stop_sig = SIGTRAP | 0x80; - } -#endif goto tracing; } -#if defined LINUX && (defined PTRACE_SETOPTIONS || defined PT_SETOPTIONS) - if (ptrace_stop_sig != SIGTRAP && WSTOPSIG(status) == SIGTRAP) { - /* - * We told ptrace to report SIGTRAP | 0x80 on this process - * but got bare SIGTRAP. This can be a genuine SIGTRAP: - * kill(pid, SIGTRAP), trap insn, etc; - * but be paranoid about it. - */ - if (((unsigned)status >> 16) == PTRACE_EVENT_EXEC) { - /* It's post-exec ptrace stop. Ignore it, - * we will get syscall exit ptrace stop later. - */ -#ifdef TCB_WAITEXECVE - tcp->flags &= ~TCB_WAITEXECVE; -#endif - goto tracing; - } else { - /* Take a better look... */ - siginfo_t si; - si.si_signo = 0; - ptrace(PTRACE_GETSIGINFO, pid, (void*) 0, (long) &si); - /* - * Check some fields to make sure we see - * real SIGTRAP. - * Otherwise interpret it as ptrace stop. - * Real SIGTRAPs (int3 insn on x86, kill() etc) - * have these values: - * int3: kill -TRAP $pid: - * si_signo:5 (SIGTRAP) si_signo:5 (SIGTRAP) - * si_errno:0 si_errno:(?) - * si_code:128 (SI_KERNEL) si_code:0 (SI_USER) - * si_pid:0 si_pid:(>0?) - * si_band:0 si_band:(?) - * Ptrace stops have garbage there instead. - */ - if (si.si_signo != SIGTRAP - || (si.si_code != SI_KERNEL && si.si_code != SI_USER) - ) { - fprintf(stderr, "bogus SIGTRAP (si_code:%x), assuming old kernel\n", si.si_code); - ptrace_stop_sig = SIGTRAP; - } - } - } -#endif - - if (WSTOPSIG(status) != ptrace_stop_sig) { - /* This isn't a ptrace stop. */ - + if (WSTOPSIG(status) != SIGTRAP) { if (WSTOPSIG(status) == SIGSTOP && (tcp->flags & TCB_SIGTRAPPED)) { /* @@ -2721,28 +2532,27 @@ 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) { - /* 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. + 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(). */ - 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); - /* [why SIGTERM? why not also kill(SIGKILL)?] */ + ptrace(PTRACE_KILL, + tcp->pid, (char *) 1, SIGTERM); droptcb(tcp); } continue; @@ -2773,34 +2583,6 @@ handle_stopped_tcbs(struct tcb *tcp) cleanup(); return -1; } - } /* for each tcp */ - - return 0; -} - -static int -trace() -{ - int rc; - struct tcb *tcbs; - - while (nprocs != 0) { - /* The loop of "wait for one tracee, serve it, repeat" - * may leave some tracees never served. - * Kernel provides no guarantees of fairness when you have - * many waitable tasks. - * Try strace -f with test/many_looping_threads.c example. - * To fix it, we collect *all* waitable tasks, then handle - * them all, then repeat. - */ - if (interrupted) - return 0; - tcbs = collect_stopped_tcbs(); - if (!tcbs) - break; - rc = handle_stopped_tcbs(tcbs); - if (rc) - return rc; } return 0; } @@ -2842,32 +2624,20 @@ va_dcl } void -printleader(struct tcb *tcp) +printleader(tcp) +struct tcb *tcp; { if (tcp_last) { - int err = tcp_last->ptrace_errno; - if (err) { - tcp_last->ptrace_errno = 0; + if (tcp_last->ptrace_errno) { if (tcp_last->flags & TCB_INSYSCALL) { - if (err == ESRCH) - tprintf(" \n"); - else - tprintf(" \n", err, strerror(err)); - tcp_last->flags |= TCB_REPRINT; - } else { - /* 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)); + tprintf(" )"); + tabto(acolumn); } + tprintf("= ? \n"); + tcp_last->ptrace_errno = 0; } else if (!outfname || followfork < 2 || tcp_last == tcp) { - tprintf(" \n"); tcp_last->flags |= TCB_REPRINT; + tprintf(" \n"); } } curcol = 0; diff --git a/svr4/syscallent.h b/svr4/syscallent.h index d8e5a125..239d6b0b 100644 --- a/svr4/syscallent.h +++ b/svr4/syscallent.h @@ -823,5 +823,5 @@ { -1, TF, sys_aioaread64, "aioaread64" }, /* 417 */ { -1, TF, sys_aioawrite64, "aioawrite64" }, /* 418 */ { -1, TF, sys_aiocancel64, "aiocancel64" }, /* 419 */ - { -1, TF, sys_aiofsync, "aiofsync" }, /* 420 */ + { -1, TF, sys_aiofsync, "aiofsync" }, /* 420 */ #endif diff --git a/syscall.c b/syscall.c index 10b6627a..2605f91a 100644 --- a/syscall.c +++ b/syscall.c @@ -38,39 +38,38 @@ #include #include #include -#include #include #include #include #if HAVE_ASM_REG_H -# if defined (SPARC) || defined (SPARC64) +#if defined (SPARC) || defined (SPARC64) # define fpq kernel_fpq # define fq kernel_fq # define fpu kernel_fpu -# endif -# include -# if defined (SPARC) || defined (SPARC64) +#endif +#include +#if defined (SPARC) || defined (SPARC64) # undef fpq # undef fq # undef fpu -# endif +#endif #endif #ifdef HAVE_SYS_REG_H -# include -# ifndef PTRACE_PEEKUSR -# define PTRACE_PEEKUSR PTRACE_PEEKUSER -# endif +#include +#ifndef PTRACE_PEEKUSR +# define PTRACE_PEEKUSR PTRACE_PEEKUSER +#endif #elif defined(HAVE_LINUX_PTRACE_H) -# undef PTRACE_SYSCALL +#undef PTRACE_SYSCALL # ifdef HAVE_STRUCT_IA64_FPREG # define ia64_fpreg XXX_ia64_fpreg # endif # ifdef HAVE_STRUCT_PT_ALL_USER_REGS # define pt_all_user_regs XXX_pt_all_user_regs # endif -# include +#include # undef ia64_fpreg # undef pt_all_user_regs #endif @@ -997,47 +996,26 @@ get_scno(struct tcb *tcp) } # elif defined(IA64) # define IA64_PSR_IS ((long)1 << 34) - if (upeek(tcp, PT_CR_IPSR, &psr) >= 0) + if (upeek (tcp, PT_CR_IPSR, &psr) >= 0) ia32 = (psr & IA64_PSR_IS) != 0; if (!(tcp->flags & TCB_INSYSCALL)) { if (ia32) { if (upeek(tcp, PT_R1, &scno) < 0) /* orig eax */ return -1; } else { - if (upeek(tcp, PT_R15, &scno) < 0) + if (upeek (tcp, PT_R15, &scno) < 0) return -1; } /* Check if we return from execve. */ if (tcp->flags & TCB_WAITEXECVE) { -# if defined PTRACE_GETSIGINFO - siginfo_t si; - - tcp->flags &= ~TCB_WAITEXECVE; - /* If SIGTRAP is masked, execve's magic SIGTRAP - * is not delivered. We end up here on a subsequent - * ptrace stop instead. Luckily, we can check - * for the type of this SIGTRAP. execve's magic one - * has 0 (SI_USER) in si.si_code, ptrace stop has 5. - * (I don't know why 5). - */ - si.si_code = SI_USER; - /* If PTRACE_GETSIGINFO fails, we assume it's - * magic SIGTRAP. Moot anyway, PTRACE_GETSIGINFO - * doesn't fail. - */ - ptrace(PTRACE_GETSIGINFO, tcp->pid, (void*) 0, (void*) &si); - if (si.si_code == SI_USER) - return 0; -# else tcp->flags &= ~TCB_WAITEXECVE; return 0; -# endif } } else { /* syscall in progress */ - if (upeek(tcp, PT_R8, &r8) < 0) + if (upeek (tcp, PT_R8, &r8) < 0) return -1; - if (upeek(tcp, PT_R10, &r10) < 0) + if (upeek (tcp, PT_R10, &r10) < 0) return -1; } # elif defined (ARM) @@ -1126,7 +1104,7 @@ get_scno(struct tcb *tcp) # elif defined (LINUX_MIPSN32) unsigned long long regs[38]; - if (do_ptrace(PTRACE_GETREGS, tcp, NULL, (long) ®s) < 0) + if (ptrace (PTRACE_GETREGS, tcp->pid, NULL, (long) ®s) < 0) return -1; a3 = regs[REG_A3]; r2 = regs[REG_V0]; @@ -1379,11 +1357,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 @@ -1938,11 +1916,10 @@ force_result(tcp, error, rval) #endif /* LINUX */ #ifdef SUNOS4 - 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 - ) { + if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error), + error << 24) < 0 || + ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0) return -1; - } #endif /* SUNOS4 */ #ifdef SVR4 @@ -2074,10 +2051,10 @@ syscall_enter(struct tcb *tcp) else nargs = tcp->u_nargs = MAX_ARGS; - if (do_ptrace(PTRACE_GETREGS, tcp, NULL, (long) ®s) < 0) + if (ptrace (PTRACE_GETREGS, pid, 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]; @@ -2092,20 +2069,20 @@ syscall_enter(struct tcb *tcp) if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1) 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) - return -1; - for (i = 0; i < 4; i++) { - if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i])<0) - return -1; + nargs = tcp->u_nargs = MAX_ARGS; + if(nargs > 4) { + if(upeek(tcp, REG_SP, &sp) < 0) + return -1; + 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++) { - if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0) - return -1; + for(i = 0; i < nargs; i++) { + if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0) + return -1; } } } @@ -2377,12 +2354,7 @@ trace_syscall(struct tcb *tcp) if (dtime) gettimeofday(&tv, NULL); - /* 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 + /* BTW, why we don't just memorize syscall no. on entry * in tcp->something? */ scno_good = res = get_scno(tcp); @@ -2407,15 +2379,14 @@ trace_syscall(struct tcb *tcp) if (tcp->flags & TCB_REPRINT) { printleader(tcp); - 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?...] */ + 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 (cflag) @@ -2424,8 +2395,8 @@ trace_syscall(struct tcb *tcp) if (res != 1) { tprintf(") "); tabto(acolumn); - tprintf("= ?"); - /* line will be finished by error handling code */ + tprintf("= ? "); + printtrailer(); tcp->flags &= ~TCB_INSYSCALL; return res; } @@ -2548,15 +2519,18 @@ trace_syscall(struct tcb *tcp) if (res != 1) { printleader(tcp); - tcp->flags &= ~TCB_REPRINT; /* why? */ + tcp->flags &= ~TCB_REPRINT; tcp_last = tcp; if (scno_good != 1) - tprintf("syscall_??" /* anti-trigraph gap */ "("); + tprintf("????" /* anti-trigraph gap */ "("); else if (tcp->scno >= nsyscalls || tcp->scno < 0) tprintf("syscall_%lu(", tcp->scno); else tprintf("%s(", sysent[tcp->scno].sys_name); - /* Line will be finished by error handling code. */ + /* + * " " will be added later by the code which + * detects ptrace errors. + */ tcp->flags |= TCB_INSYSCALL; return res; } @@ -2710,7 +2684,7 @@ struct tcb *tcp; #ifdef LINUX #if defined (SPARC) || defined (SPARC64) struct regs regs; - if (do_ptrace(PTRACE_GETREGS, tcp, (char *)®s, 0) < 0) + if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)®s,0) < 0) return -1; val = regs.r_o1; #elif defined(SH) diff --git a/test/childthread.c b/test/childthread.c index e89fb145..c580db29 100644 --- a/test/childthread.c +++ b/test/childthread.c @@ -1,7 +1,7 @@ /* Test exit of a child of a TCB_EXITING child where the toplevel process starts * waiting on it. The middle one gets detached and strace must update the * toplevel process'es number of attached children to 0. - * + * * gcc -o test/childthread test/childthread.c -Wall -ggdb2 -pthread;./strace -f ./test/childthread * It must print: write(1, "OK\n", ... */ diff --git a/test/leaderkill.c b/test/leaderkill.c index ebb6ad1c..67d5de15 100644 --- a/test/leaderkill.c +++ b/test/leaderkill.c @@ -1,7 +1,7 @@ /* Test handle_group_exit () handling of a thread leader still alive with its * thread child calling exit_group () and proper passing of the process exit * code to the process parent of this whole thread group. - * + * * gcc -o test/leaderkill test/leaderkill.c -Wall -ggdb2 -pthread;./test/leaderkill & pid=$!;sleep 1;strace -o x -q ./strace -f -p $pid * It must print: write(1, "OK\n", ... */ diff --git a/test/many_looping_threads.c b/test/many_looping_threads.c deleted file mode 100644 index 1f1fe052..00000000 --- a/test/many_looping_threads.c +++ /dev/null @@ -1,39 +0,0 @@ -/* This test is not yet added to Makefile */ - -#include -#include -#include -#include -#include -#include - -static int thd_no; - -static void *sub_thd(void *c) -{ - fprintf(stderr, "sub-thread %d created\n", ++thd_no); - for (;;) - getuid(); - return NULL; -} - -int main(int argc, char *argv[]) -{ - int i; - pthread_t *thd; - int num_threads = 1; - - if (argv[1]) - num_threads = atoi(argv[1]); - - thd = malloc(num_threads * sizeof(thd[0])); - fprintf(stderr, "test start, num_threads:%d...\n", num_threads); - - for (i = 0; i < num_threads; i++) { - pthread_create(&thd[i], NULL, sub_thd, NULL); - fprintf(stderr, "after pthread_create\n"); - } - - /* Exit. This kills all threads */ - return 0; -} diff --git a/util.c b/util.c index d9de3543..f41b0c39 100644 --- a/util.c +++ b/util.c @@ -241,103 +241,30 @@ xlookup(const struct xlat *xlat, int val) } /* - * Generic ptrace wrapper which tracks ptrace errors - * by setting tcp->ptrace_errno. + * Generic ptrace wrapper which tracks ESRCH errors + * by setting tcp->ptrace_errno to ESRCH. * * 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, long data) +do_ptrace(int request, struct tcb *tcp, void *addr, void *data) { - int err; long l; errno = 0; l = ptrace(request, tcp->pid, addr, data); - 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; - } + /* Non-ESRCH errors might be our invalid reg/mem accesses, + * we do not record them. */ + if (errno == ESRCH) + tcp->ptrace_errno = ESRCH; 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. @@ -346,21 +273,25 @@ do_ptrace5(int request, struct tcb *tcp, void *addr, long data, char *data2) * Otherwise prints error message and returns -1. */ int -ptrace_restart(int request, struct tcb *tcp, int sig) +ptrace_restart(int op, struct tcb *tcp, int sig) { int err; + const char *msg; errno = 0; - ptrace(request, tcp->pid, (void *) 1, (long) sig); + ptrace(op, tcp->pid, (void *) 1, (void *) (long) sig); err = errno; if (!err || err == ESRCH) return 0; tcp->ptrace_errno = 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 */ + 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)); return -1; } @@ -857,6 +788,7 @@ int umoven(struct tcb *tcp, long addr, int len, char *laddr) { #ifdef LINUX + int pid = tcp->pid; int n, m; int started = 0; union { @@ -868,17 +800,34 @@ 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 */ - u.val = do_ptrace_peekdata(tcp, (char *) addr, started); - if (errno) - return u.val; /* 0 or -1 */ + 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; + } started = 1; memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len)); addr += sizeof(long), laddr += m, len -= m; } while (len) { - u.val = do_ptrace_peekdata(tcp, (char *) addr, started); - if (errno) - return u.val; /* 0 or -1 */ + 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; + } started = 1; memcpy(laddr, u.x, m = MIN(sizeof(long), len)); addr += sizeof(long), laddr += m, len -= m; @@ -898,16 +847,24 @@ 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 */ - u.val = do_ptrace(PTRACE_PEEKDATA, tcp, (char *) addr, 0); - if (errno) + errno = 0; + u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0); + if (errno) { + if (errno != ESRCH) + perror("umoven"); return -1; + } memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len)); addr += sizeof(long), laddr += m, len -= m; } while (len) { - u.val = do_ptrace(PTRACE_PEEKDATA, tcp, (char *) addr, 0); - if (errno) + errno = 0; + u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0); + if (errno) { + if (errno != ESRCH) + perror("umoven"); return -1; + } memcpy(laddr, u.x, m = MIN(sizeof(long), len)); addr += sizeof(long), laddr += m, len -= m; } @@ -917,7 +874,12 @@ umoven(struct tcb *tcp, long addr, int len, char *laddr) while (len) { n = MIN(len, PAGSIZ); n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr); - if (do_ptrace5(PTRACE_READDATA, tcp, (char *) addr, len, laddr) < 0) { + if (ptrace(PTRACE_READDATA, pid, + (char *) addr, len, laddr) < 0) { + if (errno != ESRCH) { + perror("umoven: ptrace(PTRACE_READDATA, ...)"); + abort(); + } return -1; } len -= n; @@ -979,6 +941,7 @@ 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; @@ -989,9 +952,17 @@ 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 */ - u.val = do_ptrace_peekdata(tcp, (char *)addr, started); - if (errno) - return u.val; /* 0 or -1 */ + 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; + } started = 1; memcpy(laddr, &u.x[n], m = MIN(sizeof(long)-n,len)); while (n & (sizeof(long) - 1)) @@ -1000,9 +971,17 @@ umovestr(struct tcb *tcp, long addr, int len, char *laddr) addr += sizeof(long), laddr += m, len -= m; } while (len) { - u.val = do_ptrace_peekdata(tcp, (char *)addr, started); - if (errno) - return u.val; /* 0 or -1 */ + 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; + } started = 1; memcpy(laddr, u.x, m = MIN(sizeof(long), len)); for (i = 0; i < sizeof(long); i++) @@ -1025,7 +1004,12 @@ umovestr(struct tcb *tcp, long addr, int len, char *laddr) #ifdef SUNOS4 static int -uload(int cmd, struct tcb *tcp, long addr, int len, char *laddr) +uload(cmd, pid, addr, len, laddr) +int cmd; +int pid; +long addr; +int len; +char *laddr; { # if 0 int n; @@ -1033,7 +1017,8 @@ uload(int cmd, struct tcb *tcp, long addr, int len, char *laddr) while (len) { n = MIN(len, PAGSIZ); n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr); - if (do_ptrace5(cmd, tcp, (char *)addr, n, laddr) < 0) { + if (ptrace(cmd, pid, (char *)addr, n, laddr) < 0) { + perror("uload: ptrace(PTRACE_WRITE, ...)"); return -1; } len -= n; @@ -1060,39 +1045,50 @@ uload(int cmd, 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); - 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) { + errno = 0; + u.val = ptrace(peek, pid, (char *) addr, 0); + if (errno) { + perror("uload: POKE"); return -1; } - addr += sizeof(long); - laddr += m; - len -= m; + 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; } - errno = 0; while (len) { if (len < sizeof(long)) - 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) { + 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"); return -1; } - addr += sizeof(long); - laddr += m; - len -= m; + addr += sizeof(long), laddr += m, len -= m; } # endif return 0; } -static int -tload(struct tcb *tcp, int addr, int len, char *laddr) +int +tload(pid, addr, len, laddr) +int pid; +int addr, len; +char *laddr; { - return uload(PTRACE_WRITETEXT, tcp, addr, len, 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); } #endif /* SUNOS4 */ @@ -1100,7 +1096,10 @@ tload(struct tcb *tcp, int addr, int len, char *laddr) #ifndef USE_PROCFS int -upeek(struct tcb *tcp, long off, long *res) +upeek(tcp, off, res) +struct tcb *tcp; +long off; +long *res; { long val; @@ -1127,9 +1126,16 @@ upeek(struct tcb *tcp, long off, long *res) off += 1024; } # endif /* SUNOS4_KERNEL_ARCH_KLUDGE */ + errno = 0; val = do_ptrace(PTRACE_PEEKUSER, tcp, (char *) off, 0); - if (errno) + if (val == -1 && errno) { + if (errno != ESRCH) { + char buf[60]; + sprintf(buf,"upeek: ptrace(PTRACE_PEEKUSER,%d,%lu,0)", tcp->pid, off); + perror(buf); + } return -1; + } *res = val; return 0; } @@ -1175,17 +1181,17 @@ getpc(struct tcb *tcp) return -1; # elif defined(SPARC) || defined(SPARC64) struct regs regs; - if (do_ptrace(PTRACE_GETREGS, tcp, (char *) ®s, 0) < 0) + if (ptrace(PTRACE_GETREGS,tcp->pid,(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) @@ -1201,8 +1207,10 @@ getpc(struct tcb *tcp) */ struct regs regs; - if (do_ptrace(PTRACE_GETREGS, tcp, (char *) ®s, 0) < 0) + if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) ®s, 0) < 0) { + perror("getpc: ptrace(PTRACE_GETREGS, ...)"); return -1; + } return regs.r_pc; #endif /* SUNOS4 */ @@ -1238,7 +1246,7 @@ printcall(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; } @@ -1290,7 +1298,7 @@ printcall(struct tcb *tcp) tprintf("[%08lx] ", pc); # elif defined(SPARC) || defined(SPARC64) struct regs regs; - if (do_ptrace(PTRACE_GETREGS, tcp, (char *) ®s, 0) < 0) { + if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)®s,0) < 0) { PRINTBADPC; return; } @@ -1298,7 +1306,7 @@ printcall(struct tcb *tcp) # elif defined(HPPA) long pc; - if (upeek(tcp, PT_IAOQ0, &pc) < 0) { + if(upeek(tcp,PT_IAOQ0,&pc) < 0) { tprintf ("[????????] "); return; } @@ -1373,7 +1381,8 @@ printcall(struct tcb *tcp) #ifdef SUNOS4 struct regs regs; - if (do_ptrace(PTRACE_GETREGS, tcp, (char *) ®s, 0) < 0) { + if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) ®s, 0) < 0) { + perror("printcall: ptrace(PTRACE_GETREGS, ...)"); PRINTBADPC; return; } @@ -1494,9 +1503,9 @@ set_arg0 (struct tcb *tcp, arg_setup_state *state, long val) req = PTRACE_POKEUSER; } else ap = ia64_rse_skip_regs(*state, 0); - if (do_ptrace(req, tcp, ap, val) < 0) - return -1; - return 0; + errno = 0; + ptrace(req, tcp->pid, ap, val); + return errno ? -1 : 0; } static int @@ -1510,9 +1519,9 @@ set_arg1 (struct tcb *tcp, arg_setup_state *state, long val) req = PTRACE_POKEUSER; } else ap = ia64_rse_skip_regs(*state, 1); - if (do_ptrace(req, tcp, ap, val) < 0) - return -1; - return 0; + errno = 0; + ptrace(req, tcp->pid, ap, val); + return errno ? -1 : 0; } /* ia64 does not return the input arguments from functions (and syscalls) @@ -1526,9 +1535,9 @@ set_arg1 (struct tcb *tcp, arg_setup_state *state, long val) typedef struct regs arg_setup_state; # define arg_setup(tcp, state) \ - (do_ptrace(PTRACE_GETREGS, tcp, (char *) (state), 0)) + (ptrace (PTRACE_GETREGS, tcp->pid, (char *) (state), 0)) # define arg_finish_change(tcp, state) \ - (do_ptrace(PTRACE_SETREGS, tcp, (char *) (state), 0)) + (ptrace (PTRACE_SETREGS, tcp->pid, (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) @@ -1598,15 +1607,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 do_ptrace(PTRACE_POKEUSER, tcp, (char*)arg0_offset, val); + return ptrace (PTRACE_POKEUSER, tcp->pid, (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 do_ptrace(PTRACE_POKEUSER, tcp, (char*)arg1_offset, val); + return ptrace (PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val); } # endif /* architectures */ @@ -1736,13 +1745,17 @@ struct tcb *tcp; fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid); return -1; } - if (do_ptrace(PTRACE_GETREGS, tcp, (char *)®s, 0) < 0) { + if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)®s, 0) < 0) { + perror("setbpt: ptrace(PTRACE_GETREGS, ...)"); return -1; } tcp->baddr = regs.r_o7 + 8; - tcp->inst[0] = do_ptrace(PTRACE_PEEKTEXT, tcp, (char *)tcp->baddr, 0); - if (errno) + errno = 0; + tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)tcp->baddr, 0); + if(errno) { + perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)"); return -1; + } /* * XXX - BRUTAL MODE ON @@ -1760,8 +1773,11 @@ struct tcb *tcp; inst <<= 32; inst |= (tcp->inst[0] & 0xffffffffUL); # endif - if (do_ptrace(PTRACE_POKETEXT, tcp, (char *) tcp->baddr, inst) < 0) + ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, inst); + if(errno) { + perror("setbpt: ptrace(PTRACE_POKETEXT, ...)"); return -1; + } tcp->flags |= TCB_BPTSET; # else /* !SPARC && !SPARC64 */ @@ -1778,11 +1794,17 @@ struct tcb *tcp; if (debug) fprintf(stderr, "[%d] setting bpt at %lx\n", tcp->pid, tcp->baddr); - tcp->inst[0] = do_ptrace(PTRACE_PEEKTEXT, tcp, (char *) tcp->baddr, 0); - if (errno) + tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid, + (char *) tcp->baddr, 0); + if (errno) { + perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)"); return -1; - if (do_ptrace(PTRACE_POKETEXT, tcp, (char *) tcp->baddr, LOOP) < 0) + } + ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOP); + if (errno) { + perror("setbpt: ptrace(PTRACE_POKETEXT, ...)"); return -1; + } tcp->flags |= TCB_BPTSET; } else { /* @@ -1808,15 +1830,21 @@ struct tcb *tcp; /* store "ri" in low two bits */ tcp->baddr = addr | ((ipsr >> 41) & 0x3); - 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) + 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, ...)"); return -1; + } - if (do_ptrace(PTRACE_POKETEXT, tcp, (char *) addr + 0, LOOP0) < 0 - || do_ptrace(PTRACE_POKETEXT, tcp, (char *) addr + 8, LOOP1) < 0 - ) { + 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, ...)"); return -1; } tcp->flags |= TCB_BPTSET; @@ -1888,10 +1916,14 @@ struct tcb *tcp; # endif if (debug) fprintf(stderr, "[%d] setting bpt at %lx\n", tcp->pid, tcp->baddr); - tcp->inst[0] = do_ptrace(PTRACE_PEEKTEXT, tcp, (char *) tcp->baddr, 0); - if (errno) + tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *) tcp->baddr, 0); + if (errno) { + perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)"); return -1; - if (do_ptrace(PTRACE_POKETEXT, tcp, (char *) tcp->baddr, LOOP) < 0) { + } + ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOP); + if (errno) { + perror("setbpt: ptrace(PTRACE_POKETEXT, ...)"); return -1; } tcp->flags |= TCB_BPTSET; @@ -1918,12 +1950,14 @@ struct tcb *tcp; fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid); return -1; } - if (do_ptrace(PTRACE_GETREGS, tcp, (char *)®s, 0) < 0) { + if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)®s, 0) < 0) { + perror("setbpt: ptrace(PTRACE_GETREGS, ...)"); return -1; } tcp->baddr = regs.r_o7 + 8; - if (do_ptrace5(PTRACE_READTEXT, tcp, (char *)tcp->baddr, - sizeof tcp->inst, (char *)tcp->inst, "READTEXT") < 0) { + if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr, + sizeof tcp->inst, (char *)tcp->inst) < 0) { + perror("setbpt: ptrace(PTRACE_READTEXT, ...)"); return -1; } @@ -1937,8 +1971,9 @@ struct tcb *tcp; * generated by out PTRACE_ATTACH. * Of cause, if we evaporate ourselves in the middle of all this... */ - if (do_ptrace5(PTRACE_WRITETEXT, tcp, (char *) tcp->baddr, + if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr, sizeof loopdeloop, (char *) loopdeloop) < 0) { + perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)"); return -1; } tcp->flags |= TCB_BPTSET; @@ -1976,7 +2011,10 @@ struct tcb *tcp; fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid); return -1; } - if (do_ptrace(PTRACE_POKETEXT, tcp, (char *) tcp->baddr, tcp->inst[0]) < 0) { + errno = 0; + ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]); + if(errno) { + perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)"); return -1; } tcp->flags &= ~TCB_BPTSET; @@ -1990,7 +2028,10 @@ struct tcb *tcp; fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid); return -1; } - if (do_ptrace(PTRACE_POKETEXT, tcp, (char *) tcp->baddr, tcp->inst[0]) < 0) { + errno = 0; + ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]); + if (errno) { + perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)"); return -1; } tcp->flags &= ~TCB_BPTSET; @@ -2017,15 +2058,20 @@ struct tcb *tcp; return -1; /* restore original bundle: */ - 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 - ) { + 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, ...)"); return -1; } /* restore original "ri" in ipsr: */ ipsr = (ipsr & ~(0x3ul << 41)) | ((tcp->baddr & 0x3) << 41); - if (do_ptrace(PTRACE_POKEUSER, tcp, (char *) PT_CR_IPSR, ipsr) < 0) { + errno = 0; + ptrace(PTRACE_POKEUSER, pid, (char *) PT_CR_IPSR, ipsr); + if (errno) { + perror("clrbpt: ptrace(PTRACE_POKEUSER, ...)"); return -1; } @@ -2047,7 +2093,10 @@ struct tcb *tcp; fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid); return -1; } - if (do_ptrace(PTRACE_POKETEXT, tcp, (char *) tcp->baddr, tcp->inst[0]) < 0) { + errno = 0; + ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]); + if (errno) { + perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)"); return -1; } tcp->flags &= ~TCB_BPTSET; @@ -2120,11 +2169,8 @@ struct tcb *tcp; * safe to set both IAOQ0 and IAOQ1 to that so the PSW N bit * has no significant effect. */ - if (do_ptrace(PTRACE_POKEUSER, tcp, (void *)PT_IAOQ0, iaoq) < 0 - || do_ptrace(PTRACE_POKEUSER, tcp, (void *)PT_IAOQ1, iaoq) < 0 - ) { - return -1; - } + ptrace(PTRACE_POKEUSER, tcp->pid, (void *)PT_IAOQ0, iaoq); + ptrace(PTRACE_POKEUSER, tcp->pid, (void *)PT_IAOQ1, iaoq); # elif defined(SH) if (upeek(tcp, 4*REG_PC, &pc) < 0) return -1; @@ -2151,8 +2197,9 @@ struct tcb *tcp; fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid); return -1; } - if (do_ptrace5(PTRACE_WRITETEXT, tcp, (char *) tcp->baddr, + if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr, sizeof tcp->inst, (char *) tcp->inst) < 0) { + perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)"); return -1; } tcp->flags &= ~TCB_BPTSET; @@ -2162,10 +2209,12 @@ 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 (do_ptrace(PTRACE_GETREGS, tcp, (char *)®s, 0) < 0) { + if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)®s, 0) < 0) { + perror("clearbpt: ptrace(PTRACE_GETREGS, ...)"); 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, @@ -2179,7 +2228,8 @@ struct tcb *tcp; regs.r_pc, tcp->baddr); regs.r_pc = tcp->baddr; - if (do_ptrace(PTRACE_SETREGS, tcp, (char *)®s, 0) < 0) { + if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)®s, 0) < 0) { + perror("clearbpt: ptrace(PTRACE_SETREGS, ...)"); return -1; } # endif /* LOOPA */ @@ -2250,7 +2300,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; @@ -2275,7 +2325,7 @@ struct tcb *tcp; * Write entire symbol table back to avoid * memory alignment bugs in ptrace */ - if (tload(tcp, (int)ld.ld_symbols + (int)N_TXTADDR(hdr), + if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr), (int)ld.ld_symb_size, strtab) < 0) goto err;