blob: 9768ff3e658a6fe7061a96b9bc7458d5a76d14e2 [file] [log] [blame]
#!/usr/bin/env python3
# Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
from os import path
import argparse
import os
import subprocess
import sys
import jdk
import utils
def parse_arguments():
parser = argparse.ArgumentParser(
description='R8lib wrapper for retrace tool.')
parser.add_argument('-c',
'--commit-hash',
'--commit_hash',
help='Commit hash to download r8lib map file for.',
default=None)
parser.add_argument('--version',
help='Version to download r8lib map file for.',
default=None)
parser.add_argument('--tag',
help='Tag to download r8lib map file for.',
default=None)
parser.add_argument(
'--exclude-deps',
'--exclude_deps',
default=None,
action='store_true',
help='Use the exclude-deps version of the mapping file.')
parser.add_argument('--map', help='Path to r8lib map.', default=None)
parser.add_argument('--r8jar', help='Path to r8 jar.', default=None)
parser.add_argument('--no-r8lib',
'--no_r8lib',
default=False,
action='store_true',
help='Use r8.jar and not r8lib.jar.')
parser.add_argument(
'--stacktrace',
help='Path to stacktrace file (read from stdin if not passed).',
default=None)
parser.add_argument('--quiet',
default=None,
action='store_true',
help='Disables diagnostics printing to stdout.')
parser.add_argument(
'--debug-agent',
'--debug_agent',
default=None,
action='store_true',
help='Attach a debug-agent to the retracer java process.')
parser.add_argument(
'--regex',
default=None,
help='Sets a custom regular expression used for parsing')
parser.add_argument('--verbose',
default=None,
action='store_true',
help='Enables verbose retracing.')
parser.add_argument('--disable-map-validation',
default=None,
action='store_true',
help='Disable validation of map hash.')
return parser.parse_args()
def get_map_file(args, temp):
# default to using the specified map file.
if args.map:
return args.map
# next try to extract it from the tag/version options.
map_path = utils.find_cloud_storage_file_from_options('r8lib.jar.map', args)
if map_path:
return map_path
# next try to extract it from the stack-trace source-file content.
if not args.stacktrace:
if not args.quiet:
print('Waiting for stack-trace input...')
args.stacktrace = os.path.join(temp, 'stacktrace.txt')
open(args.stacktrace, 'w').writelines(sys.stdin.readlines())
r8_source_file = None
for line in open(args.stacktrace, 'r'):
start = line.rfind("(R8_")
if start > 0:
end = line.find(":", start)
content = line[start + 1:end]
if r8_source_file:
if content != r8_source_file:
print(
'WARNING: there are multiple distinct R8 source files:')
print(' ' + r8_source_file)
print(' ' + content)
else:
r8_source_file = content
if r8_source_file:
(header, r8_version_or_hash, maphash) = r8_source_file.split('_')
# If the command-line specified --exclude-deps then assume it is as previous
# versions will not be marked as such in the source-file line.
is_excldeps = args.exclude_deps
excldeps_start = r8_version_or_hash.find('+excldeps')
if (excldeps_start > 0):
is_excldeps = True
r8_version_or_hash = r8_version_or_hash[0:excldeps_start]
if len(r8_version_or_hash) < 40:
args.version = r8_version_or_hash
else:
args.commit_hash = r8_version_or_hash
map_path = None
if path.exists(utils.R8LIB_MAP) and get_hash_from_map_file(
utils.R8LIB_MAP) == maphash:
return utils.R8LIB_MAP
try:
map_path = utils.find_cloud_storage_file_from_options(
'r8lib' + ('-exclude-deps' if is_excldeps else '') + '.jar.map',
args)
except Exception as e:
print(e)
print('WARNING: Falling back to using local mapping file.')
if map_path and not args.disable_map_validation:
check_maphash(map_path, maphash, args)
return map_path
# If no other map file was found, use the local mapping file.
if args.r8jar:
return args.r8jar + ".map"
return utils.R8LIB_MAP
def check_maphash(mapping_path, maphash, args):
infile_maphash = get_hash_from_map_file(mapping_path)
if infile_maphash != maphash:
print('ERROR: The mapping file hash does not match the R8 line')
print(' In mapping file: ' + infile_maphash)
print(' In source file: ' + maphash)
if (not args.exclude_deps):
print(
'If this could be a version without internalized dependencies '
+ 'try passing --exclude-deps')
sys.exit(1)
def get_hash_from_map_file(mapping_path):
map_hash_header = "# pg_map_hash: SHA-256 "
for line in open(mapping_path, 'r'):
if line.startswith(map_hash_header):
return line[len(map_hash_header):].strip()
def main():
args = parse_arguments()
with utils.TempDir() as temp:
map_path = get_map_file(args, temp)
return run(map_path,
args.stacktrace,
args.r8jar,
args.no_r8lib,
quiet=args.quiet,
debug=args.debug_agent,
regex=args.regex,
verbose=args.verbose)
def run(map_path,
stacktrace,
r8jar,
no_r8lib,
quiet=False,
debug=False,
regex=None,
verbose=False):
retrace_args = [jdk.GetJavaExecutable()]
if debug:
retrace_args.append(
'-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005'
)
if not r8jar:
r8jar = utils.R8_JAR if no_r8lib else utils.R8LIB_JAR
retrace_args += [
'-cp', r8jar, 'com.android.tools.r8.retrace.Retrace', map_path
]
if regex:
retrace_args.append('--regex')
retrace_args.append(regex)
if quiet:
retrace_args.append('--quiet')
if stacktrace:
retrace_args.append(stacktrace)
if verbose:
retrace_args.append('--verbose')
utils.PrintCmd(retrace_args, quiet=quiet)
return subprocess.call(retrace_args)
if __name__ == '__main__':
sys.exit(main())