#ifdef USE_LIBUNWIND
/* if this is true do the stack trace for every system call */
-bool stack_trace_enabled = false;
+bool stack_trace_enabled;
#endif
#define my_tkill(tid, sig) syscall(__NR_tkill, (tid), (sig))
const unsigned int syscall_trap_sig = SIGTRAP | 0x80;
cflag_t cflag = CFLAG_NONE;
-unsigned int followfork = 0;
+unsigned int followfork;
unsigned int ptrace_setoptions = PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEEXEC
| PTRACE_O_TRACEEXIT;
-unsigned int xflag = 0;
-bool debug_flag = 0;
-bool Tflag = 0;
-bool iflag = 0;
-bool count_wallclock = 0;
-unsigned int qflag = 0;
-static unsigned int tflag = 0;
-static bool rflag = 0;
-static bool print_pid_pfx = 0;
+unsigned int xflag;
+bool debug_flag;
+bool Tflag;
+bool iflag;
+bool count_wallclock;
+unsigned int qflag;
+static unsigned int tflag;
+static bool rflag;
+static bool print_pid_pfx;
/* -I n */
enum {
- INTR_NOT_SET = 0,
- INTR_ANYWHERE = 1, /* don't block/ignore any signals */
- INTR_WHILE_WAIT = 2, /* block fatal signals while decoding syscall. default */
- INTR_NEVER = 3, /* block fatal signals. default if '-o FILE PROG' */
- INTR_BLOCK_TSTP_TOO = 4, /* block fatal signals and SIGTSTP (^Z) */
- NUM_INTR_OPTS
+ INTR_NOT_SET = 0,
+ INTR_ANYWHERE = 1, /* don't block/ignore any signals */
+ INTR_WHILE_WAIT = 2, /* block fatal signals while decoding syscall. default */
+ INTR_NEVER = 3, /* block fatal signals. default if '-o FILE PROG' */
+ INTR_BLOCK_TSTP_TOO = 4, /* block fatal signals and SIGTSTP (^Z) */
+ NUM_INTR_OPTS
};
static int opt_intr;
/* We play with signal mask only if this mode is active: */
* wait() etc. Without -D, strace process gets lodged in between,
* disrupting parent<->child link.
*/
-static bool daemonized_tracer = 0;
+static bool daemonized_tracer;
#if USE_SEIZE
static int post_attach_sigstop = TCB_IGNORE_ONE_SIGSTOP;
#endif
/* Sometimes we want to print only succeeding syscalls. */
-bool not_failing_only = 0;
+bool not_failing_only;
/* Show path associated with fd arguments */
-unsigned int show_fd_path = 0;
+unsigned int show_fd_path;
-static bool detach_on_execve = 0;
+static bool detach_on_execve;
static int exit_code;
-static int strace_child = 0;
-static int strace_tracer_pid = 0;
+static int strace_child;
+static int strace_tracer_pid;
-static char *username = NULL;
+static char *username;
static uid_t run_uid;
static gid_t run_gid;
static int acolumn = DEFAULT_ACOLUMN;
static char *acolumn_spaces;
-static char *outfname = NULL;
+static char *outfname;
/* If -ff, points to stderr. Else, it's our common output log */
static FILE *shared_log;
-struct tcb *printing_tcp = NULL;
+struct tcb *printing_tcp;
static struct tcb *current_tcp;
static struct tcb **tcbtab;
static unsigned int nprocs, tcbtabsize;
-static const char *progname;
+
+#ifndef HAVE_PROGRAM_INVOCATION_NAME
+char *program_invocation_name;
+#endif
unsigned os_release; /* generated from uname()'s u.release */
msg = NULL;
if (vasprintf(&msg, fmt, p) >= 0) {
if (err_no)
- fprintf(stderr, "%s: %s: %s\n", progname, msg, strerror(err_no));
+ fprintf(stderr, "%s: %s: %s\n",
+ program_invocation_name, msg, strerror(err_no));
else
- fprintf(stderr, "%s: %s\n", progname, msg);
+ fprintf(stderr, "%s: %s\n",
+ program_invocation_name, msg);
free(msg);
} else {
/* malloc in vasprintf failed, try it without malloc */
- fprintf(stderr, "%s: ", progname);
+ fprintf(stderr, "%s: ", program_invocation_name);
vfprintf(stderr, fmt, p);
if (err_no)
fprintf(stderr, ": %s\n", strerror(err_no));
va_start(p, fmt);
verror_msg(0, fmt, p);
}
- fprintf(stderr, "Try '%s -h' for more information.\n", progname);
+ fprintf(stderr, "Try '%s -h' for more information.\n",
+ program_invocation_name);
die();
}
return fp;
}
-static int popen_pid = 0;
+static int popen_pid;
#ifndef _PATH_BSHELL
# define _PATH_BSHELL "/bin/sh"
swap_uid();
fp = fdopen(fds[1], "w");
if (!fp)
- die_out_of_memory();
+ perror_msg_and_die("fdopen");
return fp;
}
tprintf("%6ld.%06ld ",
(long) dtv.tv_sec, (long) dtv.tv_usec);
otv = tv;
- }
- else if (tflag > 2) {
+ } else if (tflag > 2) {
tprintf("%ld.%06ld ",
(long) tv.tv_sec, (long) tv.tv_usec);
- }
- else {
+ } else {
time_t local = tv.tv_sec;
strftime(str, sizeof(str), "%T", localtime(&local));
if (tflag > 1)
goto wait_loop;
if (errno != ESRCH)
perror_msg("detach: ptrace(PTRACE_INTERRUPT,%u)", tcp->pid);
- }
- else {
+ } else {
error = my_tkill(tcp->pid, SIGSTOP);
if (!error)
goto wait_loop;
* pidof uses space as delim, pgrep uses newline. :(
*/
int pid;
- char *delim = opt + strcspn(opt, ", \n\t");
+ char *delim = opt + strcspn(opt, "\n\t ,");
char c = *delim;
*delim = '\0';
if (setreuid(run_uid, params->run_euid) < 0) {
perror_msg_and_die("setreuid");
}
- }
- else if (geteuid() != 0)
+ } else if (geteuid() != 0)
if (setreuid(run_uid, run_uid) < 0) {
perror_msg_and_die("setreuid");
}
if (colon) {
n = colon - path;
m = n + 1;
- }
- else
+ } else
m = n = strlen(path);
if (n == 0) {
if (!getcwd(pathname, PATH_MAX))
continue;
len = strlen(pathname);
- }
- else if (n > sizeof pathname - 1)
+ } else if (n > sizeof(pathname) - 1)
continue;
else {
strncpy(pathname, path, n);
| TCB_SKIP_DETACH_ON_FIRST_EXEC
| (NOMMU_SYSTEM ? 0 : (TCB_HIDE_LOG | post_attach_sigstop));
newoutf(tcp);
- }
- else {
+ } else {
/* With -D, we are *child* here, the tracee is our parent. */
strace_child = strace_tracer_pid;
strace_tracer_pid = getpid();
error_msg_and_die("Bad OS release string: '%s'", u.release);
/* Note: this open-codes KERNEL_VERSION(): */
rel = (rel << 8) | atoi(p);
- if (rel >= KERNEL_VERSION(1,0,0))
+ if (rel >= KERNEL_VERSION(1, 0, 0))
break;
while (*p >= '0' && *p <= '9')
p++;
if (*p != '.') {
- if (rel >= KERNEL_VERSION(0,1,0)) {
+ if (rel >= KERNEL_VERSION(0, 1, 0)) {
/* "X.Y-something" means "X.Y.0" */
rel <<= 8;
break;
int c, i;
int optF = 0;
- progname = argv[0] ? argv[0] : "strace";
+ if (!program_invocation_name || !*program_invocation_name) {
+ static char name[] = "strace";
+ program_invocation_name =
+ (argv[0] && *argv[0]) ? argv[0] : name;
+ }
strace_tracer_pid = getpid();
break;
case 's':
i = string_to_uint(optarg);
- if (i < 0)
+ if (i < 0 || (unsigned int) i > -1U / 4)
error_opt_arg(c, optarg);
max_strlen = i;
break;
#endif
case 'E':
if (putenv(optarg) < 0)
- die_out_of_memory();
+ perror_msg_and_die("putenv");
break;
case 'I':
opt_intr = string_to_uint_upto(optarg, NUM_INTR_OPTS - 1);
break;
}
}
- argv += optind;
- /* argc -= optind; - no need, argc is not used below */
- acolumn_spaces = xmalloc(acolumn + 1);
- memset(acolumn_spaces, ' ', acolumn);
- acolumn_spaces[acolumn] = '\0';
+ argv += optind;
+ argc -= optind;
- if (!argv[0] && !nprocs) {
+ if (argc < 0 || (!argv[0] && !nprocs)) {
error_msg_and_help("must have PROG [ARGS] or -p PID");
}
tflag = 1;
}
+ acolumn_spaces = xmalloc(acolumn + 1);
+ memset(acolumn_spaces, ' ', acolumn);
+ acolumn_spaces[acolumn] = '\0';
+
sigprocmask(SIG_SETMASK, NULL, &start_set);
memcpy(&blocked_set, &start_set, sizeof(blocked_set));
}
run_uid = pent->pw_uid;
run_gid = pent->pw_gid;
- }
- else {
+ } else {
run_uid = getuid();
run_gid = getgid();
}
if (followfork >= 2)
error_msg_and_help("piping the output and -ff are mutually exclusive");
shared_log = strace_popen(outfname + 1);
- }
- else if (followfork < 2)
+ } else if (followfork < 2)
shared_log = strace_fopen(outfname);
} else {
/* -ff without -o FILE is the same as single -f */
/*
* Used to exit simply when nprocs hits zero, but in this testcase:
- * int main() { _exit(!!fork()); }
+ * int main(void) { _exit(!!fork()); }
* under strace -f, parent sometimes (rarely) manages
* to exit before we see the first stop of the child,
* and we are losing track of it:
* Is this post-attach SIGSTOP?
* Interestingly, the process may stop
* with STOPSIG equal to some other signal
- * than SIGSTOP if we happend to attach
+ * than SIGSTOP if we happened to attach
* just before the process takes a signal.
*/
if (sig == SIGSTOP && (tcp->flags & TCB_IGNORE_ONE_SIGSTOP)) {
}
}
+static int
+trace_syscall(struct tcb *tcp, unsigned int *sig)
+{
+ if (entering(tcp)) {
+ int res = syscall_entering_decode(tcp);
+ switch (res) {
+ case 0:
+ return 0;
+ case 1:
+ res = syscall_entering_trace(tcp, sig);
+ }
+ syscall_entering_finish(tcp, res);
+ return res;
+ } else {
+ struct timeval tv = {};
+ int res = syscall_exiting_decode(tcp, &tv);
+ if (res != 0) {
+ res = syscall_exiting_trace(tcp, tv, res);
+ }
+ syscall_exiting_finish(tcp);
+ return res;
+ }
+}
+
/* Returns true iff the main trace loop has to continue. */
static bool
dispatch_event(enum trace_event ret, int *pstatus, siginfo_t *si)
* PTRACE_GETEVENTMSG returns old pid starting from Linux 3.0.
* On 2.6 and earlier, it can return garbage.
*/
- if (os_release >= KERNEL_VERSION(3,0,0))
+ if (os_release >= KERNEL_VERSION(3, 0, 0))
current_tcp = maybe_switch_tcbs(current_tcp, current_tcp->pid);
if (detach_on_execve) {
}
#ifdef ENABLE_COVERAGE_GCOV
-extern void __gcov_flush();
+extern void __gcov_flush(void);
#endif
-int
-main(int argc, char *argv[])
+static void ATTRIBUTE_NORETURN
+terminate(void)
{
- init(argc, argv);
-
- exit_code = !nprocs;
-
- int status;
- siginfo_t si;
- while (dispatch_event(next_event(&status, &si), &status, &si))
- ;
-
cleanup();
fflush(NULL);
if (shared_log != stderr)
Exit with 128 + signo then. */
exit_code += 128;
}
+ exit(exit_code);
+}
- return exit_code;
+int
+main(int argc, char *argv[])
+{
+ init(argc, argv);
+
+ exit_code = !nprocs;
+
+ int status;
+ siginfo_t si;
+ while (dispatch_event(next_event(&status, &si), &status, &si))
+ ;
+ terminate();
}