blob: 2e550609812eed8bbcc87b16f247a25483ed92d4 [file] [log] [blame]
Andrew Boie945af952017-08-22 13:15:23 -07001#!/usr/bin/env python3
2#
3# Copyright (c) 2017 Intel Corporation
4#
5# SPDX-License-Identifier: Apache-2.0
6
7import sys
8import argparse
9import os
10import re
11from distutils.version import LooseVersion
12
13# --- debug stuff ---
14
15"""
16gperf C file post-processor
17
18We use gperf to build up a perfect hashtable of pointer values. The way gperf
19does this is to create a table 'wordlist' indexed by a string repreesentation
20of a pointer address, and then doing memcmp() on a string passed in for
21comparison
22
23We are exclusively working with 4-byte pointer values. This script adjusts
24the generated code so that we work with pointers directly and not strings.
25This saves a considerable amount of space.
26"""
27
Anas Nashif72565532017-12-12 08:19:25 -050028
Andrew Boie945af952017-08-22 13:15:23 -070029def debug(text):
30 if not args.verbose:
31 return
32 sys.stdout.write(os.path.basename(sys.argv[0]) + ": " + text + "\n")
33
34
35def error(text):
36 sys.stderr.write(os.path.basename(sys.argv[0]) + " ERROR: " + text + "\n")
37 sys.exit(1)
38
39
40def warn(text):
Anas Nashif72565532017-12-12 08:19:25 -050041 sys.stdout.write(
42 os.path.basename(
43 sys.argv[0]) +
44 " WARNING: " +
45 text +
46 "\n")
Andrew Boie945af952017-08-22 13:15:23 -070047
48
49def reformat_str(match_obj):
50 addr_str = match_obj.group(0)
51
52 # Nip quotes
53 addr_str = addr_str[1:-1]
54 addr_vals = [0, 0, 0, 0]
55 ctr = 3
56 i = 0
57
58 while (True):
59 if i >= len(addr_str):
60 break
61
62 if addr_str[i] == "\\":
Anas Nashif72565532017-12-12 08:19:25 -050063 if addr_str[i + 1].isdigit():
Andrew Boie945af952017-08-22 13:15:23 -070064 # Octal escape sequence
Anas Nashif72565532017-12-12 08:19:25 -050065 val_str = addr_str[i + 1:i + 4]
Andrew Boie945af952017-08-22 13:15:23 -070066 addr_vals[ctr] = int(val_str, 8)
67 i += 4
68 else:
69 # Char value that had to be escaped by C string rules
Anas Nashif72565532017-12-12 08:19:25 -050070 addr_vals[ctr] = ord(addr_str[i + 1])
Andrew Boie945af952017-08-22 13:15:23 -070071 i += 2
72
73 else:
74 addr_vals[ctr] = ord(addr_str[i])
75 i += 1
76
77 ctr -= 1
78
79 return "(char *)0x%02x%02x%02x%02x" % tuple(addr_vals)
80
Anas Nashif72565532017-12-12 08:19:25 -050081
Andrew Boie945af952017-08-22 13:15:23 -070082def process_line(line, fp):
83 if line.startswith("#"):
84 fp.write(line)
85 return
86
87 # Set the lookup function to static inline so it gets rolled into
88 # _k_object_find(), nothing else will use it
Chunlin Han18560a02018-02-01 01:19:49 -060089 if re.search(args.pattern + " [*]$", line):
Andrew Boie945af952017-08-22 13:15:23 -070090 fp.write("static inline " + line)
91 return
92
93 m = re.search("gperf version (.*) [*][/]$", line)
94 if m:
95 v = LooseVersion(m.groups()[0])
96 v_lo = LooseVersion("3.0")
97 v_hi = LooseVersion("3.1")
98 if (v < v_lo or v > v_hi):
99 warn("gperf %s is not tested, versions %s through %s supported" %
Anas Nashif72565532017-12-12 08:19:25 -0500100 (v, v_lo, v_hi))
Andrew Boie945af952017-08-22 13:15:23 -0700101
102 # Replace length lookups with constant len of 4 since we're always
103 # looking at pointers
Andrew Boiecd255742018-12-07 15:54:34 -0800104 line = re.sub(r'lengthtable\[key\]', r'4', line)
Andrew Boie945af952017-08-22 13:15:23 -0700105
106 # Empty wordlist entries to have NULLs instead of ""
107 line = re.sub(r'[{]["]["][}]', r'{}', line)
108
109 # Suppress a compiler warning since this table is no longer necessary
110 line = re.sub(r'static unsigned char lengthtable',
111 r'static unsigned char __unused lengthtable', line)
112
113 # drop all use of register keyword, let compiler figure that out,
114 # we have to do this since we change stuff to take the address of some
115 # parameters
116 line = re.sub(r'register', r'', line)
117
118 # Hashing the address of the string
119 line = re.sub(r"hash [(]str, len[)]",
Anas Nashif72565532017-12-12 08:19:25 -0500120 r"hash((const char *)&str, len)", line)
Andrew Boie945af952017-08-22 13:15:23 -0700121
122 # Just compare pointers directly instead of using memcmp
123 if re.search("if [(][*]str", line):
124 fp.write(" if (str == s)\n")
125 return
126
127 # Take the strings with the binary information for the pointer values,
128 # and just turn them into pointers
129 line = re.sub(r'["].*["]', reformat_str, line)
130
131 fp.write(line)
132
Anas Nashif72565532017-12-12 08:19:25 -0500133
Andrew Boie945af952017-08-22 13:15:23 -0700134def parse_args():
135 global args
136
Anas Nashif72565532017-12-12 08:19:25 -0500137 parser = argparse.ArgumentParser(
138 description=__doc__,
139 formatter_class=argparse.RawDescriptionHelpFormatter)
Andrew Boie945af952017-08-22 13:15:23 -0700140
141 parser.add_argument("-i", "--input", required=True,
Anas Nashif72565532017-12-12 08:19:25 -0500142 help="Input C file from gperf")
Andrew Boie945af952017-08-22 13:15:23 -0700143 parser.add_argument("-o", "--output", required=True,
Anas Nashif72565532017-12-12 08:19:25 -0500144 help="Output C file with processing done")
Chunlin Han18560a02018-02-01 01:19:49 -0600145 parser.add_argument("-p", "--pattern", required=True,
146 help="Search pattern for objects")
Andrew Boie945af952017-08-22 13:15:23 -0700147 parser.add_argument("-v", "--verbose", action="store_true",
Anas Nashif72565532017-12-12 08:19:25 -0500148 help="Print extra debugging information")
Andrew Boie945af952017-08-22 13:15:23 -0700149 args = parser.parse_args()
Sebastian Bøe4971d2a2017-12-28 17:34:50 +0100150 if "VERBOSE" in os.environ:
151 args.verbose = 1
Andrew Boie945af952017-08-22 13:15:23 -0700152
153def main():
154 parse_args()
155
156 with open(args.input, "r") as in_fp, open(args.output, "w") as out_fp:
157 for line in in_fp.readlines():
158 process_line(line, out_fp)
159
160
161if __name__ == "__main__":
162 main()