xref: /aosp_15_r20/external/bcc/examples/tracing/strlen_hist_ifunc.py (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/python
2*387f9dfdSAndroid Build Coastguard Worker#
3*387f9dfdSAndroid Build Coastguard Worker# strlen_hist_ifunc.py     Histogram of system-wide strlen return values.
4*387f9dfdSAndroid Build Coastguard Worker# This can be used instead of strlen_hist.py if strlen is indirect function.
5*387f9dfdSAndroid Build Coastguard Worker
6*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function
7*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF
8*387f9dfdSAndroid Build Coastguard Workerfrom bcc.libbcc import lib, bcc_symbol, bcc_symbol_option
9*387f9dfdSAndroid Build Coastguard Worker
10*387f9dfdSAndroid Build Coastguard Workerimport ctypes as ct
11*387f9dfdSAndroid Build Coastguard Workerimport sys
12*387f9dfdSAndroid Build Coastguard Workerimport time
13*387f9dfdSAndroid Build Coastguard Worker
14*387f9dfdSAndroid Build Coastguard WorkerNAME = 'c'
15*387f9dfdSAndroid Build Coastguard WorkerSYMBOL = 'strlen'
16*387f9dfdSAndroid Build Coastguard WorkerSTT_GNU_IFUNC = 1 << 10
17*387f9dfdSAndroid Build Coastguard Worker
18*387f9dfdSAndroid Build Coastguard WorkerHIST_BPF_TEXT = """
19*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h>
20*387f9dfdSAndroid Build Coastguard WorkerBPF_HISTOGRAM(dist);
21*387f9dfdSAndroid Build Coastguard Workerint count(struct pt_regs *ctx) {
22*387f9dfdSAndroid Build Coastguard Worker    dist.increment(bpf_log2l(PT_REGS_RC(ctx)));
23*387f9dfdSAndroid Build Coastguard Worker    return 0;
24*387f9dfdSAndroid Build Coastguard Worker}
25*387f9dfdSAndroid Build Coastguard Worker"""
26*387f9dfdSAndroid Build Coastguard Worker
27*387f9dfdSAndroid Build Coastguard WorkerSUBMIT_FUNC_ADDR_BPF_TEXT = """
28*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h>
29*387f9dfdSAndroid Build Coastguard Worker
30*387f9dfdSAndroid Build Coastguard WorkerBPF_PERF_OUTPUT(impl_func_addr);
31*387f9dfdSAndroid Build Coastguard Workervoid submit_impl_func_addr(struct pt_regs *ctx) {
32*387f9dfdSAndroid Build Coastguard Worker    u64 addr = PT_REGS_RC(ctx);
33*387f9dfdSAndroid Build Coastguard Worker    impl_func_addr.perf_submit(ctx, &addr, sizeof(addr));
34*387f9dfdSAndroid Build Coastguard Worker}
35*387f9dfdSAndroid Build Coastguard Worker
36*387f9dfdSAndroid Build Coastguard Worker
37*387f9dfdSAndroid Build Coastguard WorkerBPF_PERF_OUTPUT(resolv_func_addr);
38*387f9dfdSAndroid Build Coastguard Workerint submit_resolv_func_addr(struct pt_regs *ctx) {
39*387f9dfdSAndroid Build Coastguard Worker    u64 rip = PT_REGS_IP(ctx);
40*387f9dfdSAndroid Build Coastguard Worker    resolv_func_addr.perf_submit(ctx, &rip, sizeof(rip));
41*387f9dfdSAndroid Build Coastguard Worker    return 0;
42*387f9dfdSAndroid Build Coastguard Worker}
43*387f9dfdSAndroid Build Coastguard Worker"""
44*387f9dfdSAndroid Build Coastguard Worker
45*387f9dfdSAndroid Build Coastguard Worker
46*387f9dfdSAndroid Build Coastguard Workerdef get_indirect_function_sym(module, symname):
47*387f9dfdSAndroid Build Coastguard Worker    sym = bcc_symbol()
48*387f9dfdSAndroid Build Coastguard Worker    sym_op = bcc_symbol_option()
49*387f9dfdSAndroid Build Coastguard Worker    sym_op.use_debug_file = 1
50*387f9dfdSAndroid Build Coastguard Worker    sym_op.check_debug_file_crc = 1
51*387f9dfdSAndroid Build Coastguard Worker    sym_op.lazy_symbolize = 1
52*387f9dfdSAndroid Build Coastguard Worker    sym_op.use_symbol_type = STT_GNU_IFUNC
53*387f9dfdSAndroid Build Coastguard Worker    if lib.bcc_resolve_symname(
54*387f9dfdSAndroid Build Coastguard Worker            module.encode(),
55*387f9dfdSAndroid Build Coastguard Worker            symname.encode(),
56*387f9dfdSAndroid Build Coastguard Worker            0x0,
57*387f9dfdSAndroid Build Coastguard Worker            0,
58*387f9dfdSAndroid Build Coastguard Worker            ct.byref(sym_op),
59*387f9dfdSAndroid Build Coastguard Worker            ct.byref(sym),
60*387f9dfdSAndroid Build Coastguard Worker    ) < 0:
61*387f9dfdSAndroid Build Coastguard Worker        return None
62*387f9dfdSAndroid Build Coastguard Worker    else:
63*387f9dfdSAndroid Build Coastguard Worker        return sym
64*387f9dfdSAndroid Build Coastguard Worker
65*387f9dfdSAndroid Build Coastguard Worker
66*387f9dfdSAndroid Build Coastguard Workerdef set_impl_func_addr(cpu, data, size):
67*387f9dfdSAndroid Build Coastguard Worker    addr = ct.cast(data, ct.POINTER(ct.c_uint64)).contents.value
68*387f9dfdSAndroid Build Coastguard Worker    global impl_func_addr
69*387f9dfdSAndroid Build Coastguard Worker    impl_func_addr = addr
70*387f9dfdSAndroid Build Coastguard Worker
71*387f9dfdSAndroid Build Coastguard Worker
72*387f9dfdSAndroid Build Coastguard Workerdef set_resolv_func_addr(cpu, data, size):
73*387f9dfdSAndroid Build Coastguard Worker    addr = ct.cast(data, ct.POINTER(ct.c_uint64)).contents.value
74*387f9dfdSAndroid Build Coastguard Worker    global resolv_func_addr
75*387f9dfdSAndroid Build Coastguard Worker    resolv_func_addr = addr
76*387f9dfdSAndroid Build Coastguard Worker
77*387f9dfdSAndroid Build Coastguard Worker
78*387f9dfdSAndroid Build Coastguard Workerdef find_impl_func_offset(ifunc_symbol):
79*387f9dfdSAndroid Build Coastguard Worker    b = BPF(text=SUBMIT_FUNC_ADDR_BPF_TEXT)
80*387f9dfdSAndroid Build Coastguard Worker    b.attach_uprobe(name=NAME, sym=SYMBOL, fn_name=b'submit_resolv_func_addr')
81*387f9dfdSAndroid Build Coastguard Worker    b['resolv_func_addr'].open_perf_buffer(set_resolv_func_addr)
82*387f9dfdSAndroid Build Coastguard Worker    b.attach_uretprobe(name=NAME, sym=SYMBOL, fn_name=b"submit_impl_func_addr")
83*387f9dfdSAndroid Build Coastguard Worker    b['impl_func_addr'].open_perf_buffer(set_impl_func_addr)
84*387f9dfdSAndroid Build Coastguard Worker
85*387f9dfdSAndroid Build Coastguard Worker    print('wait for the first {} call'.format(SYMBOL))
86*387f9dfdSAndroid Build Coastguard Worker    while True:
87*387f9dfdSAndroid Build Coastguard Worker        try:
88*387f9dfdSAndroid Build Coastguard Worker            if resolv_func_addr and impl_func_addr:
89*387f9dfdSAndroid Build Coastguard Worker                b.detach_uprobe(name=NAME, sym=SYMBOL)
90*387f9dfdSAndroid Build Coastguard Worker                b.detach_uretprobe(name=NAME, sym=SYMBOL)
91*387f9dfdSAndroid Build Coastguard Worker                b.cleanup()
92*387f9dfdSAndroid Build Coastguard Worker                break
93*387f9dfdSAndroid Build Coastguard Worker            b.perf_buffer_poll()
94*387f9dfdSAndroid Build Coastguard Worker        except KeyboardInterrupt:
95*387f9dfdSAndroid Build Coastguard Worker            exit()
96*387f9dfdSAndroid Build Coastguard Worker    print('IFUNC resolution of {} is performed'.format(SYMBOL))
97*387f9dfdSAndroid Build Coastguard Worker    print('resolver function address: {:#x}'.format(resolv_func_addr))
98*387f9dfdSAndroid Build Coastguard Worker    print('resolver function offset: {:#x}'.format(ifunc_symbol.offset))
99*387f9dfdSAndroid Build Coastguard Worker    print('function implementation address: {:#x}'.format(impl_func_addr))
100*387f9dfdSAndroid Build Coastguard Worker    impl_func_offset = impl_func_addr - resolv_func_addr + ifunc_symbol.offset
101*387f9dfdSAndroid Build Coastguard Worker    print('function implementation offset: {:#x}'.format(impl_func_offset))
102*387f9dfdSAndroid Build Coastguard Worker    return impl_func_offset
103*387f9dfdSAndroid Build Coastguard Worker
104*387f9dfdSAndroid Build Coastguard Worker
105*387f9dfdSAndroid Build Coastguard Workerdef main():
106*387f9dfdSAndroid Build Coastguard Worker    ifunc_symbol = get_indirect_function_sym(NAME, SYMBOL)
107*387f9dfdSAndroid Build Coastguard Worker    if not ifunc_symbol:
108*387f9dfdSAndroid Build Coastguard Worker        sys.stderr.write('{} is not an indirect function. abort!\n'.format(SYMBOL))
109*387f9dfdSAndroid Build Coastguard Worker        exit(1)
110*387f9dfdSAndroid Build Coastguard Worker
111*387f9dfdSAndroid Build Coastguard Worker    impl_func_offset = find_impl_func_offset(ifunc_symbol)
112*387f9dfdSAndroid Build Coastguard Worker
113*387f9dfdSAndroid Build Coastguard Worker    b = BPF(text=HIST_BPF_TEXT)
114*387f9dfdSAndroid Build Coastguard Worker    b.attach_uretprobe(name=ct.cast(ifunc_symbol.module, ct.c_char_p).value,
115*387f9dfdSAndroid Build Coastguard Worker                       addr=impl_func_offset,
116*387f9dfdSAndroid Build Coastguard Worker                       fn_name=b'count')
117*387f9dfdSAndroid Build Coastguard Worker    dist = b['dist']
118*387f9dfdSAndroid Build Coastguard Worker    try:
119*387f9dfdSAndroid Build Coastguard Worker        while True:
120*387f9dfdSAndroid Build Coastguard Worker            time.sleep(1)
121*387f9dfdSAndroid Build Coastguard Worker            print('%-8s\n' % time.strftime('%H:%M:%S'), end='')
122*387f9dfdSAndroid Build Coastguard Worker            dist.print_log2_hist(SYMBOL + ' return:')
123*387f9dfdSAndroid Build Coastguard Worker            dist.clear()
124*387f9dfdSAndroid Build Coastguard Worker
125*387f9dfdSAndroid Build Coastguard Worker    except KeyboardInterrupt:
126*387f9dfdSAndroid Build Coastguard Worker        pass
127*387f9dfdSAndroid Build Coastguard Worker
128*387f9dfdSAndroid Build Coastguard Worker
129*387f9dfdSAndroid Build Coastguard Workerresolv_func_addr = 0
130*387f9dfdSAndroid Build Coastguard Workerimpl_func_addr = 0
131*387f9dfdSAndroid Build Coastguard Worker
132*387f9dfdSAndroid Build Coastguard Workermain()
133