Filter Out Failed Syscalls from Strace Log – How to

stracesystem-calls

I can run strace on a command like sleep 1
and see what files it's accessing like this:

strace -e trace=file -o strace.log sleep 1

However, on my machine, many of the calls have a return value of -1
indicating that the file does not exist. For example:

$ grep '= -1 ENOENT' strace.log | head
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.UTF-8/LC_IDENTIFICATION", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.UTF-8/LC_MEASUREMENT", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.UTF-8/LC_TELEPHONE", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.UTF-8/LC_ADDRESS", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.UTF-8/LC_NAME", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.UTF-8/LC_PAPER", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)

I'm not really interested in the files that don't exist,
I want to know what files the process actually found and read from.
Aside from grep -v '=-1 ENOENT',
how can I reliably filter out failed calls?

Addendum

I was surprised to learn
that strace has had this feature in the works since 2002
in the form of the -z flag, which is an alias for -e status=successful,
fully functional since version 5.2
(2019-07-12),
also available as --successful-only since version 5.6 (2020-04-07).

Also available since version 5.2 is the complement of -z, the -Z flag,
which is an alias for -e status=failed,
available as --failed-only since version 5.6.

The -z flag was first added in a commit from 2002 and released in version 4.5.18 (2008-08-28),
bit it had never been documented because it was not working properly.

Relevant links:

Best Answer

Apart from post-processing the strace output, there isn’t anything available to ignore failed system calls in strace. It wouldn’t be too hard to add, look at the syscall_exiting_trace function in syscall.c.

If you’d rather pursue the post-processing angle, Ole Tange has already taken care of that for you in a more comprehensive way than you’re likely to get here: the tracefile tool will run strace and filter out the information you’re after in a nicely readable fashion. See List the files accessed by a program for details. Another answer to that question lists other possible approaches, including LoggedFS which I find very useful.

Another option is to use SystemTap; for example

#!/usr/bin/env stap

global stored_filename, stored_path

probe syscall.open {
  stored_filename = filename
}

probe syscall.open.return {
  if (execname() == "cat" && $return >= 0) {
    printf("opened %s\n", stored_filename)
  }
}

probe syscall.openat {
  stored_filename = filename
  stored_path = dfd_str
}

probe syscall.openat.return {
  if (execname() == "cat" && $return >= 0) {
    printf("opened %s in %s\n", stored_filename, stored_path)
  }
}

will show the name of any file successfully opened by any cat process.

Related Question