/* Insert a call to the runtime function "__slimer_add_fn" which will add the
* "junk" function created at compile-time to an array at runtime
*/
static void insert_add_fn(gimple stmt, int index)
{
tree fn;
gimple call;
gimple_stmt_iterator gsi;
static tree decl, proto, idx;
if (!decl || !proto)
{
proto = build_function_type_list(void_type_node, ptr_type_node,
integer_type_node, NULL_TREE);
decl = build_fn_decl("__slimer_add_fn", proto);
/* Add this fndecl to our list of things we do not process */
VEC_safe_push(tree, gc, analyized_fns, decl);
}
/* Create a constant value and pointer to the function we are to add */
idx = build_int_cst(integer_type_node, index);
fn = build_addr(VEC_index(tree, fakes, index), NULL_TREE);
call = gimple_build_call(decl, 2, fn, idx);
gsi = gsi_for_stmt(stmt);
gsi_insert_before(&gsi, call, GSI_NEW_STMT);
}
static bool
ifcombine_iforif (basic_block inner_cond_bb, basic_block outer_cond_bb)
{
gimple inner_cond, outer_cond;
tree name1, name2, bits1, bits2;
inner_cond = last_stmt (inner_cond_bb);
if (!inner_cond
|| gimple_code (inner_cond) != GIMPLE_COND)
return false;
outer_cond = last_stmt (outer_cond_bb);
if (!outer_cond
|| gimple_code (outer_cond) != GIMPLE_COND)
return false;
/* See if we have two bit tests of the same name in both tests.
In that case remove the outer test and change the inner one to
test for name & (bits1 | bits2) != 0. */
if (recognize_bits_test (inner_cond, &name1, &bits1)
&& recognize_bits_test (outer_cond, &name2, &bits2))
{
gimple_stmt_iterator gsi;
tree t;
/* Find the common name which is bit-tested. */
if (name1 == name2)
;
else if (bits1 == bits2)
{
t = name2;
name2 = bits2;
bits2 = t;
t = name1;
name1 = bits1;
bits1 = t;
}
else if (name1 == bits2)
{
t = name2;
name2 = bits2;
bits2 = t;
}
else if (bits1 == name2)
{
t = name1;
name1 = bits1;
bits1 = t;
}
else
return false;
/* As we strip non-widening conversions in finding a common
name that is tested make sure to end up with an integral
type for building the bit operations. */
if (TYPE_PRECISION (TREE_TYPE (bits1))
>= TYPE_PRECISION (TREE_TYPE (bits2)))
{
bits1 = fold_convert (unsigned_type_for (TREE_TYPE (bits1)), bits1);
name1 = fold_convert (TREE_TYPE (bits1), name1);
bits2 = fold_convert (unsigned_type_for (TREE_TYPE (bits2)), bits2);
bits2 = fold_convert (TREE_TYPE (bits1), bits2);
}
else
{
bits2 = fold_convert (unsigned_type_for (TREE_TYPE (bits2)), bits2);
name1 = fold_convert (TREE_TYPE (bits2), name1);
bits1 = fold_convert (unsigned_type_for (TREE_TYPE (bits1)), bits1);
bits1 = fold_convert (TREE_TYPE (bits2), bits1);
}
/* Do it. */
gsi = gsi_for_stmt (inner_cond);
t = fold_build2 (BIT_IOR_EXPR, TREE_TYPE (name1), bits1, bits2);
t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
true, GSI_SAME_STMT);
t = fold_build2 (BIT_AND_EXPR, TREE_TYPE (name1), name1, t);
t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
true, GSI_SAME_STMT);
t = fold_build2 (NE_EXPR, boolean_type_node, t,
build_int_cst (TREE_TYPE (t), 0));
gimple_cond_set_condition_from_tree (inner_cond, t);
update_stmt (inner_cond);
/* Leave CFG optimization to cfg_cleanup. */
gimple_cond_set_condition_from_tree (outer_cond, boolean_false_node);
update_stmt (outer_cond);
if (dump_file)
{
fprintf (dump_file, "optimizing bits or bits test to ");
print_generic_expr (dump_file, name1, 0);
fprintf (dump_file, " & T != 0\nwith temporary T = ");
print_generic_expr (dump_file, bits1, 0);
fprintf (dump_file, " | ");
print_generic_expr (dump_file, bits2, 0);
fprintf (dump_file, "\n");
}
return true;
//.........这里部分代码省略.........
static void
my_dump_gimple(gimple gnode, gimple_stmt_iterator *ptrgsi)
{
int gcode;
tree tnode;
tree funcdecl;
tree desc_node;
tree ptr_desc_node;
tree t;
tree tmp_var;
tree const_char_restrict_ptr_type_node;
gimple tmp_gstmt;
gimple new_gnode;
const char *hellocstr = "Hello, GCC!\n";
int i;
struct c_binding *b;
expanded_location xloc;
/*
* Extract the Gimple Code from a gimple node
*/
gcode = gimple_code(gnode);
/*
* Get the line number of cooresponding
* source code from a gimple node
*/
if(gimple_has_location(gnode))
{
xloc = expand_location(gimple_location(gnode));
printf("line %d:", xloc.line);
}
printf("\t\t\t\t%s\n", gimple_code_name[gcode]);
switch(gcode)
{
case GIMPLE_ASSIGN:
/*
* Add a printf("Hello, GCC!\n"); statement
* after the first appearing assignment
* if yes equals to 1, then we have already
* added the statement, and no need to add
* again
*/
if(!yes)
{
/*
* Since printf is a builtin function, we need
* to get the function declaration using
* built_in_decls[]. The index number can be
* found in gcc source gcc/builtins.def
*/
funcdecl = built_in_decls[BUILT_IN_PRINTF];
if(funcdecl == NULL_TREE)
{
printf("cannot find printf\n");
}
else
{
/*
* In gimple, every statement is simplified into
* three oprands mode. And our printf() statement
* is change into following two gimple statements:
*
* <D.XXX> = (const char * restrict) &"Hello, GCC!\n"[0]
* printf(<D.XXX>);
*
* Note that <D.XXX> is a temporary variable, we can
* actually use any name we like as long as no
* confliction.
*/
/*
* Generate a STRING_CST, the value is "Hello, GCC!\n"
*/
desc_node = build_string(strlen(hellocstr), hellocstr);
/*
* Two points need to notice here:
* 1. STRING_CST build by build_string() do
* not have TREE_TYPE set, so we need to
* set it manually.
* 2. build_string() will add a trailing '\0'
* when building the STRING_CST, so we do
* not need to care with it.
*/
TREE_TYPE(desc_node) = build_array_type(
char_type_node,
build_index_type(
build_int_cst(NULL_TREE,
strlen(hellocstr))));
/*
* Define a const char * restrict type node
* here for convertion.
* I'm not sure why we need to add a restrict
* attribute, but GCC really does it when it
* converting a STRING_CST from AST to Gimple.
//.........这里部分代码省略.........
tree
ubsan_instrument_division (location_t loc, tree op0, tree op1)
{
tree t, tt;
tree type = TREE_TYPE (op0);
/* At this point both operands should have the same type,
because they are already converted to RESULT_TYPE.
Use TYPE_MAIN_VARIANT since typedefs can confuse us. */
gcc_assert (TYPE_MAIN_VARIANT (TREE_TYPE (op0))
== TYPE_MAIN_VARIANT (TREE_TYPE (op1)));
op0 = unshare_expr (op0);
op1 = unshare_expr (op1);
if (TREE_CODE (type) == INTEGER_TYPE
&& (flag_sanitize & SANITIZE_DIVIDE))
t = fold_build2 (EQ_EXPR, boolean_type_node,
op1, build_int_cst (type, 0));
else if (TREE_CODE (type) == REAL_TYPE
&& (flag_sanitize & SANITIZE_FLOAT_DIVIDE))
t = fold_build2 (EQ_EXPR, boolean_type_node,
op1, build_real (type, dconst0));
else
return NULL_TREE;
/* We check INT_MIN / -1 only for signed types. */
if (TREE_CODE (type) == INTEGER_TYPE
&& (flag_sanitize & SANITIZE_DIVIDE)
&& !TYPE_UNSIGNED (type))
{
tree x;
tt = fold_build2 (EQ_EXPR, boolean_type_node, unshare_expr (op1),
build_int_cst (type, -1));
x = fold_build2 (EQ_EXPR, boolean_type_node, op0,
TYPE_MIN_VALUE (type));
x = fold_build2 (TRUTH_AND_EXPR, boolean_type_node, x, tt);
t = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, t, x);
}
/* If the condition was folded to 0, no need to instrument
this expression. */
if (integer_zerop (t))
return NULL_TREE;
/* In case we have a SAVE_EXPR in a conditional context, we need to
make sure it gets evaluated before the condition. */
t = fold_build2 (COMPOUND_EXPR, TREE_TYPE (t), unshare_expr (op0), t);
t = fold_build2 (COMPOUND_EXPR, TREE_TYPE (t), unshare_expr (op1), t);
if (flag_sanitize_undefined_trap_on_error)
tt = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
else
{
tree data = ubsan_create_data ("__ubsan_overflow_data", 1, &loc,
ubsan_type_descriptor (type), NULL_TREE,
NULL_TREE);
data = build_fold_addr_expr_loc (loc, data);
enum built_in_function bcode
= (flag_sanitize_recover & SANITIZE_DIVIDE)
? BUILT_IN_UBSAN_HANDLE_DIVREM_OVERFLOW
: BUILT_IN_UBSAN_HANDLE_DIVREM_OVERFLOW_ABORT;
tt = builtin_decl_explicit (bcode);
op0 = unshare_expr (op0);
op1 = unshare_expr (op1);
tt = build_call_expr_loc (loc, tt, 3, data, ubsan_encode_value (op0),
ubsan_encode_value (op1));
}
t = fold_build3 (COND_EXPR, void_type_node, t, tt, void_node);
return t;
}
tree
ubsan_instrument_bounds (location_t loc, tree array, tree *index,
bool ignore_off_by_one)
{
tree type = TREE_TYPE (array);
tree domain = TYPE_DOMAIN (type);
if (domain == NULL_TREE || TYPE_MAX_VALUE (domain) == NULL_TREE)
return NULL_TREE;
tree bound = TYPE_MAX_VALUE (domain);
if (ignore_off_by_one)
bound = fold_build2 (PLUS_EXPR, TREE_TYPE (bound), bound,
build_int_cst (TREE_TYPE (bound), 1));
/* Detect flexible array members and suchlike, unless
-fsanitize=bounds-strict. */
tree base = get_base_address (array);
if ((flag_sanitize & SANITIZE_BOUNDS_STRICT) == 0
&& TREE_CODE (array) == COMPONENT_REF
&& base && (INDIRECT_REF_P (base) || TREE_CODE (base) == MEM_REF))
{
tree next = NULL_TREE;
tree cref = array;
/* Walk all structs/unions. */
while (TREE_CODE (cref) == COMPONENT_REF)
{
if (TREE_CODE (TREE_TYPE (TREE_OPERAND (cref, 0))) == RECORD_TYPE)
for (next = DECL_CHAIN (TREE_OPERAND (cref, 1));
next && TREE_CODE (next) != FIELD_DECL;
next = DECL_CHAIN (next))
;
if (next)
/* Not a last element. Instrument it. */
break;
/* Ok, this is the last field of the structure/union. But the
aggregate containing the field must be the last field too,
recursively. */
cref = TREE_OPERAND (cref, 0);
}
if (!next)
/* Don't instrument this flexible array member-like array in non-strict
-fsanitize=bounds mode. */
return NULL_TREE;
}
/* Don't emit instrumentation in the most common cases. */
tree idx = NULL_TREE;
if (TREE_CODE (*index) == INTEGER_CST)
idx = *index;
else if (TREE_CODE (*index) == BIT_AND_EXPR
&& TREE_CODE (TREE_OPERAND (*index, 1)) == INTEGER_CST)
idx = TREE_OPERAND (*index, 1);
if (idx
&& TREE_CODE (bound) == INTEGER_CST
&& tree_int_cst_sgn (idx) >= 0
&& tree_int_cst_le (idx, bound))
return NULL_TREE;
*index = save_expr (*index);
/* Create a "(T *) 0" tree node to describe the array type. */
tree zero_with_type = build_int_cst (build_pointer_type (type), 0);
return build_call_expr_internal_loc (loc, IFN_UBSAN_BOUNDS,
void_type_node, 3, zero_with_type,
*index, bound);
}
请发表评论