#!/usr/bin/python3 # Gather the names of all dynamic linkers in the glibc source tree. # Copyright (C) 2021 Free Software Foundation, Inc. # This file is part of the GNU C Library. # # The GNU C Library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # The GNU C Library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with the GNU C Library; if not, see # . """Gather dynamic linker names. This script scans the glibc source tree for shlib-versions files and extracts the dynamic linker name from them. I writes a header file which defines an RTLD_ALL_NAMES macro. """ import argparse import os import re import sys # The dynamic linker name is optionally followed by a symbol version # baseline. RE_LD = re.compile(r'^ld=(\S+)(?:$|\s)') def get_rtld_name(path): """Extract the ld= line from the file at PATH and return the ld.so name.""" with open(path) as inp: for line in inp: match = RE_LD.match(line) if match is not None: rtld_name, = match.groups() if not rtld_name: sys.stderr.write('{}: error: invalid rtld name: {!r}\n' .format(path, line)) sys.exit(1) return rtld_name # Nothing found. Use the default. return None def write_deps(directories, files, deps, output): """Write makefile dependency information for the file OUTPUT to DEPS.""" with open(deps, 'w') as outp: outp.write(output) outp.write(': \\\n') for entry in directories + files: outp.write(' ') outp.write(entry) outp.write(' \\\n') outp.write('\n') def write_output(rtld_names, path): """Writes a header file with the names list to PATH.""" with open(path, 'w') as outp: outp.write('/* This file is automatically generated by ') our_name = os.path.basename(__file__) outp.write(our_name) outp.write('.\n Do not edit. */\n\n') outp.write('#define RTLD_ALL_NAMES \\\n') for name in rtld_names: outp.write(' "') outp.write(name) outp.write('\\0" \\\n') # An empty string terminates the list. outp.write(' ""\n') def main(): """The main entry point.""" parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('--deps', help='Dependency information for make', type=str, required=True) parser.add_argument('--root', help='Root directory of the source tree', type=str, required=True) parser.add_argument('--output', help='Generated source file with the ', type=str, required=True) opts = parser.parse_args(sys.argv[1:]) # The name of the file we are looking for. shlib_versions = 'shlib-versions' # This is used to generate directory dependencies, so that newly # added shlib-versions files will be found. directories = [] # The default file does not live in a sysdeps subdirectory. files = [os.path.join(opts.root, shlib_versions)] # More files come from the sysdeps subdirectory. for dirpath, dirnames, filenames in os.walk( os.path.join(opts.root, 'sysdeps')): if shlib_versions in filenames: files.append(os.path.join(dirpath, shlib_versions)) else: directories.append(dirpath) # Normalize the generated output. directories.sort() files.sort() write_deps(directories, files, opts.deps, opts.output) rtld_names = set() for path in files: name = get_rtld_name(path) if name is not None: rtld_names.add(name) write_output(sorted(rtld_names), opts.output) if __name__ == "__main__": main()