161 lines
4.5 KiB
Python
Executable File
161 lines
4.5 KiB
Python
Executable File
#!/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 representation
|
|
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 packaging import version
|
|
|
|
# --- 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.exit(os.path.basename(sys.argv[0]) + " ERROR: " + text)
|
|
|
|
|
|
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, 0, 0, 0 , 0]
|
|
ctr = 7
|
|
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%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
|
|
# z_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 = version.parse(m.groups()[0])
|
|
v_lo = version.parse("3.0")
|
|
v_hi = version.parse("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 since we're always
|
|
# looking at pointers
|
|
line = re.sub(r'lengthtable\[key\]', r'sizeof(void *)', 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()
|