Skip to content

Commit baae375

Browse files
committed
test: Add tools/symbol-check.py
1 parent 275ec53 commit baae375

File tree

1 file changed

+88
-0
lines changed

1 file changed

+88
-0
lines changed

tools/symbol-check.py

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
#!/usr/bin/env python3
2+
'''
3+
A script to check that a libsecp256k1 shared library
4+
exports only expected symbols.
5+
6+
Example usage:
7+
8+
- when building with Autotools:
9+
10+
./tools/symbol-check.py .libs/libsecp256k1.so
11+
or
12+
./tools/symbol-check.py .libs/libsecp256k1-<V>.dll
13+
or
14+
./tools/symbol-check.py .libs/libsecp256k1.dylib
15+
16+
- when building with CMake:
17+
18+
./tools/symbol-check.py build/lib/libsecp256k1.so
19+
or
20+
./tools/symbol-check.py build/bin/libsecp256k1-<V>.dll
21+
or
22+
./tools/symbol-check.py build/lib/libsecp256k1.dylib
23+
'''
24+
import re
25+
import sys
26+
import subprocess
27+
28+
import lief
29+
30+
31+
def grep_exported_symbols() -> list[str]:
32+
grep_output = subprocess.check_output(["git", "grep", r"^\s*SECP256K1_API", "--", "include"], universal_newlines=True, encoding="utf8")
33+
lines = grep_output.split("\n")
34+
exports: list[str] = []
35+
pattern = re.compile(r'\bsecp256k1_\w+')
36+
for line in lines:
37+
if line.strip():
38+
function_name = pattern.findall(line)[-1]
39+
exports.append(function_name)
40+
return exports
41+
42+
43+
def check_ELF_exported_symbols(library, expected_exports) -> bool:
44+
ok: bool = True
45+
for symbol in library.exported_symbols:
46+
name: str = symbol.name
47+
if name in expected_exports:
48+
continue
49+
print(f'{filename}: export of symbol {name} not expected')
50+
ok = False
51+
return ok
52+
53+
54+
def check_PE_exported_functions(library, expected_exports) -> bool:
55+
ok: bool = True
56+
for function in library.exported_functions:
57+
name: str = function.name
58+
if name in expected_exports:
59+
continue
60+
print(f'{filename}: export of function {name} not expected')
61+
ok = False
62+
return ok
63+
64+
65+
def check_MACHO_exported_functions(library, expected_exports) -> bool:
66+
ok: bool = True
67+
for function in library.exported_functions:
68+
name: str = function.name[1:]
69+
if name in expected_exports:
70+
continue
71+
print(f'{filename}: export of function {name} not expected')
72+
ok = False
73+
return ok
74+
75+
76+
if __name__ == '__main__':
77+
filename: str = sys.argv[1]
78+
library: lief.Binary = lief.parse(filename)
79+
exe_format: lief.Binary.FORMATS = library.format
80+
if exe_format == lief.Binary.FORMATS.ELF:
81+
success = check_ELF_exported_symbols(library, grep_exported_symbols())
82+
elif exe_format == lief.Binary.FORMATS.PE:
83+
success = check_PE_exported_functions(library, grep_exported_symbols())
84+
elif exe_format == lief.Binary.FORMATS.MACHO:
85+
success = check_MACHO_exported_functions(library, grep_exported_symbols())
86+
87+
if not success:
88+
sys.exit(1)

0 commit comments

Comments
 (0)