[PATCH] Raise strace awareness
Eugene Syromyatnikov
evgsyr at gmail.com
Wed Apr 1 14:03:42 UTC 2020
After der Strauss awareness has been raised sufficiently[1][2], it is
time for den Strauss itself to raise the awareness about strace,
and to do so, the most modern and contemporary method has been elected:
displaying tips, tricks and tweaks on each run.
[1] https://lists.strace.io/pipermail/strace-devel/2019-April/008701.html
[2] https://gitlab.com/strace/strace/commit/e8194a46d619
* strace.c (init) <enum>: Add GETOPT_TIPS.
<longopts>: Add "no-tips" option.
(init) <case GETOPT_TIPS>: Set show_tips to false.
(terminate): Call print_totd.
(usage): Document --no-tips.
* strace.1.in (.SS Miscellaneous): Likewise.
* straus.c (STRAUS_BODY_LINES, MAX_TIP_LINES): New enums.
(tips_tricks_tweaks, tip_top, tip_bottom, tip_left, tip_right): New
static constants.
(show_tips): New variable.
(print_totd): New function.
* straus.h (show_tips, print_totd): New declarations.
* tests/bexecve.test: Supply --no-tips to strace invocations.
* tests/clone_ptrace.test: Likewise.
* tests/fflush.test: Likewise.
* tests/first_exec_failure.test: Likewise.
* tests/options-syntax.test: Likewise.
Suggested-by: Elvira Khabirova <lineprinter0 at gmail.com>
---
strace.1.in | 3 +
strace.c | 9 ++
straus.c | 272 ++++++++++++++++++++++++++++++++++++++++++
straus.h | 2 +
tests/bexecve.test | 8 +-
tests/clone_ptrace.test | 2 +-
tests/fflush.test | 2 +-
tests/first_exec_failure.test | 2 +-
tests/options-syntax.test | 3 +-
9 files changed, 295 insertions(+), 8 deletions(-)
diff --git a/strace.1.in b/strace.1.in
index 97ab3ae..5ad8d2c 100644
--- a/strace.1.in
+++ b/strace.1.in
@@ -1347,6 +1347,9 @@ option.
.B \-\-help
Print the help summary.
.TP
+.B \-\-no\-tips
+Do not show strace tips, tricks, and tweaks.
+.TP
.B \-\-seccomp\-bpf
Enable (experimental) usage of seccomp-bpf (see
.BR seccomp (2))
diff --git a/strace.c b/strace.c
index db6cb5f..18b8fed 100644
--- a/strace.c
+++ b/strace.c
@@ -436,6 +436,7 @@ Tampering:\n\
Miscellaneous:\n\
-d, --debug enable debug output to stderr\n\
-h, --help print help message\n\
+ --no-tips do not show strace tips, tricks, and tweaks\n\
--seccomp-bpf enable seccomp-bpf filtering\n\
-V, --version print version\n\
"
@@ -1903,6 +1904,7 @@ init(int argc, char *argv[])
GETOPT_FOLLOWFORKS,
GETOPT_OUTPUT_SEPARATELY,
GETOPT_TS,
+ GETOPT_TIPS,
GETOPT_QUAL_TRACE,
GETOPT_QUAL_ABBREV,
@@ -1957,6 +1959,7 @@ init(int argc, char *argv[])
{ "failed-only", no_argument, 0, 'Z' },
{ "failing-only", no_argument, 0, 'Z' },
{ "seccomp-bpf", no_argument, 0, GETOPT_SECCOMP },
+ { "no-tips", no_argument, 0, GETOPT_TIPS },
{ "trace", required_argument, 0, GETOPT_QUAL_TRACE },
{ "abbrev", required_argument, 0, GETOPT_QUAL_ABBREV },
@@ -2169,6 +2172,9 @@ init(int argc, char *argv[])
case GETOPT_SECCOMP:
seccomp_filtering = true;
break;
+ case GETOPT_TIPS:
+ show_tips = false;
+ break;
case GETOPT_QUAL_TRACE:
qualify_trace(optarg);
break;
@@ -3535,6 +3541,7 @@ terminate(void)
exit_code &= 0xff;
signal(exit_code, SIG_DFL);
GCOV_DUMP;
+ print_totd();
raise(exit_code);
/* Unblock the signal. */
@@ -3548,6 +3555,8 @@ terminate(void)
Exit with 128 + signo then. */
exit_code += 128;
}
+
+ print_totd();
exit(exit_code);
}
diff --git a/straus.c b/straus.c
index 0c815a2..6edc583 100644
--- a/straus.c
+++ b/straus.c
@@ -9,6 +9,10 @@
#include "defs.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+
#include "straus.h"
static const char *straus[] = {
@@ -61,6 +65,234 @@ static const char *straus[] = {
const size_t straus_lines = ARRAY_SIZE(straus);
+enum {
+ STRAUS_BODY_LINES = 37,
+ MAX_TIP_LINES = 13,
+};
+
+static const char *tips_tricks_tweaks[][MAX_TIP_LINES] = {
+ { "strace has an extensive manual page",
+ "that covers all the possible options",
+ "and contains several useful invocation",
+ "examples." },
+ { "You can use -o|COMMAND to redirect strace's",
+ "output to COMMAND. This may be useful",
+ "in cases when there is redirection in place",
+ "for the traced program." },
+ { "It's possible to display timestamps",
+ " produced by -r, -t, and -T options",
+ "with nanosecond precision using their",
+ "long variants: --relative-timestamps=ns,",
+ "--absolute-timestamps=ns, and",
+ "--syscall-times=ns, respectively.", "",
+ "Why microseconds are the default?",
+ "To preserve the historic output format",
+ "which was limited by struct timeval",
+ "precision." },
+ { "A particular quote from a particular novel",
+ "by Arthur C. Clarke is printed if an attempt",
+ "is made to attach to a particular process." },
+ { "It's possible to tune the environment",
+ "of the traced process using the -E/--env",
+ "option." },
+#if ENABLE_STACKTRACE
+ { "You can print a stack trace for each traced",
+ "call by specifying -k/--stack-traces option.",
+#if USE_DEMANGLE
+ "It can even demangle symbol names.",
+#endif
+ },
+#else
+ { "We would like to tell you that you could",
+ "specify -k/--stack-traces option to print",
+ "stack traces for each traced system call,",
+ "but unfortunately you can't, this strace",
+ "binary is built without stack tracing",
+ "support." },
+#endif
+ { "Have you ever hit by accidental overwrite",
+ "of the output file specified in the -o",
+ "option? Specify -A/--output-append-mode",
+ "as well, and this problem will never annoy",
+ "you again!" },
+ { "strace is about as old as the Linux kernel.",
+ "It has been originally written for SunOS",
+ "by Paul Kranenburg in 1991." },
+ { "strace is able to decode netlink messages.",
+ "It does so automatically for IO performed",
+ "on netlink sockets. Try it yourself:", "",
+ " strace -e%network ip a" },
+ { "Filtered syscalls, errors, and signals can",
+ "be specified either by name or by number,",
+ "for example:", "",
+ " strace --trace=0,1,2 --signal=2,15 true" },
+ { "It is possible to specify -r and -t options",
+ "simultaneously since strace 4.22." },
+ { "Strace can print only successful syscall",
+ "invocations when supplied with",
+ "-z/--successful-only option. There's also",
+ "a possibility to filter calls with other",
+ "statuses, please refer to -e status option",
+ "documentation." },
+ { "If you trace a process that uses KVM",
+ "subsystem, --kvm=vcpu option may be of use:",
+ "it prints KVM VCPU exit reason. It requires",
+ "Linux 4.16+, however." },
+ { "It is possible to get strace out of your way",
+ "(in terms of parent/child relationships and",
+ "signal communication) with -D/--daemonize",
+ "option. Another option that may be of use",
+ "in this case is -I/--interruptible, it",
+ "restricts the set of signals that interrupt",
+ "strace." },
+ { "If strace is too talky to your taste, you",
+ "can silence it with -qqq option." },
+ { "strace prints file paths along with file",
+ "descriptor numbers when it is invoked with",
+ "-y/--decode-fds option.",
+ "When -yy (or --decode-fds=all) is provided,",
+ "it also prints protocol-specific information",
+ "for sockets and device numbers for character",
+ "and block device files." },
+ { "You can control what columns are shown",
+ "in the call summary table produced by -c/-C",
+ "options with -U/--summary-columns option.",
+ "It is a way to print minimum/maximum call",
+ "duration, for example." },
+ { "If you feel that syscall duration shown",
+ "in the call summary table (-c/-C option)",
+ "is not right, you can try to use -w option",
+ "(that collects wall clock time instead),",
+ "maybe that is what you are looking for." },
+ { "strace understands -z option since 2002,",
+ "but it wasn't documented because its",
+ "implementation was broken. Only 17 years",
+ "later, in strace 5.2, it was properly",
+ "implemented and documented." },
+ { "If you feel that strace is too slow, you may",
+ "want to try --seccomp-bpf option, maybe you",
+ "will feel better." },
+ { "-v is a shorthand for -e abbrev=none and not",
+ " for -e verbose=all. It is idiosyncratic,",
+ "but it is the historic behaviour." },
+ { "strace uses netlink for printing",
+ "protocol-specific information about socket",
+ "descriptors (-yy option)." },
+ { "strace is able to tamper with tracees'",
+ "execution by injecting an arbitrary return",
+ "or error value instead of syscall execution,",
+ "for example:", "",
+ " strace --inject=unlink:retval=0", "",
+ "would prevent execution of unlink calls, but",
+ "would make the traced process think that",
+ "they have succeeded." },
+ { "strace's tampering capabilities include",
+ "injection of arbitrary return/error values,",
+ "injection of a signal, injection of a delay",
+ "before or after syscall execution." },
+ { "If you want to see numerical values of named",
+ "constants, there is an option for that:",
+ "-X/--const-print-style. When -Xraw",
+ "(or --const-print-style=raw) is provided,",
+ "strace prints just the numerical value",
+ "of an argument; with -Xverbose, it prints",
+ "values in both numerical and symbolic form." },
+ { "getpid syscall is present on all",
+ "architectures except on Alpha, where getxpid",
+ "syscall (that returns a pair of PID and PPID",
+ "in a pair of registers) is used instead.",
+ "Other two examples of syscalls that utilise",
+ "two registers for their return walues are",
+ "getxuid and getxgid the return a pair",
+ "of real and effective UIDs/GIDs." },
+ { "There are three syscalls that implement",
+ "generic \"open file\" task: open, openat,",
+ "and openat2. On some (newly supported)",
+ "architectures, open syscall is not present.",
+ "How to write a robust filtering expression",
+ "in this case? With conditional syntax,",
+ "for example:", "",
+ " strace --trace=?open,?openat,?openat2", "",
+ "You may wont to escape question marks, since",
+ "your shell may interpret them as a path glob",
+ "expression." },
+ { "It is possible to use regular expressions",
+ "for syscall names in the -e trace",
+ "expression, for example:", "",
+ " strace -e trace=/^sched_.*", "",
+ "will trace all scheduling-related syscalls." },
+ { "IA-64 (Itanium) uses syscall numbers",
+ "beginning from 1024, because numbers",
+ "beginning from 0 were used for i386 compat",
+ "layer. Other example of a sparse syscall",
+ "table is MIPS, with parts of it beginning",
+ "at index 0 (SVR4 ABI), 1000 (SysV ABI), 2000",
+ "(BSD 4.3 ABI), 3000 (POSIX ABI), 4000 (Linux",
+ "O32 ABI), 5000 (Linux N64 ABI), and 6000",
+ "(Linux N32 ABI)." },
+ { "Der Strauss, the strace's project mascot,",
+ "was conceived in 2017. It is a brainchild",
+ "of Vitaly Chaykovsky." },
+ { "Medicinal effects of strace can be achieved",
+ "by invoking it with the following options:", "",
+ " strace -DDDqqq -enone --signal=none" },
+ { "Your Internet connection is working fine.",
+ "No one replies to your e-mails because",
+ "there is no one left." },
+ { "It is possible to print absolute timestamps",
+ "with nanosecond precision using",
+ "--absolute-timestamps=ns option." },
+ { "You smell something not unlike rotting",
+ "meat every time you run me. I cannot",
+ "promise that the smell will ever go away,",
+ "or that will ever find its source.", "",
+ "But I can promise that you will learn",
+ "to love it." },
+ { "Historically, supplying -o option to strace",
+ "led to silencing of messages about tracee",
+ "attach/detach and personality changes.",
+ "It can be now overridden with --quiet=none",
+ "option." },
+ { "If you open your computer, inside you",
+ "will find a cloth doll, soft and worn.",
+ "You will suddenly remember owning this doll",
+ "as a child, loving and cherishing it.", "",
+ "Do not question the truth of this memory." },
+ { "You can avoid tracing of \"other programs\"",
+ "that are executed by the traced program",
+ "with -b execve option." },
+ { "Touch your monitor. It's warm, like flesh.",
+ "But it's not flesh.", "Not yet." },
+ { "-F option used to be a separate option",
+ "for following vfork calls." },
+ { "It is possible to provide multiple PIDs",
+ "to a single -p option with whitespace",
+ "or comma as accepted delimiter, in order",
+ "to support usage like", "",
+ " strace -p \"`pidof PROG`\"",
+ "or",
+ " strace -p \"`pgrep PROG`\"", "",
+ "pidof uses space as a delimiter, pgrep uses",
+ "newline." },
+};
+
+static const char tip_top[] =
+ " ______________________________________________ ";
+static const char top_bottom[] =
+ " \\______________________________________________/ ";
+static const char *tip_left[] = { " / ", " | "};
+static const char *tip_right[] = {
+ " \\ ",
+ " | ",
+ " \\ ",
+ " \\ ",
+ " _\\ ",
+ " / ",
+ " | ", };
+
+bool show_tips = true;
+
+
void
print_straus(size_t verbosity)
{
@@ -72,3 +304,43 @@ print_straus(size_t verbosity)
for (size_t i = 0; i < verbosity; i++)
puts(straus[i]);
}
+
+void
+print_totd(void)
+{
+ static bool printed = false;
+ const int w = (int) (sizeof(tip_top) - 1 - strlen(tip_left[0])
+ - strlen(tip_right[0]));
+ struct timeval tv;
+ size_t id;
+ size_t i;
+
+ if (printed || !show_tips)
+ return;
+
+ gettimeofday(&tv, NULL);
+ srand(tv.tv_sec ^ tv.tv_usec);
+ id = rand() % ARRAY_SIZE(tips_tricks_tweaks);
+
+ fprintf(stderr, "%s%s\n", tip_top, straus[1]);
+ fprintf(stderr, "%s%-*s%s%s\n",
+ tip_left[0], w, "", tip_right[0], straus[2]);
+ for (i = 0; (i < MAX_TIP_LINES) && (tips_tricks_tweaks[id][i] ||
+ (i < (ARRAY_SIZE(tip_right) - 1)));
+ i++) {
+ fprintf(stderr, "%s%-*.*s%s%s\n",
+ tip_left[MIN(i + 1, ARRAY_SIZE(tip_left) - 1)],
+ w, w, tips_tricks_tweaks[id][i] ?: "",
+ tip_right[MIN(i + 1, ARRAY_SIZE(tip_right) - 1)],
+ straus[MIN(3 + i, STRAUS_BODY_LINES)]);
+ }
+ fprintf(stderr, "%s%s\n",
+ top_bottom, straus[MIN(3 + i, STRAUS_BODY_LINES)]);
+ fprintf(stderr, "%*s%*s%*s%s\n",
+ (int) strlen(tip_left[0]), "",
+ w, "",
+ (int) strlen(tip_right[0]), "",
+ straus[MIN(4 + i, STRAUS_BODY_LINES)]);
+
+ printed = true;
+}
diff --git a/straus.h b/straus.h
index 04864b5..3347677 100644
--- a/straus.h
+++ b/straus.h
@@ -13,7 +13,9 @@
enum { STRAUS_START_VERBOSITY = 5 };
extern const size_t straus_lines;
+extern bool show_tips;
extern void print_straus(size_t verbosity);
+extern void print_totd(void);
#endif /* STRACE_STRAUS_H */
diff --git a/tests/bexecve.test b/tests/bexecve.test
index 4ed894e..18d917c 100755
--- a/tests/bexecve.test
+++ b/tests/bexecve.test
@@ -16,14 +16,14 @@ run_strace_redir()
$STRACE "$@" 2> "$LOG"
}
-run_strace_redir --quiet=personality -enone ../set_ptracer_any true ||
+run_strace_redir --quiet=personality --no-tips -enone ../set_ptracer_any true ||
dump_log_and_fail_with "$STRACE $args: unexpected exit status"
-run_strace_redir --quiet=personality -enone ../set_ptracer_any false
+run_strace_redir --quiet=personality --no-tips -enone ../set_ptracer_any false
[ $? -eq 1 ] ||
dump_log_and_fail_with "$STRACE $args: unexpected exit status"
-run_strace_redir --quiet=personality -bexecve -enone ../set_ptracer_any false ||
+run_strace_redir --quiet=personality --no-tips -bexecve -enone ../set_ptracer_any false ||
dump_log_and_fail_with "$STRACE $args: unexpected exit status"
pattern_detached='[^:]*strace: Process [1-9][0-9]* detached'
@@ -35,7 +35,7 @@ if LC_ALL=C grep -E -v -x "$pattern_detached" "$LOG" > /dev/null; then
dump_log_and_fail_with "$STRACE $args: unexpected output"
fi
-run_strace_redir --quiet=personality --seccomp-bpf -bexecve -enone ../set_ptracer_any false ||
+run_strace_redir --quiet=personality --no-tips --seccomp-bpf -bexecve -enone ../set_ptracer_any false ||
dump_log_and_fail_with "$STRACE $args: unexpected exit status"
pattern_seccomp='[^:]*strace: --seccomp-bpf is not enabled because it is not compatible with -b'
diff --git a/tests/clone_ptrace.test b/tests/clone_ptrace.test
index 583c44d..9c77d05 100755
--- a/tests/clone_ptrace.test
+++ b/tests/clone_ptrace.test
@@ -13,7 +13,7 @@ run_prog > /dev/null 3>&1
args="-e trace=none ${1:---quiet=personality} $args"
> "$LOG" || fail_ "failed to write $LOG"
-$STRACE -o "$LOG" $args > "$EXP" 2> "$OUT"-err 3> "$EXP"-err || {
+$STRACE --no-tips -o "$LOG" $args > "$EXP" 2> "$OUT"-err 3> "$EXP"-err || {
msg="$STRACE $args failed with code $?"
cat "$OUT"-err "$LOG" >&2
fail_ "$msg"
diff --git a/tests/fflush.test b/tests/fflush.test
index b018649..f6eea93 100755
--- a/tests/fflush.test
+++ b/tests/fflush.test
@@ -10,7 +10,7 @@
. "${srcdir=.}/init.sh"
run_prog > /dev/null
-args="-o /dev/full -e trace=none $args"
+args="-o /dev/full -e trace=none --no-tips $args"
$STRACE $args > "$EXP" 2> "$LOG" || {
msg="$STRACE $args failed with code $?"
diff --git a/tests/first_exec_failure.test b/tests/first_exec_failure.test
index 175b084..b2bd8d1 100755
--- a/tests/first_exec_failure.test
+++ b/tests/first_exec_failure.test
@@ -9,7 +9,7 @@
. "${srcdir=.}/init.sh"
-$STRACE / 2> "$LOG" &&
+$STRACE --no-tips / 2> "$LOG" &&
dump_log_and_fail_with \
"$STRACE / failed to handle the error properly"
diff --git a/tests/options-syntax.test b/tests/options-syntax.test
index aebec27..a6487d5 100755
--- a/tests/options-syntax.test
+++ b/tests/options-syntax.test
@@ -311,12 +311,13 @@ args='-p 2147483647'
$STRACE $args 2> "$LOG" &&
dump_log_and_fail_with \
"strace $args failed to handle the error properly"
+head -n1 < "$LOG" > "$OUT"
for cmd in PTRACE_SEIZE PTRACE_ATTACH; do
cat > "$EXP" << __EOF__
$STRACE_EXE: attach: ptrace($cmd, 2147483647): No such process
__EOF__
- diff -- "$EXP" "$LOG" ||
+ diff -- "$EXP" "$OUT" ||
continue
args=
break
--
2.10.2
More information about the Strace-devel
mailing list