xref: /aosp_15_r20/external/bcc/tools/memleak.py (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/env python
2*387f9dfdSAndroid Build Coastguard Worker#
3*387f9dfdSAndroid Build Coastguard Worker# memleak   Trace and display outstanding allocations to detect
4*387f9dfdSAndroid Build Coastguard Worker#           memory leaks in user-mode processes and the kernel.
5*387f9dfdSAndroid Build Coastguard Worker#
6*387f9dfdSAndroid Build Coastguard Worker# USAGE: memleak [-h] [-p PID] [-t] [-a] [-o OLDER] [-c COMMAND]
7*387f9dfdSAndroid Build Coastguard Worker#                [--combined-only] [--wa-missing-free] [-s SAMPLE_RATE]
8*387f9dfdSAndroid Build Coastguard Worker#                [-T TOP] [-z MIN_SIZE] [-Z MAX_SIZE] [-O OBJ]
9*387f9dfdSAndroid Build Coastguard Worker#                [interval] [count]
10*387f9dfdSAndroid Build Coastguard Worker#
11*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License")
12*387f9dfdSAndroid Build Coastguard Worker# Copyright (C) 2016 Sasha Goldshtein.
13*387f9dfdSAndroid Build Coastguard Worker
14*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF
15*387f9dfdSAndroid Build Coastguard Workerfrom time import sleep
16*387f9dfdSAndroid Build Coastguard Workerfrom datetime import datetime
17*387f9dfdSAndroid Build Coastguard Workerimport resource
18*387f9dfdSAndroid Build Coastguard Workerimport argparse
19*387f9dfdSAndroid Build Coastguard Workerimport subprocess
20*387f9dfdSAndroid Build Coastguard Workerimport os
21*387f9dfdSAndroid Build Coastguard Workerimport sys
22*387f9dfdSAndroid Build Coastguard Worker
23*387f9dfdSAndroid Build Coastguard Workerclass Allocation(object):
24*387f9dfdSAndroid Build Coastguard Worker    def __init__(self, stack, size):
25*387f9dfdSAndroid Build Coastguard Worker        self.stack = stack
26*387f9dfdSAndroid Build Coastguard Worker        self.count = 1
27*387f9dfdSAndroid Build Coastguard Worker        self.size = size
28*387f9dfdSAndroid Build Coastguard Worker
29*387f9dfdSAndroid Build Coastguard Worker    def update(self, size):
30*387f9dfdSAndroid Build Coastguard Worker        self.count += 1
31*387f9dfdSAndroid Build Coastguard Worker        self.size += size
32*387f9dfdSAndroid Build Coastguard Worker
33*387f9dfdSAndroid Build Coastguard Workerdef run_command_get_output(command):
34*387f9dfdSAndroid Build Coastguard Worker        p = subprocess.Popen(command.split(),
35*387f9dfdSAndroid Build Coastguard Worker                stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
36*387f9dfdSAndroid Build Coastguard Worker        return iter(p.stdout.readline, b'')
37*387f9dfdSAndroid Build Coastguard Worker
38*387f9dfdSAndroid Build Coastguard Workerdef run_command_get_pid(command):
39*387f9dfdSAndroid Build Coastguard Worker        p = subprocess.Popen(command.split())
40*387f9dfdSAndroid Build Coastguard Worker        return p.pid
41*387f9dfdSAndroid Build Coastguard Worker
42*387f9dfdSAndroid Build Coastguard Workerexamples = """
43*387f9dfdSAndroid Build Coastguard WorkerEXAMPLES:
44*387f9dfdSAndroid Build Coastguard Worker
45*387f9dfdSAndroid Build Coastguard Worker./memleak -p $(pidof allocs)
46*387f9dfdSAndroid Build Coastguard Worker        Trace allocations and display a summary of "leaked" (outstanding)
47*387f9dfdSAndroid Build Coastguard Worker        allocations every 5 seconds
48*387f9dfdSAndroid Build Coastguard Worker./memleak -p $(pidof allocs) -t
49*387f9dfdSAndroid Build Coastguard Worker        Trace allocations and display each individual allocator function call
50*387f9dfdSAndroid Build Coastguard Worker./memleak -ap $(pidof allocs) 10
51*387f9dfdSAndroid Build Coastguard Worker        Trace allocations and display allocated addresses, sizes, and stacks
52*387f9dfdSAndroid Build Coastguard Worker        every 10 seconds for outstanding allocations
53*387f9dfdSAndroid Build Coastguard Worker./memleak -c "./allocs"
54*387f9dfdSAndroid Build Coastguard Worker        Run the specified command and trace its allocations
55*387f9dfdSAndroid Build Coastguard Worker./memleak
56*387f9dfdSAndroid Build Coastguard Worker        Trace allocations in kernel mode and display a summary of outstanding
57*387f9dfdSAndroid Build Coastguard Worker        allocations every 5 seconds
58*387f9dfdSAndroid Build Coastguard Worker./memleak -o 60000
59*387f9dfdSAndroid Build Coastguard Worker        Trace allocations in kernel mode and display a summary of outstanding
60*387f9dfdSAndroid Build Coastguard Worker        allocations that are at least one minute (60 seconds) old
61*387f9dfdSAndroid Build Coastguard Worker./memleak -s 5
62*387f9dfdSAndroid Build Coastguard Worker        Trace roughly every 5th allocation, to reduce overhead
63*387f9dfdSAndroid Build Coastguard Worker"""
64*387f9dfdSAndroid Build Coastguard Worker
65*387f9dfdSAndroid Build Coastguard Workerdescription = """
66*387f9dfdSAndroid Build Coastguard WorkerTrace outstanding memory allocations that weren't freed.
67*387f9dfdSAndroid Build Coastguard WorkerSupports both user-mode allocations made with libc functions and kernel-mode
68*387f9dfdSAndroid Build Coastguard Workerallocations made with kmalloc/kmem_cache_alloc/get_free_pages and corresponding
69*387f9dfdSAndroid Build Coastguard Workermemory release functions.
70*387f9dfdSAndroid Build Coastguard Worker"""
71*387f9dfdSAndroid Build Coastguard Worker
72*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser(description=description,
73*387f9dfdSAndroid Build Coastguard Worker        formatter_class=argparse.RawDescriptionHelpFormatter,
74*387f9dfdSAndroid Build Coastguard Worker        epilog=examples)
75*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-p", "--pid", type=int, default=-1,
76*387f9dfdSAndroid Build Coastguard Worker        help="the PID to trace; if not specified, trace kernel allocs")
77*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-t", "--trace", action="store_true",
78*387f9dfdSAndroid Build Coastguard Worker        help="print trace messages for each alloc/free call")
79*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("interval", nargs="?", default=5, type=int,
80*387f9dfdSAndroid Build Coastguard Worker        help="interval in seconds to print outstanding allocations")
81*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("count", nargs="?", type=int,
82*387f9dfdSAndroid Build Coastguard Worker        help="number of times to print the report before exiting")
83*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-a", "--show-allocs", default=False, action="store_true",
84*387f9dfdSAndroid Build Coastguard Worker        help="show allocation addresses and sizes as well as call stacks")
85*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-o", "--older", default=500, type=int,
86*387f9dfdSAndroid Build Coastguard Worker        help="prune allocations younger than this age in milliseconds")
87*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-c", "--command",
88*387f9dfdSAndroid Build Coastguard Worker        help="execute and trace the specified command")
89*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--combined-only", default=False, action="store_true",
90*387f9dfdSAndroid Build Coastguard Worker        help="show combined allocation statistics only")
91*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--wa-missing-free", default=False, action="store_true",
92*387f9dfdSAndroid Build Coastguard Worker        help="Workaround to alleviate misjudgments when free is missing")
93*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-s", "--sample-rate", default=1, type=int,
94*387f9dfdSAndroid Build Coastguard Worker        help="sample every N-th allocation to decrease the overhead")
95*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-T", "--top", type=int, default=10,
96*387f9dfdSAndroid Build Coastguard Worker        help="display only this many top allocating stacks (by size)")
97*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-z", "--min-size", type=int,
98*387f9dfdSAndroid Build Coastguard Worker        help="capture only allocations larger than this size")
99*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-Z", "--max-size", type=int,
100*387f9dfdSAndroid Build Coastguard Worker        help="capture only allocations smaller than this size")
101*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-O", "--obj", type=str, default="c",
102*387f9dfdSAndroid Build Coastguard Worker        help="attach to allocator functions in the specified object")
103*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--ebpf", action="store_true",
104*387f9dfdSAndroid Build Coastguard Worker        help=argparse.SUPPRESS)
105*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--percpu", default=False, action="store_true",
106*387f9dfdSAndroid Build Coastguard Worker        help="trace percpu allocations")
107*387f9dfdSAndroid Build Coastguard Worker
108*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args()
109*387f9dfdSAndroid Build Coastguard Worker
110*387f9dfdSAndroid Build Coastguard Workerpid = args.pid
111*387f9dfdSAndroid Build Coastguard Workercommand = args.command
112*387f9dfdSAndroid Build Coastguard Workerkernel_trace = (pid == -1 and command is None)
113*387f9dfdSAndroid Build Coastguard Workertrace_all = args.trace
114*387f9dfdSAndroid Build Coastguard Workerinterval = args.interval
115*387f9dfdSAndroid Build Coastguard Workermin_age_ns = 1e6 * args.older
116*387f9dfdSAndroid Build Coastguard Workersample_every_n = args.sample_rate
117*387f9dfdSAndroid Build Coastguard Workernum_prints = args.count
118*387f9dfdSAndroid Build Coastguard Workertop_stacks = args.top
119*387f9dfdSAndroid Build Coastguard Workermin_size = args.min_size
120*387f9dfdSAndroid Build Coastguard Workermax_size = args.max_size
121*387f9dfdSAndroid Build Coastguard Workerobj = args.obj
122*387f9dfdSAndroid Build Coastguard Worker
123*387f9dfdSAndroid Build Coastguard Workerif min_size is not None and max_size is not None and min_size > max_size:
124*387f9dfdSAndroid Build Coastguard Worker        print("min_size (-z) can't be greater than max_size (-Z)")
125*387f9dfdSAndroid Build Coastguard Worker        exit(1)
126*387f9dfdSAndroid Build Coastguard Worker
127*387f9dfdSAndroid Build Coastguard Workerif command is not None:
128*387f9dfdSAndroid Build Coastguard Worker        print("Executing '%s' and tracing the resulting process." % command)
129*387f9dfdSAndroid Build Coastguard Worker        pid = run_command_get_pid(command)
130*387f9dfdSAndroid Build Coastguard Worker
131*387f9dfdSAndroid Build Coastguard Workerbpf_source = """
132*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h>
133*387f9dfdSAndroid Build Coastguard Worker
134*387f9dfdSAndroid Build Coastguard Workerstruct alloc_info_t {
135*387f9dfdSAndroid Build Coastguard Worker        u64 size;
136*387f9dfdSAndroid Build Coastguard Worker        u64 timestamp_ns;
137*387f9dfdSAndroid Build Coastguard Worker        int stack_id;
138*387f9dfdSAndroid Build Coastguard Worker};
139*387f9dfdSAndroid Build Coastguard Worker
140*387f9dfdSAndroid Build Coastguard Workerstruct combined_alloc_info_t {
141*387f9dfdSAndroid Build Coastguard Worker        u64 total_size;
142*387f9dfdSAndroid Build Coastguard Worker        u64 number_of_allocs;
143*387f9dfdSAndroid Build Coastguard Worker};
144*387f9dfdSAndroid Build Coastguard Worker
145*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(sizes, u64);
146*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(allocs, u64, struct alloc_info_t, 1000000);
147*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(memptrs, u64, u64);
148*387f9dfdSAndroid Build Coastguard WorkerBPF_STACK_TRACE(stack_traces, 10240);
149*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(combined_allocs, u64, struct combined_alloc_info_t, 10240);
150*387f9dfdSAndroid Build Coastguard Worker
151*387f9dfdSAndroid Build Coastguard Workerstatic inline void update_statistics_add(u64 stack_id, u64 sz) {
152*387f9dfdSAndroid Build Coastguard Worker        struct combined_alloc_info_t *existing_cinfo;
153*387f9dfdSAndroid Build Coastguard Worker        struct combined_alloc_info_t cinfo = {0};
154*387f9dfdSAndroid Build Coastguard Worker
155*387f9dfdSAndroid Build Coastguard Worker        existing_cinfo = combined_allocs.lookup(&stack_id);
156*387f9dfdSAndroid Build Coastguard Worker        if (existing_cinfo != 0)
157*387f9dfdSAndroid Build Coastguard Worker                cinfo = *existing_cinfo;
158*387f9dfdSAndroid Build Coastguard Worker
159*387f9dfdSAndroid Build Coastguard Worker        cinfo.total_size += sz;
160*387f9dfdSAndroid Build Coastguard Worker        cinfo.number_of_allocs += 1;
161*387f9dfdSAndroid Build Coastguard Worker
162*387f9dfdSAndroid Build Coastguard Worker        combined_allocs.update(&stack_id, &cinfo);
163*387f9dfdSAndroid Build Coastguard Worker}
164*387f9dfdSAndroid Build Coastguard Worker
165*387f9dfdSAndroid Build Coastguard Workerstatic inline void update_statistics_del(u64 stack_id, u64 sz) {
166*387f9dfdSAndroid Build Coastguard Worker        struct combined_alloc_info_t *existing_cinfo;
167*387f9dfdSAndroid Build Coastguard Worker        struct combined_alloc_info_t cinfo = {0};
168*387f9dfdSAndroid Build Coastguard Worker
169*387f9dfdSAndroid Build Coastguard Worker        existing_cinfo = combined_allocs.lookup(&stack_id);
170*387f9dfdSAndroid Build Coastguard Worker        if (existing_cinfo != 0)
171*387f9dfdSAndroid Build Coastguard Worker                cinfo = *existing_cinfo;
172*387f9dfdSAndroid Build Coastguard Worker
173*387f9dfdSAndroid Build Coastguard Worker        if (sz >= cinfo.total_size)
174*387f9dfdSAndroid Build Coastguard Worker                cinfo.total_size = 0;
175*387f9dfdSAndroid Build Coastguard Worker        else
176*387f9dfdSAndroid Build Coastguard Worker                cinfo.total_size -= sz;
177*387f9dfdSAndroid Build Coastguard Worker
178*387f9dfdSAndroid Build Coastguard Worker        if (cinfo.number_of_allocs > 0)
179*387f9dfdSAndroid Build Coastguard Worker                cinfo.number_of_allocs -= 1;
180*387f9dfdSAndroid Build Coastguard Worker
181*387f9dfdSAndroid Build Coastguard Worker        combined_allocs.update(&stack_id, &cinfo);
182*387f9dfdSAndroid Build Coastguard Worker}
183*387f9dfdSAndroid Build Coastguard Worker
184*387f9dfdSAndroid Build Coastguard Workerstatic inline int gen_alloc_enter(struct pt_regs *ctx, size_t size) {
185*387f9dfdSAndroid Build Coastguard Worker        SIZE_FILTER
186*387f9dfdSAndroid Build Coastguard Worker        if (SAMPLE_EVERY_N > 1) {
187*387f9dfdSAndroid Build Coastguard Worker                u64 ts = bpf_ktime_get_ns();
188*387f9dfdSAndroid Build Coastguard Worker                if (ts % SAMPLE_EVERY_N != 0)
189*387f9dfdSAndroid Build Coastguard Worker                        return 0;
190*387f9dfdSAndroid Build Coastguard Worker        }
191*387f9dfdSAndroid Build Coastguard Worker
192*387f9dfdSAndroid Build Coastguard Worker        u64 pid = bpf_get_current_pid_tgid();
193*387f9dfdSAndroid Build Coastguard Worker        u64 size64 = size;
194*387f9dfdSAndroid Build Coastguard Worker        sizes.update(&pid, &size64);
195*387f9dfdSAndroid Build Coastguard Worker
196*387f9dfdSAndroid Build Coastguard Worker        if (SHOULD_PRINT)
197*387f9dfdSAndroid Build Coastguard Worker                bpf_trace_printk("alloc entered, size = %u\\n", size);
198*387f9dfdSAndroid Build Coastguard Worker        return 0;
199*387f9dfdSAndroid Build Coastguard Worker}
200*387f9dfdSAndroid Build Coastguard Worker
201*387f9dfdSAndroid Build Coastguard Workerstatic inline int gen_alloc_exit2(struct pt_regs *ctx, u64 address) {
202*387f9dfdSAndroid Build Coastguard Worker        u64 pid = bpf_get_current_pid_tgid();
203*387f9dfdSAndroid Build Coastguard Worker        u64* size64 = sizes.lookup(&pid);
204*387f9dfdSAndroid Build Coastguard Worker        struct alloc_info_t info = {0};
205*387f9dfdSAndroid Build Coastguard Worker
206*387f9dfdSAndroid Build Coastguard Worker        if (size64 == 0)
207*387f9dfdSAndroid Build Coastguard Worker                return 0; // missed alloc entry
208*387f9dfdSAndroid Build Coastguard Worker
209*387f9dfdSAndroid Build Coastguard Worker        info.size = *size64;
210*387f9dfdSAndroid Build Coastguard Worker        sizes.delete(&pid);
211*387f9dfdSAndroid Build Coastguard Worker
212*387f9dfdSAndroid Build Coastguard Worker        if (address != 0) {
213*387f9dfdSAndroid Build Coastguard Worker                info.timestamp_ns = bpf_ktime_get_ns();
214*387f9dfdSAndroid Build Coastguard Worker                info.stack_id = stack_traces.get_stackid(ctx, STACK_FLAGS);
215*387f9dfdSAndroid Build Coastguard Worker                allocs.update(&address, &info);
216*387f9dfdSAndroid Build Coastguard Worker                update_statistics_add(info.stack_id, info.size);
217*387f9dfdSAndroid Build Coastguard Worker        }
218*387f9dfdSAndroid Build Coastguard Worker
219*387f9dfdSAndroid Build Coastguard Worker        if (SHOULD_PRINT) {
220*387f9dfdSAndroid Build Coastguard Worker                bpf_trace_printk("alloc exited, size = %lu, result = %lx\\n",
221*387f9dfdSAndroid Build Coastguard Worker                                 info.size, address);
222*387f9dfdSAndroid Build Coastguard Worker        }
223*387f9dfdSAndroid Build Coastguard Worker        return 0;
224*387f9dfdSAndroid Build Coastguard Worker}
225*387f9dfdSAndroid Build Coastguard Worker
226*387f9dfdSAndroid Build Coastguard Workerstatic inline int gen_alloc_exit(struct pt_regs *ctx) {
227*387f9dfdSAndroid Build Coastguard Worker        return gen_alloc_exit2(ctx, PT_REGS_RC(ctx));
228*387f9dfdSAndroid Build Coastguard Worker}
229*387f9dfdSAndroid Build Coastguard Worker
230*387f9dfdSAndroid Build Coastguard Workerstatic inline int gen_free_enter(struct pt_regs *ctx, void *address) {
231*387f9dfdSAndroid Build Coastguard Worker        u64 addr = (u64)address;
232*387f9dfdSAndroid Build Coastguard Worker        struct alloc_info_t *info = allocs.lookup(&addr);
233*387f9dfdSAndroid Build Coastguard Worker        if (info == 0)
234*387f9dfdSAndroid Build Coastguard Worker                return 0;
235*387f9dfdSAndroid Build Coastguard Worker
236*387f9dfdSAndroid Build Coastguard Worker        allocs.delete(&addr);
237*387f9dfdSAndroid Build Coastguard Worker        update_statistics_del(info->stack_id, info->size);
238*387f9dfdSAndroid Build Coastguard Worker
239*387f9dfdSAndroid Build Coastguard Worker        if (SHOULD_PRINT) {
240*387f9dfdSAndroid Build Coastguard Worker                bpf_trace_printk("free entered, address = %lx, size = %lu\\n",
241*387f9dfdSAndroid Build Coastguard Worker                                 address, info->size);
242*387f9dfdSAndroid Build Coastguard Worker        }
243*387f9dfdSAndroid Build Coastguard Worker        return 0;
244*387f9dfdSAndroid Build Coastguard Worker}
245*387f9dfdSAndroid Build Coastguard Worker
246*387f9dfdSAndroid Build Coastguard Workerint malloc_enter(struct pt_regs *ctx, size_t size) {
247*387f9dfdSAndroid Build Coastguard Worker        return gen_alloc_enter(ctx, size);
248*387f9dfdSAndroid Build Coastguard Worker}
249*387f9dfdSAndroid Build Coastguard Worker
250*387f9dfdSAndroid Build Coastguard Workerint malloc_exit(struct pt_regs *ctx) {
251*387f9dfdSAndroid Build Coastguard Worker        return gen_alloc_exit(ctx);
252*387f9dfdSAndroid Build Coastguard Worker}
253*387f9dfdSAndroid Build Coastguard Worker
254*387f9dfdSAndroid Build Coastguard Workerint free_enter(struct pt_regs *ctx, void *address) {
255*387f9dfdSAndroid Build Coastguard Worker        return gen_free_enter(ctx, address);
256*387f9dfdSAndroid Build Coastguard Worker}
257*387f9dfdSAndroid Build Coastguard Worker
258*387f9dfdSAndroid Build Coastguard Workerint calloc_enter(struct pt_regs *ctx, size_t nmemb, size_t size) {
259*387f9dfdSAndroid Build Coastguard Worker        return gen_alloc_enter(ctx, nmemb * size);
260*387f9dfdSAndroid Build Coastguard Worker}
261*387f9dfdSAndroid Build Coastguard Worker
262*387f9dfdSAndroid Build Coastguard Workerint calloc_exit(struct pt_regs *ctx) {
263*387f9dfdSAndroid Build Coastguard Worker        return gen_alloc_exit(ctx);
264*387f9dfdSAndroid Build Coastguard Worker}
265*387f9dfdSAndroid Build Coastguard Worker
266*387f9dfdSAndroid Build Coastguard Workerint realloc_enter(struct pt_regs *ctx, void *ptr, size_t size) {
267*387f9dfdSAndroid Build Coastguard Worker        gen_free_enter(ctx, ptr);
268*387f9dfdSAndroid Build Coastguard Worker        return gen_alloc_enter(ctx, size);
269*387f9dfdSAndroid Build Coastguard Worker}
270*387f9dfdSAndroid Build Coastguard Worker
271*387f9dfdSAndroid Build Coastguard Workerint realloc_exit(struct pt_regs *ctx) {
272*387f9dfdSAndroid Build Coastguard Worker        return gen_alloc_exit(ctx);
273*387f9dfdSAndroid Build Coastguard Worker}
274*387f9dfdSAndroid Build Coastguard Worker
275*387f9dfdSAndroid Build Coastguard Workerint mmap_enter(struct pt_regs *ctx) {
276*387f9dfdSAndroid Build Coastguard Worker        size_t size = (size_t)PT_REGS_PARM2(ctx);
277*387f9dfdSAndroid Build Coastguard Worker        return gen_alloc_enter(ctx, size);
278*387f9dfdSAndroid Build Coastguard Worker}
279*387f9dfdSAndroid Build Coastguard Worker
280*387f9dfdSAndroid Build Coastguard Workerint mmap_exit(struct pt_regs *ctx) {
281*387f9dfdSAndroid Build Coastguard Worker        return gen_alloc_exit(ctx);
282*387f9dfdSAndroid Build Coastguard Worker}
283*387f9dfdSAndroid Build Coastguard Worker
284*387f9dfdSAndroid Build Coastguard Workerint munmap_enter(struct pt_regs *ctx, void *address) {
285*387f9dfdSAndroid Build Coastguard Worker        return gen_free_enter(ctx, address);
286*387f9dfdSAndroid Build Coastguard Worker}
287*387f9dfdSAndroid Build Coastguard Worker
288*387f9dfdSAndroid Build Coastguard Workerint posix_memalign_enter(struct pt_regs *ctx, void **memptr, size_t alignment,
289*387f9dfdSAndroid Build Coastguard Worker                         size_t size) {
290*387f9dfdSAndroid Build Coastguard Worker        u64 memptr64 = (u64)(size_t)memptr;
291*387f9dfdSAndroid Build Coastguard Worker        u64 pid = bpf_get_current_pid_tgid();
292*387f9dfdSAndroid Build Coastguard Worker
293*387f9dfdSAndroid Build Coastguard Worker        memptrs.update(&pid, &memptr64);
294*387f9dfdSAndroid Build Coastguard Worker        return gen_alloc_enter(ctx, size);
295*387f9dfdSAndroid Build Coastguard Worker}
296*387f9dfdSAndroid Build Coastguard Worker
297*387f9dfdSAndroid Build Coastguard Workerint posix_memalign_exit(struct pt_regs *ctx) {
298*387f9dfdSAndroid Build Coastguard Worker        u64 pid = bpf_get_current_pid_tgid();
299*387f9dfdSAndroid Build Coastguard Worker        u64 *memptr64 = memptrs.lookup(&pid);
300*387f9dfdSAndroid Build Coastguard Worker        void *addr;
301*387f9dfdSAndroid Build Coastguard Worker
302*387f9dfdSAndroid Build Coastguard Worker        if (memptr64 == 0)
303*387f9dfdSAndroid Build Coastguard Worker                return 0;
304*387f9dfdSAndroid Build Coastguard Worker
305*387f9dfdSAndroid Build Coastguard Worker        memptrs.delete(&pid);
306*387f9dfdSAndroid Build Coastguard Worker
307*387f9dfdSAndroid Build Coastguard Worker        if (bpf_probe_read_user(&addr, sizeof(void*), (void*)(size_t)*memptr64))
308*387f9dfdSAndroid Build Coastguard Worker                return 0;
309*387f9dfdSAndroid Build Coastguard Worker
310*387f9dfdSAndroid Build Coastguard Worker        u64 addr64 = (u64)(size_t)addr;
311*387f9dfdSAndroid Build Coastguard Worker        return gen_alloc_exit2(ctx, addr64);
312*387f9dfdSAndroid Build Coastguard Worker}
313*387f9dfdSAndroid Build Coastguard Worker
314*387f9dfdSAndroid Build Coastguard Workerint aligned_alloc_enter(struct pt_regs *ctx, size_t alignment, size_t size) {
315*387f9dfdSAndroid Build Coastguard Worker        return gen_alloc_enter(ctx, size);
316*387f9dfdSAndroid Build Coastguard Worker}
317*387f9dfdSAndroid Build Coastguard Worker
318*387f9dfdSAndroid Build Coastguard Workerint aligned_alloc_exit(struct pt_regs *ctx) {
319*387f9dfdSAndroid Build Coastguard Worker        return gen_alloc_exit(ctx);
320*387f9dfdSAndroid Build Coastguard Worker}
321*387f9dfdSAndroid Build Coastguard Worker
322*387f9dfdSAndroid Build Coastguard Workerint valloc_enter(struct pt_regs *ctx, size_t size) {
323*387f9dfdSAndroid Build Coastguard Worker        return gen_alloc_enter(ctx, size);
324*387f9dfdSAndroid Build Coastguard Worker}
325*387f9dfdSAndroid Build Coastguard Worker
326*387f9dfdSAndroid Build Coastguard Workerint valloc_exit(struct pt_regs *ctx) {
327*387f9dfdSAndroid Build Coastguard Worker        return gen_alloc_exit(ctx);
328*387f9dfdSAndroid Build Coastguard Worker}
329*387f9dfdSAndroid Build Coastguard Worker
330*387f9dfdSAndroid Build Coastguard Workerint memalign_enter(struct pt_regs *ctx, size_t alignment, size_t size) {
331*387f9dfdSAndroid Build Coastguard Worker        return gen_alloc_enter(ctx, size);
332*387f9dfdSAndroid Build Coastguard Worker}
333*387f9dfdSAndroid Build Coastguard Worker
334*387f9dfdSAndroid Build Coastguard Workerint memalign_exit(struct pt_regs *ctx) {
335*387f9dfdSAndroid Build Coastguard Worker        return gen_alloc_exit(ctx);
336*387f9dfdSAndroid Build Coastguard Worker}
337*387f9dfdSAndroid Build Coastguard Worker
338*387f9dfdSAndroid Build Coastguard Workerint pvalloc_enter(struct pt_regs *ctx, size_t size) {
339*387f9dfdSAndroid Build Coastguard Worker        return gen_alloc_enter(ctx, size);
340*387f9dfdSAndroid Build Coastguard Worker}
341*387f9dfdSAndroid Build Coastguard Worker
342*387f9dfdSAndroid Build Coastguard Workerint pvalloc_exit(struct pt_regs *ctx) {
343*387f9dfdSAndroid Build Coastguard Worker        return gen_alloc_exit(ctx);
344*387f9dfdSAndroid Build Coastguard Worker}
345*387f9dfdSAndroid Build Coastguard Worker"""
346*387f9dfdSAndroid Build Coastguard Worker
347*387f9dfdSAndroid Build Coastguard Workerbpf_source_kernel_node = """
348*387f9dfdSAndroid Build Coastguard Worker
349*387f9dfdSAndroid Build Coastguard WorkerTRACEPOINT_PROBE(kmem, kmalloc_node) {
350*387f9dfdSAndroid Build Coastguard Worker        if (WORKAROUND_MISSING_FREE)
351*387f9dfdSAndroid Build Coastguard Worker            gen_free_enter((struct pt_regs *)args, (void *)args->ptr);
352*387f9dfdSAndroid Build Coastguard Worker        gen_alloc_enter((struct pt_regs *)args, args->bytes_alloc);
353*387f9dfdSAndroid Build Coastguard Worker        return gen_alloc_exit2((struct pt_regs *)args, (size_t)args->ptr);
354*387f9dfdSAndroid Build Coastguard Worker}
355*387f9dfdSAndroid Build Coastguard Worker
356*387f9dfdSAndroid Build Coastguard WorkerTRACEPOINT_PROBE(kmem, kmem_cache_alloc_node) {
357*387f9dfdSAndroid Build Coastguard Worker        if (WORKAROUND_MISSING_FREE)
358*387f9dfdSAndroid Build Coastguard Worker            gen_free_enter((struct pt_regs *)args, (void *)args->ptr);
359*387f9dfdSAndroid Build Coastguard Worker        gen_alloc_enter((struct pt_regs *)args, args->bytes_alloc);
360*387f9dfdSAndroid Build Coastguard Worker        return gen_alloc_exit2((struct pt_regs *)args, (size_t)args->ptr);
361*387f9dfdSAndroid Build Coastguard Worker}
362*387f9dfdSAndroid Build Coastguard Worker"""
363*387f9dfdSAndroid Build Coastguard Worker
364*387f9dfdSAndroid Build Coastguard Workerbpf_source_kernel = """
365*387f9dfdSAndroid Build Coastguard Worker
366*387f9dfdSAndroid Build Coastguard WorkerTRACEPOINT_PROBE(kmem, kmalloc) {
367*387f9dfdSAndroid Build Coastguard Worker        if (WORKAROUND_MISSING_FREE)
368*387f9dfdSAndroid Build Coastguard Worker            gen_free_enter((struct pt_regs *)args, (void *)args->ptr);
369*387f9dfdSAndroid Build Coastguard Worker        gen_alloc_enter((struct pt_regs *)args, args->bytes_alloc);
370*387f9dfdSAndroid Build Coastguard Worker        return gen_alloc_exit2((struct pt_regs *)args, (size_t)args->ptr);
371*387f9dfdSAndroid Build Coastguard Worker}
372*387f9dfdSAndroid Build Coastguard Worker
373*387f9dfdSAndroid Build Coastguard WorkerTRACEPOINT_PROBE(kmem, kfree) {
374*387f9dfdSAndroid Build Coastguard Worker        return gen_free_enter((struct pt_regs *)args, (void *)args->ptr);
375*387f9dfdSAndroid Build Coastguard Worker}
376*387f9dfdSAndroid Build Coastguard Worker
377*387f9dfdSAndroid Build Coastguard WorkerTRACEPOINT_PROBE(kmem, kmem_cache_alloc) {
378*387f9dfdSAndroid Build Coastguard Worker        if (WORKAROUND_MISSING_FREE)
379*387f9dfdSAndroid Build Coastguard Worker            gen_free_enter((struct pt_regs *)args, (void *)args->ptr);
380*387f9dfdSAndroid Build Coastguard Worker        gen_alloc_enter((struct pt_regs *)args, args->bytes_alloc);
381*387f9dfdSAndroid Build Coastguard Worker        return gen_alloc_exit2((struct pt_regs *)args, (size_t)args->ptr);
382*387f9dfdSAndroid Build Coastguard Worker}
383*387f9dfdSAndroid Build Coastguard Worker
384*387f9dfdSAndroid Build Coastguard WorkerTRACEPOINT_PROBE(kmem, kmem_cache_free) {
385*387f9dfdSAndroid Build Coastguard Worker        return gen_free_enter((struct pt_regs *)args, (void *)args->ptr);
386*387f9dfdSAndroid Build Coastguard Worker}
387*387f9dfdSAndroid Build Coastguard Worker
388*387f9dfdSAndroid Build Coastguard WorkerTRACEPOINT_PROBE(kmem, mm_page_alloc) {
389*387f9dfdSAndroid Build Coastguard Worker        gen_alloc_enter((struct pt_regs *)args, PAGE_SIZE << args->order);
390*387f9dfdSAndroid Build Coastguard Worker        return gen_alloc_exit2((struct pt_regs *)args, args->pfn);
391*387f9dfdSAndroid Build Coastguard Worker}
392*387f9dfdSAndroid Build Coastguard Worker
393*387f9dfdSAndroid Build Coastguard WorkerTRACEPOINT_PROBE(kmem, mm_page_free) {
394*387f9dfdSAndroid Build Coastguard Worker        return gen_free_enter((struct pt_regs *)args, (void *)args->pfn);
395*387f9dfdSAndroid Build Coastguard Worker}
396*387f9dfdSAndroid Build Coastguard Worker"""
397*387f9dfdSAndroid Build Coastguard Worker
398*387f9dfdSAndroid Build Coastguard Workerbpf_source_percpu = """
399*387f9dfdSAndroid Build Coastguard Worker
400*387f9dfdSAndroid Build Coastguard WorkerTRACEPOINT_PROBE(percpu, percpu_alloc_percpu) {
401*387f9dfdSAndroid Build Coastguard Worker        gen_alloc_enter((struct pt_regs *)args, args->size);
402*387f9dfdSAndroid Build Coastguard Worker        return gen_alloc_exit2((struct pt_regs *)args, (size_t)args->ptr);
403*387f9dfdSAndroid Build Coastguard Worker}
404*387f9dfdSAndroid Build Coastguard Worker
405*387f9dfdSAndroid Build Coastguard WorkerTRACEPOINT_PROBE(percpu, percpu_free_percpu) {
406*387f9dfdSAndroid Build Coastguard Worker        return gen_free_enter((struct pt_regs *)args, (void *)args->ptr);
407*387f9dfdSAndroid Build Coastguard Worker}
408*387f9dfdSAndroid Build Coastguard Worker"""
409*387f9dfdSAndroid Build Coastguard Worker
410*387f9dfdSAndroid Build Coastguard Workerif kernel_trace:
411*387f9dfdSAndroid Build Coastguard Worker        if args.percpu:
412*387f9dfdSAndroid Build Coastguard Worker                bpf_source += bpf_source_percpu
413*387f9dfdSAndroid Build Coastguard Worker        else:
414*387f9dfdSAndroid Build Coastguard Worker                bpf_source += bpf_source_kernel
415*387f9dfdSAndroid Build Coastguard Worker                if BPF.tracepoint_exists("kmem", "kmalloc_node"):
416*387f9dfdSAndroid Build Coastguard Worker                        bpf_source += bpf_source_kernel_node
417*387f9dfdSAndroid Build Coastguard Worker
418*387f9dfdSAndroid Build Coastguard Workerif kernel_trace:
419*387f9dfdSAndroid Build Coastguard Worker    bpf_source = bpf_source.replace("WORKAROUND_MISSING_FREE", "1"
420*387f9dfdSAndroid Build Coastguard Worker                                    if args.wa_missing_free else "0")
421*387f9dfdSAndroid Build Coastguard Worker
422*387f9dfdSAndroid Build Coastguard Workerbpf_source = bpf_source.replace("SHOULD_PRINT", "1" if trace_all else "0")
423*387f9dfdSAndroid Build Coastguard Workerbpf_source = bpf_source.replace("SAMPLE_EVERY_N", str(sample_every_n))
424*387f9dfdSAndroid Build Coastguard Workerbpf_source = bpf_source.replace("PAGE_SIZE", str(resource.getpagesize()))
425*387f9dfdSAndroid Build Coastguard Worker
426*387f9dfdSAndroid Build Coastguard Workersize_filter = ""
427*387f9dfdSAndroid Build Coastguard Workerif min_size is not None and max_size is not None:
428*387f9dfdSAndroid Build Coastguard Worker        size_filter = "if (size < %d || size > %d) return 0;" % \
429*387f9dfdSAndroid Build Coastguard Worker                      (min_size, max_size)
430*387f9dfdSAndroid Build Coastguard Workerelif min_size is not None:
431*387f9dfdSAndroid Build Coastguard Worker        size_filter = "if (size < %d) return 0;" % min_size
432*387f9dfdSAndroid Build Coastguard Workerelif max_size is not None:
433*387f9dfdSAndroid Build Coastguard Worker        size_filter = "if (size > %d) return 0;" % max_size
434*387f9dfdSAndroid Build Coastguard Workerbpf_source = bpf_source.replace("SIZE_FILTER", size_filter)
435*387f9dfdSAndroid Build Coastguard Worker
436*387f9dfdSAndroid Build Coastguard Workerstack_flags = "0"
437*387f9dfdSAndroid Build Coastguard Workerif not kernel_trace:
438*387f9dfdSAndroid Build Coastguard Worker        stack_flags += "|BPF_F_USER_STACK"
439*387f9dfdSAndroid Build Coastguard Workerbpf_source = bpf_source.replace("STACK_FLAGS", stack_flags)
440*387f9dfdSAndroid Build Coastguard Worker
441*387f9dfdSAndroid Build Coastguard Workerif args.ebpf:
442*387f9dfdSAndroid Build Coastguard Worker    print(bpf_source)
443*387f9dfdSAndroid Build Coastguard Worker    exit()
444*387f9dfdSAndroid Build Coastguard Worker
445*387f9dfdSAndroid Build Coastguard Workerbpf = BPF(text=bpf_source)
446*387f9dfdSAndroid Build Coastguard Worker
447*387f9dfdSAndroid Build Coastguard Workerif not kernel_trace:
448*387f9dfdSAndroid Build Coastguard Worker        print("Attaching to pid %d, Ctrl+C to quit." % pid)
449*387f9dfdSAndroid Build Coastguard Worker
450*387f9dfdSAndroid Build Coastguard Worker        def attach_probes(sym, fn_prefix=None, can_fail=False):
451*387f9dfdSAndroid Build Coastguard Worker                if fn_prefix is None:
452*387f9dfdSAndroid Build Coastguard Worker                        fn_prefix = sym
453*387f9dfdSAndroid Build Coastguard Worker
454*387f9dfdSAndroid Build Coastguard Worker                try:
455*387f9dfdSAndroid Build Coastguard Worker                        bpf.attach_uprobe(name=obj, sym=sym,
456*387f9dfdSAndroid Build Coastguard Worker                                          fn_name=fn_prefix + "_enter",
457*387f9dfdSAndroid Build Coastguard Worker                                          pid=pid)
458*387f9dfdSAndroid Build Coastguard Worker                        bpf.attach_uretprobe(name=obj, sym=sym,
459*387f9dfdSAndroid Build Coastguard Worker                                             fn_name=fn_prefix + "_exit",
460*387f9dfdSAndroid Build Coastguard Worker                                             pid=pid)
461*387f9dfdSAndroid Build Coastguard Worker                except Exception:
462*387f9dfdSAndroid Build Coastguard Worker                        if can_fail:
463*387f9dfdSAndroid Build Coastguard Worker                                return
464*387f9dfdSAndroid Build Coastguard Worker                        else:
465*387f9dfdSAndroid Build Coastguard Worker                                raise
466*387f9dfdSAndroid Build Coastguard Worker
467*387f9dfdSAndroid Build Coastguard Worker        attach_probes("malloc")
468*387f9dfdSAndroid Build Coastguard Worker        attach_probes("calloc")
469*387f9dfdSAndroid Build Coastguard Worker        attach_probes("realloc")
470*387f9dfdSAndroid Build Coastguard Worker        attach_probes("mmap")
471*387f9dfdSAndroid Build Coastguard Worker        attach_probes("posix_memalign")
472*387f9dfdSAndroid Build Coastguard Worker        attach_probes("valloc", can_fail=True) # failed on Android, is deprecated in libc.so from bionic directory
473*387f9dfdSAndroid Build Coastguard Worker        attach_probes("memalign")
474*387f9dfdSAndroid Build Coastguard Worker        attach_probes("pvalloc", can_fail=True) # failed on Android, is deprecated in libc.so from bionic directory
475*387f9dfdSAndroid Build Coastguard Worker        attach_probes("aligned_alloc", can_fail=True)  # added in C11
476*387f9dfdSAndroid Build Coastguard Worker        bpf.attach_uprobe(name=obj, sym="free", fn_name="free_enter",
477*387f9dfdSAndroid Build Coastguard Worker                                  pid=pid)
478*387f9dfdSAndroid Build Coastguard Worker        bpf.attach_uprobe(name=obj, sym="munmap", fn_name="munmap_enter",
479*387f9dfdSAndroid Build Coastguard Worker                                  pid=pid)
480*387f9dfdSAndroid Build Coastguard Worker
481*387f9dfdSAndroid Build Coastguard Workerelse:
482*387f9dfdSAndroid Build Coastguard Worker        print("Attaching to kernel allocators, Ctrl+C to quit.")
483*387f9dfdSAndroid Build Coastguard Worker
484*387f9dfdSAndroid Build Coastguard Worker        # No probe attaching here. Allocations are counted by attaching to
485*387f9dfdSAndroid Build Coastguard Worker        # tracepoints.
486*387f9dfdSAndroid Build Coastguard Worker        #
487*387f9dfdSAndroid Build Coastguard Worker        # Memory allocations in Linux kernel are not limited to malloc/free
488*387f9dfdSAndroid Build Coastguard Worker        # equivalents. It's also common to allocate a memory page or multiple
489*387f9dfdSAndroid Build Coastguard Worker        # pages. Page allocator have two interfaces, one working with page
490*387f9dfdSAndroid Build Coastguard Worker        # frame numbers (PFN), while other working with page addresses. It's
491*387f9dfdSAndroid Build Coastguard Worker        # possible to allocate pages with one kind of functions, and free them
492*387f9dfdSAndroid Build Coastguard Worker        # with another. Code in kernel can easy convert PFNs to addresses and
493*387f9dfdSAndroid Build Coastguard Worker        # back, but it's hard to do the same in eBPF kprobe without fragile
494*387f9dfdSAndroid Build Coastguard Worker        # hacks.
495*387f9dfdSAndroid Build Coastguard Worker        #
496*387f9dfdSAndroid Build Coastguard Worker        # Fortunately, Linux exposes tracepoints for memory allocations, which
497*387f9dfdSAndroid Build Coastguard Worker        # can be instrumented by eBPF programs. Tracepoint for page allocations
498*387f9dfdSAndroid Build Coastguard Worker        # gives access to PFNs for both allocator interfaces. So there is no
499*387f9dfdSAndroid Build Coastguard Worker        # need to guess which allocation corresponds to which free.
500*387f9dfdSAndroid Build Coastguard Worker
501*387f9dfdSAndroid Build Coastguard Workerdef print_outstanding():
502*387f9dfdSAndroid Build Coastguard Worker        print("[%s] Top %d stacks with outstanding allocations:" %
503*387f9dfdSAndroid Build Coastguard Worker              (datetime.now().strftime("%H:%M:%S"), top_stacks))
504*387f9dfdSAndroid Build Coastguard Worker        alloc_info = {}
505*387f9dfdSAndroid Build Coastguard Worker        allocs = bpf["allocs"]
506*387f9dfdSAndroid Build Coastguard Worker        stack_traces = bpf["stack_traces"]
507*387f9dfdSAndroid Build Coastguard Worker        for address, info in sorted(allocs.items(), key=lambda a: a[1].size):
508*387f9dfdSAndroid Build Coastguard Worker                if BPF.monotonic_time() - min_age_ns < info.timestamp_ns:
509*387f9dfdSAndroid Build Coastguard Worker                        continue
510*387f9dfdSAndroid Build Coastguard Worker                if info.stack_id < 0:
511*387f9dfdSAndroid Build Coastguard Worker                        continue
512*387f9dfdSAndroid Build Coastguard Worker                if info.stack_id in alloc_info:
513*387f9dfdSAndroid Build Coastguard Worker                        alloc_info[info.stack_id].update(info.size)
514*387f9dfdSAndroid Build Coastguard Worker                else:
515*387f9dfdSAndroid Build Coastguard Worker                        stack = list(stack_traces.walk(info.stack_id))
516*387f9dfdSAndroid Build Coastguard Worker                        combined = []
517*387f9dfdSAndroid Build Coastguard Worker                        for addr in stack:
518*387f9dfdSAndroid Build Coastguard Worker                                combined.append(('0x'+format(addr, '016x')+'\t').encode('utf-8') + bpf.sym(addr, pid,
519*387f9dfdSAndroid Build Coastguard Worker                                        show_module=True, show_offset=True))
520*387f9dfdSAndroid Build Coastguard Worker                        alloc_info[info.stack_id] = Allocation(combined,
521*387f9dfdSAndroid Build Coastguard Worker                                                               info.size)
522*387f9dfdSAndroid Build Coastguard Worker                if args.show_allocs:
523*387f9dfdSAndroid Build Coastguard Worker                        print("\taddr = %x size = %s" %
524*387f9dfdSAndroid Build Coastguard Worker                              (address.value, info.size))
525*387f9dfdSAndroid Build Coastguard Worker        to_show = sorted(alloc_info.values(),
526*387f9dfdSAndroid Build Coastguard Worker                         key=lambda a: a.size)[-top_stacks:]
527*387f9dfdSAndroid Build Coastguard Worker        for alloc in to_show:
528*387f9dfdSAndroid Build Coastguard Worker                print("\t%d bytes in %d allocations from stack\n\t\t%s" %
529*387f9dfdSAndroid Build Coastguard Worker                      (alloc.size, alloc.count,
530*387f9dfdSAndroid Build Coastguard Worker                       b"\n\t\t".join(alloc.stack).decode("ascii")))
531*387f9dfdSAndroid Build Coastguard Worker
532*387f9dfdSAndroid Build Coastguard Workerdef print_outstanding_combined():
533*387f9dfdSAndroid Build Coastguard Worker        stack_traces = bpf["stack_traces"]
534*387f9dfdSAndroid Build Coastguard Worker        stacks = sorted(bpf["combined_allocs"].items(),
535*387f9dfdSAndroid Build Coastguard Worker                        key=lambda a: -a[1].total_size)
536*387f9dfdSAndroid Build Coastguard Worker        cnt = 1
537*387f9dfdSAndroid Build Coastguard Worker        entries = []
538*387f9dfdSAndroid Build Coastguard Worker        for stack_id, info in stacks:
539*387f9dfdSAndroid Build Coastguard Worker                try:
540*387f9dfdSAndroid Build Coastguard Worker                        trace = []
541*387f9dfdSAndroid Build Coastguard Worker                        for addr in stack_traces.walk(stack_id.value):
542*387f9dfdSAndroid Build Coastguard Worker                                sym = bpf.sym(addr, pid,
543*387f9dfdSAndroid Build Coastguard Worker                                                      show_module=True,
544*387f9dfdSAndroid Build Coastguard Worker                                                      show_offset=True)
545*387f9dfdSAndroid Build Coastguard Worker                                trace.append(sym)
546*387f9dfdSAndroid Build Coastguard Worker                        trace = "\n\t\t".join(trace.decode())
547*387f9dfdSAndroid Build Coastguard Worker                except KeyError:
548*387f9dfdSAndroid Build Coastguard Worker                        trace = "stack information lost"
549*387f9dfdSAndroid Build Coastguard Worker
550*387f9dfdSAndroid Build Coastguard Worker                entry = ("\t%d bytes in %d allocations from stack\n\t\t%s" %
551*387f9dfdSAndroid Build Coastguard Worker                         (info.total_size, info.number_of_allocs, trace))
552*387f9dfdSAndroid Build Coastguard Worker                entries.append(entry)
553*387f9dfdSAndroid Build Coastguard Worker
554*387f9dfdSAndroid Build Coastguard Worker                cnt += 1
555*387f9dfdSAndroid Build Coastguard Worker                if cnt > top_stacks:
556*387f9dfdSAndroid Build Coastguard Worker                        break
557*387f9dfdSAndroid Build Coastguard Worker
558*387f9dfdSAndroid Build Coastguard Worker        print("[%s] Top %d stacks with outstanding allocations:" %
559*387f9dfdSAndroid Build Coastguard Worker              (datetime.now().strftime("%H:%M:%S"), top_stacks))
560*387f9dfdSAndroid Build Coastguard Worker
561*387f9dfdSAndroid Build Coastguard Worker        print('\n'.join(reversed(entries)))
562*387f9dfdSAndroid Build Coastguard Worker
563*387f9dfdSAndroid Build Coastguard Workercount_so_far = 0
564*387f9dfdSAndroid Build Coastguard Workerwhile True:
565*387f9dfdSAndroid Build Coastguard Worker        if trace_all:
566*387f9dfdSAndroid Build Coastguard Worker                print(bpf.trace_fields())
567*387f9dfdSAndroid Build Coastguard Worker        else:
568*387f9dfdSAndroid Build Coastguard Worker                try:
569*387f9dfdSAndroid Build Coastguard Worker                        sleep(interval)
570*387f9dfdSAndroid Build Coastguard Worker                except KeyboardInterrupt:
571*387f9dfdSAndroid Build Coastguard Worker                        exit()
572*387f9dfdSAndroid Build Coastguard Worker                if args.combined_only:
573*387f9dfdSAndroid Build Coastguard Worker                        print_outstanding_combined()
574*387f9dfdSAndroid Build Coastguard Worker                else:
575*387f9dfdSAndroid Build Coastguard Worker                        print_outstanding()
576*387f9dfdSAndroid Build Coastguard Worker                sys.stdout.flush()
577*387f9dfdSAndroid Build Coastguard Worker                count_so_far += 1
578*387f9dfdSAndroid Build Coastguard Worker                if num_prints is not None and count_so_far >= num_prints:
579*387f9dfdSAndroid Build Coastguard Worker                        exit()
580