Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(222)

Side by Side Diff: tools/binary_size/libsupersize/nm.py

Issue 2880003002: supersize: A few fixes for Android+clang builds (Closed)
Patch Set: rebase Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 # Copyright 2017 The Chromium Authors. All rights reserved. 1 # Copyright 2017 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 """Functions that rely on parsing output of "nm" tool.""" 5 """Functions that rely on parsing output of "nm" tool."""
6 6
7 import atexit 7 import atexit
8 import collections 8 import collections
9 import errno 9 import errno
10 import logging 10 import logging
11 import os 11 import os
12 import subprocess 12 import subprocess
13 import sys 13 import sys
14 14
15 import concurrent 15 import concurrent
16 16
17 _active_subprocesses = None 17 _active_subprocesses = None
18 18
19 19
20 def _IsRelevantNmName(name):
21 # Skip lines like:
22 # 00000000 t $t
23 # 00000000 r $d
24 # 0000041b r .L.str.38
25 # 00000344 N
26 return name and not name.startswith('.L.str.') and not (
27 len(name) == 2 and name.startswith('$'))
28
29
20 def CollectAliasesByAddress(elf_path, tool_prefix): 30 def CollectAliasesByAddress(elf_path, tool_prefix):
21 """Runs nm on |elf_path| and returns a dict of address->[names]""" 31 """Runs nm on |elf_path| and returns a dict of address->[names]"""
22 names_by_address = collections.defaultdict(list) 32 names_by_address = collections.defaultdict(list)
23 33
24 # About 60mb of output, but piping takes ~30s, and loading it into RAM 34 # About 60mb of output, but piping takes ~30s, and loading it into RAM
25 # directly takes 3s. 35 # directly takes 3s.
26 args = [tool_prefix + 'nm', '--no-sort', '--defined-only', '--demangle', 36 args = [tool_prefix + 'nm', '--no-sort', '--defined-only', '--demangle',
27 elf_path] 37 elf_path]
28 output = subprocess.check_output(args) 38 output = subprocess.check_output(args)
29 for line in output.splitlines(): 39 for line in output.splitlines():
30 address_str, section, name = line.split(' ', 2) 40 space_idx = line.find(' ')
41 address_str = line[:space_idx]
42 section = line[space_idx + 1]
43 name = line[space_idx + 3:]
44
31 # To verify that rodata does not have aliases: 45 # To verify that rodata does not have aliases:
32 # nm --no-sort --defined-only libchrome.so > nm.out 46 # nm --no-sort --defined-only libchrome.so > nm.out
33 # grep -v '\$' nm.out | grep ' r ' | sort | cut -d' ' -f1 > addrs 47 # grep -v '\$' nm.out | grep ' r ' | sort | cut -d' ' -f1 > addrs
34 # wc -l < addrs; uniq < addrs | wc -l 48 # wc -l < addrs; uniq < addrs | wc -l
35 if section not in 'tT' or not name or name[0] == '$': 49 if section not in 'tT' or not _IsRelevantNmName(name):
36 continue 50 continue
37 51
38 address = int(address_str, 16) 52 address = int(address_str, 16)
39 if not address: 53 if not address:
40 continue 54 continue
41 # Constructors often show up twice. 55 # Constructors often show up twice.
42 name_list = names_by_address[address] 56 name_list = names_by_address[address]
43 if name not in name_list: 57 if name not in name_list:
44 name_list.append(name) 58 name_list.append(name)
45 59
(...skipping 18 matching lines...) Expand all
64 return concurrent.ForkAndCall( 78 return concurrent.ForkAndCall(
65 _CollectAliasesByAddressAsyncHelper, (elf_path, tool_prefix), 79 _CollectAliasesByAddressAsyncHelper, (elf_path, tool_prefix),
66 decode_func=decode) 80 decode_func=decode)
67 81
68 82
69 def _ParseOneObjectFileOutput(lines): 83 def _ParseOneObjectFileOutput(lines):
70 ret = [] 84 ret = []
71 for line in lines: 85 for line in lines:
72 if not line: 86 if not line:
73 break 87 break
74 sep = line.find(' ') # Skip over address. 88 space_idx = line.find(' ') # Skip over address.
75 sep = line.find(' ', sep + 1) # Skip over symbol type. 89 name = line[space_idx + 3:]
76 name = line[sep + 1:] 90 if _IsRelevantNmName(name):
77 # Skip lines like:
78 # 00000000 t $t
79 # 00000000 r $d
80 # 0000041b r .L.str.38
81 if name[0] not in '$.':
82 ret.append(name) 91 ret.append(name)
83 return ret 92 return ret
84 93
85 94
86 def _BatchCollectNames(target, tool_prefix, output_directory): 95 def _BatchCollectNames(target, tool_prefix, output_directory):
87 is_archive = isinstance(target, basestring) 96 is_archive = isinstance(target, basestring)
88 # Ensure tool_prefix is absolute so that CWD does not affect it 97 # Ensure tool_prefix is absolute so that CWD does not affect it
89 if os.path.sep in tool_prefix: 98 if os.path.sep in tool_prefix:
90 # Use abspath() on the dirname to avoid it stripping a trailing /. 99 # Use abspath() on the dirname to avoid it stripping a trailing /.
91 dirname = os.path.dirname(tool_prefix) 100 dirname = os.path.dirname(tool_prefix)
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
249 except IOError, e: 258 except IOError, e:
250 # Parent process exited. 259 # Parent process exited.
251 if e.errno == errno.EPIPE: 260 if e.errno == errno.EPIPE:
252 sys.exit(1) 261 sys.exit(1)
253 262
254 logging.debug('nm bulk subprocess finished.') 263 logging.debug('nm bulk subprocess finished.')
255 264
256 265
257 if __name__ == '__main__': 266 if __name__ == '__main__':
258 _SubMain(*sys.argv[1:]) 267 _SubMain(*sys.argv[1:])
OLDNEW
« no previous file with comments | « tools/binary_size/libsupersize/models.py ('k') | tools/binary_size/libsupersize/testdata/Archive.golden » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698