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