diff options
Diffstat (limited to 'chromium/tools/resources')
-rwxr-xr-x | chromium/tools/resources/ar.py | 96 | ||||
-rwxr-xr-x | chromium/tools/resources/generate_resource_whitelist.py | 36 |
2 files changed, 130 insertions, 2 deletions
diff --git a/chromium/tools/resources/ar.py b/chromium/tools/resources/ar.py new file mode 100755 index 00000000000..19c294fba54 --- /dev/null +++ b/chromium/tools/resources/ar.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python3 +# Copyright 2018 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. +"""Logic for reading .a files. + +Copied from //tools/binary_size/libsupersize/ar.py""" + +import os + + +def _ResolveThinObjectPath(archive_path, subpath): + """Given the .a path and .o subpath, returns the .o path.""" + # |subpath| is path complete under Gold, and incomplete under LLD. Check its + # prefix to test completeness, and if not, use |archive_path| to supply the + # required prefix. + if subpath.startswith('obj/'): + return subpath + # .o subpaths in thin archives are relative to the directory of the .a. + parent_path = os.path.dirname(archive_path) + return os.path.normpath(os.path.join(parent_path, subpath)) + + +def _IterThinPaths(path): + """Given the .a path, yields all nested .o paths.""" + # File format reference: + # https://github.com/pathscale/binutils/blob/master/gold/archive.cc + with open(path, 'rb') as f: + header = f.read(8) + is_thin = header == b'!<thin>\n' + if not is_thin and header != b'!<arch>\n': + raise Exception('Invalid .a: ' + path) + if not is_thin: + return + + def read_payload(size): + ret = f.read(size) + # Entries are 2-byte aligned. + if size & 1 != 0: + f.read(1) + return ret + + while True: + entry = f.read(60) + if not entry: + return + entry_name = entry[:16].rstrip() + entry_size = int(entry[48:58].rstrip()) + + if entry_name in (b'', b'/', b'//', b'/SYM64/'): + payload = read_payload(entry_size) + # Metadata sections we don't care about. + if entry_name == b'//': + name_list = payload + continue + + if entry_name[0:1] == b'/': + # Name is specified as location in name table. + # E.g.: /123 + name_offset = int(entry_name[1:]) + # String table enties are delimited by \n (e.g. "browser.o/\n"). + end_idx = name_list.index(b'\n', name_offset) + entry_name = name_list[name_offset:end_idx] + else: + # Name specified inline with spaces for padding (e.g. "browser.o/ "). + entry_name = entry_name.rstrip() + + yield entry_name.rstrip(b'/').decode('ascii') + + +def ExpandThinArchives(paths): + """Expands all thin archives found in |paths| into .o paths. + + Args: + paths: List of paths relative to |output_directory|. + output_directory: Output directory. + + Returns: + * A new list of paths with all archives replaced by .o paths. + """ + expanded_paths = [] + for path in paths: + if not path.endswith('.a'): + expanded_paths.append(path) + continue + + with open(path, 'rb') as f: + header = f.read(8) + is_thin = header == b'!<thin>\n' + if is_thin: + for subpath in _IterThinPaths(path): + expanded_paths.append(_ResolveThinObjectPath(path, subpath)) + elif header != b'!<arch>\n': + raise Exception('Invalid .a: ' + path) + + return expanded_paths diff --git a/chromium/tools/resources/generate_resource_whitelist.py b/chromium/tools/resources/generate_resource_whitelist.py index 754f123827b..ea96e3a340b 100755 --- a/chromium/tools/resources/generate_resource_whitelist.py +++ b/chromium/tools/resources/generate_resource_whitelist.py @@ -21,6 +21,8 @@ import os import subprocess import sys +import ar + llvm_bindir = os.path.join( os.path.dirname(sys.argv[0]), '..', '..', 'third_party', 'llvm-build', 'Release+Asserts', 'bin') @@ -100,17 +102,47 @@ def GetResourceWhitelistPDB(path): return resource_ids +def GetResourceWhitelistFileList(file_list_path): + # Creates a list of resources given the list of linker input files. + # Simply grep's them for WhitelistedResource<...>. + with open(file_list_path) as f: + paths = f.read().splitlines() + + paths = ar.ExpandThinArchives(paths) + + resource_ids = set() + prefix = 'WhitelistedResource<' + for p in paths: + with open(p) as f: + data = f.read() + start_idx = 0 + while start_idx != -1: + start_idx = data.find(prefix, start_idx) + if start_idx != -1: + end_idx = data.find('>', start_idx) + resource_ids.add(int(data[start_idx + len(prefix):end_idx])) + start_idx = end_idx + return resource_ids + + def WriteResourceWhitelist(args): resource_ids = set() for input in args.inputs: with open(input, 'r') as f: magic = f.read(4) + chunk = f.read(60) if magic == '\x7fELF': - resource_ids = resource_ids.union(GetResourceWhitelistELF(input)) + func = GetResourceWhitelistELF elif magic == 'Micr': - resource_ids = resource_ids.union(GetResourceWhitelistPDB(input)) + func = GetResourceWhitelistPDB + elif magic == 'obj/' or '/obj/' in chunk: + # For secondary toolchain, path will look like android_clang_arm/obj/... + func = GetResourceWhitelistFileList else: raise Exception('unknown file format') + + resource_ids.update(func(input)) + if len(resource_ids) == 0: raise Exception('No debug info was dumped. Ensure GN arg "symbol_level" ' '!= 0 and that the file is not stripped.') |