File: validate-unwind-info.py

package info (click to toggle)
llvm-toolchain-14 1%3A14.0.6-20
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 1,496,436 kB
  • sloc: cpp: 5,593,990; ansic: 986,873; asm: 585,869; python: 184,223; objc: 72,530; lisp: 31,119; f90: 27,793; javascript: 9,780; pascal: 9,762; sh: 9,482; perl: 7,468; ml: 5,432; awk: 3,523; makefile: 2,547; xml: 953; cs: 573; fortran: 567
file content (104 lines) | stat: -rwxr-xr-x 3,908 bytes parent folder | download | duplicates (8)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#!/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()