Test how PTRACE_SETOPTIONS support works
Currently test fork related options only. Fork a child that uses PTRACE_TRACEME at startup and then does a fork so strace can test how the PTRACE_SETOPTIONS support works before it handles any real tracee. Since PTRACE_O_TRACECLONE/*FORK were introduced to kernel at the same time, this test seems to be enough for these 3 options. * defs.h [LINUX]: Define PTRACE_O_TRACECLONE et al macros here. (ptrace_setoptions): New variable declaration. * strace.c [LINUX] (test_ptrace_setoptions): New function, tests whether kernel supports PTRACE_O_CLONE/*FORK, the result is stored in the new variable ptrace_setoptions for later use. (main): Call test_ptrace_setoptions() if followfork option is set. Signed-off-by: Wang Chao <wang.chao@cn.fujitsu.com>
This commit is contained in:
parent
09fa7f8765
commit
b13c0de058
26
defs.h
26
defs.h
@ -308,6 +308,31 @@ extern int mp_ioctl (int f, int c, void *a, int s);
|
||||
#define PR_FAULTED S_CORE
|
||||
#endif
|
||||
|
||||
#ifdef LINUX
|
||||
# ifndef PTRACE_SETOPTIONS
|
||||
# define PTRACE_SETOPTIONS 0x4200
|
||||
# endif
|
||||
# ifndef PTRACE_O_TRACEFORK
|
||||
# define PTRACE_O_TRACEFORK 0x00000002
|
||||
# endif
|
||||
# ifndef PTRACE_O_TRACEVFORK
|
||||
# define PTRACE_O_TRACEVFORK 0x00000004
|
||||
# endif
|
||||
# ifndef PTRACE_O_TRACECLONE
|
||||
# define PTRACE_O_TRACECLONE 0x00000008
|
||||
# endif
|
||||
|
||||
# ifndef PTRACE_EVENT_FORK
|
||||
# define PTRACE_EVENT_FORK 1
|
||||
# endif
|
||||
# ifndef PTRACE_EVENT_VFORK
|
||||
# define PTRACE_EVENT_VFORK 2
|
||||
# endif
|
||||
# ifndef PTRACE_EVENT_CLONE
|
||||
# define PTRACE_EVENT_CLONE 3
|
||||
# endif
|
||||
#endif /* LINUX */
|
||||
|
||||
/* Trace Control Block */
|
||||
struct tcb {
|
||||
short flags; /* See below for TCB_ values */
|
||||
@ -470,6 +495,7 @@ typedef enum {
|
||||
extern struct tcb **tcbtab;
|
||||
extern int *qual_flags;
|
||||
extern int debug, followfork;
|
||||
extern unsigned int ptrace_setoptions;
|
||||
extern int dtime, xflag, qflag;
|
||||
extern cflag_t cflag;
|
||||
extern int acolumn;
|
||||
|
81
strace.c
81
strace.c
@ -83,6 +83,7 @@ extern char *optarg;
|
||||
|
||||
|
||||
int debug = 0, followfork = 0;
|
||||
unsigned int ptrace_setoptions = 0;
|
||||
int dtime = 0, xflag = 0, qflag = 0;
|
||||
cflag_t cflag = CFLAG_NONE;
|
||||
static int iflag = 0, interactive = 0, pflag_seen = 0, rflag = 0, tflag = 0;
|
||||
@ -686,6 +687,77 @@ startup_child (char **argv)
|
||||
#endif /* USE_PROCFS */
|
||||
}
|
||||
|
||||
#ifdef LINUX
|
||||
/*
|
||||
* Test whether kernel support PTRACE_O_TRACECLONE et al options.
|
||||
* First fork a new child, call ptrace with PTRACE_SETOPTIONS on it,
|
||||
* and then see which options are supported on this kernel.
|
||||
*/
|
||||
static int
|
||||
test_ptrace_setoptions(void)
|
||||
{
|
||||
int pid;
|
||||
|
||||
if ((pid = fork()) < 0)
|
||||
return -1;
|
||||
else if (pid == 0) {
|
||||
if (ptrace(PTRACE_TRACEME, 0, (char *)1, 0) < 0) {
|
||||
_exit(1);
|
||||
}
|
||||
kill(getpid(), SIGSTOP);
|
||||
if ((pid = fork()) < 0) {
|
||||
_exit(1);
|
||||
}
|
||||
_exit(0);
|
||||
}
|
||||
else {
|
||||
int status, tracee_pid, error;
|
||||
int no_child = 0;
|
||||
while (1) {
|
||||
tracee_pid = wait4(-1, &status, 0, NULL);
|
||||
error = errno;
|
||||
if (tracee_pid == -1) {
|
||||
switch (error) {
|
||||
case EINTR:
|
||||
continue;
|
||||
case ECHILD:
|
||||
no_child = 1;
|
||||
break;
|
||||
default:
|
||||
errno = error;
|
||||
perror("test_ptrace_setoptions");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (no_child)
|
||||
break;
|
||||
if (tracee_pid != pid) {
|
||||
if (ptrace(PTRACE_CONT, tracee_pid, 0, 0) < 0 &&
|
||||
errno != ESRCH)
|
||||
kill(tracee_pid, SIGKILL);
|
||||
}
|
||||
else if (WIFSTOPPED(status)) {
|
||||
if (status >> 16 == PTRACE_EVENT_FORK)
|
||||
ptrace_setoptions |= (PTRACE_O_TRACEVFORK |
|
||||
PTRACE_O_TRACECLONE |
|
||||
PTRACE_O_TRACEFORK);
|
||||
if (WSTOPSIG(status) == SIGSTOP) {
|
||||
if (ptrace(PTRACE_SETOPTIONS, pid, NULL,
|
||||
PTRACE_O_TRACEFORK) < 0) {
|
||||
kill(pid, SIGKILL);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0 &&
|
||||
errno != ESRCH)
|
||||
kill(pid, SIGKILL);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
@ -914,6 +986,15 @@ main(int argc, char *argv[])
|
||||
interactive = 0;
|
||||
qflag = 1;
|
||||
}
|
||||
|
||||
#ifdef LINUX
|
||||
if (followfork && test_ptrace_setoptions() < 0) {
|
||||
fprintf(stderr, "Test for options supported by PTRACE_SETOPTIONS\
|
||||
failed, give up using this feature\n");
|
||||
ptrace_setoptions = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Valid states here:
|
||||
optind < argc pflag_seen outfname interactive
|
||||
1 0 0 1
|
||||
|
Loading…
Reference in New Issue
Block a user