3

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?

4
+100

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.

1

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.