STRACE(1)

๐Ÿฆ‹ strace(1) โ€” trace system calls and signals ๐Ÿฆ‹

okay bestie, pull up a chair, we're reading the manual page for strace(1) and honestly? it's a whole vibe. it's a General Commands Manual situation and it's about to eat ๐Ÿ’…


๐ŸŒธ NAME ๐ŸŒธ

strace โ€” trace system calls and signals โœจ


๐ŸŽ€ SYNOPSIS ๐ŸŽ€

strace [-ACdffhikkqqrtttTvVwxxyyYzZ] [-a column] [-b execve]
       [-e expr]... [-I n] [-o file] [-O overhead] [-p pid]...
       [-P path]... [-s strsize] [-S sortby] [-U columns] [-X format]
       [--seccomp-bpf] [--stack-trace-frame-limit=limit]
       [--syscall-limit=limit] [--secontext[=format]] [--tips[=format]]
       { -p pid | [-DDD] [-E var[=val]]... [-u username] command [args]
       }

strace -c [-dfwzZ] [-b execve] [-e expr]... [-I n] [-O overhead]
       [-p pid]... [-P path]... [-S sortby] [-U columns] [--seccomp-bpf]
       [--syscall-limit=limit] [--tips[=format]] { -p pid | [-DDD]
       [-E var[=val]]... [-u username] command [args] }

strace --tips[=format]

like, that's a lot of letters, and every single one of them is doing something. no cap. ๐Ÿ‘‘


๐Ÿ’– DESCRIPTION ๐Ÿ’–

Okay so the simplest possible use case: strace runs the command you give it until that command dips out (exits). The whole time, it's intercepting and recording the system calls the process makes, plus the signals the process receives. Then it prints the name of every system call, its arguments, and its return value โ€” either to standard error, or to a file if you passed the -o option. ๐Ÿซถ

strace is a genuinely useful diagnostic, instructional, and debugging tool. System administrators, diagnosticians, and troubleshooters will find it invaluable for solving problems with programs where the source code just isn't available โ€” because bestie, recompilation is not required to trace. Students, hackers, and the overly-curious will discover that you can learn a great deal about a system and its system calls just by tracing even the most ordinary programs. And programmers? They'll find that since system calls and signals happen at the user/kernel interface, staring really hard at that boundary is super useful for bug isolation, sanity checking, and attempting to capture race conditions. ๐Ÿ›โœจ

Every line in the trace has the system call name, then its arguments in parentheses, then its return value. Here's an example from tracing the command cat /dev/null:

open("/dev/null", O_RDONLY) = 3

Errors โ€” usually showing up as a return value of -1 โ€” get the errno symbol and error string tacked on. ๐Ÿ˜ญ

open("/foo/bar", O_RDONLY) = -1 ENOENT (No such file or directory)

Signals get printed as a signal symbol plus a decoded siginfo structure. Here's an excerpt from tracing and interrupting the command sleep 666:

sigsuspend([] <unfinished ...>
--- SIGINT {si_signo=SIGINT, si_code=SI_USER, si_pid=...} ---
+++ killed by SIGINT +++

If a system call is still executing while another gets called from a different thread or process, strace will attempt to preserve the order of these events and mark the ongoing call as unfinished. When it comes back, it gets marked as resumed. ๐ŸŒ€

[pid 28772] select(4, [3], NULL, NULL, NULL <unfinished ...>
[pid 28779] clock_gettime(CLOCK_REALTIME, {tv_sec=1130322148, tv_nsec=3977000}) = 0
[pid 28772] <... select resumed> )      = 1 (in [3])

The interruption of a (restartable) system call by a signal delivery is handled differently, because the kernel terminates the system call and arranges for its immediate re-execution after the signal handler finishes. ๐Ÿ”

read(0, 0x7ffff72cf5cf, 1)              = ? ERESTARTSYS (To be restarted)
--- SIGALRM {si_signo=SIGALRM, si_code=SI_KERNEL} ---
rt_sigreturn({mask=[]})                 = 0
read(0, "", 1)                          = 0

Arguments get printed in symbolic form, with passion. This next one shows the shell doing a >>xyzzy output redirection:

open("xyzzy", O_WRONLY|O_APPEND|O_CREAT, 0666) = 3

See how the second and third arguments of open(2) get decoded โ€” the flag argument gets broken down into its three bitwise-OR constituents, and the mode value is printed in octal, following tradition. Where traditional or native usage differs from ANSI or POSIX, the latter forms win. In some cases, strace output has proven to be more readable than the source code itself. iconic behavior honestly. ๐Ÿ‘‘

Structure pointers get dereferenced, and their members get displayed as appropriate. In most cases, arguments are formatted in the most C-like fashion possible. For example, the essence of the command ls -l /dev/null is captured as:

lstat("/dev/null", {st_mode=S_IFCHR|0666, st_rdev=makedev(0x1, 0x3), ...}) = 0

Notice how the struct stat argument is dereferenced, and how each member is displayed symbolically. In particular, ๐Ÿ‘€ observe how the st_mode member is carefully decoded into a bitwise-OR of symbolic and numeric values. Also note that in this example, the first argument to lstat(2) is an input to the system call, and the second argument is an output. Since output arguments don't get modified if the system call fails, arguments may not always be dereferenced. For example, retrying that ls -l example with a non-existent file produces this line:

lstat("/foo/bar", 0xb004) = -1 ENOENT (No such file or directory)

In this case, the porch light is on but nobody is home. ๐Ÿ’€ The pointer's value is displayed because the structure it points to wasn't populated, on account of the error.

System calls that strace doesn't know about get printed in a raw format, with the hexadecimal system call number prefixed with "syscall_":

syscall_0xbad(0x1, 0x2, 0x3, 0x4, 0x5, 0x6) = -1 ENOSYS (Function not implemented)

Character pointers get dereferenced and printed as C strings. Non-printing characters inside strings are normally represented by standard C escape codes. Only the first strsize bytes of strings are printed (32 by default), and longer strings get an ellipsis appended after the closing quote. Here's a line from ls -l where the getpwuid(3) library routine is reading the password file:

read(3, "root::0:0:System Administrator:/"..., 1024) = 422

While structures are annotated using curly braces, pointers to basic types and arrays are printed using square brackets, with commas separating the elements. Here's an example from the command id(1) on a system with supplementary group IDs:

getgroups(32, [100, 0]) = 2

On the other hand, bit-sets are also shown using square brackets, but the set elements are separated only by a space. Here's the shell, preparing to execute an external command:

sigprocmask(SIG_BLOCK, [CHLD TTOU], []) = 0

Here, the second argument is a bit-set of two signals, SIGCHLD and SIGTTOU. In some cases the bit-set is so full that it's more valuable to print the unset elements instead. In that case, the bit-set is prefixed by a tilde, like this:

sigprocmask(SIG_UNBLOCK, ~[], NULL) = 0

Here, the second argument represents the full set of all signals. โœจ


๐Ÿ’… OPTIONS ๐Ÿ’…

๐ŸŽ€ General ๐ŸŽ€

  • -e expr โ€” Modifies which events get traced or how they get traced, by specifying a qualifying expression. The format of the expression is:
[qualifier=][!]value[,value]...

where qualifier is one of trace (or t), trace-fds (or trace-fd or fd or fds), abbrev (or a), verbose (or v), raw (or x), signal (or signals or s), read (or reads or r), write (or writes or w), fault, inject, status, quiet (or silent or silence or q), secontext, decode-fds (or decode-fd), decode-pids (or decode-pid), or kvm, and value is a qualifier-dependent symbol or number. The default qualifier is trace. Using an exclamation mark negates the set of values. For example, -e open is equivalent to -e trace=open, which in turn means trace only the open system call. By contrast, -e trace=!open means trace every system call except open. And on top of all that, the special values all and none may be used to trace every event or no events, respectively. ๐ŸŒˆ

โš ๏ธ Heads up bestie: some shells use the exclamation mark for history expansion even inside quoted arguments. In that case, the exclamation mark must be escaped with a backslash. Don't let your shell eat your negation, that's so embarrassing for everyone. ๐Ÿ˜ญ

๐Ÿš€ Startup ๐Ÿš€

  • -E var=val
  • --env=var=val โ€” Runs the command with the environment variable var=val set for execution. ๐Ÿซถ
  • -E var
  • --env=var โ€” Removes var from the inherited environment variables before executing the command. ๐Ÿ’จ
  • -p pid
  • --attach=pid โ€” Attaches to the process with the process ID pid and begins tracing. The trace may be terminated at any time by a keyboard interrupt signal (Ctrl+C). strace will respond by detaching itself from the traced processes, leaving them to continue running. ๐Ÿƒโ€โ™€๏ธ

Multiple -p options can be used to attach to several processes in addition to the command, and the command is optional if at least one -p option is given.

A single -p option can accept multiple process IDs separated by a comma (โ€œ,โ€), space (โ€œ โ€), tab, or newline. Consequently, syntaxes like -p "$(pidof PROG)" and -p "$(pgrep PROG)" are supported. โœจ

  • -u username
  • --user=username โ€” Runs command with the user ID, group ID, and supplementary groups of username. This option is only useful when running as root, since it enables the correct execution of setuid and/or setgid binaries. Unless this option is used, setuid and setgid programs are executed without their effective privileges. ๐Ÿ‘‘
  • -u UID:GID
  • --user=UID:GID โ€” Alternative syntax where the program is started with exactly the given user and group IDs, and an empty list of supplementary groups. In this case, user and group name lookups are not performed. ๐Ÿ“
  • --argv0=name โ€” Sets the executed command's argv[0] to name. This is useful for tracing multi-call executables that interpret argv[0], such as busybox or kmod. ๐Ÿฆ‹

๐Ÿ” Tracing ๐Ÿ”

  • -b syscall
  • --detach-on=syscall โ€” Detaches from the traced process if the specified system call is reached. Currently, only the execve keyword is supported, which includes the execve(2) and execveat(2) system calls. This option is useful for tracing a multi-threaded process with -f without also tracing its (potentially very complex) child processes. ๐Ÿงš
  • -D
  • --daemonize
  • --daemonize=grandchild โ€” Runs the tracer process as a grandchild of the tracee, not as its parent. This reduces the visible effect of strace by keeping the tracee a direct child of the calling process. ๐ŸŒธ
  • -DD, --daemonize=pgroup, --daemonize=pgrp โ€” runs the tracer process as the tracee's grandchild, in its own separate process group. besides making strace way less visible to the thing it's tracing, this also means strace won't get merked by a kill(2) signal that somebody sent to the whole process group. iconic protective behaviour honestly ๐Ÿ’…
  • -DDD, --daemonize=session โ€” runs the tracer process as the tracee's grandchild in a separate session โ€” that's the "true daemonisation" version, the real deal โœจ. on top of the whole reduced-visibility thing, it also keeps strace from getting terminated when the session ends. she simply will not be ended ๐Ÿ™ˆ
  • -f, --follow-forks โ€” traces child processes as they're created by processes you're already tracing, whenever fork(2), vfork(2) or clone(2) happens. so you get the whole family tree, bestie ๐ŸŒธ note tho: if the process PID is multi-threaded, then -f -p PID attaches to all of its threads, not just the one with thread_id = PID. no leaving the siblings behind.
  • --output-separately โ€” if --output=filename is active, the trace for each process gets written to its own separate filename.pid file, where pid is the process ID. one file per baby, organized queen ๐Ÿ‘‘
  • -ff, --follow-forks --output-separately โ€” the combo move: does what --follow-forks does and what --output-separately does at the same time. heads up: this is incompatible with -c, because no per-process counts get kept. ๐Ÿšซ

to get one combined view of all those log files, use strace-log-merge(1). see also: SEE ALSO, she's everywhere ๐ŸŒˆ

  • -I interruptible, --interruptible=interruptible โ€” controls when strace is allowed to be interrupted by signals (like when you smash Ctrl+C). pick your vibe:
    • 1, anywhere โ€” no signals are blocked, free-for-all โœจ
    • 2, waiting โ€” fatal signals are blocked while decoding a system call. this is the default ๐ŸŽ€
    • 3, never โ€” fatal signals are always blocked. this is the default if you use -o FILE PROG
    • 4, never_tstp โ€” fatal signals and SIGTSTP (Ctrl+Z) are always blocked. super useful if you want strace -o FILE PROG to not stop on Ctrl+Z. this one's the default if you use -D ๐Ÿ’œ
  • --syscall-limit=limit โ€” detaches all tracees once limit system calls have been captured. ngl this is your "okay that's enough babe" option ๐Ÿซถ one lil detail: system calls filtered out by --trace, --trace-path or --status don't count toward that number. irrelevant calls simply don't make the tally.
  • --kill-on-exit โ€” applies the PTRACE_O_EXITKILL ptrace option to every tracee, which sends a SIGKILL signal to a tracee if the tracer exits. basically: nobody gets left running after the tracer dips, because tracees will not be detached on cleanup. > โš ๏ธ --kill-on-exit is not compatible with -p/--attach options. pick one bestie, you cannot have both ๐Ÿ’€

๐Ÿฆ‹ Filtering ๐Ÿฆ‹

  • -e trace=syscall_set, -e t=syscall_set, --trace=syscall_set โ€” traces only the system calls in the set you name. syscall_set is defined as [!]value[,value], and each value can be any of these cuties:
    • syscall โ€” traces one specific system call, named by its name (peep syscalls(2) for a reference, but also go read NOTES ๐Ÿ“).
    • ?value โ€” a question mark in front of a qualification suppresses errors if no matching system calls are found. it's the "no worries if not" of strace ๐ŸŒธ
    • value@64 โ€” limits the system call spec described by value to the 64-bit personality.
    • value@32 โ€” limits the system call spec described by value to the 32-bit personality.
    • value@x32 โ€” limits the system call spec described by value to the x32 personality.
    • all โ€” traces every single system call. the whole menu ๐Ÿ“
    • /regex โ€” traces only the system calls that match the regex. you can use POSIX Extended Regular Expression syntax here (see regex(7)). regex girlies stay winning โœจ
    • %file, file โ€” traces all system calls that take a file name as an argument. think of it as a lil abbreviation for --trace=open,stat,chmod,unlink,..., which is genuinely so useful for seeing what files a process is touching. and using the abbreviation means you won't accidentally forget to include a call like newfstatat(2). btw the syntax without the leading percent sign (--trace=file) is deprecated, so use the %. ๐Ÿ’…
    • %process, process โ€” traces system calls tied to process lifecycle (creation, exec, termination). the no-percent version (--trace=process) is deprecated.
    • %net, %network, network โ€” traces all the network related system calls. --trace=network without the percent sign is deprecated.
    • %signal, signal โ€” traces all signal related system calls. --trace=signal without the percent sign is deprecated.
    • %ipc, ipc โ€” traces all IPC related system calls. --trace=ipc without the percent sign is deprecated.
    • %desc, desc โ€” traces all file descriptor related system calls. --trace=desc without the percent sign is deprecated.
    • %memory, memory โ€” traces all memory mapping related system calls. --trace=memory without the percent sign is deprecated.
    • %creds โ€” traces system calls that read or modify user and group identifiers or capability sets. ๐Ÿ”‘
    • %stat โ€” traces stat system call variants.
    • %lstat โ€” traces lstat system call variants.
    • %fstat โ€” traces fstat, fstatat, and statx system call variants.
    • %%stat โ€” traces system calls used for requesting file status (stat, lstat, fstat, fstatat, statx, and their variants). yes, that's a double percent, she's fancy ๐Ÿ‘‘
    • %statfs โ€” traces statfs, statfs64, statvfs, osf_statfs, and osf_statfs64 system calls. same effect you'd get from the regular expression --trace=/^(.*_)?statv?fs โœจ
    • %fstatfs โ€” traces fstatfs, fstatfs64, fstatvfs, osf_fstatfs, and osf_fstatfs64 system calls. same effect as --trace=/fstatv?fs ๐Ÿ’œ
    • %%statfs โ€” traces system calls related to file system statistics (the statfs-like, fstatfs-like, and ustat ones). same effect as --trace=/statv?fs|fsstat|ustat ๐ŸŒˆ
    • %clock โ€” traces system calls that read or modify system clocks. โฐ
    • %pure โ€” traces system calls that always succeed and take no arguments. rn that list is: arc_gettls(2), getdtablesize(2), getegid(2), getegid32(2), geteuid(2), geteuid32(2), getgid(2), getgid32(2), getpagesize(2), getpgrp(2), getpid(2), getppid(2), get_thread_area(2) (on architectures other than x86), gettid(2), get_tls(2), getuid(2), getuid32(2), getxgid(2), getxpid(2), getxuid(2), kern_features(2), and metag_get_tls(2) system calls. pure of heart, zero drama ๐ŸŒฑ

the -c option is genuinely useful for figuring out which system calls are worth tracing, like a lil vibe check. for example, --trace=open,close,read,write means only those four get traced. > โš ๏ธ but be careful when making inferences about the user/kernel boundary if only a subset of system calls is being monitored. the default is --trace=all.

  • -e trace-fd=set, -e trace-fds=set, -e fd=set, -e fds=set, --trace-fds=set โ€” traces only the system calls that operate on the specified subset of (non-negative) file descriptors. note that using this also filters out every system call that doesn't operate on file descriptors at all โ€” bye ๐Ÿ‘‹

this filter gets combined with the --trace-path filter: a system call is traced if it matches either of them. it's a union, bestie ๐Ÿซถ

  • -e signal=set, -e signals=set, -e s=set, --signal=set โ€” traces only the specified subset of signals. the default is --signal=all. for example, --signal=!SIGIO (or --signal=!io) makes it so SIGIO signals don't get traced. the ! is your "not this one" โœ‹
  • -e status=set, --status=set โ€” prints only system calls with the specified return status. the default is --status=all. > โš ๏ธ ngl there's a catch: when you use the status qualifier, the chronological order of events may not be preserved. why? because strace has to wait for a system call to complete before deciding whether to print it. so if two concurrent threads each run a system call, strace will print both the entry and exit of whichever one exits first, no matter what their entry times were โ€” and then the entry and exit of the second one to exit get printed afterwards. it's giving non-chronological, sorry ๐Ÿ’€

here's an example where select(2) is called, but a different thread calls clock_gettime(2) before select(2) finishes:

[pid 28779] 1130322148.939977 clock_gettime(CLOCK_REALTIME, {1130322148, 939977000}) = 0
[pid 28772] 1130322148.438139 select(4, [3], NULL, NULL, NULL) = 1 (in [3])

set can include the following elements:

  • successful โ€” only the syscalls that came back with no error code. Literally exactly what -z does, so -z is just --status=successful with a glow-up. โœจ
  • failed โ€” only the syscalls that came back with an error code. Same energy: -Z is --status=failed.
  • unfinished โ€” the ones that never returned at all ๐Ÿ˜ญ. This can happen when, say, an execve call happens in a different thread of the same thread group.
  • unavailable โ€” the syscall did return, but strace couldn't fetch the error status. rip.
  • detached โ€” syscalls where strace detached before the return happened.

  • -P path
  • --trace-path=path โ€” traces only the system calls that touch path. You can flex multiple -P options to name several paths. Heads up: this filter stacks with the --trace-fds filter, and a syscall gets traced if it matches either one. ๐Ÿซถ
  • -z
  • --successful-only โ€” prints only the system calls that returned without an error code. clean, flawless, no drama ๐Ÿ’…
  • -Z
  • --failed-only โ€” prints only the system calls that returned with an error code. the messy ones. we love them.

๐ŸŽ€ Output format ๐ŸŽ€

  • -a column
  • --columns=column โ€” lines the return values up in a specific column. default column is 40. aesthetic โœจ
  • -e abbrev=syscall_set
  • -e a=syscall_set
  • --abbrev=syscall_set โ€” abbreviates the output so it stops printing every single member of big chonky structures. the syntax of the syscall_set spec is the same as in --trace. default is --abbrev=all. and bestie, -v has the effect of --abbrev=none. ๐Ÿฆ‹
  • -e verbose=syscall_set
  • -e v=syscall_set
  • --verbose=syscall_set โ€” dereferences structures for the specified set of syscalls. syscall_set syntax is the same as in --trace. default is --verbose=all. we go deep. ๐Ÿ”ฅ
  • -e raw=syscall_set
  • -e x=syscall_set
  • --raw=syscall_set โ€” prints raw, undecoded arguments for the specified set of syscalls. syscall_set syntax = same as --trace. this one makes all arguments print in hexadecimal. super useful if you don't trust the decoding, or if you genuinely need the actual numeric value of an argument. also see the -X raw option. ๐Ÿ’€
  • -e read=set
  • -e reads=set
  • -e r=set
  • --read=set โ€” does a full hexadecimal and ASCII dump of all the data read from the file descriptors listed in set. like, to see all input activity on fds 3 and 5, you'd do --read=3,5. ngl this is independent from the normal tracing of the read(2) system call, which is the thing controlled by --trace=read. ๐Ÿ‘‘
  • -e write=set
  • -e writes=set
  • -e w=set
  • --write=set โ€” full hexadecimal and ASCII dump of all the data written to the file descriptors listed in set. e.g. to see all output activity on fds 3 and 5: --write=3,5. same deal as above โ€” independent from the normal tracing of write(2), which --trace=write controls. ๐ŸŒธ
  • -e quiet=set
  • -e silent=set
  • -e silence=set
  • -e q=set
  • --quiet=set
  • --silent=set
  • --silence=set โ€” suppresses a bunch of informational messages. default is --quiet=none. set can include these elements:
    • attach โ€” suppresses the messages about attaching and detaching, aka "[ Process NNNN attached ]" and "[ Process NNNN detached ]".
    • exit โ€” suppresses the messages about process exits, aka "+++ exited with SSS +++".
    • path-resolution โ€” suppresses the messages about resolution of paths handed over via the -P option, aka "Requested path "..." resolved into "..."".
    • personality โ€” suppresses the messages about process personality changes, aka "[ Process PID=NNNN runs in PPP mode. ]".
    • thread-execve
    • superseded โ€” suppresses the messages about a process being superseded by execve(2) in another thread, aka "+++ superseded by execve in pid NNNN +++".
  • -e decode-fds=set
  • --decode-fds=set โ€” decodes all sorts of info tied to file descriptors. default is --decode-fds=none. set can include these elements:
    • path โ€” prints file paths. it also switches on printing of the tracee's current working directory whenever the AT_FDCWD constant is used.
    • socket โ€” prints socket protocol-specific information.
    • dev โ€” prints character/block device numbers.
    • eventfd โ€” prints eventfd object details associated with eventfd file descriptors.
    • pidfd โ€” prints PIDs associated with pidfd file descriptors.
    • signalfd โ€” prints signal masks associated with signalfd file descriptors.
  • -e decode-pids=set
  • --decode-pids=set โ€” decodes info tied to process IDs (and thread IDs, process group IDs, and session IDs too, because why not). default is --decode-pids=none. set can include:
    • comm โ€” prints command names associated with thread or process IDs.
    • pidns โ€” prints thread, process, process group, and session IDs in strace's PID namespace when the tracee is living in a different PID namespace.
  • -e kvm=vcpu|vcpu+
  • --kvm=vcpu|vcpu+ โ€” prints the exit reason of a kvm vcpu (=vcpu), or prints the whole kvm_run struct *including* the reason (=*vcpu*+). requires Linux kernel version 4.16.0` or higher. โญ

The vcpu+ output uses the prefixes VCPU:CPU#< and VCPU:CPU#>. Lines starting with the former show the state of the structure before calling KVM_RUN, and the ones starting with the latter show the state after calling KVM_RUN.

  • -e namespace=new
  • --namespace=new โ€” prints the new namespaces entered by the tracee. supported system calls: clone(2), clone3(2), setns(2), and unshare(2). ๐Ÿงš
  • -i
  • --instruction-pointer โ€” prints the instruction pointer at the moment of the system call.
  • -n
  • --syscall-number โ€” prints the system call number.
  • -N
  • --arg-names โ€” prints the system call argument names.
  • -k
  • --stack-trace[=symbol] โ€” prints the execution stack trace of the traced processes after every system call. ๐Ÿซถ
  • -kk
  • --stack-trace=source โ€” prints the execution stack trace and source code info of the traced processes after every system call. this option expects your target program to be compiled with the appropriate debug options: "-g" (gcc), or "-g -gdwarf-aranges" (clang).
  • --stack-trace-frame-limit=limit โ€” prints no more than this many stack trace frames when backtracing a system call. the default is 256. use it together with the --stack-trace (or -k) option.
  • -o filename
  • --output=filename โ€” writes the trace output to the file filename instead of to stderr. if -ff is supplied, the filename.pid form is used. if the argument starts with '|' or '!', the rest of the argument is treated as a command and all the output gets piped to it โ€” super convenient for piping debug output into a program without messing with the redirections of the executed programs. ๐ŸŒˆ
ok important: piping output to a command is not currently compatible with the -ff option. noted, bestie.
  • -A
  • --output-append-mode โ€” opens the file given in the -o option in append mode.
  • --color=when โ€” colorizes the trace output. default is --color=auto, which only turns color on when the trace output stream is a terminal (stderr by default; see -o) that supports at least 8 colors. if the NO_COLOR environment variable is set, color is disabled unless --color=always is specified. the when parameter can be one of auto, always, or never. custom color schemes can be specified with the STRACE_COLORS environment variable, for example:
STRACE_COLORS="syscall=1;33:argname=39:argval=35:call=1;34:const=1;36:comment=36:punct=0:retval=32:error=31"

The format of this value is key=value pairs separated by :, with semicolon-separated SGR codes as values.

The default palette uses standard ANSI colors (SGR 30โ€“37) and bold attributes rather than bright colors (SGR 90โ€“97), so that terminal color themes can adapt them for both dark and light backgrounds. iconic, honestly. ๐Ÿ’–

Recognized color keys are: syscall, argname, argval, call, const, comment, punct, retval, error.

  • -q
  • --quiet
  • --quiet=attach,personality โ€” suppresses the messages about attaching, detaching, and personality changes. this happens automatically when output is redirected to a file and the command is run directly instead of attaching.
  • -qq
  • --quiet=attach,personality,exit โ€” suppresses the messages about attaching, detaching, personality changes, and process exit status.
  • -qqq
  • --quiet=all โ€” suppresses all suppressible messages (go check the --quiet option description for the full list of suppressible messages, bestie).
  • -r, --relative-timestamps[=precision] โ€” stamps a relative timestamp on every syscall entry ๐Ÿ’–. It's literally recording the time gap between the start of one syscall and the start of the next one. <italic>precision</italic> can be s (seconds), ms (milliseconds), us (microseconds) or ns (nanoseconds), and it sets how precise that printed time value gets. Default is us (microseconds). Heads up bestie: -r rides the monotonic clock, so its numbers can disagree with the time differences -t reports, because -t uses the wall clock. Different clocks, different vibes ๐Ÿ•ฐ๏ธ
  • -s strsize, --string-limit=strsize โ€” sets the max string size that gets printed (default is 32) โœ‚๏ธ. But ngl, filenames are not treated as strings, so they always get printed in full, no truncation, no exceptions ๐Ÿ‘‘
  • --absolute-timestamps[=[[format:]format],[[precision:]precision]], --timestamps[=[[format:]format],[[precision:]precision]] โ€” puts the wall clock time at the front of every line of the trace, in the <italic>format</italic> you picked with the <italic>precision</italic> you picked โœจ. <italic>format</italic> can be any of these:
    • none โ€” no timestamp printed at all. Lowkey useful for overriding whatever you set before ๐Ÿ™ˆ
    • time โ€” wall clock time (the strftime(3) format string is %T)
    • unix โ€” number of seconds since the epoch (the strftime(3) format string is %s)

<italic>precision</italic> can be s (seconds), ms (milliseconds), us (microseconds) or ns (nanoseconds). The default arguments for this option are format:time,precision:s ๐Ÿ’…

  • -t, --absolute-timestamps โ€” prefixes every line of the trace with the wall clock time โฐ
  • -tt, --absolute-timestamps=precision:us โ€” prints the wall clock time with microsecond precision, she's precise ๐Ÿ’ซ
  • -ttt, --absolute-timestamps=format:unix,precision:us โ€” prints the wall clock time as seconds since the epoch, with microsecond precision ๐Ÿ•›
  • -T, --syscall-times[=precision] โ€” shows how long each system call actually took โฑ๏ธ. It records the time difference between the beginning and the end of each syscall. <italic>precision</italic> can be s (seconds), ms (milliseconds), us (microseconds) or ns (nanoseconds), and it sets how precise that printed time value gets. Default is us (microseconds).
  • -v, --no-abbrev โ€” prints unabbreviated versions of environment, stat, termios, etc. calls ๐Ÿ‘€. Those structures are super common, so by default strace shows only a reasonable subset of their members. Use this option when you want every single member, in full detail, no crumbs left behind ๐Ÿ’…
  • --strings-in-hex[=option] โ€” controls whether hexadecimal escape sequences get used when printing strings ๐Ÿ”ข. This option changes the default escaping behavior.

Normally (so when neither this option nor -x is used), strace brings in escape sequences in two situations: to represent non-printable and non-ASCII characters (meaning those with character codes less than 32 or greater than 127), or to disambiguate output โ€” for example by escaping the quotation marks that enclose a string, or the angle brackets used in file descriptor paths. When a character needs escaping, strace prioritizes the symbolic C-standard sequences if one exists: \t (tab), \n (newline), \v (vertical tab), \f (form feed), and \r (carriage return). For every other character that requires escaping, strace defaults to an octal representation of the character's byte value. This option lets you override that default and use hexadecimal escapes instead of octal ones.

<italic>option</italic> can be one of these:

  • none โ€” hexadecimal numbers aren't used in the output at all. When there's a need to emit an escape sequence, octal numbers are used.
  • non-ascii-chars โ€” hexadecimal numbers are used instead of octal in the escape sequences.
  • non-ascii โ€” strings that contain non-ASCII characters are printed using escape sequences with hexadecimal numbers.
  • all โ€” all strings are printed using escape sequences with hexadecimal numbers.

When the option is given with no argument, all is assumed ๐Ÿ‘‘

  • -x, --strings-in-hex=non-ascii โ€” prints all non-ASCII strings in hexadecimal string format ๐Ÿ”ฅ
  • -xx, --strings-in-hex[=all] โ€” prints all strings in hexadecimal string format, absolutely everything, no cap ๐Ÿ’€
  • -X format, --const-print-style=format โ€” sets the format for printing named constants and flags. The supported <italic>format</italic> values are:
    • raw โ€” raw number output, without decoding.
    • abbrev โ€” outputs a named constant or a set of flags instead of the raw number, if they're found. This is the default strace behaviour ๐Ÿ’–
    • verbose โ€” outputs both the raw value and the decoded string (as a comment).
  • -y, --decode-fds, --decode-fds=path โ€” prints paths associated with file descriptor arguments and with the AT_FDCWD constant ๐Ÿ“‚
  • -yy, --decode-fds=all โ€” prints all available info associated with file descriptors: protocol-specific info associated with socket file descriptors, block/character device number associated with device file descriptors, and PIDs associated with pidfd file descriptors. The full lore ๐Ÿ”
  • --pidns-translation, --decode-pids=pidns โ€” if strace and the tracee are in different PID namespaces, it prints PIDs in strace's namespace too ๐ŸŒ
  • -Y, --decode-pids=comm โ€” prints command names for PIDs ๐Ÿท๏ธ
  • --secontext[=format], -e secontext=format โ€” when SELinux is available and not disabled, prints the SELinux contexts of processes, files, and descriptors inside square brackets ๐Ÿ”. The <italic>format</italic> argument is a comma-separated list of items, and each item is one of these:
    • full โ€” prints the full context (user, role, type level and category).
    • mismatch โ€” also prints the context recorded by the SELinux database in case the current context differs. That one gets printed after two exclamation marks (!!).

The default value for --secontext is !full,mismatch, which prints only the type instead of the full context and doesn't check for context mismatches ๐ŸŽ€

  • --always-show-pid โ€” shows the PID prefix also for the process started by strace ๐Ÿ‘‘. It's implied when -f and -o are both specified.

โœจ Statistics โœจ

  • -c, --summary-only โ€” counts time, calls, and errors for each system call and reports a summary when the program exits, suppressing the regular output ๐Ÿ“Š. This shows system time (CPU time spent in the kernel), which is independent of wall clock time. And if -c is used with -f, only aggregate totals for all traced processes are kept. One big girlboss total ๐Ÿ’…
  • -C, --summary โ€” like -c, but it also prints the regular output while processes are running ๐Ÿซถ. Best of both worlds, honestly.
  • -O overhead, --summary-syscall-overhead=overhead โ€” sets the overhead for tracing system calls to <italic>overhead</italic> โš™๏ธ. This is useful for overriding the default heuristic, which estimates the time spent in the measurement process itself when timing system calls with the -c option. The same overhead gets subtracted from polymorphic time columns and from wall-total, wall-min, wall-max, and wall-avg. You can gauge how accurate the heuristic is by timing a given program run without tracing (using time(1)) and comparing the accumulated system call time to the total you got from -c.

The format of the <italic>overhead</italic> specification is described in the section Time specification format description.

  • -S sortby, --summary-sort-by=sortby โ€” sorts the output of the histogram printed by the -c option by whatever criterion you pick ๐Ÿ”€. Valid values are time (or time-percent or time-total or total-time), min-time (or shortest or time-min), max-time (or longest or time-max), avg-time (or time-avg), wall-total (or total-wall), wall-min (or min-wall), wall-max (or max-wall), wall-avg (or avg-wall), calls (or count), errors (or error), name (or syscall or syscall-name), and nothing (or none). Default is time โณ
  • -U columns, --summary-columns=columns โ€” configures the set and the order of columns shown in the call summary ๐Ÿ—‚๏ธ. The <italic>columns</italic> argument is a comma-separated list containing one or more of the following values:

and here's the rest of the column menu, bestie โ€” pick your faves ๐Ÿ’…

  • time-percent (or time) โ€” the percentage of cumulative time that one specific syscall gobbled up. ๐Ÿฝ๏ธ
  • total-time (or time-total) โ€” total system time (or wall-clock time, if you passed -w) eaten by a specific syscall.
  • min-time (or shortest or time-min) โ€” the smallest call duration we saw, in seconds.
  • max-time (or longest or time-max) โ€” the biggest call duration we saw, in seconds.
  • avg-time (or time-avg) โ€” average call duration, in microseconds per call.
  • wall-total (or total-wall) โ€” total wall-clock time a specific syscall consumed. This one is always wall-clock no matter what, even if you didn't pass -w โ€” so you can show it right next to total-time in one single run. ๐ŸŒˆ
  • wall-min (or min-wall) โ€” smallest observed wall-clock call duration, in seconds.
  • wall-max (or max-wall) โ€” biggest observed wall-clock call duration, in seconds.
  • wall-avg (or avg-wall) โ€” average wall-clock call duration, in microseconds per call.
  • calls (or count) โ€” how many times it got called. ๐Ÿ”ข
  • errors (or error) โ€” how many times it errored out. ๐Ÿ’€
  • name (or syscall or syscall-name) โ€” the system call's name.

The default value is time-percent,total-time,avg-time,calls,errors,name. And heads up: if you don't explicitly supply the name field, it just gets tacked on as the last column anyway. The strace girlies will not let you forget the name. ๐Ÿ™ˆ

  • -w, --summary-wall-clock โ€” summarizes the wall-clock time for each system call, measured from when it started to when it ended. The default, for reference, is to summarize the system time. โฑ๏ธ

๐ŸŽ€ Tampering ๐ŸŽ€

okay so this is the part where you start messing with syscalls directly, and it's giving mad scientist energy fr fr ๐Ÿงช

  • --inject=syscall_set[:error=errno|:retval=value][:signal=sig][:syscall=syscall][:delay_enter=delay][:delay_exit=delay][:poke_enter=@argN=DATAN,@argM=DATAM...][:poke_exit=@argN=DATAN,@argM=DATAM...][:when=expr] โ€” performs system call tampering for the specified set of system calls.

The syntax of the syscall_set specification is the same as in the --trace option.

At least one of error, retval, signal, delay_enter, delay_exit, poke_enter, or poke_exit action options must be specified. And error and retval are mutually exclusive โ€” you literally cannot pick both, bestie, the vibe check forbids it. ๐Ÿšซ

  • If the error=errno option is specified, a fault gets injected into the system call. This is done by replacing the system call number with -1 (which represents an invalid system call) and setting the error code to the specified errno. This behavior of replacing the syscall number with -1 can be overridden using the syscall= option. The errno can be a symbolic name like ENOSYS, or a numeric value in the range 1..4095.
  • If the retval=value option is specified, a success value gets injected instead. The system call number is replaced the same way as with the error= option, but instead of an error, the specified success value gets returned to the caller process. โœจ
  • If the signal=sig option is specified with either a symbolic value like SIGSEGV or a numeric value within the 1..SIGRTMAX range, that signal is delivered on entering every system call specified by the syscall_set. ๐Ÿšจ
  • If the delay_enter=delay or delay_exit=delay options are specified, delay injection is performed: the tracee gets delayed by the time period specified by delay on entering or exiting the system call, respectively. The format of the delay specification is described in section Time specification format description. ๐ŸŒ
  • If the poke_enter=@argN=DATAN,@argM=DATAM... or poke_exit=@argN=DATAN,@argM=DATAM... options are specified, the tracee's memory at the locations pointed to by system call arguments argN and argM (going from arg1 to arg7) is overwritten by the data DATAN and DATAM (specified in hexadecimal format; for example poke_enter=@arg1=0000DEAD0000BEEF). The poke_enter option modifies memory on system call enter, while poke_exit does it on system call exit. ๐Ÿช„

The injection actions are independent. For example, specifying only signal= delivers a signal without altering the system call's outcome or delaying it. Similarly, specifying only error= injects a system call fault without adding a signal or delay.

If the signal=sig option is specified together with error=errno or retval=value, then both the injection of a fault or success and the signal delivery are performed.

If the syscall=syscall option is specified, the given syscall is injected instead of the default -1. The specified syscall must have no side effects; currently, only system calls from the %pure set are supported.

Unless the when=expr subexpression is specified, an injection is being made into every invocation of each system call from the syscall_set.

The format of the subexpression is:

first[..last][+[step]]

The number first stands for the first invocation number in the range, the number last stands for the last invocation number in the range, and step stands for the step between two consecutive invocations. The following combinations are useful:

  1. first โ€” injects into invocation number first only, for each system call in the syscall_set.
  2. first..last โ€” injects into invocations from first through last (inclusive), for each system call in the syscall_set.
  3. first+ โ€” injects into every invocation, starting with number first, for each system call in the syscall_set.
  4. first+step โ€” injects into invocations number first, first+step, first+step+step, and so on, for each system call in the syscall_set.
  5. first..last+step โ€” same as the previous one, but only considers invocations with numbers up to last (inclusive).

For example, to fail each third and subsequent chdir system calls with ENOENT, use --inject=chdir:error=ENOENT:when=3+. ๐ŸŽฏ

The valid range for the numbers first and step is 1..65535, and for the number last it's 1..65534.

An injection expression can contain at most one fault or return value specification (i.e., either error= or retval=) and at most one signal= specification. If an injection expression contains multiple when= specifications, the last one takes precedence.

Accounting of system calls that are subject to injection is done per system call and per tracee.

Specification of system call injection can be combined with other system call filtering options โ€” for example, -P /dev/urandom --inject=file:error=ENOENT. ๐Ÿซถ

  • -e inject=args โ€” this is equivalent to --inject=args. Same thing, shorter keyboard journey. ๐Ÿ’…
  • --fault=syscall_set[:error=errno][:when=expr] โ€” performs system call fault injection for the specified set of system calls.

This is a shortcut for the more general --inject= option, using a default errno of ENOSYS.

  • -e fault=args โ€” this is equivalent to --fault=args. โœจ

๐ŸŽ€ Miscellaneous ๐ŸŽ€

the grab bag section, the little extras, the confetti on top ๐ŸŽŠ

  • -d, --debug โ€” shows some debugging output of strace itself on the standard error. Yes bestie, strace can be introspective too. ๐Ÿ”
  • -F โ€” this option is deprecated. It is retained for backward compatibility only and may be removed in future releases. Using multiple -F options is equivalent to a single -f. This option is ignored entirely if used in conjunction with one or more -f options. ๐Ÿ‘ป
  • -h, --help โ€” prints the help summary. Classic. ๐Ÿซถ
  • --seccomp-bpf โ€” attempts to use seccomp-bpf (see seccomp(2)) to cause the kernel to stop the tracee only for the system calls that are being traced.

This option has no effect unless -f/--follow-forks is also specified. --seccomp-bpf is not compatible with --syscall-limit and -b/--detach-on options. It is also not applicable to processes attached using the -p/--attach option.

An attempt to enable system calls filtering using seccomp-bpf may fail for various reasons โ€” e.g. there are too many system calls to filter, the seccomp API is not available, or strace itself is being traced. If the seccomp-bpf filter setup fails, strace just proceeds as usual, stopping traced processes on every system call. No drama, it just keeps going. ๐Ÿ’…

When --seccomp-bpf is activated and the -p/--attach option is not used, the --kill-on-exit option is activated as well. ๐Ÿ‘‘

๐Ÿšจ bestie listen up, this one's lowkey important: in cases where the tracee has another seccomp filter that returns an action value with a precedence greater than SECCOMP_RET_TRACE, strace --seccomp-bpf will not be notified. Like, the tea is: if another seccomp filter, say, disables the system call or just straight-up kills the tracee, then strace --seccomp-bpf will not be aware of that system call invocation at all. Not even a little. ๐Ÿ’€

  • --tips[=[[id:]id],[[format:]format]] โ€” shows strace tips, tricks, and tweaks before exit. ๐ŸŽ€ The id can be a non-negative integer to print one specific tip (note: these IDs are not guaranteed to be stable, so don't get attached). It can also be random (which is the default), and then you just get a random tip, like a little fortune cookie but for syscalls ๐Ÿ“. format can be one of these:
    • none โ€” no tip is printed. Can be used to override the previous setting.
    • compact โ€” prints the tip just big enough to contain all the text.
    • full โ€” prints the tip in its full glory. ๐Ÿ‘‘

Default is id:random,format:compact.

  • -V, --version โ€” prints the version number of strace and the list of enabled optional features. Multiple instances of this option beyond specific threshold tend to increase der Strauss awareness. ๐Ÿ™ˆ

โฐ Time specification format description โฐ

Time values are specified as a decimal floating point number (in a format accepted by strtod(3)), optionally followed by a suffix to indicate the unit of time: s (seconds), ms (milliseconds), us (microseconds), or ns (nanoseconds). If no suffix is specified, the value defaults to microseconds. ๐Ÿซถ

The described format is used for -O, --inject=delay_enter, and --inject=delay_exit options.


๐Ÿ’– DIAGNOSTICS ๐Ÿ’–

When command exits, strace exits with the same exit status. If command is terminated by a signal, strace terminates itself with the same signal, so that strace can be used as a wrapper process transparent to the invoking parent process. Honestly? Iconic behaviour. โœจ

โš ๏ธ Note though: the parent-child relationship (signal stop notifications, the getppid(2) value, etc) between the traced process and its parent is not preserved unless -D is used. So like, the vibes are preserved but the family tree is not. ๐Ÿ˜ญ

When using -p without a command, the exit status of strace is zero unless no processes have been attached or an unexpected error occurred during tracing.

๐Ÿ‘‘ SETUID INSTALLATION ๐Ÿ‘‘

If strace is installed setuid to root, then the invoking user will be able to attach to and trace processes owned by any user. In addition, setuid and setgid programs will be executed and traced with the correct effective privileges. Big power. ๐ŸŒˆ

Since these capabilities should only be granted to users with full root privileges, installing strace as setuid to root is only appropriate when its use is restricted to such trusted users. For example, a special version of strace could be installed with mode rwsr-x---, user root, and group trace. In this configuration, only trusted users who are members of the trace group could execute it.

๐Ÿ’… If you use this feature, remember to also install a regular, non-setuid version of strace for ordinary users. The trusted besties get the special one, everyone else gets the normal one, and that's the whole point.

๐Ÿฆ‹ MULTIPLE PERSONALITIES SUPPORT ๐Ÿฆ‹

On some architectures, strace can decode system calls for processes that use a different Application Binary Interface (ABI) from the one strace uses. Specifically, in addition to decoding native ABI, strace can decode the following ABIs on the following architectures:

  • x86_64 โ€” i386, x32 [1]; i386 [2]
  • AArch64 โ€” ARM 32-bit EABI
  • PowerPC 64-bit [3] โ€” PowerPC 32-bit
  • s390x โ€” s390
  • SPARC 64-bit โ€” SPARC 32-bit
  • TILE 64-bit โ€” TILE 32-bit

[1] When strace is built as an x86_64 application [2] When strace is built as an x32 application [3] Big endian only

This support is optional and depends on the ability to generate and parse structure definitions at build time. Refer to the output of the strace -V command to determine which ABIs are supported by your strace build. In this context, "non-native" refers to an ABI that differs from the one strace is using:

  • m32-mpers โ€” strace can trace and properly decode non-native 32-bit binaries.
  • no-m32-mpers โ€” strace can trace, but cannot properly decode non-native 32-bit binaries. ๐Ÿ™ˆ
  • mx32-mpers โ€” strace can trace and properly decode non-native 32-on-64-bit binaries.
  • no-mx32-mpers โ€” strace can trace, but cannot properly decode non-native 32-on-64-bit binaries. ๐Ÿ˜ญ

If the output contains neither m32-mpers nor no-m32-mpers, it means that support for decoding non-native 32-bit binaries is not applicable to the architecture.

Likewise, if the output contains neither mx32-mpers nor no-mx32-mpers, it means that support for decoding non-native 32-on-64-bit binaries is not applicable to the architecture.


๐Ÿ“ NOTES ๐Ÿ“

Systems that use shared libraries often produce a large amount of tracing output when loading them. So yeah, brace yourself, the wall of text is coming and it's not personal. ๐Ÿซถ

It is instructive to think about system call inputs and outputs as data-flow across the user/kernel boundary. Because user-space and kernel-space are separate and address-protected, it is sometimes possible to make deductive inferences about process behavior using inputs and outputs as propositions. Detective mode: activated ๐Ÿ•ต๏ธ

In some cases, a system call will differ from the documented behavior or have a different name. For example, the underlying faccessat(2) system call does not have a flags argument, and the setrlimit(2) library function is implemented using prlimit64(2) system call on modern (2.6.38+) kernels. These discrepancies are normal characteristics of the system call interface and are handled by C library wrapper functions.

Some system calls have different names in different architectures and personalities. In these cases, system call filtering and printing uses the names that match corresponding __NR_* kernel macros of the tracee's architecture and personality. There are two exceptions from this general rule: arm_fadvise64_64(2) ARM system call and xtensa_fadvise64_64(2) Xtensa system call are filtered and printed as fadvise64_64(2).

On the x32 ABI, some system calls are intended for 64-bit processes but can be invoked from x32 by setting the __X32_SYSCALL_BIT flag. When this occurs, strace designates these calls with a #64 suffix. An example is readv(2), which is syscall number 19 on x86_64, whereas its distinct x32 counterpart is syscall number 515.

On some platforms, a process attached with the -p option may receive a spurious EINTR error from a non-restartable system call. This can have an unpredictable effect on the process if it does not attempt to restart the call. Ideally, all system calls should be restarted on strace attach, making the attach invisible to the traced process, but a few system calls aren't. Arguably, every instance of such behavior is a kernel bug. ๐Ÿ‘€

Since strace executes the specified command directly without a shell, scripts that lack a shebang line (e.g., #!/bin/sh) will fail with an ENOEXEC error, even if a shell could run them correctly. It is advisable to manually supply a shell as a command with the script as its argument.

๐Ÿ’€ BUGS ๐Ÿ’€

Programs that use the setuid bit do not have effective user ID privileges while being traced.

A traced process runs more slowly than a non-traced one. The performance impact can be mitigated by using the --seccomp-bpf option.

When tracing a command, its descendant processes may be left running after strace is terminated by an interrupt signal (such as CTRL-C). This can be prevented by using the --kill-on-exit option, or by using --seccomp-bpf option in a way that implies --kill-on-exit.

A traced process can use the CLONE_UNTRACED flag with the clone system call to create a child process that is not traced by strace. This breaks a guarantee of the --seccomp-bpf option, as this untraced child may be left with an active seccomp filter after strace terminates. ๐Ÿšฉ

๐Ÿ“œ HISTORY ๐Ÿ“œ

okay so storytime bestie, because strace has LORE ๐Ÿซถ

The original strace was written by Paul Kranenburg for SunOS, and it was inspired by its trace utility. The SunOS version of strace got ported to Linux and glow-up'd by Branko Lankester, who also wrote the Linux kernel support. So even though Paul released strace 2.5 in 1992, Branko's work was based on Paul's strace 1.5 release from 1991. baby strace era ๐Ÿ’€

Then in 1993, Rick Sladkey took on the project โ€” main character move honestly ๐Ÿ‘‘ He merged strace 2.5 for SunOS with the second release of strace for Linux, added many features from SVR4's truss(1), and produced a version of strace that worked on both platforms. In 1994, Rick ported strace to SVR4 and Solaris and wrote the automatic configuration support โœจ. In 1995 he ported strace to Irix (and became tired of writing about himself in the third person) ๐Ÿ˜ญ๐Ÿ˜ญ iconic.

Beginning with 1996, strace was maintained by Wichert Akkerman. During his tenure, strace development migrated to CVS; and ports to FreeBSD and many architectures on Linux (including ARM, IA-64, MIPS, PA-RISC, PowerPC, s390, SPARC) were introduced. so many platforms bestie, it's giving multiverse ๐ŸŒˆ

In 2002, responsibility for strace maintenance was transferred to Roland McGrath. Since then, strace gained support for several new Linux architectures (AMD64, s390x, SuperH), bi-architecture support for some of them, and received numerous additions and improvements in system calls decoders on Linux; and strace development migrated to Git during that period ๐Ÿงš

Since 2009, strace has been actively maintained by Dmitry Levin. During this period, strace has gained support for the AArch64, ARC, AVR32, Blackfin, C-SKY, LoongArch, Meta, Nios II, OpenRISC 1000, RISC-V, Tile/TileGx, and Xtensa architectures. In 2012, unmaintained and apparently broken support for non-Linux operating systems was removed ๐Ÿ—‘๏ธ (rip but also slay). Also, in 2012 strace gained support for path tracing and file descriptor path decoding. In 2014, support for stack trace printing was added. In 2016, system call tampering was implemented ๐Ÿ‘€

For the additional information, please refer to the NEWS file and strace repository commit log. the receipts are all there fr fr ๐Ÿ’…


๐Ÿ› REPORTING BUGS ๐Ÿ›

Found a problem with strace? bestie don't suffer in silence ๐Ÿ˜ค Problems with strace should be reported to the strace mailing list ๐Ÿ“ฌ


๐Ÿ‘€ SEE ALSO ๐Ÿ‘€

also, the strace Home Page exists and is out there living its best life ๐ŸŒธ


๐Ÿ’– AUTHORS ๐Ÿ’–

The complete list of strace contributors can be found in the CREDITS file. so many legends, we love a collaborative queen ๐Ÿ‘‘


and that's the whole page bestie, you read all of it, I'm so proud of you ๐Ÿ˜ญ๐Ÿซถ

this beauty is strace 7.3, dated 2026-06-25, and yes it's still STRACE(1) โœจ go forth and trace responsibly ๐Ÿ’…๐ŸŽ€๐Ÿฆ‹

๐Ÿ“ฆ where this page comes from
  • fedora 43: strace 7.3-1.fc43 ยท LGPL-2.1-or-later AND GPL-2.0-or-later AND GPL-3.0-or-later AND BSD-2-Clause AND BSD-3-Clause AND (GPL-1.0-or-later WITH Linux-syscall-note) AND (GPL-2.0-or-later WITH Linux-syscall-note) AND (GPL-2.0-only WITH Linux-syscall-note) AND (LGPL-2.0-or-later WITH Linux-syscall-note) AND (LGPL-2.1-or-later WITH Linux-syscall-note) AND ((GPL-2.0-only WITH Linux-syscall-note) OR Linux-OpenIB) AND ((GPL-2.0-only WITH Linux-syscall-note) OR MIT) AND ((GPL-2.0-or-later WITH Linux-syscall-note) OR BSD-3-Clause) AND ISC AND X11 AND FSFAP AND FSFUL AND FSFULLR AND FSFULLRWD
  • fedora 44: strace 7.3-1.fc44 ยท LGPL-2.1-or-later AND GPL-2.0-or-later AND GPL-3.0-or-later AND BSD-2-Clause AND BSD-3-Clause AND (GPL-1.0-or-later WITH Linux-syscall-note) AND (GPL-2.0-or-later WITH Linux-syscall-note) AND (GPL-2.0-only WITH Linux-syscall-note) AND (LGPL-2.0-or-later WITH Linux-syscall-note) AND (LGPL-2.1-or-later WITH Linux-syscall-note) AND ((GPL-2.0-only WITH Linux-syscall-note) OR Linux-OpenIB) AND ((GPL-2.0-only WITH Linux-syscall-note) OR MIT) AND ((GPL-2.0-or-later WITH Linux-syscall-note) OR BSD-3-Clause) AND ISC AND X11 AND FSFAP AND FSFUL AND FSFULLR AND FSFULLRWD
  • ๐Ÿ“œ the page's license: LGPL-2.1-or-later
  • ๐Ÿ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms