chromium/tools/tracing/get_clank_symbols

#!/usr/bin/env python3
#
# Copyright 2021 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import optparse
import os
import sys

sys.path.insert(
    0,
    os.path.join(
        os.path.dirname(__file__), os.pardir, os.pardir, 'third_party',
        'catapult', 'systrace'))
import breakpad_file_extractor
import flag_utils
import metadata_extractor
import symbol_fetcher
import get_symbols_util

_DESCRIPTION = (
"""Fetches symbol files for Android official builds, need access to the storage.
Useful to symbolize crashes. You can find the version number and version code
in the bug reports or stack trace. Version number is commonly used Chrome
Version, like "93.0.4606.0" and version code is play store version code, a 9-10
digit number starting with branch number, 460601633. Module ID can be seen from
unsymbolized stack trace, a 32 character hex string in upper case. You need to
build dump_syms in your local output dir to use module ID matcher. In any
Android output directory with same arch (arm), build dump_syms by using
ninja -C out-android/Release dump_syms.
""")

_USAGE = """
  tools/tracing/get_clank_symbols --version=<> --version_code=<> \\
      --arch={arm/x86} --module_id=<ABC123> \\
      --dump_syms=<out-android/Release/dupm_syms> -v

  optional:
    --arch={arm/x86}
    --output=/tmp/output_dir/
"""


def _CreateOptionParser():
  parser = optparse.OptionParser(
      description=_DESCRIPTION, usage=_USAGE, conflict_handler='resolve')

  parser.add_option_group(flag_utils.GeneralOptions(parser))
  parser.add_option_group(flag_utils.SymbolizeOptions(parser))

  parser.add_option('--version', dest='version')
  parser.add_option('--version_code', dest='version_code')
  parser.add_option('--module_id', dest='module_id')
  parser.add_option('--arch', dest='arch', default='arm64')
  parser.add_option('--output', dest='output', default='/tmp/symbols')

  return parser


def main():
  parser = _CreateOptionParser()
  options, _ = parser.parse_args()

  flag_utils.SetupLogging(options.verbosity)
  logger = flag_utils.GetTracingLogger()

  if not options.version or not options.version_code:
    raise Exception('Both Chrome --version and --version_code are necessary to '
                    'fetch symbols.')

  metadata = metadata_extractor.MetadataExtractor(None, None)
  metadata.os_name = 'android'
  metadata.version_number = options.version
  metadata.version_code = options.version_code
  metadata.architecture = options.arch

  if options.module_id:
    if not options.dump_syms_path:
      raise Exception('Path to dump_syms binary is required for symbolizing '
                      'official Android traces. You can build dump_syms from '
                      'your local build directory with the right architecture '
                      'with: autoninja -C out_<arch>/Release dump_syms.')

  if os.path.isdir(options.output):
    logger.warning(
        'The output directory %s exists, and new files will overwrite the old '
        'ones.', options.output)

  print(
      'Downloading all symbols for the version, please wait up to 5 minutes...')
  symbol_fetcher.GetAndroidSymbols(options.cloud_storage_bucket, metadata,
                                   options.output)

  if not options.module_id:
    print('All symbols downloaded to ' + options.output)
    return

  found_module = get_symbols_util.FindMatchingModule(options.output,
                                                     options.dump_syms_path,
                                                     options.module_id)
  if found_module:
    print('Found symbol file with module ID: %s and saved to %s. Use this '
          'directory for symbolization' % (options.module_id, found_module))
  else:
    logger.error(
        'No modules with the module ID %s found. All symbols for the specified '
        'version are saved to %s', (options.module_id, options.output))


if __name__ == '__main__':
  sys.exit(main())