Loading...
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 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | #!/usr/bin/env python3 # # Copyright (c) 2017 Intel Corporation # # SPDX-License-Identifier: Apache-2.0 """ gperf C file post-processor We use gperf to build up a perfect hashtable of pointer values. The way gperf does this is to create a table 'wordlist' indexed by a string repreesentation of a pointer address, and then doing memcmp() on a string passed in for comparison We are exclusively working with 4-byte pointer values. This script adjusts the generated code so that we work with pointers directly and not strings. This saves a considerable amount of space. """ import sys import argparse import os import re from distutils.version import LooseVersion # --- debug stuff --- def debug(text): if not args.verbose: return sys.stdout.write(os.path.basename(sys.argv[0]) + ": " + text + "\n") def error(text): sys.stderr.write(os.path.basename(sys.argv[0]) + " ERROR: " + text + "\n") sys.exit(1) def warn(text): sys.stdout.write( os.path.basename( sys.argv[0]) + " WARNING: " + text + "\n") def reformat_str(match_obj): addr_str = match_obj.group(0) # Nip quotes addr_str = addr_str[1:-1] addr_vals = [0, 0, 0, 0] ctr = 3 i = 0 while True: if i >= len(addr_str): break if addr_str[i] == "\\": if addr_str[i + 1].isdigit(): # Octal escape sequence val_str = addr_str[i + 1:i + 4] addr_vals[ctr] = int(val_str, 8) i += 4 else: # Char value that had to be escaped by C string rules addr_vals[ctr] = ord(addr_str[i + 1]) i += 2 else: addr_vals[ctr] = ord(addr_str[i]) i += 1 ctr -= 1 return "(char *)0x%02x%02x%02x%02x" % tuple(addr_vals) def process_line(line, fp): if line.startswith("#"): fp.write(line) return # Set the lookup function to static inline so it gets rolled into # _k_object_find(), nothing else will use it if re.search(args.pattern + " [*]$", line): fp.write("static inline " + line) return m = re.search("gperf version (.*) [*][/]$", line) if m: v = LooseVersion(m.groups()[0]) v_lo = LooseVersion("3.0") v_hi = LooseVersion("3.1") if (v < v_lo or v > v_hi): warn("gperf %s is not tested, versions %s through %s supported" % (v, v_lo, v_hi)) # Replace length lookups with constant len of 4 since we're always # looking at pointers line = re.sub(r'lengthtable\[key\]', r'4', line) # Empty wordlist entries to have NULLs instead of "" line = re.sub(r'[{]["]["][}]', r'{}', line) # Suppress a compiler warning since this table is no longer necessary line = re.sub(r'static unsigned char lengthtable', r'static unsigned char __unused lengthtable', line) # drop all use of register keyword, let compiler figure that out, # we have to do this since we change stuff to take the address of some # parameters line = re.sub(r'register', r'', line) # Hashing the address of the string line = re.sub(r"hash [(]str, len[)]", r"hash((const char *)&str, len)", line) # Just compare pointers directly instead of using memcmp if re.search("if [(][*]str", line): fp.write(" if (str == s)\n") return # Take the strings with the binary information for the pointer values, # and just turn them into pointers line = re.sub(r'["].*["]', reformat_str, line) fp.write(line) def parse_args(): global args parser = argparse.ArgumentParser( description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) parser.add_argument("-i", "--input", required=True, help="Input C file from gperf") parser.add_argument("-o", "--output", required=True, help="Output C file with processing done") parser.add_argument("-p", "--pattern", required=True, help="Search pattern for objects") parser.add_argument("-v", "--verbose", action="store_true", help="Print extra debugging information") args = parser.parse_args() if "VERBOSE" in os.environ: args.verbose = 1 def main(): parse_args() with open(args.input, "r") as in_fp, open(args.output, "w") as out_fp: for line in in_fp.readlines(): process_line(line, out_fp) if __name__ == "__main__": main() |