1#!/usr/bin/env python 2# Copyright (c) 2012 The Chromium Authors. All rights reserved. 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6"""Symbolizes and prints live objects as recorded by tcmalloc's 7HeapProfilerDumpLiveObjects. 8""" 9 10import os 11import re 12import subprocess 13import sys 14import tempfile 15 16def usage(): 17 print """\ 18Usage: 19 tools/tcmalloc/print-live-objects.py out/Debug/chrome leaks.dmp 20""" 21 22def LoadDump(dump_file): 23 result = [] 24 leakfmt = re.compile( 25 r"^\s*1:\s*(\d+)\s*\[\s*1:\s*\d+\]\s*@(0x[a-f0-9]+)((\s+0x[a-f0-9]+)*)$") 26 line_no = 0 27 with open(dump_file) as f: 28 for line in f: 29 line_no = line_no + 1 30 matches = leakfmt.match(line) 31 if not matches: 32 print "%s: could not parse line %d, skipping" % (dump_file, line_no) 33 else: 34 trace = { "size": int(matches.group(1)), 35 "address": matches.group(2), 36 "frames": matches.group(3).strip().split(" ")} 37 result.append(trace) 38 return result 39 40 41def Symbolize(binary, traces): 42 addresses = set() 43 for trace in traces: 44 for frame in trace["frames"]: 45 addresses.add(frame) 46 addr_file, addr_filename = tempfile.mkstemp() 47 for addr in addresses: 48 os.write(addr_file, "%s\n" % addr) 49 os.close(addr_file) 50 syms = subprocess.Popen([ 51 "addr2line", "-f", "-C", "-e", binary, "@%s" % addr_filename], 52 stdout=subprocess.PIPE).communicate()[0].strip().split("\n") 53 table = {} 54 cwd = os.getcwd() 55 for address, symbol, location in zip(addresses, syms[::2], syms[1::2]): 56 if location != "??:0": 57 filename, line = location.split(":") 58 filename = os.path.realpath(filename)[len(cwd)+1:] 59 location = "%s:%s" % (filename, line) 60 table[address] = { "name": symbol, "location": location } 61 for trace in traces: 62 frames = [] 63 for frame in trace["frames"]: 64 frames.append(table[frame]) 65 trace["frames"] = frames 66 67 68def Main(argv): 69 if sys.platform != 'linux2': 70 print 'print-live-objects.py requires addr2line only present on Linux.' 71 sys.exit(1) 72 73 if len(argv) != 3: 74 usage() 75 sys.exit(1) 76 77 traces = LoadDump(argv[2]) 78 Symbolize(argv[1], traces) 79 80 if not traces: 81 print "No leaks found!" 82 83 for trace in sorted(traces, key=lambda x: -x["size"]): 84 print "Leak of %d bytes at address %s" % (trace["size"], trace["address"]) 85 for frame in trace["frames"]: 86 print " %s (%s)" % (frame["name"], frame["location"]) 87 print "" 88 89 90if __name__ == '__main__': 91 Main(sys.argv) 92