Troubleshooting with strace

Scenario 3: Diagnosing Permission Issues

A program sometimes has the correct files available but fails because of permission problems with those files. The Python script in Listing 3 attempts to open a file it doesn't have permission to read.

Listing 3

permission_issue.py

def main():
  try:
    with open('/tmp/no-permission.txt', 'r') as f:
      print("File opened successfully")
  except PermissionError as e:
    print(f"Failed to open file: {e}")
if __name__ == "__main__":
  main()

To try out this example, I'll create a file that the current user doesn't have permission to read:

$ sudo bash -c 'echo "Secret data" > /tmp/no-permission.txt'
$ sudo chown root /tmp/no-permission.txt
$ sudo chmod 600 /tmp/no-permission.txt

Now I'll run the script with strace:

$ strace python3 permission_issue.py

The output shows the following:

openat (AT_FDCWD, "/tmp/no-permission.txt", O_RDONLYI0_CLOEXEC) = -1 EACCES (Permission denied)
write(1, "Failed to open file: [Errno 13] ..., 76Failed to open file: [Errno 13] Permission denied: '/tmp/no-permission.txt') = 76

This output clearly shows that the kernel is denying access to the file due to insufficient permissions and the name of the file that caused the program to fail. Figure 3 shows a typical strace output for permission denied errors.

Figure 3: Strace output showing a permission denied (EACCES) error when the program attempts to access a restricted file.

Scenario 4: Profiling System Call Overhead

Performance issues can often be traced to inefficient system call patterns. Strace can help identify these bottlenecks. Consider the Python script in Listing 4.

Listing 4

io_profile.py

import os
import subprocess
def main():
  # Create a test file
  subprocess.run("dd if=/dev/urandom of=/tmp/test_file bs=1M count=10",
    shell=True, stderr=subprocess.DEVNULL)
  print("Reading file byte-by-byte (inefficient)...")
  # Open the file
  fd = os.open("/tmp/test_file", os.O_RDONLY)
  bytes_read = 0
  # Read one byte at a time (very inefficient)
  for i in range(10000):
    buffer = os.read(fd, 1)
    if buffer:
      bytes_read += 1
  os.close(fd)
  print(f"Read {bytes_read} bytes")
if __name__ == "__main__":
  main()

To profile the program in Listing 4 for system call usage, I will use strace with the -c flag:

$ strace -c python3 io_profile.py

This command produces a summary table showing counts and timing for each system call. Table 1 shows the contents of the summary table.

Table 1

System Call Profiling Results

% Time

Seconds

Usecs/Call

Calls

Errors

Syscall

55.03

0.161835

16

10081

 

read

31.03

0.091243

91243

1

 

wait4

8.02

0.023571

126

187

33

newfstatat

2.89

0.008484

132

64

6

openat

0.82

0.002406

109

22

 

getdents64

0.44

0.001291

15

81

3

lseek

0.39

0.001148

18

61

 

close

0.36

0.001069

11

96

 

fstat

0.28

0.000827

827

1

 

execve

This summary immediately highlights that the application is spending 55 percent of its system call time in read() operations, with 10,081 individual calls. This pattern of many small reads is highly inefficient compared to fewer, larger reads. Armed with this information, I can optimize the I/O strategy to improve performance dramatically. Figure 4 clearly show how system call profiling can identify performance bottlenecks.

Figure 4: System call profiling output showing inefficient I/O patterns with read() calls dominating execution time.

Beyond strace: The Tracing Ecosystem

The strace utility is quite powerful, but it is just one part of a rich ecosystem of Linux tracing tools. For more advanced tracing, consider exploring:

  • ltrace – traces library calls, complementing strace's system call tracing
  • perf – a powerful performance analysis tool with low overhead
  • eBPF/BCC – allows for custom, efficient tracing programs
  • SystemTap – provides a scripting language for creating custom tracing tools
  • ftrace – the kernel's built-in tracing utility

Each of these tools offers different capabilities and performance characteristics, allowing you to choose the right approach for your specific needs.

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy Linux Magazine

SINGLE ISSUES
 
SUBSCRIPTIONS
 
TABLET & SMARTPHONE APPS
Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

  • Practical strace

    After "Hello World," you really need to look at system calls in more detail. In this second of two articles, we'll look at debugging in the real world.

  • strace

    Get started with strace by examining a pair of "Hello World" programs. Next month, in the second part of this two-part series, I'll take a deeper look at strace output.

  • strace and Firejail

    Software from unknown sources always poses some risks. With the strace analysis tool and the Firejail sandbox, you can monitor and isolate unknown applications to safeguard your system.

  • Core Technologies

    Ever wondered what processes are currently doing on your system? Linux has a capable mechanism to answer your questions.

  • LD_PRELOAD

    A little C code and the LD_PRELOAD variable let you customize library functions to modify program behavior.

comments powered by Disqus
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters

Support Our Work

Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.

Learn More

News