Revert unapproved commits.
This commit is contained in:
parent
4ac9d627f4
commit
eb9e2e8904
136
ChangeLog
136
ChangeLog
@ -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
21
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 *));
|
||||
|
2
desc.c
2
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("{...}");
|
||||
}
|
||||
|
63
process.c
63
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", },
|
||||
|
7
signal.c
7
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;
|
||||
}
|
||||
|
384
strace.c
384
strace.c
@ -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;
|
||||
|
@ -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
132
syscall.c
@ -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) ®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("= ? <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 *)®s, 0) < 0)
|
||||
if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)®s,0) < 0)
|
||||
return -1;
|
||||
val = regs.r_o1;
|
||||
#elif defined(SH)
|
||||
|
@ -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", ...
|
||||
*/
|
||||
|
@ -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", ...
|
||||
*/
|
||||
|
@ -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
430
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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user