Update generate_breakpad_symbols.py for python 3
After https://chromium.googlesource.com/chromium/src/+/refs/heads/main/components/crash/content/tools/generate_breakpad_symbols.py
This commit is contained in:
parent
f4bee8e269
commit
08cad29118
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# 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.
|
||||
|
@ -18,15 +18,19 @@ import glob
|
|||
import multiprocessing
|
||||
import optparse
|
||||
import os
|
||||
import Queue
|
||||
import queue
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import threading
|
||||
|
||||
import traceback
|
||||
|
||||
CONCURRENT_TASKS=multiprocessing.cpu_count()
|
||||
if sys.platform == 'win32':
|
||||
# TODO(crbug.com/1190269) - we can't use more than 56
|
||||
# cores on Windows or Python3 may hang.
|
||||
CONCURRENT_TASKS = min(CONCURRENT_TASKS, 56)
|
||||
|
||||
# The BINARY_INFO tuple describes a binary as dump_syms identifies it.
|
||||
BINARY_INFO = collections.namedtuple('BINARY_INFO',
|
||||
|
@ -38,7 +42,7 @@ def GetDumpSymsBinary(build_dir=None):
|
|||
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
|
||||
print('Cannot find %s.' % dump_syms_bin)
|
||||
return None
|
||||
|
||||
return dump_syms_bin
|
||||
|
@ -67,7 +71,7 @@ def GetSharedLibraryDependenciesLinux(binary):
|
|||
"""Return absolute paths to all shared library dependencies of the binary.
|
||||
|
||||
This implementation assumes that we're running on a Linux system."""
|
||||
ldd = subprocess.check_output(['ldd', binary])
|
||||
ldd = subprocess.check_output(['ldd', binary]).decode('utf-8')
|
||||
lib_re = re.compile('\t.* => (.+) \(.*\)$')
|
||||
result = []
|
||||
for line in ldd.splitlines():
|
||||
|
@ -85,7 +89,7 @@ def _GetSharedLibraryDependenciesAndroidOrChromeOS(binary):
|
|||
readelf plays nice with mixed host/device architectures (e.g. x86-64 host,
|
||||
arm64 device), so use that.
|
||||
"""
|
||||
readelf = subprocess.check_output(['readelf', '-d', binary])
|
||||
readelf = subprocess.check_output(['readelf', '-d', binary]).decode('utf-8')
|
||||
lib_re = re.compile('Shared library: \[(.+)\]$')
|
||||
result = []
|
||||
binary_path = os.path.dirname(os.path.abspath(binary))
|
||||
|
@ -120,7 +124,7 @@ def GetDeveloperDirMac():
|
|||
if 'DEVELOPER_DIR' in os.environ:
|
||||
candidate_paths.append(os.environ['DEVELOPER_DIR'])
|
||||
candidate_paths.extend([
|
||||
subprocess.check_output(['xcode-select', '-p']).strip(),
|
||||
subprocess.check_output(['xcode-select', '-p']).decode('utf-8').strip(),
|
||||
# Most Mac 10.1[0-2] bots have at least one Xcode installed.
|
||||
'/Applications/Xcode.app',
|
||||
'/Applications/Xcode9.0.app',
|
||||
|
@ -132,7 +136,7 @@ def GetDeveloperDirMac():
|
|||
for path in candidate_paths:
|
||||
if os.path.exists(path):
|
||||
return path
|
||||
print 'WARNING: no value found for DEVELOPER_DIR. Some commands may fail.'
|
||||
print('WARNING: no value found for DEVELOPER_DIR. Some commands may fail.')
|
||||
|
||||
|
||||
def GetSharedLibraryDependenciesMac(binary, exe_path):
|
||||
|
@ -164,7 +168,7 @@ def GetSharedLibraryDependenciesMac(binary, exe_path):
|
|||
otool_path = 'otool'
|
||||
|
||||
otool = subprocess.check_output(
|
||||
[otool_path, '-l', binary], env=env).splitlines()
|
||||
[otool_path, '-lm', binary], env=env).decode('utf-8').splitlines()
|
||||
rpaths = []
|
||||
dylib_id = None
|
||||
for idx, line in enumerate(otool):
|
||||
|
@ -184,7 +188,7 @@ def GetSharedLibraryDependenciesMac(binary, exe_path):
|
|||
# the loading executables.
|
||||
|
||||
otool = subprocess.check_output(
|
||||
[otool_path, '-L', binary], env=env).splitlines()
|
||||
[otool_path, '-Lm', binary], env=env).decode('utf-8').splitlines()
|
||||
lib_re = re.compile('\t(.*) \(compatibility .*\)$')
|
||||
deps = []
|
||||
for line in otool:
|
||||
|
@ -198,10 +202,10 @@ def GetSharedLibraryDependenciesMac(binary, exe_path):
|
|||
if dep:
|
||||
deps.append(os.path.normpath(dep))
|
||||
else:
|
||||
print >>sys.stderr, (
|
||||
print((
|
||||
'ERROR: failed to resolve %s, exe_path %s, loader_path %s, '
|
||||
'rpaths %s' % (m.group(1), exe_path, loader_path,
|
||||
', '.join(rpaths)))
|
||||
', '.join(rpaths))), file=sys.stderr)
|
||||
sys.exit(1)
|
||||
return deps
|
||||
|
||||
|
@ -217,7 +221,7 @@ def GetSharedLibraryDependenciesChromeOS(binary):
|
|||
def GetSharedLibraryDependencies(options, binary, exe_path):
|
||||
"""Return absolute paths to all shared library dependencies of the binary."""
|
||||
deps = []
|
||||
if options.platform == 'linux2':
|
||||
if options.platform == 'linux':
|
||||
deps = GetSharedLibraryDependenciesLinux(binary)
|
||||
elif options.platform == 'android':
|
||||
deps = GetSharedLibraryDependenciesAndroid(binary)
|
||||
|
@ -226,7 +230,7 @@ def GetSharedLibraryDependencies(options, binary, exe_path):
|
|||
elif options.platform == 'chromeos':
|
||||
deps = GetSharedLibraryDependenciesChromeOS(binary)
|
||||
else:
|
||||
print "Platform not supported."
|
||||
print("Platform not supported.")
|
||||
sys.exit(1)
|
||||
|
||||
result = []
|
||||
|
@ -243,7 +247,7 @@ def GetTransitiveDependencies(options):
|
|||
dependencies of the binary, along with the binary itself."""
|
||||
binary = os.path.abspath(options.binary)
|
||||
exe_path = os.path.dirname(binary)
|
||||
if options.platform == 'linux2':
|
||||
if options.platform == 'linux':
|
||||
# 'ldd' returns all transitive dependencies for us.
|
||||
deps = set(GetSharedLibraryDependencies(options, binary, exe_path))
|
||||
deps.add(binary)
|
||||
|
@ -251,14 +255,14 @@ def GetTransitiveDependencies(options):
|
|||
elif (options.platform == 'darwin' or options.platform == 'android' or
|
||||
options.platform == 'chromeos'):
|
||||
binaries = set([binary])
|
||||
queue = [binary]
|
||||
while queue:
|
||||
deps = GetSharedLibraryDependencies(options, queue.pop(0), exe_path)
|
||||
q = [binary]
|
||||
while q:
|
||||
deps = GetSharedLibraryDependencies(options, q.pop(0), exe_path)
|
||||
new_deps = set(deps) - binaries
|
||||
binaries |= new_deps
|
||||
queue.extend(list(new_deps))
|
||||
q.extend(list(new_deps))
|
||||
return binaries
|
||||
print "Platform not supported."
|
||||
print("Platform not supported.")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
|
@ -285,7 +289,7 @@ def CreateSymbolDir(options, output_dir, relative_hash_dir):
|
|||
"""Create the directory to store breakpad symbols in. On Android/Linux, we
|
||||
also create a symlink in case the hash in the binary is missing."""
|
||||
mkdir_p(output_dir)
|
||||
if options.platform == 'android' or options.platform == "linux2":
|
||||
if options.platform == 'android' or options.platform == 'linux':
|
||||
try:
|
||||
os.symlink(relative_hash_dir, os.path.join(os.path.dirname(output_dir),
|
||||
'000000000000000000000000000000000'))
|
||||
|
@ -296,84 +300,91 @@ def CreateSymbolDir(options, output_dir, relative_hash_dir):
|
|||
def GenerateSymbols(options, binaries):
|
||||
"""Dumps the symbols of binary and places them in the given directory."""
|
||||
|
||||
queue = Queue.Queue()
|
||||
q = queue.Queue()
|
||||
exceptions = []
|
||||
print_lock = threading.Lock()
|
||||
exceptions_lock = threading.Lock()
|
||||
|
||||
def _Worker():
|
||||
dump_syms = options.dumpsyms_bin
|
||||
while True:
|
||||
should_dump_syms = True
|
||||
reason = "no reason"
|
||||
binary = queue.get()
|
||||
try:
|
||||
should_dump_syms = True
|
||||
reason = "no reason"
|
||||
binary = q.get()
|
||||
|
||||
run_once = True
|
||||
while run_once:
|
||||
run_once = False
|
||||
run_once = True
|
||||
while run_once:
|
||||
run_once = False
|
||||
|
||||
if not dump_syms:
|
||||
should_dump_syms = False
|
||||
reason = "Could not locate dump_syms executable."
|
||||
break
|
||||
|
||||
binary_info = GetBinaryInfoFromHeaderInfo(
|
||||
subprocess.check_output([dump_syms, '-i', binary]).splitlines()[0])
|
||||
if not binary_info:
|
||||
should_dump_syms = False
|
||||
reason = "Could not obtain binary information."
|
||||
break
|
||||
|
||||
# See if the output file already exists.
|
||||
output_dir = os.path.join(options.symbols_dir, binary_info.name,
|
||||
binary_info.hash)
|
||||
output_path = os.path.join(output_dir, binary_info.name + '.sym')
|
||||
if os.path.isfile(output_path):
|
||||
should_dump_syms = False
|
||||
reason = "Symbol file already found."
|
||||
break
|
||||
|
||||
# See if there is a symbol file already found next to the binary
|
||||
potential_symbol_files = glob.glob('%s.breakpad*' % binary)
|
||||
for potential_symbol_file in potential_symbol_files:
|
||||
with open(potential_symbol_file, 'rt') as f:
|
||||
symbol_info = GetBinaryInfoFromHeaderInfo(f.readline())
|
||||
if symbol_info == binary_info:
|
||||
CreateSymbolDir(options, output_dir, binary_info.hash)
|
||||
shutil.copyfile(potential_symbol_file, output_path)
|
||||
if not dump_syms:
|
||||
should_dump_syms = False
|
||||
reason = "Found local symbol file."
|
||||
reason = "Could not locate dump_syms executable."
|
||||
break
|
||||
|
||||
if not should_dump_syms:
|
||||
dump_syms_output = subprocess.check_output(
|
||||
[dump_syms, '-i', binary]).decode('utf-8')
|
||||
header_info = dump_syms_output.splitlines()[0]
|
||||
binary_info = GetBinaryInfoFromHeaderInfo(header_info)
|
||||
if not binary_info:
|
||||
should_dump_syms = False
|
||||
reason = "Could not obtain binary information."
|
||||
break
|
||||
|
||||
# See if the output file already exists.
|
||||
output_dir = os.path.join(options.symbols_dir, binary_info.name,
|
||||
binary_info.hash)
|
||||
output_path = os.path.join(output_dir, binary_info.name + '.sym')
|
||||
if os.path.isfile(output_path):
|
||||
should_dump_syms = False
|
||||
reason = "Symbol file already found."
|
||||
break
|
||||
|
||||
# See if there is a symbol file already found next to the binary
|
||||
potential_symbol_files = glob.glob('%s.breakpad*' % binary)
|
||||
for potential_symbol_file in potential_symbol_files:
|
||||
with open(potential_symbol_file, 'rt') as f:
|
||||
symbol_info = GetBinaryInfoFromHeaderInfo(f.readline())
|
||||
if symbol_info == binary_info:
|
||||
CreateSymbolDir(options, output_dir, binary_info.hash)
|
||||
shutil.copyfile(potential_symbol_file, output_path)
|
||||
should_dump_syms = False
|
||||
reason = "Found local symbol file."
|
||||
break
|
||||
|
||||
if not should_dump_syms:
|
||||
if options.verbose:
|
||||
with print_lock:
|
||||
print("Skipping %s (%s)" % (binary, reason))
|
||||
continue
|
||||
|
||||
if options.verbose:
|
||||
with print_lock:
|
||||
print "Skipping %s (%s)" % (binary, reason)
|
||||
queue.task_done()
|
||||
continue
|
||||
print("Generating symbols for %s" % binary)
|
||||
|
||||
if options.verbose:
|
||||
with print_lock:
|
||||
print "Generating symbols for %s" % binary
|
||||
|
||||
CreateSymbolDir(options, output_dir, binary_info.hash)
|
||||
try:
|
||||
CreateSymbolDir(options, output_dir, binary_info.hash)
|
||||
with open(output_path, 'wb') as f:
|
||||
subprocess.check_call([dump_syms, '-r', binary], stdout=f)
|
||||
except Exception, e:
|
||||
# Not much we can do about this.
|
||||
with print_lock:
|
||||
print e
|
||||
|
||||
queue.task_done()
|
||||
except Exception as e:
|
||||
with exceptions_lock:
|
||||
exceptions.append(traceback.format_exc())
|
||||
finally:
|
||||
q.task_done()
|
||||
|
||||
for binary in binaries:
|
||||
queue.put(binary)
|
||||
q.put(binary)
|
||||
|
||||
for _ in range(options.jobs):
|
||||
t = threading.Thread(target=_Worker)
|
||||
t.daemon = True
|
||||
t.start()
|
||||
|
||||
queue.join()
|
||||
q.join()
|
||||
if exceptions:
|
||||
exception_str = ('One or more exceptions occurred while generating '
|
||||
'symbols:\n')
|
||||
exception_str += '\n'.join(exceptions)
|
||||
raise Exception(exception_str)
|
||||
|
||||
|
||||
def main():
|
||||
|
@ -399,23 +410,23 @@ def main():
|
|||
(options, _) = parser.parse_args()
|
||||
|
||||
if not options.dumpsyms_bin:
|
||||
print "Required option --dumpsyms-bin missing."
|
||||
print("Required option --dumpsyms-bin missing.")
|
||||
return 1
|
||||
|
||||
if not options.symbols_dir:
|
||||
print "Required option --symbols-dir missing."
|
||||
print("Required option --symbols-dir missing.")
|
||||
return 1
|
||||
|
||||
if not options.build_dir:
|
||||
print "Required option --build-dir missing."
|
||||
print("Required option --build-dir missing.")
|
||||
return 1
|
||||
|
||||
if not options.binary:
|
||||
print "Required option --binary missing."
|
||||
print("Required option --binary missing.")
|
||||
return 1
|
||||
|
||||
if not os.access(options.binary, os.X_OK):
|
||||
print "Cannot find %s" % options.binary
|
||||
print("Cannot find %s." % options.binary)
|
||||
return 1
|
||||
|
||||
if options.clear:
|
||||
|
|
Loading…
Reference in New Issue