| Index: tools/tcmalloc/print-live-objects.py
|
| diff --git a/tools/tcmalloc/print-live-objects.py b/tools/tcmalloc/print-live-objects.py
|
| new file mode 100755
|
| index 0000000000000000000000000000000000000000..9886fd1924e141e603ef91ffb3e79772fe219189
|
| --- /dev/null
|
| +++ b/tools/tcmalloc/print-live-objects.py
|
| @@ -0,0 +1,91 @@
|
| +#!/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 traces:
|
| + 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)
|
|
|