(root)/
strace-6.5/
src/
strauss.c
       1  /*
       2   * Strauss awareness implementation.
       3   *
       4   * Copyright (c) 2018-2023 The strace developers.
       5   * All rights reserved.
       6   *
       7   * SPDX-License-Identifier: LGPL-2.1-or-later
       8   */
       9  
      10  #include "defs.h"
      11  
      12  #include <stdio.h>
      13  #include <stdlib.h>
      14  #include <sys/time.h>
      15  
      16  #include "strauss.h"
      17  
      18  static const char *strauss[] = {
      19  	"",
      20  	"     ____",
      21  	"    /    \\",
      22  	"   |-. .-.|",
      23  	"   (_@)(_@)",
      24  	"   .---_  \\",
      25  	"  /..   \\_/",
      26  	"  |__.-^ /",
      27  	"      }  |",
      28  	"     |   [",
      29  	"     [  ]",
      30  	"    ]   |",
      31  	"    |   [",
      32  	"    [  ]",
      33  	"   /   |        __",
      34  	"  \\|   |/     _/ /_",
      35  	" \\ |   |//___/__/__/_",
      36  	"\\\\  \\ /  //    -____/_",
      37  	"//   \"   \\\\      \\___.-",
      38  	" //     \\\\  __.----._/_",
      39  	"/ '/|||\\` .-         __>",
      40  	"[        /         __.-",
      41  	"[        [           }",
      42  	"\\        \\          /",
      43  	" \"-._____ \\.____.--\"",
      44  	"    |  | |  |",
      45  	"    |  | |  |",
      46  	"    |  | |  |",
      47  	"    |  | |  |",
      48  	"    {  } {  }",
      49  	"    |  | |  |",
      50  	"    |  | |  |",
      51  	"    |  | |  |",
      52  	"    /  { |  |",
      53  	" .-\"   / [   -._",
      54  	"/___/ /   \\ \\___\"-.",
      55  	"    -\"     \"-",
      56  	};
      57  
      58  const size_t strauss_lines = ARRAY_SIZE(strauss);
      59  
      60  enum { MAX_TIP_LINES = 14 };
      61  
      62  static const char *tips_tricks_tweaks[][MAX_TIP_LINES] = {
      63  	{ "strace has an extensive manual page",
      64  	  "that covers all the possible options",
      65  	  "and contains several useful invocation",
      66  	  "examples." },
      67  	{ "You can use -o|COMMAND to redirect strace's",
      68  	  "output to COMMAND.  This may be useful",
      69  	  "in cases when there is a redirection",
      70  	  "in place for the traced program.  Don't",
      71  	  "forget to escape the pipe character, though,",
      72  	  "as it is usually interpreted by the shell." },
      73  	{ "It's possible to display timestamps",
      74  	  " produced by -r, -t, and -T options",
      75  	  "with nanosecond precision using their",
      76  	  "long variants: --relative-timestamps=ns,",
      77  	  "--absolute-timestamps=ns, and",
      78  	  "--syscall-times=ns, respectively.", "",
      79  	  "Why microsecond precision is the default?",
      80  	  "To preserve the historic output format",
      81  	  "which was limited by struct timeval",
      82  	  "precision." },
      83  	{ "A particular quote from a particular novel",
      84  	  "by Arthur C. Clarke is printed if an attempt",
      85  	  "is made to attach to a particular process." },
      86  	{ "It's possible to tune the environment",
      87  	  "of the traced process using the -E/--env",
      88  	  "option:", "",
      89  	  "    strace -E REMOVE_VAR -E VAR=new_val" },
      90  #ifdef ENABLE_STACKTRACE
      91  	{ "You can print a stack trace for each traced",
      92  	  "call by specifying -k/--stack-traces option.",
      93  # ifdef USE_DEMANGLE
      94  	  "It can even demangle symbol names.",
      95  # endif
      96  	  },
      97  #else
      98  	{ "We wish we could tell you that you can",
      99  	  "specify -k/--stack-traces option to print",
     100  	  "stack traces for each traced system call,",
     101  	  "but, unfortunately, you can't: this strace",
     102  	  "binary is built without stack tracing",
     103  	  "support." },
     104  #endif
     105  #ifdef ENABLE_SECONTEXT
     106  	{ "You can print SELinux contexts associated",
     107  	  "with PIDs, FDs, and paths by specifying",
     108  	  "--secontext option.  Unless provided",
     109  	  "with the \"full\" parameter, it prints only",
     110  	  "SELinux context type, and the \"mismatch\"",
     111  	  "parameter enables printing of the expected",
     112  	  "context in case of mismatch, so", "",
     113  	  "    strace --secontext=full,mismatch", "",
     114  	  "will show all gory SELinux details." },
     115  #else
     116  	{ "We wish we could tell you that you can",
     117  	  "specify --secontext option to print SELinux",
     118  	  "context for each PID, FD, and path occurred",
     119  	  "in the trace, but, unfortunately, you can't:",
     120  	  "this strace binary is built without SELinux",
     121  	  "support." },
     122  #endif
     123  	{ "Have you ever been bitten by an accidental",
     124  	  "overwrite of the output file specified",
     125  	  "in the -o option?  Specify",
     126  	  "-A/--output-append-mode as well,",
     127  	  "and this problem will never bite you again!" },
     128  	{ "strace is about as old as the Linux kernel.",
     129  	  "It has been originally written for SunOS",
     130  	  "by Paul Kranenburg in 1991.  The support",
     131  	  "for all OSes except Linux was dropped",
     132  	  "in 2012, though, in strace 4.7." },
     133  	{ "strace is able to decode netlink messages.",
     134  	  "It does so automatically for I/O performed",
     135  	  "on netlink sockets.  Try it yourself:", "",
     136  	  "    strace -e%network ip a" },
     137  	{ "Filtered syscalls, errors, and signals can",
     138  	  "be specified either by name or by number,",
     139  	  "for example:", "",
     140  	  "    strace --trace=0,1,2 --signal=2,15 true" },
     141  	{ "It is possible to specify -r and -t options",
     142  	  "simultaneously since strace 4.22." },
     143  	{ "Strace can print only successful syscall",
     144  	  "invocations when supplied with",
     145  	  "-z/--successful-only option.  There's also",
     146  	  "a possibility to filter calls with other",
     147  	  "statuses, please refer to -e status option",
     148  	  "documentation." },
     149  	{ "If you trace a process that uses KVM",
     150  	  "subsystem, --kvm=vcpu option may be of use:",
     151  	  "it prints KVM VCPU exit reason.  It requires",
     152  	  "Linux 4.16+, however." },
     153  	{ "It is possible to get strace out of your way",
     154  	  "(in terms of parent/child relationships and",
     155  	  "signal communication) with -D/--daemonize",
     156  	  "option.  Another option that may be of use",
     157  	  "in this case is -I/--interruptible, it",
     158  	  "restricts the set of signals that interrupt",
     159  	  "strace." },
     160  	{ "If strace is too chatty to your taste, you",
     161  	  "can silence it with -qqq option." },
     162  	{ "strace prints file paths along with file",
     163  	  "descriptor numbers when it is invoked with",
     164  	  "-y/--decode-fds option.",
     165  	  "When -yy (or --decode-fds=all) is provided,",
     166  	  "it also prints protocol-specific information",
     167  	  "for sockets and device numbers for character",
     168  	  "and block device files." },
     169  	{ "You can control what columns are shown",
     170  	  "in the call summary table produced by -c/-C",
     171  	  "options with -U/--summary-columns option.",
     172  	  "It is a way to get minimum/maximum call",
     173  	  "duration printed, for example:", "",
     174  	  "    strace -c -U name,min-time,max-time ls" },
     175  	{ "If you feel that syscall duration shown",
     176  	  "in the call summary table (-c/-C option)",
     177  	  "is not right, you can try to use -w option",
     178  	  "(that collects wall clock time,",
     179  	  "instead of system time), maybe that is what",
     180  	  "you are looking for." },
     181  	{ "strace understands -z option since 2002,",
     182  	  "but it wasn't documented because its",
     183  	  "implementation was broken.  Only 17 years",
     184  	  "later, in strace 5.2, it was properly",
     185  	  "implemented and documented." },
     186  	{ "If you feel that strace is too slow, you may",
     187  	  "want to try --seccomp-bpf option, maybe you",
     188  	  "will feel better." },
     189  	{ "-v is a shorthand for -e abbrev=none and not",
     190  	  "for -e verbose=all.  It is idiosyncratic,",
     191  	  "but it is the historic behaviour." },
     192  	{ "strace uses netlink for printing",
     193  	  "protocol-specific information about socket",
     194  	  "descriptors (-yy option)." },
     195  	{ "strace is able to tamper with tracees'",
     196  	  "execution by injecting an arbitrary return",
     197  	  "or error value instead of syscall execution,",
     198  	  "for example:", "",
     199  	  "    strace --inject=unlink:retval=0", "",
     200  	  "will prevent execution of unlink calls, but",
     201  	  "the traced process will think that the calls",
     202  	  "have succeeded." },
     203  	{ "strace's tampering capabilities include",
     204  	  "injection of arbitrary return/error values,",
     205  	  "injection of a signal, injection of a delay",
     206  	  "or data before or after syscall execution." },
     207  	{ "If you want to see numerical values of named",
     208  	  "constants, there is an option for that:",
     209  	  "-X/--const-print-style.  When -Xraw",
     210  	  "(or --const-print-style=raw) is provided,",
     211  	  "strace prints just the numerical value",
     212  	  "of an argument; with -Xverbose, it prints",
     213  	  "values in both numerical and symbolic form." },
     214  	{ "getpid syscall is present on all",
     215  	  "architectures except on Alpha, where getxpid",
     216  	  "syscall (that returns a pair of PID and PPID",
     217  	  "in a pair of registers) is used instead.",
     218  	  "Other two examples of syscalls that utilise",
     219  	  "two registers for their return values are",
     220  	  "getxuid and getxgid: they return a pair",
     221  	  "of real and effective UIDs/GIDs." },
     222  	{ "There are three syscalls that implement",
     223  	  "generic \"open file\" task: open, openat,",
     224  	  "and openat2.  On some (newly supported)",
     225  	  "architectures, open syscall is not even",
     226  	  "present.  How to write a robust filtering",
     227  	  "expression in this case?",
     228  	  "With the conditional syntax, for example:", "",
     229  	  "    strace --trace=?open,?openat,?openat2", "",
     230  	  "You may want to escape question marks, since",
     231  	  "your shell may interpret them as a path glob",
     232  	  "expression." },
     233  	{ "It is possible to use regular expressions",
     234  	  "for syscall names in the -e trace",
     235  	  "expression, for example:", "",
     236  	  "    strace -e trace=/^sched_.*", "",
     237  	  "will trace all scheduling-related syscalls." },
     238  	{ "IA-64 (Itanium) uses syscall numbers",
     239  	  "beginning from 1024, because numbers",
     240  	  "beginning from 0 were designated for i386",
     241  	  "compat layer (that has never been",
     242  	  "upstreamed).  Another example",
     243  	  "of an architecture with sparse syscall table",
     244  	  "is MIPS, with parts of it beginning at index",
     245  	  "0 (SVR4 ABI), 1000 (SysV ABI), 2000",
     246  	  "(BSD 4.3 ABI), 3000 (POSIX ABI), 4000 (Linux",
     247  	  "O32 ABI), 5000 (Linux N64 ABI), and 6000",
     248  	  "(Linux N32 ABI)." },
     249  	{ "Der Strauss, the strace's project mascot,",
     250  	  "was conceived in 2017.  It is a brainchild",
     251  	  "of Vitaly Chaykovsky." },
     252  	/* https://github.com/strace/strace/issues/14 */
     253  	{ "Medicinal effects of strace can be achieved",
     254  	  "by invoking it with the following options:", "",
     255  	  "    strace -DDDqqq -enone --signal=none" },
     256  	{ "Historically, supplying -o option to strace",
     257  	  "leads to silencing of messages about tracee",
     258  	  "attach/detach and personality changes.",
     259  	  "It can be now overridden with --quiet=none",
     260  	  "option." },
     261  	{ "You can avoid tracing of \"other programs\"",
     262  	  "that are executed by the traced program",
     263  	  "with -b execve option." },
     264  	{ "-F option used to be a separate option",
     265  	  "for following vfork calls." },
     266  	{ "It is possible to provide multiple PIDs",
     267  	  "to a single -p option with white space",
     268  	  "or comma as accepted delimiter, in order",
     269  	  "to support usage like", "",
     270  	  "    strace -p \"`pidof PROG`\"",
     271  	  "or",
     272  	  "    strace -p \"`pgrep PROG`\"", "",
     273  	  "pidof uses space as a delimiter, pgrep uses",
     274  	  "newline." },
     275  	{ "-n option, that prints syscall numbers,",
     276  	  "while seemingly quite obvious functionality,",
     277  	  "was added to strace only in version 5.9,",
     278  	  "in the year 2020." },
     279  	{ "Instead of tirelessly specifying",
     280  	  "architecture- and libc-specific sets",
     281  	  "of syscalls pertaining specific task each",
     282  	  "time, one can try to use pre-defined syscall",
     283  	  "classes.  For example,", "",
     284  	  "    strace -e%creds", "",
     285  	  "will trace all syscalls related to accessing",
     286  	  "and modifying process's user/group IDs",
     287  	  "and capability sets.  Other pre-defined",
     288  	  "syscall classes include %clock, %desc,",
     289  	  "%file, %ipc, %memory, %net, %process,",
     290  	  "and %signal." },
     291  	{ "Trying to figure out communication between",
     292  	  "tracees inside a different PID namespace",
     293  	  "(in so-called \"containers\", for example)?",
     294  	  "Try out the --pidns-translation option,",
     295  	  "it prints PIDs in strace's PID NS when a PID",
     296  	  "reference from a different PID NS occurs",
     297  	  "in trace.  It is not enabled by default",
     298  	  "because there is no sane kernel API",
     299  	  "to perform PID translation between",
     300  	  "namespaces, so each such translation",
     301  	  "requires many reads and ioctls in procfs,",
     302  	  "which may incur severe performance penalty." },
     303  	{ "If you don't like the way strace escapes",
     304  	  "non-printable characters using octal",
     305  	  "numbers, and don't want to sacrifice",
     306  	  "readability of the ASCII output with -x/-xx",
     307  	  "options, you might want to try", "",
     308  	  "    strace --strings-in-hex=non-ascii-chars", "",
     309  	  "that will change escape sequences",
     310  	  "to hexadecimal numbers usage." },
     311  	{ "-Y option (an alias to --decode-pids=comm)",
     312  	  "shows comm string associated with the PID." },
     313  	{ "Historically, strace had a mis-feature",
     314  	  "of interpreting the \" (deleted)\" part",
     315  	  "of the proc/pid/fd symlinks as a part",
     316  	  "of the filename.  This peculiar behaviour",
     317  	  "ended with strace 5.19, which also enables",
     318  	  "path tracing to trace FDs associated",
     319  	  "with specific paths even after the paths",
     320  	  "are unlinked." },
     321  	{ "It seems that IA-64, POWER and s390 are",
     322  	  "the only architectures where it is possible",
     323  	  "for strace to account for syscall time",
     324  	  "properly by relying on the system time usage",
     325  	  "reported by the kernel: these are the only",
     326  	  "architectures that HAVE_VIRT_CPU_ACCOUNTING",
     327  	  "config option enabled and thusly account",
     328  	  "the CPU time on syscall entering and exiting",
     329  	  "instead of approximating it." },
     330  };
     331  
     332  static const char tip_top[] =
     333  	"  ______________________________________________    ";
     334  static const char tip_bottom[] =
     335  	" \\______________________________________________/   ";
     336  static const char *tip_left[] = { " / ", " | "};
     337  static const char *tip_right[] = {
     338  	" \\   ",
     339  	" |   ",
     340  	" \\   ",
     341  	"  \\  ",
     342  	"  _\\ ",
     343  	" /   ",
     344  	" |   ", };
     345  
     346  enum tips_fmt show_tips = TIPS_NONE;
     347  int tip_id = TIP_ID_RANDOM;
     348  
     349  void
     350  print_strauss(size_t verbosity)
     351  {
     352  	if (verbosity < STRAUSS_START_VERBOSITY)
     353  		return;
     354  
     355  	verbosity = MIN(verbosity - STRAUSS_START_VERBOSITY, strauss_lines);
     356  
     357  	for (size_t i = 0; i < verbosity; i++)
     358  		puts(strauss[i]);
     359  }
     360  
     361  void
     362  print_totd(void)
     363  {
     364  	static bool printed = false;
     365  	const int w = (int) (sizeof(tip_top) - 1 - strlen(tip_left[0])
     366  				- strlen(tip_right[0]));
     367  	struct timeval tv;
     368  	size_t id;
     369  	size_t i;
     370  
     371  	if (printed || show_tips == TIPS_NONE)
     372  		return;
     373  
     374  	if (tip_id == TIP_ID_RANDOM) {
     375  		gettimeofday(&tv, NULL);
     376  		srand(tv.tv_sec ^ tv.tv_usec);
     377  		id = rand();
     378  	} else {
     379  		id = tip_id;
     380  	}
     381  	id %= ARRAY_SIZE(tips_tricks_tweaks);
     382  
     383  	fprintf(stderr, "%s%s\n", tip_top, strauss[1]);
     384  	fprintf(stderr, "%s%-*s%s%s\n",
     385  		tip_left[0], w, "", tip_right[0], strauss[2]);
     386  	for (i = 0; (i < MAX_TIP_LINES) && (tips_tricks_tweaks[id][i] ||
     387  					    (i < (ARRAY_SIZE(tip_right) - 1)));
     388  	     i++) {
     389  		fprintf(stderr, "%s%-*s%s%s\n",
     390  			tip_left[MIN(i + 1, ARRAY_SIZE(tip_left) - 1)],
     391  			w, tips_tricks_tweaks[id][i] ?: "",
     392  			tip_right[MIN(i + 1, ARRAY_SIZE(tip_right) - 1)],
     393  			strauss[MIN(3 + i, strauss_lines - 1)]);
     394  	}
     395  	fprintf(stderr, "%s%s\n",
     396  		tip_bottom, strauss[MIN(3 + i, strauss_lines - 1)]);
     397  	do {
     398  		fprintf(stderr, "%*s%*s%*s%s\n",
     399  			(int) strlen(tip_left[0]), "",
     400  			w, "",
     401  			(int) strlen(tip_right[0]), "",
     402  			strauss[MIN(4 + i, strauss_lines - 1)]);
     403  	} while ((show_tips == TIPS_FULL) && (4 + ++i < strauss_lines));
     404  
     405  	printed = true;
     406  }