aboutsummaryrefslogtreecommitdiff
path: root/gcc/sym-exec/state.h
blob: 1fe85f858058fc8257f5d3ac80128f0684cec66d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
/* 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.  */


#ifndef SYM_EXEC_STATE_H
#define SYM_EXEC_STATE_H

#define MAX_VALUE_SIZE 64

#include "expression-is-a-helper.h"

struct value {
 private:
  vec<value_bit *> number;

 public:
  const bool is_unsigned;

  value (unsigned size, bool is_unsigned);
  value (const value &other);
  value_bit **push (value_bit *elem);
  size_t length () const;
  value_bit *&last ();
  unsigned allocated () const;
  bool exists () const;
  value_bit *&operator[] (unsigned i);
  value &operator= (const value &other);
  value_bit *operator[] (unsigned i) const;
  ~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);

  static value_bit *operate_bits (bit_func bit_op, value_bit *bit1,
				  value_bit *bit2, value_bit **bit3);

  static value_bit *operate_bits (bit_func3 bit_op, value_bit *bit1,
				  value_bit *bit2, value_bit **bit3);

  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);

  void do_and (value *arg1, value *arg2, tree dest);

  void do_or (value *arg1, value *arg2, tree dest);

  void do_xor (value *arg1, value *arg2, tree dest);

  void do_shift_right (value *arg1, value *arg2, tree dest);

  void do_shift_left (value *arg1, value *arg2, tree dest);

  void do_add (value *arg1, value *arg2, tree dest);

  void do_sub (value *arg1, value *arg2, tree dest);

  /* Casts arg to cast_size size, stores value in dest.  */
  bool do_cast (tree arg, tree dest, size_t cast_size);

  /* Performs AND operation on two values.  */
  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);

  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);

  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);

  /* Checks if all bits of the given value have constant bit type.  */
  bool is_bit_vector (const value *var);

  /* 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);

  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:
  state () = default;

  ~state ();

  /* Adds an empty state for the given variable.  */
  bool decl_var (tree name, unsigned size);

  state (const state &s);

  bool add_var_state (tree var, value *state);

  static void clear_states (vec<state *> *states);

  void clear_var_states ();

  void clear_conditions ();

  bool add_condition (bit_expression *cond);

  bool bulk_add_conditions (const hash_set<bit_expression *> &conds);

  value *get_value (tree var);

  /* Get the value of the tree, which is in the beginning of the var_states.  */
  value *get_first_value ();

  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);

  /* Does bit-level XOR operation for given variables.  */
  bool do_xor (tree arg1, tree arg2, tree dest);

  /* Does bit-level AND operation for given variables.  */
  bool do_and (tree arg1, tree arg2, tree dest);

  /* Does bit-level OR operation for given variables.  */
  bool do_or (tree arg1, tree arg2, tree dest);

  bool do_assign (tree arg, tree dest);

  /* Assigns pow 2 value.  */
  bool do_assign_pow2 (tree dest, unsigned pow);

  /* Does shift_left operation for given variables.  */
  bool do_shift_left (tree arg1, tree arg2, tree dest);

  /* Does shift_right operation for given variables.  */
  bool do_shift_right (tree arg1, tree arg2, tree dest);

  /* Adds two variables.  */
  bool do_add (tree arg1, tree arg2, tree dest);

  /* Does subtraction.  */
  bool do_sub (tree arg1, tree arg2, tree dest);

  /* Multiplies two variables, stores result in dest.  */
  bool do_mul (tree arg1, tree arg2, tree dest);

  /* Negates given variable.  */
  bool do_complement (tree arg, tree dest);

  bool add_equal_cond (tree arg1, tree arg2);

  /* Gets the value of *arg1 and stores it in dest.  */
  bool do_mem_ref (tree arg1, tree dest);

  /* Performs addition on arg1 pointer.  */
  bool do_pointer_plus (tree arg1, tree arg2, tree dest);

  /* Perform subtractions on arg1 pointer.  */
  bool do_pointer_diff (tree arg1, tree arg2, tree dest);

  bool add_not_equal_cond (tree arg1, tree arg2);

  bool add_greater_than_cond (tree arg1, tree arg2);

  bool add_less_than_cond (tree arg1, tree arg2);

  bool add_greater_or_equal_cond (tree arg1, tree arg2);

  bool add_less_or_equal_cond (tree arg1, tree arg2);

  bool add_bool_cond (tree arg);

  static bool check_const_value_equality (value *arg1, value *arg2);

  static bool check_const_value_are_not_equal (value *arg1, value *arg2);

  static bool check_const_value_is_greater_than (value *arg1, value *arg2);

  static bool check_const_value_is_less_than (value *arg1, value *arg2);

  static value_bit *complement_bits_with_origin (value_bit *root, tree origin);

  static void complement_val_bits_with_origin (value *val, tree origin);

  void complement_all_vars_bits_with_origin (tree origin);

  void complement_conditions_with_origin (tree origin);

  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);
};


size_t min (size_t a, size_t b, size_t c);


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.  */