0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078 #include "gcc-common.h"
0079
0080 __visible int plugin_is_GPL_compatible;
0081
0082 static GTY(()) tree latent_entropy_decl;
0083
0084 static struct plugin_info latent_entropy_plugin_info = {
0085 .version = PLUGIN_VERSION,
0086 .help = "disable\tturn off latent entropy instrumentation\n",
0087 };
0088
0089 static unsigned HOST_WIDE_INT deterministic_seed;
0090 static unsigned HOST_WIDE_INT rnd_buf[32];
0091 static size_t rnd_idx = ARRAY_SIZE(rnd_buf);
0092 static int urandom_fd = -1;
0093
0094 static unsigned HOST_WIDE_INT get_random_const(void)
0095 {
0096 if (deterministic_seed) {
0097 unsigned HOST_WIDE_INT w = deterministic_seed;
0098 w ^= w << 13;
0099 w ^= w >> 7;
0100 w ^= w << 17;
0101 deterministic_seed = w;
0102 return deterministic_seed;
0103 }
0104
0105 if (urandom_fd < 0) {
0106 urandom_fd = open("/dev/urandom", O_RDONLY);
0107 gcc_assert(urandom_fd >= 0);
0108 }
0109 if (rnd_idx >= ARRAY_SIZE(rnd_buf)) {
0110 gcc_assert(read(urandom_fd, rnd_buf, sizeof(rnd_buf)) == sizeof(rnd_buf));
0111 rnd_idx = 0;
0112 }
0113 return rnd_buf[rnd_idx++];
0114 }
0115
0116 static tree tree_get_random_const(tree type)
0117 {
0118 unsigned long long mask;
0119
0120 mask = 1ULL << (TREE_INT_CST_LOW(TYPE_SIZE(type)) - 1);
0121 mask = 2 * (mask - 1) + 1;
0122
0123 if (TYPE_UNSIGNED(type))
0124 return build_int_cstu(type, mask & get_random_const());
0125 return build_int_cst(type, mask & get_random_const());
0126 }
0127
0128 static tree handle_latent_entropy_attribute(tree *node, tree name,
0129 tree args __unused,
0130 int flags __unused,
0131 bool *no_add_attrs)
0132 {
0133 tree type;
0134 vec<constructor_elt, va_gc> *vals;
0135
0136 switch (TREE_CODE(*node)) {
0137 default:
0138 *no_add_attrs = true;
0139 error("%qE attribute only applies to functions and variables",
0140 name);
0141 break;
0142
0143 case VAR_DECL:
0144 if (DECL_INITIAL(*node)) {
0145 *no_add_attrs = true;
0146 error("variable %qD with %qE attribute must not be initialized",
0147 *node, name);
0148 break;
0149 }
0150
0151 if (!TREE_STATIC(*node)) {
0152 *no_add_attrs = true;
0153 error("variable %qD with %qE attribute must not be local",
0154 *node, name);
0155 break;
0156 }
0157
0158 type = TREE_TYPE(*node);
0159 switch (TREE_CODE(type)) {
0160 default:
0161 *no_add_attrs = true;
0162 error("variable %qD with %qE attribute must be an integer or a fixed length integer array type or a fixed sized structure with integer fields",
0163 *node, name);
0164 break;
0165
0166 case RECORD_TYPE: {
0167 tree fld, lst = TYPE_FIELDS(type);
0168 unsigned int nelt = 0;
0169
0170 for (fld = lst; fld; nelt++, fld = TREE_CHAIN(fld)) {
0171 tree fieldtype;
0172
0173 fieldtype = TREE_TYPE(fld);
0174 if (TREE_CODE(fieldtype) == INTEGER_TYPE)
0175 continue;
0176
0177 *no_add_attrs = true;
0178 error("structure variable %qD with %qE attribute has a non-integer field %qE",
0179 *node, name, fld);
0180 break;
0181 }
0182
0183 if (fld)
0184 break;
0185
0186 vec_alloc(vals, nelt);
0187
0188 for (fld = lst; fld; fld = TREE_CHAIN(fld)) {
0189 tree random_const, fld_t = TREE_TYPE(fld);
0190
0191 random_const = tree_get_random_const(fld_t);
0192 CONSTRUCTOR_APPEND_ELT(vals, fld, random_const);
0193 }
0194
0195
0196 DECL_INITIAL(*node) = build_constructor(type, vals);
0197 break;
0198 }
0199
0200
0201 case INTEGER_TYPE:
0202 DECL_INITIAL(*node) = tree_get_random_const(type);
0203 break;
0204
0205 case ARRAY_TYPE: {
0206 tree elt_type, array_size, elt_size;
0207 unsigned int i, nelt;
0208 HOST_WIDE_INT array_size_int, elt_size_int;
0209
0210 elt_type = TREE_TYPE(type);
0211 elt_size = TYPE_SIZE_UNIT(TREE_TYPE(type));
0212 array_size = TYPE_SIZE_UNIT(type);
0213
0214 if (TREE_CODE(elt_type) != INTEGER_TYPE || !array_size
0215 || TREE_CODE(array_size) != INTEGER_CST) {
0216 *no_add_attrs = true;
0217 error("array variable %qD with %qE attribute must be a fixed length integer array type",
0218 *node, name);
0219 break;
0220 }
0221
0222 array_size_int = TREE_INT_CST_LOW(array_size);
0223 elt_size_int = TREE_INT_CST_LOW(elt_size);
0224 nelt = array_size_int / elt_size_int;
0225
0226 vec_alloc(vals, nelt);
0227
0228 for (i = 0; i < nelt; i++) {
0229 tree cst = size_int(i);
0230 tree rand_cst = tree_get_random_const(elt_type);
0231
0232 CONSTRUCTOR_APPEND_ELT(vals, cst, rand_cst);
0233 }
0234
0235
0236
0237
0238
0239 DECL_INITIAL(*node) = build_constructor(type, vals);
0240 break;
0241 }
0242 }
0243 break;
0244
0245 case FUNCTION_DECL:
0246 break;
0247 }
0248
0249 return NULL_TREE;
0250 }
0251
0252 static struct attribute_spec latent_entropy_attr = { };
0253
0254 static void register_attributes(void *event_data __unused, void *data __unused)
0255 {
0256 latent_entropy_attr.name = "latent_entropy";
0257 latent_entropy_attr.decl_required = true;
0258 latent_entropy_attr.handler = handle_latent_entropy_attribute;
0259
0260 register_attribute(&latent_entropy_attr);
0261 }
0262
0263 static bool latent_entropy_gate(void)
0264 {
0265 tree list;
0266
0267
0268 if (TREE_THIS_VOLATILE(current_function_decl))
0269 return false;
0270
0271
0272 if (EDGE_COUNT(EXIT_BLOCK_PTR_FOR_FN(cfun)->preds) == 0)
0273 return false;
0274
0275 list = DECL_ATTRIBUTES(current_function_decl);
0276 return lookup_attribute("latent_entropy", list) != NULL_TREE;
0277 }
0278
0279 static tree create_var(tree type, const char *name)
0280 {
0281 tree var;
0282
0283 var = create_tmp_var(type, name);
0284 add_referenced_var(var);
0285 mark_sym_for_renaming(var);
0286 return var;
0287 }
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301 static enum tree_code get_op(tree *rhs)
0302 {
0303 static enum tree_code op;
0304 unsigned HOST_WIDE_INT random_const;
0305
0306 random_const = get_random_const();
0307
0308 switch (op) {
0309 case BIT_XOR_EXPR:
0310 op = PLUS_EXPR;
0311 break;
0312
0313 case PLUS_EXPR:
0314 if (rhs) {
0315 op = LROTATE_EXPR;
0316
0317
0318
0319
0320 random_const %= TYPE_PRECISION(long_unsigned_type_node);
0321 break;
0322 }
0323
0324 case LROTATE_EXPR:
0325 default:
0326 op = BIT_XOR_EXPR;
0327 break;
0328 }
0329 if (rhs)
0330 *rhs = build_int_cstu(long_unsigned_type_node, random_const);
0331 return op;
0332 }
0333
0334 static gimple create_assign(enum tree_code code, tree lhs, tree op1,
0335 tree op2)
0336 {
0337 return gimple_build_assign_with_ops(code, lhs, op1, op2);
0338 }
0339
0340 static void perturb_local_entropy(basic_block bb, tree local_entropy)
0341 {
0342 gimple_stmt_iterator gsi;
0343 gimple assign;
0344 tree rhs;
0345 enum tree_code op;
0346
0347 op = get_op(&rhs);
0348 assign = create_assign(op, local_entropy, local_entropy, rhs);
0349 gsi = gsi_after_labels(bb);
0350 gsi_insert_before(&gsi, assign, GSI_NEW_STMT);
0351 update_stmt(assign);
0352 }
0353
0354 static void __perturb_latent_entropy(gimple_stmt_iterator *gsi,
0355 tree local_entropy)
0356 {
0357 gimple assign;
0358 tree temp;
0359 enum tree_code op;
0360
0361
0362 temp = create_var(long_unsigned_type_node, "temp_latent_entropy");
0363
0364
0365 add_referenced_var(latent_entropy_decl);
0366 mark_sym_for_renaming(latent_entropy_decl);
0367 assign = gimple_build_assign(temp, latent_entropy_decl);
0368 gsi_insert_before(gsi, assign, GSI_NEW_STMT);
0369 update_stmt(assign);
0370
0371
0372 op = get_op(NULL);
0373 assign = create_assign(op, temp, temp, local_entropy);
0374 gsi_insert_after(gsi, assign, GSI_NEW_STMT);
0375 update_stmt(assign);
0376
0377
0378 assign = gimple_build_assign(latent_entropy_decl, temp);
0379 gsi_insert_after(gsi, assign, GSI_NEW_STMT);
0380 update_stmt(assign);
0381 }
0382
0383 static bool handle_tail_calls(basic_block bb, tree local_entropy)
0384 {
0385 gimple_stmt_iterator gsi;
0386
0387 for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) {
0388 gcall *call;
0389 gimple stmt = gsi_stmt(gsi);
0390
0391 if (!is_gimple_call(stmt))
0392 continue;
0393
0394 call = as_a_gcall(stmt);
0395 if (!gimple_call_tail_p(call))
0396 continue;
0397
0398 __perturb_latent_entropy(&gsi, local_entropy);
0399 return true;
0400 }
0401
0402 return false;
0403 }
0404
0405 static void perturb_latent_entropy(tree local_entropy)
0406 {
0407 edge_iterator ei;
0408 edge e, last_bb_e;
0409 basic_block last_bb;
0410
0411 gcc_assert(single_pred_p(EXIT_BLOCK_PTR_FOR_FN(cfun)));
0412 last_bb_e = single_pred_edge(EXIT_BLOCK_PTR_FOR_FN(cfun));
0413
0414 FOR_EACH_EDGE(e, ei, last_bb_e->src->preds) {
0415 if (ENTRY_BLOCK_PTR_FOR_FN(cfun) == e->src)
0416 continue;
0417 if (EXIT_BLOCK_PTR_FOR_FN(cfun) == e->src)
0418 continue;
0419
0420 handle_tail_calls(e->src, local_entropy);
0421 }
0422
0423 last_bb = single_pred(EXIT_BLOCK_PTR_FOR_FN(cfun));
0424 if (!handle_tail_calls(last_bb, local_entropy)) {
0425 gimple_stmt_iterator gsi = gsi_last_bb(last_bb);
0426
0427 __perturb_latent_entropy(&gsi, local_entropy);
0428 }
0429 }
0430
0431 static void init_local_entropy(basic_block bb, tree local_entropy)
0432 {
0433 gimple assign, call;
0434 tree frame_addr, rand_const, tmp, fndecl, udi_frame_addr;
0435 enum tree_code op;
0436 unsigned HOST_WIDE_INT rand_cst;
0437 gimple_stmt_iterator gsi = gsi_after_labels(bb);
0438
0439
0440 frame_addr = create_var(ptr_type_node, "local_entropy_frameaddr");
0441
0442
0443 fndecl = builtin_decl_implicit(BUILT_IN_FRAME_ADDRESS);
0444 call = gimple_build_call(fndecl, 1, integer_zero_node);
0445 gimple_call_set_lhs(call, frame_addr);
0446 gsi_insert_before(&gsi, call, GSI_NEW_STMT);
0447 update_stmt(call);
0448
0449 udi_frame_addr = fold_convert(long_unsigned_type_node, frame_addr);
0450 assign = gimple_build_assign(local_entropy, udi_frame_addr);
0451 gsi_insert_after(&gsi, assign, GSI_NEW_STMT);
0452 update_stmt(assign);
0453
0454
0455 tmp = create_var(long_unsigned_type_node, "temp_latent_entropy");
0456
0457
0458 add_referenced_var(latent_entropy_decl);
0459 mark_sym_for_renaming(latent_entropy_decl);
0460 assign = gimple_build_assign(tmp, latent_entropy_decl);
0461 gsi_insert_after(&gsi, assign, GSI_NEW_STMT);
0462 update_stmt(assign);
0463
0464
0465 assign = create_assign(BIT_XOR_EXPR, local_entropy, local_entropy, tmp);
0466 gsi_insert_after(&gsi, assign, GSI_NEW_STMT);
0467 update_stmt(assign);
0468
0469 rand_cst = get_random_const();
0470 rand_const = build_int_cstu(long_unsigned_type_node, rand_cst);
0471 op = get_op(NULL);
0472 assign = create_assign(op, local_entropy, local_entropy, rand_const);
0473 gsi_insert_after(&gsi, assign, GSI_NEW_STMT);
0474 update_stmt(assign);
0475 }
0476
0477 static bool create_latent_entropy_decl(void)
0478 {
0479 varpool_node_ptr node;
0480
0481 if (latent_entropy_decl != NULL_TREE)
0482 return true;
0483
0484 FOR_EACH_VARIABLE(node) {
0485 tree name, var = NODE_DECL(node);
0486
0487 if (DECL_NAME_LENGTH(var) < sizeof("latent_entropy") - 1)
0488 continue;
0489
0490 name = DECL_NAME(var);
0491 if (strcmp(IDENTIFIER_POINTER(name), "latent_entropy"))
0492 continue;
0493
0494 latent_entropy_decl = var;
0495 break;
0496 }
0497
0498 return latent_entropy_decl != NULL_TREE;
0499 }
0500
0501 static unsigned int latent_entropy_execute(void)
0502 {
0503 basic_block bb;
0504 tree local_entropy;
0505
0506 if (!create_latent_entropy_decl())
0507 return 0;
0508
0509
0510 gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun)));
0511 bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun));
0512 if (!single_pred_p(bb)) {
0513 split_edge(single_succ_edge(ENTRY_BLOCK_PTR_FOR_FN(cfun)));
0514 gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun)));
0515 bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun));
0516 }
0517
0518
0519 local_entropy = create_var(long_unsigned_type_node, "local_entropy");
0520
0521
0522 init_local_entropy(bb, local_entropy);
0523
0524 bb = bb->next_bb;
0525
0526
0527
0528
0529
0530 while (bb != EXIT_BLOCK_PTR_FOR_FN(cfun)) {
0531 perturb_local_entropy(bb, local_entropy);
0532 bb = bb->next_bb;
0533 }
0534
0535
0536 perturb_latent_entropy(local_entropy);
0537 return 0;
0538 }
0539
0540 static void latent_entropy_start_unit(void *gcc_data __unused,
0541 void *user_data __unused)
0542 {
0543 tree type, id;
0544 int quals;
0545
0546 if (in_lto_p)
0547 return;
0548
0549
0550 quals = TYPE_QUALS(long_unsigned_type_node) | TYPE_QUAL_VOLATILE;
0551 type = build_qualified_type(long_unsigned_type_node, quals);
0552 id = get_identifier("latent_entropy");
0553 latent_entropy_decl = build_decl(UNKNOWN_LOCATION, VAR_DECL, id, type);
0554
0555 TREE_STATIC(latent_entropy_decl) = 1;
0556 TREE_PUBLIC(latent_entropy_decl) = 1;
0557 TREE_USED(latent_entropy_decl) = 1;
0558 DECL_PRESERVE_P(latent_entropy_decl) = 1;
0559 TREE_THIS_VOLATILE(latent_entropy_decl) = 1;
0560 DECL_EXTERNAL(latent_entropy_decl) = 1;
0561 DECL_ARTIFICIAL(latent_entropy_decl) = 1;
0562 lang_hooks.decls.pushdecl(latent_entropy_decl);
0563 }
0564
0565 #define PASS_NAME latent_entropy
0566 #define PROPERTIES_REQUIRED PROP_gimple_leh | PROP_cfg
0567 #define TODO_FLAGS_FINISH TODO_verify_ssa | TODO_verify_stmts | TODO_dump_func \
0568 | TODO_update_ssa
0569 #include "gcc-generate-gimple-pass.h"
0570
0571 __visible int plugin_init(struct plugin_name_args *plugin_info,
0572 struct plugin_gcc_version *version)
0573 {
0574 bool enabled = true;
0575 const char * const plugin_name = plugin_info->base_name;
0576 const int argc = plugin_info->argc;
0577 const struct plugin_argument * const argv = plugin_info->argv;
0578 int i;
0579
0580
0581
0582
0583
0584 deterministic_seed = get_random_seed(true);
0585
0586 static const struct ggc_root_tab gt_ggc_r_gt_latent_entropy[] = {
0587 {
0588 .base = &latent_entropy_decl,
0589 .nelt = 1,
0590 .stride = sizeof(latent_entropy_decl),
0591 .cb = >_ggc_mx_tree_node,
0592 .pchw = >_pch_nx_tree_node
0593 },
0594 LAST_GGC_ROOT_TAB
0595 };
0596
0597 PASS_INFO(latent_entropy, "optimized", 1, PASS_POS_INSERT_BEFORE);
0598
0599 if (!plugin_default_version_check(version, &gcc_version)) {
0600 error(G_("incompatible gcc/plugin versions"));
0601 return 1;
0602 }
0603
0604 for (i = 0; i < argc; ++i) {
0605 if (!(strcmp(argv[i].key, "disable"))) {
0606 enabled = false;
0607 continue;
0608 }
0609 error(G_("unknown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key);
0610 }
0611
0612 register_callback(plugin_name, PLUGIN_INFO, NULL,
0613 &latent_entropy_plugin_info);
0614 if (enabled) {
0615 register_callback(plugin_name, PLUGIN_START_UNIT,
0616 &latent_entropy_start_unit, NULL);
0617 register_callback(plugin_name, PLUGIN_REGISTER_GGC_ROOTS,
0618 NULL, (void *)>_ggc_r_gt_latent_entropy);
0619 register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL,
0620 &latent_entropy_pass_info);
0621 }
0622 register_callback(plugin_name, PLUGIN_ATTRIBUTES, register_attributes,
0623 NULL);
0624
0625 return 0;
0626 }