xref: /aosp_15_r20/external/bcc/examples/tracing/undump.py (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1#!/usr/bin/python
2# @lint-avoid-python-3-compatibility-imports
3#
4# undump        Dump UNIX socket packets.
5#               For Linux, uses BCC, eBPF. Embedded C.
6# USAGE: undump [-h] [-t] [-p PID]
7#
8# This uses dynamic tracing of kernel functions, and will need to be updated
9# to match kernel changes.
10#
11# Copyright (c) 2021 Rong Tao.
12# Licensed under the GPL License, Version 2.0
13#
14# 27-Aug-2021   Rong Tao   Created this.
15# 17-Sep-2021   Rong Tao   Simplify according to chenhengqi's suggestion
16#                           https://github.com/iovisor/bcc/pull/3615
17#
18from __future__ import print_function
19from bcc import BPF
20from bcc.containers import filter_by_containers
21from bcc.utils import printb
22import argparse
23from socket import inet_ntop, ntohs, AF_INET, AF_INET6
24from struct import pack
25from time import sleep
26from datetime import datetime
27import sys
28
29# arguments
30examples = """examples:
31    ./undump           # trace/dump all UNIX packets
32    ./undump -p 181    # only trace/dump PID 181
33"""
34parser = argparse.ArgumentParser(
35    description="Dump UNIX socket packets",
36    formatter_class=argparse.RawDescriptionHelpFormatter,
37    epilog=examples)
38
39parser.add_argument("-p", "--pid",
40        help="trace this PID only")
41args = parser.parse_args()
42
43# define BPF program
44bpf_text = """
45#include <uapi/linux/ptrace.h>
46#include <net/sock.h>
47#include <bcc/proto.h>
48#include <linux/aio.h>
49#include <linux/socket.h>
50#include <linux/net.h>
51#include <linux/fs.h>
52#include <linux/mount.h>
53#include <linux/module.h>
54#include <net/sock.h>
55#include <net/af_unix.h>
56
57#define MAX_PKT 512
58struct recv_data_t {
59    u32 recv_len;
60    u8  pkt[MAX_PKT];
61};
62
63// single element per-cpu array to hold the current event off the stack
64BPF_PERCPU_ARRAY(unix_data, struct recv_data_t, 1);
65
66BPF_PERF_OUTPUT(unix_recv_events);
67
68int trace_unix_stream_read_actor(struct pt_regs *ctx)
69{
70    u32 zero = 0;
71    int ret = PT_REGS_RC(ctx);
72    u64 pid_tgid = bpf_get_current_pid_tgid();
73    u32 pid = pid_tgid >> 32;
74    u32 tid = pid_tgid;
75
76    FILTER_PID
77
78    struct sk_buff *skb = (struct sk_buff *)PT_REGS_PARM1(ctx);
79
80    struct recv_data_t *data = unix_data.lookup(&zero);
81    if (!data)
82        return 0;
83
84    unsigned int data_len = skb->len;
85    if(data_len > MAX_PKT)
86        return 0;
87
88    void *iodata = (void *)skb->data;
89    data->recv_len = data_len;
90
91    bpf_probe_read(data->pkt, data_len, iodata);
92    unix_recv_events.perf_submit(ctx, data, data_len+sizeof(u32));
93
94    return 0;
95}
96"""
97
98if args.pid:
99    bpf_text = bpf_text.replace('FILTER_PID',
100        'if (pid != %s) { return 0; }' % args.pid)
101
102bpf_text = bpf_text.replace('FILTER_PID', '')
103
104# process event
105def print_recv_pkg(cpu, data, size):
106    event = b["unix_recv_events"].event(data)
107    if args.pid:
108        print("PID \033[1;31m%s\033[m " % args.pid, end="")
109    print("Recv \033[1;31m%d\033[m bytes" % event.recv_len)
110
111    print("    ", end="")
112    for i in range(0, event.recv_len):
113        print("%02x " % event.pkt[i], end="")
114        sys.stdout.flush()
115        if (i+1)%16 == 0:
116            print("")
117            print("    ", end="")
118    print("")
119
120# initialize BPF
121b = BPF(text=bpf_text)
122b.attach_kprobe(event="unix_stream_read_actor", fn_name="trace_unix_stream_read_actor")
123
124if args.pid:
125    print("Tracing \033[1;31mPID=%s\033[m UNIX socket packets ... Hit Ctrl-C to end" % args.pid)
126else:
127    print("Tracing UNIX socket packets ... Hit Ctrl-C to end")
128
129start_ts = 0
130
131# read events
132b["unix_recv_events"].open_perf_buffer(print_recv_pkg)
133
134while True:
135    try:
136        b.perf_buffer_poll()
137    except KeyboardInterrupt:
138        exit()
139