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 = &gt_ggc_mx_tree_node,
6048c2ecf20Sopenharmony_ci			.pchw = &gt_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 *)&gt_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