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