[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