Flutter Engine
The Flutter Engine
copy_debug_symbols.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2#
3# Copyright 2013 The Flutter Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7""" Gather the build_id, prefix_dir, and exec_name given the path to executable
8 also copies to the specified destination.
9
10 The structure of debug symbols is as follows:
11 .build-id/<prefix>/<exec_name>[.debug]
12"""
13
14import argparse
15import errno
16import hashlib
17import json
18import os
19import re
20import shutil
21import subprocess
22import sys
23import time
24
25
26def HashFile(filepath):
27 """Calculates the hash of a file without reading it all in memory at once."""
28 digest = hashlib.sha1()
29 with open(filepath, 'rb') as f:
30 while True:
31 chunk = f.read(1024 * 1024)
32 if not chunk:
33 break
34 digest.update(chunk)
35 return digest.hexdigest()
36
37
38def Touch(fname):
39 with open(fname, 'a'):
40 os.utime(fname, None)
41
42
43def GetBuildIdParts(exec_path, read_elf):
44 sha1_pattern = re.compile(r'[0-9a-fA-F\-]+')
45 file_out = subprocess.check_output([read_elf, '-n', exec_path])
46 build_id_line = file_out.splitlines()[-1].split()
47 if (build_id_line[0] != b'Build' or build_id_line[1] != b'ID:' or
48 not sha1_pattern.match(str(build_id_line[-1])) or not len(build_id_line[-1]) > 2):
49 raise Exception(
50 'Expected the last line of llvm-readelf to match "Build ID <Hex String>" Got: %s' % file_out
51 )
52
53 build_id = build_id_line[-1]
54 return {
55 'build_id': build_id.decode('utf-8'), 'prefix_dir': build_id[:2].decode('utf-8'),
56 'exec_name': build_id[2:].decode('utf-8')
57 }
58
59
60def main():
61 parser = argparse.ArgumentParser()
62
63 parser.add_argument(
64 '--executable-name',
65 dest='exec_name',
66 action='store',
67 required=True,
68 help='This is the name of the executable that we wish to layout debug symbols for.'
69 )
70 parser.add_argument(
71 '--executable-path',
72 dest='exec_path',
73 action='store',
74 required=True,
75 help='Path to the executable on the filesystem.'
76 )
77 parser.add_argument(
78 '--destination-base',
79 dest='dest',
80 action='store',
81 required=True,
82 help='Path to the base directory where the debug symbols are to be laid out.'
83 )
84 parser.add_argument(
85 '--stripped',
86 dest='stripped',
87 action='store_true',
88 default=True,
89 help='Executable at the specified path is stripped.'
90 )
91 parser.add_argument(
92 '--unstripped',
93 dest='stripped',
94 action='store_false',
95 help='Executable at the specified path is unstripped.'
96 )
97 parser.add_argument(
98 '--read-elf',
99 dest='read_elf',
100 action='store',
101 required=True,
102 help='Path to read-elf executable.'
103 )
104
105 args = parser.parse_args()
106 assert os.path.exists(args.exec_path), ('exec_path "%s" does not exist' % args.exec_path)
107 assert os.path.exists(args.dest), ('dest "%s" does not exist' % args.dest)
108 assert os.path.exists(args.read_elf), ('read_elf "%s" does not exist' % args.read_elf)
109
110 parts = GetBuildIdParts(args.exec_path, args.read_elf)
111 dbg_prefix_base = os.path.join(args.dest, parts['prefix_dir'])
112
113 # Multiple processes may be trying to create the same directory.
114 # TODO(dnfield): use exist_ok when we upgrade to python 3, rather than try
115 try:
116 os.makedirs(dbg_prefix_base)
117 except OSError as e:
118 if e.errno != errno.EEXIST:
119 raise
120
121 if not os.path.exists(dbg_prefix_base):
122 print('Unable to create directory: %s.' % dbg_prefix_base)
123 return 1
124
125 dbg_suffix = ''
126 if not args.stripped:
127 dbg_suffix = '.debug'
128 dbg_file_name = '%s%s' % (parts['exec_name'], dbg_suffix)
129 dbg_file_path = os.path.join(dbg_prefix_base, dbg_file_name)
130
131 # If the debug file hasn't changed, don't rewrite the debug and completion
132 # file, speeding up incremental builds.
133 if os.path.exists(dbg_file_path) and HashFile(args.exec_path) == HashFile(dbg_file_path):
134 return 0
135
136 shutil.copyfile(args.exec_path, dbg_file_path)
137
138 # Note this needs to be in sync with fuchsia_debug_symbols.gni
139 completion_file = os.path.join(args.dest, '.%s_dbg_success' % args.exec_name)
140 Touch(completion_file)
141
142 return 0
143
144
145if __name__ == '__main__':
146 sys.exit(main())
def GetBuildIdParts(exec_path, read_elf)
def HashFile(filepath)
Definition: main.py:1
def print(*args, **kwargs)
Definition: run_tests.py:49
static DecodeResult decode(std::string path)
Definition: png_codec.cpp:124