blob: 4dc615fd86188a44f38a564aad2a8cfa5e4360c2 [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
Andrew Boie945af952017-08-22 13:15:23 -07007"""
8gperf C file post-processor
9
10We use gperf to build up a perfect hashtable of pointer values. The way gperf
11does this is to create a table 'wordlist' indexed by a string repreesentation
12of a pointer address, and then doing memcmp() on a string passed in for
13comparison
14
15We are exclusively working with 4-byte pointer values. This script adjusts
16the generated code so that we work with pointers directly and not strings.
17This saves a considerable amount of space.
18"""
19
Ulf Magnusson605423f2019-03-25 20:29:13 +010020import sys
21import argparse
22import os
23import re
24from distutils.version import LooseVersion
25
26# --- debug stuff ---
Anas Nashif72565532017-12-12 08:19:25 -050027
Andrew Boie945af952017-08-22 13:15:23 -070028def debug(text):
29 if not args.verbose:
30 return
31 sys.stdout.write(os.path.basename(sys.argv[0]) + ": " + text + "\n")
32
33
34def error(text):
35 sys.stderr.write(os.path.basename(sys.argv[0]) + " ERROR: " + text + "\n")
36 sys.exit(1)
37
38
39def warn(text):
Anas Nashif72565532017-12-12 08:19:25 -050040 sys.stdout.write(
41 os.path.basename(
42 sys.argv[0]) +
43 " WARNING: " +
44 text +
45 "\n")
Andrew Boie945af952017-08-22 13:15:23 -070046
47
48def reformat_str(match_obj):
49 addr_str = match_obj.group(0)
50
51 # Nip quotes
52 addr_str = addr_str[1:-1]
53 addr_vals = [0, 0, 0, 0]
54 ctr = 3
55 i = 0
56
Ulf Magnussonba312fe2019-03-20 19:30:29 +010057 while True:
Andrew Boie945af952017-08-22 13:15:23 -070058 if i >= len(addr_str):
59 break
60
61 if addr_str[i] == "\\":
Anas Nashif72565532017-12-12 08:19:25 -050062 if addr_str[i + 1].isdigit():
Andrew Boie945af952017-08-22 13:15:23 -070063 # Octal escape sequence
Anas Nashif72565532017-12-12 08:19:25 -050064 val_str = addr_str[i + 1:i + 4]
Andrew Boie945af952017-08-22 13:15:23 -070065 addr_vals[ctr] = int(val_str, 8)
66 i += 4
67 else:
68 # Char value that had to be escaped by C string rules
Anas Nashif72565532017-12-12 08:19:25 -050069 addr_vals[ctr] = ord(addr_str[i + 1])
Andrew Boie945af952017-08-22 13:15:23 -070070 i += 2
71
72 else:
73 addr_vals[ctr] = ord(addr_str[i])
74 i += 1
75
76 ctr -= 1
77
78 return "(char *)0x%02x%02x%02x%02x" % tuple(addr_vals)
79
Anas Nashif72565532017-12-12 08:19:25 -050080
Andrew Boie945af952017-08-22 13:15:23 -070081def process_line(line, fp):
82 if line.startswith("#"):
83 fp.write(line)
84 return
85
86 # Set the lookup function to static inline so it gets rolled into
87 # _k_object_find(), nothing else will use it
Chunlin Han18560a02018-02-01 01:19:49 -060088 if re.search(args.pattern + " [*]$", line):
Andrew Boie945af952017-08-22 13:15:23 -070089 fp.write("static inline " + line)
90 return
91
92 m = re.search("gperf version (.*) [*][/]$", line)
93 if m:
94 v = LooseVersion(m.groups()[0])
95 v_lo = LooseVersion("3.0")
96 v_hi = LooseVersion("3.1")
97 if (v < v_lo or v > v_hi):
98 warn("gperf %s is not tested, versions %s through %s supported" %
Anas Nashif72565532017-12-12 08:19:25 -050099 (v, v_lo, v_hi))
Andrew Boie945af952017-08-22 13:15:23 -0700100
101 # Replace length lookups with constant len of 4 since we're always
102 # looking at pointers
Andrew Boiecd255742018-12-07 15:54:34 -0800103 line = re.sub(r'lengthtable\[key\]', r'4', line)
Andrew Boie945af952017-08-22 13:15:23 -0700104
105 # Empty wordlist entries to have NULLs instead of ""
106 line = re.sub(r'[{]["]["][}]', r'{}', line)
107
108 # Suppress a compiler warning since this table is no longer necessary
109 line = re.sub(r'static unsigned char lengthtable',
110 r'static unsigned char __unused lengthtable', line)
111
112 # drop all use of register keyword, let compiler figure that out,
113 # we have to do this since we change stuff to take the address of some
114 # parameters
115 line = re.sub(r'register', r'', line)
116
117 # Hashing the address of the string
118 line = re.sub(r"hash [(]str, len[)]",
Anas Nashif72565532017-12-12 08:19:25 -0500119 r"hash((const char *)&str, len)", line)
Andrew Boie945af952017-08-22 13:15:23 -0700120
121 # Just compare pointers directly instead of using memcmp
122 if re.search("if [(][*]str", line):
123 fp.write(" if (str == s)\n")
124 return
125
126 # Take the strings with the binary information for the pointer values,
127 # and just turn them into pointers
128 line = re.sub(r'["].*["]', reformat_str, line)
129
130 fp.write(line)
131
Anas Nashif72565532017-12-12 08:19:25 -0500132
Andrew Boie945af952017-08-22 13:15:23 -0700133def parse_args():
134 global args
135
Anas Nashif72565532017-12-12 08:19:25 -0500136 parser = argparse.ArgumentParser(
137 description=__doc__,
138 formatter_class=argparse.RawDescriptionHelpFormatter)
Andrew Boie945af952017-08-22 13:15:23 -0700139
140 parser.add_argument("-i", "--input", required=True,
Anas Nashif72565532017-12-12 08:19:25 -0500141 help="Input C file from gperf")
Andrew Boie945af952017-08-22 13:15:23 -0700142 parser.add_argument("-o", "--output", required=True,
Anas Nashif72565532017-12-12 08:19:25 -0500143 help="Output C file with processing done")
Chunlin Han18560a02018-02-01 01:19:49 -0600144 parser.add_argument("-p", "--pattern", required=True,
145 help="Search pattern for objects")
Andrew Boie945af952017-08-22 13:15:23 -0700146 parser.add_argument("-v", "--verbose", action="store_true",
Anas Nashif72565532017-12-12 08:19:25 -0500147 help="Print extra debugging information")
Andrew Boie945af952017-08-22 13:15:23 -0700148 args = parser.parse_args()
Sebastian Bøe4971d2a2017-12-28 17:34:50 +0100149 if "VERBOSE" in os.environ:
150 args.verbose = 1
Andrew Boie945af952017-08-22 13:15:23 -0700151
152def main():
153 parse_args()
154
155 with open(args.input, "r") as in_fp, open(args.output, "w") as out_fp:
156 for line in in_fp.readlines():
157 process_line(line, out_fp)
158
159
160if __name__ == "__main__":
161 main()