blob: cbb2d33320668db5f2565fe847d9f4a116b10855 [file] [log] [blame] [edit]
#!/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(
'--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.
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.no_r8lib,
quiet=args.quiet,
debug=args.debug_agent,
regex=args.regex,
verbose=args.verbose)
def run(map_path, stacktrace, 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')
retrace_args += [
'-cp',
utils.R8_JAR if no_r8lib else utils.R8RETRACE_JAR,
'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())