1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/python 2*387f9dfdSAndroid Build Coastguard Worker# 3*387f9dfdSAndroid Build Coastguard Worker# mallocstacks Trace malloc() calls in a process and print the full 4*387f9dfdSAndroid Build Coastguard Worker# stack trace for all callsites. 5*387f9dfdSAndroid Build Coastguard Worker# For Linux, uses BCC, eBPF. Embedded C. 6*387f9dfdSAndroid Build Coastguard Worker# 7*387f9dfdSAndroid Build Coastguard Worker# This script is a basic example of the new Linux 4.6+ BPF_STACK_TRACE 8*387f9dfdSAndroid Build Coastguard Worker# table API. 9*387f9dfdSAndroid Build Coastguard Worker# 10*387f9dfdSAndroid Build Coastguard Worker# Copyright 2016 GitHub, Inc. 11*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License") 12*387f9dfdSAndroid Build Coastguard Worker 13*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function 14*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF 15*387f9dfdSAndroid Build Coastguard Workerfrom bcc.utils import printb 16*387f9dfdSAndroid Build Coastguard Workerfrom time import sleep 17*387f9dfdSAndroid Build Coastguard Workerimport sys 18*387f9dfdSAndroid Build Coastguard Worker 19*387f9dfdSAndroid Build Coastguard Workerif len(sys.argv) < 2: 20*387f9dfdSAndroid Build Coastguard Worker print("USAGE: mallocstacks PID [NUM_STACKS=1024]") 21*387f9dfdSAndroid Build Coastguard Worker exit() 22*387f9dfdSAndroid Build Coastguard Workerpid = int(sys.argv[1]) 23*387f9dfdSAndroid Build Coastguard Workerif len(sys.argv) == 3: 24*387f9dfdSAndroid Build Coastguard Worker try: 25*387f9dfdSAndroid Build Coastguard Worker assert int(sys.argv[2]) > 0, "" 26*387f9dfdSAndroid Build Coastguard Worker except (ValueError, AssertionError) as e: 27*387f9dfdSAndroid Build Coastguard Worker print("USAGE: mallocstacks PID [NUM_STACKS=1024]") 28*387f9dfdSAndroid Build Coastguard Worker print("NUM_STACKS must be a non-zero, positive integer") 29*387f9dfdSAndroid Build Coastguard Worker exit() 30*387f9dfdSAndroid Build Coastguard Worker stacks = sys.argv[2] 31*387f9dfdSAndroid Build Coastguard Workerelse: 32*387f9dfdSAndroid Build Coastguard Worker stacks = "1024" 33*387f9dfdSAndroid Build Coastguard Worker 34*387f9dfdSAndroid Build Coastguard Worker# load BPF program 35*387f9dfdSAndroid Build Coastguard Workerb = BPF(text=""" 36*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h> 37*387f9dfdSAndroid Build Coastguard Worker 38*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(calls, int); 39*387f9dfdSAndroid Build Coastguard WorkerBPF_STACK_TRACE(stack_traces, """ + stacks + """); 40*387f9dfdSAndroid Build Coastguard Worker 41*387f9dfdSAndroid Build Coastguard Workerint alloc_enter(struct pt_regs *ctx, size_t size) { 42*387f9dfdSAndroid Build Coastguard Worker int key = stack_traces.get_stackid(ctx, BPF_F_USER_STACK); 43*387f9dfdSAndroid Build Coastguard Worker if (key < 0) 44*387f9dfdSAndroid Build Coastguard Worker return 0; 45*387f9dfdSAndroid Build Coastguard Worker 46*387f9dfdSAndroid Build Coastguard Worker // could also use `calls.increment(key, size);` 47*387f9dfdSAndroid Build Coastguard Worker u64 zero = 0, *val; 48*387f9dfdSAndroid Build Coastguard Worker val = calls.lookup_or_try_init(&key, &zero); 49*387f9dfdSAndroid Build Coastguard Worker if (val) { 50*387f9dfdSAndroid Build Coastguard Worker (*val) += size; 51*387f9dfdSAndroid Build Coastguard Worker } 52*387f9dfdSAndroid Build Coastguard Worker return 0; 53*387f9dfdSAndroid Build Coastguard Worker}; 54*387f9dfdSAndroid Build Coastguard Worker""") 55*387f9dfdSAndroid Build Coastguard Worker 56*387f9dfdSAndroid Build Coastguard Workerb.attach_uprobe(name="c", sym="malloc", fn_name="alloc_enter", pid=pid) 57*387f9dfdSAndroid Build Coastguard Workerprint("Attaching to malloc in pid %d, Ctrl+C to quit." % pid) 58*387f9dfdSAndroid Build Coastguard Worker 59*387f9dfdSAndroid Build Coastguard Worker# sleep until Ctrl-C 60*387f9dfdSAndroid Build Coastguard Workertry: 61*387f9dfdSAndroid Build Coastguard Worker sleep(99999999) 62*387f9dfdSAndroid Build Coastguard Workerexcept KeyboardInterrupt: 63*387f9dfdSAndroid Build Coastguard Worker pass 64*387f9dfdSAndroid Build Coastguard Worker 65*387f9dfdSAndroid Build Coastguard Workercalls = b.get_table("calls") 66*387f9dfdSAndroid Build Coastguard Workerstack_traces = b.get_table("stack_traces") 67*387f9dfdSAndroid Build Coastguard Worker 68*387f9dfdSAndroid Build Coastguard Workerfor k, v in reversed(sorted(calls.items(), key=lambda c: c[1].value)): 69*387f9dfdSAndroid Build Coastguard Worker print("%d bytes allocated at:" % v.value) 70*387f9dfdSAndroid Build Coastguard Worker if k.value > 0 : 71*387f9dfdSAndroid Build Coastguard Worker for addr in stack_traces.walk(k.value): 72*387f9dfdSAndroid Build Coastguard Worker printb(b"\t%s" % b.sym(addr, pid, show_offset=True)) 73