1#!/usr/bin/python 2# 3# mallocstacks Trace malloc() calls in a process and print the full 4# stack trace for all callsites. 5# For Linux, uses BCC, eBPF. Embedded C. 6# 7# This script is a basic example of the new Linux 4.6+ BPF_STACK_TRACE 8# table API. 9# 10# Copyright 2016 GitHub, Inc. 11# Licensed under the Apache License, Version 2.0 (the "License") 12 13from __future__ import print_function 14from bcc import BPF 15from time import sleep 16import sys 17 18if len(sys.argv) < 2: 19 print("USAGE: mallocstacks PID") 20 exit() 21pid = int(sys.argv[1]) 22 23# load BPF program 24b = BPF(text=""" 25#include <uapi/linux/ptrace.h> 26 27BPF_HASH(calls, int); 28BPF_STACK_TRACE(stack_traces, 1024); 29 30int alloc_enter(struct pt_regs *ctx, size_t size) { 31 int key = stack_traces.get_stackid(ctx, 32 BPF_F_USER_STACK|BPF_F_REUSE_STACKID); 33 if (key < 0) 34 return 0; 35 36 // could also use `calls.increment(key, size);` 37 u64 zero = 0, *val; 38 val = calls.lookup_or_init(&key, &zero); 39 (*val) += size; 40 return 0; 41}; 42""") 43 44b.attach_uprobe(name="c", sym="malloc", fn_name="alloc_enter", pid=pid) 45print("Attaching to malloc in pid %d, Ctrl+C to quit." % pid) 46 47# sleep until Ctrl-C 48try: 49 sleep(99999999) 50except KeyboardInterrupt: 51 pass 52 53calls = b.get_table("calls") 54stack_traces = b.get_table("stack_traces") 55 56for k, v in reversed(sorted(calls.items(), key=lambda c: c[1].value)): 57 print("%d bytes allocated at:" % v.value) 58 for addr in stack_traces.walk(k.value): 59 print("\t%s" % b.sym(addr, pid, show_offset=True)) 60