-
-
Save dreness/390ce576ac754f07b4f8c0616381fd7c to your computer and use it in GitHub Desktop.
Automatic symbol definition discovery for OS X binaries and their linked shared libraries
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
"""Usage: symfind BINARY_PATH SEARCH_STR | |
symfind automates the usage of otool and nm to attempt to find out which | |
binary a symbol is defined in that's used within BINARY_PATH's code. | |
""" | |
import subprocess, os.path, sys, getopt | |
def find_symbol(binary_path, symbol_str): | |
print "At path: {}".format(binary_path) | |
# Check the binary itself first | |
symbols_raw = subprocess.check_output(['/usr/bin/nm', '-a', binary_path]) | |
symbols = [x for x in symbols_raw.splitlines() if not ' u ' in x.lower()] | |
symbols = [x for x in symbols if symbol_str.lower() in x.lower()] | |
if symbols: | |
print "\nFOUND:", binary_path | |
for x in symbols: | |
print x | |
# Root linked images | |
root_images_raw = subprocess.check_output(['/usr/bin/otool', '-L', binary_path]) | |
root_images = [x for x in root_images_raw.splitlines() if x[0] == '\t'] | |
root_images = [x for x in root_images if ' (compatibility version' in x] | |
root_images = [x.split('\t',1)[-1].split(' (compatibility version', 1)[0] for x in root_images] | |
for image in root_images: | |
# normalize @rpath and @executable_path linkage to an absolute path | |
if "@rpath" in image: | |
rPathPrefix = binary_path.partition(image.split("/")[1])[0] | |
image = image.replace("@rpath", rPathPrefix) | |
if "@executable_path" in image: | |
image = image.replace("@executable_path", os.path.dirname(binary_path)) | |
symbols_raw = subprocess.check_output(['/usr/bin/nm', '-a', image]) | |
symbols = [x for x in symbols_raw.splitlines() if not ' u ' in x.lower()] | |
symbols = [x for x in symbols if symbol_str.lower() in x.lower()] | |
if symbols: | |
print "\nFOUND:", image | |
for x in symbols: | |
print x | |
def usage(): | |
print __doc__ | |
sys.exit() | |
def main(): | |
try: | |
opts, args = getopt.getopt(sys.argv[1:], "h", ["help"]) | |
except getopt.GetoptError, err: | |
print str(err) | |
usage() | |
for o, a in opts: | |
usage() | |
if len(args) != 2: | |
usage() | |
binary_path = args[0] | |
symbol_str = args[1] | |
if not os.path.exists(binary_path): | |
usage() | |
find_symbol(binary_path, symbol_str) | |
sys.exit(0) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment