[PATCH] Raise strace awareness
enh
enh at google.com
Wed Apr 1 15:42:13 UTC 2020
usually i'm annoyed by the waste of time represented on both sides by
april fool's day stuff, but -- although it got silly nearer the end --
there were some genuinely useful tips in there. i use strace pretty
much every day, and there were several tips that pointed out things i
didn't even know were possible. thanks!
On Wed, Apr 1, 2020 at 7:03 AM Eugene Syromyatnikov <evgsyr at gmail.com> wrote:
>
> 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",
want
> + "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
>
> --
> Strace-devel mailing list
> Strace-devel at lists.strace.io
> https://lists.strace.io/mailman/listinfo/strace-devel
More information about the Strace-devel
mailing list