| /* State will store states of variables for a function's single execution path. | |
| It will be used for bit-level symbolic execution to determine values of bits | |
| of function's return value and symbolic marked arguments. | |
| Copyright (C) 2022-2026 Free Software Foundation, Inc. | |
| Contributed by Matevos Mehrabyan <matevosmehrabyan@gmail.com> | |
| This file is part of GCC. | |
| GCC is free software; you can redistribute it and/or modify it under | |
| the terms of the GNU General Public License as published by the Free | |
| Software Foundation; either version 3, or (at your option) any later | |
| version. | |
| GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |
| WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| for more details. | |
| You should have received a copy of the GNU General Public License | |
| along with GCC; see the file COPYING3. If not see | |
| <http://www.gnu.org/licenses/>. */ | |
| #ifndef SYM_EXEC_STATE_H | |
| #define SYM_EXEC_STATE_H | |
| #define MAX_VALUE_SIZE 64 | |
| #include "sym-exec-expr-is-a-helper.h" | |
| /* Struct used for representing values. */ | |
| struct value { | |
| private: | |
| /* bit-vector that represents the value. */ | |
| vec<value_bit *> number; | |
| public: | |
| /* Used for denoting whether the number is unsigned. */ | |
| const bool is_unsigned; | |
| /* Constructor for value. The first argument is the size of the bit-vector | |
| and the second argument is the sign of the number. */ | |
| value (unsigned size, bool is_unsigned); | |
| /* Copy constructor for value. */ | |
| value (const value &other); | |
| /* Pushes the given bit to the end of the bit-vector. */ | |
| value_bit **push (value_bit *elem); | |
| /* Returns pushed bits count. */ | |
| unsigned length () const; | |
| /* Returns a reference the last bit. */ | |
| value_bit *&last (); | |
| /* Returns the size in bits. */ | |
| unsigned allocated () const; | |
| /* Wrapper of vec<..>.exists for the bit-vector. */ | |
| bool exists () const; | |
| /* Wrapper of vec<..>::operator[] for the bit-vector. */ | |
| value_bit *&operator[] (unsigned i); | |
| /* Assignment operator. If the specified value's size is smaller, | |
| then 0 constant bit will be assigned to the remaining upper bits. */ | |
| value &operator= (const value &other); | |
| /* Wrapper of vec<..>::operator[] const for the bit-vector. */ | |
| value_bit *operator[] (unsigned i) const; | |
| /* Destructor for value. */ | |
| ~value (); | |
| /* Removes given sequence of bits. */ | |
| void free_bits (); | |
| }; | |
| /* Stores states of variables' values on bit-level. */ | |
| class state { | |
| typedef void (state::*binary_func) (value *arg1, value *arg2, tree dest); | |
| typedef value_bit *(*bit_func) (value_bit *bit1, value_bit *bit2); | |
| typedef value_bit *(*bit_func3) (value_bit *var1, value_bit *var2, | |
| value_bit **var3); | |
| typedef void (state::*binary_cond_func) (value *arg1, value *arg2); | |
| private: | |
| /* Here is stored values by bits of each variable. */ | |
| hash_map<tree, value> var_states; | |
| /* Here is stored conditions of symbolic bits. */ | |
| hash_set<bit_expression *> conditions; | |
| /* The result of last added condition. */ | |
| condition_status last_cond_status = condition_status::CS_NO_COND; | |
| /* Creates value for given constant tree. */ | |
| static value create_val_for_const (tree var, size_t size); | |
| /* Checks if sizes of arguments and destination are compatible. */ | |
| bool check_args_compatibility (tree arg1, tree arg2, tree dest); | |
| /* Adds equality condition for two values. */ | |
| void add_equal_cond (value *arg1, value *arg2); | |
| /* Adds not equal condition for two values. */ | |
| void add_not_equal_cond (value *arg1, value *arg2); | |
| /* Adds greater than condition for two values. */ | |
| void add_greater_than_cond (value *arg1, value *arg2); | |
| /* Adds less than condition for two values. */ | |
| void add_less_than_cond (value *arg1, value *arg2); | |
| /* Adds greater or equal condition for two values. */ | |
| void add_greater_or_equal_cond (value *arg1, value *arg2); | |
| /* Adds less or equal condition for two values. */ | |
| void add_less_or_equal_cond (value *arg1, value *arg2); | |
| /* Does preprocessing and postprocessing for condition adding. | |
| Handles value creation for constants and their removement in the end. */ | |
| bool add_binary_cond (tree arg1, tree arg2, binary_cond_func cond_func); | |
| /* Constructs expression trees of greater than condition for given values. */ | |
| bit_expression *construct_great_than_cond (value *arg1, value *arg2); | |
| /* Constructs expression trees of less than condition for given values. */ | |
| bit_expression *construct_less_than_cond (value *arg1, value *arg2); | |
| /* Constructs expression trees of equal condition for given values. */ | |
| bit_expression *construct_equal_cond (value *arg1, value *arg2); | |
| /* A wrapper for operations on two bits. | |
| Operation and operands are passed as arguments. */ | |
| static value_bit *operate_bits (bit_func bit_op, value_bit *bit1, | |
| value_bit *bit2, value_bit **bit3); | |
| /* A wrapper for operations on three bits. | |
| Operation and operands are passed as arguments. */ | |
| static value_bit *operate_bits (bit_func3 bit_op, value_bit *bit1, | |
| value_bit *bit2, value_bit **bit3); | |
| /* Performs the given operation on passed arguments. | |
| The result is stored in dest. */ | |
| template<class func> | |
| void operate (value *arg1, value *arg2, value_bit **bit_arg, tree dest, | |
| func bit_op); | |
| /* Does preprocessing and postprocessing for expressions with tree operands. | |
| Handles value creation for constant and their removement in the end. */ | |
| bool do_binary_operation (tree arg1, tree arg2, tree dest, | |
| binary_func bin_func); | |
| /* Performs AND operation on given values. The result is stored in dest. */ | |
| void do_and (value *arg1, value *arg2, tree dest); | |
| /* Performs OR operation on given values. The result is stored in dest. */ | |
| void do_or (value *arg1, value *arg2, tree dest); | |
| /* Performs XOR operation on given values. The result is stored in dest. */ | |
| void do_xor (value *arg1, value *arg2, tree dest); | |
| /* Performs shift right operation on given values. | |
| The result is stored in dest. */ | |
| void do_shift_right (value *arg1, value *arg2, tree dest); | |
| /* Performs shift left operation on given values. | |
| The result is stored in dest. */ | |
| void do_shift_left (value *arg1, value *arg2, tree dest); | |
| /* Adds given values. The result is stored in dest. */ | |
| void do_add (value *arg1, value *arg2, tree dest); | |
| /* Subtracks second value from the first. The result is stored in dest. */ | |
| void do_sub (value *arg1, value *arg2, tree dest); | |
| /* Performs AND operation on two bits. */ | |
| static value_bit *and_two_bits (value_bit *arg1, value_bit *arg2); | |
| /* ANDs every bit of the value with var_bit, stores the result in var1. */ | |
| void and_number_bit (value *var1, value_bit *var_bit); | |
| /* Multiplies given values. The result is stored in dest. */ | |
| void do_mul (value *arg1, value *arg2, tree dest); | |
| /* Performs AND operation for 2 symbolic_bit operands. */ | |
| static value_bit *and_sym_bits (const value_bit *var1, | |
| const value_bit *var2); | |
| /* Performs AND operation for a symbolic_bit and const_bit operands. */ | |
| static value_bit *and_var_const (const value_bit *var1, | |
| const bit *const_bit); | |
| /* Performs AND operation for 2 constant bit operands. */ | |
| static bit *and_const_bits (const bit *const_bit1, const bit *const_bit2); | |
| /* Performs OR operation on two bits. */ | |
| static value_bit *or_two_bits (value_bit *arg1_bit, value_bit *arg2_bit); | |
| /* Performs OR operation for 2 symbolic_bit operands. */ | |
| static value_bit *or_sym_bits (const value_bit *var1, | |
| const value_bit *var2); | |
| /* Performs OR operation for a symbolic_bit and a constant bit operands. */ | |
| static value_bit *or_var_const (const value_bit *var1, | |
| const bit *const_bit); | |
| /* Performs OR operation for 2 constant bit operands. */ | |
| static bit *or_const_bits (const bit *const_bit1, const bit *const_bit2); | |
| /* Performs complement operation on a bit. */ | |
| static value_bit *complement_a_bit (value_bit *var); | |
| /* Performs NOT operation for constant bit. */ | |
| static bit *complement_const_bit (const bit *const_bit); | |
| /* Performs NOT operation for symbolic_bit. */ | |
| static value_bit *complement_sym_bit (const value_bit *var); | |
| /* Performs XOR operation on two bits. */ | |
| static value_bit *xor_two_bits (value_bit *var1, value_bit *var2); | |
| /* Performs XOR operation for 2 symbolic_bit operands. */ | |
| static value_bit *xor_sym_bits (const value_bit *var1, | |
| const value_bit *var2); | |
| /* Performs XOR operation for 2 constant bit operands. */ | |
| static bit *xor_const_bits (const bit *const_bit1, const bit *const_bit2); | |
| /* Performs XOR operation for a symbolic_bit and const_bit operands. */ | |
| static value_bit *xor_var_const (const value_bit *var, | |
| const bit *const_bit); | |
| /* Shift_right operation. Case: var2 is a symbolic value. */ | |
| static value_bit *shift_right_sym_bits (value_bit *var1, value_bit *var2); | |
| /* Shift_left operation. Case: var2 is a symbolic value. */ | |
| static value_bit *shift_left_sym_bits (value_bit *var1, value_bit *var2); | |
| /* Shifts var right by size of shift_value. */ | |
| value *shift_right_by_const (value *var, size_t shift_value); | |
| /* Return node which has a const bit child. Traversal is done based | |
| on safe branching. */ | |
| static void get_parent_with_const_child (value_bit *root, | |
| bit_expression *&parent, | |
| bit_expression *&parent_of_parent); | |
| /* Checks whether state for variable with specified name already | |
| exists or not. */ | |
| bool is_declared (tree var); | |
| /* Declares given variable if it has not been declared yet. */ | |
| void declare_if_needed (tree var, size_t size); | |
| /* Shifts number left by size of shift_value. */ | |
| value *shift_left_by_const (const value *number, size_t shift_value); | |
| /* Adds two bits and carry value. | |
| Returns result and stores new carry bit in "carry". */ | |
| static value_bit *full_adder (value_bit *var1, value_bit *var2, | |
| value_bit **carry); | |
| /* Returns the additive inverse of the given number. */ | |
| value *additive_inverse (const value *number); | |
| /* Adds two values, stores the result in the first one. */ | |
| void add_numbers (value *var1, const value *var2); | |
| /* Make a copy of given bits. */ | |
| static vec<value_bit *> *make_copy (vec<value_bit *> *bits); | |
| /* Create LFSR value for the reversed CRC. */ | |
| static void create_reversed_lfsr (value &lfsr, const value &crc, | |
| const value &polynomial); | |
| /* Create LFSR value for the forward CRC. */ | |
| static void create_forward_lfsr (value &lfsr, const value &crc, | |
| const value &polynomial); | |
| public: | |
| /* Default constructor for state. */ | |
| state () = default; | |
| /* Destructor for state. */ | |
| ~state (); | |
| /* Adds an empty state for the given variable. */ | |
| bool decl_var (tree name, unsigned size); | |
| /* Copy constructor for state. It copies all variables and conditions | |
| of the given state. */ | |
| state (const state &s); | |
| /* Adds the given variable to state. */ | |
| bool add_var_state (tree var, value *state); | |
| /* Remove all states from the states' vector. */ | |
| static void remove_states (vec<state *> *states); | |
| /* Remove all states from the states' vector and release the vector. */ | |
| static void clear_states (vec<state *> *states); | |
| /* Removes all variables added to the state. */ | |
| void clear_var_states (); | |
| /* Removes all conditions added to the state. */ | |
| void clear_conditions (); | |
| /* Adds the given condition to the state. */ | |
| bool add_condition (bit_expression *cond); | |
| /* Bulk add the given conditions to the state. */ | |
| bool bulk_add_conditions (const hash_set<bit_expression *> &conds); | |
| /* Get value of the given variable. */ | |
| value *get_value (tree var); | |
| /* Get the value of the tree, which is in the beginning of the var_states. */ | |
| value *get_first_value (); | |
| /* Returns the list of conditions in the state. */ | |
| const hash_set<bit_expression *> &get_conditions (); | |
| /* Adds a variable with unknown value to state. Such variables are | |
| represented as sequence of symbolic bits. */ | |
| bool make_symbolic (tree var, unsigned size); | |
| /* Returns size of the given variable. */ | |
| unsigned get_var_size (tree var); | |
| /* Prints the given value. */ | |
| static void print_value (value *var); | |
| /* Prints added conditions. */ | |
| void print_conditions (); | |
| /* Returns the number represented by the value. */ | |
| static unsigned HOST_WIDE_INT | |
| make_number (const value *var); | |
| /* Checks if all bits of the given value have constant bit type. */ | |
| static bool is_bit_vector (const value *var); | |
| /* Performs the specified operation on passed variables. */ | |
| bool do_operation (tree_code op_code, tree arg1, tree arg2, tree dest); | |
| /* Does Assignment. */ | |
| bool do_assign (tree arg, tree dest); | |
| /* Assigns pow 2 value. */ | |
| bool do_assign_pow2 (tree dest, unsigned pow); | |
| /* Negates given variable. */ | |
| bool do_complement (tree arg, tree dest); | |
| /* Adds EQUAL condition of given variables to state. */ | |
| bool add_equal_cond (tree arg1, tree arg2); | |
| /* Adds NOT EQUAL condition of given variables to state. */ | |
| bool add_not_equal_cond (tree arg1, tree arg2); | |
| /* Adds GREATER THAN condition of given variables to state. */ | |
| bool add_greater_than_cond (tree arg1, tree arg2); | |
| /* Adds LESS THAN condition of given variables to state. */ | |
| bool add_less_than_cond (tree arg1, tree arg2); | |
| /* Adds GREATER OR EQUAL condition of given variables to state. */ | |
| bool add_greater_or_equal_cond (tree arg1, tree arg2); | |
| /* Adds LESS OR EQUAL condition of given variables to state. */ | |
| bool add_less_or_equal_cond (tree arg1, tree arg2); | |
| /* Adds a bool condition to state. */ | |
| bool add_bool_cond (tree arg); | |
| /* Checks whether the given two constant values are equal. */ | |
| static bool check_const_value_equality (value *arg1, value *arg2); | |
| /* Checks whether the given two constant values are not equal. */ | |
| static bool check_const_value_are_not_equal (value *arg1, value *arg2); | |
| /* Checks whether the first given constant value | |
| is greater than the second one. */ | |
| static bool check_const_value_is_greater_than (value *arg1, value *arg2); | |
| /* Checks whether the first given constant value | |
| is less than the second one. */ | |
| static bool check_const_value_is_less_than (value *arg1, value *arg2); | |
| /* For the given value_bit, iterates over its expression tree, complements | |
| those bit which came from the given origin. */ | |
| static value_bit *complement_bits_with_origin (value_bit *root, tree origin); | |
| /* Iterates over every bit of the given value and complements their | |
| expression trees' those bits, that came from the given origin. */ | |
| static void complement_val_bits_with_origin (value *val, tree origin); | |
| /* Complements all bits of all values that came from the given origin. */ | |
| void complement_all_vars_bits_with_origin (tree origin); | |
| /* Complements all bits with the given origin of all added conditions. */ | |
| void complement_conditions_with_origin (tree origin); | |
| /* Complements all bits with the given origin of all values | |
| and added conditions. */ | |
| void complement_state_with_origin (tree origin); | |
| /* Returns status of last added condition. */ | |
| condition_status get_last_cond_status (); | |
| /* Create LFSR value. */ | |
| static value *create_lfsr (tree crc, value *polynomial, bool is_bit_forward); | |
| }; | |
| /* Returns the minimum of A, B, C. */ | |
| size_t min (size_t a, size_t b, size_t c); | |
| /* Performs the given operation on passed arguments. | |
| The result is stored in dest. */ | |
| template<class func> | |
| void | |
| state::operate (value *arg1, value *arg2, value_bit **bit_arg, tree dest, | |
| func bit_op) | |
| { | |
| value *dest_var = var_states.get (dest); | |
| size_t min_iter = min (arg1->length (), arg2->length (), dest_var->length ()); | |
| size_t i = 0; | |
| for (; i < min_iter; i++) | |
| { | |
| value_bit *temp = (*var_states.get (dest))[i]; | |
| (*var_states.get (dest))[i] = operate_bits (bit_op, (*arg1)[i], | |
| (*arg2)[i], bit_arg); | |
| delete temp; | |
| } | |
| if (i >= dest_var->length ()) | |
| return; | |
| value *biggest = arg1; | |
| value_bit *sign_bit = (*arg2)[i - 1]; | |
| if (arg2->length () > arg1->length ()) | |
| { | |
| biggest = arg2; | |
| sign_bit = (*arg1)[i - 1]; | |
| } | |
| min_iter = min (biggest->length (), dest_var->length (), dest_var->length ()); | |
| for (; i < min_iter; i++) | |
| { | |
| value_bit *temp = (*var_states.get (dest))[i]; | |
| (*var_states.get (dest))[i] = operate_bits (bit_op, (*biggest)[i], | |
| sign_bit, bit_arg); | |
| delete temp; | |
| } | |
| if (i >= dest_var->length ()) | |
| return; | |
| sign_bit = (*biggest)[i - 1]; | |
| for (; i < dest_var->length (); i++) | |
| { | |
| value_bit *temp = (*var_states.get (dest))[i]; | |
| (*var_states.get (dest))[i] = operate_bits (bit_op, sign_bit, sign_bit, | |
| bit_arg); | |
| delete temp; | |
| } | |
| } | |
| #endif /* SYM_EXEC_STATE_H. */ |