• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 bcc.utils import printb
16from time import sleep
17import sys
18
19if len(sys.argv) < 2:
20    print("USAGE: mallocstacks PID [NUM_STACKS=1024]")
21    exit()
22pid = int(sys.argv[1])
23if len(sys.argv) == 3:
24    try:
25        assert int(sys.argv[2]) > 0, ""
26    except (ValueError, AssertionError) as e:
27        print("USAGE: mallocstacks PID [NUM_STACKS=1024]")
28        print("NUM_STACKS must be a non-zero, positive integer")
29        exit()
30    stacks = sys.argv[2]
31else:
32    stacks = "1024"
33
34# load BPF program
35b = BPF(text="""
36#include <uapi/linux/ptrace.h>
37
38BPF_HASH(calls, int);
39BPF_STACK_TRACE(stack_traces, """ + stacks + """);
40
41int alloc_enter(struct pt_regs *ctx, size_t size) {
42    int key = stack_traces.get_stackid(ctx, BPF_F_USER_STACK);
43    if (key < 0)
44        return 0;
45
46    // could also use `calls.increment(key, size);`
47    u64 zero = 0, *val;
48    val = calls.lookup_or_try_init(&key, &zero);
49    if (val) {
50      (*val) += size;
51    }
52    return 0;
53};
54""")
55
56b.attach_uprobe(name="c", sym="malloc", fn_name="alloc_enter", pid=pid)
57print("Attaching to malloc in pid %d, Ctrl+C to quit." % pid)
58
59# sleep until Ctrl-C
60try:
61    sleep(99999999)
62except KeyboardInterrupt:
63    pass
64
65calls = b.get_table("calls")
66stack_traces = b.get_table("stack_traces")
67
68for k, v in reversed(sorted(calls.items(), key=lambda c: c[1].value)):
69    print("%d bytes allocated at:" % v.value)
70    if k.value > 0 :
71        for addr in stack_traces.walk(k.value):
72            printb(b"\t%s" % b.sym(addr, pid, show_offset=True))
73