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