[contrib] fixup symbol-check.py Python3 support

This commit is contained in:
John Newbery 2018-03-28 16:58:42 -04:00
parent 5de2b18c67
commit f50975b136

View File

@ -46,28 +46,28 @@ MAX_VERSIONS = {
# Ignore symbols that are exported as part of every executable # Ignore symbols that are exported as part of every executable
IGNORE_EXPORTS = { IGNORE_EXPORTS = {
b'_edata', b'_end', b'_init', b'__bss_start', b'_fini', b'_IO_stdin_used' '_edata', '_end', '_init', '__bss_start', '_fini', '_IO_stdin_used'
} }
READELF_CMD = os.getenv('READELF', '/usr/bin/readelf') READELF_CMD = os.getenv('READELF', '/usr/bin/readelf')
CPPFILT_CMD = os.getenv('CPPFILT', '/usr/bin/c++filt') CPPFILT_CMD = os.getenv('CPPFILT', '/usr/bin/c++filt')
# Allowed NEEDED libraries # Allowed NEEDED libraries
ALLOWED_LIBRARIES = { ALLOWED_LIBRARIES = {
# bitcoind and bitcoin-qt # bitcoind and bitcoin-qt
b'libgcc_s.so.1', # GCC base support 'libgcc_s.so.1', # GCC base support
b'libc.so.6', # C library 'libc.so.6', # C library
b'libpthread.so.0', # threading 'libpthread.so.0', # threading
b'libanl.so.1', # DNS resolve 'libanl.so.1', # DNS resolve
b'libm.so.6', # math library 'libm.so.6', # math library
b'librt.so.1', # real-time (clock) 'librt.so.1', # real-time (clock)
b'ld-linux-x86-64.so.2', # 64-bit dynamic linker 'ld-linux-x86-64.so.2', # 64-bit dynamic linker
b'ld-linux.so.2', # 32-bit dynamic linker 'ld-linux.so.2', # 32-bit dynamic linker
# bitcoin-qt only # bitcoin-qt only
b'libX11-xcb.so.1', # part of X11 'libX11-xcb.so.1', # part of X11
b'libX11.so.6', # part of X11 'libX11.so.6', # part of X11
b'libxcb.so.1', # part of X11 'libxcb.so.1', # part of X11
b'libfontconfig.so.1', # font support 'libfontconfig.so.1', # font support
b'libfreetype.so.6', # font parsing 'libfreetype.so.6', # font parsing
b'libdl.so.2' # programming interface to dynamic linker 'libdl.so.2' # programming interface to dynamic linker
} }
class CPPFilt(object): class CPPFilt(object):
@ -77,10 +77,10 @@ class CPPFilt(object):
Use a pipe to the 'c++filt' command. Use a pipe to the 'c++filt' command.
''' '''
def __init__(self): def __init__(self):
self.proc = subprocess.Popen(CPPFILT_CMD, stdin=subprocess.PIPE, stdout=subprocess.PIPE) self.proc = subprocess.Popen(CPPFILT_CMD, stdin=subprocess.PIPE, stdout=subprocess.PIPE, universal_newlines=True)
def __call__(self, mangled): def __call__(self, mangled):
self.proc.stdin.write(mangled + b'\n') self.proc.stdin.write(mangled + '\n')
self.proc.stdin.flush() self.proc.stdin.flush()
return self.proc.stdout.readline().rstrip() return self.proc.stdout.readline().rstrip()
@ -94,43 +94,43 @@ def read_symbols(executable, imports=True):
Parse an ELF executable and return a list of (symbol,version) tuples Parse an ELF executable and return a list of (symbol,version) tuples
for dynamic, imported symbols. for dynamic, imported symbols.
''' '''
p = subprocess.Popen([READELF_CMD, '--dyn-syms', '-W', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) p = subprocess.Popen([READELF_CMD, '--dyn-syms', '-W', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True)
(stdout, stderr) = p.communicate() (stdout, stderr) = p.communicate()
if p.returncode: if p.returncode:
raise IOError('Could not read symbols for %s: %s' % (executable, stderr.strip())) raise IOError('Could not read symbols for %s: %s' % (executable, stderr.strip()))
syms = [] syms = []
for line in stdout.split(b'\n'): for line in stdout.splitlines():
line = line.split() line = line.split()
if len(line)>7 and re.match(b'[0-9]+:$', line[0]): if len(line)>7 and re.match('[0-9]+:$', line[0]):
(sym, _, version) = line[7].partition(b'@') (sym, _, version) = line[7].partition('@')
is_import = line[6] == b'UND' is_import = line[6] == 'UND'
if version.startswith(b'@'): if version.startswith('@'):
version = version[1:] version = version[1:]
if is_import == imports: if is_import == imports:
syms.append((sym, version)) syms.append((sym, version))
return syms return syms
def check_version(max_versions, version): def check_version(max_versions, version):
if b'_' in version: if '_' in version:
(lib, _, ver) = version.rpartition(b'_') (lib, _, ver) = version.rpartition('_')
else: else:
lib = version lib = version
ver = '0' ver = '0'
ver = tuple([int(x) for x in ver.split(b'.')]) ver = tuple([int(x) for x in ver.split('.')])
if not lib in max_versions: if not lib in max_versions:
return False return False
return ver <= max_versions[lib] return ver <= max_versions[lib]
def read_libraries(filename): def read_libraries(filename):
p = subprocess.Popen([READELF_CMD, '-d', '-W', filename], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) p = subprocess.Popen([READELF_CMD, '-d', '-W', filename], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True)
(stdout, stderr) = p.communicate() (stdout, stderr) = p.communicate()
if p.returncode: if p.returncode:
raise IOError('Error opening file') raise IOError('Error opening file')
libraries = [] libraries = []
for line in stdout.split(b'\n'): for line in stdout.splitlines():
tokens = line.split() tokens = line.split()
if len(tokens)>2 and tokens[1] == b'(NEEDED)': if len(tokens)>2 and tokens[1] == '(NEEDED)':
match = re.match(b'^Shared library: \[(.*)\]$', b' '.join(tokens[2:])) match = re.match('^Shared library: \[(.*)\]$', ' '.join(tokens[2:]))
if match: if match:
libraries.append(match.group(1)) libraries.append(match.group(1))
else: else:
@ -144,18 +144,18 @@ if __name__ == '__main__':
# Check imported symbols # Check imported symbols
for sym,version in read_symbols(filename, True): for sym,version in read_symbols(filename, True):
if version and not check_version(MAX_VERSIONS, version): if version and not check_version(MAX_VERSIONS, version):
print('%s: symbol %s from unsupported version %s' % (filename, cppfilt(sym).decode('utf-8'), version.decode('utf-8'))) print('%s: symbol %s from unsupported version %s' % (filename, cppfilt(sym), version))
retval = 1 retval = 1
# Check exported symbols # Check exported symbols
for sym,version in read_symbols(filename, False): for sym,version in read_symbols(filename, False):
if sym in IGNORE_EXPORTS: if sym in IGNORE_EXPORTS:
continue continue
print('%s: export of symbol %s not allowed' % (filename, cppfilt(sym).decode('utf-8'))) print('%s: export of symbol %s not allowed' % (filename, cppfilt(sym)))
retval = 1 retval = 1
# Check dependency libraries # Check dependency libraries
for library_name in read_libraries(filename): for library_name in read_libraries(filename):
if library_name not in ALLOWED_LIBRARIES: if library_name not in ALLOWED_LIBRARIES:
print('%s: NEEDED library %s is not allowed' % (filename, library_name.decode('utf-8'))) print('%s: NEEDED library %s is not allowed' % (filename, library_name))
retval = 1 retval = 1
sys.exit(retval) sys.exit(retval)