tst-ld-trace.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. #!/usr/bin/python3
  2. # Dump the output of LD_TRACE_LOADED_OBJECTS in architecture neutral format.
  3. # Copyright (C) 2022-2026 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. import argparse
  21. import os
  22. import subprocess
  23. import sys
  24. try:
  25. subprocess.run
  26. except:
  27. class _CompletedProcess:
  28. def __init__(self, args, returncode, stdout=None, stderr=None):
  29. self.args = args
  30. self.returncode = returncode
  31. self.stdout = stdout
  32. self.stderr = stderr
  33. def _run(*popenargs, input=None, timeout=None, check=False, **kwargs):
  34. assert(timeout is None)
  35. with subprocess.Popen(*popenargs, **kwargs) as process:
  36. try:
  37. stdout, stderr = process.communicate(input)
  38. except:
  39. process.kill()
  40. process.wait()
  41. raise
  42. returncode = process.poll()
  43. if check and returncode:
  44. raise subprocess.CalledProcessError(returncode, popenargs)
  45. return _CompletedProcess(popenargs, returncode, stdout, stderr)
  46. subprocess.run = _run
  47. def is_vdso(lib):
  48. return lib.startswith('linux-gate') or lib.startswith('linux-vdso')
  49. def parse_trace(cmd, fref):
  50. new_env = os.environ.copy()
  51. new_env['LD_TRACE_LOADED_OBJECTS'] = '1'
  52. trace_out = subprocess.run(cmd, stdout=subprocess.PIPE, check=True,
  53. universal_newlines=True, env=new_env).stdout
  54. trace = []
  55. for line in trace_out.splitlines():
  56. line = line.strip()
  57. if is_vdso(line):
  58. continue
  59. fields = line.split('=>' if '=>' in line else ' ')
  60. lib = os.path.basename(fields[0].strip())
  61. if lib.startswith('ld'):
  62. lib = 'ld'
  63. elif lib.startswith('libc'):
  64. lib = 'libc'
  65. found = 1 if fields[1].strip() != 'not found' else 0
  66. trace += ['{} {}'.format(lib, found)]
  67. trace = sorted(trace)
  68. reference = sorted(line.replace('\n','') for line in fref.readlines())
  69. ret = 0 if trace == reference else 1
  70. if ret != 0:
  71. for i in reference:
  72. if i not in trace:
  73. print("Only in {}: {}".format(fref.name, i))
  74. for i in trace:
  75. if i not in reference:
  76. print("Only in trace: {}".format(i))
  77. sys.exit(ret)
  78. def get_parser():
  79. parser = argparse.ArgumentParser(description=__doc__)
  80. parser.add_argument('command',
  81. help='comand to run')
  82. parser.add_argument('reference',
  83. help='reference file to compare')
  84. return parser
  85. def main(argv):
  86. parser = get_parser()
  87. opts = parser.parse_args(argv)
  88. with open(opts.reference, 'r') as fref:
  89. # Remove the initial 'env' command.
  90. parse_trace(opts.command.split()[1:], fref)
  91. if __name__ == '__main__':
  92. main(sys.argv[1:])