• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/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>
20#include <linux/sched.h>
21
22struct data_t {
23    u64 stack_id;
24    u32 pid;
25    char comm[TASK_COMM_LEN];
26};
27
28BPF_STACK_TRACE(stack_traces, 128);
29BPF_PERF_OUTPUT(events);
30
31void trace_stack(struct pt_regs *ctx) {
32    u32 pid = bpf_get_current_pid_tgid();
33    FILTER
34    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));
39}
40]]
41
42local ffi = require("ffi")
43
44return 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
57    filter = "if (pid != %d) { return; }" % args.pid
58  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
65    print("Function \"%s\" not found. Exiting." % {args.fn})
66    return
67  end
68
69  if args.verbose then
70    print("%-18s %-12s %-6s %-3s %s" %
71        {"TIME(s)", "COMM", "PID", "CPU", "FUNCTION"})
72  else
73    print("%-18s %s" % {"TIME(s)", "FUNCTION"})
74  end
75
76  local stack_traces = bpf:get_table("stack_traces")
77  local start_ts = utils.posix.time_ns()
78
79  local function print_event(cpu, event)
80    local ts = (utils.posix.time_ns() - start_ts) / 1e9
81
82    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)})
93      else
94        print("\t%-16p %s" % {addr, sym})
95      end
96    end
97
98    print()
99  end
100
101  local TASK_COMM_LEN = 16 -- linux/sched.h
102
103  bpf:get_table("events"):open_perf_buffer(print_event,
104    "struct { uint64_t stack_id; uint32_t pid; char comm[$]; }",
105    {TASK_COMM_LEN})
106  bpf:perf_buffer_poll_loop()
107end
108