Index: components/crash/tools/generate_breakpad_symbols.py |
diff --git a/components/crash/tools/generate_breakpad_symbols.py b/components/crash/tools/generate_breakpad_symbols.py |
deleted file mode 100755 |
index 5f8fb8565140d49f3cc022b3bb99f9fd2c6610cf..0000000000000000000000000000000000000000 |
--- a/components/crash/tools/generate_breakpad_symbols.py |
+++ /dev/null |
@@ -1,262 +0,0 @@ |
-#!/usr/bin/env python |
-# Copyright 2013 The Chromium Authors. All rights reserved. |
-# Use of this source code is governed by a BSD-style license that can be |
-# found in the LICENSE file. |
- |
-"""A tool to generate symbols for a binary suitable for breakpad. |
- |
-Currently, the tool only supports Linux, Android, and Mac. Support for other |
-platforms is planned. |
-""" |
- |
-import errno |
-import optparse |
-import os |
-import Queue |
-import re |
-import shutil |
-import subprocess |
-import sys |
-import threading |
- |
- |
-CONCURRENT_TASKS=4 |
- |
- |
-def GetCommandOutput(command): |
- """Runs the command list, returning its output. |
- |
- Prints the given command (which should be a list of one or more strings), |
- then runs it and returns its output (stdout) as a string. |
- |
- From chromium_utils. |
- """ |
- devnull = open(os.devnull, 'w') |
- proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=devnull, |
- bufsize=1) |
- output = proc.communicate()[0] |
- return output |
- |
- |
-def GetDumpSymsBinary(build_dir=None): |
- """Returns the path to the dump_syms binary.""" |
- DUMP_SYMS = 'dump_syms' |
- dump_syms_bin = os.path.join(os.path.expanduser(build_dir), DUMP_SYMS) |
- if not os.access(dump_syms_bin, os.X_OK): |
- print 'Cannot find %s.' % dump_syms_bin |
- return None |
- |
- return dump_syms_bin |
- |
- |
-def Resolve(path, exe_path, loader_path, rpaths): |
- """Resolve a dyld path. |
- |
- @executable_path is replaced with |exe_path| |
- @loader_path is replaced with |loader_path| |
- @rpath is replaced with the first path in |rpaths| where the referenced file |
- is found |
- """ |
- path = path.replace('@loader_path', loader_path) |
- path = path.replace('@executable_path', exe_path) |
- if path.find('@rpath') != -1: |
- for rpath in rpaths: |
- new_path = Resolve(path.replace('@rpath', rpath), exe_path, loader_path, |
- []) |
- if os.access(new_path, os.X_OK): |
- return new_path |
- return '' |
- return path |
- |
- |
-def GetSharedLibraryDependenciesLinux(binary): |
- """Return absolute paths to all shared library dependecies of the binary. |
- |
- This implementation assumes that we're running on a Linux system.""" |
- ldd = GetCommandOutput(['ldd', binary]) |
- lib_re = re.compile('\t.* => (.+) \(.*\)$') |
- result = [] |
- for line in ldd.splitlines(): |
- m = lib_re.match(line) |
- if m: |
- result.append(m.group(1)) |
- return result |
- |
- |
-def GetSharedLibraryDependenciesMac(binary, exe_path): |
- """Return absolute paths to all shared library dependecies of the binary. |
- |
- This implementation assumes that we're running on a Mac system.""" |
- loader_path = os.path.dirname(binary) |
- otool = GetCommandOutput(['otool', '-l', binary]).splitlines() |
- rpaths = [] |
- for idx, line in enumerate(otool): |
- if line.find('cmd LC_RPATH') != -1: |
- m = re.match(' *path (.*) \(offset .*\)$', otool[idx+2]) |
- rpaths.append(m.group(1)) |
- |
- otool = GetCommandOutput(['otool', '-L', binary]).splitlines() |
- lib_re = re.compile('\t(.*) \(compatibility .*\)$') |
- deps = [] |
- for line in otool: |
- m = lib_re.match(line) |
- if m: |
- dep = Resolve(m.group(1), exe_path, loader_path, rpaths) |
- if dep: |
- deps.append(os.path.normpath(dep)) |
- return deps |
- |
- |
-def GetSharedLibraryDependencies(options, binary, exe_path): |
- """Return absolute paths to all shared library dependecies of the binary.""" |
- deps = [] |
- if sys.platform.startswith('linux'): |
- deps = GetSharedLibraryDependenciesLinux(binary) |
- elif sys.platform == 'darwin': |
- deps = GetSharedLibraryDependenciesMac(binary, exe_path) |
- else: |
- print "Platform not supported." |
- sys.exit(1) |
- |
- result = [] |
- build_dir = os.path.abspath(options.build_dir) |
- for dep in deps: |
- if (os.access(dep, os.X_OK) and |
- os.path.abspath(os.path.dirname(dep)).startswith(build_dir)): |
- result.append(dep) |
- return result |
- |
- |
-def mkdir_p(path): |
- """Simulates mkdir -p.""" |
- try: |
- os.makedirs(path) |
- except OSError as e: |
- if e.errno == errno.EEXIST and os.path.isdir(path): |
- pass |
- else: raise |
- |
- |
-def GenerateSymbols(options, binaries): |
- """Dumps the symbols of binary and places them in the given directory.""" |
- |
- queue = Queue.Queue() |
- print_lock = threading.Lock() |
- |
- def _Worker(): |
- while True: |
- binary = queue.get() |
- |
- should_dump_syms = True |
- reason = "no reason" |
- |
- output_path = os.path.join( |
- options.symbols_dir, os.path.basename(binary)) |
- if os.path.isdir(output_path): |
- if os.path.getmtime(binary) < os.path.getmtime(output_path): |
- should_dump_syms = False |
- reason = "symbols are more current than binary" |
- |
- if not should_dump_syms: |
- if options.verbose: |
- with print_lock: |
- print "Skipping %s (%s)" % (binary, reason) |
- queue.task_done() |
- continue |
- |
- if options.verbose: |
- with print_lock: |
- print "Generating symbols for %s" % binary |
- |
- if os.path.isdir(output_path): |
- os.utime(output_path, None) |
- |
- syms = GetCommandOutput([GetDumpSymsBinary(options.build_dir), '-r', |
- binary]) |
- module_line = re.match("MODULE [^ ]+ [^ ]+ ([0-9A-F]+) (.*)\n", syms) |
- output_path = os.path.join(options.symbols_dir, module_line.group(2), |
- module_line.group(1)) |
- mkdir_p(output_path) |
- symbol_file = "%s.sym" % module_line.group(2) |
- try: |
- f = open(os.path.join(output_path, symbol_file), 'w') |
- f.write(syms) |
- f.close() |
- except Exception, e: |
- # Not much we can do about this. |
- with print_lock: |
- print e |
- |
- queue.task_done() |
- |
- for binary in binaries: |
- queue.put(binary) |
- |
- for _ in range(options.jobs): |
- t = threading.Thread(target=_Worker) |
- t.daemon = True |
- t.start() |
- |
- queue.join() |
- |
- |
-def main(): |
- parser = optparse.OptionParser() |
- parser.add_option('', '--build-dir', default='', |
- help='The build output directory.') |
- parser.add_option('', '--symbols-dir', default='', |
- help='The directory where to write the symbols file.') |
- parser.add_option('', '--binary', default='', |
- help='The path of the binary to generate symbols for.') |
- parser.add_option('', '--clear', default=False, action='store_true', |
- help='Clear the symbols directory before writing new ' |
- 'symbols.') |
- parser.add_option('-j', '--jobs', default=CONCURRENT_TASKS, action='store', |
- type='int', help='Number of parallel tasks to run.') |
- parser.add_option('-v', '--verbose', action='store_true', |
- help='Print verbose status output.') |
- |
- (options, _) = parser.parse_args() |
- |
- if not options.symbols_dir: |
- print "Required option --symbols-dir missing." |
- return 1 |
- |
- if not options.build_dir: |
- print "Required option --build-dir missing." |
- return 1 |
- |
- if not options.binary: |
- print "Required option --binary missing." |
- return 1 |
- |
- if not os.access(options.binary, os.X_OK): |
- print "Cannot find %s." % options.binary |
- return 1 |
- |
- if options.clear: |
- try: |
- shutil.rmtree(options.symbols_dir) |
- except: |
- pass |
- |
- if not GetDumpSymsBinary(options.build_dir): |
- return 1 |
- |
- # Build the transitive closure of all dependencies. |
- binaries = set([options.binary]) |
- queue = [options.binary] |
- exe_path = os.path.dirname(options.binary) |
- while queue: |
- deps = GetSharedLibraryDependencies(options, queue.pop(0), exe_path) |
- new_deps = set(deps) - binaries |
- binaries |= new_deps |
- queue.extend(list(new_deps)) |
- |
- GenerateSymbols(options, binaries) |
- |
- return 0 |
- |
- |
-if '__main__' == __name__: |
- sys.exit(main()) |