diff --git a/tools/fuchsia/copy_debug_symbols.py b/tools/fuchsia/copy_debug_symbols.py new file mode 100755 index 0000000000000000000000000000000000000000..e7f2ad7810aecf5ccd33c912ec28d5792bc9fa63 --- /dev/null +++ b/tools/fuchsia/copy_debug_symbols.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python +# +# Copyright 2013 The Flutter Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +""" Gather the build_id, prefix_dir, and exec_name given the path to executable + also copies to the specified destination. + + The structure of debug symbols is as follows: + .build-id//[.debug] +""" + +import argparse +import json +import os +import re +import shutil +import subprocess +import sys +import time + + +def Touch(fname): + with open(fname, 'a'): + os.utime(fname, None) + + +def GetBuildIdParts(exec_path, read_elf): + file_out = subprocess.check_output( + [read_elf, '--hex-dump=.note.gnu.build-id', exec_path]) + second_line = file_out.splitlines()[-1].split() + build_id = second_line[1] + second_line[2] + return { + 'build_id': build_id, + 'prefix_dir': build_id[:2], + 'exec_name': build_id[2:] + } + + +def main(): + parser = argparse.ArgumentParser() + + parser.add_argument( + '--executable-name', + dest='exec_name', + action='store', + required=True, + help='This is the name of the executable that we wish to layout debug symbols for.' + ) + parser.add_argument( + '--executable-path', + dest='exec_path', + action='store', + required=True, + help='Path to the executable on the filesystem.') + parser.add_argument( + '--destination-base', + dest='dest', + action='store', + required=True, + help='Path to the base directory where the debug symbols are to be laid out.' + ) + parser.add_argument( + '--stripped', + dest='stripped', + action='store_true', + default=True, + help='Executable at the specified path is stripped.') + parser.add_argument( + '--unstripped', + dest='stripped', + action='store_false', + help='Executable at the specified path is unstripped.') + parser.add_argument( + '--read-elf', + dest='read_elf', + action='store', + required=True, + help='Path to read-elf executable.') + + args = parser.parse_args() + assert os.path.exists(args.exec_path) + assert os.path.exists(args.dest) + assert os.path.exists(args.read_elf) + + parts = GetBuildIdParts(args.exec_path, args.read_elf) + dbg_prefix_base = os.path.join(args.dest, parts['prefix_dir']) + + success = False + for _ in range(3): + try: + if not os.path.exists(dbg_prefix_base): + os.makedirs(dbg_prefix_base) + success = True + break + except OSError as error: + print 'Failed to create dir %s, error: %s. sleeping...' % ( + dbg_prefix_base, error) + time.sleep(3) + + if not success: + print 'Unable to create directory: %s.' % dbg_prefix_base + return 1 + + dbg_suffix = '' + if not args.stripped: + dbg_suffix = '.debug' + dbg_file_name = '%s%s' % (parts['exec_name'], dbg_suffix) + dbg_file_path = os.path.join(dbg_prefix_base, dbg_file_name) + + shutil.copyfile(args.exec_path, dbg_file_path) + + # Note this needs to be in sync with debug_symbols.gni + completion_file = os.path.join(args.dest, '.%s_dbg_success' % args.exec_name) + Touch(completion_file) + + return 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/tools/fuchsia/fuchsia_archive.gni b/tools/fuchsia/fuchsia_archive.gni index 752b5def4cbfefcc0a8a4e4bf256ac2df7e813a0..a5c0a0cb05917f4b6300243791ec04c688b99f4d 100644 --- a/tools/fuchsia/fuchsia_archive.gni +++ b/tools/fuchsia/fuchsia_archive.gni @@ -2,6 +2,8 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("$flutter_root/tools/fuchsia/fuchsia_debug_symbols.gni") + # Creates a Fuchsia archive (.far) file using PM from the Fuchsia SDK. template("fuchsia_archive") { assert(defined(invoker.binary), "package must define binary") @@ -72,6 +74,13 @@ template("fuchsia_archive") { }, "json") + _dbg_symbols_target = "${target_name}_dbg_symbols" + fuchsia_debug_symbols(_dbg_symbols_target) { + deps = pkg.deps + testonly = pkg_testonly + binary = invoker.binary + } + pkg_dir_deps = pkg.deps + [ ":$cmx_target" ] action("${target_name}_dir") { @@ -86,7 +95,10 @@ template("fuchsia_archive") { action(target_name) { script = "$flutter_root/tools/fuchsia/gen_package.py" - deps = pkg_dir_deps + [ ":${target_name}_dir" ] + deps = pkg_dir_deps + [ + ":${target_name}_dir", + ":${_dbg_symbols_target}", + ] sources = copy_outputs inputs = [] diff --git a/tools/fuchsia/fuchsia_debug_symbols.gni b/tools/fuchsia/fuchsia_debug_symbols.gni new file mode 100644 index 0000000000000000000000000000000000000000..fb02d70eeea41949557687ed762a604f1497bbc7 --- /dev/null +++ b/tools/fuchsia/fuchsia_debug_symbols.gni @@ -0,0 +1,74 @@ +# Copyright 2013 The Flutter Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# The inputs to this template are 'binary_path' and a boolean 'unstripped'. +# If 'unstripped' is specified, we append '.debug' to the symbols name. +template("_copy_debug_symbols") { + assert(defined(invoker.binary_path), "'binary_path' needs to be defined.") + assert(defined(invoker.unstripped), "'unstripped' needs to be defined.") + + action(target_name) { + forward_variables_from(invoker, + [ + "deps", + "unstripped", + "binary_path", + "testonly", + ]) + + script = "$flutter_root/tools/fuchsia/copy_debug_symbols.py" + + sources = [ + binary_path, + ] + + _dest_base = + "${root_out_dir}/flutter-debug-symbols-${target_os}-${target_cpu}" + + args = [ + "--executable-name", + target_name, + "--executable-path", + rebase_path(binary_path), + "--destination-base", + rebase_path(_dest_base), + "--read-elf", + rebase_path("//fuchsia/toolchain/$host_os/bin/llvm-readelf"), + ] + + if (unstripped) { + args += [ "--unstripped" ] + } + + outputs = [ + "${_dest_base}/.${target_name}_success", + ] + } +} + +# Takes a binary and generates its debug symbols following +# the Fuchsia packaging convention. +template("fuchsia_debug_symbols") { + assert(defined(invoker.binary), "'binary' needs to be defined.") + + _copy_debug_symbols("_${target_name}_stripped") { + forward_variables_from(invoker, "*") + binary_path = rebase_path("${root_out_dir}/$binary") + unstripped = false + } + + _copy_debug_symbols("_${target_name}_unstripped") { + forward_variables_from(invoker, "*") + binary_path = "${root_out_dir}/exe.unstripped/$binary" + unstripped = true + } + + group(target_name) { + forward_variables_from(invoker, [ "testonly" ]) + deps = [ + ":_${target_name}_stripped", + ":_${target_name}_unstripped", + ] + } +}