128 lines · python
1#!/usr/bin/env python2 3"""Validate compact unwind info by cross checking the llvm-objdump4reports of the input object file vs final linked output.5"""6from __future__ import print_function7import sys8import argparse9import re10from pprint import pprint11 12 13def main():14 hex = r"[a-f\d]"15 hex8 = hex + "{8}"16 17 parser = argparse.ArgumentParser(description=__doc__)18 parser.add_argument(19 "files",20 metavar="FILES",21 nargs="*",22 help="output of (llvm-objdump --unwind-info --syms) for object file(s) plus final linker output",23 )24 parser.add_argument("--debug", action="store_true")25 args = parser.parse_args()26 27 if args.files:28 objdump_string = "".join([open(f).read() for f in args.files])29 else:30 objdump_string = sys.stdin.read()31 32 object_encodings_list = [33 (symbol, encoding, personality, lsda)34 for symbol, encoding, personality, lsda in re.findall(35 r"start:\s+0x%s+\s+(\w+)\s+" % hex36 + r"length:\s+0x%s+\s+" % hex37 + r"compact encoding:\s+0x(%s+)(?:\s+" % hex38 + r"personality function:\s+0x(%s+)\s+\w+\s+" % hex39 + r"LSDA:\s+0x(%s+)\s+\w+(?: \+ 0x%s+)?)?" % (hex, hex),40 objdump_string,41 re.DOTALL,42 )43 ]44 object_encodings_map = {45 symbol: encoding for symbol, encoding, _, _ in object_encodings_list46 }47 if not object_encodings_map:48 sys.exit("no object encodings found in input")49 50 # generate-cfi-funcs.py doesn't generate unwind info for _main.51 object_encodings_map["_main"] = "00000000"52 53 program_symbols_map = {54 address: symbol55 for address, symbol in re.findall(56 r"^%s(%s) g\s+F __TEXT,__text (x\1|_main)$" % (hex8, hex8),57 objdump_string,58 re.MULTILINE,59 )60 }61 if not program_symbols_map:62 sys.exit("no program symbols found in input")63 64 program_common_encodings = re.findall(65 r"^\s+encoding\[(?:\d|\d\d|1[01]\d|12[0-6])\]: 0x(%s+)$" % hex,66 objdump_string,67 re.MULTILINE,68 )69 if not program_common_encodings:70 sys.exit("no common encodings found in input")71 72 program_encodings_map = {73 program_symbols_map[address]: encoding74 for address, encoding in re.findall(75 r"^\s+\[\d+\]: function offset=0x(%s+), " % hex76 + r"encoding(?:\[\d+\])?=0x(%s+)$" % hex,77 objdump_string,78 re.MULTILINE,79 )80 }81 if not object_encodings_map:82 sys.exit("no program encodings found in input")83 84 # Fold adjacent entries from the object file that have matching encodings85 # TODO(gkm) add check for personality+lsda86 encoding0 = 087 for symbol in sorted(object_encodings_map):88 encoding = object_encodings_map[symbol]89 fold = encoding == encoding090 if fold:91 del object_encodings_map[symbol]92 if args.debug:93 print("%s %s with %s" % ("delete" if fold else "retain", symbol, encoding))94 encoding0 = encoding95 96 if program_encodings_map != object_encodings_map:97 if args.debug:98 print("program encodings map:")99 pprint(program_encodings_map)100 print("object encodings map:")101 pprint(object_encodings_map)102 sys.exit("encoding maps differ")103 104 # Count frequency of object-file folded encodings105 # and compare with the program-file common encodings table106 encoding_frequency_map = {}107 for _, encoding in object_encodings_map.items():108 encoding_frequency_map[encoding] = 1 + encoding_frequency_map.get(encoding, 0)109 encoding_frequencies = [110 x111 for x in sorted(112 encoding_frequency_map,113 key=lambda x: (encoding_frequency_map.get(x), x),114 reverse=True,115 )116 ]117 del encoding_frequencies[127:]118 119 if program_common_encodings != encoding_frequencies:120 if args.debug:121 pprint("program common encodings:\n" + str(program_common_encodings))122 pprint("object encoding frequencies:\n" + str(encoding_frequencies))123 sys.exit("encoding frequencies differ")124 125 126if __name__ == "__main__":127 main()128