blob: c2028355c762f0f4482c29cc9426299cfa93a6d2 [file] [log] [blame]
/* 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-2025 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, stroes 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.
Resturn 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. */