Skip to content

Commit 78921b1

Browse files
committed
test: Add tools/symbol-check.py
1 parent a1354fe commit 78921b1

File tree

1 file changed

+131
-0
lines changed

1 file changed

+131
-0
lines changed

tools/symbol-check.py

+131
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
#!/usr/bin/env python3
2+
'''
3+
A script to check that a secp256k1 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/src/libsecp256k1.so
19+
or
20+
./tools/symbol-check.py build/src/libsecp256k1-<V>.dll
21+
or
22+
./tools/symbol-check.py build/src/libsecp256k1.dylib
23+
'''
24+
import os
25+
import re
26+
import sys
27+
import subprocess
28+
from typing import List
29+
30+
import lief
31+
32+
def grep_exported_symbols() -> List[str]:
33+
grep_output = subprocess.check_output(["git", "grep", "^SECP256K1_API", "--", "include"], universal_newlines=True, encoding="utf8")
34+
lines = grep_output.split("\n")
35+
exports: List[str] = []
36+
pattern = re.compile(r'\bsecp256k1_\w+')
37+
for line in lines:
38+
if line.strip():
39+
function_name = pattern.findall(line)[-1]
40+
exports.append(function_name)
41+
return exports
42+
43+
def check_ELF_exported_symbols(library, expected_exports) -> bool:
44+
ok: bool = True
45+
elf_lib: lief.ELF.Binary = library.concrete
46+
47+
for symbol in elf_lib.exported_symbols:
48+
name: str = symbol.name
49+
if name in expected_exports:
50+
continue
51+
print(f'{filename}: export of symbol {name} not expected')
52+
ok = False
53+
return ok
54+
55+
def check_PE_exported_functions(library, expected_exports) -> bool:
56+
ok: bool = True
57+
pe_lib: lief.PE.Binary = library.concrete
58+
59+
for function in pe_lib.exported_functions:
60+
name: str = function.name
61+
if name in expected_exports:
62+
continue
63+
print(f'{filename}: export of function {name} not expected')
64+
ok = False
65+
return ok
66+
67+
def check_MACHO_exported_functions(library, expected_exports) -> bool:
68+
ok: bool = True
69+
macho_lib: lief.MACHO.Binary = library.concrete
70+
71+
for function in macho_lib.exported_functions:
72+
name: str = function.name[1:]
73+
if name in expected_exports:
74+
continue
75+
print(f'{filename}: export of function {name} not expected')
76+
ok = False
77+
return ok
78+
79+
CHECKS = {
80+
lief.EXE_FORMATS.ELF: [
81+
('EXPORTED_SYMBOLS', check_ELF_exported_symbols),
82+
],
83+
lief.EXE_FORMATS.PE: [
84+
('EXPORTED_FUNCTIONS', check_PE_exported_functions),
85+
],
86+
lief.EXE_FORMATS.MACHO: [
87+
('EXPORTED_FUNCTIONS', check_MACHO_exported_functions),
88+
]
89+
}
90+
91+
USAGE = """
92+
symbol-check.py is a script to check that a secp256k1 shared library
93+
exports only expected symbols.
94+
95+
Usage:
96+
./tools/symbol-check.py <library>
97+
98+
"""
99+
100+
if __name__ == '__main__':
101+
if len(sys.argv) != 2:
102+
sys.exit(USAGE)
103+
104+
filename: str = sys.argv[1]
105+
if not os.path.isfile(filename):
106+
print(f'{filename}: file does not exist')
107+
sys.exit(1)
108+
109+
try:
110+
library: lief.Binary = lief.parse(filename)
111+
exe_format: lief.EXE_FORMATS = library.format
112+
if exe_format == lief.EXE_FORMATS.UNKNOWN:
113+
print(f'{filename}: unknown executable format')
114+
sys.exit(1)
115+
116+
obj_type = library.abstract.header.object_type
117+
if obj_type != lief.OBJECT_TYPES.LIBRARY:
118+
print(f'{filename}: unsupported object type, only LIBRARY type is supported')
119+
sys.exit(1)
120+
121+
expected_exports = grep_exported_symbols()
122+
failed: List[str] = []
123+
for (name, func) in CHECKS[exe_format]:
124+
if not func(library, expected_exports):
125+
failed.append(name)
126+
if failed:
127+
print(f'{filename}: failed {" ".join(failed)}')
128+
sys.exit(1)
129+
except IOError:
130+
print(f'{filename}: cannot open')
131+
sys.exit(1)

0 commit comments

Comments
 (0)