🔬 strace Quick Reference

strace cheat sheet / survival guide

Video: strace Cheat Sheet (sysadmin video)
Prefer to watch? This video runs the guide's main commands on a real Ubuntu 24.04 machine, with on-screen captions and no voiceover. Click to play, or watch it on YouTube. It is part of the Troubleshooting and Performance playlist.
strace [options] command [args]
strace -p PID

strace shows the system calls a program makes to the Linux kernel: files it opens, network
connections it makes, processes it starts, signals it gets. When a program fails with a
useless error, strace often shows exactly which file, permission or connection it choked on.
Install it with: sudo apt install strace | sudo dnf install strace
Attaching to another user's process needs sudo. Tracing slows the program down a lot,
so be careful on busy production systems.

Start tracing

strace ls /tmp                         # run a command under strace
strace -o out.txt ls /tmp              # write the trace to a file (keeps the screen clean)
strace -p 1234                         # attach to a running process
sudo strace -p 1234                    # ...owned by someone else
strace -f ./script.sh                  # also follow child processes (forks, threads)
strace -ff -o trace ./server           # one file per process: trace.PID
strace -c ls /tmp                      # summary table of calls, counts and time
strace -p 1234 -p 5678                 # several processes
Stop an attached trace with Ctrl+C. That detaches and the program keeps running.

Common options

-o FILE    Write output to FILE                   -f     Follow child processes and threads
-ff        Separate output file per process      -p PID Attach to a running process
-s N       Show up to N characters of strings (default 32; try -s 200)
-v         Do not abbreviate arrays and structures    -x   Print non-ASCII strings in hex
-e EXPR    Filter what is traced (see below)     -c     Count and time calls, print a summary
-C         Like -c but also prints the normal trace
-t / -tt / -ttt   Timestamps: time of day, with microseconds, or epoch seconds
-r         Time since the previous call          -T     Time spent inside each call
-y         Show file paths next to file descriptors   -yy   Also show socket addresses
-i         Show the instruction pointer           -k     Print a stack trace for each call
-q         Suppress attach/detach messages        -qq    Suppress exit messages too
-D         Run the tracer as a detached grandchild (so ps shows less noise)
-E VAR=val Run the command with an environment variable set
-u USER    Run the command as another user        -z     Show only successful calls (newer versions)
-Z         Show only failed calls (newer versions)   -n   Number each line (newer versions)
--follow-forks, --output-separately     Long forms of -f and -ff
Good default for investigating: strace -f -tt -T -s 200 -o trace.txt COMMAND

Reading a line

openat(AT_FDCWD, "/etc/app.conf", O_RDONLY) = -1 ENOENT (No such file or directory)
call   arguments                                 return value   error name and text
- Success returns 0 or a positive number (a file descriptor, or a count of bytes read/written)
- Failure returns -1 followed by an errno name (ENOENT) and its message
- read(3, "hello\n", 4096) = 6     means it read 6 bytes from file descriptor 3
- +++ exited with 0 +++            is the exit status
- --- SIGSEGV {...} ---            is a signal received (SEGV is a crash)
- <unfinished ...> and <... resumed>  show a call interrupted by another thread

Filter what you trace (-e)

strace -e trace=openat,open ls          # only these calls
strace -e trace=file cmd                # calls that take a filename (open, stat, unlink ...)
strace -e trace=process cmd             # fork, exec, exit, wait
strace -e trace=network cmd             # socket, connect, send, recv, bind ...
strace -e trace=memory cmd              # mmap, brk, munmap ...
strace -e trace=signal cmd              # kill, signal handlers
strace -e trace=desc cmd                # calls on file descriptors
strace -e trace=ipc cmd                 # shared memory, semaphores, queues
strace -e trace=%file,%network cmd      # the % form works in newer versions
strace -e trace=!write cmd              # everything except write (quote the ! in shells)
strace -e signal=none cmd               # hide signals
strace -e read=3 cmd                    # dump the data read from fd 3 (-e write=N for writes)
strace -e verbose=none cmd
strace -e status=failed cmd             # only failed calls (newer versions)
strace -e inject=openat:error=ENOENT cmd          # make a call fail on purpose (fault injection)
strace -e inject=openat:error=EACCES:when=3 cmd   # fail only the 3rd call
strace -e inject=read:delay_enter=500ms cmd       # slow down a call to test timeouts

Speed and performance

strace -c ls /tmp                       # counts, errors and time per call
strace -c -f -p 1234                    # summary for a running process and its children
strace -T cmd                           # time spent in each call <0.000123>
strace -r cmd                           # relative time between calls
strace -tt -T -f cmd                    # timestamps plus per-call durations: find the slow call
Sample -c output: % time, seconds, usecs/call, calls, errors, syscall. Sort by the top row.
Anything with a huge count or time usually points at the problem (busy loops, slow reads).

Common system calls

openat / open       Open a file                  read / write        Read or write a descriptor
close               Close a descriptor           stat / fstat / lstat File information
access              Check permissions            execve              Start a program
clone / fork        Create a process or thread   wait4               Wait for a child
socket / connect    Create and connect a socket  bind / listen / accept  Server sockets
sendto / recvfrom   Network data                 poll / epoll_wait / select  Wait for events
mmap / brk          Memory                       futex               Lock waiting between threads
ioctl               Device control               getdents64          Read a directory
nanosleep / clock_nanosleep   Sleeping           unlink / rename     Delete or move a file

Common errno values

ENOENT     No such file or directory     EACCES   Permission denied
EEXIST     File exists                   EISDIR   Is a directory
ENOTDIR    Not a directory               EPERM    Operation not permitted
EAGAIN     Try again (normal for non-blocking I/O)    EINTR   Interrupted by a signal
ECONNREFUSED   Nothing listening there   ETIMEDOUT   Connection timed out
EADDRINUSE     Port already in use       EMFILE   Too many open files
ENOSPC     No space left on device       EPIPE    Broken pipe
ENOENT on a config file or library is the most common cause of "program will not start".

Practical one-liners

# Why won't it start? Which files does it try to open?
strace -f -e trace=openat,open,stat,access -o trace.txt ./myapp
grep ENOENT trace.txt                    # missing files
grep EACCES trace.txt                    # permission problems

# Which config files does this program read?
strace -e trace=openat -f cmd 2>&1 | grep -v ENOENT | grep -E '\.(conf|cfg|ini|yaml|json)'

# What is this hung process waiting on?
sudo strace -p 1234
#   stuck on read(4, ...) or futex(...) or poll(...) shows what it waits for

# What network connections does it make?
strace -f -e trace=network -s 200 -o net.txt curl https://example.com
grep connect net.txt

# What commands does a script really run?
strace -f -e trace=execve -o exec.txt ./install.sh
grep execve exec.txt

# See what a program writes (for example to the terminal or a log)
strace -e trace=write -s 500 cmd

# Which system calls are slow?
strace -c -S time cmd                    # summary sorted by time
strace -f -tt -T -o trace.txt cmd && sort -t'<' -k2 -n -r trace.txt | head

# How many files does it open?
strace -c -e trace=openat cmd

# Which environment variables and libraries does it use?
strace -e trace=openat,execve -f cmd 2>&1 | grep -E '\.so|/etc/'

# Find the log file a daemon writes to
sudo strace -f -e trace=openat,write -p $(pgrep -o daemon) 2>&1 | grep -E '\.log'

# Trace a program started by systemd or a service (attach after it starts)
sudo strace -f -p $(systemctl show -p MainPID --value myservice) -o svc.txt

# Test how an app handles a failing disk or missing file
strace -e inject=openat:error=ENOSPC cmd

# Trace SSH connection problems
strace -f -e trace=network,file -o ssh.txt ssh host
ltrace           Traces library calls (libc functions) instead of system calls
lsof -p PID      Files and sockets a process has open right now
ls -l /proc/PID/fd    Open descriptors straight from /proc
perf trace       Lower-overhead system call tracing (Linux perf)
bpftrace / bcc / eBPF tools   Very low-overhead tracing for production
gdb -p PID       Attach a debugger to inspect a stuck process
dtruss / dtrace  The macOS equivalents (strace itself is Linux only)
tcpdump          Network packets rather than system calls

Common problems

"ptrace: Operation not permitted"   Use sudo, or the kernel restricts ptrace (see /proc/sys/kernel/yama/ptrace_scope)
"attach: ptrace(PTRACE_SEIZE) ... Permission denied"   Same: sudo, or set ptrace_scope to 0 temporarily
Output flies by                    Use -o file, then grep and less it
Strings are cut off                Add -s 200 (or larger)
Program runs very slowly           That is strace overhead: filter with -e trace=... or use -c
Child processes missing            Add -f (follow forks and threads)
Too much noise from read/write     Filter: -e trace=file, or exclude with -e trace=!read,write
Setuid programs do not trace as root   ptrace drops privileges: run strace as root, not the program
Containers                         Needs SYS_PTRACE capability (docker run --cap-add SYS_PTRACE)

Tips

    Start with strace -f -o trace.txt COMMAND, then grep the file for ENOENT, EACCES and ECONNREFUSED.

    Always add -f for anything that starts other processes, including scripts, shells and servers.

    Use -s 200 so you can read the strings, not just the first 32 characters.

    A process stuck in read, poll, epoll_wait or futex is waiting. The descriptor or lock in the arguments shows for what.

    Use -c first for a bird's-eye summary, then trace only the interesting calls with -e trace=.

    ENOENT lines on the way to finding a file (search paths) are often harmless. Look at the last one before the failure.

    strace slows programs down badly. On production, attach briefly, filter tightly, and detach with Ctrl+C.

    Traces may contain passwords, tokens and private data. Treat trace files as sensitive and delete them when done.

    For long-term or low-overhead tracing on busy systems, use perf trace or eBPF tools instead.