#include <pwd.h>
#include <grp.h>
#include <dirent.h>
+#include <locale.h>
#include <sys/utsname.h>
#ifdef HAVE_PRCTL
# include <sys/prctl.h>
extern int optind;
extern char *optarg;
-#ifdef USE_LIBUNWIND
+#ifdef ENABLE_STACKTRACE
/* if this is true do the stack trace for every system call */
bool stack_trace_enabled;
#endif
static int acolumn = DEFAULT_ACOLUMN;
static char *acolumn_spaces;
+/* Default output style for xlat entities */
+enum xlat_style xlat_verbosity = XLAT_STYLE_ABBREV;
+
static const char *outfname;
/* If -ff, points to stderr. Else, it's our common output log */
static FILE *shared_log;
+static bool open_append;
struct tcb *printing_tcp;
static struct tcb *current_tcp;
print_version(void)
{
static const char features[] =
-#ifdef USE_LIBUNWIND
- " stack-unwind"
-#endif /* USE_LIBUNWIND */
+#ifdef ENABLE_STACKTRACE
+ " stack-trace=" USE_UNWINDER
+#endif
#ifdef USE_DEMANGLE
" stack-demangle"
-#endif /* USE_DEMANGLE */
+#endif
#if SUPPORTED_PERSONALITIES > 1
# if defined HAVE_M32_MPERS
" m32-mpers"
-a column alignment COLUMN for printing syscall results (default %d)\n\
-i print instruction pointer at time of syscall\n\
"
-#ifdef USE_LIBUNWIND
+#ifdef ENABLE_STACKTRACE
"\
- -k obtain stack trace between each syscall (experimental)\n\
+ -k obtain stack trace between each syscall\n\
"
#endif
"\
if (flags == newflags)
return;
- fcntl(fd, F_SETFD, newflags); /* never fails */
+ if (fcntl(fd, F_SETFD, newflags)) /* never fails */
+ perror_msg_and_die("fcntl(%d, F_SETFD, %#x)", fd, newflags);
}
static void
FILE *fp;
swap_uid();
- fp = fopen_stream(path, "w");
+ fp = fopen_stream(path, open_append ? "a" : "w");
if (!fp)
perror_msg_and_die("Can't fopen '%s'", path);
swap_uid();
if (tflag) {
struct timespec ts;
- clock_gettime(rflag ? CLOCK_MONOTONIC : CLOCK_REALTIME, &ts);
+ clock_gettime(CLOCK_REALTIME, &ts);
- if (rflag) {
- static struct timespec ots;
- if (ots.tv_sec == 0)
- ots = ts;
-
- struct timespec dts;
- ts_sub(&dts, &ts, &ots);
- ots = ts;
-
- tprintf("%6ld.%06ld ",
- (long) dts.tv_sec, (long) dts.tv_nsec / 1000);
- } else if (tflag > 2) {
+ if (tflag > 2) {
tprintf("%lld.%06ld ",
(long long) ts.tv_sec, (long) ts.tv_nsec / 1000);
} else {
time_t local = ts.tv_sec;
- char str[sizeof("HH:MM:SS")];
+ char str[MAX(sizeof("HH:MM:SS"), sizeof(ts.tv_sec) * 3)];
+ struct tm *tm = localtime(&local);
- strftime(str, sizeof(str), "%T", localtime(&local));
+ if (tm)
+ strftime(str, sizeof(str), "%T", tm);
+ else
+ xsprintf(str, "%lld", (long long) local);
if (tflag > 1)
tprintf("%s.%06ld ",
str, (long) ts.tv_nsec / 1000);
tprintf("%s ", str);
}
}
+
+ if (rflag) {
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+
+ static struct timespec ots;
+ if (ots.tv_sec == 0)
+ ots = ts;
+
+ struct timespec dts;
+ ts_sub(&dts, &ts, &ots);
+ ots = ts;
+
+ tprintf("%s%6ld.%06ld%s ",
+ tflag ? "(+" : "",
+ (long) dts.tv_sec, (long) dts.tv_nsec / 1000,
+ tflag ? ")" : "");
+ }
+
if (iflag)
print_pc(tcp);
}
* may create bogus empty FILE.<nonexistant_pid>, and then die.
*/
static void
-newoutf(struct tcb *tcp)
+after_successful_attach(struct tcb *tcp, const unsigned int flags)
{
+ tcp->flags |= TCB_ATTACHED | TCB_STARTUP | flags;
tcp->outf = shared_log; /* if not -ff mode, the same file is for all */
if (followfork >= 2) {
char name[PATH_MAX];
xsprintf(name, "%s.%u", outfname, tcp->pid);
tcp->outf = strace_fopen(name);
}
+
+#ifdef ENABLE_STACKTRACE
+ if (stack_trace_enabled)
+ unwind_tcb_init(tcp);
+#endif
}
static void
#if SUPPORTED_PERSONALITIES > 1
tcp->currpers = current_personality;
#endif
-
-#ifdef USE_LIBUNWIND
- if (stack_trace_enabled)
- unwind_tcb_init(tcp);
-#endif
-
nprocs++;
debug_msg("new tcb for pid %d, active tcbs:%d",
tcp->pid, nprocs);
free_tcb_priv_data(tcp);
-#ifdef USE_LIBUNWIND
- if (stack_trace_enabled) {
+#ifdef ENABLE_STACKTRACE
+ if (stack_trace_enabled)
unwind_tcb_fin(tcp);
- }
#endif
- mmap_cache_delete(tcp, __func__);
+ if (tcp->mmap_cache)
+ tcp->mmap_cache->free_fn(tcp, __func__);
nprocs--;
debug_msg("dropped tcb for pid %d, %d remain", tcp->pid, nprocs);
return;
}
- tcp->flags |= TCB_ATTACHED | TCB_GRABBED | TCB_STARTUP |
- post_attach_sigstop;
- newoutf(tcp);
+ after_successful_attach(tcp, TCB_GRABBED | post_attach_sigstop);
debug_msg("attach to pid %d (main) succeeded", tcp->pid);
static const char task_path[] = "/proc/%d/task";
ptrace_attach_cmd, tid);
continue;
}
- debug_msg("attach to pid %d succeeded", tid);
- struct tcb *tid_tcp = alloctcb(tid);
- tid_tcp->flags |= TCB_ATTACHED | TCB_GRABBED |
- TCB_STARTUP | post_attach_sigstop;
- newoutf(tid_tcp);
+ after_successful_attach(alloctcb(tid),
+ TCB_GRABBED | post_attach_sigstop);
+ debug_msg("attach to pid %d succeeded", tid);
}
closedir(dir);
kill(pid, SIGCONT);
}
tcp = alloctcb(pid);
- tcp->flags |= TCB_ATTACHED | TCB_STARTUP
- | TCB_SKIP_DETACH_ON_FIRST_EXEC
- | (NOMMU_SYSTEM ? 0 : (TCB_HIDE_LOG | post_attach_sigstop));
- newoutf(tcp);
+ after_successful_attach(tcp, TCB_SKIP_DETACH_ON_FIRST_EXEC
+ | (NOMMU_SYSTEM ? 0
+ : (TCB_HIDE_LOG
+ | post_attach_sigstop)));
} else {
/* With -D, we are *child* here, the tracee is our parent. */
strace_child = strace_tracer_pid;
strace_tracer_pid = getpid();
tcp = alloctcb(strace_child);
tcp->flags |= TCB_SKIP_DETACH_ON_FIRST_EXEC | TCB_HIDE_LOG;
- /* attaching will be done later, by startup_attach */
- /* note: we don't do newoutf(tcp) here either! */
+ /*
+ * Attaching will be done later, by startup_attach.
+ * Note: we don't do after_successful_attach() here either!
+ */
/* NOMMU BUG! -D mode is active, we (child) return,
* and we will scribble over parent's stack!
#endif
qualify("signal=all");
while ((c = getopt(argc, argv, "+"
-#ifdef USE_LIBUNWIND
+#ifdef ENABLE_STACKTRACE
"k"
#endif
- "a:b:cCdDe:E:fFhiI:o:O:p:P:qrs:S:tTu:vVwxyz")) != EOF) {
+ "a:Ab:cCdDe:E:fFhiI:o:O:p:P:qrs:S:tTu:vVwxX:yz")) != EOF) {
switch (c) {
case 'a':
acolumn = string_to_uint(optarg);
if (acolumn < 0)
error_opt_arg(c, optarg);
break;
+ case 'A':
+ open_append = true;
+ break;
case 'b':
if (strcmp(optarg, "execve") != 0)
error_msg_and_die("Syscall '%s' for -b isn't supported",
if (opt_intr <= 0)
error_opt_arg(c, optarg);
break;
-#ifdef USE_LIBUNWIND
+#ifdef ENABLE_STACKTRACE
case 'k':
stack_trace_enabled = true;
break;
case 'x':
xflag++;
break;
+ case 'X':
+ if (!strcmp(optarg, "raw"))
+ xlat_verbosity = XLAT_STYLE_RAW;
+ else if (!strcmp(optarg, "abbrev"))
+ xlat_verbosity = XLAT_STYLE_ABBREV;
+ else if (!strcmp(optarg, "verbose"))
+ xlat_verbosity = XLAT_STYLE_VERBOSE;
+ else
+ error_opt_arg(c, optarg);
+ break;
case 'y':
show_fd_path++;
break;
if (cflag == CFLAG_ONLY_STATS) {
if (iflag)
error_msg("-%c has no effect with -c", 'i');
-#ifdef USE_LIBUNWIND
+#ifdef ENABLE_STACKTRACE
if (stack_trace_enabled)
error_msg("-%c has no effect with -c", 'k');
#endif
error_msg("-%c has no effect with -c", 'y');
}
- if (rflag) {
- if (tflag > 1)
- error_msg("-tt has no effect with -r");
- tflag = 1;
- }
-
acolumn_spaces = xmalloc(acolumn + 1);
memset(acolumn_spaces, ' ', acolumn);
acolumn_spaces[acolumn] = '\0';
set_sighandler(SIGCHLD, SIG_DFL, ¶ms_for_tracee.child_sa);
-#ifdef USE_LIBUNWIND
- if (stack_trace_enabled) {
- unsigned int tcbi;
-
+#ifdef ENABLE_STACKTRACE
+ if (stack_trace_enabled)
unwind_init();
- for (tcbi = 0; tcbi < tcbtabsize; ++tcbi) {
- unwind_tcb_init(tcbtab[tcbi]);
- }
- }
#endif
/* See if they want to run as another user. */
if (followfork) {
/* We assume it's a fork/vfork/clone child */
struct tcb *tcp = alloctcb(pid);
- tcp->flags |= TCB_ATTACHED | TCB_STARTUP | post_attach_sigstop;
- newoutf(tcp);
+ after_successful_attach(tcp, post_attach_sigstop);
if (!qflag)
error_msg("Process %d attached", pid);
return tcp;
int
main(int argc, char *argv[])
{
+ setlocale(LC_ALL, "");
init(argc, argv);
exit_code = !nprocs;