added conditional enum which must hold true for differenciating different sub-FSMs depending on configuration
This commit is contained in:
parent
57cb073ff4
commit
ae98044d2c
32
analyze.py
32
analyze.py
@ -19,6 +19,7 @@ if __name__ == "__main__":
|
|||||||
argparser.add_argument('-I', '--includedirs', nargs='+', default=[])
|
argparser.add_argument('-I', '--includedirs', nargs='+', default=[])
|
||||||
argparser.add_argument('-D', '--defines', nargs='+', default=[])
|
argparser.add_argument('-D', '--defines', nargs='+', default=[])
|
||||||
argparser.add_argument('-p', '--preprocess', help='output preprocessor file')
|
argparser.add_argument('-p', '--preprocess', help='output preprocessor file')
|
||||||
|
argparser.add_argument('-c', '--conditional', help='only count state assignment if this conditional applies on the path')
|
||||||
argparser.add_argument('--func', help='process function')
|
argparser.add_argument('--func', help='process function')
|
||||||
argparser.add_argument('--enum', help='state enum')
|
argparser.add_argument('--enum', help='state enum')
|
||||||
argparser.add_argument('--initial', help='initial state')
|
argparser.add_argument('--initial', help='initial state')
|
||||||
@ -104,6 +105,33 @@ if __name__ == "__main__":
|
|||||||
print(f" - {f.decl.name} {'<<< entry' if (f.decl.name == args.func) else ''}")
|
print(f" - {f.decl.name} {'<<< entry' if (f.decl.name == args.func) else ''}")
|
||||||
print("")
|
print("")
|
||||||
|
|
||||||
|
config_cond = None
|
||||||
|
cond_blacklist = []
|
||||||
|
cond_whitelist = []
|
||||||
|
if args.conditional is not None:
|
||||||
|
config_cond = args.conditional
|
||||||
|
print(f"Configuration Conditional {config_cond}")
|
||||||
|
config_type = None
|
||||||
|
config_enums = None
|
||||||
|
for name,enum_type in enum_table.items():
|
||||||
|
ev = EnumVisitor()
|
||||||
|
ev.visit(enum_type)
|
||||||
|
if config_cond in ev.enum_names:
|
||||||
|
config_type = name
|
||||||
|
config_enums = ev.enum_names
|
||||||
|
break
|
||||||
|
if config_type is not None:
|
||||||
|
print(f" - Type is {config_type}")
|
||||||
|
cond_whitelist.append(config_cond)
|
||||||
|
print( " - Enum Blacklist is")
|
||||||
|
for enum in config_enums:
|
||||||
|
if enum != config_cond:
|
||||||
|
print(f" * {enum}")
|
||||||
|
cond_blacklist.append(enum)
|
||||||
|
else:
|
||||||
|
print("No type found for conditional, ignoring")
|
||||||
|
print("")
|
||||||
|
|
||||||
print("Enum Table")
|
print("Enum Table")
|
||||||
if args.enum in enum_table:
|
if args.enum in enum_table:
|
||||||
ev = EnumVisitor()
|
ev = EnumVisitor()
|
||||||
@ -112,13 +140,13 @@ if __name__ == "__main__":
|
|||||||
print(" - ",ename)
|
print(" - ",ename)
|
||||||
states.append(ename)
|
states.append(ename)
|
||||||
#for f in fsm_funcs:
|
#for f in fsm_funcs:
|
||||||
sav = StateAssignmentVisitor(ast, ename)
|
sav = StateAssignmentVisitor(ast, ename, cond_blacklist, cond_whitelist)
|
||||||
#sav.visit(f)
|
#sav.visit(f)
|
||||||
sav.visit(proc_func)
|
sav.visit(proc_func)
|
||||||
state_asmts += sav.assignments
|
state_asmts += sav.assignments
|
||||||
else:
|
else:
|
||||||
print(f"Initial State Enum '{args.enum}' not found")
|
print(f"Initial State Enum '{args.enum}' not found")
|
||||||
|
|
||||||
paths = []
|
paths = []
|
||||||
for asm in state_asmts:
|
for asm in state_asmts:
|
||||||
paths.append(asm[1])
|
paths.append(asm[1])
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
from pycparser import c_ast
|
import re
|
||||||
|
from pycparser import c_ast, c_generator
|
||||||
from itertools import pairwise
|
from itertools import pairwise
|
||||||
|
|
||||||
def path_to_str(p):
|
def path_to_str(p):
|
||||||
@ -134,10 +135,12 @@ class FuncCallVisitor(c_ast.NodeVisitor):
|
|||||||
self.func_calls.append(node.children()[0][1].name)
|
self.func_calls.append(node.children()[0][1].name)
|
||||||
|
|
||||||
class StateAssignmentVisitor(NodeVisitorFuncCallForward):
|
class StateAssignmentVisitor(NodeVisitorFuncCallForward):
|
||||||
def __init__(self, ast, state):
|
def __init__(self, ast, state, config_cond_blacklist=None, config_cond_whitelist=None):
|
||||||
super().__init__(ast)
|
super().__init__(ast)
|
||||||
self._method_cache = {}
|
self._method_cache = {}
|
||||||
self.state = state
|
self.state = state
|
||||||
|
self.ccb = config_cond_blacklist
|
||||||
|
self.ccw = config_cond_whitelist
|
||||||
self.assignments = []
|
self.assignments = []
|
||||||
|
|
||||||
def visit(self, node, path = None, invariants = None):
|
def visit(self, node, path = None, invariants = None):
|
||||||
@ -172,7 +175,13 @@ class StateAssignmentVisitor(NodeVisitorFuncCallForward):
|
|||||||
#print("CAL path", path_to_str(path))
|
#print("CAL path", path_to_str(path))
|
||||||
cases = path_filter(path, c_ast.Case)
|
cases = path_filter(path, c_ast.Case)
|
||||||
#print(cases)
|
#print(cases)
|
||||||
new_invariants = [x.expr.name for x in cases]
|
#new_invariants = [x.expr.name for x in cases]
|
||||||
|
new_invariants = []
|
||||||
|
for x in cases:
|
||||||
|
clev = CaseLabelExtractionVisitor()
|
||||||
|
clev.visit(x.expr)
|
||||||
|
new_invariants.append(clev.label)
|
||||||
|
|
||||||
invariants = invariants.copy()
|
invariants = invariants.copy()
|
||||||
for ni in new_invariants:
|
for ni in new_invariants:
|
||||||
if not(ni in invariants):
|
if not(ni in invariants):
|
||||||
@ -218,14 +227,51 @@ class StateAssignmentVisitor(NodeVisitorFuncCallForward):
|
|||||||
|
|
||||||
# conditional assignment detection
|
# conditional assignment detection
|
||||||
asm_if = path_select_last('If', path)
|
asm_if = path_select_last('If', path)
|
||||||
|
asm_case = path_select_last('Case', path)
|
||||||
|
asm_ifs = path_filter(path, c_ast.If)
|
||||||
|
asm_cases = path_filter(path, c_ast.Case)
|
||||||
subpath_case = path_slice_back(case_node, path)
|
subpath_case = path_slice_back(case_node, path)
|
||||||
is_exhaustive_conditional = True if asm_if is None else (asm_if.iftrue is not None) and (asm_if.iffalse is not None)
|
is_exhaustive_conditional = True if asm_if is None else (asm_if.iftrue is not None) and (asm_if.iffalse is not None)
|
||||||
is_conditional = path_contains(subpath_case, c_ast.If) and not(is_exhaustive_conditional)
|
is_conditional = path_contains(subpath_case, c_ast.If) and not(is_exhaustive_conditional)
|
||||||
|
type_condition_antivalent = False
|
||||||
|
#if asm_case is not None:
|
||||||
|
for case in asm_cases:
|
||||||
|
elsv = ExprListSerializerVisitor()
|
||||||
|
elsv.visit(case.expr)
|
||||||
|
print("big case", elsv.serial[0])
|
||||||
|
if elsv.serial[0] in self.ccb:
|
||||||
|
type_condition_antivalent = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if not(type_condition_antivalent):
|
||||||
|
for if_node in asm_ifs:
|
||||||
|
cg = c_generator.CGenerator()
|
||||||
|
if_expr = cg.visit(if_node.cond)
|
||||||
|
print("big if", if_expr)
|
||||||
|
for incl_cond in self.ccw:
|
||||||
|
match = re.search(f"(\!=|==)[\(\)\w\d\s]+{incl_cond}", if_expr)
|
||||||
|
if match is not None:
|
||||||
|
op = match.groups()[0]
|
||||||
|
if op == '!=':
|
||||||
|
type_condition_antivalent = True
|
||||||
|
break
|
||||||
|
|
||||||
|
for excl_cond in self.ccb:
|
||||||
|
match = re.search(f"(\!=|==)[\(\)\w\d\s]+{excl_cond}", if_expr)
|
||||||
|
if match is not None:
|
||||||
|
op = match.groups()[0]
|
||||||
|
if op == '==':
|
||||||
|
type_condition_antivalent = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if type_condition_antivalent:
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
if not(isinstance(n.rvalue, c_ast.Constant) or isinstance(n.rvalue, c_ast.BinaryOp) or isinstance(n.rvalue, c_ast.TernaryOp)):
|
if not(isinstance(n.rvalue, c_ast.Constant) or isinstance(n.rvalue, c_ast.BinaryOp) or isinstance(n.rvalue, c_ast.TernaryOp)):
|
||||||
rval_str = n.rvalue.name
|
rval_str = n.rvalue.name
|
||||||
#print(f">>>> {rval_str} == {self.state}")
|
print(f">>>> {rval_str} == {self.state} antivalent={type_condition_antivalent}")
|
||||||
if rval_str == self.state:
|
if (rval_str == self.state) and not(type_condition_antivalent):
|
||||||
self.assignments.append((n,path,fallthrough_case_names,is_conditional,invariants))
|
self.assignments.append((n,path,fallthrough_case_names,is_conditional,invariants))
|
||||||
|
|
||||||
class EnumDefVisitor(c_ast.NodeVisitor):
|
class EnumDefVisitor(c_ast.NodeVisitor):
|
||||||
@ -321,10 +367,12 @@ class SwitchCasePropertyVisitor(c_ast.NodeVisitor):
|
|||||||
else:
|
else:
|
||||||
lvalue = node.lvalue.name
|
lvalue = node.lvalue.name
|
||||||
|
|
||||||
if isinstance(node.rvalue, c_ast.Constant):
|
#if isinstance(node.rvalue, c_ast.Constant):
|
||||||
rvalue = f"{node.rvalue.type }({node.rvalue.value})"
|
# rvalue = f"{node.rvalue.type }({node.rvalue.value})"
|
||||||
else:
|
#else:
|
||||||
rvalue = node.rvalue.name
|
# rvalue = node.rvalue.name
|
||||||
|
cg = c_generator.CGenerator()
|
||||||
|
rvalue = cg.visit(node.rvalue)
|
||||||
|
|
||||||
prop = f"{lvalue}<={rvalue}"
|
prop = f"{lvalue}<={rvalue}"
|
||||||
self.properties.append(prop)
|
self.properties.append(prop)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user