Skip to content

Commit 6e6aa49

Browse files
committed
Add contrib/symbol-check.py
1 parent 694ce8f commit 6e6aa49

File tree

1 file changed

+118
-0
lines changed

1 file changed

+118
-0
lines changed

tools/symbol-check.py

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
#!/usr/bin/env python3
2+
# Copyright (c) 2014 Wladimir J. van der Laan
3+
# Distributed under the MIT software license, see the accompanying
4+
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
'''
6+
A script to check that a secp256k1 shared library
7+
exports only expected symbols.
8+
9+
Example usage:
10+
11+
./tools/symbol-check.py .libs/libsecp256k1.so.0.0.0
12+
or
13+
./tools/symbol-check.py .libs/libsecp256k1-0.dll
14+
or
15+
./tools/symbol-check.py .libs/libsecp256k1.0.dylib
16+
'''
17+
import re
18+
import sys
19+
import subprocess
20+
from typing import List
21+
22+
import lief #type:ignore
23+
24+
def grep_exported_symbols() -> List[str]:
25+
grep_output = subprocess.check_output(["git", "grep", "^SECP256K1_API", "--", "include"], universal_newlines=True, encoding="utf8")
26+
lines = grep_output.split("\n")
27+
exports: List[str] = []
28+
for line in lines:
29+
if line.strip():
30+
function_name = re.sub(r'\W', '', line.split(" ")[-1])
31+
exports.append(function_name)
32+
return exports
33+
34+
def check_ELF_exported_symbols(library, expected_exports) -> bool:
35+
ok: bool = True
36+
elf_lib: lief.ELF.Binary = library.concrete
37+
38+
for symbol in elf_lib.exported_symbols:
39+
name: str = symbol.name
40+
if name in expected_exports:
41+
continue
42+
print(f'{filename}: export of symbol {name} not expected')
43+
ok = False
44+
return ok
45+
46+
def check_PE_exported_functions(library, expected_exports) -> bool:
47+
ok: bool = True
48+
pe_lib: lief.PE.Binary = library.concrete
49+
50+
for function in pe_lib.exported_functions:
51+
name: str = function.name
52+
if name in expected_exports:
53+
continue
54+
print(f'{filename}: export of function {name} not expected')
55+
ok = False
56+
return ok
57+
58+
def check_MACHO_exported_functions(library, expected_exports) -> bool:
59+
ok: bool = True
60+
macho_lib: lief.MACHO.Binary = library.concrete
61+
62+
for function in macho_lib.exported_functions:
63+
name: str = function.name[1:]
64+
if name in expected_exports:
65+
continue
66+
print(f'{filename}: export of function {name} not expected')
67+
ok = False
68+
return ok
69+
70+
CHECKS = {
71+
lief.EXE_FORMATS.ELF: [
72+
('EXPORTED_SYMBOLS', check_ELF_exported_symbols),
73+
],
74+
lief.EXE_FORMATS.PE: [
75+
('EXPORTED_FUNCTIONS', check_PE_exported_functions),
76+
],
77+
lief.EXE_FORMATS.MACHO: [
78+
('EXPORTED_FUNCTIONS', check_MACHO_exported_functions),
79+
]
80+
}
81+
82+
USAGE = """
83+
symbol-check.py is a script to check that a secp256k1 shared library
84+
exports only expected symbols.
85+
86+
Usage:
87+
./tools/symbol-check.py <library>
88+
89+
"""
90+
91+
if __name__ == '__main__':
92+
if len(sys.argv) != 2:
93+
sys.exit(USAGE)
94+
95+
filename: str = sys.argv[1]
96+
try:
97+
library: lief.Binary = lief.parse(filename)
98+
exe_format: lief.EXE_FORMATS = library.format
99+
if exe_format == lief.EXE_FORMATS.UNKNOWN:
100+
print(f'{filename}: unknown executable format')
101+
sys.exit(1)
102+
103+
obj_type = library.abstract.header.object_type
104+
if obj_type != lief.OBJECT_TYPES.LIBRARY:
105+
print(f'{filename}: unsupported object type, only LIBRARY type is supported')
106+
sys.exit(1)
107+
108+
expected_exports = grep_exported_symbols()
109+
failed: List[str] = []
110+
for (name, func) in CHECKS[exe_format]:
111+
if not func(library, expected_exports):
112+
failed.append(name)
113+
if failed:
114+
print(f'{filename}: failed {" ".join(failed)}')
115+
sys.exit(1)
116+
except IOError:
117+
print(f'{filename}: cannot open')
118+
sys.exit(1)

0 commit comments

Comments
 (0)