Skip to content

Commit

Permalink
feat: experimental undefined symbol tracer
Browse files Browse the repository at this point in the history
  • Loading branch information
vibhatha committed Mar 14, 2024
1 parent d7a3f6d commit 090275e
Showing 1 changed file with 40 additions and 0 deletions.
40 changes: 40 additions & 0 deletions dev/archery/archery/linking.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,16 @@
# under the License.

import platform
import re
import subprocess

from .utils.command import Command


_ldd = Command("ldd")
_otool = Command("otool")
_nm = Command("nm")
_ldconfig = Command('ldconfig')


class DependencyError(Exception):
Expand Down Expand Up @@ -61,9 +64,32 @@ def list_dependency_names(self):
names.append(name)
return names

def list_symbols_for_dependency(self, dependency):
result = _nm.run('--format=just-symbols', '-D', dependency, stdout=subprocess.PIPE)
lines = result.stdout.decode('utf-8').splitlines()
return lines

def list_undefined_symbols_for_dependency(self, dependency):
result = _nm.run('--format=just-symbols', '-u', dependency, stdout=subprocess.PIPE)
lines = result.stdout.decode('utf-8').splitlines()
return lines

def find_library_paths(self, libraries):
result = _ldconfig.run('-p', stdout=subprocess.PIPE)
lines = result.stdout.decode('utf-8').splitlines()
paths = {}
for lib in libraries:
for line in lines:
if lib in line:
match = re.search(r' => (.*)', line)
if match:
paths[lib] = match.group(1)
return paths


def check_dynamic_library_dependencies(path, allowed, disallowed):
dylib = DynamicLibrary(path)

for dep in dylib.list_dependency_names():
if allowed and dep not in allowed:
raise DependencyError(
Expand All @@ -73,3 +99,17 @@ def check_dynamic_library_dependencies(path, allowed, disallowed):
raise DependencyError(
f"Disallowed shared dependency found in {dylib.path}: `{dep}`"
)
# Check for undefined symbols
undefined_symbols = dylib.list_undefined_symbols_for_dependency(path)
expected_lib_paths = dylib.find_library_paths(allowed)
for lb_path in expected_lib_paths.values():
expected_symbols = dylib.list_symbols_for_dependency(lb_path)
for exp_sym in expected_symbols:
if exp_sym in undefined_symbols:
undefined_symbols.remove(exp_sym)

if undefined_symbols:
undefined_symbols_str = '\n'.join(undefined_symbols)
raise DependencyError(
f"Undefined symbols found in {dylib.path}:\n{undefined_symbols_str}"
)

0 comments on commit 090275e

Please sign in to comment.