6

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:

3 Answers3

4

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.

Stephen Kitt
  • 434,908
3

Possible solution:

strace -e trace=file sleep 1 2>&1 | grep -v "= -1 ENOENT" > strace.log

strace by default prints to stderr so redirect it to stdout.

1

A slightly more reliable pattern (i.e. slightly less risk of skipping the wrong lines by accident) could be

| grep -v "= -1 ENOENT [(]No such file or directory[)]$"

I.e. copy-paste the end of line, "escaping" the brackets (which might otherwise be treated as special characters), and add the special character $ to the end which "anchors" the pattern to the end of the line.

I can't find any better option in man strace. Quick and dirty text manipulation hacks are the Unix Way :-P.

It's almost certainly possible to do what you want with a custom gdb script. However that's more work, and I don't have such a script prepared.

Another question references a tracefile script, which you would run with the -e option. This is still implemented by parsing the output of strace, and so it does not appear to be entirely reliable either, but I guess it's possible you'd prefer it. https://gitlab.com/ole.tange/tangetools/blob/master/tracefile/tracefile

sourcejedi
  • 50,249