Commit 6b0ed37f authored by Teng Qin's avatar Teng Qin Committed by 4ast

Add stack trace to trace.py (#712)

parent 0615bff0
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
# Copyright (C) 2016 Sasha Goldshtein. # Copyright (C) 2016 Sasha Goldshtein.
from bcc import BPF, Tracepoint, Perf, USDT from bcc import BPF, Tracepoint, Perf, USDT
from functools import partial
from time import sleep, strftime from time import sleep, strftime
import argparse import argparse
import re import re
...@@ -58,10 +59,12 @@ class Probe(object): ...@@ -58,10 +59,12 @@ class Probe(object):
cls.first_ts = Time.monotonic_time() cls.first_ts = Time.monotonic_time()
cls.pid = args.pid or -1 cls.pid = args.pid or -1
def __init__(self, probe, string_size): def __init__(self, probe, string_size, kernel_stack, user_stack):
self.usdt = None self.usdt = None
self.raw_probe = probe self.raw_probe = probe
self.string_size = string_size self.string_size = string_size
self.kernel_stack = kernel_stack
self.user_stack = user_stack
Probe.probe_count += 1 Probe.probe_count += 1
self._parse_probe() self._parse_probe()
self.probe_num = Probe.probe_count self.probe_num = Probe.probe_count
...@@ -236,6 +239,10 @@ class Probe(object): ...@@ -236,6 +239,10 @@ class Probe(object):
] ]
for i in range(0, len(self.types)): for i in range(0, len(self.types)):
self._generate_python_field_decl(i, fields) self._generate_python_field_decl(i, fields)
if self.kernel_stack:
fields.append(("kernel_stack_id", ct.c_int))
if self.user_stack:
fields.append(("user_stack_id", ct.c_int))
return type(self.python_struct_name, (ct.Structure,), return type(self.python_struct_name, (ct.Structure,),
dict(_fields_=fields)) dict(_fields_=fields))
...@@ -260,12 +267,19 @@ class Probe(object): ...@@ -260,12 +267,19 @@ class Probe(object):
# construct the final display string. # construct the final display string.
self.events_name = "%s_events" % self.probe_name self.events_name = "%s_events" % self.probe_name
self.struct_name = "%s_data_t" % self.probe_name self.struct_name = "%s_data_t" % self.probe_name
self.stacks_name = "%s_stacks" % self.probe_name
stack_table = "BPF_STACK_TRACE(%s, 1024);" % self.stacks_name \
if (self.kernel_stack or self.user_stack) else ""
data_fields = "" data_fields = ""
for i, field_type in enumerate(self.types): for i, field_type in enumerate(self.types):
data_fields += " " + \ data_fields += " " + \
self._generate_field_decl(i) self._generate_field_decl(i)
kernel_stack_str = " int kernel_stack_id;" \
if self.kernel_stack else ""
user_stack_str = " int user_stack_id;" \
if self.user_stack else ""
text = """ text = """
struct %s struct %s
{ {
...@@ -273,11 +287,16 @@ struct %s ...@@ -273,11 +287,16 @@ struct %s
u32 pid; u32 pid;
char comm[TASK_COMM_LEN]; char comm[TASK_COMM_LEN];
%s %s
%s
%s
}; };
BPF_PERF_OUTPUT(%s); BPF_PERF_OUTPUT(%s);
%s
""" """
return text % (self.struct_name, data_fields, self.events_name) return text % (self.struct_name, data_fields,
kernel_stack_str, user_stack_str,
self.events_name, stack_table)
def _generate_field_assign(self, idx): def _generate_field_assign(self, idx):
field_type = self.types[idx] field_type = self.types[idx]
...@@ -346,6 +365,18 @@ BPF_PERF_OUTPUT(%s); ...@@ -346,6 +365,18 @@ BPF_PERF_OUTPUT(%s);
for i, expr in enumerate(self.values): for i, expr in enumerate(self.values):
data_fields += self._generate_field_assign(i) data_fields += self._generate_field_assign(i)
stack_trace = ""
if self.user_stack:
stack_trace += """
__data.user_stack_id = %s.get_stackid(
ctx, BPF_F_REUSE_STACKID | BPF_F_USER_STACK
);""" % self.stacks_name
if self.kernel_stack:
stack_trace += """
__data.kernel_stack_id = %s.get_stackid(
ctx, BPF_F_REUSE_STACKID
);""" % self.stacks_name
text = """ text = """
int %s(%s) int %s(%s)
{ {
...@@ -358,6 +389,7 @@ int %s(%s) ...@@ -358,6 +389,7 @@ int %s(%s)
__data.timestamp_ns = bpf_ktime_get_ns(); __data.timestamp_ns = bpf_ktime_get_ns();
__data.pid = bpf_get_current_pid_tgid(); __data.pid = bpf_get_current_pid_tgid();
bpf_get_current_comm(&__data.comm, sizeof(__data.comm)); bpf_get_current_comm(&__data.comm, sizeof(__data.comm));
%s
%s %s
%s.perf_submit(ctx, &__data, sizeof(__data)); %s.perf_submit(ctx, &__data, sizeof(__data));
return 0; return 0;
...@@ -366,7 +398,8 @@ int %s(%s) ...@@ -366,7 +398,8 @@ int %s(%s)
text = text % (self.probe_name, signature, text = text % (self.probe_name, signature,
pid_filter, prefix, pid_filter, prefix,
self._generate_usdt_filter_read(), self.filter, self._generate_usdt_filter_read(), self.filter,
self.struct_name, data_fields, self.events_name) self.struct_name, data_fields,
stack_trace, self.events_name)
return data_decl + "\n" + text return data_decl + "\n" + text
...@@ -382,7 +415,16 @@ int %s(%s) ...@@ -382,7 +415,16 @@ int %s(%s)
else: # self.probe_type == 't' else: # self.probe_type == 't'
return self.tp_event return self.tp_event
def print_event(self, cpu, data, size): def print_stack(self, bpf, stack_id, pid):
if stack_id < 0:
print(" %d" % stack_id)
return
stack = list(bpf.get_table(self.stacks_name).walk(stack_id))
for addr in stack:
print(" %016x %s" % (addr, bpf.sym(addr, pid)))
def print_event(self, bpf, cpu, data, size):
# Cast as the generated structure type and display # Cast as the generated structure type and display
# according to the format string in the probe. # according to the format string in the probe.
event = ct.cast(data, ct.POINTER(self.python_struct)).contents event = ct.cast(data, ct.POINTER(self.python_struct)).contents
...@@ -395,6 +437,15 @@ int %s(%s) ...@@ -395,6 +437,15 @@ int %s(%s)
(time[:8], event.pid, event.comm[:12], (time[:8], event.pid, event.comm[:12],
self._display_function(), msg)) self._display_function(), msg))
if self.user_stack:
print(" User Stack Trace:")
self.print_stack(bpf, event.user_stack_id, event.pid)
if self.kernel_stack:
print(" Kernel Stack Trace:")
self.print_stack(bpf, event.kernel_stack_id, -1)
if self.user_stack or self.kernel_stack:
print("")
Probe.event_count += 1 Probe.event_count += 1
if Probe.max_events is not None and \ if Probe.max_events is not None and \
Probe.event_count >= Probe.max_events: Probe.event_count >= Probe.max_events:
...@@ -406,7 +457,8 @@ int %s(%s) ...@@ -406,7 +457,8 @@ int %s(%s)
else: else:
self._attach_u(bpf) self._attach_u(bpf)
self.python_struct = self._generate_python_data_decl() self.python_struct = self._generate_python_data_decl()
bpf[self.events_name].open_perf_buffer(self.print_event) callback = partial(self.print_event, bpf)
bpf[self.events_name].open_perf_buffer(callback)
def _attach_k(self, bpf): def _attach_k(self, bpf):
if self.probe_type == "r": if self.probe_type == "r":
...@@ -482,6 +534,10 @@ trace 'u:pthread:pthread_create (arg4 != 0)' ...@@ -482,6 +534,10 @@ trace 'u:pthread:pthread_create (arg4 != 0)'
help="number of events to print before quitting") help="number of events to print before quitting")
parser.add_argument("-o", "--offset", action="store_true", parser.add_argument("-o", "--offset", action="store_true",
help="use relative time from first traced message") help="use relative time from first traced message")
parser.add_argument("-K", "--kernel-stack", action="store_true",
help="output kernel stack trace")
parser.add_argument("-U", "--user_stack", action="store_true",
help="output user stack trace")
parser.add_argument(metavar="probe", dest="probes", nargs="+", parser.add_argument(metavar="probe", dest="probes", nargs="+",
help="probe specifier (see examples)") help="probe specifier (see examples)")
self.args = parser.parse_args() self.args = parser.parse_args()
...@@ -491,7 +547,8 @@ trace 'u:pthread:pthread_create (arg4 != 0)' ...@@ -491,7 +547,8 @@ trace 'u:pthread:pthread_create (arg4 != 0)'
self.probes = [] self.probes = []
for probe_spec in self.args.probes: for probe_spec in self.args.probes:
self.probes.append(Probe( self.probes.append(Probe(
probe_spec, self.args.string_size)) probe_spec, self.args.string_size,
self.args.kernel_stack, self.args.user_stack))
def _generate_program(self): def _generate_program(self):
self.program = """ self.program = """
......
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