105 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
			
		
		
	
	
			105 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
#!/usr/bin/env python
 | 
						|
 | 
						|
"""Validate compact unwind info by cross checking the llvm-objdump
 | 
						|
reports of the input object file vs final linked output.
 | 
						|
"""
 | 
						|
from __future__ import print_function
 | 
						|
import sys
 | 
						|
import argparse
 | 
						|
import re
 | 
						|
from pprint import pprint
 | 
						|
 | 
						|
def main():
 | 
						|
  hex = "[a-f\d]"
 | 
						|
  hex8 = hex + "{8}"
 | 
						|
 | 
						|
  parser = argparse.ArgumentParser(description=__doc__)
 | 
						|
  parser.add_argument('files', metavar='FILES', nargs='*',
 | 
						|
                      help='output of (llvm-objdump --unwind-info --syms) for object file(s) plus final linker output')
 | 
						|
  parser.add_argument('--debug', action='store_true')
 | 
						|
  args = parser.parse_args()
 | 
						|
 | 
						|
  if args.files:
 | 
						|
    objdump_string = ''.join([open(f).read() for f in args.files])
 | 
						|
  else:
 | 
						|
    objdump_string = sys.stdin.read()
 | 
						|
 | 
						|
  object_encodings_list = [(symbol, encoding, personality, lsda)
 | 
						|
    for symbol, encoding, personality, lsda in
 | 
						|
    re.findall(r"start:\s+0x%s+\s+(\w+)\s+" % hex +
 | 
						|
               r"length:\s+0x%s+\s+" % hex +
 | 
						|
               r"compact encoding:\s+0x(%s+)(?:\s+" % hex +
 | 
						|
               r"personality function:\s+0x(%s+)\s+\w+\s+" % hex +
 | 
						|
               r"LSDA:\s+0x(%s+)\s+\w+(?: \+ 0x%s+)?)?" % (hex, hex),
 | 
						|
               objdump_string, re.DOTALL)]
 | 
						|
  object_encodings_map = {symbol:encoding
 | 
						|
    for symbol, encoding, _, _ in object_encodings_list}
 | 
						|
  if not object_encodings_map:
 | 
						|
    sys.exit("no object encodings found in input")
 | 
						|
 | 
						|
  # generate-cfi-funcs.py doesn't generate unwind info for _main.
 | 
						|
  object_encodings_map['_main'] = '00000000'
 | 
						|
 | 
						|
  program_symbols_map = {address:symbol
 | 
						|
    for address, symbol in
 | 
						|
    re.findall(r"^%s(%s) g\s+F __TEXT,__text (x\1|_main)$" % (hex8, hex8),
 | 
						|
               objdump_string, re.MULTILINE)}
 | 
						|
  if not program_symbols_map:
 | 
						|
    sys.exit("no program symbols found in input")
 | 
						|
 | 
						|
  program_common_encodings = (
 | 
						|
    re.findall(r"^\s+encoding\[(?:\d|\d\d|1[01]\d|12[0-6])\]: 0x(%s+)$" % hex,
 | 
						|
               objdump_string, re.MULTILINE))
 | 
						|
  if not program_common_encodings:
 | 
						|
    sys.exit("no common encodings found in input")
 | 
						|
 | 
						|
  program_encodings_map = {program_symbols_map[address]:encoding
 | 
						|
    for address, encoding in
 | 
						|
    re.findall(r"^\s+\[\d+\]: function offset=0x(%s+), " % hex +
 | 
						|
               r"encoding(?:\[\d+\])?=0x(%s+)$" % hex,
 | 
						|
               objdump_string, re.MULTILINE)}
 | 
						|
  if not object_encodings_map:
 | 
						|
    sys.exit("no program encodings found in input")
 | 
						|
 | 
						|
  # Fold adjacent entries from the object file that have matching encodings
 | 
						|
  # TODO(gkm) add check for personality+lsda
 | 
						|
  encoding0 = 0
 | 
						|
  for symbol in sorted(object_encodings_map):
 | 
						|
    encoding = object_encodings_map[symbol]
 | 
						|
    fold = (encoding == encoding0)
 | 
						|
    if fold:
 | 
						|
      del object_encodings_map[symbol]
 | 
						|
    if args.debug:
 | 
						|
      print("%s %s with %s" % (
 | 
						|
              'delete' if fold else 'retain', symbol, encoding))
 | 
						|
    encoding0 = encoding
 | 
						|
 | 
						|
  if program_encodings_map != object_encodings_map:
 | 
						|
    if args.debug:
 | 
						|
      print("program encodings map:")
 | 
						|
      pprint(program_encodings_map)
 | 
						|
      print("object encodings map:")
 | 
						|
      pprint(object_encodings_map)
 | 
						|
    sys.exit("encoding maps differ")
 | 
						|
 | 
						|
  # Count frequency of object-file folded encodings
 | 
						|
  # and compare with the program-file common encodings table
 | 
						|
  encoding_frequency_map = {}
 | 
						|
  for _, encoding in object_encodings_map.items():
 | 
						|
    encoding_frequency_map[encoding] = 1 + encoding_frequency_map.get(encoding, 0)
 | 
						|
  encoding_frequencies = [x for x in
 | 
						|
                          sorted(encoding_frequency_map,
 | 
						|
                                 key=lambda x: (encoding_frequency_map.get(x), x),
 | 
						|
                                 reverse=True)]
 | 
						|
  del encoding_frequencies[127:]
 | 
						|
 | 
						|
  if program_common_encodings != encoding_frequencies:
 | 
						|
    if args.debug:
 | 
						|
      pprint("program common encodings:\n" + str(program_common_encodings))
 | 
						|
      pprint("object encoding frequencies:\n" + str(encoding_frequencies))
 | 
						|
    sys.exit("encoding frequencies differ")
 | 
						|
 | 
						|
 | 
						|
if __name__ == '__main__':
 | 
						|
  main()
 |