1#!/usr/bin/env bcc-lua
2--[[
3Copyright 2016 Marek Vavrusa <mvavrusa@cloudflare.com>
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-- Trace readline() call from all bash instances (print bash commands from all running shells).
18-- This is rough equivallent to `bashreadline` with output through perf event API.
19-- Source: http://www.brendangregg.com/blog/2016-02-08/linux-ebpf-bcc-uprobes.html
20local ffi = require('ffi')
21local bpf = require('bpf')
22local S = require('syscall')
23-- Perf event map
24local sample_t = 'struct { uint64_t pid; char str[80]; }'
25local events = bpf.map('perf_event_array')
26-- Kernel-space part of the program
27local probe = bpf.uprobe('/bin/bash:readline', function (ptregs)
28	local sample = ffi.new(sample_t)
29	sample.pid = pid_tgid()
30	ffi.copy(sample.str, ffi.cast('char *', ptregs.ax)) -- Cast `ax` to string pointer and copy to buffer
31	perf_submit(events, sample)                         -- Write buffer to perf event map
32end, true, -1, 0)
33-- User-space part of the program
34local log = events:reader(nil, 0, sample_t) -- Must specify PID or CPU_ID to observe
35print('            TASK-PID         TIMESTAMP  FUNCTION')
36print('               | |               |         |')
37while true do
38	log:block()               -- Wait until event reader is readable
39	for _,e in log:read() do  -- Collect available reader events
40		print(string.format('%12s%-16s %-10s %s', '', tonumber(e.pid), os.date("%H:%M:%S"), ffi.string(e.str)))
41	end
42end
43