blob: c086ea14bd47970d1ded8aa3ac0698b3dad83cc3 [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
Ruslan Mstoi7d8addd2020-05-26 16:41:05 +030011does this is to create a table 'wordlist' indexed by a string representation
Andrew Boie945af952017-08-22 13:15:23 -070012of 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
Julien Massot36f116b2021-11-19 16:30:43 +010024from packaging import version
Ulf Magnusson605423f2019-03-25 20:29:13 +010025
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):
Ulf Magnusson50b9b122019-09-07 14:41:01 +020035 sys.exit(os.path.basename(sys.argv[0]) + " ERROR: " + text)
Andrew Boie945af952017-08-22 13:15:23 -070036
37
38def warn(text):
Anas Nashif72565532017-12-12 08:19:25 -050039 sys.stdout.write(
40 os.path.basename(
41 sys.argv[0]) +
42 " WARNING: " +
43 text +
44 "\n")
Andrew Boie945af952017-08-22 13:15:23 -070045
46
47def reformat_str(match_obj):
48 addr_str = match_obj.group(0)
49
50 # Nip quotes
51 addr_str = addr_str[1:-1]
Andrew Boief290ab52019-11-18 17:06:13 -080052 addr_vals = [0, 0, 0, 0, 0, 0, 0 , 0]
53 ctr = 7
Andrew Boie945af952017-08-22 13:15:23 -070054 i = 0
55
Ulf Magnussonba312fe2019-03-20 19:30:29 +010056 while True:
Andrew Boie945af952017-08-22 13:15:23 -070057 if i >= len(addr_str):
58 break
59
60 if addr_str[i] == "\\":
Anas Nashif72565532017-12-12 08:19:25 -050061 if addr_str[i + 1].isdigit():
Andrew Boie945af952017-08-22 13:15:23 -070062 # Octal escape sequence
Anas Nashif72565532017-12-12 08:19:25 -050063 val_str = addr_str[i + 1:i + 4]
Andrew Boie945af952017-08-22 13:15:23 -070064 addr_vals[ctr] = int(val_str, 8)
65 i += 4
66 else:
67 # Char value that had to be escaped by C string rules
Anas Nashif72565532017-12-12 08:19:25 -050068 addr_vals[ctr] = ord(addr_str[i + 1])
Andrew Boie945af952017-08-22 13:15:23 -070069 i += 2
70
71 else:
72 addr_vals[ctr] = ord(addr_str[i])
73 i += 1
74
75 ctr -= 1
76
Andrew Boief290ab52019-11-18 17:06:13 -080077 return "(char *)0x%02x%02x%02x%02x%02x%02x%02x%02x" % tuple(addr_vals)
Andrew Boie945af952017-08-22 13:15:23 -070078
Anas Nashif72565532017-12-12 08:19:25 -050079
Andrew Boie945af952017-08-22 13:15:23 -070080def process_line(line, fp):
81 if line.startswith("#"):
82 fp.write(line)
83 return
84
85 # Set the lookup function to static inline so it gets rolled into
Andrew Boieae8acff2020-03-11 07:19:16 -070086 # z_object_find(), nothing else will use it
Chunlin Han18560a02018-02-01 01:19:49 -060087 if re.search(args.pattern + " [*]$", line):
Andrew Boie945af952017-08-22 13:15:23 -070088 fp.write("static inline " + line)
89 return
90
91 m = re.search("gperf version (.*) [*][/]$", line)
92 if m:
Julien Massot36f116b2021-11-19 16:30:43 +010093 v = version.parse(m.groups()[0])
94 v_lo = version.parse("3.0")
95 v_hi = version.parse("3.1")
Andrew Boie945af952017-08-22 13:15:23 -070096 if (v < v_lo or v > v_hi):
97 warn("gperf %s is not tested, versions %s through %s supported" %
Anas Nashif72565532017-12-12 08:19:25 -050098 (v, v_lo, v_hi))
Andrew Boie945af952017-08-22 13:15:23 -070099
Andrew Boief290ab52019-11-18 17:06:13 -0800100 # Replace length lookups with constant len since we're always
Andrew Boie945af952017-08-22 13:15:23 -0700101 # looking at pointers
Andrew Boief290ab52019-11-18 17:06:13 -0800102 line = re.sub(r'lengthtable\[key\]', r'sizeof(void *)', line)
Andrew Boie945af952017-08-22 13:15:23 -0700103
104 # Empty wordlist entries to have NULLs instead of ""
105 line = re.sub(r'[{]["]["][}]', r'{}', line)
106
107 # Suppress a compiler warning since this table is no longer necessary
108 line = re.sub(r'static unsigned char lengthtable',
109 r'static unsigned char __unused lengthtable', line)
110
111 # drop all use of register keyword, let compiler figure that out,
112 # we have to do this since we change stuff to take the address of some
113 # parameters
114 line = re.sub(r'register', r'', line)
115
116 # Hashing the address of the string
117 line = re.sub(r"hash [(]str, len[)]",
Anas Nashif72565532017-12-12 08:19:25 -0500118 r"hash((const char *)&str, len)", line)
Andrew Boie945af952017-08-22 13:15:23 -0700119
120 # Just compare pointers directly instead of using memcmp
121 if re.search("if [(][*]str", line):
122 fp.write(" if (str == s)\n")
123 return
124
125 # Take the strings with the binary information for the pointer values,
126 # and just turn them into pointers
127 line = re.sub(r'["].*["]', reformat_str, line)
128
129 fp.write(line)
130
Anas Nashif72565532017-12-12 08:19:25 -0500131
Andrew Boie945af952017-08-22 13:15:23 -0700132def parse_args():
133 global args
134
Anas Nashif72565532017-12-12 08:19:25 -0500135 parser = argparse.ArgumentParser(
136 description=__doc__,
137 formatter_class=argparse.RawDescriptionHelpFormatter)
Andrew Boie945af952017-08-22 13:15:23 -0700138
139 parser.add_argument("-i", "--input", required=True,
Anas Nashif72565532017-12-12 08:19:25 -0500140 help="Input C file from gperf")
Andrew Boie945af952017-08-22 13:15:23 -0700141 parser.add_argument("-o", "--output", required=True,
Anas Nashif72565532017-12-12 08:19:25 -0500142 help="Output C file with processing done")
Chunlin Han18560a02018-02-01 01:19:49 -0600143 parser.add_argument("-p", "--pattern", required=True,
144 help="Search pattern for objects")
Andrew Boie945af952017-08-22 13:15:23 -0700145 parser.add_argument("-v", "--verbose", action="store_true",
Anas Nashif72565532017-12-12 08:19:25 -0500146 help="Print extra debugging information")
Andrew Boie945af952017-08-22 13:15:23 -0700147 args = parser.parse_args()
Sebastian Bøe4971d2a2017-12-28 17:34:50 +0100148 if "VERBOSE" in os.environ:
149 args.verbose = 1
Andrew Boie945af952017-08-22 13:15:23 -0700150
151def main():
152 parse_args()
153
154 with open(args.input, "r") as in_fp, open(args.output, "w") as out_fp:
155 for line in in_fp.readlines():
156 process_line(line, out_fp)
157
158
159if __name__ == "__main__":
160 main()