blob: 7dfaf3d221cb8966a8a881e30dbea4fbd4e28f9b [file] [log] [blame]
Mark Drayton75291d02016-04-20 14:11:00 -07001#!/usr/bin/env bcc-lua
2--[[
3Copyright 2016 GitHub, Inc
4
5Licensed under the Apache License, Version 2.0 (the "License");
6you may not use this file except in compliance with the License.
7You may obtain a copy of the License at
8
9http://www.apache.org/licenses/LICENSE-2.0
10
11Unless required by applicable law or agreed to in writing, software
12distributed under the License is distributed on an "AS IS" BASIS,
13WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14See the License for the specific language governing permissions and
15limitations under the License.
16--]]
17
18local program = [[
19#include <uapi/linux/ptrace.h>
Mark Drayton266d6f62016-05-24 07:01:01 -070020#include <linux/sched.h>
21
22struct data_t {
23 u64 stack_id;
24 u32 pid;
25 char comm[TASK_COMM_LEN];
26};
Mark Drayton75291d02016-04-20 14:11:00 -070027
28BPF_STACK_TRACE(stack_traces, 128)
Mark Drayton266d6f62016-05-24 07:01:01 -070029BPF_PERF_OUTPUT(events);
Mark Drayton75291d02016-04-20 14:11:00 -070030
31void trace_stack(struct pt_regs *ctx) {
Mark Drayton266d6f62016-05-24 07:01:01 -070032 u32 pid = bpf_get_current_pid_tgid();
Mark Drayton75291d02016-04-20 14:11:00 -070033 FILTER
Mark Drayton266d6f62016-05-24 07:01:01 -070034 struct data_t data = {};
35 data.stack_id = stack_traces.get_stackid(ctx, BPF_F_REUSE_STACKID),
36 data.pid = pid;
37 bpf_get_current_comm(&data.comm, sizeof(data.comm));
38 events.perf_submit(ctx, &data, sizeof(data));
Mark Drayton75291d02016-04-20 14:11:00 -070039}
40]]
41
Mark Drayton266d6f62016-05-24 07:01:01 -070042local ffi = require("ffi")
43
Mark Drayton75291d02016-04-20 14:11:00 -070044return function(BPF, utils)
45 local parser = utils.argparse("stacksnoop",
46 "Trace and print kernel stack traces for a kernel function")
47 parser:flag("-s --offset")
48 parser:flag("-v --verbose")
49 parser:option("-p --pid"):convert(tonumber)
50 parser:argument("function", "kernel function name"):target("fn")
51
52 local args = parser:parse()
53 local ksym = BPF.SymbolCache()
54 local filter = ""
55
56 if args.pid then
Mark Drayton266d6f62016-05-24 07:01:01 -070057 filter = "if (pid != %d) { return; }" % args.pid
Mark Drayton75291d02016-04-20 14:11:00 -070058 end
59
60 local text = program:gsub("FILTER", filter)
61 local bpf = BPF:new{text=text}
62 bpf:attach_kprobe{event=args.fn, fn_name="trace_stack"}
63
64 if BPF.num_open_kprobes() == 0 then
Mark Drayton266d6f62016-05-24 07:01:01 -070065 print("Function \"%s\" not found. Exiting." % {args.fn})
Mark Drayton75291d02016-04-20 14:11:00 -070066 return
67 end
68
69 if args.verbose then
70 print("%-18s %-12s %-6s %-3s %s" %
Mark Drayton266d6f62016-05-24 07:01:01 -070071 {"TIME(s)", "COMM", "PID", "CPU", "FUNCTION"})
Mark Drayton75291d02016-04-20 14:11:00 -070072 else
Mark Drayton266d6f62016-05-24 07:01:01 -070073 print("%-18s %s" % {"TIME(s)", "FUNCTION"})
Mark Drayton75291d02016-04-20 14:11:00 -070074 end
75
76 local stack_traces = bpf:get_table("stack_traces")
Mark Drayton266d6f62016-05-24 07:01:01 -070077 local start_ts = utils.posix.time_ns()
Mark Drayton75291d02016-04-20 14:11:00 -070078
Mark Drayton266d6f62016-05-24 07:01:01 -070079 local function print_event(cpu, event)
80 local ts = (utils.posix.time_ns() - start_ts) / 1e9
Mark Drayton75291d02016-04-20 14:11:00 -070081
Mark Drayton266d6f62016-05-24 07:01:01 -070082 if args.verbose then
83 print("%-18.9f %-12.12s %-6d %-3d %s" %
84 {ts, ffi.string(event.comm), event.pid, cpu, args.fn})
85 else
86 print("%-18.9f %s" % {ts, args.fn})
87 end
88
89 for addr in stack_traces:walk(tonumber(event.stack_id)) do
90 local sym, offset = ksym:resolve(addr)
91 if args.offset then
92 print("\t%-16p %s+0x%x" % {addr, sym, tonumber(offset)})
Mark Drayton75291d02016-04-20 14:11:00 -070093 else
Mark Drayton266d6f62016-05-24 07:01:01 -070094 print("\t%-16p %s" % {addr, sym})
Mark Drayton75291d02016-04-20 14:11:00 -070095 end
96 end
Mark Drayton266d6f62016-05-24 07:01:01 -070097
Mark Drayton75291d02016-04-20 14:11:00 -070098 print()
99 end
Mark Drayton266d6f62016-05-24 07:01:01 -0700100
101 local TASK_COMM_LEN = 16 -- linux/sched.h
102
Vicent Marti973a5282016-05-24 17:57:34 +0200103 bpf:get_table("events"):open_perf_buffer(print_event,
104 "struct { uint64_t stack_id; uint32_t pid; char comm[$]; }",
Mark Drayton5f5687e2017-02-20 18:13:03 +0000105 {TASK_COMM_LEN})
Mark Drayton266d6f62016-05-24 07:01:01 -0700106 bpf:kprobe_poll_loop()
Mark Drayton75291d02016-04-20 14:11:00 -0700107end