1#!/usr/bin/python3 2# Dump the output of LD_TRACE_LOADED_OBJECTS in architecture neutral format. 3# Copyright (C) 2022 Free Software Foundation, Inc. 4# Copyright The GNU Toolchain Authors. 5# This file is part of the GNU C Library. 6# 7# The GNU C Library is free software; you can redistribute it and/or 8# modify it under the terms of the GNU Lesser General Public 9# License as published by the Free Software Foundation; either 10# version 2.1 of the License, or (at your option) any later version. 11# 12# The GNU C Library is distributed in the hope that it will be useful, 13# but WITHOUT ANY WARRANTY; without even the implied warranty of 14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15# Lesser General Public License for more details. 16# 17# You should have received a copy of the GNU Lesser General Public 18# License along with the GNU C Library; if not, see 19# <https://www.gnu.org/licenses/>. 20 21import argparse 22import os 23import subprocess 24import sys 25 26try: 27 subprocess.run 28except: 29 class _CompletedProcess: 30 def __init__(self, args, returncode, stdout=None, stderr=None): 31 self.args = args 32 self.returncode = returncode 33 self.stdout = stdout 34 self.stderr = stderr 35 36 def _run(*popenargs, input=None, timeout=None, check=False, **kwargs): 37 assert(timeout is None) 38 with subprocess.Popen(*popenargs, **kwargs) as process: 39 try: 40 stdout, stderr = process.communicate(input) 41 except: 42 process.kill() 43 process.wait() 44 raise 45 returncode = process.poll() 46 if check and returncode: 47 raise subprocess.CalledProcessError(returncode, popenargs) 48 return _CompletedProcess(popenargs, returncode, stdout, stderr) 49 50 subprocess.run = _run 51 52def is_vdso(lib): 53 return lib.startswith('linux-gate') or lib.startswith('linux-vdso') 54 55 56def parse_trace(cmd, fref): 57 new_env = os.environ.copy() 58 new_env['LD_TRACE_LOADED_OBJECTS'] = '1' 59 trace_out = subprocess.run(cmd, stdout=subprocess.PIPE, check=True, 60 universal_newlines=True, env=new_env).stdout 61 trace = [] 62 for line in trace_out.splitlines(): 63 line = line.strip() 64 if is_vdso(line): 65 continue 66 fields = line.split('=>' if '=>' in line else ' ') 67 lib = os.path.basename(fields[0].strip()) 68 if lib.startswith('ld'): 69 lib = 'ld' 70 elif lib.startswith('libc'): 71 lib = 'libc' 72 found = 1 if fields[1].strip() != 'not found' else 0 73 trace += ['{} {}'.format(lib, found)] 74 trace = sorted(trace) 75 76 reference = sorted(line.replace('\n','') for line in fref.readlines()) 77 78 ret = 0 if trace == reference else 1 79 if ret != 0: 80 for i in reference: 81 if i not in trace: 82 print("Only in {}: {}".format(fref.name, i)) 83 for i in trace: 84 if i not in reference: 85 print("Only in trace: {}".format(i)) 86 87 sys.exit(ret) 88 89 90def get_parser(): 91 parser = argparse.ArgumentParser(description=__doc__) 92 parser.add_argument('command', 93 help='comand to run') 94 parser.add_argument('reference', 95 help='reference file to compare') 96 return parser 97 98 99def main(argv): 100 parser = get_parser() 101 opts = parser.parse_args(argv) 102 with open(opts.reference, 'r') as fref: 103 # Remove the initial 'env' command. 104 parse_trace(opts.command.split()[1:], fref) 105 106 107if __name__ == '__main__': 108 main(sys.argv[1:]) 109