92 lines
2.5 KiB
Python
Executable File
92 lines
2.5 KiB
Python
Executable File
#!/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)
|