*
* Make sure that all entries in all syscallent.h files
* have nargs <= MAX_ARGS!
- * linux/<ARCH>/syscallent.h: ia64 has many syscalls with
- * nargs = 8, mips has two with nargs = 7 (both are printargs),
- * all others are <= 6.
+ * linux/<ARCH>/syscallent.h: all have nargs <= 6.
* freebsd/i386/syscallent.h: one syscall with nargs = 8
* (sys_sendfile, looks legitimate)
* and one with nargs = 7 (sys_mmap, maybe it should have 6?).
* sunos4/syscallent.h: all are <= 6.
- * svr4/syscallent.h: all are -1.
+ * svr4/syscallent.h: all are MA (MAX_ARGS), it's unclear what the real max is.
*/
#ifndef MAX_ARGS
-# ifdef HPPA
+# if defined LINUX
+# define MAX_ARGS 6
+# elif defined HPPA
# define MAX_ARGS 6
# elif defined X86_64 || defined I386
# ifdef FREEBSD
#endif
#ifdef USE_PROCFS
-#include <sys/procfs.h>
-#ifdef HAVE_MP_PROCFS
-#include <sys/uio.h>
-#endif
-#ifdef FREEBSD
-#include <sys/pioctl.h>
-#endif /* FREEBSD */
+# include <sys/procfs.h>
+# ifdef HAVE_MP_PROCFS
+# include <sys/uio.h>
+# endif
+# ifdef FREEBSD
+# include <sys/pioctl.h>
+# endif
#else /* !USE_PROCFS */
-#if (defined(LINUXSPARC) || defined(LINUX_X86_64) || defined(LINUX_ARM) || defined(LINUX_AVR32)) && defined(__GLIBC__)
-#include <sys/ptrace.h>
-#else
+# if (defined(LINUXSPARC) || defined(LINUX_X86_64) || defined(LINUX_ARM) || defined(LINUX_AVR32)) && defined(__GLIBC__)
+# include <sys/ptrace.h>
+# else
/* Work around awkward prototype in ptrace.h. */
-#define ptrace xptrace
-#include <sys/ptrace.h>
-#undef ptrace
-#ifdef POWERPC
-#define __KERNEL__
-#include <asm/ptrace.h>
-#undef __KERNEL__
-#endif
-#ifdef LINUX
+# define ptrace xptrace
+# include <sys/ptrace.h>
+# undef ptrace
+# ifdef POWERPC
+# define __KERNEL__
+# include <asm/ptrace.h>
+# undef __KERNEL__
+# endif
+# ifdef LINUX
extern long ptrace(int, int, char *, long);
-#else /* !LINUX */
+# else
extern int ptrace(int, int, char *, int, ...);
-#endif /* !LINUX */
-#endif /* !LINUXSPARC */
-#endif /* !SVR4 */
+# endif
+# endif
+#endif /* !USE_PROCFS */
#ifdef LINUX
#if !defined(__GLIBC__)
#define PTRACE_PEEKUSER PTRACE_PEEKUSR
#define PTRACE_POKEUSER PTRACE_POKEUSR
#endif
+#if defined(X86_64) || defined(I386)
+/* For struct pt_regs. x86 strace uses PTRACE_GETREGS.
+ * PTRACE_GETREGS returns registers in the layout of this struct.
+ */
+# include <asm/ptrace.h>
+#endif
#ifdef ALPHA
# define REG_R0 0
# define REG_A0 16
struct tcb {
int flags; /* See below for TCB_ values */
int pid; /* Process Id of this entry */
+ int u_nargs; /* System call argument count */
+ int u_error; /* Error code */
long scno; /* System call number */
- int u_nargs; /* System call arguments */
long u_arg[MAX_ARGS]; /* System call arguments */
#if defined (LINUX_MIPSN32)
long long ext_arg[MAX_ARGS]; /* System call arguments */
#endif
- int u_error; /* Error code */
long u_rval; /* (first) return value */
#ifdef HAVE_LONG_LONG
long long u_lrval; /* long long return value */
#endif
- FILE *outf; /* Output file for this process */
+ int ptrace_errno;
int curcol; /* Output column for this process */
+ FILE *outf; /* Output file for this process */
const char *auxstr; /* Auxiliary info from syscall (see RVAL_STR) */
struct timeval stime; /* System time usage as of last process wait */
struct timeval dtime; /* Delta for system time usage */
/* Support for tracing forked processes */
long baddr; /* `Breakpoint' address */
long inst[2]; /* Instructions on above */
+#ifdef USE_PROCFS
int pfd; /* proc file descriptor */
+#endif
#ifdef SVR4
-#ifdef HAVE_MP_PROCFS
+# ifdef HAVE_MP_PROCFS
int pfd_stat;
int pfd_as;
pstatus_t status;
-#else
+# else
prstatus_t status; /* procfs status structure */
+# endif
#endif
-#endif
- int ptrace_errno;
#ifdef FREEBSD
struct procfs_status status;
int pfd_reg;
/* TCB flags */
#define TCB_STARTUP 00001 /* We have just begun ptracing this process */
#define TCB_INUSE 00002 /* This table entry is in use */
-#define TCB_INSYSCALL 00004 /* A system call is in progress */
+/*
+ * Are we in system call entry or in syscall exit?
+ *
+ * This bit is set after all syscall entry processing is done.
+ * Therefore, this bit will be set when next ptrace stop occurs,
+ * which should be syscall exit stop. Other stops which are possible
+ * directly after syscall entry (death, ptrace event stop)
+ * are simpler and handled without calling trace_syscall(), therefore
+ * the places where TCB_INSYSCALL can be set but we aren't in syscall stop
+ * are limited to trace(), this condition is never observed in trace_syscall()
+ * and below.
+ * The bit is cleared after all syscall exit processing is done.
+ * User-generated SIGTRAPs and post-execve SIGTRAP make it necessary
+ * to be very careful and NOT set TCB_INSYSCALL bit when they are encountered.
+ * TCB_WAITEXECVE bit is used for this purpose (see below).
+ *
+ * Use entering(tcp) / exiting(tcp) to check this bit to make code more readable.
+ */
+#define TCB_INSYSCALL 00004
#define TCB_ATTACHED 00010 /* Process is not our own child */
#ifdef LINUX
#define TCB_ATTACH_DONE 00020 /* PTRACE_ATTACH was done on this tcb->pid */
#define TCB_FILTERED 02000 /* This system call has been filtered out */
#ifdef LINUX
/* 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().
+ * It can detect SIGTRAP by looking at eax/rax.
+ * See "not a syscall entry (eax = %ld)\n" message
+ * in syscall_fixup_on_sysenter().
*/
# if defined(ALPHA) || defined(AVR32) || defined(SPARC) || defined(SPARC64) \
|| defined(POWERPC) || defined(IA64) || defined(HPPA) \
|| defined(SH) || defined(SH64) || defined(S390) || defined(S390X) \
|| defined(ARM) || defined(MIPS) || defined(BFIN) || defined(TILE)
-# define TCB_WAITEXECVE 04000 /* ignore SIGTRAP after execve */
+/* This tracee has entered into execve syscall. Expect post-execve SIGTRAP
+ * to happen. (When it is detected, tracee is continued and this bit is cleared.)
+ */
+# define TCB_WAITEXECVE 04000
# endif
# include <sys/syscall.h>
# ifndef __NR_exit_group
extern unsigned int ptrace_setoptions;
extern int dtime, xflag, qflag;
extern cflag_t cflag;
-extern int acolumn;
extern int max_strlen;
extern struct tcb *tcp_last;
void perror_msg(const char *fmt, ...) __attribute__ ((format(printf, 1, 2)));
void error_msg_and_die(const char *fmt, ...) __attribute__ ((noreturn, format(printf, 1, 2)));
void perror_msg_and_die(const char *fmt, ...) __attribute__ ((noreturn, format(printf, 1, 2)));
+void die_out_of_memory(void) __attribute__ ((noreturn));
extern void set_personality(int personality);
extern const char *xlookup(const struct xlat *, int);
extern void set_sortby(const char *);
extern void set_overhead(int);
extern void qualify(const char *);
+#ifdef USE_PROCFS
extern int get_scno(struct tcb *);
+#endif
extern long known_scno(struct tcb *);
extern long do_ptrace(int request, struct tcb *tcp, void *addr, void *data);
extern int ptrace_restart(int request, struct tcb *tcp, int sig);
-extern int force_result(struct tcb *, int, long);
extern int trace_syscall(struct tcb *);
-extern int count_syscall(struct tcb *, struct timeval *);
+extern void count_syscall(struct tcb *, struct timeval *);
extern void printxval(const struct xlat *, int, const char *);
extern int printargs(struct tcb *);
extern void addflags(const struct xlat *, int);
extern void printpath(struct tcb *, long);
extern void printpathn(struct tcb *, long, int);
extern void printtv_bitness(struct tcb *, long, enum bitness_t, int);
-extern void sprinttv(struct tcb *, long, enum bitness_t, char *);
+extern char *sprinttv(struct tcb *, long, enum bitness_t, char *);
extern void print_timespec(struct tcb *, long);
extern void sprint_timespec(char *, struct tcb *, long);
#ifdef HAVE_SIGINFO_T
extern void printsignal(int);
extern void printleader(struct tcb *);
extern void printtrailer(void);
-extern void tabto(int);
+extern void tabto(void);
extern void call_summary(FILE *);
extern void tprint_iov(struct tcb *, unsigned long, unsigned long, int decode_iov);
extern void tprint_open_modes(mode_t);
extern void tv_mul(struct timeval *, struct timeval *, int);
extern void tv_div(struct timeval *, struct timeval *, int);
+/* Some libc have stpcpy, some don't. Sigh...
+ * Roll our private implementation...
+ */
+#undef stpcpy
+#define stpcpy strace_stpcpy
+extern char *stpcpy(char *dst, const char *src);
+
#ifdef SUNOS4
extern int fixvfork(struct tcb *);
#endif
printtv_bitness((tcp), (addr), BITNESS_CURRENT, 1)
extern void tprintf(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
+extern void tprints(const char *str);
#ifndef HAVE_STRERROR
const char *strerror(int);
extern const int personality_wordsize[];
struct sysent {
- int nargs;
+ unsigned nargs;
int sys_flags;
int (*sys_func)();
const char *sys_name;
long native_scno; /* Match against SYS_* constants. */
};
-extern const struct sysent *sysent;
-extern int nsyscalls;
-
-extern const char *const *errnoent;
-extern int nerrnos;
-
struct ioctlent {
const char *doth;
const char *symbol;
unsigned long code;
};
+extern const struct sysent *sysent;
+extern unsigned nsyscalls;
+extern const char *const *errnoent;
+extern unsigned nerrnos;
extern const struct ioctlent *ioctlent;
-extern int nioctlents;
-
+extern unsigned nioctlents;
extern const char *const *signalent;
-extern int nsignals;
-
-extern const struct ioctlent ioctlent0[];
-extern const int nioctlents0;
-extern const char *const signalent0[];
-extern const int nsignals0;
-
-#if SUPPORTED_PERSONALITIES >= 2
-extern const struct ioctlent ioctlent1[];
-extern const int nioctlents1;
-extern const char *const signalent1[];
-extern const int nsignals1;
-#endif /* SUPPORTED_PERSONALITIES >= 2 */
-
-#if SUPPORTED_PERSONALITIES >= 3
-extern const struct ioctlent ioctlent2[];
-extern const int nioctlents2;
-extern const char *const signalent2[];
-extern const int nsignals2;
-#endif /* SUPPORTED_PERSONALITIES >= 3 */
+extern unsigned nsignals;
+
+#define SCNO_IN_RANGE(scno) ((unsigned long)(scno) < nsyscalls)
#if HAVE_LONG_LONG