[go: nahoru, domu]

blob: b1bd99c8e65a77164b114de206ea773a4f2e5383 [file] [log] [blame]
maruel@chromium.orgcb155a82011-11-29 17:25:341#!/usr/bin/env python
Avi Drissmandfd880852022-09-15 20:11:092# Copyright 2011 The Chromium Authors
evan@chromium.org74b2cbc2010-10-12 21:46:413# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
maruel@chromium.orgcb155a82011-11-29 17:25:346"""Prints a report of symbols stripped by the linker due to being unused.
evan@chromium.org74b2cbc2010-10-12 21:46:417
8To use, build with these linker flags:
9 -Wl,--gc-sections
10 -Wl,--print-gc-sections
11the first one is the default in Release; search build/common.gypi for it
12and to see where to add the other.
13
14Then build, saving the output into a file:
15 make chrome 2>&1 | tee buildlog
16and run this script on it:
17 ./tools/unused-symbols-report.py buildlog > report.html
18"""
19
Raul Tambreca9124e42019-09-27 04:13:3520from __future__ import print_function
21
evan@chromium.org74b2cbc2010-10-12 21:46:4122import cgi
23import optparse
24import os
25import re
26import subprocess
27import sys
28
29cppfilt_proc = None
30def Demangle(sym):
31 """Demangle a C++ symbol by passing it through c++filt."""
32 global cppfilt_proc
33 if cppfilt_proc is None:
34 cppfilt_proc = subprocess.Popen(['c++filt'], stdin=subprocess.PIPE,
35 stdout=subprocess.PIPE)
Raul Tambreca9124e42019-09-27 04:13:3536 print(sym, file=cppfilt_proc.stdin)
evan@chromium.org74b2cbc2010-10-12 21:46:4137 return cppfilt_proc.stdout.readline().strip()
38
39
40def Unyuck(sym):
41 """Attempt to prettify a C++ symbol by some basic heuristics."""
42 sym = sym.replace('std::basic_string<char, std::char_traits<char>, '
43 'std::allocator<char> >', 'std::string')
44 sym = sym.replace('std::basic_string<wchar_t, std::char_traits<wchar_t>, '
45 'std::allocator<wchar_t> >', 'std::wstring')
Jan Wilken Dörrie858cc5c42021-03-14 17:46:1746 sym = sym.replace(
47 'std::basic_string<char16_t, std::char_traits<char16_t>, '
48 'std::allocator<char16_t> >', 'std::u16string')
evan@chromium.org74b2cbc2010-10-12 21:46:4149 sym = re.sub(r', std::allocator<\S+\s+>', '', sym)
50 return sym
51
52
53def Parse(input, skip_paths=None, only_paths=None):
54 """Parse the --print-gc-sections build output.
55
56 Args:
57 input: iterable over the lines of the build output
58
59 Yields:
60 (target name, path to .o file, demangled symbol)
61 """
62 symbol_re = re.compile(r"'\.text\.(\S+)' in file '(\S+)'$")
63 path_re = re.compile(r"^out/[^/]+/[^/]+/([^/]+)/(.*)$")
64 for line in input:
65 match = symbol_re.search(line)
66 if not match:
67 continue
68 symbol, path = match.groups()
69 symbol = Unyuck(Demangle(symbol))
70 path = os.path.normpath(path)
71 if skip_paths and skip_paths in path:
72 continue
73 if only_paths and only_paths not in path:
74 continue
75 match = path_re.match(path)
76 if not match:
Raul Tambreca9124e42019-09-27 04:13:3577 print("Skipping weird path", path, file=sys.stderr)
evan@chromium.org74b2cbc2010-10-12 21:46:4178 continue
79 target, path = match.groups()
80 yield target, path, symbol
81
82
83# HTML header for our output page.
84TEMPLATE_HEADER = """<!DOCTYPE html>
85<head>
86<style>
87body {
88 font-family: sans-serif;
89 font-size: 0.8em;
90}
91h1, h2 {
92 font-weight: normal;
93 margin: 0.5em 0;
94}
95h2 {
96 margin-top: 1em;
97}
98tr:hover {
99 background: #eee;
100}
101.permalink {
102 padding-left: 1ex;
103 font-size: 80%;
104 text-decoration: none;
105 color: #ccc;
106}
107.symbol {
108 font-family: WebKitWorkAround, monospace;
109 margin-left: 4ex;
110 text-indent: -4ex;
111 padding: 0.5ex 1ex;
112}
113.file {
114 padding: 0.5ex 1ex;
115 padding-left: 2ex;
116 font-family: WebKitWorkAround, monospace;
117 font-size: 90%;
118 color: #777;
119}
120</style>
121</head>
122<body>
123<h1>chrome symbols deleted at link time</h1>
124"""
125
126
127def Output(iter):
128 """Print HTML given an iterable of (target, path, symbol) tuples."""
129 targets = {}
130 for target, path, symbol in iter:
131 entries = targets.setdefault(target, [])
132 entries.append((symbol, path))
133
Raul Tambreca9124e42019-09-27 04:13:35134 print(TEMPLATE_HEADER)
135 print("<p>jump to target:")
136 print("<select = this.value'>")
evan@chromium.org74b2cbc2010-10-12 21:46:41137 for target in sorted(targets.keys()):
Raul Tambreca9124e42019-09-27 04:13:35138 print("<option>%s</option>" % target)
139 print("</select></p>")
evan@chromium.org74b2cbc2010-10-12 21:46:41140
141 for target in sorted(targets.keys()):
Raul Tambreca9124e42019-09-27 04:13:35142 print("<h2>%s" % target)
143 print("<a class=permalink href='#%s' name='%s'>#</a>" % (target, target))
144 print("</h2>")
145 print("<table width=100% cellspacing=0>")
evan@chromium.org74b2cbc2010-10-12 21:46:41146 for symbol, path in sorted(targets[target]):
147 htmlsymbol = cgi.escape(symbol).replace('::', '::<wbr>')
Raul Tambreca9124e42019-09-27 04:13:35148 print("<tr><td><div class=symbol>%s</div></td>" % htmlsymbol)
149 print("<td valign=top><div class=file>%s</div></td></tr>" % path)
150 print("</table>")
evan@chromium.org74b2cbc2010-10-12 21:46:41151
152
153def main():
154 parser = optparse.OptionParser(usage='%prog [options] buildoutput\n\n' +
155 __doc__)
156 parser.add_option("--skip-paths", metavar="STR", default="third_party",
157 help="skip paths matching STR [default=%default]")
158 parser.add_option("--only-paths", metavar="STR",
159 help="only include paths matching STR [default=%default]")
160 opts, args = parser.parse_args()
161
162 if len(args) < 1:
163 parser.print_help()
164 sys.exit(1)
165
166 iter = Parse(open(args[0]),
167 skip_paths=opts.skip_paths,
168 only_paths=opts.only_paths)
169 Output(iter)
170
maruel@chromium.orgcb155a82011-11-29 17:25:34171
evan@chromium.org74b2cbc2010-10-12 21:46:41172if __name__ == '__main__':
173 main()