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

Unified Diff: tools/binary_size/libsupersize/console.py

Issue 2881563003: supersize: Make Disassemble() work for downloaded .size files (Closed)
Patch Set: self-review 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 side-by-side diff with in-line comments
Download patch
Index: tools/binary_size/libsupersize/console.py
diff --git a/tools/binary_size/libsupersize/console.py b/tools/binary_size/libsupersize/console.py
index f019564557333c337a84594bc8f2436226ef2484..1e87f44416577c38177b03c8bea61c15832b71c8 100644
--- a/tools/binary_size/libsupersize/console.py
+++ b/tools/binary_size/libsupersize/console.py
@@ -66,7 +66,7 @@ def _WriteToStream(lines, use_pager=None, to_file=None):
class _Session(object):
_readline_initialized = False
- def __init__(self, size_infos, lazy_paths):
+ def __init__(self, size_infos, size_paths, lazy_paths):
self._variables = {
'Print': self._PrintFunc,
'Diff': self._DiffFunc,
@@ -77,6 +77,8 @@ class _Session(object):
}
self._lazy_paths = lazy_paths
self._size_infos = size_infos
+ self._size_paths = size_paths
+ self._disassemble_prefix_len = None
if len(size_infos) == 1:
self._variables['size_info'] = size_infos[0]
@@ -119,23 +121,71 @@ class _Session(object):
lines = describe.GenerateLines(obj, verbose=verbose, recursive=recursive)
_WriteToStream(lines, use_pager=use_pager, to_file=to_file)
- def _ElfPathForSymbol(self, symbol):
+ def _ElfPathAndToolPrefixForSymbol(self, symbol, elf_path, tool_prefix):
size_info = None
- for size_info in self._size_infos:
+ size_path = None
+ for size_info, size_path in zip(self._size_infos, self._size_paths):
if symbol in size_info.symbols:
break
else:
- assert False, 'Symbol does not belong to a size_info.'
-
- filename = size_info.metadata.get(models.METADATA_ELF_FILENAME)
- output_dir = self._lazy_paths.output_directory or ''
- path = os.path.normpath(os.path.join(output_dir, filename))
-
- found_build_id = archive.BuildIdFromElf(path, self._lazy_paths.tool_prefix)
+ # If symbols is from a diff(), use its address+name to find it.
+ for size_info, size_path in zip(self._size_infos, self._size_paths):
+ matched = size_info.symbols.WhereAddressInRange(symbol.address)
+ # Use last matched symbol to skip over padding-only symbols.
+ if len(matched) > 0 and matched[-1].full_name == symbol.full_name:
+ symbol = matched[-1]
+ break
+ else:
+ assert False, 'Symbol does not belong to a size_info.'
+
+ orig_tool_prefix = size_info.metadata.get(models.METADATA_TOOL_PREFIX)
+ if orig_tool_prefix:
+ orig_tool_prefix = paths.FromSrcRootRelative(orig_tool_prefix)
+ if os.path.exists(orig_tool_prefix + 'objdump'):
+ tool_prefix = orig_tool_prefix
+
+ # TODO(agrieve): Would be even better to use objdump --info to check that
+ # the toolchain is for the correct architecture.
+ assert tool_prefix is not None, (
+ 'Could not determine --tool-prefix. Possible fixes include setting '
+ '--tool-prefix, or setting --output-directory')
+
+ if elf_path is None:
+ filename = size_info.metadata.get(models.METADATA_ELF_FILENAME)
+ output_dir = self._lazy_paths.output_directory
+ size_path = self._size_paths[self._size_infos.index(size_info)]
+ if output_dir:
+ # Local build: File is located in output directory.
+ path = os.path.normpath(os.path.join(output_dir, filename))
+ if not output_dir or not os.path.exists(path):
+ # Downloaded build: File is located beside .size file.
+ path = os.path.normpath(os.path.join(
+ os.path.dirname(size_path), os.path.basename(filename)))
+
+ assert os.path.exists(path), (
+ 'Could locate ELF file. If binary was built locally, ensure '
+ '--output-directory is set. If output directory is unavailable, '
+ 'ensure {} is located beside {}, or pass its path explicitly using '
+ 'elf_path=').format(os.path.basename(filename), size_path)
+
+ found_build_id = archive.BuildIdFromElf(path, tool_prefix)
expected_build_id = size_info.metadata.get(models.METADATA_ELF_BUILD_ID)
assert found_build_id == expected_build_id, (
'Build ID does not match for %s' % path)
- return path
+ return path, tool_prefix
+
+ def _DetectDisassemblePrefixLen(self, args):
+ # Look for a line that looks like:
+ # /usr/{snip}/src/out/Release/../../net/quic/core/quic_time.h:100
+ output = subprocess.check_output(args)
+ for line in output.splitlines():
+ if line and line[0] == os.path.sep and line[-1].isdigit():
+ release_idx = line.find('Release')
+ if release_idx == -1:
+ break
+ return line.count(os.path.sep, 0, release_idx)
+ logging.warning('Found no source paths in objdump output.')
+ return None
def _DisassembleFunc(self, symbol, elf_path=None, use_pager=None,
to_file=None):
@@ -147,13 +197,34 @@ class _Session(object):
when auto-detection fails.
"""
assert symbol.address and symbol.section_name == '.text'
- if not elf_path:
- elf_path = self._ElfPathForSymbol(symbol)
+
tool_prefix = self._lazy_paths.tool_prefix
+ if not elf_path:
+ elf_path, tool_prefix = self._ElfPathAndToolPrefixForSymbol(
+ symbol, elf_path, tool_prefix)
+
args = [tool_prefix + 'objdump', '--disassemble', '--source',
'--line-numbers', '--demangle',
'--start-address=0x%x' % symbol.address,
'--stop-address=0x%x' % symbol.end_address, elf_path]
+ if self._disassemble_prefix_len is None:
+ prefix_len = self._DetectDisassemblePrefixLen(args)
+ if prefix_len is not None:
+ self._disassemble_prefix_len = prefix_len
+
+ if self._disassemble_prefix_len is not None:
+ output_directory = self._lazy_paths.output_directory
+ # Only matters for non-generated paths, so be lenient here.
+ if output_directory is None:
+ output_directory = os.path.join(paths.SRC_ROOT, 'out', 'Release')
+ if not os.path.exists(output_directory):
+ os.makedirs(output_directory)
+
+ args += [
+ '--prefix-strip', str(self._disassemble_prefix_len),
+ '--prefix', os.path.normpath(os.path.relpath(output_directory))
+ ]
+
proc = subprocess.Popen(args, stdout=subprocess.PIPE)
lines = itertools.chain(('Showing disassembly for %r' % symbol,
'Command: %s' % ' '.join(args)),
@@ -174,7 +245,7 @@ class _Session(object):
'# Show two levels of .text, grouped by first two subdirectories',
'text_syms = size_info.symbols.WhereInSection("t")',
'by_path = text_syms.GroupedByPath(depth=2)',
- 'Print(by_path.WhereBiggerThan(1024))',
+ 'Print(by_path.WherePssBiggerThan(1024))',
'',
'# Show all non-vtable generated symbols',
'generated_syms = size_info.symbols.WhereGeneratedByToolchain()',
@@ -276,7 +347,7 @@ def Run(args, parser):
lazy_paths = paths.LazyPaths(tool_prefix=args.tool_prefix,
output_directory=args.output_directory,
any_path_within_output_directory=args.inputs[0])
- session = _Session(size_infos, lazy_paths)
+ session = _Session(size_infos, args.inputs, lazy_paths)
if args.query:
logging.info('Running query from command-line.')

Powered by Google App Engine
This is Rietveld 408576698