| #!/usr/bin/env python |
| # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """Symbolizes and prints live objects as recorded by tcmalloc's |
| HeapProfilerDumpLiveObjects. |
| """ |
| |
| import os |
| import re |
| import subprocess |
| import sys |
| import tempfile |
| |
| def usage(): |
| print """\ |
| Usage: |
| tools/tcmalloc/print-live-objects.py out/Debug/chrome leaks.dmp |
| """ |
| |
| def LoadDump(dump_file): |
| result = [] |
| leakfmt = re.compile( |
| r"^\s*1:\s*(\d+)\s*\[\s*1:\s*\d+\]\s*@(0x[a-f0-9]+)((\s+0x[a-f0-9]+)*)$") |
| line_no = 0 |
| with open(dump_file) as f: |
| for line in f: |
| line_no = line_no + 1 |
| matches = leakfmt.match(line) |
| if not matches: |
| print "%s: could not parse line %d, skipping" % (dump_file, line_no) |
| else: |
| trace = { "size": int(matches.group(1)), |
| "address": matches.group(2), |
| "frames": matches.group(3).strip().split(" ")} |
| result.append(trace) |
| return result |
| |
| |
| def Symbolize(binary, traces): |
| addresses = set() |
| for trace in traces: |
| for frame in trace["frames"]: |
| addresses.add(frame) |
| addr_file, addr_filename = tempfile.mkstemp() |
| for addr in addresses: |
| os.write(addr_file, "%s\n" % addr) |
| os.close(addr_file) |
| syms = subprocess.Popen([ |
| "addr2line", "-f", "-C", "-e", binary, "@%s" % addr_filename], |
| stdout=subprocess.PIPE).communicate()[0].strip().split("\n") |
| table = {} |
| cwd = os.getcwd() |
| for address, symbol, location in zip(addresses, syms[::2], syms[1::2]): |
| if location != "??:0": |
| filename, line = location.split(":") |
| filename = os.path.realpath(filename)[len(cwd)+1:] |
| location = "%s:%s" % (filename, line) |
| table[address] = { "name": symbol, "location": location } |
| for trace in traces: |
| frames = [] |
| for frame in trace["frames"]: |
| frames.append(table[frame]) |
| trace["frames"] = frames |
| |
| |
| def Main(argv): |
| if sys.platform != 'linux2': |
| print 'print-live-objects.py requires addr2line only present on Linux.' |
| sys.exit(1) |
| |
| if len(argv) != 3: |
| usage() |
| sys.exit(1) |
| |
| traces = LoadDump(argv[2]) |
| Symbolize(argv[1], traces) |
| |
| if not traces: |
| print "No leaks found!" |
| |
| for trace in sorted(traces, key=lambda x: -x["size"]): |
| print "Leak of %d bytes at address %s" % (trace["size"], trace["address"]) |
| for frame in trace["frames"]: |
| print " %s (%s)" % (frame["name"], frame["location"]) |
| print "" |
| |
| |
| if __name__ == '__main__': |
| Main(sys.argv) |