Revert unapproved commits.

This commit is contained in:
Roland McGrath 2009-06-02 16:49:22 -07:00
parent 4ac9d627f4
commit eb9e2e8904
12 changed files with 419 additions and 801 deletions

136
ChangeLog
View File

@ -1,8 +1,5 @@
2009-06-01 Dmitry V. Levin <ldv@altlinux.org>
* 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 <dvlasenk@redhat.com>
* strace.c (collect_stopped_tcbs): Do not enable/disable signals
multiple times, do it just once per collecting pass.
2009-04-16 Denys Vlasenko <dvlasenk@redhat.com>
* 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 <dvlasenk@redhat.com>
* 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 <dvlasenk@redhat.com>
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 <dvlasenk@redhat.com>
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 <dvlasenk@redhat.com>
* process.c: Indent preprocessor directives so that nesting
@ -192,17 +156,6 @@
[HAVE_STRUCT_SIGCONTEXT].
From Muttley Meen <muttley.meen@gmail.com>.
2009-02-10 Denys Vlasenko <dvlasenk@redhat.com>
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 <dvlasenk@redhat.com>
* 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 <dvlasenk@redhat.com>
* 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 "<unavailable>" markers.
2009-01-27 Denys Vlasenko <dvlasenk@redhat.com>
* strace.c (collect_stopped_tcbs): Guard against the case when
waitpid() reports the same task multiple times.
2009-01-26 Denys Vlasenko <dvlasenk@redhat.com>
* 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 <dvlasenk@redhat.com>
* 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 <dvlasenk@redhat.com>
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 <dvlasenk@redhat.com>
* 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 <dvlasenk@redhat.com>
* 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 <dvlasenk@redhat.com>
* 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 <dvlasenk@redhat.com>
* 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 <dvlasenk@redhat.com>
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 <dvlasenk@redhat.com>
* 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 <kirill@shutemov.name>
* 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 <dvlasenk@redhat.com>
* 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 <dvlasenk@redhat.com>
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 <dvlasenk@redhat.com>
Make strace detect when traced process suddenly disappeared

21
defs.h
View File

@ -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 *));

2
desc.c
View File

@ -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("{...}");
}

View File

@ -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", },

View File

@ -1403,13 +1403,14 @@ sys_sigreturn(struct tcb *tcp)
struct regs regs;
m_siginfo_t si;
if (do_ptrace(PTRACE_GETREGS, tcp, (char *)&regs, 0) < 0) {
if(ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 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;
}

384
strace.c
View File

@ -40,7 +40,6 @@
#include <sys/resource.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/utsname.h>
#include <pwd.h>
#include <grp.h>
#include <string.h>
@ -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(" <unavailable>");
else
tprintf(" <ptrace error %d (%s)>", err, strerror(err));
printtrailer();
if (err == ESRCH)
/* Want to get death report anyway. */
goto tracing;
/* Strange error, we dare not continue. */
if (tcp->flags & TCB_ATTACHED) {
if (tcp_last) {
/* Do we have dangling line "syscall(param, param"?
* Finish the line then. We cannot
*/
tcp_last->flags |= TCB_REPRINT;
tprintf(" <unfinished ...>");
printtrailer();
}
detach(tcp, 0);
} else {
ptrace(PTRACE_KILL, tcp->pid, (char *) 1, SIGTERM);
/* [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(" <unavailable ...>\n");
else
tprintf(" <ptrace error %d (%s) ...>\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("= <unavailable>\n");
else
tprintf("= <ptrace error %d (%s)>\n", err, strerror(err));
tprintf(" <unavailable>)");
tabto(acolumn);
}
tprintf("= ? <unavailable>\n");
tcp_last->ptrace_errno = 0;
} else if (!outfname || followfork < 2 || tcp_last == tcp) {
tprintf(" <unfinished ...>\n");
tcp_last->flags |= TCB_REPRINT;
tprintf(" <unfinished ...>\n");
}
}
curcol = 0;

View File

@ -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

132
syscall.c
View File

@ -38,39 +38,38 @@
#include <signal.h>
#include <time.h>
#include <errno.h>
#include <sched.h>
#include <sys/user.h>
#include <sys/syscall.h>
#include <sys/param.h>
#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 <asm/reg.h>
# if defined (SPARC) || defined (SPARC64)
#endif
#include <asm/reg.h>
#if defined (SPARC) || defined (SPARC64)
# undef fpq
# undef fq
# undef fpu
# endif
#endif
#endif
#ifdef HAVE_SYS_REG_H
# include <sys/reg.h>
# ifndef PTRACE_PEEKUSR
# define PTRACE_PEEKUSR PTRACE_PEEKUSER
# endif
#include <sys/reg.h>
#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 <linux/ptrace.h>
#include <linux/ptrace.h>
# 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) &regs) < 0)
if (ptrace (PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 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) &regs) < 0)
if (ptrace (PTRACE_GETREGS, pid, NULL, (long) &regs) < 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("= ? <unavailable>");
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. */
/*
* " <unavailable>" 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 *)&regs, 0) < 0)
if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
return -1;
val = regs.r_o1;
#elif defined(SH)

View File

@ -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", ...
*/

View File

@ -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", ...
*/

View File

@ -1,39 +0,0 @@
/* This test is not yet added to Makefile */
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <stdlib.h>
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;
}

430
util.c
View File

@ -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 *) &regs, 0) < 0)
if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,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 *) &regs, 0) < 0)
if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 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 *) &regs, 0) < 0) {
if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,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 *) &regs, 0) < 0) {
if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 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 *)&regs, 0) < 0) {
if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 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 *)&regs, 0) < 0) {
if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 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 *)&regs, 0) < 0) {
if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 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 *)&regs, 0) < 0) {
if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 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;