• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2
3"""Validate compact unwind info by cross checking the llvm-objdump
4reports of the input object file vs final linked output.
5"""
6from __future__ import print_function
7import sys
8import argparse
9import re
10from pprint import pprint
11
12def main():
13  hex = "[a-f\d]"
14  hex8 = hex + "{8}"
15
16  parser = argparse.ArgumentParser(description=__doc__)
17  parser.add_argument('files', metavar='FILES', nargs='*',
18                      help='output of (llvm-objdump --unwind-info --syms) for object file(s) plus final linker output')
19  parser.add_argument('--debug', action='store_true')
20  args = parser.parse_args()
21
22  if args.files:
23    objdump_string = ''.join([open(f).read() for f in args.files])
24  else:
25    objdump_string = sys.stdin.read()
26
27  object_encodings_list = [(symbol, encoding, personality, lsda)
28    for symbol, encoding, personality, lsda in
29    re.findall(r"start:\s+0x%s+\s+(\w+)\s+" % hex +
30               r"length:\s+0x%s+\s+" % hex +
31               r"compact encoding:\s+0x(%s+)(?:\s+" % hex +
32               r"personality function:\s+0x(%s+)\s+\w+\s+" % hex +
33               r"LSDA:\s+0x(%s+)\s+\w+(?: \+ 0x%s+)?)?" % (hex, hex),
34               objdump_string, re.DOTALL)]
35  object_encodings_map = {symbol:encoding
36    for symbol, encoding, _, _ in object_encodings_list}
37  if not object_encodings_map:
38    sys.exit("no object encodings found in input")
39
40  program_symbols_map = {address:symbol
41    for address, symbol in
42    re.findall(r"^%s(%s) g\s+F __TEXT,__text (x\1)$" % (hex8, hex8),
43               objdump_string, re.MULTILINE)}
44  if not program_symbols_map:
45    sys.exit("no program symbols found in input")
46
47  program_common_encodings = (
48    re.findall(r"^\s+encoding\[\d+\]: 0x(%s+)$" % hex,
49               objdump_string, re.MULTILINE))
50  if not program_common_encodings:
51    sys.exit("no common encodings found in input")
52
53  program_encodings_map = {program_symbols_map[address]:encoding
54    for address, encoding in
55    re.findall(r"^\s+\[\d+\]: function offset=0x(%s+), " % hex +
56               r"encoding\[\d+\]=0x(%s+)$" % hex,
57               objdump_string, re.MULTILINE)}
58  if not object_encodings_map:
59    sys.exit("no program encodings found in input")
60
61  # Fold adjacent entries from the object file that have matching encodings
62  # TODO(gkm) add check for personality+lsda
63  encoding0 = 0
64  for symbol in sorted(object_encodings_map):
65    encoding = object_encodings_map[symbol]
66    fold = (encoding == encoding0)
67    if fold:
68      del object_encodings_map[symbol]
69    if args.debug:
70      print("%s %s with %s" % (
71              'delete' if fold else 'retain', symbol, encoding))
72    encoding0 = encoding
73
74  if program_encodings_map != object_encodings_map:
75    if args.debug:
76      pprint("program encodings map:\n" + program_encodings_map)
77      pprint("object encodings map:\n" + object_encodings_map)
78    sys.exit("encoding maps differ")
79
80  # Count frequency of object-file folded encodings
81  # and compare with the program-file common encodings table
82  encoding_frequency_map = {}
83  for _, encoding in object_encodings_map.items():
84    encoding_frequency_map[encoding] = 1 + encoding_frequency_map.get(encoding, 0)
85  encoding_frequencies = [x for x in
86                          sorted(encoding_frequency_map,
87                                 key=lambda x: (encoding_frequency_map.get(x), x),
88                                 reverse=True)]
89
90  if program_common_encodings != encoding_frequencies:
91    if args.debug:
92      pprint("program common encodings:\n" + program_common_encodings)
93      pprint("object encoding frequencies:\n" + encoding_frequencies)
94    sys.exit("encoding frequencies differ")
95
96
97if __name__ == '__main__':
98  main()
99