18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright 2012-2016 by the PaX Team <pageexec@freemail.hu> 38c2ecf20Sopenharmony_ci * Copyright 2016 by Emese Revfy <re.emese@gmail.com> 48c2ecf20Sopenharmony_ci * Licensed under the GPL v2 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Note: the choice of the license means that the compilation process is 78c2ecf20Sopenharmony_ci * NOT 'eligible' as defined by gcc's library exception to the GPL v3, 88c2ecf20Sopenharmony_ci * but for the kernel it doesn't matter since it doesn't link against 98c2ecf20Sopenharmony_ci * any of the gcc libraries 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * This gcc plugin helps generate a little bit of entropy from program state, 128c2ecf20Sopenharmony_ci * used throughout the uptime of the kernel. Here is an instrumentation example: 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * before: 158c2ecf20Sopenharmony_ci * void __latent_entropy test(int argc, char *argv[]) 168c2ecf20Sopenharmony_ci * { 178c2ecf20Sopenharmony_ci * if (argc <= 1) 188c2ecf20Sopenharmony_ci * printf("%s: no command arguments :(\n", *argv); 198c2ecf20Sopenharmony_ci * else 208c2ecf20Sopenharmony_ci * printf("%s: %d command arguments!\n", *argv, args - 1); 218c2ecf20Sopenharmony_ci * } 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * after: 248c2ecf20Sopenharmony_ci * void __latent_entropy test(int argc, char *argv[]) 258c2ecf20Sopenharmony_ci * { 268c2ecf20Sopenharmony_ci * // latent_entropy_execute() 1. 278c2ecf20Sopenharmony_ci * unsigned long local_entropy; 288c2ecf20Sopenharmony_ci * // init_local_entropy() 1. 298c2ecf20Sopenharmony_ci * void *local_entropy_frameaddr; 308c2ecf20Sopenharmony_ci * // init_local_entropy() 3. 318c2ecf20Sopenharmony_ci * unsigned long tmp_latent_entropy; 328c2ecf20Sopenharmony_ci * 338c2ecf20Sopenharmony_ci * // init_local_entropy() 2. 348c2ecf20Sopenharmony_ci * local_entropy_frameaddr = __builtin_frame_address(0); 358c2ecf20Sopenharmony_ci * local_entropy = (unsigned long) local_entropy_frameaddr; 368c2ecf20Sopenharmony_ci * 378c2ecf20Sopenharmony_ci * // init_local_entropy() 4. 388c2ecf20Sopenharmony_ci * tmp_latent_entropy = latent_entropy; 398c2ecf20Sopenharmony_ci * // init_local_entropy() 5. 408c2ecf20Sopenharmony_ci * local_entropy ^= tmp_latent_entropy; 418c2ecf20Sopenharmony_ci * 428c2ecf20Sopenharmony_ci * // latent_entropy_execute() 3. 438c2ecf20Sopenharmony_ci * if (argc <= 1) { 448c2ecf20Sopenharmony_ci * // perturb_local_entropy() 458c2ecf20Sopenharmony_ci * local_entropy += 4623067384293424948; 468c2ecf20Sopenharmony_ci * printf("%s: no command arguments :(\n", *argv); 478c2ecf20Sopenharmony_ci * // perturb_local_entropy() 488c2ecf20Sopenharmony_ci * } else { 498c2ecf20Sopenharmony_ci * local_entropy ^= 3896280633962944730; 508c2ecf20Sopenharmony_ci * printf("%s: %d command arguments!\n", *argv, args - 1); 518c2ecf20Sopenharmony_ci * } 528c2ecf20Sopenharmony_ci * 538c2ecf20Sopenharmony_ci * // latent_entropy_execute() 4. 548c2ecf20Sopenharmony_ci * tmp_latent_entropy = rol(tmp_latent_entropy, local_entropy); 558c2ecf20Sopenharmony_ci * latent_entropy = tmp_latent_entropy; 568c2ecf20Sopenharmony_ci * } 578c2ecf20Sopenharmony_ci * 588c2ecf20Sopenharmony_ci * TODO: 598c2ecf20Sopenharmony_ci * - add ipa pass to identify not explicitly marked candidate functions 608c2ecf20Sopenharmony_ci * - mix in more program state (function arguments/return values, 618c2ecf20Sopenharmony_ci * loop variables, etc) 628c2ecf20Sopenharmony_ci * - more instrumentation control via attribute parameters 638c2ecf20Sopenharmony_ci * 648c2ecf20Sopenharmony_ci * BUGS: 658c2ecf20Sopenharmony_ci * - none known 668c2ecf20Sopenharmony_ci * 678c2ecf20Sopenharmony_ci * Options: 688c2ecf20Sopenharmony_ci * -fplugin-arg-latent_entropy_plugin-disable 698c2ecf20Sopenharmony_ci * 708c2ecf20Sopenharmony_ci * Attribute: __attribute__((latent_entropy)) 718c2ecf20Sopenharmony_ci * The latent_entropy gcc attribute can be only on functions and variables. 728c2ecf20Sopenharmony_ci * If it is on a function then the plugin will instrument it. If the attribute 738c2ecf20Sopenharmony_ci * is on a variable then the plugin will initialize it with a random value. 748c2ecf20Sopenharmony_ci * The variable must be an integer, an integer array type or a structure 758c2ecf20Sopenharmony_ci * with integer fields. 768c2ecf20Sopenharmony_ci */ 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci#include "gcc-common.h" 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci__visible int plugin_is_GPL_compatible; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic GTY(()) tree latent_entropy_decl; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic struct plugin_info latent_entropy_plugin_info = { 858c2ecf20Sopenharmony_ci .version = "201606141920vanilla", 868c2ecf20Sopenharmony_ci .help = "disable\tturn off latent entropy instrumentation\n", 878c2ecf20Sopenharmony_ci}; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic unsigned HOST_WIDE_INT deterministic_seed; 908c2ecf20Sopenharmony_cistatic unsigned HOST_WIDE_INT rnd_buf[32]; 918c2ecf20Sopenharmony_cistatic size_t rnd_idx = ARRAY_SIZE(rnd_buf); 928c2ecf20Sopenharmony_cistatic int urandom_fd = -1; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic unsigned HOST_WIDE_INT get_random_const(void) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci if (deterministic_seed) { 978c2ecf20Sopenharmony_ci unsigned HOST_WIDE_INT w = deterministic_seed; 988c2ecf20Sopenharmony_ci w ^= w << 13; 998c2ecf20Sopenharmony_ci w ^= w >> 7; 1008c2ecf20Sopenharmony_ci w ^= w << 17; 1018c2ecf20Sopenharmony_ci deterministic_seed = w; 1028c2ecf20Sopenharmony_ci return deterministic_seed; 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci if (urandom_fd < 0) { 1068c2ecf20Sopenharmony_ci urandom_fd = open("/dev/urandom", O_RDONLY); 1078c2ecf20Sopenharmony_ci gcc_assert(urandom_fd >= 0); 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci if (rnd_idx >= ARRAY_SIZE(rnd_buf)) { 1108c2ecf20Sopenharmony_ci gcc_assert(read(urandom_fd, rnd_buf, sizeof(rnd_buf)) == sizeof(rnd_buf)); 1118c2ecf20Sopenharmony_ci rnd_idx = 0; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci return rnd_buf[rnd_idx++]; 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic tree tree_get_random_const(tree type) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci unsigned long long mask; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci mask = 1ULL << (TREE_INT_CST_LOW(TYPE_SIZE(type)) - 1); 1218c2ecf20Sopenharmony_ci mask = 2 * (mask - 1) + 1; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if (TYPE_UNSIGNED(type)) 1248c2ecf20Sopenharmony_ci return build_int_cstu(type, mask & get_random_const()); 1258c2ecf20Sopenharmony_ci return build_int_cst(type, mask & get_random_const()); 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic tree handle_latent_entropy_attribute(tree *node, tree name, 1298c2ecf20Sopenharmony_ci tree args __unused, 1308c2ecf20Sopenharmony_ci int flags __unused, 1318c2ecf20Sopenharmony_ci bool *no_add_attrs) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci tree type; 1348c2ecf20Sopenharmony_ci#if BUILDING_GCC_VERSION <= 4007 1358c2ecf20Sopenharmony_ci VEC(constructor_elt, gc) *vals; 1368c2ecf20Sopenharmony_ci#else 1378c2ecf20Sopenharmony_ci vec<constructor_elt, va_gc> *vals; 1388c2ecf20Sopenharmony_ci#endif 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci switch (TREE_CODE(*node)) { 1418c2ecf20Sopenharmony_ci default: 1428c2ecf20Sopenharmony_ci *no_add_attrs = true; 1438c2ecf20Sopenharmony_ci error("%qE attribute only applies to functions and variables", 1448c2ecf20Sopenharmony_ci name); 1458c2ecf20Sopenharmony_ci break; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci case VAR_DECL: 1488c2ecf20Sopenharmony_ci if (DECL_INITIAL(*node)) { 1498c2ecf20Sopenharmony_ci *no_add_attrs = true; 1508c2ecf20Sopenharmony_ci error("variable %qD with %qE attribute must not be initialized", 1518c2ecf20Sopenharmony_ci *node, name); 1528c2ecf20Sopenharmony_ci break; 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci if (!TREE_STATIC(*node)) { 1568c2ecf20Sopenharmony_ci *no_add_attrs = true; 1578c2ecf20Sopenharmony_ci error("variable %qD with %qE attribute must not be local", 1588c2ecf20Sopenharmony_ci *node, name); 1598c2ecf20Sopenharmony_ci break; 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci type = TREE_TYPE(*node); 1638c2ecf20Sopenharmony_ci switch (TREE_CODE(type)) { 1648c2ecf20Sopenharmony_ci default: 1658c2ecf20Sopenharmony_ci *no_add_attrs = true; 1668c2ecf20Sopenharmony_ci 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", 1678c2ecf20Sopenharmony_ci *node, name); 1688c2ecf20Sopenharmony_ci break; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci case RECORD_TYPE: { 1718c2ecf20Sopenharmony_ci tree fld, lst = TYPE_FIELDS(type); 1728c2ecf20Sopenharmony_ci unsigned int nelt = 0; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci for (fld = lst; fld; nelt++, fld = TREE_CHAIN(fld)) { 1758c2ecf20Sopenharmony_ci tree fieldtype; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci fieldtype = TREE_TYPE(fld); 1788c2ecf20Sopenharmony_ci if (TREE_CODE(fieldtype) == INTEGER_TYPE) 1798c2ecf20Sopenharmony_ci continue; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci *no_add_attrs = true; 1828c2ecf20Sopenharmony_ci error("structure variable %qD with %qE attribute has a non-integer field %qE", 1838c2ecf20Sopenharmony_ci *node, name, fld); 1848c2ecf20Sopenharmony_ci break; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci if (fld) 1888c2ecf20Sopenharmony_ci break; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci#if BUILDING_GCC_VERSION <= 4007 1918c2ecf20Sopenharmony_ci vals = VEC_alloc(constructor_elt, gc, nelt); 1928c2ecf20Sopenharmony_ci#else 1938c2ecf20Sopenharmony_ci vec_alloc(vals, nelt); 1948c2ecf20Sopenharmony_ci#endif 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci for (fld = lst; fld; fld = TREE_CHAIN(fld)) { 1978c2ecf20Sopenharmony_ci tree random_const, fld_t = TREE_TYPE(fld); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci random_const = tree_get_random_const(fld_t); 2008c2ecf20Sopenharmony_ci CONSTRUCTOR_APPEND_ELT(vals, fld, random_const); 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci /* Initialize the fields with random constants */ 2048c2ecf20Sopenharmony_ci DECL_INITIAL(*node) = build_constructor(type, vals); 2058c2ecf20Sopenharmony_ci break; 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci /* Initialize the variable with a random constant */ 2098c2ecf20Sopenharmony_ci case INTEGER_TYPE: 2108c2ecf20Sopenharmony_ci DECL_INITIAL(*node) = tree_get_random_const(type); 2118c2ecf20Sopenharmony_ci break; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci case ARRAY_TYPE: { 2148c2ecf20Sopenharmony_ci tree elt_type, array_size, elt_size; 2158c2ecf20Sopenharmony_ci unsigned int i, nelt; 2168c2ecf20Sopenharmony_ci HOST_WIDE_INT array_size_int, elt_size_int; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci elt_type = TREE_TYPE(type); 2198c2ecf20Sopenharmony_ci elt_size = TYPE_SIZE_UNIT(TREE_TYPE(type)); 2208c2ecf20Sopenharmony_ci array_size = TYPE_SIZE_UNIT(type); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci if (TREE_CODE(elt_type) != INTEGER_TYPE || !array_size 2238c2ecf20Sopenharmony_ci || TREE_CODE(array_size) != INTEGER_CST) { 2248c2ecf20Sopenharmony_ci *no_add_attrs = true; 2258c2ecf20Sopenharmony_ci error("array variable %qD with %qE attribute must be a fixed length integer array type", 2268c2ecf20Sopenharmony_ci *node, name); 2278c2ecf20Sopenharmony_ci break; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci array_size_int = TREE_INT_CST_LOW(array_size); 2318c2ecf20Sopenharmony_ci elt_size_int = TREE_INT_CST_LOW(elt_size); 2328c2ecf20Sopenharmony_ci nelt = array_size_int / elt_size_int; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci#if BUILDING_GCC_VERSION <= 4007 2358c2ecf20Sopenharmony_ci vals = VEC_alloc(constructor_elt, gc, nelt); 2368c2ecf20Sopenharmony_ci#else 2378c2ecf20Sopenharmony_ci vec_alloc(vals, nelt); 2388c2ecf20Sopenharmony_ci#endif 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci for (i = 0; i < nelt; i++) { 2418c2ecf20Sopenharmony_ci tree cst = size_int(i); 2428c2ecf20Sopenharmony_ci tree rand_cst = tree_get_random_const(elt_type); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci CONSTRUCTOR_APPEND_ELT(vals, cst, rand_cst); 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci /* 2488c2ecf20Sopenharmony_ci * Initialize the elements of the array with random 2498c2ecf20Sopenharmony_ci * constants 2508c2ecf20Sopenharmony_ci */ 2518c2ecf20Sopenharmony_ci DECL_INITIAL(*node) = build_constructor(type, vals); 2528c2ecf20Sopenharmony_ci break; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci break; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci case FUNCTION_DECL: 2588c2ecf20Sopenharmony_ci break; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci return NULL_TREE; 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic struct attribute_spec latent_entropy_attr = { }; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistatic void register_attributes(void *event_data __unused, void *data __unused) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci latent_entropy_attr.name = "latent_entropy"; 2698c2ecf20Sopenharmony_ci latent_entropy_attr.decl_required = true; 2708c2ecf20Sopenharmony_ci latent_entropy_attr.handler = handle_latent_entropy_attribute; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci register_attribute(&latent_entropy_attr); 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic bool latent_entropy_gate(void) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci tree list; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci /* don't bother with noreturn functions for now */ 2808c2ecf20Sopenharmony_ci if (TREE_THIS_VOLATILE(current_function_decl)) 2818c2ecf20Sopenharmony_ci return false; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci /* gcc-4.5 doesn't discover some trivial noreturn functions */ 2848c2ecf20Sopenharmony_ci if (EDGE_COUNT(EXIT_BLOCK_PTR_FOR_FN(cfun)->preds) == 0) 2858c2ecf20Sopenharmony_ci return false; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci list = DECL_ATTRIBUTES(current_function_decl); 2888c2ecf20Sopenharmony_ci return lookup_attribute("latent_entropy", list) != NULL_TREE; 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic tree create_var(tree type, const char *name) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci tree var; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci var = create_tmp_var(type, name); 2968c2ecf20Sopenharmony_ci add_referenced_var(var); 2978c2ecf20Sopenharmony_ci mark_sym_for_renaming(var); 2988c2ecf20Sopenharmony_ci return var; 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci/* 3028c2ecf20Sopenharmony_ci * Set up the next operation and its constant operand to use in the latent 3038c2ecf20Sopenharmony_ci * entropy PRNG. When RHS is specified, the request is for perturbing the 3048c2ecf20Sopenharmony_ci * local latent entropy variable, otherwise it is for perturbing the global 3058c2ecf20Sopenharmony_ci * latent entropy variable where the two operands are already given by the 3068c2ecf20Sopenharmony_ci * local and global latent entropy variables themselves. 3078c2ecf20Sopenharmony_ci * 3088c2ecf20Sopenharmony_ci * The operation is one of add/xor/rol when instrumenting the local entropy 3098c2ecf20Sopenharmony_ci * variable and one of add/xor when perturbing the global entropy variable. 3108c2ecf20Sopenharmony_ci * Rotation is not used for the latter case because it would transmit less 3118c2ecf20Sopenharmony_ci * entropy to the global variable than the other two operations. 3128c2ecf20Sopenharmony_ci */ 3138c2ecf20Sopenharmony_cistatic enum tree_code get_op(tree *rhs) 3148c2ecf20Sopenharmony_ci{ 3158c2ecf20Sopenharmony_ci static enum tree_code op; 3168c2ecf20Sopenharmony_ci unsigned HOST_WIDE_INT random_const; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci random_const = get_random_const(); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci switch (op) { 3218c2ecf20Sopenharmony_ci case BIT_XOR_EXPR: 3228c2ecf20Sopenharmony_ci op = PLUS_EXPR; 3238c2ecf20Sopenharmony_ci break; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci case PLUS_EXPR: 3268c2ecf20Sopenharmony_ci if (rhs) { 3278c2ecf20Sopenharmony_ci op = LROTATE_EXPR; 3288c2ecf20Sopenharmony_ci /* 3298c2ecf20Sopenharmony_ci * This code limits the value of random_const to 3308c2ecf20Sopenharmony_ci * the size of a long for the rotation 3318c2ecf20Sopenharmony_ci */ 3328c2ecf20Sopenharmony_ci random_const %= TYPE_PRECISION(long_unsigned_type_node); 3338c2ecf20Sopenharmony_ci break; 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci case LROTATE_EXPR: 3378c2ecf20Sopenharmony_ci default: 3388c2ecf20Sopenharmony_ci op = BIT_XOR_EXPR; 3398c2ecf20Sopenharmony_ci break; 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci if (rhs) 3428c2ecf20Sopenharmony_ci *rhs = build_int_cstu(long_unsigned_type_node, random_const); 3438c2ecf20Sopenharmony_ci return op; 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cistatic gimple create_assign(enum tree_code code, tree lhs, tree op1, 3478c2ecf20Sopenharmony_ci tree op2) 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci return gimple_build_assign_with_ops(code, lhs, op1, op2); 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_cistatic void perturb_local_entropy(basic_block bb, tree local_entropy) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci gimple_stmt_iterator gsi; 3558c2ecf20Sopenharmony_ci gimple assign; 3568c2ecf20Sopenharmony_ci tree rhs; 3578c2ecf20Sopenharmony_ci enum tree_code op; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci op = get_op(&rhs); 3608c2ecf20Sopenharmony_ci assign = create_assign(op, local_entropy, local_entropy, rhs); 3618c2ecf20Sopenharmony_ci gsi = gsi_after_labels(bb); 3628c2ecf20Sopenharmony_ci gsi_insert_before(&gsi, assign, GSI_NEW_STMT); 3638c2ecf20Sopenharmony_ci update_stmt(assign); 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cistatic void __perturb_latent_entropy(gimple_stmt_iterator *gsi, 3678c2ecf20Sopenharmony_ci tree local_entropy) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci gimple assign; 3708c2ecf20Sopenharmony_ci tree temp; 3718c2ecf20Sopenharmony_ci enum tree_code op; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci /* 1. create temporary copy of latent_entropy */ 3748c2ecf20Sopenharmony_ci temp = create_var(long_unsigned_type_node, "temp_latent_entropy"); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci /* 2. read... */ 3778c2ecf20Sopenharmony_ci add_referenced_var(latent_entropy_decl); 3788c2ecf20Sopenharmony_ci mark_sym_for_renaming(latent_entropy_decl); 3798c2ecf20Sopenharmony_ci assign = gimple_build_assign(temp, latent_entropy_decl); 3808c2ecf20Sopenharmony_ci gsi_insert_before(gsi, assign, GSI_NEW_STMT); 3818c2ecf20Sopenharmony_ci update_stmt(assign); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci /* 3. ...modify... */ 3848c2ecf20Sopenharmony_ci op = get_op(NULL); 3858c2ecf20Sopenharmony_ci assign = create_assign(op, temp, temp, local_entropy); 3868c2ecf20Sopenharmony_ci gsi_insert_after(gsi, assign, GSI_NEW_STMT); 3878c2ecf20Sopenharmony_ci update_stmt(assign); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci /* 4. ...write latent_entropy */ 3908c2ecf20Sopenharmony_ci assign = gimple_build_assign(latent_entropy_decl, temp); 3918c2ecf20Sopenharmony_ci gsi_insert_after(gsi, assign, GSI_NEW_STMT); 3928c2ecf20Sopenharmony_ci update_stmt(assign); 3938c2ecf20Sopenharmony_ci} 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_cistatic bool handle_tail_calls(basic_block bb, tree local_entropy) 3968c2ecf20Sopenharmony_ci{ 3978c2ecf20Sopenharmony_ci gimple_stmt_iterator gsi; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) { 4008c2ecf20Sopenharmony_ci gcall *call; 4018c2ecf20Sopenharmony_ci gimple stmt = gsi_stmt(gsi); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci if (!is_gimple_call(stmt)) 4048c2ecf20Sopenharmony_ci continue; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci call = as_a_gcall(stmt); 4078c2ecf20Sopenharmony_ci if (!gimple_call_tail_p(call)) 4088c2ecf20Sopenharmony_ci continue; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci __perturb_latent_entropy(&gsi, local_entropy); 4118c2ecf20Sopenharmony_ci return true; 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci return false; 4158c2ecf20Sopenharmony_ci} 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_cistatic void perturb_latent_entropy(tree local_entropy) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci edge_iterator ei; 4208c2ecf20Sopenharmony_ci edge e, last_bb_e; 4218c2ecf20Sopenharmony_ci basic_block last_bb; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci gcc_assert(single_pred_p(EXIT_BLOCK_PTR_FOR_FN(cfun))); 4248c2ecf20Sopenharmony_ci last_bb_e = single_pred_edge(EXIT_BLOCK_PTR_FOR_FN(cfun)); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci FOR_EACH_EDGE(e, ei, last_bb_e->src->preds) { 4278c2ecf20Sopenharmony_ci if (ENTRY_BLOCK_PTR_FOR_FN(cfun) == e->src) 4288c2ecf20Sopenharmony_ci continue; 4298c2ecf20Sopenharmony_ci if (EXIT_BLOCK_PTR_FOR_FN(cfun) == e->src) 4308c2ecf20Sopenharmony_ci continue; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci handle_tail_calls(e->src, local_entropy); 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci last_bb = single_pred(EXIT_BLOCK_PTR_FOR_FN(cfun)); 4368c2ecf20Sopenharmony_ci if (!handle_tail_calls(last_bb, local_entropy)) { 4378c2ecf20Sopenharmony_ci gimple_stmt_iterator gsi = gsi_last_bb(last_bb); 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci __perturb_latent_entropy(&gsi, local_entropy); 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cistatic void init_local_entropy(basic_block bb, tree local_entropy) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci gimple assign, call; 4468c2ecf20Sopenharmony_ci tree frame_addr, rand_const, tmp, fndecl, udi_frame_addr; 4478c2ecf20Sopenharmony_ci enum tree_code op; 4488c2ecf20Sopenharmony_ci unsigned HOST_WIDE_INT rand_cst; 4498c2ecf20Sopenharmony_ci gimple_stmt_iterator gsi = gsi_after_labels(bb); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci /* 1. create local_entropy_frameaddr */ 4528c2ecf20Sopenharmony_ci frame_addr = create_var(ptr_type_node, "local_entropy_frameaddr"); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci /* 2. local_entropy_frameaddr = __builtin_frame_address() */ 4558c2ecf20Sopenharmony_ci fndecl = builtin_decl_implicit(BUILT_IN_FRAME_ADDRESS); 4568c2ecf20Sopenharmony_ci call = gimple_build_call(fndecl, 1, integer_zero_node); 4578c2ecf20Sopenharmony_ci gimple_call_set_lhs(call, frame_addr); 4588c2ecf20Sopenharmony_ci gsi_insert_before(&gsi, call, GSI_NEW_STMT); 4598c2ecf20Sopenharmony_ci update_stmt(call); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci udi_frame_addr = fold_convert(long_unsigned_type_node, frame_addr); 4628c2ecf20Sopenharmony_ci assign = gimple_build_assign(local_entropy, udi_frame_addr); 4638c2ecf20Sopenharmony_ci gsi_insert_after(&gsi, assign, GSI_NEW_STMT); 4648c2ecf20Sopenharmony_ci update_stmt(assign); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci /* 3. create temporary copy of latent_entropy */ 4678c2ecf20Sopenharmony_ci tmp = create_var(long_unsigned_type_node, "temp_latent_entropy"); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci /* 4. read the global entropy variable into local entropy */ 4708c2ecf20Sopenharmony_ci add_referenced_var(latent_entropy_decl); 4718c2ecf20Sopenharmony_ci mark_sym_for_renaming(latent_entropy_decl); 4728c2ecf20Sopenharmony_ci assign = gimple_build_assign(tmp, latent_entropy_decl); 4738c2ecf20Sopenharmony_ci gsi_insert_after(&gsi, assign, GSI_NEW_STMT); 4748c2ecf20Sopenharmony_ci update_stmt(assign); 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci /* 5. mix local_entropy_frameaddr into local entropy */ 4778c2ecf20Sopenharmony_ci assign = create_assign(BIT_XOR_EXPR, local_entropy, local_entropy, tmp); 4788c2ecf20Sopenharmony_ci gsi_insert_after(&gsi, assign, GSI_NEW_STMT); 4798c2ecf20Sopenharmony_ci update_stmt(assign); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci rand_cst = get_random_const(); 4828c2ecf20Sopenharmony_ci rand_const = build_int_cstu(long_unsigned_type_node, rand_cst); 4838c2ecf20Sopenharmony_ci op = get_op(NULL); 4848c2ecf20Sopenharmony_ci assign = create_assign(op, local_entropy, local_entropy, rand_const); 4858c2ecf20Sopenharmony_ci gsi_insert_after(&gsi, assign, GSI_NEW_STMT); 4868c2ecf20Sopenharmony_ci update_stmt(assign); 4878c2ecf20Sopenharmony_ci} 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cistatic bool create_latent_entropy_decl(void) 4908c2ecf20Sopenharmony_ci{ 4918c2ecf20Sopenharmony_ci varpool_node_ptr node; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci if (latent_entropy_decl != NULL_TREE) 4948c2ecf20Sopenharmony_ci return true; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci FOR_EACH_VARIABLE(node) { 4978c2ecf20Sopenharmony_ci tree name, var = NODE_DECL(node); 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci if (DECL_NAME_LENGTH(var) < sizeof("latent_entropy") - 1) 5008c2ecf20Sopenharmony_ci continue; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci name = DECL_NAME(var); 5038c2ecf20Sopenharmony_ci if (strcmp(IDENTIFIER_POINTER(name), "latent_entropy")) 5048c2ecf20Sopenharmony_ci continue; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci latent_entropy_decl = var; 5078c2ecf20Sopenharmony_ci break; 5088c2ecf20Sopenharmony_ci } 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci return latent_entropy_decl != NULL_TREE; 5118c2ecf20Sopenharmony_ci} 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_cistatic unsigned int latent_entropy_execute(void) 5148c2ecf20Sopenharmony_ci{ 5158c2ecf20Sopenharmony_ci basic_block bb; 5168c2ecf20Sopenharmony_ci tree local_entropy; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci if (!create_latent_entropy_decl()) 5198c2ecf20Sopenharmony_ci return 0; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci /* prepare for step 2 below */ 5228c2ecf20Sopenharmony_ci gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun))); 5238c2ecf20Sopenharmony_ci bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun)); 5248c2ecf20Sopenharmony_ci if (!single_pred_p(bb)) { 5258c2ecf20Sopenharmony_ci split_edge(single_succ_edge(ENTRY_BLOCK_PTR_FOR_FN(cfun))); 5268c2ecf20Sopenharmony_ci gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun))); 5278c2ecf20Sopenharmony_ci bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun)); 5288c2ecf20Sopenharmony_ci } 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci /* 1. create the local entropy variable */ 5318c2ecf20Sopenharmony_ci local_entropy = create_var(long_unsigned_type_node, "local_entropy"); 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci /* 2. initialize the local entropy variable */ 5348c2ecf20Sopenharmony_ci init_local_entropy(bb, local_entropy); 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci bb = bb->next_bb; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci /* 5398c2ecf20Sopenharmony_ci * 3. instrument each BB with an operation on the 5408c2ecf20Sopenharmony_ci * local entropy variable 5418c2ecf20Sopenharmony_ci */ 5428c2ecf20Sopenharmony_ci while (bb != EXIT_BLOCK_PTR_FOR_FN(cfun)) { 5438c2ecf20Sopenharmony_ci perturb_local_entropy(bb, local_entropy); 5448c2ecf20Sopenharmony_ci bb = bb->next_bb; 5458c2ecf20Sopenharmony_ci }; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci /* 4. mix local entropy into the global entropy variable */ 5488c2ecf20Sopenharmony_ci perturb_latent_entropy(local_entropy); 5498c2ecf20Sopenharmony_ci return 0; 5508c2ecf20Sopenharmony_ci} 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_cistatic void latent_entropy_start_unit(void *gcc_data __unused, 5538c2ecf20Sopenharmony_ci void *user_data __unused) 5548c2ecf20Sopenharmony_ci{ 5558c2ecf20Sopenharmony_ci tree type, id; 5568c2ecf20Sopenharmony_ci int quals; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci if (in_lto_p) 5598c2ecf20Sopenharmony_ci return; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci /* extern volatile unsigned long latent_entropy */ 5628c2ecf20Sopenharmony_ci quals = TYPE_QUALS(long_unsigned_type_node) | TYPE_QUAL_VOLATILE; 5638c2ecf20Sopenharmony_ci type = build_qualified_type(long_unsigned_type_node, quals); 5648c2ecf20Sopenharmony_ci id = get_identifier("latent_entropy"); 5658c2ecf20Sopenharmony_ci latent_entropy_decl = build_decl(UNKNOWN_LOCATION, VAR_DECL, id, type); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci TREE_STATIC(latent_entropy_decl) = 1; 5688c2ecf20Sopenharmony_ci TREE_PUBLIC(latent_entropy_decl) = 1; 5698c2ecf20Sopenharmony_ci TREE_USED(latent_entropy_decl) = 1; 5708c2ecf20Sopenharmony_ci DECL_PRESERVE_P(latent_entropy_decl) = 1; 5718c2ecf20Sopenharmony_ci TREE_THIS_VOLATILE(latent_entropy_decl) = 1; 5728c2ecf20Sopenharmony_ci DECL_EXTERNAL(latent_entropy_decl) = 1; 5738c2ecf20Sopenharmony_ci DECL_ARTIFICIAL(latent_entropy_decl) = 1; 5748c2ecf20Sopenharmony_ci lang_hooks.decls.pushdecl(latent_entropy_decl); 5758c2ecf20Sopenharmony_ci} 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci#define PASS_NAME latent_entropy 5788c2ecf20Sopenharmony_ci#define PROPERTIES_REQUIRED PROP_gimple_leh | PROP_cfg 5798c2ecf20Sopenharmony_ci#define TODO_FLAGS_FINISH TODO_verify_ssa | TODO_verify_stmts | TODO_dump_func \ 5808c2ecf20Sopenharmony_ci | TODO_update_ssa 5818c2ecf20Sopenharmony_ci#include "gcc-generate-gimple-pass.h" 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci__visible int plugin_init(struct plugin_name_args *plugin_info, 5848c2ecf20Sopenharmony_ci struct plugin_gcc_version *version) 5858c2ecf20Sopenharmony_ci{ 5868c2ecf20Sopenharmony_ci bool enabled = true; 5878c2ecf20Sopenharmony_ci const char * const plugin_name = plugin_info->base_name; 5888c2ecf20Sopenharmony_ci const int argc = plugin_info->argc; 5898c2ecf20Sopenharmony_ci const struct plugin_argument * const argv = plugin_info->argv; 5908c2ecf20Sopenharmony_ci int i; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci /* 5938c2ecf20Sopenharmony_ci * Call get_random_seed() with noinit=true, so that this returns 5948c2ecf20Sopenharmony_ci * 0 in the case where no seed has been passed via -frandom-seed. 5958c2ecf20Sopenharmony_ci */ 5968c2ecf20Sopenharmony_ci deterministic_seed = get_random_seed(true); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci static const struct ggc_root_tab gt_ggc_r_gt_latent_entropy[] = { 5998c2ecf20Sopenharmony_ci { 6008c2ecf20Sopenharmony_ci .base = &latent_entropy_decl, 6018c2ecf20Sopenharmony_ci .nelt = 1, 6028c2ecf20Sopenharmony_ci .stride = sizeof(latent_entropy_decl), 6038c2ecf20Sopenharmony_ci .cb = >_ggc_mx_tree_node, 6048c2ecf20Sopenharmony_ci .pchw = >_pch_nx_tree_node 6058c2ecf20Sopenharmony_ci }, 6068c2ecf20Sopenharmony_ci LAST_GGC_ROOT_TAB 6078c2ecf20Sopenharmony_ci }; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci PASS_INFO(latent_entropy, "optimized", 1, PASS_POS_INSERT_BEFORE); 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci if (!plugin_default_version_check(version, &gcc_version)) { 6128c2ecf20Sopenharmony_ci error(G_("incompatible gcc/plugin versions")); 6138c2ecf20Sopenharmony_ci return 1; 6148c2ecf20Sopenharmony_ci } 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci for (i = 0; i < argc; ++i) { 6178c2ecf20Sopenharmony_ci if (!(strcmp(argv[i].key, "disable"))) { 6188c2ecf20Sopenharmony_ci enabled = false; 6198c2ecf20Sopenharmony_ci continue; 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci error(G_("unknown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key); 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci register_callback(plugin_name, PLUGIN_INFO, NULL, 6258c2ecf20Sopenharmony_ci &latent_entropy_plugin_info); 6268c2ecf20Sopenharmony_ci if (enabled) { 6278c2ecf20Sopenharmony_ci register_callback(plugin_name, PLUGIN_START_UNIT, 6288c2ecf20Sopenharmony_ci &latent_entropy_start_unit, NULL); 6298c2ecf20Sopenharmony_ci register_callback(plugin_name, PLUGIN_REGISTER_GGC_ROOTS, 6308c2ecf20Sopenharmony_ci NULL, (void *)>_ggc_r_gt_latent_entropy); 6318c2ecf20Sopenharmony_ci register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, 6328c2ecf20Sopenharmony_ci &latent_entropy_pass_info); 6338c2ecf20Sopenharmony_ci } 6348c2ecf20Sopenharmony_ci register_callback(plugin_name, PLUGIN_ATTRIBUTES, register_attributes, 6358c2ecf20Sopenharmony_ci NULL); 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci return 0; 6388c2ecf20Sopenharmony_ci} 639