aboutsummaryrefslogtreecommitdiff
path: root/contrib
diff options
context:
space:
mode:
authorfanquake <fanquake@gmail.com>2021-07-02 14:22:04 +0800
committerfanquake <fanquake@gmail.com>2021-10-12 08:36:15 +0800
commit309eac9019c224dfd79a78e381cfcb70fee190f3 (patch)
treeac28e7425c940665d738c3a42320cf5cb1ad08ad /contrib
parent610a8a8e39c1d94839dfb7e1c66c01f13f946657 (diff)
downloadbitcoin-309eac9019c224dfd79a78e381cfcb70fee190f3.tar.xz
scripts: use LIEF for ELF checks in symbol-check.py
Co-authored-by: Carl Dong <contact@carldong.me>
Diffstat (limited to 'contrib')
-rwxr-xr-xcontrib/devtools/symbol-check.py89
-rwxr-xr-xcontrib/devtools/test-symbol-check.py4
2 files changed, 36 insertions, 57 deletions
diff --git a/contrib/devtools/symbol-check.py b/contrib/devtools/symbol-check.py
index 98cab1b7fc..36ac6faa81 100755
--- a/contrib/devtools/symbol-check.py
+++ b/contrib/devtools/symbol-check.py
@@ -10,14 +10,14 @@ Example usage:
find ../path/to/binaries -type f -executable | xargs python3 contrib/devtools/symbol-check.py
'''
-import subprocess
import sys
from typing import List, Optional
import lief
-import pixie
-from utils import determine_wellknown_cmd
+# temporary constant, to be replaced with lief.ELF.ARCH.RISCV
+# https://github.com/lief-project/LIEF/pull/562
+LIEF_ELF_ARCH_RISCV = lief.ELF.ARCH(243)
# Debian 8 (Jessie) EOL: 2020. https://wiki.debian.org/DebianReleases#Production_Releases
#
@@ -43,12 +43,12 @@ from utils import determine_wellknown_cmd
MAX_VERSIONS = {
'GCC': (4,8,0),
'GLIBC': {
- pixie.EM_386: (2,17),
- pixie.EM_X86_64: (2,17),
- pixie.EM_ARM: (2,17),
- pixie.EM_AARCH64:(2,17),
- pixie.EM_PPC64: (2,17),
- pixie.EM_RISCV: (2,27),
+ lief.ELF.ARCH.i386: (2,17),
+ lief.ELF.ARCH.x86_64: (2,17),
+ lief.ELF.ARCH.ARM: (2,17),
+ lief.ELF.ARCH.AARCH64:(2,17),
+ lief.ELF.ARCH.PPC64: (2,17),
+ LIEF_ELF_ARCH_RISCV: (2,27),
},
'LIBATOMIC': (1,0),
'V': (0,5,0), # xkb (bitcoin-qt only)
@@ -58,7 +58,8 @@ MAX_VERSIONS = {
# Ignore symbols that are exported as part of every executable
IGNORE_EXPORTS = {
-'_edata', '_end', '__end__', '_init', '__bss_start', '__bss_start__', '_bss_end__', '__bss_end__', '_fini', '_IO_stdin_used', 'stdin', 'stdout', 'stderr',
+'_edata', '_end', '__end__', '_init', '__bss_start', '__bss_start__', '_bss_end__',
+'__bss_end__', '_fini', '_IO_stdin_used', 'stdin', 'stdout', 'stderr',
'environ', '_environ', '__environ',
}
@@ -133,31 +134,8 @@ PE_ALLOWED_LIBRARIES = {
'WTSAPI32.dll',
}
-class CPPFilt(object):
- '''
- Demangle C++ symbol names.
-
- Use a pipe to the 'c++filt' command.
- '''
- def __init__(self):
- self.proc = subprocess.Popen(determine_wellknown_cmd('CPPFILT', 'c++filt'), stdin=subprocess.PIPE, stdout=subprocess.PIPE, universal_newlines=True)
-
- def __call__(self, mangled):
- self.proc.stdin.write(mangled + '\n')
- self.proc.stdin.flush()
- return self.proc.stdout.readline().rstrip()
-
- def close(self):
- self.proc.stdin.close()
- self.proc.stdout.close()
- self.proc.wait()
-
def check_version(max_versions, version, arch) -> bool:
- if '_' in version:
- (lib, _, ver) = version.rpartition('_')
- else:
- lib = version
- ver = '0'
+ (lib, _, ver) = version.rpartition('_')
ver = tuple([int(x) for x in ver.split('.')])
if not lib in max_versions:
return False
@@ -167,41 +145,42 @@ def check_version(max_versions, version, arch) -> bool:
return ver <= max_versions[lib][arch]
def check_imported_symbols(filename) -> bool:
- elf = pixie.load(filename)
- cppfilt = CPPFilt()
ok: bool = True
+ binary = lief.parse(filename)
- for symbol in elf.dyn_symbols:
- if not symbol.is_import:
+ for symbol in binary.imported_symbols:
+ if not symbol.imported:
continue
- sym = symbol.name.decode()
- version = symbol.version.decode() if symbol.version is not None else None
- if version and not check_version(MAX_VERSIONS, version, elf.hdr.e_machine):
- print('{}: symbol {} from unsupported version {}'.format(filename, cppfilt(sym), version))
- ok = False
+
+ version = symbol.symbol_version if symbol.has_version else None
+
+ if version:
+ aux_version = version.symbol_version_auxiliary.name if version.has_auxiliary_version else None
+ if aux_version and not check_version(MAX_VERSIONS, aux_version, binary.header.machine_type):
+ print(f'{filename}: symbol {symbol.name} from unsupported version {version}')
+ ok = False
return ok
def check_exported_symbols(filename) -> bool:
- elf = pixie.load(filename)
- cppfilt = CPPFilt()
ok: bool = True
- for symbol in elf.dyn_symbols:
- if not symbol.is_export:
+ binary = lief.parse(filename)
+
+ for symbol in binary.dynamic_symbols:
+ if not symbol.exported:
continue
- sym = symbol.name.decode()
- if elf.hdr.e_machine == pixie.EM_RISCV or sym in IGNORE_EXPORTS:
+ name = symbol.name
+ if binary.header.machine_type == LIEF_ELF_ARCH_RISCV or name in IGNORE_EXPORTS:
continue
- print('{}: export of symbol {} not allowed'.format(filename, cppfilt(sym)))
+ print(f'{filename}: export of symbol {name} not allowed!')
ok = False
return ok
def check_ELF_libraries(filename) -> bool:
ok: bool = True
- elf = pixie.load(filename)
- for library_name in elf.query_dyn_tags(pixie.DT_NEEDED):
- assert(isinstance(library_name, bytes))
- if library_name.decode() not in ELF_ALLOWED_LIBRARIES:
- print('{}: NEEDED library {} is not allowed'.format(filename, library_name.decode()))
+ binary = lief.parse(filename)
+ for library in binary.libraries:
+ if library not in ELF_ALLOWED_LIBRARIES:
+ print(f'{filename}: {library} is not in ALLOWED_LIBRARIES!')
ok = False
return ok
diff --git a/contrib/devtools/test-symbol-check.py b/contrib/devtools/test-symbol-check.py
index 40143f9e23..5246375fe3 100755
--- a/contrib/devtools/test-symbol-check.py
+++ b/contrib/devtools/test-symbol-check.py
@@ -60,7 +60,7 @@ class TestSymbolChecks(unittest.TestCase):
''')
self.assertEqual(call_symbol_check(cc, source, executable, ['-lm']),
- (1, executable + ': symbol nextup from unsupported version GLIBC_2.24\n' +
+ (1, executable + ': symbol nextup from unsupported version GLIBC_2.24(3)\n' +
executable + ': failed IMPORTED_SYMBOLS'))
# -lutil is part of the libc6 package so a safe bet that it's installed
@@ -79,7 +79,7 @@ class TestSymbolChecks(unittest.TestCase):
''')
self.assertEqual(call_symbol_check(cc, source, executable, ['-lutil']),
- (1, executable + ': NEEDED library libutil.so.1 is not allowed\n' +
+ (1, executable + ': libutil.so.1 is not in ALLOWED_LIBRARIES!\n' +
executable + ': failed LIBRARY_DEPENDENCIES'))
# finally, check a simple conforming binary