11e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#!/usr/bin/env python
21e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)# Copyright 2013 The Chromium Authors. All rights reserved.
31e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
41e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)# found in the LICENSE file.
51e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
61e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)"""A tool to generate symbols for a binary suitable for breakpad.
71e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
81e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)Currently, the tool only supports Linux, Android, and Mac. Support for other
91e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)platforms is planned.
101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)"""
111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)import errno
131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)import optparse
141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)import os
151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)import Queue
161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)import re
171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)import shutil
181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)import subprocess
191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)import sys
201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)import threading
211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)CONCURRENT_TASKS=4
241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)def GetCommandOutput(command):
271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  """Runs the command list, returning its output.
281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  Prints the given command (which should be a list of one or more strings),
301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  then runs it and returns its output (stdout) as a string.
311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  From chromium_utils.
331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  """
341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  devnull = open(os.devnull, 'w')
351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=devnull,
361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                          bufsize=1)
371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  output = proc.communicate()[0]
381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return output
391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)def GetDumpSymsBinary(build_dir=None):
421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  """Returns the path to the dump_syms binary."""
431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  DUMP_SYMS = 'dump_syms'
441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  dump_syms_bin = os.path.join(os.path.expanduser(build_dir), DUMP_SYMS)
451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if not os.access(dump_syms_bin, os.X_OK):
461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    print 'Cannot find %s.' % DUMP_SYMS
471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    sys.exit(1)
481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return dump_syms_bin
501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)def Resolve(path, exe_path, loader_path, rpaths):
531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  """Resolve a dyld path.
541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  @executable_path is replaced with |exe_path|
561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  @loader_path is replaced with |loader_path|
571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  @rpath is replaced with the first path in |rpaths| where the referenced file
581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      is found
591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  """
601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  path = path.replace('@loader_path', loader_path)
611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  path = path.replace('@executable_path', exe_path)
621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if path.find('@rpath') != -1:
631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    for rpath in rpaths:
641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      new_path = Resolve(path.replace('@rpath', rpath), exe_path, loader_path,
651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                         [])
661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      if os.access(new_path, os.X_OK):
671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        return new_path
681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return ''
691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return path
701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)def GetSharedLibraryDependenciesLinux(binary):
731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  """Return absolute paths to all shared library dependecies of the binary.
741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  This implementation assumes that we're running on a Linux system."""
761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  ldd = GetCommandOutput(['ldd', binary])
771e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  lib_re = re.compile('\t.* => (.+) \(.*\)$')
781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  result = []
791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  for line in ldd.splitlines():
801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    m = lib_re.match(line)
811e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    if m:
821e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      result.append(m.group(1))
831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return result
841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)def GetSharedLibraryDependenciesMac(binary, exe_path):
871e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  """Return absolute paths to all shared library dependecies of the binary.
881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  This implementation assumes that we're running on a Mac system."""
901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  loader_path = os.path.dirname(binary)
911e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  otool = GetCommandOutput(['otool', '-l', binary]).splitlines()
921e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  rpaths = []
931e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  for idx, line in enumerate(otool):
941e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    if line.find('cmd LC_RPATH') != -1:
951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      m = re.match(' *path (.*) \(offset .*\)$', otool[idx+2])
961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      rpaths.append(m.group(1))
971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  otool = GetCommandOutput(['otool', '-L', binary]).splitlines()
991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  lib_re = re.compile('\t(.*) \(compatibility .*\)$')
1001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  deps = []
1011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  for line in otool:
1021e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    m = lib_re.match(line)
1031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    if m:
1041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      dep = Resolve(m.group(1), exe_path, loader_path, rpaths)
1051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      if dep:
1061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        deps.append(os.path.normpath(dep))
1071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return deps
1081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)def GetSharedLibraryDependencies(options, binary, exe_path):
1111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  """Return absolute paths to all shared library dependecies of the binary."""
1121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  deps = []
1131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if sys.platform.startswith('linux'):
1141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    deps = GetSharedLibraryDependenciesLinux(binary)
1151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  elif sys.platform == 'darwin':
1161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    deps = GetSharedLibraryDependenciesMac(binary, exe_path)
1171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  else:
1181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    print "Platform not supported."
1191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    sys.exit(1)
1201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  result = []
1221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  build_dir = os.path.abspath(options.build_dir)
1231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  for dep in deps:
1241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    if (os.access(dep, os.X_OK) and
1251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        os.path.abspath(os.path.dirname(dep)).startswith(build_dir)):
1261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      result.append(dep)
1271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return result
1281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)def mkdir_p(path):
1311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  """Simulates mkdir -p."""
1321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  try:
1331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    os.makedirs(path)
1341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  except OSError as e:
1351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    if e.errno == errno.EEXIST and os.path.isdir(path):
1361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      pass
1371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    else: raise
1381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)def GenerateSymbols(options, binaries):
1411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  """Dumps the symbols of binary and places them in the given directory."""
1421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  queue = Queue.Queue()
1440f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  print_lock = threading.Lock()
1451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  def _Worker():
1471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    while True:
1481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      binary = queue.get()
1491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      should_dump_syms = True
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      reason = "no reason"
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      output_path = os.path.join(
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          options.symbols_dir, os.path.basename(binary))
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if os.path.isdir(output_path):
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if os.path.getmtime(binary) < os.path.getmtime(output_path):
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          should_dump_syms = False
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          reason = "symbols are more current than binary"
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if not should_dump_syms:
161010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        if options.verbose:
162010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)          with print_lock:
163010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)            print "Skipping %s (%s)" % (binary, reason)
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        queue.task_done()
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        continue
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1670f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      if options.verbose:
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        with print_lock:
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          print "Generating symbols for %s" % binary
1700f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
171010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      if os.path.isdir(output_path):
172010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        os.utime(output_path, None)
173010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
1740f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      syms = GetCommandOutput([GetDumpSymsBinary(options.build_dir), '-r',
1751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                               binary])
1761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      module_line = re.match("MODULE [^ ]+ [^ ]+ ([0-9A-F]+) (.*)\n", syms)
1771e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      output_path = os.path.join(options.symbols_dir, module_line.group(2),
1781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                 module_line.group(1))
1791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      mkdir_p(output_path)
1801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      symbol_file = "%s.sym" % module_line.group(2)
181cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      try:
182cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        f = open(os.path.join(output_path, symbol_file), 'w')
183cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        f.write(syms)
184cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        f.close()
185cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      except Exception, e:
186cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        # Not much we can do about this.
187cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        with print_lock:
188cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          print e
1891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      queue.task_done()
1911e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1921e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  for binary in binaries:
1931e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    queue.put(binary)
1941e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  for _ in range(options.jobs):
1961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    t = threading.Thread(target=_Worker)
1971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    t.daemon = True
1981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    t.start()
1991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  queue.join()
2011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2021e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)def main():
2041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  parser = optparse.OptionParser()
2051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  parser.add_option('', '--build-dir', default='',
2061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                    help='The build output directory.')
2071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  parser.add_option('', '--symbols-dir', default='',
2081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                    help='The directory where to write the symbols file.')
2091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  parser.add_option('', '--binary', default='',
2101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                    help='The path of the binary to generate symbols for.')
2111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  parser.add_option('', '--clear', default=False, action='store_true',
2121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                    help='Clear the symbols directory before writing new '
2131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                         'symbols.')
2141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  parser.add_option('-j', '--jobs', default=CONCURRENT_TASKS, action='store',
2151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                    type='int', help='Number of parallel tasks to run.')
2160f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  parser.add_option('-v', '--verbose', action='store_true',
2170f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                    help='Print verbose status output.')
2181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  (options, _) = parser.parse_args()
2201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if not options.symbols_dir:
2221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    print "Required option --symbols-dir missing."
2231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return 1
2241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if not options.build_dir:
2261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    print "Required option --build-dir missing."
2271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return 1
2281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if not options.binary:
2301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    print "Required option --binary missing."
2311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return 1
2321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if not os.access(options.binary, os.X_OK):
2341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    print "Cannot find %s." % options.binary
2351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return 1
2361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if options.clear:
2381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    try:
2391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      shutil.rmtree(options.symbols_dir)
2401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    except:
2411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      pass
2421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  # Build the transitive closure of all dependencies.
2441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  binaries = set([options.binary])
2451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  queue = [options.binary]
2461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  exe_path = os.path.dirname(options.binary)
2471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  while queue:
2481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    deps = GetSharedLibraryDependencies(options, queue.pop(0), exe_path)
2491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    new_deps = set(deps) - binaries
2501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    binaries |= new_deps
2511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    queue.extend(list(new_deps))
2521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  GenerateSymbols(options, binaries)
2541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return 0
2561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)if '__main__' == __name__:
2591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  sys.exit(main())
260