Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(252)

Side by Side Diff: components/breakpad/tools/generate_breakpad_symbols.py

Issue 48633002: Only generate breakpad symbols for build artefacts (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: updates Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | content/content_shell.gypi » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright 2013 The Chromium Authors. All rights reserved. 2 # Copyright 2013 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """A tool to generate symbols for a binary suitable for breakpad. 6 """A tool to generate symbols for a binary suitable for breakpad.
7 7
8 Currently, the tool only supports Linux, Android, and Mac. Support for other 8 Currently, the tool only supports Linux, Android, and Mac. Support for other
9 platforms is planned. 9 platforms is planned.
10 """ 10 """
(...skipping 20 matching lines...) Expand all
31 31
32 From chromium_utils. 32 From chromium_utils.
33 """ 33 """
34 devnull = open(os.devnull, 'w') 34 devnull = open(os.devnull, 'w')
35 proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=devnull, 35 proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=devnull,
36 bufsize=1) 36 bufsize=1)
37 output = proc.communicate()[0] 37 output = proc.communicate()[0]
38 return output 38 return output
39 39
40 40
41 def GetDumpSymsBinary(dump_syms_dir=None): 41 def GetDumpSymsBinary(build_dir=None):
42 """Returns the path to the dump_syms binary.""" 42 """Returns the path to the dump_syms binary."""
43 DUMP_SYMS = 'dump_syms' 43 DUMP_SYMS = 'dump_syms'
44 dump_syms_bin = None 44 dump_syms_bin = os.path.join(os.path.expanduser(build_dir), DUMP_SYMS)
45 if dump_syms_dir: 45 if not os.access(dump_syms_bin, os.X_OK):
46 bin = os.path.join(os.path.expanduser(dump_syms_dir), DUMP_SYMS)
47 if os.access(bin, os.X_OK):
48 dump_syms_bin = bin
49 else:
50 for path in os.environ['PATH'].split(':'):
51 bin = os.path.join(path, DUMP_SYMS)
52 if os.access(bin, os.X_OK):
53 dump_syms_bin = bin
54 break
55 if not dump_syms_bin:
56 print 'Cannot find %s.' % DUMP_SYMS 46 print 'Cannot find %s.' % DUMP_SYMS
57 sys.exit(1) 47 sys.exit(1)
58 48
59 return dump_syms_bin 49 return dump_syms_bin
60 50
61 51
62 def Resolve(path, exe_path, loader_path, rpaths): 52 def Resolve(path, exe_path, loader_path, rpaths):
63 """Resolve a dyld path. 53 """Resolve a dyld path.
64 54
65 @executable_path is replaced with |exe_path| 55 @executable_path is replaced with |exe_path|
66 @loader_path is replaced with |loader_path| 56 @loader_path is replaced with |loader_path|
67 @rpath is replaced with the first path in |rpaths| where the referenced file 57 @rpath is replaced with the first path in |rpaths| where the referenced file
68 is found 58 is found
69 """ 59 """
70 path.replace('@loader_path', loader_path) 60 path = path.replace('@loader_path', loader_path)
71 path.replace('@executable_path', exe_path) 61 path = path.replace('@executable_path', exe_path)
72 if path.find('@rpath') != -1: 62 if path.find('@rpath') != -1:
73 for rpath in rpaths: 63 for rpath in rpaths:
74 new_path = Resolve(path.replace('@rpath', rpath), exe_path, loader_path, 64 new_path = Resolve(path.replace('@rpath', rpath), exe_path, loader_path,
75 []) 65 [])
76 if os.access(new_path, os.X_OK): 66 if os.access(new_path, os.X_OK):
77 return new_path 67 return new_path
78 return '' 68 return ''
79 return path 69 return path
80 70
81 71
(...skipping 23 matching lines...) Expand all
105 m = re.match(' *path (.*) \(offset .*\)$', otool[idx+2]) 95 m = re.match(' *path (.*) \(offset .*\)$', otool[idx+2])
106 rpaths.append(m.group(1)) 96 rpaths.append(m.group(1))
107 97
108 otool = GetCommandOutput(['otool', '-L', binary]).splitlines() 98 otool = GetCommandOutput(['otool', '-L', binary]).splitlines()
109 lib_re = re.compile('\t(.*) \(compatibility .*\)$') 99 lib_re = re.compile('\t(.*) \(compatibility .*\)$')
110 deps = [] 100 deps = []
111 for line in otool: 101 for line in otool:
112 m = lib_re.match(line) 102 m = lib_re.match(line)
113 if m: 103 if m:
114 dep = Resolve(m.group(1), exe_path, loader_path, rpaths) 104 dep = Resolve(m.group(1), exe_path, loader_path, rpaths)
115 if dep and os.access(dep, os.X_OK): 105 if dep:
116 deps.append(os.path.normpath(dep)) 106 deps.append(os.path.normpath(dep))
117 return deps 107 return deps
118 108
119 109
120 def GetSharedLibraryDependencies(binary, exe_path): 110 def GetSharedLibraryDependencies(options, binary, exe_path):
121 """Return absolute paths to all shared library dependecies of the binary.""" 111 """Return absolute paths to all shared library dependecies of the binary."""
112 deps = []
122 if sys.platform.startswith('linux'): 113 if sys.platform.startswith('linux'):
123 return GetSharedLibraryDependenciesLinux(binary) 114 deps = GetSharedLibraryDependenciesLinux(binary)
115 elif sys.platform == 'darwin':
116 deps = GetSharedLibraryDependenciesMac(binary, exe_path)
117 else:
118 print "Platform not supported."
119 sys.exit(1)
124 120
125 if sys.platform == 'darwin': 121 result = []
126 return GetSharedLibraryDependenciesMac(binary, exe_path) 122 build_dir = os.path.abspath(options.build_dir)
127 123 for dep in deps:
128 print "Platform not supported." 124 if (os.access(dep, os.X_OK) and
129 sys.exit(1) 125 os.path.abspath(os.path.dirname(dep)).startswith(build_dir)):
126 result.append(dep)
127 return result
130 128
131 129
132 def mkdir_p(path): 130 def mkdir_p(path):
133 """Simulates mkdir -p.""" 131 """Simulates mkdir -p."""
134 try: 132 try:
135 os.makedirs(path) 133 os.makedirs(path)
136 except OSError as e: 134 except OSError as e:
137 if e.errno == errno.EEXIST and os.path.isdir(path): 135 if e.errno == errno.EEXIST and os.path.isdir(path):
138 pass 136 pass
139 else: raise 137 else: raise
140 138
141 139
142 def GenerateSymbols(options, binaries): 140 def GenerateSymbols(options, binaries):
143 """Dumps the symbols of binary and places them in the given directory.""" 141 """Dumps the symbols of binary and places them in the given directory."""
144 142
145 queue = Queue.Queue() 143 queue = Queue.Queue()
146 144
147 def _Worker(): 145 def _Worker():
148 while True: 146 while True:
149 binary = queue.get() 147 binary = queue.get()
150 148
151 syms = GetCommandOutput([GetDumpSymsBinary(options.dump_syms_dir), 149 syms = GetCommandOutput([GetDumpSymsBinary(options.build_dir),
152 binary]) 150 binary])
153 module_line = re.match("MODULE [^ ]+ [^ ]+ ([0-9A-F]+) (.*)\n", syms) 151 module_line = re.match("MODULE [^ ]+ [^ ]+ ([0-9A-F]+) (.*)\n", syms)
154 output_path = os.path.join(options.symbols_dir, module_line.group(2), 152 output_path = os.path.join(options.symbols_dir, module_line.group(2),
155 module_line.group(1)) 153 module_line.group(1))
156 mkdir_p(output_path) 154 mkdir_p(output_path)
157 symbol_file = "%s.sym" % module_line.group(2) 155 symbol_file = "%s.sym" % module_line.group(2)
158 f = open(os.path.join(output_path, symbol_file), 'w') 156 f = open(os.path.join(output_path, symbol_file), 'w')
159 f.write(syms) 157 f.write(syms)
160 f.close() 158 f.close()
161 159
162 queue.task_done() 160 queue.task_done()
163 161
164 for binary in binaries: 162 for binary in binaries:
165 queue.put(binary) 163 queue.put(binary)
166 164
167 for _ in range(options.jobs): 165 for _ in range(options.jobs):
168 t = threading.Thread(target=_Worker) 166 t = threading.Thread(target=_Worker)
169 t.daemon = True 167 t.daemon = True
170 t.start() 168 t.start()
171 169
172 queue.join() 170 queue.join()
173 171
174 172
175 def main(): 173 def main():
176 parser = optparse.OptionParser() 174 parser = optparse.OptionParser()
177 parser.add_option('', '--dump-syms-dir', default='', 175 parser.add_option('', '--build-dir', default='',
178 help='The directory where dump_syms is installed. ' 176 help='The build output directory.')
179 'Searches $PATH by default')
180 parser.add_option('', '--symbols-dir', default='', 177 parser.add_option('', '--symbols-dir', default='',
181 help='The directory where to write the symbols file.') 178 help='The directory where to write the symbols file.')
182 parser.add_option('', '--binary', default='', 179 parser.add_option('', '--binary', default='',
183 help='The path of the binary to generate symbols for.') 180 help='The path of the binary to generate symbols for.')
184 parser.add_option('', '--clear', default=False, action='store_true', 181 parser.add_option('', '--clear', default=False, action='store_true',
185 help='Clear the symbols directory before writing new ' 182 help='Clear the symbols directory before writing new '
186 'symbols.') 183 'symbols.')
187 parser.add_option('-j', '--jobs', default=CONCURRENT_TASKS, action='store', 184 parser.add_option('-j', '--jobs', default=CONCURRENT_TASKS, action='store',
188 type='int', help='Number of parallel tasks to run.') 185 type='int', help='Number of parallel tasks to run.')
189 186
190 (options, _) = parser.parse_args() 187 (options, _) = parser.parse_args()
191 188
192 if not options.symbols_dir: 189 if not options.symbols_dir:
193 print "Required option --symbols-dir missing." 190 print "Required option --symbols-dir missing."
194 return 1 191 return 1
195 192
193 if not options.build_dir:
194 print "Required option --build-dir missing."
195 return 1
196
196 if not options.binary: 197 if not options.binary:
197 print "Required option --binary missing." 198 print "Required option --binary missing."
198 return 1 199 return 1
199 200
200 if not os.access(options.binary, os.X_OK): 201 if not os.access(options.binary, os.X_OK):
201 print "Cannot find %s." % options.binary 202 print "Cannot find %s." % options.binary
202 return 1 203 return 1
203 204
204 if options.clear: 205 if options.clear:
205 try: 206 try:
206 shutil.rmtree(options.symbols_dir) 207 shutil.rmtree(options.symbols_dir)
207 except: 208 except:
208 pass 209 pass
209 210
210 # Build the transitive closure of all dependencies. 211 # Build the transitive closure of all dependencies.
211 binaries = set([options.binary]) 212 binaries = set([options.binary])
212 queue = [options.binary] 213 queue = [options.binary]
213 exe_path = os.path.dirname(options.binary) 214 exe_path = os.path.dirname(options.binary)
214 while queue: 215 while queue:
215 deps = GetSharedLibraryDependencies(queue.pop(0), exe_path) 216 deps = GetSharedLibraryDependencies(options, queue.pop(0), exe_path)
216 new_deps = set(deps) - binaries 217 new_deps = set(deps) - binaries
217 binaries |= new_deps 218 binaries |= new_deps
218 queue.extend(list(new_deps)) 219 queue.extend(list(new_deps))
219 220
220 GenerateSymbols(options, binaries) 221 GenerateSymbols(options, binaries)
221 222
222 return 0 223 return 0
223 224
224 225
225 if '__main__' == __name__: 226 if '__main__' == __name__:
226 sys.exit(main()) 227 sys.exit(main())
OLDNEW
« no previous file with comments | « no previous file | content/content_shell.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698