Commit c9551307 authored by Sasha Goldshtein's avatar Sasha Goldshtein

Print traceback only if verbose mode was requested

parent a6f5a219
...@@ -16,6 +16,8 @@ from bcc import BPF ...@@ -16,6 +16,8 @@ from bcc import BPF
from time import sleep, strftime from time import sleep, strftime
import argparse import argparse
import re import re
import traceback
import sys
class Specifier(object): class Specifier(object):
probe_text = """ probe_text = """
...@@ -443,7 +445,8 @@ u64 __time = bpf_ktime_get_ns(); ...@@ -443,7 +445,8 @@ u64 __time = bpf_ktime_get_ns();
if not self.is_default_expr else "retval") if not self.is_default_expr else "retval")
data.print_log2_hist(val_type=label) data.print_log2_hist(val_type=label)
examples = """ class Tool(object):
examples = """
Probe specifier syntax: Probe specifier syntax:
{p,r}:[library]:function(signature)[:type[,type...]:expr[,expr...][:filter]][#label] {p,r}:[library]:function(signature)[:type[,type...]:expr[,expr...][:filter]][#label]
Where: Where:
...@@ -510,69 +513,96 @@ argdist -p 2780 -z 120 \\ ...@@ -510,69 +513,96 @@ argdist -p 2780 -z 120 \\
of 120 characters of 120 characters
""" """
parser = argparse.ArgumentParser(description= def __init__(self):
"Trace a function and display a summary of its parameter values.", parser = argparse.ArgumentParser(description="Trace a " +
"function and display a summary of its parameter values.",
formatter_class=argparse.RawDescriptionHelpFormatter, formatter_class=argparse.RawDescriptionHelpFormatter,
epilog=examples) epilog=Tool.examples)
parser.add_argument("-p", "--pid", type=int, parser.add_argument("-p", "--pid", type=int,
help="id of the process to trace (optional)") help="id of the process to trace (optional)")
parser.add_argument("-z", "--string-size", default=80, type=int, parser.add_argument("-z", "--string-size", default=80,
type=int,
help="maximum string size to read from char* arguments") help="maximum string size to read from char* arguments")
parser.add_argument("-i", "--interval", default=1, type=int, parser.add_argument("-i", "--interval", default=1, type=int,
help="output interval, in seconds") help="output interval, in seconds")
parser.add_argument("-n", "--number", type=int, dest="count", parser.add_argument("-n", "--number", type=int, dest="count",
help="number of outputs") help="number of outputs")
parser.add_argument("-v", "--verbose", action="store_true", parser.add_argument("-v", "--verbose", action="store_true",
help="print resulting BPF program code before executing") help="print resulting BPF program code before executing")
parser.add_argument("-T", "--top", type=int, parser.add_argument("-T", "--top", type=int,
help="number of top results to show (not applicable to histograms)") help="number of top results to show (not applicable to " +
parser.add_argument("-H", "--histogram", nargs="*", dest="histspecifier", "histograms)")
metavar="specifier", parser.add_argument("-H", "--histogram", nargs="*",
help="probe specifier to capture histogram of (see examples below)") dest="histspecifier", metavar="specifier",
parser.add_argument("-C", "--count", nargs="*", dest="countspecifier", help="probe specifier to capture histogram of " +
metavar="specifier", "(see examples below)")
help="probe specifier to capture count of (see examples below)") parser.add_argument("-C", "--count", nargs="*",
parser.add_argument("-I", "--include", nargs="*", metavar="header", dest="countspecifier", metavar="specifier",
help="probe specifier to capture count of " +
"(see examples below)")
parser.add_argument("-I", "--include", nargs="*",
metavar="header",
help="additional header files to include in the BPF program") help="additional header files to include in the BPF program")
args = parser.parse_args() self.args = parser.parse_args()
specifiers = [] def _create_specifiers(self):
for specifier in (args.countspecifier or []): self.specifiers = []
specifiers.append(Specifier("freq", specifier, args.pid)) for specifier in (self.args.countspecifier or []):
for histspecifier in (args.histspecifier or []): self.specifiers.append(Specifier(
specifiers.append(Specifier("hist", histspecifier, args.pid)) "freq", specifier, self.args.pid))
if len(specifiers) == 0: for histspecifier in (self.args.histspecifier or []):
self.specifiers.append(
Specifier("hist", histspecifier, self.args.pid))
if len(self.specifiers) == 0:
print("at least one specifier is required") print("at least one specifier is required")
exit(1) exit(1)
bpf_source = """ def _generate_program(self):
bpf_source = """
struct __string_t { char s[%d]; }; struct __string_t { char s[%d]; };
#include <uapi/linux/ptrace.h> #include <uapi/linux/ptrace.h>
""" % args.string_size """ % self.args.string_size
for include in (args.include or []): for include in (self.args.include or []):
bpf_source += "#include <%s>\n" % include bpf_source += "#include <%s>\n" % include
bpf_source += Specifier.generate_auto_includes(map(lambda s: s.raw_spec, specifiers)) bpf_source += Specifier.generate_auto_includes(
for specifier in specifiers: map(lambda s: s.raw_spec, self.specifiers))
for specifier in self.specifiers:
bpf_source += specifier.generate_text() bpf_source += specifier.generate_text()
if self.args.verbose:
if args.verbose:
print(bpf_source) print(bpf_source)
self.bpf = BPF(text=bpf_source)
bpf = BPF(text=bpf_source) def _attach(self):
for specifier in self.specifiers:
for specifier in specifiers: specifier.attach(self.bpf)
specifier.attach(bpf)
count_so_far = 0 def _main_loop(self):
while True: count_so_far = 0
while True:
try: try:
sleep(args.interval) sleep(self.args.interval)
except KeyboardInterrupt: except KeyboardInterrupt:
exit() exit()
print("[%s]" % strftime("%H:%M:%S")) print("[%s]" % strftime("%H:%M:%S"))
for specifier in specifiers: for specifier in self.specifiers:
specifier.display(args.top) specifier.display(self.args.top)
count_so_far += 1 count_so_far += 1
if args.count is not None and count_so_far >= args.count: if self.args.count is not None and \
count_so_far >= self.args.count:
exit() exit()
def run(self):
try:
self._create_specifiers()
self._generate_program()
self._attach()
self._main_loop()
except:
if self.args.verbose:
traceback.print_exc()
else:
print(sys.exc_value)
if __name__ == "__main__":
Tool().run()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment