* Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
* Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
* Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
- * Copyright (c) 1999-2017 The strace developers.
+ * Copyright (c) 1999-2018 The strace developers.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
#include "defs.h"
#include <stdarg.h>
-#include <sys/param.h>
+#include <limits.h>
#include <fcntl.h>
+#include "ptrace.h"
#include <signal.h>
#include <sys/resource.h>
#include <sys/wait.h>
#endif
#include <asm/unistd.h>
+#include "largefile_wrappers.h"
#include "number_set.h"
#include "scno.h"
-#include "ptrace.h"
#include "printsiginfo.h"
#include "trace_event.h"
#include "xstring.h"
#ifdef USE_LIBUNWIND
" stack-unwind"
#endif /* USE_LIBUNWIND */
+#ifdef USE_DEMANGLE
+ " stack-demangle"
+#endif /* USE_DEMANGLE */
+#if SUPPORTED_PERSONALITIES > 1
+# if defined HAVE_M32_MPERS
+ " m32-mpers"
+# else
+ " no-m32-mpers"
+# endif
+#endif /* SUPPORTED_PERSONALITIES > 1 */
+#if SUPPORTED_PERSONALITIES > 2
+# if defined HAVE_MX32_MPERS
+ " mx32-mpers"
+# else
+ " no-mx32-mpers"
+# endif
+#endif /* SUPPORTED_PERSONALITIES > 2 */
"";
printf("%s -- version %s\n"
}
}
-#ifdef _LARGEFILE64_SOURCE
-# ifdef HAVE_FOPEN64
-# define fopen_for_output fopen64
-# else
-# define fopen_for_output fopen
-# endif
-# define struct_stat struct stat64
-# define stat_file stat64
-# define struct_dirent struct dirent64
-# define read_dir readdir64
-# define struct_rlimit struct rlimit64
-# define set_rlimit setrlimit64
-#else
-# define fopen_for_output fopen
-# define struct_stat struct stat
-# define stat_file stat
-# define struct_dirent struct dirent
-# define read_dir readdir
-# define struct_rlimit struct rlimit
-# define set_rlimit setrlimit
-#endif
-
static FILE *
strace_fopen(const char *path)
{
return fp;
}
+static void
+outf_perror(const struct tcb * const tcp)
+{
+ if (tcp->outf == stderr)
+ return;
+
+ /* This is ugly, but we don't store separate file names */
+ if (followfork >= 2)
+ perror_msg("%s.%u", outfname, tcp->pid);
+ else
+ perror_msg("%s", outfname);
+}
+
ATTRIBUTE_FORMAT((printf, 1, 0))
static void
tvprintf(const char *const fmt, va_list args)
int n = vfprintf(current_tcp->outf, fmt, args);
if (n < 0) {
/* very unlikely due to vfprintf buffering */
- if (current_tcp->outf != stderr)
- perror_msg("%s", outfname);
+ outf_perror(current_tcp);
} else
current_tcp->curcol += n;
}
return;
}
/* very unlikely due to fputs_unlocked buffering */
- if (current_tcp->outf != stderr)
- perror_msg("%s", outfname);
+ outf_perror(current_tcp);
}
}
static void
flush_tcp_output(const struct tcb *const tcp)
{
- if (fflush(tcp->outf) && tcp->outf != stderr)
- perror_msg("%s", outfname);
+ if (fflush(tcp->outf))
+ outf_perror(tcp);
}
void
}
}
+void
+set_current_tcp(const struct tcb *tcp)
+{
+ current_tcp = (struct tcb *) tcp;
+
+ /* Sync current_personality and stuff */
+ if (current_tcp)
+ set_personality(current_tcp->currpers);
+}
+
void
printleader(struct tcb *tcp)
{
printing_tcp = tcp;
if (printing_tcp) {
- current_tcp = printing_tcp;
+ set_current_tcp(printing_tcp);
if (printing_tcp->curcol != 0 && (followfork < 2 || printing_tcp == tcp)) {
/*
* case 1: we have a shared log (i.e. not -ff), and last line
}
printing_tcp = tcp;
- current_tcp = tcp;
+ set_current_tcp(tcp);
current_tcp->curcol = 0;
if (print_pid_pfx)
}
#endif
+ mmap_cache_delete(tcp, __func__);
+
nprocs--;
debug_msg("dropped tcb for pid %d, %d remain", tcp->pid, nprocs);
}
if (current_tcp == tcp)
- current_tcp = NULL;
+ set_current_tcp(NULL);
if (printing_tcp == tcp)
printing_tcp = NULL;
if (followfork < 2 && printing_tcp && printing_tcp != tcp
&& printing_tcp->curcol != 0) {
- current_tcp = printing_tcp;
+ set_current_tcp(printing_tcp);
tprints(" <unfinished ...>\n");
flush_tcp_output(printing_tcp);
printing_tcp->curcol = 0;
- current_tcp = tcp;
+ set_current_tcp(tcp);
}
if ((followfork < 2 && printing_tcp != tcp)
*/
tprints(" <unfinished ...>");
}
+
+ printing_tcp = tcp;
tprints(") ");
tabto();
tprints("= ?\n");
return TE_NEXT;
}
- clear_regs();
+ clear_regs(tcp);
/* Set current output file */
- current_tcp = tcp;
+ set_current_tcp(tcp);
if (cflag) {
tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
return true;
case TE_STOP_BEFORE_EXECVE:
+ /*
+ * Check that we are inside syscall now (next event after
+ * PTRACE_EVENT_EXEC should be for syscall exiting). If it is
+ * not the case, we might have a situation when we attach to a
+ * process and the first thing we see is a PTRACE_EVENT_EXEC
+ * and all the following syscall state tracking is screwed up
+ * otherwise.
+ */
+ if (entering(current_tcp)) {
+ int ret;
+
+ error_msg("Stray PTRACE_EVENT_EXEC from pid %d"
+ ", trying to recover...",
+ current_tcp->pid);
+
+ current_tcp->flags |= TCB_RECOVERING;
+ ret = trace_syscall(current_tcp, &restart_sig);
+ current_tcp->flags &= ~TCB_RECOVERING;
+
+ if (ret < 0) {
+ /* The reason is described in TE_SYSCALL_STOP */
+ return true;
+ }
+ }
+
/*
* Under Linux, execve changes pid to thread leader's pid,
* and we see this changed pid on EVENT_EXEC and later,
* On 2.6 and earlier, it can return garbage.
*/
if (os_release >= KERNEL_VERSION(3, 0, 0))
- current_tcp = maybe_switch_tcbs(current_tcp, current_tcp->pid);
+ set_current_tcp(maybe_switch_tcbs(current_tcp,
+ current_tcp->pid));
if (detach_on_execve) {
if (current_tcp->flags & TCB_SKIP_DETACH_ON_FIRST_EXEC) {