1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright 2012-2016 by the PaX Team <pageexec@freemail.hu>
3*4882a593Smuzhiyun * Copyright 2016 by Emese Revfy <re.emese@gmail.com>
4*4882a593Smuzhiyun * Licensed under the GPL v2
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Note: the choice of the license means that the compilation process is
7*4882a593Smuzhiyun * NOT 'eligible' as defined by gcc's library exception to the GPL v3,
8*4882a593Smuzhiyun * but for the kernel it doesn't matter since it doesn't link against
9*4882a593Smuzhiyun * any of the gcc libraries
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun * This gcc plugin helps generate a little bit of entropy from program state,
12*4882a593Smuzhiyun * used throughout the uptime of the kernel. Here is an instrumentation example:
13*4882a593Smuzhiyun *
14*4882a593Smuzhiyun * before:
15*4882a593Smuzhiyun * void __latent_entropy test(int argc, char *argv[])
16*4882a593Smuzhiyun * {
17*4882a593Smuzhiyun * if (argc <= 1)
18*4882a593Smuzhiyun * printf("%s: no command arguments :(\n", *argv);
19*4882a593Smuzhiyun * else
20*4882a593Smuzhiyun * printf("%s: %d command arguments!\n", *argv, args - 1);
21*4882a593Smuzhiyun * }
22*4882a593Smuzhiyun *
23*4882a593Smuzhiyun * after:
24*4882a593Smuzhiyun * void __latent_entropy test(int argc, char *argv[])
25*4882a593Smuzhiyun * {
26*4882a593Smuzhiyun * // latent_entropy_execute() 1.
27*4882a593Smuzhiyun * unsigned long local_entropy;
28*4882a593Smuzhiyun * // init_local_entropy() 1.
29*4882a593Smuzhiyun * void *local_entropy_frameaddr;
30*4882a593Smuzhiyun * // init_local_entropy() 3.
31*4882a593Smuzhiyun * unsigned long tmp_latent_entropy;
32*4882a593Smuzhiyun *
33*4882a593Smuzhiyun * // init_local_entropy() 2.
34*4882a593Smuzhiyun * local_entropy_frameaddr = __builtin_frame_address(0);
35*4882a593Smuzhiyun * local_entropy = (unsigned long) local_entropy_frameaddr;
36*4882a593Smuzhiyun *
37*4882a593Smuzhiyun * // init_local_entropy() 4.
38*4882a593Smuzhiyun * tmp_latent_entropy = latent_entropy;
39*4882a593Smuzhiyun * // init_local_entropy() 5.
40*4882a593Smuzhiyun * local_entropy ^= tmp_latent_entropy;
41*4882a593Smuzhiyun *
42*4882a593Smuzhiyun * // latent_entropy_execute() 3.
43*4882a593Smuzhiyun * if (argc <= 1) {
44*4882a593Smuzhiyun * // perturb_local_entropy()
45*4882a593Smuzhiyun * local_entropy += 4623067384293424948;
46*4882a593Smuzhiyun * printf("%s: no command arguments :(\n", *argv);
47*4882a593Smuzhiyun * // perturb_local_entropy()
48*4882a593Smuzhiyun * } else {
49*4882a593Smuzhiyun * local_entropy ^= 3896280633962944730;
50*4882a593Smuzhiyun * printf("%s: %d command arguments!\n", *argv, args - 1);
51*4882a593Smuzhiyun * }
52*4882a593Smuzhiyun *
53*4882a593Smuzhiyun * // latent_entropy_execute() 4.
54*4882a593Smuzhiyun * tmp_latent_entropy = rol(tmp_latent_entropy, local_entropy);
55*4882a593Smuzhiyun * latent_entropy = tmp_latent_entropy;
56*4882a593Smuzhiyun * }
57*4882a593Smuzhiyun *
58*4882a593Smuzhiyun * TODO:
59*4882a593Smuzhiyun * - add ipa pass to identify not explicitly marked candidate functions
60*4882a593Smuzhiyun * - mix in more program state (function arguments/return values,
61*4882a593Smuzhiyun * loop variables, etc)
62*4882a593Smuzhiyun * - more instrumentation control via attribute parameters
63*4882a593Smuzhiyun *
64*4882a593Smuzhiyun * BUGS:
65*4882a593Smuzhiyun * - none known
66*4882a593Smuzhiyun *
67*4882a593Smuzhiyun * Options:
68*4882a593Smuzhiyun * -fplugin-arg-latent_entropy_plugin-disable
69*4882a593Smuzhiyun *
70*4882a593Smuzhiyun * Attribute: __attribute__((latent_entropy))
71*4882a593Smuzhiyun * The latent_entropy gcc attribute can be only on functions and variables.
72*4882a593Smuzhiyun * If it is on a function then the plugin will instrument it. If the attribute
73*4882a593Smuzhiyun * is on a variable then the plugin will initialize it with a random value.
74*4882a593Smuzhiyun * The variable must be an integer, an integer array type or a structure
75*4882a593Smuzhiyun * with integer fields.
76*4882a593Smuzhiyun */
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun #include "gcc-common.h"
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun __visible int plugin_is_GPL_compatible;
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun static GTY(()) tree latent_entropy_decl;
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun static struct plugin_info latent_entropy_plugin_info = {
85*4882a593Smuzhiyun .version = "201606141920vanilla",
86*4882a593Smuzhiyun .help = "disable\tturn off latent entropy instrumentation\n",
87*4882a593Smuzhiyun };
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun static unsigned HOST_WIDE_INT deterministic_seed;
90*4882a593Smuzhiyun static unsigned HOST_WIDE_INT rnd_buf[32];
91*4882a593Smuzhiyun static size_t rnd_idx = ARRAY_SIZE(rnd_buf);
92*4882a593Smuzhiyun static int urandom_fd = -1;
93*4882a593Smuzhiyun
get_random_const(void)94*4882a593Smuzhiyun static unsigned HOST_WIDE_INT get_random_const(void)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun if (deterministic_seed) {
97*4882a593Smuzhiyun unsigned HOST_WIDE_INT w = deterministic_seed;
98*4882a593Smuzhiyun w ^= w << 13;
99*4882a593Smuzhiyun w ^= w >> 7;
100*4882a593Smuzhiyun w ^= w << 17;
101*4882a593Smuzhiyun deterministic_seed = w;
102*4882a593Smuzhiyun return deterministic_seed;
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun if (urandom_fd < 0) {
106*4882a593Smuzhiyun urandom_fd = open("/dev/urandom", O_RDONLY);
107*4882a593Smuzhiyun gcc_assert(urandom_fd >= 0);
108*4882a593Smuzhiyun }
109*4882a593Smuzhiyun if (rnd_idx >= ARRAY_SIZE(rnd_buf)) {
110*4882a593Smuzhiyun gcc_assert(read(urandom_fd, rnd_buf, sizeof(rnd_buf)) == sizeof(rnd_buf));
111*4882a593Smuzhiyun rnd_idx = 0;
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun return rnd_buf[rnd_idx++];
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun
tree_get_random_const(tree type)116*4882a593Smuzhiyun static tree tree_get_random_const(tree type)
117*4882a593Smuzhiyun {
118*4882a593Smuzhiyun unsigned long long mask;
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun mask = 1ULL << (TREE_INT_CST_LOW(TYPE_SIZE(type)) - 1);
121*4882a593Smuzhiyun mask = 2 * (mask - 1) + 1;
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun if (TYPE_UNSIGNED(type))
124*4882a593Smuzhiyun return build_int_cstu(type, mask & get_random_const());
125*4882a593Smuzhiyun return build_int_cst(type, mask & get_random_const());
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun
handle_latent_entropy_attribute(tree * node,tree name,tree args __unused,int flags __unused,bool * no_add_attrs)128*4882a593Smuzhiyun static tree handle_latent_entropy_attribute(tree *node, tree name,
129*4882a593Smuzhiyun tree args __unused,
130*4882a593Smuzhiyun int flags __unused,
131*4882a593Smuzhiyun bool *no_add_attrs)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun tree type;
134*4882a593Smuzhiyun #if BUILDING_GCC_VERSION <= 4007
135*4882a593Smuzhiyun VEC(constructor_elt, gc) *vals;
136*4882a593Smuzhiyun #else
137*4882a593Smuzhiyun vec<constructor_elt, va_gc> *vals;
138*4882a593Smuzhiyun #endif
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun switch (TREE_CODE(*node)) {
141*4882a593Smuzhiyun default:
142*4882a593Smuzhiyun *no_add_attrs = true;
143*4882a593Smuzhiyun error("%qE attribute only applies to functions and variables",
144*4882a593Smuzhiyun name);
145*4882a593Smuzhiyun break;
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun case VAR_DECL:
148*4882a593Smuzhiyun if (DECL_INITIAL(*node)) {
149*4882a593Smuzhiyun *no_add_attrs = true;
150*4882a593Smuzhiyun error("variable %qD with %qE attribute must not be initialized",
151*4882a593Smuzhiyun *node, name);
152*4882a593Smuzhiyun break;
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun if (!TREE_STATIC(*node)) {
156*4882a593Smuzhiyun *no_add_attrs = true;
157*4882a593Smuzhiyun error("variable %qD with %qE attribute must not be local",
158*4882a593Smuzhiyun *node, name);
159*4882a593Smuzhiyun break;
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun type = TREE_TYPE(*node);
163*4882a593Smuzhiyun switch (TREE_CODE(type)) {
164*4882a593Smuzhiyun default:
165*4882a593Smuzhiyun *no_add_attrs = true;
166*4882a593Smuzhiyun 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",
167*4882a593Smuzhiyun *node, name);
168*4882a593Smuzhiyun break;
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun case RECORD_TYPE: {
171*4882a593Smuzhiyun tree fld, lst = TYPE_FIELDS(type);
172*4882a593Smuzhiyun unsigned int nelt = 0;
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun for (fld = lst; fld; nelt++, fld = TREE_CHAIN(fld)) {
175*4882a593Smuzhiyun tree fieldtype;
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun fieldtype = TREE_TYPE(fld);
178*4882a593Smuzhiyun if (TREE_CODE(fieldtype) == INTEGER_TYPE)
179*4882a593Smuzhiyun continue;
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun *no_add_attrs = true;
182*4882a593Smuzhiyun error("structure variable %qD with %qE attribute has a non-integer field %qE",
183*4882a593Smuzhiyun *node, name, fld);
184*4882a593Smuzhiyun break;
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun if (fld)
188*4882a593Smuzhiyun break;
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun #if BUILDING_GCC_VERSION <= 4007
191*4882a593Smuzhiyun vals = VEC_alloc(constructor_elt, gc, nelt);
192*4882a593Smuzhiyun #else
193*4882a593Smuzhiyun vec_alloc(vals, nelt);
194*4882a593Smuzhiyun #endif
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun for (fld = lst; fld; fld = TREE_CHAIN(fld)) {
197*4882a593Smuzhiyun tree random_const, fld_t = TREE_TYPE(fld);
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun random_const = tree_get_random_const(fld_t);
200*4882a593Smuzhiyun CONSTRUCTOR_APPEND_ELT(vals, fld, random_const);
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun /* Initialize the fields with random constants */
204*4882a593Smuzhiyun DECL_INITIAL(*node) = build_constructor(type, vals);
205*4882a593Smuzhiyun break;
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun /* Initialize the variable with a random constant */
209*4882a593Smuzhiyun case INTEGER_TYPE:
210*4882a593Smuzhiyun DECL_INITIAL(*node) = tree_get_random_const(type);
211*4882a593Smuzhiyun break;
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun case ARRAY_TYPE: {
214*4882a593Smuzhiyun tree elt_type, array_size, elt_size;
215*4882a593Smuzhiyun unsigned int i, nelt;
216*4882a593Smuzhiyun HOST_WIDE_INT array_size_int, elt_size_int;
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun elt_type = TREE_TYPE(type);
219*4882a593Smuzhiyun elt_size = TYPE_SIZE_UNIT(TREE_TYPE(type));
220*4882a593Smuzhiyun array_size = TYPE_SIZE_UNIT(type);
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun if (TREE_CODE(elt_type) != INTEGER_TYPE || !array_size
223*4882a593Smuzhiyun || TREE_CODE(array_size) != INTEGER_CST) {
224*4882a593Smuzhiyun *no_add_attrs = true;
225*4882a593Smuzhiyun error("array variable %qD with %qE attribute must be a fixed length integer array type",
226*4882a593Smuzhiyun *node, name);
227*4882a593Smuzhiyun break;
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun array_size_int = TREE_INT_CST_LOW(array_size);
231*4882a593Smuzhiyun elt_size_int = TREE_INT_CST_LOW(elt_size);
232*4882a593Smuzhiyun nelt = array_size_int / elt_size_int;
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun #if BUILDING_GCC_VERSION <= 4007
235*4882a593Smuzhiyun vals = VEC_alloc(constructor_elt, gc, nelt);
236*4882a593Smuzhiyun #else
237*4882a593Smuzhiyun vec_alloc(vals, nelt);
238*4882a593Smuzhiyun #endif
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun for (i = 0; i < nelt; i++) {
241*4882a593Smuzhiyun tree cst = size_int(i);
242*4882a593Smuzhiyun tree rand_cst = tree_get_random_const(elt_type);
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun CONSTRUCTOR_APPEND_ELT(vals, cst, rand_cst);
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun /*
248*4882a593Smuzhiyun * Initialize the elements of the array with random
249*4882a593Smuzhiyun * constants
250*4882a593Smuzhiyun */
251*4882a593Smuzhiyun DECL_INITIAL(*node) = build_constructor(type, vals);
252*4882a593Smuzhiyun break;
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun break;
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun case FUNCTION_DECL:
258*4882a593Smuzhiyun break;
259*4882a593Smuzhiyun }
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun return NULL_TREE;
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun static struct attribute_spec latent_entropy_attr = { };
265*4882a593Smuzhiyun
register_attributes(void * event_data __unused,void * data __unused)266*4882a593Smuzhiyun static void register_attributes(void *event_data __unused, void *data __unused)
267*4882a593Smuzhiyun {
268*4882a593Smuzhiyun latent_entropy_attr.name = "latent_entropy";
269*4882a593Smuzhiyun latent_entropy_attr.decl_required = true;
270*4882a593Smuzhiyun latent_entropy_attr.handler = handle_latent_entropy_attribute;
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun register_attribute(&latent_entropy_attr);
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun
latent_entropy_gate(void)275*4882a593Smuzhiyun static bool latent_entropy_gate(void)
276*4882a593Smuzhiyun {
277*4882a593Smuzhiyun tree list;
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun /* don't bother with noreturn functions for now */
280*4882a593Smuzhiyun if (TREE_THIS_VOLATILE(current_function_decl))
281*4882a593Smuzhiyun return false;
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun /* gcc-4.5 doesn't discover some trivial noreturn functions */
284*4882a593Smuzhiyun if (EDGE_COUNT(EXIT_BLOCK_PTR_FOR_FN(cfun)->preds) == 0)
285*4882a593Smuzhiyun return false;
286*4882a593Smuzhiyun
287*4882a593Smuzhiyun list = DECL_ATTRIBUTES(current_function_decl);
288*4882a593Smuzhiyun return lookup_attribute("latent_entropy", list) != NULL_TREE;
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun
create_var(tree type,const char * name)291*4882a593Smuzhiyun static tree create_var(tree type, const char *name)
292*4882a593Smuzhiyun {
293*4882a593Smuzhiyun tree var;
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun var = create_tmp_var(type, name);
296*4882a593Smuzhiyun add_referenced_var(var);
297*4882a593Smuzhiyun mark_sym_for_renaming(var);
298*4882a593Smuzhiyun return var;
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun /*
302*4882a593Smuzhiyun * Set up the next operation and its constant operand to use in the latent
303*4882a593Smuzhiyun * entropy PRNG. When RHS is specified, the request is for perturbing the
304*4882a593Smuzhiyun * local latent entropy variable, otherwise it is for perturbing the global
305*4882a593Smuzhiyun * latent entropy variable where the two operands are already given by the
306*4882a593Smuzhiyun * local and global latent entropy variables themselves.
307*4882a593Smuzhiyun *
308*4882a593Smuzhiyun * The operation is one of add/xor/rol when instrumenting the local entropy
309*4882a593Smuzhiyun * variable and one of add/xor when perturbing the global entropy variable.
310*4882a593Smuzhiyun * Rotation is not used for the latter case because it would transmit less
311*4882a593Smuzhiyun * entropy to the global variable than the other two operations.
312*4882a593Smuzhiyun */
get_op(tree * rhs)313*4882a593Smuzhiyun static enum tree_code get_op(tree *rhs)
314*4882a593Smuzhiyun {
315*4882a593Smuzhiyun static enum tree_code op;
316*4882a593Smuzhiyun unsigned HOST_WIDE_INT random_const;
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun random_const = get_random_const();
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun switch (op) {
321*4882a593Smuzhiyun case BIT_XOR_EXPR:
322*4882a593Smuzhiyun op = PLUS_EXPR;
323*4882a593Smuzhiyun break;
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun case PLUS_EXPR:
326*4882a593Smuzhiyun if (rhs) {
327*4882a593Smuzhiyun op = LROTATE_EXPR;
328*4882a593Smuzhiyun /*
329*4882a593Smuzhiyun * This code limits the value of random_const to
330*4882a593Smuzhiyun * the size of a long for the rotation
331*4882a593Smuzhiyun */
332*4882a593Smuzhiyun random_const %= TYPE_PRECISION(long_unsigned_type_node);
333*4882a593Smuzhiyun break;
334*4882a593Smuzhiyun }
335*4882a593Smuzhiyun
336*4882a593Smuzhiyun case LROTATE_EXPR:
337*4882a593Smuzhiyun default:
338*4882a593Smuzhiyun op = BIT_XOR_EXPR;
339*4882a593Smuzhiyun break;
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun if (rhs)
342*4882a593Smuzhiyun *rhs = build_int_cstu(long_unsigned_type_node, random_const);
343*4882a593Smuzhiyun return op;
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun
create_assign(enum tree_code code,tree lhs,tree op1,tree op2)346*4882a593Smuzhiyun static gimple create_assign(enum tree_code code, tree lhs, tree op1,
347*4882a593Smuzhiyun tree op2)
348*4882a593Smuzhiyun {
349*4882a593Smuzhiyun return gimple_build_assign_with_ops(code, lhs, op1, op2);
350*4882a593Smuzhiyun }
351*4882a593Smuzhiyun
perturb_local_entropy(basic_block bb,tree local_entropy)352*4882a593Smuzhiyun static void perturb_local_entropy(basic_block bb, tree local_entropy)
353*4882a593Smuzhiyun {
354*4882a593Smuzhiyun gimple_stmt_iterator gsi;
355*4882a593Smuzhiyun gimple assign;
356*4882a593Smuzhiyun tree rhs;
357*4882a593Smuzhiyun enum tree_code op;
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun op = get_op(&rhs);
360*4882a593Smuzhiyun assign = create_assign(op, local_entropy, local_entropy, rhs);
361*4882a593Smuzhiyun gsi = gsi_after_labels(bb);
362*4882a593Smuzhiyun gsi_insert_before(&gsi, assign, GSI_NEW_STMT);
363*4882a593Smuzhiyun update_stmt(assign);
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun
__perturb_latent_entropy(gimple_stmt_iterator * gsi,tree local_entropy)366*4882a593Smuzhiyun static void __perturb_latent_entropy(gimple_stmt_iterator *gsi,
367*4882a593Smuzhiyun tree local_entropy)
368*4882a593Smuzhiyun {
369*4882a593Smuzhiyun gimple assign;
370*4882a593Smuzhiyun tree temp;
371*4882a593Smuzhiyun enum tree_code op;
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun /* 1. create temporary copy of latent_entropy */
374*4882a593Smuzhiyun temp = create_var(long_unsigned_type_node, "temp_latent_entropy");
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun /* 2. read... */
377*4882a593Smuzhiyun add_referenced_var(latent_entropy_decl);
378*4882a593Smuzhiyun mark_sym_for_renaming(latent_entropy_decl);
379*4882a593Smuzhiyun assign = gimple_build_assign(temp, latent_entropy_decl);
380*4882a593Smuzhiyun gsi_insert_before(gsi, assign, GSI_NEW_STMT);
381*4882a593Smuzhiyun update_stmt(assign);
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun /* 3. ...modify... */
384*4882a593Smuzhiyun op = get_op(NULL);
385*4882a593Smuzhiyun assign = create_assign(op, temp, temp, local_entropy);
386*4882a593Smuzhiyun gsi_insert_after(gsi, assign, GSI_NEW_STMT);
387*4882a593Smuzhiyun update_stmt(assign);
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun /* 4. ...write latent_entropy */
390*4882a593Smuzhiyun assign = gimple_build_assign(latent_entropy_decl, temp);
391*4882a593Smuzhiyun gsi_insert_after(gsi, assign, GSI_NEW_STMT);
392*4882a593Smuzhiyun update_stmt(assign);
393*4882a593Smuzhiyun }
394*4882a593Smuzhiyun
handle_tail_calls(basic_block bb,tree local_entropy)395*4882a593Smuzhiyun static bool handle_tail_calls(basic_block bb, tree local_entropy)
396*4882a593Smuzhiyun {
397*4882a593Smuzhiyun gimple_stmt_iterator gsi;
398*4882a593Smuzhiyun
399*4882a593Smuzhiyun for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) {
400*4882a593Smuzhiyun gcall *call;
401*4882a593Smuzhiyun gimple stmt = gsi_stmt(gsi);
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun if (!is_gimple_call(stmt))
404*4882a593Smuzhiyun continue;
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun call = as_a_gcall(stmt);
407*4882a593Smuzhiyun if (!gimple_call_tail_p(call))
408*4882a593Smuzhiyun continue;
409*4882a593Smuzhiyun
410*4882a593Smuzhiyun __perturb_latent_entropy(&gsi, local_entropy);
411*4882a593Smuzhiyun return true;
412*4882a593Smuzhiyun }
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun return false;
415*4882a593Smuzhiyun }
416*4882a593Smuzhiyun
perturb_latent_entropy(tree local_entropy)417*4882a593Smuzhiyun static void perturb_latent_entropy(tree local_entropy)
418*4882a593Smuzhiyun {
419*4882a593Smuzhiyun edge_iterator ei;
420*4882a593Smuzhiyun edge e, last_bb_e;
421*4882a593Smuzhiyun basic_block last_bb;
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun gcc_assert(single_pred_p(EXIT_BLOCK_PTR_FOR_FN(cfun)));
424*4882a593Smuzhiyun last_bb_e = single_pred_edge(EXIT_BLOCK_PTR_FOR_FN(cfun));
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun FOR_EACH_EDGE(e, ei, last_bb_e->src->preds) {
427*4882a593Smuzhiyun if (ENTRY_BLOCK_PTR_FOR_FN(cfun) == e->src)
428*4882a593Smuzhiyun continue;
429*4882a593Smuzhiyun if (EXIT_BLOCK_PTR_FOR_FN(cfun) == e->src)
430*4882a593Smuzhiyun continue;
431*4882a593Smuzhiyun
432*4882a593Smuzhiyun handle_tail_calls(e->src, local_entropy);
433*4882a593Smuzhiyun }
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun last_bb = single_pred(EXIT_BLOCK_PTR_FOR_FN(cfun));
436*4882a593Smuzhiyun if (!handle_tail_calls(last_bb, local_entropy)) {
437*4882a593Smuzhiyun gimple_stmt_iterator gsi = gsi_last_bb(last_bb);
438*4882a593Smuzhiyun
439*4882a593Smuzhiyun __perturb_latent_entropy(&gsi, local_entropy);
440*4882a593Smuzhiyun }
441*4882a593Smuzhiyun }
442*4882a593Smuzhiyun
init_local_entropy(basic_block bb,tree local_entropy)443*4882a593Smuzhiyun static void init_local_entropy(basic_block bb, tree local_entropy)
444*4882a593Smuzhiyun {
445*4882a593Smuzhiyun gimple assign, call;
446*4882a593Smuzhiyun tree frame_addr, rand_const, tmp, fndecl, udi_frame_addr;
447*4882a593Smuzhiyun enum tree_code op;
448*4882a593Smuzhiyun unsigned HOST_WIDE_INT rand_cst;
449*4882a593Smuzhiyun gimple_stmt_iterator gsi = gsi_after_labels(bb);
450*4882a593Smuzhiyun
451*4882a593Smuzhiyun /* 1. create local_entropy_frameaddr */
452*4882a593Smuzhiyun frame_addr = create_var(ptr_type_node, "local_entropy_frameaddr");
453*4882a593Smuzhiyun
454*4882a593Smuzhiyun /* 2. local_entropy_frameaddr = __builtin_frame_address() */
455*4882a593Smuzhiyun fndecl = builtin_decl_implicit(BUILT_IN_FRAME_ADDRESS);
456*4882a593Smuzhiyun call = gimple_build_call(fndecl, 1, integer_zero_node);
457*4882a593Smuzhiyun gimple_call_set_lhs(call, frame_addr);
458*4882a593Smuzhiyun gsi_insert_before(&gsi, call, GSI_NEW_STMT);
459*4882a593Smuzhiyun update_stmt(call);
460*4882a593Smuzhiyun
461*4882a593Smuzhiyun udi_frame_addr = fold_convert(long_unsigned_type_node, frame_addr);
462*4882a593Smuzhiyun assign = gimple_build_assign(local_entropy, udi_frame_addr);
463*4882a593Smuzhiyun gsi_insert_after(&gsi, assign, GSI_NEW_STMT);
464*4882a593Smuzhiyun update_stmt(assign);
465*4882a593Smuzhiyun
466*4882a593Smuzhiyun /* 3. create temporary copy of latent_entropy */
467*4882a593Smuzhiyun tmp = create_var(long_unsigned_type_node, "temp_latent_entropy");
468*4882a593Smuzhiyun
469*4882a593Smuzhiyun /* 4. read the global entropy variable into local entropy */
470*4882a593Smuzhiyun add_referenced_var(latent_entropy_decl);
471*4882a593Smuzhiyun mark_sym_for_renaming(latent_entropy_decl);
472*4882a593Smuzhiyun assign = gimple_build_assign(tmp, latent_entropy_decl);
473*4882a593Smuzhiyun gsi_insert_after(&gsi, assign, GSI_NEW_STMT);
474*4882a593Smuzhiyun update_stmt(assign);
475*4882a593Smuzhiyun
476*4882a593Smuzhiyun /* 5. mix local_entropy_frameaddr into local entropy */
477*4882a593Smuzhiyun assign = create_assign(BIT_XOR_EXPR, local_entropy, local_entropy, tmp);
478*4882a593Smuzhiyun gsi_insert_after(&gsi, assign, GSI_NEW_STMT);
479*4882a593Smuzhiyun update_stmt(assign);
480*4882a593Smuzhiyun
481*4882a593Smuzhiyun rand_cst = get_random_const();
482*4882a593Smuzhiyun rand_const = build_int_cstu(long_unsigned_type_node, rand_cst);
483*4882a593Smuzhiyun op = get_op(NULL);
484*4882a593Smuzhiyun assign = create_assign(op, local_entropy, local_entropy, rand_const);
485*4882a593Smuzhiyun gsi_insert_after(&gsi, assign, GSI_NEW_STMT);
486*4882a593Smuzhiyun update_stmt(assign);
487*4882a593Smuzhiyun }
488*4882a593Smuzhiyun
create_latent_entropy_decl(void)489*4882a593Smuzhiyun static bool create_latent_entropy_decl(void)
490*4882a593Smuzhiyun {
491*4882a593Smuzhiyun varpool_node_ptr node;
492*4882a593Smuzhiyun
493*4882a593Smuzhiyun if (latent_entropy_decl != NULL_TREE)
494*4882a593Smuzhiyun return true;
495*4882a593Smuzhiyun
496*4882a593Smuzhiyun FOR_EACH_VARIABLE(node) {
497*4882a593Smuzhiyun tree name, var = NODE_DECL(node);
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun if (DECL_NAME_LENGTH(var) < sizeof("latent_entropy") - 1)
500*4882a593Smuzhiyun continue;
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun name = DECL_NAME(var);
503*4882a593Smuzhiyun if (strcmp(IDENTIFIER_POINTER(name), "latent_entropy"))
504*4882a593Smuzhiyun continue;
505*4882a593Smuzhiyun
506*4882a593Smuzhiyun latent_entropy_decl = var;
507*4882a593Smuzhiyun break;
508*4882a593Smuzhiyun }
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun return latent_entropy_decl != NULL_TREE;
511*4882a593Smuzhiyun }
512*4882a593Smuzhiyun
latent_entropy_execute(void)513*4882a593Smuzhiyun static unsigned int latent_entropy_execute(void)
514*4882a593Smuzhiyun {
515*4882a593Smuzhiyun basic_block bb;
516*4882a593Smuzhiyun tree local_entropy;
517*4882a593Smuzhiyun
518*4882a593Smuzhiyun if (!create_latent_entropy_decl())
519*4882a593Smuzhiyun return 0;
520*4882a593Smuzhiyun
521*4882a593Smuzhiyun /* prepare for step 2 below */
522*4882a593Smuzhiyun gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun)));
523*4882a593Smuzhiyun bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun));
524*4882a593Smuzhiyun if (!single_pred_p(bb)) {
525*4882a593Smuzhiyun split_edge(single_succ_edge(ENTRY_BLOCK_PTR_FOR_FN(cfun)));
526*4882a593Smuzhiyun gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun)));
527*4882a593Smuzhiyun bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun));
528*4882a593Smuzhiyun }
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun /* 1. create the local entropy variable */
531*4882a593Smuzhiyun local_entropy = create_var(long_unsigned_type_node, "local_entropy");
532*4882a593Smuzhiyun
533*4882a593Smuzhiyun /* 2. initialize the local entropy variable */
534*4882a593Smuzhiyun init_local_entropy(bb, local_entropy);
535*4882a593Smuzhiyun
536*4882a593Smuzhiyun bb = bb->next_bb;
537*4882a593Smuzhiyun
538*4882a593Smuzhiyun /*
539*4882a593Smuzhiyun * 3. instrument each BB with an operation on the
540*4882a593Smuzhiyun * local entropy variable
541*4882a593Smuzhiyun */
542*4882a593Smuzhiyun while (bb != EXIT_BLOCK_PTR_FOR_FN(cfun)) {
543*4882a593Smuzhiyun perturb_local_entropy(bb, local_entropy);
544*4882a593Smuzhiyun bb = bb->next_bb;
545*4882a593Smuzhiyun };
546*4882a593Smuzhiyun
547*4882a593Smuzhiyun /* 4. mix local entropy into the global entropy variable */
548*4882a593Smuzhiyun perturb_latent_entropy(local_entropy);
549*4882a593Smuzhiyun return 0;
550*4882a593Smuzhiyun }
551*4882a593Smuzhiyun
latent_entropy_start_unit(void * gcc_data __unused,void * user_data __unused)552*4882a593Smuzhiyun static void latent_entropy_start_unit(void *gcc_data __unused,
553*4882a593Smuzhiyun void *user_data __unused)
554*4882a593Smuzhiyun {
555*4882a593Smuzhiyun tree type, id;
556*4882a593Smuzhiyun int quals;
557*4882a593Smuzhiyun
558*4882a593Smuzhiyun if (in_lto_p)
559*4882a593Smuzhiyun return;
560*4882a593Smuzhiyun
561*4882a593Smuzhiyun /* extern volatile unsigned long latent_entropy */
562*4882a593Smuzhiyun quals = TYPE_QUALS(long_unsigned_type_node) | TYPE_QUAL_VOLATILE;
563*4882a593Smuzhiyun type = build_qualified_type(long_unsigned_type_node, quals);
564*4882a593Smuzhiyun id = get_identifier("latent_entropy");
565*4882a593Smuzhiyun latent_entropy_decl = build_decl(UNKNOWN_LOCATION, VAR_DECL, id, type);
566*4882a593Smuzhiyun
567*4882a593Smuzhiyun TREE_STATIC(latent_entropy_decl) = 1;
568*4882a593Smuzhiyun TREE_PUBLIC(latent_entropy_decl) = 1;
569*4882a593Smuzhiyun TREE_USED(latent_entropy_decl) = 1;
570*4882a593Smuzhiyun DECL_PRESERVE_P(latent_entropy_decl) = 1;
571*4882a593Smuzhiyun TREE_THIS_VOLATILE(latent_entropy_decl) = 1;
572*4882a593Smuzhiyun DECL_EXTERNAL(latent_entropy_decl) = 1;
573*4882a593Smuzhiyun DECL_ARTIFICIAL(latent_entropy_decl) = 1;
574*4882a593Smuzhiyun lang_hooks.decls.pushdecl(latent_entropy_decl);
575*4882a593Smuzhiyun }
576*4882a593Smuzhiyun
577*4882a593Smuzhiyun #define PASS_NAME latent_entropy
578*4882a593Smuzhiyun #define PROPERTIES_REQUIRED PROP_gimple_leh | PROP_cfg
579*4882a593Smuzhiyun #define TODO_FLAGS_FINISH TODO_verify_ssa | TODO_verify_stmts | TODO_dump_func \
580*4882a593Smuzhiyun | TODO_update_ssa
581*4882a593Smuzhiyun #include "gcc-generate-gimple-pass.h"
582*4882a593Smuzhiyun
plugin_init(struct plugin_name_args * plugin_info,struct plugin_gcc_version * version)583*4882a593Smuzhiyun __visible int plugin_init(struct plugin_name_args *plugin_info,
584*4882a593Smuzhiyun struct plugin_gcc_version *version)
585*4882a593Smuzhiyun {
586*4882a593Smuzhiyun bool enabled = true;
587*4882a593Smuzhiyun const char * const plugin_name = plugin_info->base_name;
588*4882a593Smuzhiyun const int argc = plugin_info->argc;
589*4882a593Smuzhiyun const struct plugin_argument * const argv = plugin_info->argv;
590*4882a593Smuzhiyun int i;
591*4882a593Smuzhiyun
592*4882a593Smuzhiyun /*
593*4882a593Smuzhiyun * Call get_random_seed() with noinit=true, so that this returns
594*4882a593Smuzhiyun * 0 in the case where no seed has been passed via -frandom-seed.
595*4882a593Smuzhiyun */
596*4882a593Smuzhiyun deterministic_seed = get_random_seed(true);
597*4882a593Smuzhiyun
598*4882a593Smuzhiyun static const struct ggc_root_tab gt_ggc_r_gt_latent_entropy[] = {
599*4882a593Smuzhiyun {
600*4882a593Smuzhiyun .base = &latent_entropy_decl,
601*4882a593Smuzhiyun .nelt = 1,
602*4882a593Smuzhiyun .stride = sizeof(latent_entropy_decl),
603*4882a593Smuzhiyun .cb = >_ggc_mx_tree_node,
604*4882a593Smuzhiyun .pchw = >_pch_nx_tree_node
605*4882a593Smuzhiyun },
606*4882a593Smuzhiyun LAST_GGC_ROOT_TAB
607*4882a593Smuzhiyun };
608*4882a593Smuzhiyun
609*4882a593Smuzhiyun PASS_INFO(latent_entropy, "optimized", 1, PASS_POS_INSERT_BEFORE);
610*4882a593Smuzhiyun
611*4882a593Smuzhiyun if (!plugin_default_version_check(version, &gcc_version)) {
612*4882a593Smuzhiyun error(G_("incompatible gcc/plugin versions"));
613*4882a593Smuzhiyun return 1;
614*4882a593Smuzhiyun }
615*4882a593Smuzhiyun
616*4882a593Smuzhiyun for (i = 0; i < argc; ++i) {
617*4882a593Smuzhiyun if (!(strcmp(argv[i].key, "disable"))) {
618*4882a593Smuzhiyun enabled = false;
619*4882a593Smuzhiyun continue;
620*4882a593Smuzhiyun }
621*4882a593Smuzhiyun error(G_("unknown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key);
622*4882a593Smuzhiyun }
623*4882a593Smuzhiyun
624*4882a593Smuzhiyun register_callback(plugin_name, PLUGIN_INFO, NULL,
625*4882a593Smuzhiyun &latent_entropy_plugin_info);
626*4882a593Smuzhiyun if (enabled) {
627*4882a593Smuzhiyun register_callback(plugin_name, PLUGIN_START_UNIT,
628*4882a593Smuzhiyun &latent_entropy_start_unit, NULL);
629*4882a593Smuzhiyun register_callback(plugin_name, PLUGIN_REGISTER_GGC_ROOTS,
630*4882a593Smuzhiyun NULL, (void *)>_ggc_r_gt_latent_entropy);
631*4882a593Smuzhiyun register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL,
632*4882a593Smuzhiyun &latent_entropy_pass_info);
633*4882a593Smuzhiyun }
634*4882a593Smuzhiyun register_callback(plugin_name, PLUGIN_ATTRIBUTES, register_attributes,
635*4882a593Smuzhiyun NULL);
636*4882a593Smuzhiyun
637*4882a593Smuzhiyun return 0;
638*4882a593Smuzhiyun }
639