|
#!/usr/bin/python |
|
|
|
from __future__ import print_function |
|
from bcc import BPF, USDT |
|
import ctypes as ct |
|
import sys |
|
import json |
|
import subprocess |
|
|
|
pid = sys.argv[1] |
|
|
|
def out_cmd(cmd): |
|
return subprocess.check_output(cmd, shell=True).decode("utf-8") |
|
|
|
# pin map to path so it's globally accessible |
|
# dump with: sudo bpftool map dump pinned /sys/fs/bpf/map_instruction |
|
# tamper with: sudo bpftool map update pinned /sys/fs/bpf/map_instruction key 0 0 0 0 value 0xff 0 0 0 0 0 0 0 any |
|
def pin_map(map_name): |
|
cmd = 'sudo bpftool -j map list' |
|
for m in json.loads(out_cmd(cmd)): |
|
if 'name' in m and m['name'] == map_name: |
|
print ('pinning ' + str(m['id']) + ' to path ' + '/sys/fs/bpf/' + map_name) |
|
out_cmd('bpftool -j map pin id ' + str(m['id']) + ' /sys/fs/bpf/' + map_name) |
|
return |
|
|
|
# load BPF program |
|
bpf_text = """ |
|
#include <uapi/linux/ptrace.h> |
|
#include <linux/sched.h> |
|
BPF_PERF_OUTPUT(events); |
|
BPF_ARRAY(map_instruction, long, 1); |
|
|
|
struct xchange_t { |
|
u32 pid; |
|
} __attribute__((__packed__)); |
|
|
|
int do_trace(struct pt_regs *ctx) { |
|
uint64_t addr; |
|
struct xchange_t data = {}; |
|
long *value; |
|
uint32_t key = 0; |
|
|
|
value = map_instruction.lookup(&key); |
|
if (value) *value += 1; |
|
|
|
// get some data |
|
data.pid = bpf_get_current_pid_tgid(); |
|
|
|
// ship userland |
|
events.perf_submit(ctx, &data, sizeof(data)); |
|
return 0; |
|
}; |
|
""" |
|
|
|
class Xchange(ct.Structure): |
|
_fields_ = [("pid", ct.c_uint)] |
|
|
|
# enable USDT probe from given PID |
|
u = USDT(pid=int(pid)) |
|
u.enable_probe(probe="test-probe", fn_name="do_trace") |
|
|
|
# initialize BPF |
|
b = BPF(text=bpf_text, usdt_contexts=[u]) |
|
|
|
# define map |
|
map_instruction = b.get_table("map_instruction") |
|
pin_map('map_instruction') |
|
|
|
# process event |
|
def print_event(cpu, data, size): |
|
data_parsed = ct.cast(data, ct.POINTER(Xchange)).contents |
|
print(">> pid:", data_parsed.pid, "map_value:", map_instruction[0].value) |
|
|
|
# loop with callback to print_event |
|
b["events"].open_perf_buffer(print_event) |
|
while 1: |
|
try: |
|
b.perf_buffer_poll() |
|
except KeyboardInterrupt: |
|
out_cmd('sudo rm -rf /sys/fs/bpf/map_instruction') |
|
exit() |