def test_shift_left(self): actual = self.functions['<<']( self.evaluator, c_ast.CNumber(5), c_ast.CNumber(2), ) self.assertEqual(actual, c_ast.CNumber(20))
def test_multiplication(self): actual = self.functions['*']( self.evaluator, c_ast.CNumber(5), c_ast.CNumber(7), ) self.assertEqual(actual, c_ast.CNumber(35))
def test_binary_minus(self): actual = self.functions['-']( self.evaluator, c_ast.CNumber(5), c_ast.CNumber(7), ) self.assertEqual(actual, c_ast.CNumber(-2))
def test_binary_plus(self): actual = self.functions['+']( self.evaluator, c_ast.CNumber(3), c_ast.CNumber(4), ) self.assertEqual(actual, c_ast.CNumber(7))
def test_shift_right(self): actual = self.functions['>>']( self.evaluator, c_ast.CNumber(42), c_ast.CNumber(3), ) self.assertEqual(actual, c_ast.CNumber(5))
def test_bitwise_xor(self): actual = self.functions['^']( self.evaluator, c_ast.CNumber(42), c_ast.CNumber(33), ) self.assertEqual(actual, c_ast.CNumber(11))
def test_bitwise_or(self): actual = self.functions['|']( self.evaluator, c_ast.CNumber(42), c_ast.CNumber(24), ) self.assertEqual(actual, c_ast.CNumber(58))
def test_parse_unary_operator_on_expression_in_parentheses(self): source = '!(x > 0 || y == 0)' expected = c_ast.CFunctionCall( function_name='!', arguments=[ c_ast.CNestedExpression( opener='(', content=c_ast.CFunctionCall( function_name='||', arguments=[ c_ast.CFunctionCall( function_name='>', arguments=[ c_ast.CVariable('x'), c_ast.CNumber(0), ], ), c_ast.CFunctionCall( function_name='==', arguments=[ c_ast.CVariable('y'), c_ast.CNumber(0), ], ), ], ), closer=')', ), ], ) actual = self.parser.parse(source) self.assertASTEqual(actual, expected)
def _parse_value(self, value): if value == 'y': return c_ast.CNumber(1) elif len(value) >= 2 and value[0] == '"' and value[-1] == '"': return c_ast.CLiteral(value[1:-1]) else: return c_ast.CNumber(int(value, base=0)) # Throws ValueError.
def test_parse_variable_in_parentheses2(self): # Unfortunately our parser is not that great since it misidentifies the # below with & is substituted for +. It accidentally considers it the # dereference operator. I dont think there is a way to properly parse # without context (i.e. cant make a context free grammer) because you # need to resolve the RHS to the & operator to know if it makes sense. source = '(((x) + 1) | 2)' actual = self.parser.parse(source) expected = c_ast.CNestedExpression( opener='(', closer=')', content=c_ast.CFunctionCall( function_name="|", arguments=[ c_ast.CNestedExpression( opener='(', closer=')', content=c_ast.CFunctionCall( function_name="+", arguments=[ c_ast.CNestedExpression( opener='(', content=c_ast.CVariable('x'), closer=')', ), c_ast.CNumber(1), ])), c_ast.CNumber(2) ])) self.assertASTEqual(actual, expected)
def test_parse_function_call_with_five_arguments(self): source = 'f(2, 3, 5, 7, 11)' expected = c_ast.CFunctionCall( function_name='f', arguments=[ c_ast.CNumber(2), c_ast.CNumber(3), c_ast.CNumber(5), c_ast.CNumber(7), c_ast.CNumber(11), ], ) actual = self.parser.parse(source) self.assertASTEqual(actual, expected)
def test_parse_logical_or_and_negation(self): source = 'someFunction(a) || !defined(b) || c < 2' expected = c_ast.CFunctionCall( function_name='||', arguments=[ c_ast.CFunctionCall( function_name='||', arguments=[ c_ast.CFunctionCall( function_name='someFunction', arguments=[c_ast.CVariable('a')], ), c_ast.CFunctionCall( function_name='!', arguments=[ c_ast.CFunctionCall( function_name='defined', arguments=[c_ast.CVariable('b')], ) ], ), ], ), c_ast.CFunctionCall( function_name='<', arguments=[ c_ast.CVariable('c'), c_ast.CNumber(2), ], ), ], ) actual = self.parser.parse(source) self.assertASTEqual(actual, expected)
def _create_type_definition(self, type_definition, field): """Creates the token definition from inspecting results in tok.""" # The initial type definition we detected. definition = type_definition # Is it a pointer to function? if field.function_args: if field.function_pointer: definition = c_ast.CPointer(c_ast.CFunction()) else: definition = c_ast.CFunction() # We detected pointers - Add pointer references. for _ in field.type_pointer: definition = c_ast.CPointer(definition) # We detected an array - add an array reference. for expr in reversed(field.brackets_with_expression_inside): # 0 length for an anonymous array (e.g. int a[]). length = 0 if expr: length = self.expression_parser.evaluate_string(expr) definition = c_ast.CArray(length=c_ast.CNumber(length), type_definition=definition) return definition
def sizeof(evaluator=None, name=None, type_manager=None): """This is the implementation of the sizeof function. We get called whenever the expression evaluator is asked to evaluate an expression with a sizeof() in it. This might happen recursively. For example: struct xregs_state { struct fxregs_state i387; struct xstate_header header; u8 __reserved [(sizeof(struct ymmh_struct) + sizeof(struct lwp_struct) + sizeof(struct mpx_struct))]; } __attribute__ ((packed, aligned (64))); """ _ = evaluator name = str(name) # To know the size of a type we need to ask the type manager to produce the # layout for this type. try: type_layout = type_manager.get_type_layout(name) return c_ast.CNumber(type_layout.bit_size // 8) except (AttributeError, KeyError): raise c_ast.IrreducibleFunction("Unsupported sizeof")
def test_parse_with_hexadecimal_integer_flag(self): config = 'CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000' actual = self.parser.parse(config) expected = { 'CONFIG_ILLEGAL_POINTER_VALUE': c_ast.CNumber(0xdead000000000000), } self.assertEqual(actual, expected)
def test_parse_negative_hex_integer_with_suffix(self): source = '-0xdcbaLL' expected = c_ast.CFunctionCall( function_name='-', arguments=[c_ast.CNumber(56506)], ) actual = self.parser.parse(source) self.assertASTEqual(actual, expected)
def test_parse_negative_hex_integer(self): source = '-0xabcd' expected = c_ast.CFunctionCall( function_name='-', arguments=[c_ast.CNumber(43981)], ) actual = self.parser.parse(source) self.assertASTEqual(actual, expected)
def test_not_equal(self): not_equal = self.functions['!='] self.assertEqual( not_equal(self.evaluator, c_ast.CNumber(4), c_ast.CNumber(5)), c_ast.CNumber(1) ) self.assertEqual( not_equal(self.evaluator, c_ast.CNumber(5), c_ast.CNumber(4)), c_ast.CNumber(1) ) self.assertEqual( not_equal(self.evaluator, c_ast.CNumber(4), c_ast.CNumber(4)), c_ast.CNumber(0) )
def test_less_or_equal(self): less_or_equal = self.functions['<='] self.assertEqual( less_or_equal(self.evaluator, c_ast.CNumber(4), c_ast.CNumber(5)), c_ast.CNumber(1) ) self.assertEqual( less_or_equal(self.evaluator, c_ast.CNumber(5), c_ast.CNumber(4)), c_ast.CNumber(0) ) self.assertEqual( less_or_equal(self.evaluator, c_ast.CNumber(4), c_ast.CNumber(4)), c_ast.CNumber(1) )
def test_greater_than(self): greater_than = self.functions['>'] self.assertEqual( greater_than(self.evaluator, c_ast.CNumber(4), c_ast.CNumber(5)), c_ast.CNumber(0) ) self.assertEqual( greater_than(self.evaluator, c_ast.CNumber(5), c_ast.CNumber(4)), c_ast.CNumber(1) ) self.assertEqual( greater_than(self.evaluator, c_ast.CNumber(4), c_ast.CNumber(4)), c_ast.CNumber(0) )
def test_parse_number_in_parentheses(self): source = '(42)' expected = c_ast.CNestedExpression( opener='(', content=c_ast.CNumber(42), closer=')', ) actual = self.parser.parse(source) self.assertASTEqual(actual, expected)
def test_parse_unary_operator_with_number(self): for unary_operator in self.unary_operators: source = unary_operator + '33' actual = self.parser.parse(source) expected = c_ast.CFunctionCall( function_name=unary_operator, arguments=[c_ast.CNumber(33)], ) self.assertASTEqual(actual, expected)
def test_evaluator(self): source = 'x + (1 << 14)' # Cant evaluate the expression without a value for x. self.assertRaises(c_ast.IrreducibleFunction, self.parser.evaluate_string, source) # Now we provide a value for x - it should evaluate the expression. self.type_manager.add_constant("x", c_ast.CNumber(10)) result = self.parser.evaluate_string(source) self.assertEqual(result, 10 + (1 << 14))
def _process_flag_and_value_line(self, line, match, flags): flag = match.group('flag') value = match.group('value') try: if value == 'm': flags[flag + '_MODULE'] = c_ast.CNumber(1) else: flags[flag] = self._parse_value(value) except ValueError: raise UnknownConfigLineFormatException(line)
def test_parse_comparison_and_shift_with_parentheses_on_right(self): source = 'x < (1 << 14)' expected = c_ast.CFunctionCall( function_name='<', arguments=[ c_ast.CVariable('x'), c_ast.CNestedExpression( opener='(', content=c_ast.CFunctionCall(function_name='<<', arguments=[ c_ast.CNumber(1), c_ast.CNumber(14), ]), closer=')', ), ], ) actual = self.parser.parse(source) self.assertASTEqual(actual, expected)
def setUp(self): self.variables = { 'a': c_ast.CNumber(1), 'c': c_ast.CNumber(2), } self.x = [] self.y = [] self.z = [] self.functions = { 'f1': self.f1, 'f2': self.f2, } type_manager_obj = type_manager.TypeManager() type_manager_obj.functions.update(self.functions) type_manager_obj.variables.update(self.variables) self.expression_evaluator = ( expression_evaluator_visitor.ExpressionEvaluatorVisitor( type_manager_obj))
def test_sizeof_evaluation(self): source = 'sizeof(unsigned int)' actual = self.parser.evaluate_string(source) expected = c_ast.CNumber(4) self.assertASTEqual(actual, expected) self.type_manager.add_type( "__kernel_uid32_t", c_ast.CTypedef( name="__kernel_uid32_t", type_definition=c_ast.CTypeReference(name="unsigned long"))) source = 'sizeof(__kernel_uid32_t)' actual = self.parser.evaluate_string(source) expected = c_ast.CNumber(8) self.assertASTEqual(actual, expected) source = 'sizeof(_unknown_t)' self.assertRaises(c_ast.IrreducibleFunction, self.parser.evaluate_string, source)
def test_parse_binary_operator_with_variable_and_number(self): for binary_operator in self.binary_operators: source = '51' + binary_operator + 'CONFIG_SOMETHING' actual = self.parser.parse(source) expected = c_ast.CFunctionCall( function_name=binary_operator, arguments=[ c_ast.CNumber(51), c_ast.CVariable('CONFIG_SOMETHING'), ]) self.assertASTEqual(actual, expected)
def test_parse_function_call_with_two_arguments(self): source = 'f(a, 42)' expected = c_ast.CFunctionCall( function_name='f', arguments=[ c_ast.CVariable('a'), c_ast.CNumber(42), ], ) actual = self.parser.parse(source) self.assertASTEqual(actual, expected)
def test_visit_function_call(self): function_call = c_ast.CFunctionCall( function_name='f1', arguments=[ c_ast.CNumber(24), c_ast.CLiteral('literal'), ], ) actual = self.expression_evaluator.evaluate(function_call) self.assertEqual(actual, 33) self.assertEqual(self.x, [24]) self.assertEqual(self.y, ['literal'])