layers: Initial ParamChecker layer
ParamChecker layer is generated and currently only checks that ENUM input to functions or ENUMS as part of input structs have valid values.
Conflicts:
layers/CMakeLists.txt
diff --git a/layers/CMakeLists.txt b/layers/CMakeLists.txt
index 86fc031..618e491 100644
--- a/layers/CMakeLists.txt
+++ b/layers/CMakeLists.txt
@@ -2,15 +2,15 @@
macro(run_xgl_helper subcmd)
add_custom_command(OUTPUT ${ARGN}
- COMMAND ${PROJECT_SOURCE_DIR}/xgl-helper.py --${subcmd} ${PROJECT_SOURCE_DIR}/include/xgl.h --abs_out_dir ${CMAKE_CURRENT_BINARY_DIR}
- DEPENDS ${PROJECT_SOURCE_DIR}/xgl-helper.py ${PROJECT_SOURCE_DIR}/include/xgl.h
+ COMMAND ${PROJECT_SOURCE_DIR}/xgl_helper.py --${subcmd} ${PROJECT_SOURCE_DIR}/include/xgl.h --abs_out_dir ${CMAKE_CURRENT_BINARY_DIR}
+ DEPENDS ${PROJECT_SOURCE_DIR}/xgl_helper.py ${PROJECT_SOURCE_DIR}/include/xgl.h
)
endmacro()
macro(run_xgl_layer_generate subcmd output)
add_custom_command(OUTPUT ${output}
- COMMAND ${PROJECT_SOURCE_DIR}/xgl-layer-generate.py ${subcmd} > ${output}
- DEPENDS ${PROJECT_SOURCE_DIR}/xgl-layer-generate.py ${PROJECT_SOURCE_DIR}/xgl.py
+ COMMAND ${PROJECT_SOURCE_DIR}/xgl-layer-generate.py ${subcmd} ${PROJECT_SOURCE_DIR}/include/xgl.h > ${output}
+ DEPENDS ${PROJECT_SOURCE_DIR}/xgl-layer-generate.py ${PROJECT_SOURCE_DIR}/include/xgl.h ${PROJECT_SOURCE_DIR}/xgl.py
)
endmacro()
@@ -67,6 +67,7 @@
run_xgl_layer_generate(ApiDumpCpp api_dump.cpp)
run_xgl_layer_generate(ApiDumpNoAddrCpp api_dump_no_addr.cpp)
run_xgl_layer_generate(ObjectTracker object_track.c)
+run_xgl_layer_generate(ParamChecker param_checker.c)
add_xgl_layer(Basic basic.cpp)
add_xgl_layer(Multi multi.cpp)
@@ -80,3 +81,4 @@
add_xgl_layer(APIDumpCpp api_dump.cpp)
add_xgl_layer(APIDumpNoAddrCpp api_dump_no_addr.cpp)
add_xgl_layer(ObjectTracker object_track.c)
+add_xgl_layer(ParamChecker param_checker.c)
diff --git a/xgl-layer-generate.py b/xgl-layer-generate.py
index d19a63f..7e2cb74 100755
--- a/xgl-layer-generate.py
+++ b/xgl-layer-generate.py
@@ -26,8 +26,10 @@
# Chia-I Wu <olv@lunarg.com>
import sys
+import os
import xgl
+import xgl_helper
class Subcommand(object):
def __init__(self, argv):
@@ -434,10 +436,9 @@
(pft, pfi) = ("%s", '"addr"')
log_func += '%s = %s, ' % (p.name, pft)
print_vals += ', %s' % (pfi)
- # TODO : Just want this to be simple check for params of STRUCT type
- if "pCreateInfo" in p.name or ('const' in p.ty and '*' in p.ty and False not in [tmp_ty not in p.ty for tmp_ty in ['XGL_CHAR', 'XGL_VOID', 'XGL_CMD_BUFFER', 'XGL_QUEUE_SEMAPHORE', 'XGL_FENCE', 'XGL_SAMPLER', 'XGL_UINT32']]):
- if 'Wsi' not in proto.name:
- cis_param_index.append(pindex)
+ # 'format' gets special treatment as a small struct that we print inline
+ if 'Wsi' not in proto.name and 'format' != p.name and xgl_helper.is_type(p.ty.strip('*').strip('const '), 'struct'):
+ cis_param_index.append(pindex)
pindex += 1
log_func = log_func.strip(', ')
if proto.ret != "XGL_VOID":
@@ -624,13 +625,96 @@
'%s%s'
'%s'
'}' % (qual, decl, proto.params[0].name, using_line, ret_val, c_call, create_line, destroy_line, stmt))
-
- # TODO : Put this code somewhere so it gets called at the end if objects not deleted :
- # // Report any remaining objects in LL
- # objNode *pTrav = pObjLLHead;
- # while (pTrav) {
- # printf("WARN : %s object %p has not been destroyed.\n", pTrav->objType, pTrav->pObj);
- # }
+ elif "ParamChecker" == layer:
+ # TODO : Need to fix up the non-else cases below to do param checking as well
+ decl = proto.c_func(prefix="xgl", attr="XGLAPI")
+ param0_name = proto.params[0].name
+ ret_val = ''
+ stmt = ''
+ param_checks = []
+ # Add code to check enums and structs
+ # TODO : Currently only validating enum values, need to validate everything
+ str_decl = False
+ for p in proto.params:
+ if xgl_helper.is_type(p.ty.strip('*').strip('const '), 'enum'):
+ if not str_decl:
+ param_checks.append(' char str[1024];')
+ str_decl = True
+ param_checks.append(' if (!validate_%s(%s)) {' % (p.ty, p.name))
+ param_checks.append(' char str[1024];')
+ param_checks.append(' sprintf(str, "Parameter %s to function %s has invalid value of %%i.", (int)%s);' % (p.name, proto.name, p.name))
+ param_checks.append(' layerCbMsg(XGL_DBG_MSG_ERROR, XGL_VALIDATION_LEVEL_0, NULL, 0, 1, "PARAMCHECK", str);')
+ param_checks.append(' }')
+ elif xgl_helper.is_type(p.ty.strip('*').strip('const '), 'struct') and 'const' in p.ty:
+ if not str_decl:
+ param_checks.append(' char str[1024];')
+ str_decl = True
+ if '*' in p.ty: # First check for null ptr
+ param_checks.append(' if (!%s) {' % p.name)
+ param_checks.append(' sprintf(str, "Struct ptr parameter %s to function %s is NULL.");' % (p.name, proto.name))
+ param_checks.append(' layerCbMsg(XGL_DBG_MSG_UNKNOWN, XGL_VALIDATION_LEVEL_0, NULL, 0, 1, "PARAMCHECK", str);')
+ param_checks.append(' }')
+ param_checks.append(' else if (!xgl_validate_%s(%s)) {' % (p.ty.strip('*').strip('const ').lower(), p.name))
+ else:
+ param_checks.append(' if (!xgl_validate_%s(%s)) {' % (p.ty.strip('const ').lower(), p.name))
+ param_checks.append(' sprintf(str, "Parameter %s to function %s contains an invalid value.");' % (p.name, proto.name))
+ param_checks.append(' layerCbMsg(XGL_DBG_MSG_ERROR, XGL_VALIDATION_LEVEL_0, NULL, 0, 1, "PARAMCHECK", str);')
+ param_checks.append(' }')
+ if proto.ret != "XGL_VOID":
+ ret_val = "XGL_RESULT result = "
+ stmt = " return result;\n"
+ if proto.name == "EnumerateLayers":
+ c_call = proto.c_call().replace("(" + proto.params[0].name, "((XGL_PHYSICAL_GPU)gpuw->nextObject", 1)
+ funcs.append('%s%s\n'
+ '{\n'
+ ' char str[1024];\n'
+ ' if (gpu != NULL) {\n'
+ ' XGL_BASE_LAYER_OBJECT* gpuw = (XGL_BASE_LAYER_OBJECT *) %s;\n'
+ ' sprintf(str, "At start of layered %s\\n");\n'
+ ' layerCbMsg(XGL_DBG_MSG_UNKNOWN, XGL_VALIDATION_LEVEL_0, gpu, 0, 0, "PARAMCHECK", str);\n'
+ ' pCurObj = gpuw;\n'
+ ' pthread_once(&tabOnce, initLayerTable);\n'
+ ' %snextTable.%s;\n'
+ ' sprintf(str, "Completed layered %s\\n");\n'
+ ' layerCbMsg(XGL_DBG_MSG_UNKNOWN, XGL_VALIDATION_LEVEL_0, gpu, 0, 0, "PARAMCHECK", str);\n'
+ ' fflush(stdout);\n'
+ ' %s'
+ ' } else {\n'
+ ' if (pOutLayerCount == NULL || pOutLayers == NULL || pOutLayers[0] == NULL)\n'
+ ' return XGL_ERROR_INVALID_POINTER;\n'
+ ' // This layer compatible with all GPUs\n'
+ ' *pOutLayerCount = 1;\n'
+ ' strncpy(pOutLayers[0], "%s", maxStringSize);\n'
+ ' return XGL_SUCCESS;\n'
+ ' }\n'
+ '}' % (qual, decl, proto.params[0].name, proto.name, ret_val, c_call, proto.name, stmt, layer_name))
+ elif 'DbgRegisterMsgCallback' == proto.name:
+ funcs.append(self._gen_layer_dbg_callback_register())
+ elif 'DbgUnregisterMsgCallback' == proto.name:
+ funcs.append(self._gen_layer_dbg_callback_unregister())
+ elif proto.params[0].ty != "XGL_PHYSICAL_GPU":
+ funcs.append('%s%s\n'
+ '{\n'
+ '%s\n'
+ ' %snextTable.%s;\n'
+ '%s'
+ '}' % (qual, decl, "\n".join(param_checks), ret_val, proto.c_call(), stmt))
+ else:
+ c_call = proto.c_call().replace("(" + proto.params[0].name, "((XGL_PHYSICAL_GPU)gpuw->nextObject", 1)
+ funcs.append('%s%s\n'
+ '{\n'
+ ' char str[1024];'
+ ' XGL_BASE_LAYER_OBJECT* gpuw = (XGL_BASE_LAYER_OBJECT *) %s;\n'
+ ' sprintf(str, "At start of layered %s\\n");\n'
+ ' layerCbMsg(XGL_DBG_MSG_UNKNOWN, XGL_VALIDATION_LEVEL_0, gpuw, 0, 0, "PARAMCHECK", str);\n'
+ ' pCurObj = gpuw;\n'
+ ' pthread_once(&tabOnce, initLayerTable);\n'
+ ' %snextTable.%s;\n'
+ ' sprintf(str, "Completed layered %s\\n");\n'
+ ' layerCbMsg(XGL_DBG_MSG_UNKNOWN, XGL_VALIDATION_LEVEL_0, gpuw, 0, 0, "PARAMCHECK", str);\n'
+ ' fflush(stdout);\n'
+ '%s'
+ '}' % (qual, decl, proto.params[0].name, proto.name, ret_val, c_call, proto.name, stmt))
return "\n\n".join(funcs)
@@ -1086,6 +1170,18 @@
return "\n\n".join(body)
+class ParamCheckerSubcommand(Subcommand):
+ def generate_header(self):
+ return '#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <assert.h>\n#include <pthread.h>\n#include "xglLayer.h"\n#include "xgl_enum_validate_helper.h"\n#include "xgl_struct_validate_helper.h"\n\nstatic XGL_LAYER_DISPATCH_TABLE nextTable;\nstatic XGL_BASE_LAYER_OBJECT *pCurObj;\nstatic pthread_once_t tabOnce = PTHREAD_ONCE_INIT;\n'
+
+ def generate_body(self):
+ body = [self._gen_layer_dbg_callback_header(),
+ self._generate_layer_dispatch_table(),
+ self._generate_dispatch_entrypoints("XGL_LAYER_EXPORT", "ParamChecker"),
+ self._generate_layer_gpa_function()]
+
+ return "\n\n".join(body)
+
def main():
subcommands = {
"layer-funcs" : LayerFuncsSubcommand,
@@ -1097,14 +1193,24 @@
"ApiDumpCpp" : ApiDumpCppSubcommand,
"ApiDumpNoAddrCpp" : ApiDumpNoAddrCppSubcommand,
"ObjectTracker" : ObjectTrackerSubcommand,
+ "ParamChecker" : ParamCheckerSubcommand,
}
- if len(sys.argv) < 2 or sys.argv[1] not in subcommands:
- print("Usage: %s <subcommand> [options]" % sys.argv[0])
+ if len(sys.argv) < 3 or sys.argv[1] not in subcommands or not os.path.exists(sys.argv[2]):
+ print("Usage: %s <subcommand> <input_header> [options]" % sys.argv[0])
print
print("Available sucommands are: %s" % " ".join(subcommands))
exit(1)
+ hfp = xgl_helper.HeaderFileParser(sys.argv[2])
+ hfp.parse()
+ xgl_helper.enum_val_dict = hfp.get_enum_val_dict()
+ xgl_helper.enum_type_dict = hfp.get_enum_type_dict()
+ xgl_helper.struct_dict = hfp.get_struct_dict()
+ xgl_helper.typedef_fwd_dict = hfp.get_typedef_fwd_dict()
+ xgl_helper.typedef_rev_dict = hfp.get_typedef_rev_dict()
+ xgl_helper.types_dict = hfp.get_types_dict()
+
subcmd = subcommands[sys.argv[1]](sys.argv[2:])
subcmd.run()
diff --git a/xgl-helper.py b/xgl_helper.py
similarity index 96%
rename from xgl-helper.py
rename to xgl_helper.py
index 67cada7..36e05ac 100755
--- a/xgl-helper.py
+++ b/xgl_helper.py
@@ -321,11 +321,13 @@
self.string_helper_no_addr_filename = os.path.join(out_dir, self.api+"_struct_string_helper_no_addr.h")
self.string_helper_cpp_filename = os.path.join(out_dir, self.api+"_struct_string_helper_cpp.h")
self.string_helper_no_addr_cpp_filename = os.path.join(out_dir, self.api+"_struct_string_helper_no_addr_cpp.h")
+ self.validate_helper_filename = os.path.join(out_dir, self.api+"_struct_validate_helper.h")
self.no_addr = False
self.hfg = CommonFileGen(self.header_filename)
self.cfg = CommonFileGen(self.class_filename)
self.shg = CommonFileGen(self.string_helper_filename)
self.shcppg = CommonFileGen(self.string_helper_cpp_filename)
+ self.vhg = CommonFileGen(self.validate_helper_filename)
#print(self.header_filename)
self.header_txt = ""
self.definition_txt = ""
@@ -382,6 +384,14 @@
self.shcppg.setBody(self._generateStringHelperFunctionsCpp())
self.shcppg.generate()
+ # Generate c-style .h file that contains functions for printing structs
+ def generateValidateHelper(self):
+ print("Generating struct validate helper")
+ self.vhg.setCopyright(self._generateCopyright())
+ self.vhg.setHeader(self._generateValidateHelperHeader())
+ self.vhg.setBody(self._generateValidateHelperFunctions())
+ self.vhg.generate()
+
def _generateCopyright(self):
return "//This is the copyright\n"
@@ -445,8 +455,14 @@
dp_funcs.append("}\n")
return "\n".join(dp_funcs)
+ def _get_func_name(self, struct, mid_str):
+ return "%s_%s_%s" % (self.api, mid_str, struct.lower().strip("_"))
+
def _get_sh_func_name(self, struct):
- return "%s_print_%s" % (self.api, struct.lower().strip("_"))
+ return self._get_func_name(struct, 'print')
+
+ def _get_vh_func_name(self, struct):
+ return self._get_func_name(struct, 'validate')
# Return elements to create formatted string for given struct member
def _get_struct_print_formatted(self, struct_member, pre_var_name="prefix", postfix = "\\n", struct_var_name="pStruct", struct_ptr=True, print_array=False):
@@ -863,6 +879,31 @@
header.append("string dynamic_display(const XGL_VOID* pStruct, const string prefix);\n")
return "".join(header)
+ def _generateValidateHelperFunctions(self):
+ sh_funcs = []
+ # We do two passes, first pass just generates prototypes for all the functsions
+ for s in self.struct_dict:
+ sh_funcs.append('uint32_t %s(const %s* pStruct);' % (self._get_vh_func_name(s), typedef_fwd_dict[s]))
+ sh_funcs.append('\n')
+ for s in self.struct_dict:
+ sh_funcs.append('uint32_t %s(const %s* pStruct)\n{' % (self._get_vh_func_name(s), typedef_fwd_dict[s]))
+ for m in sorted(self.struct_dict[s]):
+ if is_type(self.struct_dict[s][m]['type'], 'enum'):
+ sh_funcs.append(' if (!validate_%s(pStruct->%s))\n return 0;' % (self.struct_dict[s][m]['type'], self.struct_dict[s][m]['name']))
+ sh_funcs.append(" return 1;\n}")
+
+ return "\n".join(sh_funcs)
+
+ def _generateValidateHelperHeader(self):
+ header = []
+ header.append("//#includes, #defines, globals and such...\n")
+ for f in self.include_headers:
+ if 'xgl_enum_validate_helper' not in f:
+ header.append("#include <%s>\n" % f)
+ header.append('#include "xgl_enum_validate_helper.h"\n\n// Function Prototypes\n')
+ #header.append("char* dynamic_display(const XGL_VOID* pStruct, const char* prefix);\n")
+ return "".join(header)
+
def _generateHeader(self):
header = []
header.append("//#includes, #defines, globals and such...\n")
@@ -940,7 +981,7 @@
def generateEnumValidate(self):
self.evhfg.setHeader(self._generateSHHeader())
- self.evhfg.setHeader(self._generateVHBody())
+ self.evhfg.setBody(self._generateVHBody())
self.evhfg.generate()
def _generateVHBody(self):
@@ -1301,6 +1342,7 @@
print("Generating struct wrapper class to %s" % sw.class_filename)
sw.generateBody()
sw.generateStringHelper()
+ sw.generateValidateHelper()
# Generate a 2nd helper file that excludes addrs
sw.set_no_addr(True)
sw.generateStringHelper()