Home / Alt manpages / proc_pid_syscall(5)

  • proc_pid_syscall(5)
  • File format
  • linux

Read a Process's Current System Call from /proc

You will finish with a read-only way to inspect the system call state of a Linux process, understand the register values that come back, and report an access failure without mistaking it for missing data. The examples follow the installed proc_pid_syscall(5) page from Linux man-pages 6.7-2 on a Linux 6.8.0-139-generic x86_64 kernel.

Allow about ten minutes. You need a shell and a process ID. No package, service or kernel setting needs to change. Reading another process can require the access allowed by the host's ptrace policy, so keep the first test to your own process.

1. Read your own process entry

The file is named /proc/pid/syscall, where pid is the decimal process ID. In a shell, $$ expands to that shell's PID:

$ printf 'shell pid: %s\n' "$$"
shell pid: 150321
$ cat "/proc/$$/syscall"
0 0x3 0x7857630f9000 0x20000 0x22 0x0 0x7857631c0440 0x7ffd3e555cb8 0x785762f1bd31

The PID and hexadecimal addresses will differ. The first value is the system call number currently being executed. The next six values are the argument registers, followed by the stack pointer and program counter. The file exposes all six argument registers even when the particular system call uses fewer.

Checkpoint: confirm that the file was read, rather than accepting a pasted sample as evidence:

test -r "/proc/$$/syscall" && echo 'proc entry is readable'
cat "/proc/$$/syscall"

This is a snapshot, not a stable event log. A running process can move to another system call immediately after the read, so use the values to investigate a moment, not to reconstruct an entire execution trace.

2. Inspect a known PID carefully

For a process you own, replace PID with the exact decimal PID and read the file directly:

$ PID='12345'
$ cat "/proc/$PID/syscall"
cat: /proc/12345/syscall: No such file or directory

The output above is an example of a process that has already exited, not a required result. Check that the process still exists before interpreting the read:

PID='12345'
if kill -0 "$PID" 2>/dev/null; then
    cat "/proc/$PID/syscall"
else
    printf 'process %s is not available\n' "$PID" >&2
    exit 1
fi

kill -0 does not send a terminating signal. It tests whether the PID can be addressed, but the process can still exit between that check and cat. Treat a missing file as a race or an invalid PID before treating it as a kernel feature problem.

3. Distinguish the three documented states

The contents depend on what the target process is doing when the kernel produces the read:

  • A line beginning with a system call number contains that call's argument registers, stack pointer and program counter.
  • -1 as the system call number means the process is blocked but is not currently in a system call. In that state only the stack pointer and program counter follow it.
  • running means the process is not blocked. There are no register fields to parse after that word.

Do not write a parser that assumes every result is a row of numbers. Handle the literal running state and the -1 state before converting fields from hexadecimal. A process can also change state during the read, so a single result is not a synchronisation primitive.

Checkpoint: record the raw line first when troubleshooting:

PID='12345'
if ! result=$(cat "/proc/$PID/syscall" 2> /tmp/proc-pid-syscall.err); then
    status=$?
    printf 'read failed for PID %s (status %s): %s\n' \
        "$PID" "$status" "$(cat /tmp/proc-pid-syscall.err)" >&2
    exit "$status"
fi
printf 'raw syscall state: %s\n' "$result"

The temporary error file above is safe to remove after inspection with rm -- /tmp/proc-pid-syscall.err. Do not place sensitive process data in a shared temporary directory in a multi-user script without choosing a protected temporary file.

4. Treat permission errors as a separate diagnosis

Access is controlled by the ptrace access mode PTRACE_MODE_ATTACH_FSCREDS. A process can exist and the file can be present while your credentials are still refused. On this host, reading a short-lived background sleep process produced:

$ cat "/proc/150584/syscall"
cat: /proc/150584/syscall: Operation not permitted

That message is not an empty syscall state. It is an access decision. Check the target's identity and your own identity without changing either:

PID='12345'
ps -o pid=,user=,stat=,comm= -p "$PID"
id
ls -l "/proc/$PID/syscall"

Do not make a production script solve this by blindly adding sudo. Elevated access changes the security boundary and may expose more process information than intended. If observation is required, use the host's approved tracing or monitoring policy, document the privilege, and keep the command read-only. A missing privilege is not evidence that the target is idle, blocked or running.

5. Check whether the interface exists

The file is present only when the kernel was configured with CONFIG_HAVE_ARCH_TRACEHOOK. This machine reports that capability as enabled:

$ grep '^CONFIG_HAVE_ARCH_TRACEHOOK=' "/boot/config-$(uname -r)"
CONFIG_HAVE_ARCH_TRACEHOOK=y

Some installations do not expose the kernel configuration at that path. Do not infer support from a failed grep alone. First inspect the target path and the kernel release:

uname -r
test -e "/proc/$$/syscall" && echo 'syscall proc entry exists' || echo 'syscall proc entry is absent'

If the entry is absent for every process, compare the running kernel's configuration and the distribution's kernel documentation before changing anything. This guide does not alter kernel configuration, mount state or boot parameters.

6. Avoid common interpretation traps

The values are architecture-specific register values. The installed page describes their order, but it does not promise that a number has the same meaning on every architecture. Do not label a register as a particular argument type without consulting the system call's own ABI documentation.

The process ID must identify the process whose state you mean. Reading /proc/self/syscall from a helper such as cat reads the helper's state, not the shell or service that launched it. Use /proc/$$/syscall for the current shell, or build the target path before starting a separate reader.

Finally, this interface reports the currently executed call; it does not provide return values, syscall history, or a guarantee that the target remains in that call. Use a tracing facility designed for event history when you need repeated observations, and obtain the required authority before attaching to another process.

Done means

  • You read the exact /proc/PID/syscall entry for a live PID.
  • Your parser handles numeric output, -1, and running separately.
  • You distinguish a vanished process and Operation not permitted from an absent kernel interface.
  • You treat register values as an architecture-specific snapshot, not a syscall history.
  • You made no persistent, service-disrupting or privilege-changing alteration.