xref: /aosp_15_r20/external/bcc/tools/bashreadline.py (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1#!/usr/bin/env python
2#
3# bashreadline  Print entered bash commands from all running shells.
4#               For Linux, uses BCC, eBPF. Embedded C.
5#
6# USAGE: bashreadline [-s SHARED]
7# This works by tracing the readline() function using a uretprobe (uprobes).
8# When you failed to run the script directly with error:
9# `Exception: could not determine address of symbol b'readline'`,
10# you may need specify the location of libreadline.so library
11# with `-s` option.
12#
13# Copyright 2016 Netflix, Inc.
14# Licensed under the Apache License, Version 2.0 (the "License")
15#
16# 28-Jan-2016    Brendan Gregg   Created this.
17# 12-Feb-2016    Allan McAleavy migrated to BPF_PERF_OUTPUT
18
19from __future__ import print_function
20from bcc import BPF
21from time import strftime
22import argparse
23
24parser = argparse.ArgumentParser(
25        description="Print entered bash commands from all running shells",
26        formatter_class=argparse.RawDescriptionHelpFormatter)
27parser.add_argument("-s", "--shared", nargs="?",
28        const="/lib/libreadline.so", type=str,
29        help="specify the location of libreadline.so library.\
30              Default is /lib/libreadline.so")
31args = parser.parse_args()
32
33name = args.shared if args.shared else "/bin/bash"
34
35# load BPF program
36bpf_text = """
37#include <uapi/linux/ptrace.h>
38#include <linux/sched.h>
39
40struct str_t {
41    u32 pid;
42    char str[80];
43};
44
45BPF_PERF_OUTPUT(events);
46
47int printret(struct pt_regs *ctx) {
48    struct str_t data  = {};
49    char comm[TASK_COMM_LEN] = {};
50    if (!PT_REGS_RC(ctx))
51        return 0;
52    data.pid = bpf_get_current_pid_tgid() >> 32;
53    bpf_probe_read_user(&data.str, sizeof(data.str), (void *)PT_REGS_RC(ctx));
54
55    bpf_get_current_comm(&comm, sizeof(comm));
56    if (comm[0] == 'b' && comm[1] == 'a' && comm[2] == 's' && comm[3] == 'h' && comm[4] == 0 ) {
57        events.perf_submit(ctx,&data,sizeof(data));
58    }
59
60
61    return 0;
62};
63"""
64
65b = BPF(text=bpf_text)
66b.attach_uretprobe(name=name, sym="readline", fn_name="printret")
67
68# header
69print("%-9s %-7s %s" % ("TIME", "PID", "COMMAND"))
70
71def print_event(cpu, data, size):
72    event = b["events"].event(data)
73    print("%-9s %-7d %s" % (strftime("%H:%M:%S"), event.pid,
74                            event.str.decode('utf-8', 'replace')))
75
76b["events"].open_perf_buffer(print_event)
77while 1:
78    try:
79        b.perf_buffer_poll()
80    except KeyboardInterrupt:
81        exit()
82