strace Command in Linux: Trace System Calls

strace Command in Linux: Trace System Calls

A program exits with a vague error, or hangs, and the logs say nothing useful. Before guessing, you can watch exactly what the program asks the kernel to do. Every time a process opens a file, reads a socket, or allocates memory, it makes a system call, and strace records each one along with its arguments and return value. That trace often reveals the real problem in seconds: a config file the program looked for in the wrong place, a permission denied on a socket, or a call that blocks forever.

This guide explains how to trace a command with strace, attach to a running process, filter the calls you care about, and read the output to find the failing call.

Installing strace

strace is not always installed by default, so add it from your distribution’s repositories.

On Ubuntu, Debian, and Derivatives:

Terminal

sudo apt install strace

On Fedora, RHEL, and Derivatives:

Terminal

sudo dnf install strace

Tracing a Command

The general syntax is:

txt

strace [OPTIONS] COMMAND [ARGS]

The simplest use is to run a command under strace, which prints every system call the program makes to standard error. Trace a small command such as whoami to see the shape of the output:

Terminal

strace whoami

output

execve("/usr/bin/whoami", ["whoami"], 0x7ffd... /* 25 vars */) = 0
brk(NULL) = 0x55d3...
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
...
openat(AT_FDCWD, "/etc/passwd", O_RDONLY|O_CLOEXEC) = 3
write(1, "dejan\n", 6) = 6
exit_group(0) = ?
+++ exited with 0 +++

Each line is one system call: the name, its arguments in parentheses, and the return value after the =. A return of 3 from openat is a file descriptor, meaning the open succeeded; a return of -1 carries an error name such as ENOENT. Notice the program opened /etc/passwd to look up the user name, then write sent the result to file descriptor 1, which is standard output.

Reading Failed Calls

The reason to reach for strace is usually a failure, and failures are easy to spot because the return value is -1 followed by the error code. Suppose a program cannot start and you trace it:

Terminal

strace ./myapp

A failing line looks like this:

output

openat(AT_FDCWD, "/etc/myapp/config.yaml", O_RDONLY) = -1 ENOENT (No such file or directory)

This single line tells you the program expected its config at /etc/myapp/config.yaml and the file is not there. A -1 EACCES instead would mean the file exists but the process lacks permission. For a short trace, scan for -1 to find failed calls. With a noisy program, use -Z to print only calls that returned an error:

Terminal

strace -Z ./myapp

Not every failed call is the root cause. Programs commonly probe several paths before finding a file, so read the calls around the failure and look for the last relevant error before the program exits.

Filtering the Calls You Care About

A full trace is noisy. When you only care about file access, limit the trace to the relevant calls with -e trace=. To see just the file-opening calls, trace openat:

Terminal

strace -e trace=openat ./myapp

You can name a category instead of individual calls. The %file category covers every call that takes a filename, and %network covers network-related calls:

Terminal

strace -e trace=%file ./myapp
strace -e trace=%network ./myapp

This focus turns a flood of output into the handful of lines that matter for the question you are asking.

Attaching to a Running Process

When a process is already running, perhaps stuck or pinning the CPU, attach to it by PID with -p instead of starting a new program. First find the PID with the ps command
, then attach:

Terminal

sudo strace -p 2841

strace begins printing the calls the live process makes from that moment on. You may not need sudo when the process belongs to your user, but Linux capabilities and the kernel.yama.ptrace_scope setting can impose additional restrictions. Press Ctrl+C to detach and leave the process running. For a hung process, attaching usually shows it parked in a single blocking call such as read or futex, which points straight at what it is waiting for.

Following Child Processes

By default strace follows only the process it started. Programs that fork workers, such as shells or servers, do their real work in children that the trace would miss. Add -f to follow forks so the children are traced too:

Terminal

strace -f ./server

Each line is then prefixed with the PID that made the call, so you can tell the parent and its children apart.

Summarizing System Call Time

Beyond individual calls, strace can profile where a program spends its time in the kernel. The -c flag suppresses the per-call output and prints a summary table when the program exits:

Terminal

strace -c ./myapp

output

% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
41.23 0.004812 18 267 read
22.10 0.002579 10 251 12 openat
15.04 0.001755 14 125 mmap
...
------ ----------- ----------- --------- --------- ----------------
100.00 0.011670 843 14 total

The table ranks system calls by total time, shows how many times each was called, and counts how many returned an error. The 12 openat errors show that some file lookups failed, but programs often probe optional paths as part of normal operation. Inspect the individual calls before treating the count as a problem.

Saving a Trace to a File

Traces scroll fast, so for anything non-trivial write the output to a file with -o and read it afterward:

Terminal

strace -o trace.log -f ./myapp

This keeps strace output separate from the program’s own output and gives you a file to grep, for example grep ENOENT trace.log to list every missing-file error at once.

Quick Reference

Task Command
Trace a command strace ./app
Trace only failed calls strace -Z ./app
Trace only file calls strace -e trace=%file ./app
Trace network calls strace -e trace=%network ./app
Attach to a running process sudo strace -p PID
Follow child processes strace -f ./app
Summarize call time and errors strace -c ./app
Write trace to a file strace -o trace.log ./app

Conclusion

Use focused filters and read the calls around a failure instead of treating every error as the cause. For another view of open files and sockets on a running process, use the lsof command
.

By admin

Leave a Reply

Your email address will not be published. Required fields are marked *