[RFC,09/19] ktf: resolve: A helper utility to aid in exposing private kernel symbols to KTF tests.
diff mbox series

Message ID 09d79897772dd370a61967b03e83fa4b8663698b.1565676440.git-series.knut.omang@oracle.com
State New
Headers show
Series
  • Integration of Kernel Test Framework (KTF) into the kernel tree
Related show

Commit Message

Knut Omang Aug. 13, 2019, 6:09 a.m. UTC
Takes an input file foo.txt with a list of symbols on the form:

#module foo
#header foo.h
private_foo_symbol_1
private_foo_symbol_2

and creates usable definitions to access these (requires CONFIG_KALLSYMS_ALL).
This is useful to be able to easily and cleanly test internal interfaces of a module.
Examples follows in the selftests later in the series.

Signed-off-by: Knut Omang <knut.omang@oracle.com>
---
 tools/testing/selftests/ktf/scripts/resolve | 188 +++++++++++++++++++++-
 1 file changed, 188 insertions(+)
 create mode 100755 tools/testing/selftests/ktf/scripts/resolve

Patch
diff mbox series

diff --git a/tools/testing/selftests/ktf/scripts/resolve b/tools/testing/selftests/ktf/scripts/resolve
new file mode 100755
index 0000000..74005f7
--- /dev/null
+++ b/tools/testing/selftests/ktf/scripts/resolve
@@ -0,0 +1,188 @@ 
+#!/usr/bin/python
+
+# Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+#    Author: Knut Omang <knut.omang@oracle.com>
+#
+# SPDX-License-Identifier: GPL-2.0
+#
+# A script to generate code and header definitions for
+# module and kernel symbols not directly exposed to KTF.
+# (See the documentation for KTF for details)
+#
+
+import os, sys, re, shutil, string, ConfigParser
+
+def usage():
+    print "Usage: resolve symbolfile outputfile"
+    exit(0)
+
+class FuncInfo:
+    def __init__(self, sym, re_sym, re_decl):
+        self.symbol = sym
+        self.re_sym = re_sym
+        self.re_decl = re_decl
+
+    def __repr__(self):
+        return "FuncInfo: [%s: %s]" % (self.symbol, self.re_decl)
+
+class Module:
+    def __init__(self, name, header):
+        self.cur_header = header
+        self.prefix = "Z"
+        self.name = name
+        self.symbols = {}  # Input:  headerfile -> symbol list
+        self.func_def = []  # FuncInfo list
+        self.debug = False
+        all_modules.append(self)
+
+    def log(self, str):
+        if self.debug:
+            print str
+
+    def SetHeader(self, header):
+        self.cur_header = header
+
+    def AddSymbol(self, sym):
+        try:
+            h = self.symbols[self.cur_header]
+            h.append(sym)
+        except:
+            self.symbols[self.cur_header] = [sym]
+
+    # Open along include path:
+    def Open(self, filename):
+        for p in includepath:
+            try:
+                f = os.path.join(p, filename)
+                self.log(" -- trying " + f)
+                header = open(f,'r')
+                return header
+            except:
+                continue
+        sys.stderr.write(" ** unable to open \"%s\"\n" % filename)
+        return None
+
+    # Parse the relevant header files for function defs:
+    def ParseDefs(self):
+        for hf in self.symbols.keys():
+            self.log(" ** Parsing %s:" % hf)
+            header = self.Open(hf)
+            if header == None:
+                return
+            content = header.read()
+            symbols = self.symbols[hf]
+            types = r"(extern|u8|u16|u32|u64|int|long|size_t|off_t|loff_t|void|struct|union\s)(.*[\*\s]"
+            funor = ")(" + "|".join(symbols) + r")(\([^\)]+\);)$"
+            tt = types + funor
+            s = re.compile(tt, re.MULTILINE)
+            miter = s.finditer(content)
+            s_count = 0
+            for m in miter:
+                sym = m.group(3)
+                re_name = "_".join([self.prefix, sym])
+                re_decl = "%s%s(*%s)%s" % (m.group(1), m.group(2), re_name, m.group(4))
+                self.func_def.append(FuncInfo(sym, re_name, re_decl))
+                s_count = s_count + 1
+
+            if s_count != len(symbols):
+                print " ** Warning: File %s: Found %d definitions from %d symbols!" % \
+                    (hf, s_count, len(symbols))
+                print " ** - please check/fix output manually!"
+
+    # Output functions:
+    def write_funcs(self, file):
+        for fi in self.func_def:
+            file.write("\t%s\n"% fi.re_decl)
+
+    def write_defines(self, file):
+        for fi in self.func_def:
+            file.write("#define %s ktf_syms.%s\n" % (fi.symbol, fi.re_sym))
+
+    def write_resolve_calls(self, file):
+        for fi in self.func_def:
+            file.write("\tktf_resolve_symbol(%s, %s);\n" % (self.name, fi.symbol))
+
+usage_h = False
+my_argv = []
+includepath = [""]
+
+for arg in sys.argv[1:]:
+    if arg == "-h":
+        usage_h = True
+        continue
+    incl = re.match(r"-I([^\s]+)", arg)
+    if incl != None:
+        includepath.append(incl.group(1))
+        continue
+    genopt = re.match(r"-([^\s]+)", arg)
+    if genopt != None:
+        # Silently ignore other cc options as we accept cc-flags-y:
+        #
+        continue
+    my_argv.append(arg)
+
+# Main program:
+
+if len(my_argv) != 2 or usage_h:
+    usage()
+
+symfile = my_argv[0]
+outputfile = my_argv[1]
+
+all_modules = []
+module = Module("kernel", None)  # Default, at the top of the file is the main kernel symbols
+header = None  # A header directive is required before any symbols
+
+try:
+    file = open(symfile, 'r')
+except:
+    print "Unable to open config file \"%s\"" % symfile
+    exit(1)
+for line in file:
+    match = re.match(r"^#(\w+) ([\w\.]+)\s*$", line)
+    if match != None:
+        cmd = match.group(1)
+        value = match.group(2)
+        if cmd == "module":
+            module = Module(value, header)
+        elif cmd == "header":
+            header = value
+            module.SetHeader(header)
+        else:
+            raise ResolveError("Unknown directive \"%s\"" % cmd)
+        #print "%s set to %s" % (cmd, value)
+        continue
+    match = re.match(r"\s*(\w+)\s*", line)
+    if match != None:
+        s = match.group(1)
+        module.AddSymbol(s)
+
+for m in all_modules:
+    m.ParseDefs()
+
+try:
+    output = open(outputfile, "w")
+except:
+    print "Failed to open output header file \"%s\"" % outputfile
+output.write('#ifndef _KTF_RESOLVE_H\n#define _KTF_RESOLVE_H\n')
+output.write('#include "ktf.h"\n\nstruct ktf_syms {\n')
+
+for m in all_modules:
+    m.write_funcs(output)
+
+output.write('};\n\n')
+
+for m in all_modules:
+    m.write_defines(output)
+
+output.write('\n\nextern struct ktf_syms ktf_syms;\n')
+output.write('\nint ktf_resolve_symbols(void);\n#ifndef KTF_CLIENT\n')
+output.write('struct ktf_syms ktf_syms;\n\n')
+
+output.write('\nint ktf_resolve_symbols(void)\n{\n')
+
+for m in all_modules:
+    m.write_resolve_calls(output)
+
+output.write('\treturn 0;\n}\n\n#endif /* !KTF_CLIENT */\n#endif /* _KTF_RESOLVE_H */ \n')
+output.close()