Skip to content

Commit

Permalink
tools: syscount: add --errno=EPERM filter
Browse files Browse the repository at this point in the history
Similar to `--filter` which reports all failing syscalls,
`--errno=ENOENT` reports syscalls failing with the specified errno value.

```
$ sudo bcc/tools/syscount.py -e ENOENT
Tracing syscalls, printing top 10... Ctrl+C to quit.
^C[12:07:13]
SYSCALL                   COUNT
open                        330
stat                        240
access                       63
execve                       22
readlink                      3
```
  • Loading branch information
luciang committed Jan 11, 2018
1 parent fe86aee commit 5426ef2
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 3 deletions.
9 changes: 8 additions & 1 deletion man/man8/syscount.8
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
.SH NAME
syscount \- Summarize syscall counts and latencies.
.SH SYNOPSIS
.B syscount [-h] [-p PID] [-i INTERVAL] [-T TOP] [-x] [-L] [-m] [-P] [-l]
.B syscount [-h] [-p PID] [-i INTERVAL] [-T TOP] [-x] [-e ERRNO] [-L] [-m] [-P] [-l]
.SH DESCRIPTION
This tool traces syscall entry and exit tracepoints and summarizes either the
number of syscalls of each type, or the number of syscalls per process. It can
Expand All @@ -29,6 +29,9 @@ Print only this many entries. Default: 10.
\-x
Trace only failed syscalls (i.e., the return value from the syscall was < 0).
.TP
\-e ERRNO
Trace only syscalls that failed with that error (e.g. -e EPERM or -e 1).
.TP
\-m
Display times in milliseconds. Default: microseconds.
.TP
Expand All @@ -53,6 +56,10 @@ Summarize only failed syscalls:
#
.B syscount \-x
.TP
Summarize only syscalls that failed with EPERM:
#
.B syscount \-e EPERM
.TP
Trace PID 181 only:
#
.B syscount \-p 181
Expand Down
23 changes: 23 additions & 0 deletions tools/syscount.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from bcc import BPF
from time import sleep, strftime
import argparse
import errno
import itertools
import subprocess
import sys
Expand Down Expand Up @@ -368,6 +369,19 @@ def parse_syscall(line):
else:
raise Exception("ausyscall: command not found")


def handle_errno(errstr):
try:
return abs(int(errstr))
except ValueError:
pass

try:
return getattr(errno, errstr)
except AttributeError:
raise argparse.ArgumentTypeError("couldn't map %s to an errno" % errstr)


parser = argparse.ArgumentParser(
description="Summarize syscall counts and latencies.")
parser.add_argument("-p", "--pid", type=int, help="trace only this pid")
Expand All @@ -377,6 +391,8 @@ def parse_syscall(line):
help="print only the top syscalls by count or latency")
parser.add_argument("-x", "--failures", action="store_true",
help="trace only failed syscalls (return < 0)")
parser.add_argument("-e", "--errno", type=handle_errno,
help="trace only syscalls that return this error (numeric or EPERM, etc.)")
parser.add_argument("-L", "--latency", action="store_true",
help="collect syscall latency")
parser.add_argument("-m", "--milliseconds", action="store_true",
Expand Down Expand Up @@ -433,6 +449,11 @@ def parse_syscall(line):
return 0;
#endif
#ifdef FILTER_ERRNO
if (args->ret != -FILTER_ERRNO)
return 0;
#endif
#ifdef BY_PROCESS
u32 key = pid_tgid >> 32;
#else
Expand Down Expand Up @@ -461,6 +482,8 @@ def parse_syscall(line):
text = ("#define FILTER_PID %d\n" % args.pid) + text
if args.failures:
text = "#define FILTER_FAILED\n" + text
if args.errno:
text = "#define FILTER_ERRNO %d\n" % abs(args.errno) + text
if args.latency:
text = "#define LATENCY\n" + text
if args.process:
Expand Down
40 changes: 38 additions & 2 deletions tools/syscount_example.txt
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,43 @@ access 1
pause 1
^C

Similar to -x/--failures, sometimes you only care about certain syscall
errors like EPERM or ENONET -- these are the ones that might be worth
investigating with follow-up tools like opensnoop, execsnoop, or
trace. Use the -e/--errno switch for this; the following example also
demonstrates the -e switch, for printing ENOENT failures at predefined intervals:

# syscount -e ENOENT -i 5
Tracing syscalls, printing top 10... Ctrl+C to quit.
[13:15:57]
SYSCALL COUNT
stat 4669
open 1951
access 561
lstat 62
openat 42
readlink 8
execve 4
newfstatat 1

[13:16:02]
SYSCALL COUNT
lstat 18506
stat 13087
open 2907
access 412
openat 19
readlink 12
execve 7
connect 6
unlink 1
rmdir 1
^C

USAGE:
# syscount -h
usage: syscount.py [-h] [-p PID] [-i INTERVAL] [-T TOP] [-x] [-L] [-m] [-P]
[-l]
usage: syscount.py [-h] [-p PID] [-i INTERVAL] [-T TOP] [-x] [-e ERRNO] [-L]
[-m] [-P] [-l]

Summarize syscall counts and latencies.

Expand All @@ -120,6 +153,9 @@ optional arguments:
print summary at this interval (seconds)
-T TOP, --top TOP print only the top syscalls by count or latency
-x, --failures trace only failed syscalls (return < 0)
-e ERRNO, --errno ERRNO
trace only syscalls that return this error (numeric or
EPERM, etc.)
-L, --latency collect syscall latency
-m, --milliseconds display latency in milliseconds (default:
microseconds)
Expand Down

0 comments on commit 5426ef2

Please sign in to comment.