1*38fd1498Szrj /* Pointer Bounds Checker insrumentation pass. 2*38fd1498Szrj Copyright (C) 2014-2018 Free Software Foundation, Inc. 3*38fd1498Szrj Contributed by Ilya Enkovich (ilya.enkovich@intel.com) 4*38fd1498Szrj 5*38fd1498Szrj This file is part of GCC. 6*38fd1498Szrj 7*38fd1498Szrj GCC is free software; you can redistribute it and/or modify it under 8*38fd1498Szrj the terms of the GNU General Public License as published by the Free 9*38fd1498Szrj Software Foundation; either version 3, or (at your option) any later 10*38fd1498Szrj version. 11*38fd1498Szrj 12*38fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY 13*38fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or 14*38fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15*38fd1498Szrj for more details. 16*38fd1498Szrj 17*38fd1498Szrj You should have received a copy of the GNU General Public License 18*38fd1498Szrj along with GCC; see the file COPYING3. If not see 19*38fd1498Szrj <http://www.gnu.org/licenses/>. */ 20*38fd1498Szrj 21*38fd1498Szrj #include "config.h" 22*38fd1498Szrj #include "system.h" 23*38fd1498Szrj #include "coretypes.h" 24*38fd1498Szrj #include "backend.h" 25*38fd1498Szrj #include "target.h" 26*38fd1498Szrj #include "rtl.h" 27*38fd1498Szrj #include "tree.h" 28*38fd1498Szrj #include "gimple.h" 29*38fd1498Szrj #include "cfghooks.h" 30*38fd1498Szrj #include "tree-pass.h" 31*38fd1498Szrj #include "ssa.h" 32*38fd1498Szrj #include "cgraph.h" 33*38fd1498Szrj #include "diagnostic.h" 34*38fd1498Szrj #include "fold-const.h" 35*38fd1498Szrj #include "stor-layout.h" 36*38fd1498Szrj #include "varasm.h" 37*38fd1498Szrj #include "tree-iterator.h" 38*38fd1498Szrj #include "tree-cfg.h" 39*38fd1498Szrj #include "langhooks.h" 40*38fd1498Szrj #include "tree-ssa-address.h" 41*38fd1498Szrj #include "tree-ssa-loop-niter.h" 42*38fd1498Szrj #include "gimple-pretty-print.h" 43*38fd1498Szrj #include "gimple-iterator.h" 44*38fd1498Szrj #include "gimplify.h" 45*38fd1498Szrj #include "gimplify-me.h" 46*38fd1498Szrj #include "print-tree.h" 47*38fd1498Szrj #include "calls.h" 48*38fd1498Szrj #include "expr.h" 49*38fd1498Szrj #include "tree-ssa-propagate.h" 50*38fd1498Szrj #include "tree-chkp.h" 51*38fd1498Szrj #include "gimple-walk.h" 52*38fd1498Szrj #include "tree-dfa.h" 53*38fd1498Szrj #include "ipa-chkp.h" 54*38fd1498Szrj #include "params.h" 55*38fd1498Szrj #include "stringpool.h" 56*38fd1498Szrj #include "attribs.h" 57*38fd1498Szrj 58*38fd1498Szrj /* Pointer Bounds Checker instruments code with memory checks to find 59*38fd1498Szrj out-of-bounds memory accesses. Checks are performed by computing 60*38fd1498Szrj bounds for each pointer and then comparing address of accessed 61*38fd1498Szrj memory before pointer dereferencing. 62*38fd1498Szrj 63*38fd1498Szrj 1. Function clones. 64*38fd1498Szrj 65*38fd1498Szrj See ipa-chkp.c. 66*38fd1498Szrj 67*38fd1498Szrj 2. Instrumentation. 68*38fd1498Szrj 69*38fd1498Szrj There are few things to instrument: 70*38fd1498Szrj 71*38fd1498Szrj a) Memory accesses - add checker calls to check address of accessed memory 72*38fd1498Szrj against bounds of dereferenced pointer. Obviously safe memory 73*38fd1498Szrj accesses like static variable access does not have to be instrumented 74*38fd1498Szrj with checks. 75*38fd1498Szrj 76*38fd1498Szrj Example: 77*38fd1498Szrj 78*38fd1498Szrj val_2 = *p_1; 79*38fd1498Szrj 80*38fd1498Szrj with 4 bytes access is transformed into: 81*38fd1498Szrj 82*38fd1498Szrj __builtin___chkp_bndcl (__bound_tmp.1_3, p_1); 83*38fd1498Szrj D.1_4 = p_1 + 3; 84*38fd1498Szrj __builtin___chkp_bndcu (__bound_tmp.1_3, D.1_4); 85*38fd1498Szrj val_2 = *p_1; 86*38fd1498Szrj 87*38fd1498Szrj where __bound_tmp.1_3 are bounds computed for pointer p_1, 88*38fd1498Szrj __builtin___chkp_bndcl is a lower bound check and 89*38fd1498Szrj __builtin___chkp_bndcu is an upper bound check. 90*38fd1498Szrj 91*38fd1498Szrj b) Pointer stores. 92*38fd1498Szrj 93*38fd1498Szrj When pointer is stored in memory we need to store its bounds. To 94*38fd1498Szrj achieve compatibility of instrumented code with regular codes 95*38fd1498Szrj we have to keep data layout and store bounds in special bound tables 96*38fd1498Szrj via special checker call. Implementation of bounds table may vary for 97*38fd1498Szrj different platforms. It has to associate pointer value and its 98*38fd1498Szrj location (it is required because we may have two equal pointers 99*38fd1498Szrj with different bounds stored in different places) with bounds. 100*38fd1498Szrj Another checker builtin allows to get bounds for specified pointer 101*38fd1498Szrj loaded from specified location. 102*38fd1498Szrj 103*38fd1498Szrj Example: 104*38fd1498Szrj 105*38fd1498Szrj buf1[i_1] = &buf2; 106*38fd1498Szrj 107*38fd1498Szrj is transformed into: 108*38fd1498Szrj 109*38fd1498Szrj buf1[i_1] = &buf2; 110*38fd1498Szrj D.1_2 = &buf1[i_1]; 111*38fd1498Szrj __builtin___chkp_bndstx (D.1_2, &buf2, __bound_tmp.1_2); 112*38fd1498Szrj 113*38fd1498Szrj where __bound_tmp.1_2 are bounds of &buf2. 114*38fd1498Szrj 115*38fd1498Szrj c) Static initialization. 116*38fd1498Szrj 117*38fd1498Szrj The special case of pointer store is static pointer initialization. 118*38fd1498Szrj Bounds initialization is performed in a few steps: 119*38fd1498Szrj - register all static initializations in front-end using 120*38fd1498Szrj chkp_register_var_initializer 121*38fd1498Szrj - when file compilation finishes we create functions with special 122*38fd1498Szrj attribute 'chkp ctor' and put explicit initialization code 123*38fd1498Szrj (assignments) for all statically initialized pointers. 124*38fd1498Szrj - when checker constructor is compiled checker pass adds required 125*38fd1498Szrj bounds initialization for all statically initialized pointers 126*38fd1498Szrj - since we do not actually need excess pointers initialization 127*38fd1498Szrj in checker constructor we remove such assignments from them 128*38fd1498Szrj 129*38fd1498Szrj d) Calls. 130*38fd1498Szrj 131*38fd1498Szrj For each call in the code we add additional arguments to pass 132*38fd1498Szrj bounds for pointer arguments. We determine type of call arguments 133*38fd1498Szrj using arguments list from function declaration; if function 134*38fd1498Szrj declaration is not available we use function type; otherwise 135*38fd1498Szrj (e.g. for unnamed arguments) we use type of passed value. Function 136*38fd1498Szrj declaration/type is replaced with the instrumented one. 137*38fd1498Szrj 138*38fd1498Szrj Example: 139*38fd1498Szrj 140*38fd1498Szrj val_1 = foo (&buf1, &buf2, &buf1, 0); 141*38fd1498Szrj 142*38fd1498Szrj is translated into: 143*38fd1498Szrj 144*38fd1498Szrj val_1 = foo.chkp (&buf1, __bound_tmp.1_2, &buf2, __bound_tmp.1_3, 145*38fd1498Szrj &buf1, __bound_tmp.1_2, 0); 146*38fd1498Szrj 147*38fd1498Szrj e) Returns. 148*38fd1498Szrj 149*38fd1498Szrj If function returns a pointer value we have to return bounds also. 150*38fd1498Szrj A new operand was added for return statement to hold returned bounds. 151*38fd1498Szrj 152*38fd1498Szrj Example: 153*38fd1498Szrj 154*38fd1498Szrj return &_buf1; 155*38fd1498Szrj 156*38fd1498Szrj is transformed into 157*38fd1498Szrj 158*38fd1498Szrj return &_buf1, __bound_tmp.1_1; 159*38fd1498Szrj 160*38fd1498Szrj 3. Bounds computation. 161*38fd1498Szrj 162*38fd1498Szrj Compiler is fully responsible for computing bounds to be used for each 163*38fd1498Szrj memory access. The first step for bounds computation is to find the 164*38fd1498Szrj origin of pointer dereferenced for memory access. Basing on pointer 165*38fd1498Szrj origin we define a way to compute its bounds. There are just few 166*38fd1498Szrj possible cases: 167*38fd1498Szrj 168*38fd1498Szrj a) Pointer is returned by call. 169*38fd1498Szrj 170*38fd1498Szrj In this case we use corresponding checker builtin method to obtain returned 171*38fd1498Szrj bounds. 172*38fd1498Szrj 173*38fd1498Szrj Example: 174*38fd1498Szrj 175*38fd1498Szrj buf_1 = malloc (size_2); 176*38fd1498Szrj foo (buf_1); 177*38fd1498Szrj 178*38fd1498Szrj is translated into: 179*38fd1498Szrj 180*38fd1498Szrj buf_1 = malloc (size_2); 181*38fd1498Szrj __bound_tmp.1_3 = __builtin___chkp_bndret (buf_1); 182*38fd1498Szrj foo (buf_1, __bound_tmp.1_3); 183*38fd1498Szrj 184*38fd1498Szrj b) Pointer is an address of an object. 185*38fd1498Szrj 186*38fd1498Szrj In this case compiler tries to compute objects size and create corresponding 187*38fd1498Szrj bounds. If object has incomplete type then special checker builtin is used to 188*38fd1498Szrj obtain its size at runtime. 189*38fd1498Szrj 190*38fd1498Szrj Example: 191*38fd1498Szrj 192*38fd1498Szrj foo () 193*38fd1498Szrj { 194*38fd1498Szrj <unnamed type> __bound_tmp.3; 195*38fd1498Szrj static int buf[100]; 196*38fd1498Szrj 197*38fd1498Szrj <bb 3>: 198*38fd1498Szrj __bound_tmp.3_2 = __builtin___chkp_bndmk (&buf, 400); 199*38fd1498Szrj 200*38fd1498Szrj <bb 2>: 201*38fd1498Szrj return &buf, __bound_tmp.3_2; 202*38fd1498Szrj } 203*38fd1498Szrj 204*38fd1498Szrj Example: 205*38fd1498Szrj 206*38fd1498Szrj Address of an object 'extern int buf[]' with incomplete type is 207*38fd1498Szrj returned. 208*38fd1498Szrj 209*38fd1498Szrj foo () 210*38fd1498Szrj { 211*38fd1498Szrj <unnamed type> __bound_tmp.4; 212*38fd1498Szrj long unsigned int __size_tmp.3; 213*38fd1498Szrj 214*38fd1498Szrj <bb 3>: 215*38fd1498Szrj __size_tmp.3_4 = __builtin_ia32_sizeof (buf); 216*38fd1498Szrj __bound_tmp.4_3 = __builtin_ia32_bndmk (&buf, __size_tmp.3_4); 217*38fd1498Szrj 218*38fd1498Szrj <bb 2>: 219*38fd1498Szrj return &buf, __bound_tmp.4_3; 220*38fd1498Szrj } 221*38fd1498Szrj 222*38fd1498Szrj c) Pointer is the result of object narrowing. 223*38fd1498Szrj 224*38fd1498Szrj It happens when we use pointer to an object to compute pointer to a part 225*38fd1498Szrj of an object. E.g. we take pointer to a field of a structure. In this 226*38fd1498Szrj case we perform bounds intersection using bounds of original object and 227*38fd1498Szrj bounds of object's part (which are computed basing on its type). 228*38fd1498Szrj 229*38fd1498Szrj There may be some debatable questions about when narrowing should occur 230*38fd1498Szrj and when it should not. To avoid false bound violations in correct 231*38fd1498Szrj programs we do not perform narrowing when address of an array element is 232*38fd1498Szrj obtained (it has address of the whole array) and when address of the first 233*38fd1498Szrj structure field is obtained (because it is guaranteed to be equal to 234*38fd1498Szrj address of the whole structure and it is legal to cast it back to structure). 235*38fd1498Szrj 236*38fd1498Szrj Default narrowing behavior may be changed using compiler flags. 237*38fd1498Szrj 238*38fd1498Szrj Example: 239*38fd1498Szrj 240*38fd1498Szrj In this example address of the second structure field is returned. 241*38fd1498Szrj 242*38fd1498Szrj foo (struct A * p, __bounds_type __bounds_of_p) 243*38fd1498Szrj { 244*38fd1498Szrj <unnamed type> __bound_tmp.3; 245*38fd1498Szrj int * _2; 246*38fd1498Szrj int * _5; 247*38fd1498Szrj 248*38fd1498Szrj <bb 2>: 249*38fd1498Szrj _5 = &p_1(D)->second_field; 250*38fd1498Szrj __bound_tmp.3_6 = __builtin___chkp_bndmk (_5, 4); 251*38fd1498Szrj __bound_tmp.3_8 = __builtin___chkp_intersect (__bound_tmp.3_6, 252*38fd1498Szrj __bounds_of_p_3(D)); 253*38fd1498Szrj _2 = &p_1(D)->second_field; 254*38fd1498Szrj return _2, __bound_tmp.3_8; 255*38fd1498Szrj } 256*38fd1498Szrj 257*38fd1498Szrj Example: 258*38fd1498Szrj 259*38fd1498Szrj In this example address of the first field of array element is returned. 260*38fd1498Szrj 261*38fd1498Szrj foo (struct A * p, __bounds_type __bounds_of_p, int i) 262*38fd1498Szrj { 263*38fd1498Szrj long unsigned int _3; 264*38fd1498Szrj long unsigned int _4; 265*38fd1498Szrj struct A * _6; 266*38fd1498Szrj int * _7; 267*38fd1498Szrj 268*38fd1498Szrj <bb 2>: 269*38fd1498Szrj _3 = (long unsigned int) i_1(D); 270*38fd1498Szrj _4 = _3 * 8; 271*38fd1498Szrj _6 = p_5(D) + _4; 272*38fd1498Szrj _7 = &_6->first_field; 273*38fd1498Szrj return _7, __bounds_of_p_2(D); 274*38fd1498Szrj } 275*38fd1498Szrj 276*38fd1498Szrj 277*38fd1498Szrj d) Pointer is the result of pointer arithmetic or type cast. 278*38fd1498Szrj 279*38fd1498Szrj In this case bounds of the base pointer are used. In case of binary 280*38fd1498Szrj operation producing a pointer we are analyzing data flow further 281*38fd1498Szrj looking for operand's bounds. One operand is considered as a base 282*38fd1498Szrj if it has some valid bounds. If we fall into a case when none of 283*38fd1498Szrj operands (or both of them) has valid bounds, a default bounds value 284*38fd1498Szrj is used. 285*38fd1498Szrj 286*38fd1498Szrj Trying to find out bounds for binary operations we may fall into 287*38fd1498Szrj cyclic dependencies for pointers. To avoid infinite recursion all 288*38fd1498Szrj walked phi nodes instantly obtain corresponding bounds but created 289*38fd1498Szrj bounds are marked as incomplete. It helps us to stop DF walk during 290*38fd1498Szrj bounds search. 291*38fd1498Szrj 292*38fd1498Szrj When we reach pointer source, some args of incomplete bounds phi obtain 293*38fd1498Szrj valid bounds and those values are propagated further through phi nodes. 294*38fd1498Szrj If no valid bounds were found for phi node then we mark its result as 295*38fd1498Szrj invalid bounds. Process stops when all incomplete bounds become either 296*38fd1498Szrj valid or invalid and we are able to choose a pointer base. 297*38fd1498Szrj 298*38fd1498Szrj e) Pointer is loaded from the memory. 299*38fd1498Szrj 300*38fd1498Szrj In this case we just need to load bounds from the bounds table. 301*38fd1498Szrj 302*38fd1498Szrj Example: 303*38fd1498Szrj 304*38fd1498Szrj foo () 305*38fd1498Szrj { 306*38fd1498Szrj <unnamed type> __bound_tmp.3; 307*38fd1498Szrj static int * buf; 308*38fd1498Szrj int * _2; 309*38fd1498Szrj 310*38fd1498Szrj <bb 2>: 311*38fd1498Szrj _2 = buf; 312*38fd1498Szrj __bound_tmp.3_4 = __builtin___chkp_bndldx (&buf, _2); 313*38fd1498Szrj return _2, __bound_tmp.3_4; 314*38fd1498Szrj } 315*38fd1498Szrj 316*38fd1498Szrj */ 317*38fd1498Szrj 318*38fd1498Szrj typedef void (*assign_handler)(tree, tree, void *); 319*38fd1498Szrj 320*38fd1498Szrj static tree chkp_get_zero_bounds (); 321*38fd1498Szrj static tree chkp_find_bounds (tree ptr, gimple_stmt_iterator *iter); 322*38fd1498Szrj static tree chkp_find_bounds_loaded (tree ptr, tree ptr_src, 323*38fd1498Szrj gimple_stmt_iterator *iter); 324*38fd1498Szrj static void chkp_parse_array_and_component_ref (tree node, tree *ptr, 325*38fd1498Szrj tree *elt, bool *safe, 326*38fd1498Szrj bool *bitfield, 327*38fd1498Szrj tree *bounds, 328*38fd1498Szrj gimple_stmt_iterator *iter, 329*38fd1498Szrj bool innermost_bounds); 330*38fd1498Szrj static void chkp_parse_bit_field_ref (tree node, location_t loc, 331*38fd1498Szrj tree *offset, tree *size); 332*38fd1498Szrj static tree 333*38fd1498Szrj chkp_make_addressed_object_bounds (tree obj, gimple_stmt_iterator *iter); 334*38fd1498Szrj 335*38fd1498Szrj #define chkp_bndldx_fndecl \ 336*38fd1498Szrj (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDLDX)) 337*38fd1498Szrj #define chkp_bndstx_fndecl \ 338*38fd1498Szrj (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDSTX)) 339*38fd1498Szrj #define chkp_checkl_fndecl \ 340*38fd1498Szrj (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDCL)) 341*38fd1498Szrj #define chkp_checku_fndecl \ 342*38fd1498Szrj (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDCU)) 343*38fd1498Szrj #define chkp_bndmk_fndecl \ 344*38fd1498Szrj (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDMK)) 345*38fd1498Szrj #define chkp_ret_bnd_fndecl \ 346*38fd1498Szrj (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDRET)) 347*38fd1498Szrj #define chkp_intersect_fndecl \ 348*38fd1498Szrj (targetm.builtin_chkp_function (BUILT_IN_CHKP_INTERSECT)) 349*38fd1498Szrj #define chkp_narrow_bounds_fndecl \ 350*38fd1498Szrj (targetm.builtin_chkp_function (BUILT_IN_CHKP_NARROW)) 351*38fd1498Szrj #define chkp_sizeof_fndecl \ 352*38fd1498Szrj (targetm.builtin_chkp_function (BUILT_IN_CHKP_SIZEOF)) 353*38fd1498Szrj #define chkp_extract_lower_fndecl \ 354*38fd1498Szrj (targetm.builtin_chkp_function (BUILT_IN_CHKP_EXTRACT_LOWER)) 355*38fd1498Szrj #define chkp_extract_upper_fndecl \ 356*38fd1498Szrj (targetm.builtin_chkp_function (BUILT_IN_CHKP_EXTRACT_UPPER)) 357*38fd1498Szrj 358*38fd1498Szrj static GTY (()) tree chkp_uintptr_type; 359*38fd1498Szrj 360*38fd1498Szrj static GTY (()) tree chkp_zero_bounds_var; 361*38fd1498Szrj static GTY (()) tree chkp_none_bounds_var; 362*38fd1498Szrj 363*38fd1498Szrj static GTY (()) basic_block entry_block; 364*38fd1498Szrj static GTY (()) tree zero_bounds; 365*38fd1498Szrj static GTY (()) tree none_bounds; 366*38fd1498Szrj static GTY (()) tree incomplete_bounds; 367*38fd1498Szrj static GTY (()) tree tmp_var; 368*38fd1498Szrj static GTY (()) tree size_tmp_var; 369*38fd1498Szrj static GTY (()) bitmap chkp_abnormal_copies; 370*38fd1498Szrj 371*38fd1498Szrj struct hash_set<tree> *chkp_invalid_bounds; 372*38fd1498Szrj struct hash_set<tree> *chkp_completed_bounds_set; 373*38fd1498Szrj struct hash_map<tree, tree> *chkp_reg_bounds; 374*38fd1498Szrj struct hash_map<tree, tree> *chkp_bound_vars; 375*38fd1498Szrj struct hash_map<tree, tree> *chkp_reg_addr_bounds; 376*38fd1498Szrj struct hash_map<tree, tree> *chkp_incomplete_bounds_map; 377*38fd1498Szrj struct hash_map<tree, tree> *chkp_bounds_map; 378*38fd1498Szrj struct hash_map<tree, tree> *chkp_static_var_bounds; 379*38fd1498Szrj 380*38fd1498Szrj static bool in_chkp_pass; 381*38fd1498Szrj 382*38fd1498Szrj #define CHKP_BOUND_TMP_NAME "__bound_tmp" 383*38fd1498Szrj #define CHKP_SIZE_TMP_NAME "__size_tmp" 384*38fd1498Szrj #define CHKP_BOUNDS_OF_SYMBOL_PREFIX "__chkp_bounds_of_" 385*38fd1498Szrj #define CHKP_STRING_BOUNDS_PREFIX "__chkp_string_bounds_" 386*38fd1498Szrj #define CHKP_VAR_BOUNDS_PREFIX "__chkp_var_bounds_" 387*38fd1498Szrj #define CHKP_ZERO_BOUNDS_VAR_NAME "__chkp_zero_bounds" 388*38fd1498Szrj #define CHKP_NONE_BOUNDS_VAR_NAME "__chkp_none_bounds" 389*38fd1498Szrj 390*38fd1498Szrj /* Static checker constructors may become very large and their 391*38fd1498Szrj compilation with optimization may take too much time. 392*38fd1498Szrj Therefore we put a limit to number of statements in one 393*38fd1498Szrj constructor. Tests with 100 000 statically initialized 394*38fd1498Szrj pointers showed following compilation times on Sandy Bridge 395*38fd1498Szrj server (used -O2): 396*38fd1498Szrj limit 100 => ~18 sec. 397*38fd1498Szrj limit 300 => ~22 sec. 398*38fd1498Szrj limit 1000 => ~30 sec. 399*38fd1498Szrj limit 3000 => ~49 sec. 400*38fd1498Szrj limit 5000 => ~55 sec. 401*38fd1498Szrj limit 10000 => ~76 sec. 402*38fd1498Szrj limit 100000 => ~532 sec. */ 403*38fd1498Szrj #define MAX_STMTS_IN_STATIC_CHKP_CTOR (PARAM_VALUE (PARAM_CHKP_MAX_CTOR_SIZE)) 404*38fd1498Szrj 405*38fd1498Szrj struct chkp_ctor_stmt_list 406*38fd1498Szrj { 407*38fd1498Szrj tree stmts; 408*38fd1498Szrj int avail; 409*38fd1498Szrj }; 410*38fd1498Szrj 411*38fd1498Szrj /* Return 1 if function FNDECL is instrumented by Pointer 412*38fd1498Szrj Bounds Checker. */ 413*38fd1498Szrj bool 414*38fd1498Szrj chkp_function_instrumented_p (tree fndecl) 415*38fd1498Szrj { 416*38fd1498Szrj return fndecl 417*38fd1498Szrj && lookup_attribute ("chkp instrumented", DECL_ATTRIBUTES (fndecl)); 418*38fd1498Szrj } 419*38fd1498Szrj 420*38fd1498Szrj /* Mark function FNDECL as instrumented. */ 421*38fd1498Szrj void 422*38fd1498Szrj chkp_function_mark_instrumented (tree fndecl) 423*38fd1498Szrj { 424*38fd1498Szrj if (chkp_function_instrumented_p (fndecl)) 425*38fd1498Szrj return; 426*38fd1498Szrj 427*38fd1498Szrj DECL_ATTRIBUTES (fndecl) 428*38fd1498Szrj = tree_cons (get_identifier ("chkp instrumented"), NULL, 429*38fd1498Szrj DECL_ATTRIBUTES (fndecl)); 430*38fd1498Szrj } 431*38fd1498Szrj 432*38fd1498Szrj /* Return true when STMT is builtin call to instrumentation function 433*38fd1498Szrj corresponding to CODE. */ 434*38fd1498Szrj 435*38fd1498Szrj bool 436*38fd1498Szrj chkp_gimple_call_builtin_p (gimple *call, 437*38fd1498Szrj enum built_in_function code) 438*38fd1498Szrj { 439*38fd1498Szrj tree fndecl; 440*38fd1498Szrj /* We are skipping the check for address-spaces, that's 441*38fd1498Szrj why we don't use gimple_call_builtin_p directly here. */ 442*38fd1498Szrj if (is_gimple_call (call) 443*38fd1498Szrj && (fndecl = gimple_call_fndecl (call)) != NULL 444*38fd1498Szrj && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD 445*38fd1498Szrj && (fndecl = targetm.builtin_chkp_function (code)) 446*38fd1498Szrj && (DECL_FUNCTION_CODE (gimple_call_fndecl (call)) 447*38fd1498Szrj == DECL_FUNCTION_CODE (fndecl))) 448*38fd1498Szrj return true; 449*38fd1498Szrj return false; 450*38fd1498Szrj } 451*38fd1498Szrj 452*38fd1498Szrj /* Emit code to build zero bounds and return RTL holding 453*38fd1498Szrj the result. */ 454*38fd1498Szrj rtx 455*38fd1498Szrj chkp_expand_zero_bounds () 456*38fd1498Szrj { 457*38fd1498Szrj tree zero_bnd; 458*38fd1498Szrj 459*38fd1498Szrj if (flag_chkp_use_static_const_bounds) 460*38fd1498Szrj zero_bnd = chkp_get_zero_bounds_var (); 461*38fd1498Szrj else 462*38fd1498Szrj zero_bnd = chkp_build_make_bounds_call (integer_zero_node, 463*38fd1498Szrj integer_zero_node); 464*38fd1498Szrj return expand_normal (zero_bnd); 465*38fd1498Szrj } 466*38fd1498Szrj 467*38fd1498Szrj /* Emit code to store zero bounds for PTR located at MEM. */ 468*38fd1498Szrj void 469*38fd1498Szrj chkp_expand_bounds_reset_for_mem (tree mem, tree ptr) 470*38fd1498Szrj { 471*38fd1498Szrj tree zero_bnd, bnd, addr, bndstx; 472*38fd1498Szrj 473*38fd1498Szrj if (flag_chkp_use_static_const_bounds) 474*38fd1498Szrj zero_bnd = chkp_get_zero_bounds_var (); 475*38fd1498Szrj else 476*38fd1498Szrj zero_bnd = chkp_build_make_bounds_call (integer_zero_node, 477*38fd1498Szrj integer_zero_node); 478*38fd1498Szrj bnd = make_tree (pointer_bounds_type_node, 479*38fd1498Szrj assign_temp (pointer_bounds_type_node, 0, 1)); 480*38fd1498Szrj addr = build1 (ADDR_EXPR, 481*38fd1498Szrj build_pointer_type (TREE_TYPE (mem)), mem); 482*38fd1498Szrj bndstx = chkp_build_bndstx_call (addr, ptr, bnd); 483*38fd1498Szrj 484*38fd1498Szrj expand_assignment (bnd, zero_bnd, false); 485*38fd1498Szrj expand_normal (bndstx); 486*38fd1498Szrj } 487*38fd1498Szrj 488*38fd1498Szrj /* Build retbnd call for returned value RETVAL. 489*38fd1498Szrj 490*38fd1498Szrj If BNDVAL is not NULL then result is stored 491*38fd1498Szrj in it. Otherwise a temporary is created to 492*38fd1498Szrj hold returned value. 493*38fd1498Szrj 494*38fd1498Szrj GSI points to a position for a retbnd call 495*38fd1498Szrj and is set to created stmt. 496*38fd1498Szrj 497*38fd1498Szrj Cgraph edge is created for a new call if 498*38fd1498Szrj UPDATE_EDGE is 1. 499*38fd1498Szrj 500*38fd1498Szrj Obtained bounds are returned. */ 501*38fd1498Szrj tree 502*38fd1498Szrj chkp_insert_retbnd_call (tree bndval, tree retval, 503*38fd1498Szrj gimple_stmt_iterator *gsi) 504*38fd1498Szrj { 505*38fd1498Szrj gimple *call; 506*38fd1498Szrj 507*38fd1498Szrj if (!bndval) 508*38fd1498Szrj bndval = create_tmp_reg (pointer_bounds_type_node, "retbnd"); 509*38fd1498Szrj 510*38fd1498Szrj call = gimple_build_call (chkp_ret_bnd_fndecl, 1, retval); 511*38fd1498Szrj gimple_call_set_lhs (call, bndval); 512*38fd1498Szrj gsi_insert_after (gsi, call, GSI_CONTINUE_LINKING); 513*38fd1498Szrj 514*38fd1498Szrj return bndval; 515*38fd1498Szrj } 516*38fd1498Szrj 517*38fd1498Szrj /* Build a GIMPLE_CALL identical to CALL but skipping bounds 518*38fd1498Szrj arguments. */ 519*38fd1498Szrj 520*38fd1498Szrj gcall * 521*38fd1498Szrj chkp_copy_call_skip_bounds (gcall *call) 522*38fd1498Szrj { 523*38fd1498Szrj bitmap bounds; 524*38fd1498Szrj unsigned i; 525*38fd1498Szrj 526*38fd1498Szrj bitmap_obstack_initialize (NULL); 527*38fd1498Szrj bounds = BITMAP_ALLOC (NULL); 528*38fd1498Szrj 529*38fd1498Szrj for (i = 0; i < gimple_call_num_args (call); i++) 530*38fd1498Szrj if (POINTER_BOUNDS_P (gimple_call_arg (call, i))) 531*38fd1498Szrj bitmap_set_bit (bounds, i); 532*38fd1498Szrj 533*38fd1498Szrj if (!bitmap_empty_p (bounds)) 534*38fd1498Szrj call = gimple_call_copy_skip_args (call, bounds); 535*38fd1498Szrj gimple_call_set_with_bounds (call, false); 536*38fd1498Szrj 537*38fd1498Szrj BITMAP_FREE (bounds); 538*38fd1498Szrj bitmap_obstack_release (NULL); 539*38fd1498Szrj 540*38fd1498Szrj return call; 541*38fd1498Szrj } 542*38fd1498Szrj 543*38fd1498Szrj /* Redirect edge E to the correct node according to call_stmt. 544*38fd1498Szrj Return 1 if bounds removal from call_stmt should be done 545*38fd1498Szrj instead of redirection. */ 546*38fd1498Szrj 547*38fd1498Szrj bool 548*38fd1498Szrj chkp_redirect_edge (cgraph_edge *e) 549*38fd1498Szrj { 550*38fd1498Szrj bool instrumented = false; 551*38fd1498Szrj tree decl = e->callee->decl; 552*38fd1498Szrj 553*38fd1498Szrj if (e->callee->instrumentation_clone 554*38fd1498Szrj || chkp_function_instrumented_p (decl)) 555*38fd1498Szrj instrumented = true; 556*38fd1498Szrj 557*38fd1498Szrj if (instrumented 558*38fd1498Szrj && !gimple_call_with_bounds_p (e->call_stmt)) 559*38fd1498Szrj e->redirect_callee (cgraph_node::get_create (e->callee->orig_decl)); 560*38fd1498Szrj else if (!instrumented 561*38fd1498Szrj && gimple_call_with_bounds_p (e->call_stmt) 562*38fd1498Szrj && !chkp_gimple_call_builtin_p (e->call_stmt, BUILT_IN_CHKP_BNDCL) 563*38fd1498Szrj && !chkp_gimple_call_builtin_p (e->call_stmt, BUILT_IN_CHKP_BNDCU) 564*38fd1498Szrj && !chkp_gimple_call_builtin_p (e->call_stmt, BUILT_IN_CHKP_BNDSTX)) 565*38fd1498Szrj { 566*38fd1498Szrj if (e->callee->instrumented_version) 567*38fd1498Szrj e->redirect_callee (e->callee->instrumented_version); 568*38fd1498Szrj else 569*38fd1498Szrj { 570*38fd1498Szrj tree args = TYPE_ARG_TYPES (TREE_TYPE (decl)); 571*38fd1498Szrj /* Avoid bounds removal if all args will be removed. */ 572*38fd1498Szrj if (!args || TREE_VALUE (args) != void_type_node) 573*38fd1498Szrj return true; 574*38fd1498Szrj else 575*38fd1498Szrj gimple_call_set_with_bounds (e->call_stmt, false); 576*38fd1498Szrj } 577*38fd1498Szrj } 578*38fd1498Szrj 579*38fd1498Szrj return false; 580*38fd1498Szrj } 581*38fd1498Szrj 582*38fd1498Szrj /* Mark statement S to not be instrumented. */ 583*38fd1498Szrj static void 584*38fd1498Szrj chkp_mark_stmt (gimple *s) 585*38fd1498Szrj { 586*38fd1498Szrj gimple_set_plf (s, GF_PLF_1, true); 587*38fd1498Szrj } 588*38fd1498Szrj 589*38fd1498Szrj /* Mark statement S to be instrumented. */ 590*38fd1498Szrj static void 591*38fd1498Szrj chkp_unmark_stmt (gimple *s) 592*38fd1498Szrj { 593*38fd1498Szrj gimple_set_plf (s, GF_PLF_1, false); 594*38fd1498Szrj } 595*38fd1498Szrj 596*38fd1498Szrj /* Return 1 if statement S should not be instrumented. */ 597*38fd1498Szrj static bool 598*38fd1498Szrj chkp_marked_stmt_p (gimple *s) 599*38fd1498Szrj { 600*38fd1498Szrj return gimple_plf (s, GF_PLF_1); 601*38fd1498Szrj } 602*38fd1498Szrj 603*38fd1498Szrj /* Get var to be used for bound temps. */ 604*38fd1498Szrj static tree 605*38fd1498Szrj chkp_get_tmp_var (void) 606*38fd1498Szrj { 607*38fd1498Szrj if (!tmp_var) 608*38fd1498Szrj tmp_var = create_tmp_reg (pointer_bounds_type_node, CHKP_BOUND_TMP_NAME); 609*38fd1498Szrj 610*38fd1498Szrj return tmp_var; 611*38fd1498Szrj } 612*38fd1498Szrj 613*38fd1498Szrj /* Get SSA_NAME to be used as temp. */ 614*38fd1498Szrj static tree 615*38fd1498Szrj chkp_get_tmp_reg (gimple *stmt) 616*38fd1498Szrj { 617*38fd1498Szrj if (in_chkp_pass) 618*38fd1498Szrj return make_ssa_name (chkp_get_tmp_var (), stmt); 619*38fd1498Szrj 620*38fd1498Szrj return make_temp_ssa_name (pointer_bounds_type_node, stmt, 621*38fd1498Szrj CHKP_BOUND_TMP_NAME); 622*38fd1498Szrj } 623*38fd1498Szrj 624*38fd1498Szrj /* Get var to be used for size temps. */ 625*38fd1498Szrj static tree 626*38fd1498Szrj chkp_get_size_tmp_var (void) 627*38fd1498Szrj { 628*38fd1498Szrj if (!size_tmp_var) 629*38fd1498Szrj size_tmp_var = create_tmp_reg (chkp_uintptr_type, CHKP_SIZE_TMP_NAME); 630*38fd1498Szrj 631*38fd1498Szrj return size_tmp_var; 632*38fd1498Szrj } 633*38fd1498Szrj 634*38fd1498Szrj /* Register bounds BND for address of OBJ. */ 635*38fd1498Szrj static void 636*38fd1498Szrj chkp_register_addr_bounds (tree obj, tree bnd) 637*38fd1498Szrj { 638*38fd1498Szrj if (bnd == incomplete_bounds) 639*38fd1498Szrj return; 640*38fd1498Szrj 641*38fd1498Szrj chkp_reg_addr_bounds->put (obj, bnd); 642*38fd1498Szrj 643*38fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS)) 644*38fd1498Szrj { 645*38fd1498Szrj fprintf (dump_file, "Regsitered bound "); 646*38fd1498Szrj print_generic_expr (dump_file, bnd); 647*38fd1498Szrj fprintf (dump_file, " for address of "); 648*38fd1498Szrj print_generic_expr (dump_file, obj); 649*38fd1498Szrj fprintf (dump_file, "\n"); 650*38fd1498Szrj } 651*38fd1498Szrj } 652*38fd1498Szrj 653*38fd1498Szrj /* Return bounds registered for address of OBJ. */ 654*38fd1498Szrj static tree 655*38fd1498Szrj chkp_get_registered_addr_bounds (tree obj) 656*38fd1498Szrj { 657*38fd1498Szrj tree *slot = chkp_reg_addr_bounds->get (obj); 658*38fd1498Szrj return slot ? *slot : NULL_TREE; 659*38fd1498Szrj } 660*38fd1498Szrj 661*38fd1498Szrj /* Mark BOUNDS as completed. */ 662*38fd1498Szrj static void 663*38fd1498Szrj chkp_mark_completed_bounds (tree bounds) 664*38fd1498Szrj { 665*38fd1498Szrj chkp_completed_bounds_set->add (bounds); 666*38fd1498Szrj 667*38fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS)) 668*38fd1498Szrj { 669*38fd1498Szrj fprintf (dump_file, "Marked bounds "); 670*38fd1498Szrj print_generic_expr (dump_file, bounds); 671*38fd1498Szrj fprintf (dump_file, " as completed\n"); 672*38fd1498Szrj } 673*38fd1498Szrj } 674*38fd1498Szrj 675*38fd1498Szrj /* Return 1 if BOUNDS were marked as completed and 0 otherwise. */ 676*38fd1498Szrj static bool 677*38fd1498Szrj chkp_completed_bounds (tree bounds) 678*38fd1498Szrj { 679*38fd1498Szrj return chkp_completed_bounds_set->contains (bounds); 680*38fd1498Szrj } 681*38fd1498Szrj 682*38fd1498Szrj /* Clear comleted bound marks. */ 683*38fd1498Szrj static void 684*38fd1498Szrj chkp_erase_completed_bounds (void) 685*38fd1498Szrj { 686*38fd1498Szrj delete chkp_completed_bounds_set; 687*38fd1498Szrj chkp_completed_bounds_set = new hash_set<tree>; 688*38fd1498Szrj } 689*38fd1498Szrj 690*38fd1498Szrj /* This function is used to provide a base address for 691*38fd1498Szrj chkp_get_hard_register_fake_addr_expr. */ 692*38fd1498Szrj static tree 693*38fd1498Szrj chkp_get_hard_register_var_fake_base_address () 694*38fd1498Szrj { 695*38fd1498Szrj int prec = TYPE_PRECISION (ptr_type_node); 696*38fd1498Szrj return wide_int_to_tree (ptr_type_node, wi::min_value (prec, SIGNED)); 697*38fd1498Szrj } 698*38fd1498Szrj 699*38fd1498Szrj /* If we check bounds for a hard register variable, we cannot 700*38fd1498Szrj use its address - it is illegal, so instead of that we use 701*38fd1498Szrj this fake value. */ 702*38fd1498Szrj static tree 703*38fd1498Szrj chkp_get_hard_register_fake_addr_expr (tree obj) 704*38fd1498Szrj { 705*38fd1498Szrj tree addr = chkp_get_hard_register_var_fake_base_address (); 706*38fd1498Szrj tree outer = obj; 707*38fd1498Szrj while (TREE_CODE (outer) == COMPONENT_REF || TREE_CODE (outer) == ARRAY_REF) 708*38fd1498Szrj { 709*38fd1498Szrj if (TREE_CODE (outer) == COMPONENT_REF) 710*38fd1498Szrj { 711*38fd1498Szrj addr = fold_build_pointer_plus (addr, 712*38fd1498Szrj component_ref_field_offset (outer)); 713*38fd1498Szrj outer = TREE_OPERAND (outer, 0); 714*38fd1498Szrj } 715*38fd1498Szrj else if (TREE_CODE (outer) == ARRAY_REF) 716*38fd1498Szrj { 717*38fd1498Szrj tree indx = fold_convert(size_type_node, TREE_OPERAND(outer, 1)); 718*38fd1498Szrj tree offset = size_binop (MULT_EXPR, 719*38fd1498Szrj array_ref_element_size (outer), indx); 720*38fd1498Szrj addr = fold_build_pointer_plus (addr, offset); 721*38fd1498Szrj outer = TREE_OPERAND (outer, 0); 722*38fd1498Szrj } 723*38fd1498Szrj } 724*38fd1498Szrj 725*38fd1498Szrj return addr; 726*38fd1498Szrj } 727*38fd1498Szrj 728*38fd1498Szrj /* Mark BOUNDS associated with PTR as incomplete. */ 729*38fd1498Szrj static void 730*38fd1498Szrj chkp_register_incomplete_bounds (tree bounds, tree ptr) 731*38fd1498Szrj { 732*38fd1498Szrj chkp_incomplete_bounds_map->put (bounds, ptr); 733*38fd1498Szrj 734*38fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS)) 735*38fd1498Szrj { 736*38fd1498Szrj fprintf (dump_file, "Regsitered incomplete bounds "); 737*38fd1498Szrj print_generic_expr (dump_file, bounds); 738*38fd1498Szrj fprintf (dump_file, " for "); 739*38fd1498Szrj print_generic_expr (dump_file, ptr); 740*38fd1498Szrj fprintf (dump_file, "\n"); 741*38fd1498Szrj } 742*38fd1498Szrj } 743*38fd1498Szrj 744*38fd1498Szrj /* Return 1 if BOUNDS are incomplete and 0 otherwise. */ 745*38fd1498Szrj static bool 746*38fd1498Szrj chkp_incomplete_bounds (tree bounds) 747*38fd1498Szrj { 748*38fd1498Szrj if (bounds == incomplete_bounds) 749*38fd1498Szrj return true; 750*38fd1498Szrj 751*38fd1498Szrj if (chkp_completed_bounds (bounds)) 752*38fd1498Szrj return false; 753*38fd1498Szrj 754*38fd1498Szrj return chkp_incomplete_bounds_map->get (bounds) != NULL; 755*38fd1498Szrj } 756*38fd1498Szrj 757*38fd1498Szrj /* Clear incomleted bound marks. */ 758*38fd1498Szrj static void 759*38fd1498Szrj chkp_erase_incomplete_bounds (void) 760*38fd1498Szrj { 761*38fd1498Szrj delete chkp_incomplete_bounds_map; 762*38fd1498Szrj chkp_incomplete_bounds_map = new hash_map<tree, tree>; 763*38fd1498Szrj } 764*38fd1498Szrj 765*38fd1498Szrj /* Build and return bndmk call which creates bounds for structure 766*38fd1498Szrj pointed by PTR. Structure should have complete type. */ 767*38fd1498Szrj tree 768*38fd1498Szrj chkp_make_bounds_for_struct_addr (tree ptr) 769*38fd1498Szrj { 770*38fd1498Szrj tree type = TREE_TYPE (ptr); 771*38fd1498Szrj tree size; 772*38fd1498Szrj 773*38fd1498Szrj gcc_assert (POINTER_TYPE_P (type)); 774*38fd1498Szrj 775*38fd1498Szrj size = TYPE_SIZE (TREE_TYPE (type)); 776*38fd1498Szrj 777*38fd1498Szrj gcc_assert (size); 778*38fd1498Szrj 779*38fd1498Szrj return build_call_nary (pointer_bounds_type_node, 780*38fd1498Szrj build_fold_addr_expr (chkp_bndmk_fndecl), 781*38fd1498Szrj 2, ptr, size); 782*38fd1498Szrj } 783*38fd1498Szrj 784*38fd1498Szrj /* Traversal function for chkp_may_finish_incomplete_bounds. 785*38fd1498Szrj Set RES to 0 if at least one argument of phi statement 786*38fd1498Szrj defining bounds (passed in KEY arg) is unknown. 787*38fd1498Szrj Traversal stops when first unknown phi argument is found. */ 788*38fd1498Szrj bool 789*38fd1498Szrj chkp_may_complete_phi_bounds (tree const &bounds, tree *slot ATTRIBUTE_UNUSED, 790*38fd1498Szrj bool *res) 791*38fd1498Szrj { 792*38fd1498Szrj gimple *phi; 793*38fd1498Szrj unsigned i; 794*38fd1498Szrj 795*38fd1498Szrj gcc_assert (TREE_CODE (bounds) == SSA_NAME); 796*38fd1498Szrj 797*38fd1498Szrj phi = SSA_NAME_DEF_STMT (bounds); 798*38fd1498Szrj 799*38fd1498Szrj gcc_assert (phi && gimple_code (phi) == GIMPLE_PHI); 800*38fd1498Szrj 801*38fd1498Szrj for (i = 0; i < gimple_phi_num_args (phi); i++) 802*38fd1498Szrj { 803*38fd1498Szrj tree phi_arg = gimple_phi_arg_def (phi, i); 804*38fd1498Szrj if (!phi_arg) 805*38fd1498Szrj { 806*38fd1498Szrj *res = false; 807*38fd1498Szrj /* Do not need to traverse further. */ 808*38fd1498Szrj return false; 809*38fd1498Szrj } 810*38fd1498Szrj } 811*38fd1498Szrj 812*38fd1498Szrj return true; 813*38fd1498Szrj } 814*38fd1498Szrj 815*38fd1498Szrj /* Return 1 if all phi nodes created for bounds have their 816*38fd1498Szrj arguments computed. */ 817*38fd1498Szrj static bool 818*38fd1498Szrj chkp_may_finish_incomplete_bounds (void) 819*38fd1498Szrj { 820*38fd1498Szrj bool res = true; 821*38fd1498Szrj 822*38fd1498Szrj chkp_incomplete_bounds_map 823*38fd1498Szrj ->traverse<bool *, chkp_may_complete_phi_bounds> (&res); 824*38fd1498Szrj 825*38fd1498Szrj return res; 826*38fd1498Szrj } 827*38fd1498Szrj 828*38fd1498Szrj /* Helper function for chkp_finish_incomplete_bounds. 829*38fd1498Szrj Recompute args for bounds phi node. */ 830*38fd1498Szrj bool 831*38fd1498Szrj chkp_recompute_phi_bounds (tree const &bounds, tree *slot, 832*38fd1498Szrj void *res ATTRIBUTE_UNUSED) 833*38fd1498Szrj { 834*38fd1498Szrj tree ptr = *slot; 835*38fd1498Szrj gphi *bounds_phi; 836*38fd1498Szrj gphi *ptr_phi; 837*38fd1498Szrj unsigned i; 838*38fd1498Szrj 839*38fd1498Szrj gcc_assert (TREE_CODE (bounds) == SSA_NAME); 840*38fd1498Szrj gcc_assert (TREE_CODE (ptr) == SSA_NAME); 841*38fd1498Szrj 842*38fd1498Szrj bounds_phi = as_a <gphi *> (SSA_NAME_DEF_STMT (bounds)); 843*38fd1498Szrj ptr_phi = as_a <gphi *> (SSA_NAME_DEF_STMT (ptr)); 844*38fd1498Szrj 845*38fd1498Szrj for (i = 0; i < gimple_phi_num_args (bounds_phi); i++) 846*38fd1498Szrj { 847*38fd1498Szrj tree ptr_arg = gimple_phi_arg_def (ptr_phi, i); 848*38fd1498Szrj tree bound_arg = chkp_find_bounds (ptr_arg, NULL); 849*38fd1498Szrj 850*38fd1498Szrj add_phi_arg (bounds_phi, bound_arg, 851*38fd1498Szrj gimple_phi_arg_edge (ptr_phi, i), 852*38fd1498Szrj UNKNOWN_LOCATION); 853*38fd1498Szrj } 854*38fd1498Szrj 855*38fd1498Szrj return true; 856*38fd1498Szrj } 857*38fd1498Szrj 858*38fd1498Szrj /* Mark BOUNDS as invalid. */ 859*38fd1498Szrj static void 860*38fd1498Szrj chkp_mark_invalid_bounds (tree bounds) 861*38fd1498Szrj { 862*38fd1498Szrj chkp_invalid_bounds->add (bounds); 863*38fd1498Szrj 864*38fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS)) 865*38fd1498Szrj { 866*38fd1498Szrj fprintf (dump_file, "Marked bounds "); 867*38fd1498Szrj print_generic_expr (dump_file, bounds); 868*38fd1498Szrj fprintf (dump_file, " as invalid\n"); 869*38fd1498Szrj } 870*38fd1498Szrj } 871*38fd1498Szrj 872*38fd1498Szrj /* Return 1 if BOUNDS were marked as invalid and 0 otherwise. */ 873*38fd1498Szrj static bool 874*38fd1498Szrj chkp_valid_bounds (tree bounds) 875*38fd1498Szrj { 876*38fd1498Szrj if (bounds == zero_bounds || bounds == none_bounds) 877*38fd1498Szrj return false; 878*38fd1498Szrj 879*38fd1498Szrj return !chkp_invalid_bounds->contains (bounds); 880*38fd1498Szrj } 881*38fd1498Szrj 882*38fd1498Szrj /* Helper function for chkp_finish_incomplete_bounds. 883*38fd1498Szrj Check all arguments of phi nodes trying to find 884*38fd1498Szrj valid completed bounds. If there is at least one 885*38fd1498Szrj such arg then bounds produced by phi node are marked 886*38fd1498Szrj as valid completed bounds and all phi args are 887*38fd1498Szrj recomputed. */ 888*38fd1498Szrj bool 889*38fd1498Szrj chkp_find_valid_phi_bounds (tree const &bounds, tree *slot, bool *res) 890*38fd1498Szrj { 891*38fd1498Szrj gimple *phi; 892*38fd1498Szrj unsigned i; 893*38fd1498Szrj 894*38fd1498Szrj gcc_assert (TREE_CODE (bounds) == SSA_NAME); 895*38fd1498Szrj 896*38fd1498Szrj if (chkp_completed_bounds (bounds)) 897*38fd1498Szrj return true; 898*38fd1498Szrj 899*38fd1498Szrj phi = SSA_NAME_DEF_STMT (bounds); 900*38fd1498Szrj 901*38fd1498Szrj gcc_assert (phi && gimple_code (phi) == GIMPLE_PHI); 902*38fd1498Szrj 903*38fd1498Szrj for (i = 0; i < gimple_phi_num_args (phi); i++) 904*38fd1498Szrj { 905*38fd1498Szrj tree phi_arg = gimple_phi_arg_def (phi, i); 906*38fd1498Szrj 907*38fd1498Szrj gcc_assert (phi_arg); 908*38fd1498Szrj 909*38fd1498Szrj if (chkp_valid_bounds (phi_arg) && !chkp_incomplete_bounds (phi_arg)) 910*38fd1498Szrj { 911*38fd1498Szrj *res = true; 912*38fd1498Szrj chkp_mark_completed_bounds (bounds); 913*38fd1498Szrj chkp_recompute_phi_bounds (bounds, slot, NULL); 914*38fd1498Szrj return true; 915*38fd1498Szrj } 916*38fd1498Szrj } 917*38fd1498Szrj 918*38fd1498Szrj return true; 919*38fd1498Szrj } 920*38fd1498Szrj 921*38fd1498Szrj /* Helper function for chkp_finish_incomplete_bounds. 922*38fd1498Szrj Marks all incompleted bounds as invalid. */ 923*38fd1498Szrj bool 924*38fd1498Szrj chkp_mark_invalid_bounds_walker (tree const &bounds, 925*38fd1498Szrj tree *slot ATTRIBUTE_UNUSED, 926*38fd1498Szrj void *res ATTRIBUTE_UNUSED) 927*38fd1498Szrj { 928*38fd1498Szrj if (!chkp_completed_bounds (bounds)) 929*38fd1498Szrj { 930*38fd1498Szrj chkp_mark_invalid_bounds (bounds); 931*38fd1498Szrj chkp_mark_completed_bounds (bounds); 932*38fd1498Szrj } 933*38fd1498Szrj return true; 934*38fd1498Szrj } 935*38fd1498Szrj 936*38fd1498Szrj /* When all bound phi nodes have all their args computed 937*38fd1498Szrj we have enough info to find valid bounds. We iterate 938*38fd1498Szrj through all incompleted bounds searching for valid 939*38fd1498Szrj bounds. Found valid bounds are marked as completed 940*38fd1498Szrj and all remaining incompleted bounds are recomputed. 941*38fd1498Szrj Process continues until no new valid bounds may be 942*38fd1498Szrj found. All remained incompleted bounds are marked as 943*38fd1498Szrj invalid (i.e. have no valid source of bounds). */ 944*38fd1498Szrj static void 945*38fd1498Szrj chkp_finish_incomplete_bounds (void) 946*38fd1498Szrj { 947*38fd1498Szrj bool found_valid = true; 948*38fd1498Szrj 949*38fd1498Szrj while (found_valid) 950*38fd1498Szrj { 951*38fd1498Szrj found_valid = false; 952*38fd1498Szrj 953*38fd1498Szrj chkp_incomplete_bounds_map-> 954*38fd1498Szrj traverse<bool *, chkp_find_valid_phi_bounds> (&found_valid); 955*38fd1498Szrj 956*38fd1498Szrj if (found_valid) 957*38fd1498Szrj chkp_incomplete_bounds_map-> 958*38fd1498Szrj traverse<void *, chkp_recompute_phi_bounds> (NULL); 959*38fd1498Szrj } 960*38fd1498Szrj 961*38fd1498Szrj chkp_incomplete_bounds_map-> 962*38fd1498Szrj traverse<void *, chkp_mark_invalid_bounds_walker> (NULL); 963*38fd1498Szrj chkp_incomplete_bounds_map-> 964*38fd1498Szrj traverse<void *, chkp_recompute_phi_bounds> (NULL); 965*38fd1498Szrj 966*38fd1498Szrj chkp_erase_completed_bounds (); 967*38fd1498Szrj chkp_erase_incomplete_bounds (); 968*38fd1498Szrj } 969*38fd1498Szrj 970*38fd1498Szrj /* Return 1 if type TYPE is a pointer type or a 971*38fd1498Szrj structure having a pointer type as one of its fields. 972*38fd1498Szrj Otherwise return 0. */ 973*38fd1498Szrj bool 974*38fd1498Szrj chkp_type_has_pointer (const_tree type) 975*38fd1498Szrj { 976*38fd1498Szrj bool res = false; 977*38fd1498Szrj 978*38fd1498Szrj if (BOUNDED_TYPE_P (type)) 979*38fd1498Szrj res = true; 980*38fd1498Szrj else if (RECORD_OR_UNION_TYPE_P (type)) 981*38fd1498Szrj { 982*38fd1498Szrj tree field; 983*38fd1498Szrj 984*38fd1498Szrj for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) 985*38fd1498Szrj if (TREE_CODE (field) == FIELD_DECL) 986*38fd1498Szrj res = res || chkp_type_has_pointer (TREE_TYPE (field)); 987*38fd1498Szrj } 988*38fd1498Szrj else if (TREE_CODE (type) == ARRAY_TYPE) 989*38fd1498Szrj res = chkp_type_has_pointer (TREE_TYPE (type)); 990*38fd1498Szrj 991*38fd1498Szrj return res; 992*38fd1498Szrj } 993*38fd1498Szrj 994*38fd1498Szrj unsigned 995*38fd1498Szrj chkp_type_bounds_count (const_tree type) 996*38fd1498Szrj { 997*38fd1498Szrj unsigned res = 0; 998*38fd1498Szrj 999*38fd1498Szrj if (!type) 1000*38fd1498Szrj res = 0; 1001*38fd1498Szrj else if (BOUNDED_TYPE_P (type)) 1002*38fd1498Szrj res = 1; 1003*38fd1498Szrj else if (RECORD_OR_UNION_TYPE_P (type)) 1004*38fd1498Szrj { 1005*38fd1498Szrj bitmap have_bound; 1006*38fd1498Szrj 1007*38fd1498Szrj bitmap_obstack_initialize (NULL); 1008*38fd1498Szrj have_bound = BITMAP_ALLOC (NULL); 1009*38fd1498Szrj chkp_find_bound_slots (type, have_bound); 1010*38fd1498Szrj res = bitmap_count_bits (have_bound); 1011*38fd1498Szrj BITMAP_FREE (have_bound); 1012*38fd1498Szrj bitmap_obstack_release (NULL); 1013*38fd1498Szrj } 1014*38fd1498Szrj 1015*38fd1498Szrj return res; 1016*38fd1498Szrj } 1017*38fd1498Szrj 1018*38fd1498Szrj /* Get bounds associated with NODE via 1019*38fd1498Szrj chkp_set_bounds call. */ 1020*38fd1498Szrj tree 1021*38fd1498Szrj chkp_get_bounds (tree node) 1022*38fd1498Szrj { 1023*38fd1498Szrj tree *slot; 1024*38fd1498Szrj 1025*38fd1498Szrj if (!chkp_bounds_map) 1026*38fd1498Szrj return NULL_TREE; 1027*38fd1498Szrj 1028*38fd1498Szrj slot = chkp_bounds_map->get (node); 1029*38fd1498Szrj return slot ? *slot : NULL_TREE; 1030*38fd1498Szrj } 1031*38fd1498Szrj 1032*38fd1498Szrj /* Associate bounds VAL with NODE. */ 1033*38fd1498Szrj void 1034*38fd1498Szrj chkp_set_bounds (tree node, tree val) 1035*38fd1498Szrj { 1036*38fd1498Szrj if (!chkp_bounds_map) 1037*38fd1498Szrj chkp_bounds_map = new hash_map<tree, tree>; 1038*38fd1498Szrj 1039*38fd1498Szrj chkp_bounds_map->put (node, val); 1040*38fd1498Szrj } 1041*38fd1498Szrj 1042*38fd1498Szrj /* Check if statically initialized variable VAR require 1043*38fd1498Szrj static bounds initialization. If VAR is added into 1044*38fd1498Szrj bounds initlization list then 1 is returned. Otherwise 1045*38fd1498Szrj return 0. */ 1046*38fd1498Szrj extern bool 1047*38fd1498Szrj chkp_register_var_initializer (tree var) 1048*38fd1498Szrj { 1049*38fd1498Szrj if (!flag_check_pointer_bounds 1050*38fd1498Szrj || DECL_INITIAL (var) == error_mark_node) 1051*38fd1498Szrj return false; 1052*38fd1498Szrj 1053*38fd1498Szrj gcc_assert (VAR_P (var)); 1054*38fd1498Szrj gcc_assert (DECL_INITIAL (var)); 1055*38fd1498Szrj 1056*38fd1498Szrj if (TREE_STATIC (var) 1057*38fd1498Szrj && chkp_type_has_pointer (TREE_TYPE (var))) 1058*38fd1498Szrj { 1059*38fd1498Szrj varpool_node::get_create (var)->need_bounds_init = 1; 1060*38fd1498Szrj return true; 1061*38fd1498Szrj } 1062*38fd1498Szrj 1063*38fd1498Szrj return false; 1064*38fd1498Szrj } 1065*38fd1498Szrj 1066*38fd1498Szrj /* Helper function for chkp_finish_file. 1067*38fd1498Szrj 1068*38fd1498Szrj Add new modification statement (RHS is assigned to LHS) 1069*38fd1498Szrj into list of static initializer statementes (passed in ARG). 1070*38fd1498Szrj If statements list becomes too big, emit checker constructor 1071*38fd1498Szrj and start the new one. */ 1072*38fd1498Szrj static void 1073*38fd1498Szrj chkp_add_modification_to_stmt_list (tree lhs, 1074*38fd1498Szrj tree rhs, 1075*38fd1498Szrj void *arg) 1076*38fd1498Szrj { 1077*38fd1498Szrj struct chkp_ctor_stmt_list *stmts = (struct chkp_ctor_stmt_list *)arg; 1078*38fd1498Szrj tree modify; 1079*38fd1498Szrj 1080*38fd1498Szrj if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs))) 1081*38fd1498Szrj rhs = build1 (CONVERT_EXPR, TREE_TYPE (lhs), rhs); 1082*38fd1498Szrj 1083*38fd1498Szrj modify = build2 (MODIFY_EXPR, TREE_TYPE (lhs), lhs, rhs); 1084*38fd1498Szrj append_to_statement_list (modify, &stmts->stmts); 1085*38fd1498Szrj 1086*38fd1498Szrj stmts->avail--; 1087*38fd1498Szrj } 1088*38fd1498Szrj 1089*38fd1498Szrj /* Build and return ADDR_EXPR for specified object OBJ. */ 1090*38fd1498Szrj static tree 1091*38fd1498Szrj chkp_build_addr_expr (tree obj) 1092*38fd1498Szrj { 1093*38fd1498Szrj /* We first check whether it is a "hard reg case". */ 1094*38fd1498Szrj tree base = get_base_address (obj); 1095*38fd1498Szrj if (VAR_P (base) && DECL_HARD_REGISTER (base)) 1096*38fd1498Szrj return chkp_get_hard_register_fake_addr_expr (obj); 1097*38fd1498Szrj 1098*38fd1498Szrj /* If not - return regular ADDR_EXPR. */ 1099*38fd1498Szrj return TREE_CODE (obj) == TARGET_MEM_REF 1100*38fd1498Szrj ? tree_mem_ref_addr (ptr_type_node, obj) 1101*38fd1498Szrj : build_fold_addr_expr (obj); 1102*38fd1498Szrj } 1103*38fd1498Szrj 1104*38fd1498Szrj /* Helper function for chkp_finish_file. 1105*38fd1498Szrj Initialize bound variable BND_VAR with bounds of variable 1106*38fd1498Szrj VAR to statements list STMTS. If statements list becomes 1107*38fd1498Szrj too big, emit checker constructor and start the new one. */ 1108*38fd1498Szrj static void 1109*38fd1498Szrj chkp_output_static_bounds (tree bnd_var, tree var, 1110*38fd1498Szrj struct chkp_ctor_stmt_list *stmts) 1111*38fd1498Szrj { 1112*38fd1498Szrj tree lb, ub, size; 1113*38fd1498Szrj 1114*38fd1498Szrj if (TREE_CODE (var) == STRING_CST) 1115*38fd1498Szrj { 1116*38fd1498Szrj lb = build1 (CONVERT_EXPR, size_type_node, chkp_build_addr_expr (var)); 1117*38fd1498Szrj size = build_int_cst (size_type_node, TREE_STRING_LENGTH (var) - 1); 1118*38fd1498Szrj } 1119*38fd1498Szrj else if (DECL_SIZE (var) 1120*38fd1498Szrj && !chkp_variable_size_type (TREE_TYPE (var))) 1121*38fd1498Szrj { 1122*38fd1498Szrj /* Compute bounds using statically known size. */ 1123*38fd1498Szrj lb = build1 (CONVERT_EXPR, size_type_node, chkp_build_addr_expr (var)); 1124*38fd1498Szrj size = size_binop (MINUS_EXPR, DECL_SIZE_UNIT (var), size_one_node); 1125*38fd1498Szrj } 1126*38fd1498Szrj else 1127*38fd1498Szrj { 1128*38fd1498Szrj /* Compute bounds using dynamic size. */ 1129*38fd1498Szrj tree call; 1130*38fd1498Szrj 1131*38fd1498Szrj lb = build1 (CONVERT_EXPR, size_type_node, chkp_build_addr_expr (var)); 1132*38fd1498Szrj call = build1 (ADDR_EXPR, 1133*38fd1498Szrj build_pointer_type (TREE_TYPE (chkp_sizeof_fndecl)), 1134*38fd1498Szrj chkp_sizeof_fndecl); 1135*38fd1498Szrj size = build_call_nary (TREE_TYPE (TREE_TYPE (chkp_sizeof_fndecl)), 1136*38fd1498Szrj call, 1, var); 1137*38fd1498Szrj 1138*38fd1498Szrj if (flag_chkp_zero_dynamic_size_as_infinite) 1139*38fd1498Szrj { 1140*38fd1498Szrj tree max_size, cond; 1141*38fd1498Szrj 1142*38fd1498Szrj max_size = build2 (MINUS_EXPR, size_type_node, size_zero_node, lb); 1143*38fd1498Szrj cond = build2 (NE_EXPR, boolean_type_node, size, size_zero_node); 1144*38fd1498Szrj size = build3 (COND_EXPR, size_type_node, cond, size, max_size); 1145*38fd1498Szrj } 1146*38fd1498Szrj 1147*38fd1498Szrj size = size_binop (MINUS_EXPR, size, size_one_node); 1148*38fd1498Szrj } 1149*38fd1498Szrj 1150*38fd1498Szrj ub = size_binop (PLUS_EXPR, lb, size); 1151*38fd1498Szrj stmts->avail -= targetm.chkp_initialize_bounds (bnd_var, lb, ub, 1152*38fd1498Szrj &stmts->stmts); 1153*38fd1498Szrj if (stmts->avail <= 0) 1154*38fd1498Szrj { 1155*38fd1498Szrj cgraph_build_static_cdtor ('B', stmts->stmts, 1156*38fd1498Szrj MAX_RESERVED_INIT_PRIORITY + 2); 1157*38fd1498Szrj stmts->avail = MAX_STMTS_IN_STATIC_CHKP_CTOR; 1158*38fd1498Szrj stmts->stmts = NULL; 1159*38fd1498Szrj } 1160*38fd1498Szrj } 1161*38fd1498Szrj 1162*38fd1498Szrj /* Return entry block to be used for checker initilization code. 1163*38fd1498Szrj Create new block if required. */ 1164*38fd1498Szrj static basic_block 1165*38fd1498Szrj chkp_get_entry_block (void) 1166*38fd1498Szrj { 1167*38fd1498Szrj if (!entry_block) 1168*38fd1498Szrj entry_block 1169*38fd1498Szrj = split_block_after_labels (ENTRY_BLOCK_PTR_FOR_FN (cfun))->dest; 1170*38fd1498Szrj 1171*38fd1498Szrj return entry_block; 1172*38fd1498Szrj } 1173*38fd1498Szrj 1174*38fd1498Szrj /* Return a bounds var to be used for pointer var PTR_VAR. */ 1175*38fd1498Szrj static tree 1176*38fd1498Szrj chkp_get_bounds_var (tree ptr_var) 1177*38fd1498Szrj { 1178*38fd1498Szrj tree bnd_var; 1179*38fd1498Szrj tree *slot; 1180*38fd1498Szrj 1181*38fd1498Szrj slot = chkp_bound_vars->get (ptr_var); 1182*38fd1498Szrj if (slot) 1183*38fd1498Szrj bnd_var = *slot; 1184*38fd1498Szrj else 1185*38fd1498Szrj { 1186*38fd1498Szrj bnd_var = create_tmp_reg (pointer_bounds_type_node, 1187*38fd1498Szrj CHKP_BOUND_TMP_NAME); 1188*38fd1498Szrj chkp_bound_vars->put (ptr_var, bnd_var); 1189*38fd1498Szrj } 1190*38fd1498Szrj 1191*38fd1498Szrj return bnd_var; 1192*38fd1498Szrj } 1193*38fd1498Szrj 1194*38fd1498Szrj /* If BND is an abnormal bounds copy, return a copied value. 1195*38fd1498Szrj Otherwise return BND. */ 1196*38fd1498Szrj static tree 1197*38fd1498Szrj chkp_get_orginal_bounds_for_abnormal_copy (tree bnd) 1198*38fd1498Szrj { 1199*38fd1498Szrj if (bitmap_bit_p (chkp_abnormal_copies, SSA_NAME_VERSION (bnd))) 1200*38fd1498Szrj { 1201*38fd1498Szrj gimple *bnd_def = SSA_NAME_DEF_STMT (bnd); 1202*38fd1498Szrj gcc_checking_assert (gimple_code (bnd_def) == GIMPLE_ASSIGN); 1203*38fd1498Szrj bnd = gimple_assign_rhs1 (bnd_def); 1204*38fd1498Szrj } 1205*38fd1498Szrj 1206*38fd1498Szrj return bnd; 1207*38fd1498Szrj } 1208*38fd1498Szrj 1209*38fd1498Szrj /* Register bounds BND for object PTR in global bounds table. 1210*38fd1498Szrj A copy of bounds may be created for abnormal ssa names. 1211*38fd1498Szrj Returns bounds to use for PTR. */ 1212*38fd1498Szrj static tree 1213*38fd1498Szrj chkp_maybe_copy_and_register_bounds (tree ptr, tree bnd) 1214*38fd1498Szrj { 1215*38fd1498Szrj bool abnormal_ptr; 1216*38fd1498Szrj 1217*38fd1498Szrj if (!chkp_reg_bounds) 1218*38fd1498Szrj return bnd; 1219*38fd1498Szrj 1220*38fd1498Szrj /* Do nothing if bounds are incomplete_bounds 1221*38fd1498Szrj because it means bounds will be recomputed. */ 1222*38fd1498Szrj if (bnd == incomplete_bounds) 1223*38fd1498Szrj return bnd; 1224*38fd1498Szrj 1225*38fd1498Szrj abnormal_ptr = (TREE_CODE (ptr) == SSA_NAME 1226*38fd1498Szrj && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr) 1227*38fd1498Szrj && gimple_code (SSA_NAME_DEF_STMT (ptr)) != GIMPLE_PHI); 1228*38fd1498Szrj 1229*38fd1498Szrj /* A single bounds value may be reused multiple times for 1230*38fd1498Szrj different pointer values. It may cause coalescing issues 1231*38fd1498Szrj for abnormal SSA names. To avoid it we create a bounds 1232*38fd1498Szrj copy in case it is computed for abnormal SSA name. 1233*38fd1498Szrj 1234*38fd1498Szrj We also cannot reuse such created copies for other pointers */ 1235*38fd1498Szrj if (abnormal_ptr 1236*38fd1498Szrj || bitmap_bit_p (chkp_abnormal_copies, SSA_NAME_VERSION (bnd))) 1237*38fd1498Szrj { 1238*38fd1498Szrj tree bnd_var = NULL_TREE; 1239*38fd1498Szrj 1240*38fd1498Szrj if (abnormal_ptr) 1241*38fd1498Szrj { 1242*38fd1498Szrj if (SSA_NAME_VAR (ptr)) 1243*38fd1498Szrj bnd_var = chkp_get_bounds_var (SSA_NAME_VAR (ptr)); 1244*38fd1498Szrj } 1245*38fd1498Szrj else 1246*38fd1498Szrj bnd_var = chkp_get_tmp_var (); 1247*38fd1498Szrj 1248*38fd1498Szrj /* For abnormal copies we may just find original 1249*38fd1498Szrj bounds and use them. */ 1250*38fd1498Szrj if (!abnormal_ptr && !SSA_NAME_IS_DEFAULT_DEF (bnd)) 1251*38fd1498Szrj bnd = chkp_get_orginal_bounds_for_abnormal_copy (bnd); 1252*38fd1498Szrj /* For undefined values we usually use none bounds 1253*38fd1498Szrj value but in case of abnormal edge it may cause 1254*38fd1498Szrj coalescing failures. Use default definition of 1255*38fd1498Szrj bounds variable instead to avoid it. */ 1256*38fd1498Szrj else if (SSA_NAME_IS_DEFAULT_DEF (ptr) 1257*38fd1498Szrj && TREE_CODE (SSA_NAME_VAR (ptr)) != PARM_DECL) 1258*38fd1498Szrj { 1259*38fd1498Szrj bnd = get_or_create_ssa_default_def (cfun, bnd_var); 1260*38fd1498Szrj 1261*38fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS)) 1262*38fd1498Szrj { 1263*38fd1498Szrj fprintf (dump_file, "Using default def bounds "); 1264*38fd1498Szrj print_generic_expr (dump_file, bnd); 1265*38fd1498Szrj fprintf (dump_file, " for abnormal default def SSA name "); 1266*38fd1498Szrj print_generic_expr (dump_file, ptr); 1267*38fd1498Szrj fprintf (dump_file, "\n"); 1268*38fd1498Szrj } 1269*38fd1498Szrj } 1270*38fd1498Szrj else 1271*38fd1498Szrj { 1272*38fd1498Szrj tree copy; 1273*38fd1498Szrj gimple *def = SSA_NAME_DEF_STMT (ptr); 1274*38fd1498Szrj gimple *assign; 1275*38fd1498Szrj gimple_stmt_iterator gsi; 1276*38fd1498Szrj 1277*38fd1498Szrj if (bnd_var) 1278*38fd1498Szrj copy = make_ssa_name (bnd_var); 1279*38fd1498Szrj else 1280*38fd1498Szrj copy = make_temp_ssa_name (pointer_bounds_type_node, 1281*38fd1498Szrj NULL, 1282*38fd1498Szrj CHKP_BOUND_TMP_NAME); 1283*38fd1498Szrj bnd = chkp_get_orginal_bounds_for_abnormal_copy (bnd); 1284*38fd1498Szrj assign = gimple_build_assign (copy, bnd); 1285*38fd1498Szrj 1286*38fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS)) 1287*38fd1498Szrj { 1288*38fd1498Szrj fprintf (dump_file, "Creating a copy of bounds "); 1289*38fd1498Szrj print_generic_expr (dump_file, bnd); 1290*38fd1498Szrj fprintf (dump_file, " for abnormal SSA name "); 1291*38fd1498Szrj print_generic_expr (dump_file, ptr); 1292*38fd1498Szrj fprintf (dump_file, "\n"); 1293*38fd1498Szrj } 1294*38fd1498Szrj 1295*38fd1498Szrj if (gimple_code (def) == GIMPLE_NOP) 1296*38fd1498Szrj { 1297*38fd1498Szrj gsi = gsi_last_bb (chkp_get_entry_block ()); 1298*38fd1498Szrj if (!gsi_end_p (gsi) && is_ctrl_stmt (gsi_stmt (gsi))) 1299*38fd1498Szrj gsi_insert_before (&gsi, assign, GSI_CONTINUE_LINKING); 1300*38fd1498Szrj else 1301*38fd1498Szrj gsi_insert_after (&gsi, assign, GSI_CONTINUE_LINKING); 1302*38fd1498Szrj } 1303*38fd1498Szrj else 1304*38fd1498Szrj { 1305*38fd1498Szrj gimple *bnd_def = SSA_NAME_DEF_STMT (bnd); 1306*38fd1498Szrj /* Sometimes (e.g. when we load a pointer from a 1307*38fd1498Szrj memory) bounds are produced later than a pointer. 1308*38fd1498Szrj We need to insert bounds copy appropriately. */ 1309*38fd1498Szrj if (gimple_code (bnd_def) != GIMPLE_NOP 1310*38fd1498Szrj && stmt_dominates_stmt_p (def, bnd_def)) 1311*38fd1498Szrj gsi = gsi_for_stmt (bnd_def); 1312*38fd1498Szrj else 1313*38fd1498Szrj gsi = gsi_for_stmt (def); 1314*38fd1498Szrj gsi_insert_after (&gsi, assign, GSI_CONTINUE_LINKING); 1315*38fd1498Szrj } 1316*38fd1498Szrj 1317*38fd1498Szrj bnd = copy; 1318*38fd1498Szrj } 1319*38fd1498Szrj 1320*38fd1498Szrj if (abnormal_ptr) 1321*38fd1498Szrj bitmap_set_bit (chkp_abnormal_copies, SSA_NAME_VERSION (bnd)); 1322*38fd1498Szrj } 1323*38fd1498Szrj 1324*38fd1498Szrj chkp_reg_bounds->put (ptr, bnd); 1325*38fd1498Szrj 1326*38fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS)) 1327*38fd1498Szrj { 1328*38fd1498Szrj fprintf (dump_file, "Regsitered bound "); 1329*38fd1498Szrj print_generic_expr (dump_file, bnd); 1330*38fd1498Szrj fprintf (dump_file, " for pointer "); 1331*38fd1498Szrj print_generic_expr (dump_file, ptr); 1332*38fd1498Szrj fprintf (dump_file, "\n"); 1333*38fd1498Szrj } 1334*38fd1498Szrj 1335*38fd1498Szrj return bnd; 1336*38fd1498Szrj } 1337*38fd1498Szrj 1338*38fd1498Szrj /* Get bounds registered for object PTR in global bounds table. */ 1339*38fd1498Szrj static tree 1340*38fd1498Szrj chkp_get_registered_bounds (tree ptr) 1341*38fd1498Szrj { 1342*38fd1498Szrj tree *slot; 1343*38fd1498Szrj 1344*38fd1498Szrj if (!chkp_reg_bounds) 1345*38fd1498Szrj return NULL_TREE; 1346*38fd1498Szrj 1347*38fd1498Szrj slot = chkp_reg_bounds->get (ptr); 1348*38fd1498Szrj return slot ? *slot : NULL_TREE; 1349*38fd1498Szrj } 1350*38fd1498Szrj 1351*38fd1498Szrj /* Add bound retvals to return statement pointed by GSI. */ 1352*38fd1498Szrj 1353*38fd1498Szrj static void 1354*38fd1498Szrj chkp_add_bounds_to_ret_stmt (gimple_stmt_iterator *gsi) 1355*38fd1498Szrj { 1356*38fd1498Szrj greturn *ret = as_a <greturn *> (gsi_stmt (*gsi)); 1357*38fd1498Szrj tree retval = gimple_return_retval (ret); 1358*38fd1498Szrj tree ret_decl = DECL_RESULT (cfun->decl); 1359*38fd1498Szrj tree bounds; 1360*38fd1498Szrj 1361*38fd1498Szrj if (!retval) 1362*38fd1498Szrj return; 1363*38fd1498Szrj 1364*38fd1498Szrj if (BOUNDED_P (ret_decl)) 1365*38fd1498Szrj { 1366*38fd1498Szrj bounds = chkp_find_bounds (retval, gsi); 1367*38fd1498Szrj bounds = chkp_maybe_copy_and_register_bounds (ret_decl, bounds); 1368*38fd1498Szrj gimple_return_set_retbnd (ret, bounds); 1369*38fd1498Szrj } 1370*38fd1498Szrj 1371*38fd1498Szrj update_stmt (ret); 1372*38fd1498Szrj } 1373*38fd1498Szrj 1374*38fd1498Szrj /* Force OP to be suitable for using as an argument for call. 1375*38fd1498Szrj New statements (if any) go to SEQ. */ 1376*38fd1498Szrj static tree 1377*38fd1498Szrj chkp_force_gimple_call_op (tree op, gimple_seq *seq) 1378*38fd1498Szrj { 1379*38fd1498Szrj gimple_seq stmts; 1380*38fd1498Szrj gimple_stmt_iterator si; 1381*38fd1498Szrj 1382*38fd1498Szrj op = force_gimple_operand (unshare_expr (op), &stmts, true, NULL_TREE); 1383*38fd1498Szrj 1384*38fd1498Szrj for (si = gsi_start (stmts); !gsi_end_p (si); gsi_next (&si)) 1385*38fd1498Szrj chkp_mark_stmt (gsi_stmt (si)); 1386*38fd1498Szrj 1387*38fd1498Szrj gimple_seq_add_seq (seq, stmts); 1388*38fd1498Szrj 1389*38fd1498Szrj return op; 1390*38fd1498Szrj } 1391*38fd1498Szrj 1392*38fd1498Szrj /* Generate lower bound check for memory access by ADDR. 1393*38fd1498Szrj Check is inserted before the position pointed by ITER. 1394*38fd1498Szrj DIRFLAG indicates whether memory access is load or store. */ 1395*38fd1498Szrj static void 1396*38fd1498Szrj chkp_check_lower (tree addr, tree bounds, 1397*38fd1498Szrj gimple_stmt_iterator iter, 1398*38fd1498Szrj location_t location, 1399*38fd1498Szrj tree dirflag) 1400*38fd1498Szrj { 1401*38fd1498Szrj gimple_seq seq; 1402*38fd1498Szrj gimple *check; 1403*38fd1498Szrj tree node; 1404*38fd1498Szrj 1405*38fd1498Szrj if (!chkp_function_instrumented_p (current_function_decl) 1406*38fd1498Szrj && bounds == chkp_get_zero_bounds ()) 1407*38fd1498Szrj return; 1408*38fd1498Szrj 1409*38fd1498Szrj if (dirflag == integer_zero_node 1410*38fd1498Szrj && !flag_chkp_check_read) 1411*38fd1498Szrj return; 1412*38fd1498Szrj 1413*38fd1498Szrj if (dirflag == integer_one_node 1414*38fd1498Szrj && !flag_chkp_check_write) 1415*38fd1498Szrj return; 1416*38fd1498Szrj 1417*38fd1498Szrj seq = NULL; 1418*38fd1498Szrj 1419*38fd1498Szrj node = chkp_force_gimple_call_op (addr, &seq); 1420*38fd1498Szrj 1421*38fd1498Szrj check = gimple_build_call (chkp_checkl_fndecl, 2, node, bounds); 1422*38fd1498Szrj chkp_mark_stmt (check); 1423*38fd1498Szrj gimple_call_set_with_bounds (check, true); 1424*38fd1498Szrj gimple_set_location (check, location); 1425*38fd1498Szrj gimple_seq_add_stmt (&seq, check); 1426*38fd1498Szrj 1427*38fd1498Szrj gsi_insert_seq_before (&iter, seq, GSI_SAME_STMT); 1428*38fd1498Szrj 1429*38fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS)) 1430*38fd1498Szrj { 1431*38fd1498Szrj gimple *before = gsi_stmt (iter); 1432*38fd1498Szrj fprintf (dump_file, "Generated lower bound check for statement "); 1433*38fd1498Szrj print_gimple_stmt (dump_file, before, 0, TDF_VOPS|TDF_MEMSYMS); 1434*38fd1498Szrj fprintf (dump_file, " "); 1435*38fd1498Szrj print_gimple_stmt (dump_file, check, 0, TDF_VOPS|TDF_MEMSYMS); 1436*38fd1498Szrj } 1437*38fd1498Szrj } 1438*38fd1498Szrj 1439*38fd1498Szrj /* Generate upper bound check for memory access by ADDR. 1440*38fd1498Szrj Check is inserted before the position pointed by ITER. 1441*38fd1498Szrj DIRFLAG indicates whether memory access is load or store. */ 1442*38fd1498Szrj static void 1443*38fd1498Szrj chkp_check_upper (tree addr, tree bounds, 1444*38fd1498Szrj gimple_stmt_iterator iter, 1445*38fd1498Szrj location_t location, 1446*38fd1498Szrj tree dirflag) 1447*38fd1498Szrj { 1448*38fd1498Szrj gimple_seq seq; 1449*38fd1498Szrj gimple *check; 1450*38fd1498Szrj tree node; 1451*38fd1498Szrj 1452*38fd1498Szrj if (!chkp_function_instrumented_p (current_function_decl) 1453*38fd1498Szrj && bounds == chkp_get_zero_bounds ()) 1454*38fd1498Szrj return; 1455*38fd1498Szrj 1456*38fd1498Szrj if (dirflag == integer_zero_node 1457*38fd1498Szrj && !flag_chkp_check_read) 1458*38fd1498Szrj return; 1459*38fd1498Szrj 1460*38fd1498Szrj if (dirflag == integer_one_node 1461*38fd1498Szrj && !flag_chkp_check_write) 1462*38fd1498Szrj return; 1463*38fd1498Szrj 1464*38fd1498Szrj seq = NULL; 1465*38fd1498Szrj 1466*38fd1498Szrj node = chkp_force_gimple_call_op (addr, &seq); 1467*38fd1498Szrj 1468*38fd1498Szrj check = gimple_build_call (chkp_checku_fndecl, 2, node, bounds); 1469*38fd1498Szrj chkp_mark_stmt (check); 1470*38fd1498Szrj gimple_call_set_with_bounds (check, true); 1471*38fd1498Szrj gimple_set_location (check, location); 1472*38fd1498Szrj gimple_seq_add_stmt (&seq, check); 1473*38fd1498Szrj 1474*38fd1498Szrj gsi_insert_seq_before (&iter, seq, GSI_SAME_STMT); 1475*38fd1498Szrj 1476*38fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS)) 1477*38fd1498Szrj { 1478*38fd1498Szrj gimple *before = gsi_stmt (iter); 1479*38fd1498Szrj fprintf (dump_file, "Generated upper bound check for statement "); 1480*38fd1498Szrj print_gimple_stmt (dump_file, before, 0, TDF_VOPS|TDF_MEMSYMS); 1481*38fd1498Szrj fprintf (dump_file, " "); 1482*38fd1498Szrj print_gimple_stmt (dump_file, check, 0, TDF_VOPS|TDF_MEMSYMS); 1483*38fd1498Szrj } 1484*38fd1498Szrj } 1485*38fd1498Szrj 1486*38fd1498Szrj /* Generate lower and upper bound checks for memory access 1487*38fd1498Szrj to memory slot [FIRST, LAST] againsr BOUNDS. Checks 1488*38fd1498Szrj are inserted before the position pointed by ITER. 1489*38fd1498Szrj DIRFLAG indicates whether memory access is load or store. */ 1490*38fd1498Szrj void 1491*38fd1498Szrj chkp_check_mem_access (tree first, tree last, tree bounds, 1492*38fd1498Szrj gimple_stmt_iterator iter, 1493*38fd1498Szrj location_t location, 1494*38fd1498Szrj tree dirflag) 1495*38fd1498Szrj { 1496*38fd1498Szrj chkp_check_lower (first, bounds, iter, location, dirflag); 1497*38fd1498Szrj chkp_check_upper (last, bounds, iter, location, dirflag); 1498*38fd1498Szrj } 1499*38fd1498Szrj 1500*38fd1498Szrj /* Replace call to _bnd_chk_* pointed by GSI with 1501*38fd1498Szrj bndcu and bndcl calls. DIRFLAG determines whether 1502*38fd1498Szrj check is for read or write. */ 1503*38fd1498Szrj 1504*38fd1498Szrj void 1505*38fd1498Szrj chkp_replace_address_check_builtin (gimple_stmt_iterator *gsi, 1506*38fd1498Szrj tree dirflag) 1507*38fd1498Szrj { 1508*38fd1498Szrj gimple_stmt_iterator call_iter = *gsi; 1509*38fd1498Szrj gimple *call = gsi_stmt (*gsi); 1510*38fd1498Szrj tree fndecl = gimple_call_fndecl (call); 1511*38fd1498Szrj tree addr = gimple_call_arg (call, 0); 1512*38fd1498Szrj tree bounds = chkp_find_bounds (addr, gsi); 1513*38fd1498Szrj 1514*38fd1498Szrj if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_CHECK_PTR_LBOUNDS 1515*38fd1498Szrj || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_CHECK_PTR_BOUNDS) 1516*38fd1498Szrj chkp_check_lower (addr, bounds, *gsi, gimple_location (call), dirflag); 1517*38fd1498Szrj 1518*38fd1498Szrj if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_CHECK_PTR_UBOUNDS) 1519*38fd1498Szrj chkp_check_upper (addr, bounds, *gsi, gimple_location (call), dirflag); 1520*38fd1498Szrj 1521*38fd1498Szrj if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_CHECK_PTR_BOUNDS) 1522*38fd1498Szrj { 1523*38fd1498Szrj tree size = gimple_call_arg (call, 1); 1524*38fd1498Szrj addr = fold_build_pointer_plus (addr, size); 1525*38fd1498Szrj addr = fold_build_pointer_plus_hwi (addr, -1); 1526*38fd1498Szrj chkp_check_upper (addr, bounds, *gsi, gimple_location (call), dirflag); 1527*38fd1498Szrj } 1528*38fd1498Szrj 1529*38fd1498Szrj gsi_remove (&call_iter, true); 1530*38fd1498Szrj } 1531*38fd1498Szrj 1532*38fd1498Szrj /* Replace call to _bnd_get_ptr_* pointed by GSI with 1533*38fd1498Szrj corresponding bounds extract call. */ 1534*38fd1498Szrj 1535*38fd1498Szrj void 1536*38fd1498Szrj chkp_replace_extract_builtin (gimple_stmt_iterator *gsi) 1537*38fd1498Szrj { 1538*38fd1498Szrj gimple *call = gsi_stmt (*gsi); 1539*38fd1498Szrj tree fndecl = gimple_call_fndecl (call); 1540*38fd1498Szrj tree addr = gimple_call_arg (call, 0); 1541*38fd1498Szrj tree bounds = chkp_find_bounds (addr, gsi); 1542*38fd1498Szrj gimple *extract; 1543*38fd1498Szrj 1544*38fd1498Szrj if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_GET_PTR_LBOUND) 1545*38fd1498Szrj fndecl = chkp_extract_lower_fndecl; 1546*38fd1498Szrj else if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_GET_PTR_UBOUND) 1547*38fd1498Szrj fndecl = chkp_extract_upper_fndecl; 1548*38fd1498Szrj else 1549*38fd1498Szrj gcc_unreachable (); 1550*38fd1498Szrj 1551*38fd1498Szrj extract = gimple_build_call (fndecl, 1, bounds); 1552*38fd1498Szrj gimple_call_set_lhs (extract, gimple_call_lhs (call)); 1553*38fd1498Szrj chkp_mark_stmt (extract); 1554*38fd1498Szrj 1555*38fd1498Szrj gsi_replace (gsi, extract, false); 1556*38fd1498Szrj } 1557*38fd1498Szrj 1558*38fd1498Szrj /* Return COMPONENT_REF accessing FIELD in OBJ. */ 1559*38fd1498Szrj static tree 1560*38fd1498Szrj chkp_build_component_ref (tree obj, tree field) 1561*38fd1498Szrj { 1562*38fd1498Szrj tree res; 1563*38fd1498Szrj 1564*38fd1498Szrj /* If object is TMR then we do not use component_ref but 1565*38fd1498Szrj add offset instead. We need it to be able to get addr 1566*38fd1498Szrj of the reasult later. */ 1567*38fd1498Szrj if (TREE_CODE (obj) == TARGET_MEM_REF) 1568*38fd1498Szrj { 1569*38fd1498Szrj tree offs = TMR_OFFSET (obj); 1570*38fd1498Szrj offs = fold_binary_to_constant (PLUS_EXPR, TREE_TYPE (offs), 1571*38fd1498Szrj offs, DECL_FIELD_OFFSET (field)); 1572*38fd1498Szrj 1573*38fd1498Szrj gcc_assert (offs); 1574*38fd1498Szrj 1575*38fd1498Szrj res = copy_node (obj); 1576*38fd1498Szrj TREE_TYPE (res) = TREE_TYPE (field); 1577*38fd1498Szrj TMR_OFFSET (res) = offs; 1578*38fd1498Szrj } 1579*38fd1498Szrj else 1580*38fd1498Szrj res = build3 (COMPONENT_REF, TREE_TYPE (field), obj, field, NULL_TREE); 1581*38fd1498Szrj 1582*38fd1498Szrj return res; 1583*38fd1498Szrj } 1584*38fd1498Szrj 1585*38fd1498Szrj /* Return ARRAY_REF for array ARR and index IDX with 1586*38fd1498Szrj specified element type ETYPE and element size ESIZE. */ 1587*38fd1498Szrj static tree 1588*38fd1498Szrj chkp_build_array_ref (tree arr, tree etype, tree esize, 1589*38fd1498Szrj unsigned HOST_WIDE_INT idx) 1590*38fd1498Szrj { 1591*38fd1498Szrj tree index = build_int_cst (size_type_node, idx); 1592*38fd1498Szrj tree res; 1593*38fd1498Szrj 1594*38fd1498Szrj /* If object is TMR then we do not use array_ref but 1595*38fd1498Szrj add offset instead. We need it to be able to get addr 1596*38fd1498Szrj of the reasult later. */ 1597*38fd1498Szrj if (TREE_CODE (arr) == TARGET_MEM_REF) 1598*38fd1498Szrj { 1599*38fd1498Szrj tree offs = TMR_OFFSET (arr); 1600*38fd1498Szrj 1601*38fd1498Szrj esize = fold_binary_to_constant (MULT_EXPR, TREE_TYPE (esize), 1602*38fd1498Szrj esize, index); 1603*38fd1498Szrj gcc_assert(esize); 1604*38fd1498Szrj 1605*38fd1498Szrj offs = fold_binary_to_constant (PLUS_EXPR, TREE_TYPE (offs), 1606*38fd1498Szrj offs, esize); 1607*38fd1498Szrj gcc_assert (offs); 1608*38fd1498Szrj 1609*38fd1498Szrj res = copy_node (arr); 1610*38fd1498Szrj TREE_TYPE (res) = etype; 1611*38fd1498Szrj TMR_OFFSET (res) = offs; 1612*38fd1498Szrj } 1613*38fd1498Szrj else 1614*38fd1498Szrj res = build4 (ARRAY_REF, etype, arr, index, NULL_TREE, NULL_TREE); 1615*38fd1498Szrj 1616*38fd1498Szrj return res; 1617*38fd1498Szrj } 1618*38fd1498Szrj 1619*38fd1498Szrj /* Helper function for chkp_add_bounds_to_call_stmt. 1620*38fd1498Szrj Fill ALL_BOUNDS output array with created bounds. 1621*38fd1498Szrj 1622*38fd1498Szrj OFFS is used for recursive calls and holds basic 1623*38fd1498Szrj offset of TYPE in outer structure in bits. 1624*38fd1498Szrj 1625*38fd1498Szrj ITER points a position where bounds are searched. 1626*38fd1498Szrj 1627*38fd1498Szrj ALL_BOUNDS[i] is filled with elem bounds if there 1628*38fd1498Szrj is a field in TYPE which has pointer type and offset 1629*38fd1498Szrj equal to i * POINTER_SIZE in bits. */ 1630*38fd1498Szrj static void 1631*38fd1498Szrj chkp_find_bounds_for_elem (tree elem, tree *all_bounds, 1632*38fd1498Szrj HOST_WIDE_INT offs, 1633*38fd1498Szrj gimple_stmt_iterator *iter) 1634*38fd1498Szrj { 1635*38fd1498Szrj tree type = TREE_TYPE (elem); 1636*38fd1498Szrj 1637*38fd1498Szrj if (BOUNDED_TYPE_P (type)) 1638*38fd1498Szrj { 1639*38fd1498Szrj if (!all_bounds[offs / POINTER_SIZE]) 1640*38fd1498Szrj { 1641*38fd1498Szrj tree temp = make_temp_ssa_name (type, NULL, ""); 1642*38fd1498Szrj gimple *assign = gimple_build_assign (temp, elem); 1643*38fd1498Szrj gimple_stmt_iterator gsi; 1644*38fd1498Szrj 1645*38fd1498Szrj gsi_insert_before (iter, assign, GSI_SAME_STMT); 1646*38fd1498Szrj gsi = gsi_for_stmt (assign); 1647*38fd1498Szrj 1648*38fd1498Szrj all_bounds[offs / POINTER_SIZE] = chkp_find_bounds (temp, &gsi); 1649*38fd1498Szrj } 1650*38fd1498Szrj } 1651*38fd1498Szrj else if (RECORD_OR_UNION_TYPE_P (type)) 1652*38fd1498Szrj { 1653*38fd1498Szrj tree field; 1654*38fd1498Szrj 1655*38fd1498Szrj for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) 1656*38fd1498Szrj if (TREE_CODE (field) == FIELD_DECL) 1657*38fd1498Szrj { 1658*38fd1498Szrj tree base = unshare_expr (elem); 1659*38fd1498Szrj tree field_ref = chkp_build_component_ref (base, field); 1660*38fd1498Szrj HOST_WIDE_INT field_offs 1661*38fd1498Szrj = TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field)); 1662*38fd1498Szrj if (DECL_FIELD_OFFSET (field)) 1663*38fd1498Szrj field_offs += TREE_INT_CST_LOW (DECL_FIELD_OFFSET (field)) * 8; 1664*38fd1498Szrj 1665*38fd1498Szrj chkp_find_bounds_for_elem (field_ref, all_bounds, 1666*38fd1498Szrj offs + field_offs, iter); 1667*38fd1498Szrj } 1668*38fd1498Szrj } 1669*38fd1498Szrj else if (TREE_CODE (type) == ARRAY_TYPE) 1670*38fd1498Szrj { 1671*38fd1498Szrj tree maxval = TYPE_MAX_VALUE (TYPE_DOMAIN (type)); 1672*38fd1498Szrj tree etype = TREE_TYPE (type); 1673*38fd1498Szrj HOST_WIDE_INT esize = TREE_INT_CST_LOW (TYPE_SIZE (etype)); 1674*38fd1498Szrj unsigned HOST_WIDE_INT cur; 1675*38fd1498Szrj 1676*38fd1498Szrj if (!maxval || integer_minus_onep (maxval)) 1677*38fd1498Szrj return; 1678*38fd1498Szrj 1679*38fd1498Szrj for (cur = 0; cur <= TREE_INT_CST_LOW (maxval); cur++) 1680*38fd1498Szrj { 1681*38fd1498Szrj tree base = unshare_expr (elem); 1682*38fd1498Szrj tree arr_elem = chkp_build_array_ref (base, etype, 1683*38fd1498Szrj TYPE_SIZE (etype), 1684*38fd1498Szrj cur); 1685*38fd1498Szrj chkp_find_bounds_for_elem (arr_elem, all_bounds, offs + cur * esize, 1686*38fd1498Szrj iter); 1687*38fd1498Szrj } 1688*38fd1498Szrj } 1689*38fd1498Szrj } 1690*38fd1498Szrj 1691*38fd1498Szrj /* Maximum number of elements to check in an array. */ 1692*38fd1498Szrj 1693*38fd1498Szrj #define CHKP_ARRAY_MAX_CHECK_STEPS 4096 1694*38fd1498Szrj 1695*38fd1498Szrj /* Fill HAVE_BOUND output bitmap with information about 1696*38fd1498Szrj bounds requred for object of type TYPE. 1697*38fd1498Szrj 1698*38fd1498Szrj OFFS is used for recursive calls and holds basic 1699*38fd1498Szrj offset of TYPE in outer structure in bits. 1700*38fd1498Szrj 1701*38fd1498Szrj HAVE_BOUND[i] is set to 1 if there is a field 1702*38fd1498Szrj in TYPE which has pointer type and offset 1703*38fd1498Szrj equal to i * POINTER_SIZE - OFFS in bits. */ 1704*38fd1498Szrj void 1705*38fd1498Szrj chkp_find_bound_slots_1 (const_tree type, bitmap have_bound, 1706*38fd1498Szrj HOST_WIDE_INT offs) 1707*38fd1498Szrj { 1708*38fd1498Szrj if (BOUNDED_TYPE_P (type)) 1709*38fd1498Szrj bitmap_set_bit (have_bound, offs / POINTER_SIZE); 1710*38fd1498Szrj else if (RECORD_OR_UNION_TYPE_P (type)) 1711*38fd1498Szrj { 1712*38fd1498Szrj tree field; 1713*38fd1498Szrj 1714*38fd1498Szrj for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) 1715*38fd1498Szrj if (TREE_CODE (field) == FIELD_DECL) 1716*38fd1498Szrj { 1717*38fd1498Szrj HOST_WIDE_INT field_offs = 0; 1718*38fd1498Szrj if (DECL_FIELD_BIT_OFFSET (field)) 1719*38fd1498Szrj field_offs += TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field)); 1720*38fd1498Szrj if (DECL_FIELD_OFFSET (field)) 1721*38fd1498Szrj field_offs += TREE_INT_CST_LOW (DECL_FIELD_OFFSET (field)) * 8; 1722*38fd1498Szrj chkp_find_bound_slots_1 (TREE_TYPE (field), have_bound, 1723*38fd1498Szrj offs + field_offs); 1724*38fd1498Szrj } 1725*38fd1498Szrj } 1726*38fd1498Szrj else if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type)) 1727*38fd1498Szrj { 1728*38fd1498Szrj /* The object type is an array of complete type, i.e., other 1729*38fd1498Szrj than a flexible array. */ 1730*38fd1498Szrj tree maxval = TYPE_MAX_VALUE (TYPE_DOMAIN (type)); 1731*38fd1498Szrj tree etype = TREE_TYPE (type); 1732*38fd1498Szrj HOST_WIDE_INT esize = TREE_INT_CST_LOW (TYPE_SIZE (etype)); 1733*38fd1498Szrj unsigned HOST_WIDE_INT cur; 1734*38fd1498Szrj 1735*38fd1498Szrj if (!maxval 1736*38fd1498Szrj || TREE_CODE (maxval) != INTEGER_CST 1737*38fd1498Szrj || integer_minus_onep (maxval)) 1738*38fd1498Szrj return; 1739*38fd1498Szrj 1740*38fd1498Szrj for (cur = 0; 1741*38fd1498Szrj cur <= MIN (CHKP_ARRAY_MAX_CHECK_STEPS, TREE_INT_CST_LOW (maxval)); 1742*38fd1498Szrj cur++) 1743*38fd1498Szrj chkp_find_bound_slots_1 (etype, have_bound, offs + cur * esize); 1744*38fd1498Szrj } 1745*38fd1498Szrj } 1746*38fd1498Szrj 1747*38fd1498Szrj /* Fill bitmap RES with information about bounds for 1748*38fd1498Szrj type TYPE. See chkp_find_bound_slots_1 for more 1749*38fd1498Szrj details. */ 1750*38fd1498Szrj void 1751*38fd1498Szrj chkp_find_bound_slots (const_tree type, bitmap res) 1752*38fd1498Szrj { 1753*38fd1498Szrj bitmap_clear (res); 1754*38fd1498Szrj chkp_find_bound_slots_1 (type, res, 0); 1755*38fd1498Szrj } 1756*38fd1498Szrj 1757*38fd1498Szrj /* Return 1 if call to FNDECL should be instrumented 1758*38fd1498Szrj and 0 otherwise. */ 1759*38fd1498Szrj 1760*38fd1498Szrj static bool 1761*38fd1498Szrj chkp_instrument_normal_builtin (tree fndecl) 1762*38fd1498Szrj { 1763*38fd1498Szrj switch (DECL_FUNCTION_CODE (fndecl)) 1764*38fd1498Szrj { 1765*38fd1498Szrj case BUILT_IN_STRLEN: 1766*38fd1498Szrj case BUILT_IN_STRCPY: 1767*38fd1498Szrj case BUILT_IN_STRNCPY: 1768*38fd1498Szrj case BUILT_IN_STPCPY: 1769*38fd1498Szrj case BUILT_IN_STPNCPY: 1770*38fd1498Szrj case BUILT_IN_STRCAT: 1771*38fd1498Szrj case BUILT_IN_STRNCAT: 1772*38fd1498Szrj case BUILT_IN_MEMCPY: 1773*38fd1498Szrj case BUILT_IN_MEMPCPY: 1774*38fd1498Szrj case BUILT_IN_MEMSET: 1775*38fd1498Szrj case BUILT_IN_MEMMOVE: 1776*38fd1498Szrj case BUILT_IN_BZERO: 1777*38fd1498Szrj case BUILT_IN_STRCMP: 1778*38fd1498Szrj case BUILT_IN_STRNCMP: 1779*38fd1498Szrj case BUILT_IN_BCMP: 1780*38fd1498Szrj case BUILT_IN_MEMCMP: 1781*38fd1498Szrj case BUILT_IN_MEMCPY_CHK: 1782*38fd1498Szrj case BUILT_IN_MEMPCPY_CHK: 1783*38fd1498Szrj case BUILT_IN_MEMMOVE_CHK: 1784*38fd1498Szrj case BUILT_IN_MEMSET_CHK: 1785*38fd1498Szrj case BUILT_IN_STRCPY_CHK: 1786*38fd1498Szrj case BUILT_IN_STRNCPY_CHK: 1787*38fd1498Szrj case BUILT_IN_STPCPY_CHK: 1788*38fd1498Szrj case BUILT_IN_STPNCPY_CHK: 1789*38fd1498Szrj case BUILT_IN_STRCAT_CHK: 1790*38fd1498Szrj case BUILT_IN_STRNCAT_CHK: 1791*38fd1498Szrj case BUILT_IN_MALLOC: 1792*38fd1498Szrj case BUILT_IN_CALLOC: 1793*38fd1498Szrj case BUILT_IN_REALLOC: 1794*38fd1498Szrj return 1; 1795*38fd1498Szrj 1796*38fd1498Szrj default: 1797*38fd1498Szrj return 0; 1798*38fd1498Szrj } 1799*38fd1498Szrj } 1800*38fd1498Szrj 1801*38fd1498Szrj /* Add bound arguments to call statement pointed by GSI. 1802*38fd1498Szrj Also performs a replacement of user checker builtins calls 1803*38fd1498Szrj with internal ones. */ 1804*38fd1498Szrj 1805*38fd1498Szrj static void 1806*38fd1498Szrj chkp_add_bounds_to_call_stmt (gimple_stmt_iterator *gsi) 1807*38fd1498Szrj { 1808*38fd1498Szrj gcall *call = as_a <gcall *> (gsi_stmt (*gsi)); 1809*38fd1498Szrj unsigned arg_no = 0; 1810*38fd1498Szrj tree fndecl = gimple_call_fndecl (call); 1811*38fd1498Szrj tree fntype; 1812*38fd1498Szrj tree first_formal_arg; 1813*38fd1498Szrj tree arg; 1814*38fd1498Szrj bool use_fntype = false; 1815*38fd1498Szrj tree op; 1816*38fd1498Szrj ssa_op_iter iter; 1817*38fd1498Szrj gcall *new_call; 1818*38fd1498Szrj 1819*38fd1498Szrj /* Do nothing for internal functions. */ 1820*38fd1498Szrj if (gimple_call_internal_p (call)) 1821*38fd1498Szrj return; 1822*38fd1498Szrj 1823*38fd1498Szrj fntype = TREE_TYPE (TREE_TYPE (gimple_call_fn (call))); 1824*38fd1498Szrj 1825*38fd1498Szrj /* Do nothing if back-end builtin is called. */ 1826*38fd1498Szrj if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD) 1827*38fd1498Szrj return; 1828*38fd1498Szrj 1829*38fd1498Szrj /* Do nothing for some middle-end builtins. */ 1830*38fd1498Szrj if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL 1831*38fd1498Szrj && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_OBJECT_SIZE) 1832*38fd1498Szrj return; 1833*38fd1498Szrj 1834*38fd1498Szrj /* Do nothing for calls to not instrumentable functions. */ 1835*38fd1498Szrj if (fndecl && !chkp_instrumentable_p (fndecl)) 1836*38fd1498Szrj return; 1837*38fd1498Szrj 1838*38fd1498Szrj /* Ignore CHKP_INIT_PTR_BOUNDS, CHKP_NULL_PTR_BOUNDS 1839*38fd1498Szrj and CHKP_COPY_PTR_BOUNDS. */ 1840*38fd1498Szrj if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL 1841*38fd1498Szrj && (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_INIT_PTR_BOUNDS 1842*38fd1498Szrj || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_NULL_PTR_BOUNDS 1843*38fd1498Szrj || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_COPY_PTR_BOUNDS 1844*38fd1498Szrj || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_SET_PTR_BOUNDS)) 1845*38fd1498Szrj return; 1846*38fd1498Szrj 1847*38fd1498Szrj /* Check user builtins are replaced with checks. */ 1848*38fd1498Szrj if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL 1849*38fd1498Szrj && (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_CHECK_PTR_LBOUNDS 1850*38fd1498Szrj || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_CHECK_PTR_UBOUNDS 1851*38fd1498Szrj || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_CHECK_PTR_BOUNDS)) 1852*38fd1498Szrj { 1853*38fd1498Szrj chkp_replace_address_check_builtin (gsi, integer_minus_one_node); 1854*38fd1498Szrj return; 1855*38fd1498Szrj } 1856*38fd1498Szrj 1857*38fd1498Szrj /* Check user builtins are replaced with bound extract. */ 1858*38fd1498Szrj if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL 1859*38fd1498Szrj && (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_GET_PTR_LBOUND 1860*38fd1498Szrj || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_GET_PTR_UBOUND)) 1861*38fd1498Szrj { 1862*38fd1498Szrj chkp_replace_extract_builtin (gsi); 1863*38fd1498Szrj return; 1864*38fd1498Szrj } 1865*38fd1498Szrj 1866*38fd1498Szrj /* BUILT_IN_CHKP_NARROW_PTR_BOUNDS call is replaced with 1867*38fd1498Szrj target narrow bounds call. */ 1868*38fd1498Szrj if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL 1869*38fd1498Szrj && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_NARROW_PTR_BOUNDS) 1870*38fd1498Szrj { 1871*38fd1498Szrj tree arg = gimple_call_arg (call, 1); 1872*38fd1498Szrj tree bounds = chkp_find_bounds (arg, gsi); 1873*38fd1498Szrj 1874*38fd1498Szrj gimple_call_set_fndecl (call, chkp_narrow_bounds_fndecl); 1875*38fd1498Szrj gimple_call_set_arg (call, 1, bounds); 1876*38fd1498Szrj update_stmt (call); 1877*38fd1498Szrj 1878*38fd1498Szrj return; 1879*38fd1498Szrj } 1880*38fd1498Szrj 1881*38fd1498Szrj /* BUILT_IN_CHKP_STORE_PTR_BOUNDS call is replaced with 1882*38fd1498Szrj bndstx call. */ 1883*38fd1498Szrj if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL 1884*38fd1498Szrj && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_STORE_PTR_BOUNDS) 1885*38fd1498Szrj { 1886*38fd1498Szrj tree addr = gimple_call_arg (call, 0); 1887*38fd1498Szrj tree ptr = gimple_call_arg (call, 1); 1888*38fd1498Szrj tree bounds = chkp_find_bounds (ptr, gsi); 1889*38fd1498Szrj gimple_stmt_iterator iter = gsi_for_stmt (call); 1890*38fd1498Szrj 1891*38fd1498Szrj chkp_build_bndstx (addr, ptr, bounds, gsi); 1892*38fd1498Szrj gsi_remove (&iter, true); 1893*38fd1498Szrj 1894*38fd1498Szrj return; 1895*38fd1498Szrj } 1896*38fd1498Szrj 1897*38fd1498Szrj if (!flag_chkp_instrument_calls) 1898*38fd1498Szrj return; 1899*38fd1498Szrj 1900*38fd1498Szrj /* We instrument only some subset of builtins. We also instrument 1901*38fd1498Szrj builtin calls to be inlined. */ 1902*38fd1498Szrj if (fndecl 1903*38fd1498Szrj && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL 1904*38fd1498Szrj && !chkp_instrument_normal_builtin (fndecl)) 1905*38fd1498Szrj { 1906*38fd1498Szrj if (!lookup_attribute ("always_inline", DECL_ATTRIBUTES (fndecl))) 1907*38fd1498Szrj return; 1908*38fd1498Szrj 1909*38fd1498Szrj struct cgraph_node *clone = chkp_maybe_create_clone (fndecl); 1910*38fd1498Szrj if (!clone 1911*38fd1498Szrj || !gimple_has_body_p (clone->decl)) 1912*38fd1498Szrj return; 1913*38fd1498Szrj } 1914*38fd1498Szrj 1915*38fd1498Szrj /* If function decl is available then use it for 1916*38fd1498Szrj formal arguments list. Otherwise use function type. */ 1917*38fd1498Szrj if (fndecl 1918*38fd1498Szrj && DECL_ARGUMENTS (fndecl) 1919*38fd1498Szrj && gimple_call_fntype (call) == TREE_TYPE (fndecl)) 1920*38fd1498Szrj first_formal_arg = DECL_ARGUMENTS (fndecl); 1921*38fd1498Szrj else 1922*38fd1498Szrj { 1923*38fd1498Szrj first_formal_arg = TYPE_ARG_TYPES (fntype); 1924*38fd1498Szrj use_fntype = true; 1925*38fd1498Szrj } 1926*38fd1498Szrj 1927*38fd1498Szrj /* Fill vector of new call args. */ 1928*38fd1498Szrj vec<tree> new_args = vNULL; 1929*38fd1498Szrj new_args.create (gimple_call_num_args (call)); 1930*38fd1498Szrj arg = first_formal_arg; 1931*38fd1498Szrj for (arg_no = 0; arg_no < gimple_call_num_args (call); arg_no++) 1932*38fd1498Szrj { 1933*38fd1498Szrj tree call_arg = gimple_call_arg (call, arg_no); 1934*38fd1498Szrj tree type; 1935*38fd1498Szrj 1936*38fd1498Szrj /* Get arg type using formal argument description 1937*38fd1498Szrj or actual argument type. */ 1938*38fd1498Szrj if (arg) 1939*38fd1498Szrj if (use_fntype) 1940*38fd1498Szrj if (TREE_VALUE (arg) != void_type_node) 1941*38fd1498Szrj { 1942*38fd1498Szrj type = TREE_VALUE (arg); 1943*38fd1498Szrj arg = TREE_CHAIN (arg); 1944*38fd1498Szrj } 1945*38fd1498Szrj else 1946*38fd1498Szrj type = TREE_TYPE (call_arg); 1947*38fd1498Szrj else 1948*38fd1498Szrj { 1949*38fd1498Szrj type = TREE_TYPE (arg); 1950*38fd1498Szrj arg = TREE_CHAIN (arg); 1951*38fd1498Szrj } 1952*38fd1498Szrj else 1953*38fd1498Szrj type = TREE_TYPE (call_arg); 1954*38fd1498Szrj 1955*38fd1498Szrj new_args.safe_push (call_arg); 1956*38fd1498Szrj 1957*38fd1498Szrj if (BOUNDED_TYPE_P (type) 1958*38fd1498Szrj || pass_by_reference (NULL, TYPE_MODE (type), type, true)) 1959*38fd1498Szrj new_args.safe_push (chkp_find_bounds (call_arg, gsi)); 1960*38fd1498Szrj else if (chkp_type_has_pointer (type)) 1961*38fd1498Szrj { 1962*38fd1498Szrj HOST_WIDE_INT max_bounds 1963*38fd1498Szrj = TREE_INT_CST_LOW (TYPE_SIZE (type)) / POINTER_SIZE; 1964*38fd1498Szrj tree *all_bounds = (tree *)xmalloc (sizeof (tree) * max_bounds); 1965*38fd1498Szrj HOST_WIDE_INT bnd_no; 1966*38fd1498Szrj 1967*38fd1498Szrj memset (all_bounds, 0, sizeof (tree) * max_bounds); 1968*38fd1498Szrj 1969*38fd1498Szrj chkp_find_bounds_for_elem (call_arg, all_bounds, 0, gsi); 1970*38fd1498Szrj 1971*38fd1498Szrj for (bnd_no = 0; bnd_no < max_bounds; bnd_no++) 1972*38fd1498Szrj if (all_bounds[bnd_no]) 1973*38fd1498Szrj new_args.safe_push (all_bounds[bnd_no]); 1974*38fd1498Szrj 1975*38fd1498Szrj free (all_bounds); 1976*38fd1498Szrj } 1977*38fd1498Szrj } 1978*38fd1498Szrj 1979*38fd1498Szrj if (new_args.length () == gimple_call_num_args (call)) 1980*38fd1498Szrj new_call = call; 1981*38fd1498Szrj else 1982*38fd1498Szrj { 1983*38fd1498Szrj new_call = gimple_build_call_vec (gimple_op (call, 1), new_args); 1984*38fd1498Szrj gimple_call_set_lhs (new_call, gimple_call_lhs (call)); 1985*38fd1498Szrj gimple_call_copy_flags (new_call, call); 1986*38fd1498Szrj gimple_call_set_chain (new_call, gimple_call_chain (call)); 1987*38fd1498Szrj } 1988*38fd1498Szrj new_args.release (); 1989*38fd1498Szrj 1990*38fd1498Szrj /* For direct calls fndecl is replaced with instrumented version. */ 1991*38fd1498Szrj if (fndecl) 1992*38fd1498Szrj { 1993*38fd1498Szrj tree new_decl = chkp_maybe_create_clone (fndecl)->decl; 1994*38fd1498Szrj gimple_call_set_fndecl (new_call, new_decl); 1995*38fd1498Szrj /* In case of a type cast we should modify used function 1996*38fd1498Szrj type instead of using type of new fndecl. */ 1997*38fd1498Szrj if (gimple_call_fntype (call) != TREE_TYPE (fndecl)) 1998*38fd1498Szrj { 1999*38fd1498Szrj tree type = gimple_call_fntype (call); 2000*38fd1498Szrj type = chkp_copy_function_type_adding_bounds (type); 2001*38fd1498Szrj gimple_call_set_fntype (new_call, type); 2002*38fd1498Szrj } 2003*38fd1498Szrj else 2004*38fd1498Szrj gimple_call_set_fntype (new_call, TREE_TYPE (new_decl)); 2005*38fd1498Szrj } 2006*38fd1498Szrj /* For indirect call we should fix function pointer type if 2007*38fd1498Szrj pass some bounds. */ 2008*38fd1498Szrj else if (new_call != call) 2009*38fd1498Szrj { 2010*38fd1498Szrj tree type = gimple_call_fntype (call); 2011*38fd1498Szrj type = chkp_copy_function_type_adding_bounds (type); 2012*38fd1498Szrj gimple_call_set_fntype (new_call, type); 2013*38fd1498Szrj } 2014*38fd1498Szrj 2015*38fd1498Szrj /* replace old call statement with the new one. */ 2016*38fd1498Szrj if (call != new_call) 2017*38fd1498Szrj { 2018*38fd1498Szrj FOR_EACH_SSA_TREE_OPERAND (op, call, iter, SSA_OP_ALL_DEFS) 2019*38fd1498Szrj { 2020*38fd1498Szrj SSA_NAME_DEF_STMT (op) = new_call; 2021*38fd1498Szrj } 2022*38fd1498Szrj gsi_replace (gsi, new_call, true); 2023*38fd1498Szrj } 2024*38fd1498Szrj else 2025*38fd1498Szrj update_stmt (new_call); 2026*38fd1498Szrj 2027*38fd1498Szrj gimple_call_set_with_bounds (new_call, true); 2028*38fd1498Szrj } 2029*38fd1498Szrj 2030*38fd1498Szrj /* Return constant static bounds var with specified bounds LB and UB. 2031*38fd1498Szrj If such var does not exists then new var is created with specified NAME. */ 2032*38fd1498Szrj static tree 2033*38fd1498Szrj chkp_make_static_const_bounds (HOST_WIDE_INT lb, 2034*38fd1498Szrj HOST_WIDE_INT ub, 2035*38fd1498Szrj const char *name) 2036*38fd1498Szrj { 2037*38fd1498Szrj tree id = get_identifier (name); 2038*38fd1498Szrj tree var; 2039*38fd1498Szrj varpool_node *node; 2040*38fd1498Szrj symtab_node *snode; 2041*38fd1498Szrj 2042*38fd1498Szrj var = build_decl (UNKNOWN_LOCATION, VAR_DECL, id, 2043*38fd1498Szrj pointer_bounds_type_node); 2044*38fd1498Szrj TREE_STATIC (var) = 1; 2045*38fd1498Szrj TREE_PUBLIC (var) = 1; 2046*38fd1498Szrj 2047*38fd1498Szrj /* With LTO we may have constant bounds already in varpool. 2048*38fd1498Szrj Try to find it. */ 2049*38fd1498Szrj if ((snode = symtab_node::get_for_asmname (DECL_ASSEMBLER_NAME (var)))) 2050*38fd1498Szrj { 2051*38fd1498Szrj /* We don't allow this symbol usage for non bounds. */ 2052*38fd1498Szrj if (snode->type != SYMTAB_VARIABLE 2053*38fd1498Szrj || !POINTER_BOUNDS_P (snode->decl)) 2054*38fd1498Szrj sorry ("-fcheck-pointer-bounds requires %qs " 2055*38fd1498Szrj "name for internal usage", 2056*38fd1498Szrj IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (var))); 2057*38fd1498Szrj 2058*38fd1498Szrj return snode->decl; 2059*38fd1498Szrj } 2060*38fd1498Szrj 2061*38fd1498Szrj TREE_USED (var) = 1; 2062*38fd1498Szrj TREE_READONLY (var) = 1; 2063*38fd1498Szrj TREE_ADDRESSABLE (var) = 0; 2064*38fd1498Szrj DECL_ARTIFICIAL (var) = 1; 2065*38fd1498Szrj DECL_READ_P (var) = 1; 2066*38fd1498Szrj DECL_INITIAL (var) = targetm.chkp_make_bounds_constant (lb, ub); 2067*38fd1498Szrj make_decl_one_only (var, DECL_ASSEMBLER_NAME (var)); 2068*38fd1498Szrj /* We may use this symbol during ctors generation in chkp_finish_file 2069*38fd1498Szrj when all symbols are emitted. Force output to avoid undefined 2070*38fd1498Szrj symbols in ctors. */ 2071*38fd1498Szrj node = varpool_node::get_create (var); 2072*38fd1498Szrj node->force_output = 1; 2073*38fd1498Szrj 2074*38fd1498Szrj varpool_node::finalize_decl (var); 2075*38fd1498Szrj 2076*38fd1498Szrj return var; 2077*38fd1498Szrj } 2078*38fd1498Szrj 2079*38fd1498Szrj /* Generate code to make bounds with specified lower bound LB and SIZE. 2080*38fd1498Szrj if AFTER is 1 then code is inserted after position pointed by ITER 2081*38fd1498Szrj otherwise code is inserted before position pointed by ITER. 2082*38fd1498Szrj If ITER is NULL then code is added to entry block. */ 2083*38fd1498Szrj static tree 2084*38fd1498Szrj chkp_make_bounds (tree lb, tree size, gimple_stmt_iterator *iter, bool after) 2085*38fd1498Szrj { 2086*38fd1498Szrj gimple_seq seq; 2087*38fd1498Szrj gimple_stmt_iterator gsi; 2088*38fd1498Szrj gimple *stmt; 2089*38fd1498Szrj tree bounds; 2090*38fd1498Szrj 2091*38fd1498Szrj if (iter) 2092*38fd1498Szrj gsi = *iter; 2093*38fd1498Szrj else 2094*38fd1498Szrj gsi = gsi_start_bb (chkp_get_entry_block ()); 2095*38fd1498Szrj 2096*38fd1498Szrj seq = NULL; 2097*38fd1498Szrj 2098*38fd1498Szrj lb = chkp_force_gimple_call_op (lb, &seq); 2099*38fd1498Szrj size = chkp_force_gimple_call_op (size, &seq); 2100*38fd1498Szrj 2101*38fd1498Szrj stmt = gimple_build_call (chkp_bndmk_fndecl, 2, lb, size); 2102*38fd1498Szrj chkp_mark_stmt (stmt); 2103*38fd1498Szrj 2104*38fd1498Szrj bounds = chkp_get_tmp_reg (stmt); 2105*38fd1498Szrj gimple_call_set_lhs (stmt, bounds); 2106*38fd1498Szrj 2107*38fd1498Szrj gimple_seq_add_stmt (&seq, stmt); 2108*38fd1498Szrj 2109*38fd1498Szrj if (iter && after) 2110*38fd1498Szrj gsi_insert_seq_after (&gsi, seq, GSI_SAME_STMT); 2111*38fd1498Szrj else 2112*38fd1498Szrj gsi_insert_seq_before (&gsi, seq, GSI_SAME_STMT); 2113*38fd1498Szrj 2114*38fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS)) 2115*38fd1498Szrj { 2116*38fd1498Szrj fprintf (dump_file, "Made bounds: "); 2117*38fd1498Szrj print_gimple_stmt (dump_file, stmt, 0, TDF_VOPS|TDF_MEMSYMS); 2118*38fd1498Szrj if (iter) 2119*38fd1498Szrj { 2120*38fd1498Szrj fprintf (dump_file, " inserted before statement: "); 2121*38fd1498Szrj print_gimple_stmt (dump_file, gsi_stmt (*iter), 0, TDF_VOPS|TDF_MEMSYMS); 2122*38fd1498Szrj } 2123*38fd1498Szrj else 2124*38fd1498Szrj fprintf (dump_file, " at function entry\n"); 2125*38fd1498Szrj } 2126*38fd1498Szrj 2127*38fd1498Szrj /* update_stmt (stmt); */ 2128*38fd1498Szrj 2129*38fd1498Szrj return bounds; 2130*38fd1498Szrj } 2131*38fd1498Szrj 2132*38fd1498Szrj /* Return var holding zero bounds. */ 2133*38fd1498Szrj tree 2134*38fd1498Szrj chkp_get_zero_bounds_var (void) 2135*38fd1498Szrj { 2136*38fd1498Szrj if (!chkp_zero_bounds_var) 2137*38fd1498Szrj chkp_zero_bounds_var 2138*38fd1498Szrj = chkp_make_static_const_bounds (0, -1, 2139*38fd1498Szrj CHKP_ZERO_BOUNDS_VAR_NAME); 2140*38fd1498Szrj return chkp_zero_bounds_var; 2141*38fd1498Szrj } 2142*38fd1498Szrj 2143*38fd1498Szrj /* Return var holding none bounds. */ 2144*38fd1498Szrj tree 2145*38fd1498Szrj chkp_get_none_bounds_var (void) 2146*38fd1498Szrj { 2147*38fd1498Szrj if (!chkp_none_bounds_var) 2148*38fd1498Szrj chkp_none_bounds_var 2149*38fd1498Szrj = chkp_make_static_const_bounds (-1, 0, 2150*38fd1498Szrj CHKP_NONE_BOUNDS_VAR_NAME); 2151*38fd1498Szrj return chkp_none_bounds_var; 2152*38fd1498Szrj } 2153*38fd1498Szrj 2154*38fd1498Szrj /* Return SSA_NAME used to represent zero bounds. */ 2155*38fd1498Szrj static tree 2156*38fd1498Szrj chkp_get_zero_bounds (void) 2157*38fd1498Szrj { 2158*38fd1498Szrj if (zero_bounds) 2159*38fd1498Szrj return zero_bounds; 2160*38fd1498Szrj 2161*38fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS)) 2162*38fd1498Szrj fprintf (dump_file, "Creating zero bounds..."); 2163*38fd1498Szrj 2164*38fd1498Szrj if ((flag_chkp_use_static_bounds && flag_chkp_use_static_const_bounds) 2165*38fd1498Szrj || flag_chkp_use_static_const_bounds > 0) 2166*38fd1498Szrj { 2167*38fd1498Szrj gimple_stmt_iterator gsi = gsi_start_bb (chkp_get_entry_block ()); 2168*38fd1498Szrj gimple *stmt; 2169*38fd1498Szrj 2170*38fd1498Szrj zero_bounds = chkp_get_tmp_reg (NULL); 2171*38fd1498Szrj stmt = gimple_build_assign (zero_bounds, chkp_get_zero_bounds_var ()); 2172*38fd1498Szrj gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); 2173*38fd1498Szrj } 2174*38fd1498Szrj else 2175*38fd1498Szrj zero_bounds = chkp_make_bounds (integer_zero_node, 2176*38fd1498Szrj integer_zero_node, 2177*38fd1498Szrj NULL, 2178*38fd1498Szrj false); 2179*38fd1498Szrj 2180*38fd1498Szrj return zero_bounds; 2181*38fd1498Szrj } 2182*38fd1498Szrj 2183*38fd1498Szrj /* Return SSA_NAME used to represent none bounds. */ 2184*38fd1498Szrj static tree 2185*38fd1498Szrj chkp_get_none_bounds (void) 2186*38fd1498Szrj { 2187*38fd1498Szrj if (none_bounds) 2188*38fd1498Szrj return none_bounds; 2189*38fd1498Szrj 2190*38fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS)) 2191*38fd1498Szrj fprintf (dump_file, "Creating none bounds..."); 2192*38fd1498Szrj 2193*38fd1498Szrj 2194*38fd1498Szrj if ((flag_chkp_use_static_bounds && flag_chkp_use_static_const_bounds) 2195*38fd1498Szrj || flag_chkp_use_static_const_bounds > 0) 2196*38fd1498Szrj { 2197*38fd1498Szrj gimple_stmt_iterator gsi = gsi_start_bb (chkp_get_entry_block ()); 2198*38fd1498Szrj gimple *stmt; 2199*38fd1498Szrj 2200*38fd1498Szrj none_bounds = chkp_get_tmp_reg (NULL); 2201*38fd1498Szrj stmt = gimple_build_assign (none_bounds, chkp_get_none_bounds_var ()); 2202*38fd1498Szrj gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); 2203*38fd1498Szrj } 2204*38fd1498Szrj else 2205*38fd1498Szrj none_bounds = chkp_make_bounds (integer_minus_one_node, 2206*38fd1498Szrj build_int_cst (size_type_node, 2), 2207*38fd1498Szrj NULL, 2208*38fd1498Szrj false); 2209*38fd1498Szrj 2210*38fd1498Szrj return none_bounds; 2211*38fd1498Szrj } 2212*38fd1498Szrj 2213*38fd1498Szrj /* Return bounds to be used as a result of operation which 2214*38fd1498Szrj should not create poiunter (e.g. MULT_EXPR). */ 2215*38fd1498Szrj static tree 2216*38fd1498Szrj chkp_get_invalid_op_bounds (void) 2217*38fd1498Szrj { 2218*38fd1498Szrj return chkp_get_zero_bounds (); 2219*38fd1498Szrj } 2220*38fd1498Szrj 2221*38fd1498Szrj /* Return bounds to be used for loads of non-pointer values. */ 2222*38fd1498Szrj static tree 2223*38fd1498Szrj chkp_get_nonpointer_load_bounds (void) 2224*38fd1498Szrj { 2225*38fd1498Szrj return chkp_get_zero_bounds (); 2226*38fd1498Szrj } 2227*38fd1498Szrj 2228*38fd1498Szrj /* Return 1 if may use bndret call to get bounds for pointer 2229*38fd1498Szrj returned by CALL. */ 2230*38fd1498Szrj static bool 2231*38fd1498Szrj chkp_call_returns_bounds_p (gcall *call) 2232*38fd1498Szrj { 2233*38fd1498Szrj if (gimple_call_internal_p (call)) 2234*38fd1498Szrj { 2235*38fd1498Szrj if (gimple_call_internal_fn (call) == IFN_VA_ARG) 2236*38fd1498Szrj return true; 2237*38fd1498Szrj return false; 2238*38fd1498Szrj } 2239*38fd1498Szrj 2240*38fd1498Szrj if (gimple_call_builtin_p (call, BUILT_IN_CHKP_NARROW_PTR_BOUNDS) 2241*38fd1498Szrj || chkp_gimple_call_builtin_p (call, BUILT_IN_CHKP_NARROW)) 2242*38fd1498Szrj return true; 2243*38fd1498Szrj 2244*38fd1498Szrj if (gimple_call_with_bounds_p (call)) 2245*38fd1498Szrj return true; 2246*38fd1498Szrj 2247*38fd1498Szrj tree fndecl = gimple_call_fndecl (call); 2248*38fd1498Szrj 2249*38fd1498Szrj if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD) 2250*38fd1498Szrj return false; 2251*38fd1498Szrj 2252*38fd1498Szrj if (fndecl && !chkp_instrumentable_p (fndecl)) 2253*38fd1498Szrj return false; 2254*38fd1498Szrj 2255*38fd1498Szrj if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL) 2256*38fd1498Szrj { 2257*38fd1498Szrj if (chkp_instrument_normal_builtin (fndecl)) 2258*38fd1498Szrj return true; 2259*38fd1498Szrj 2260*38fd1498Szrj if (!lookup_attribute ("always_inline", DECL_ATTRIBUTES (fndecl))) 2261*38fd1498Szrj return false; 2262*38fd1498Szrj 2263*38fd1498Szrj struct cgraph_node *clone = chkp_maybe_create_clone (fndecl); 2264*38fd1498Szrj return (clone && gimple_has_body_p (clone->decl)); 2265*38fd1498Szrj } 2266*38fd1498Szrj 2267*38fd1498Szrj return true; 2268*38fd1498Szrj } 2269*38fd1498Szrj 2270*38fd1498Szrj /* Build bounds returned by CALL. */ 2271*38fd1498Szrj static tree 2272*38fd1498Szrj chkp_build_returned_bound (gcall *call) 2273*38fd1498Szrj { 2274*38fd1498Szrj gimple_stmt_iterator gsi; 2275*38fd1498Szrj tree bounds; 2276*38fd1498Szrj gimple *stmt; 2277*38fd1498Szrj tree fndecl = gimple_call_fndecl (call); 2278*38fd1498Szrj unsigned int retflags; 2279*38fd1498Szrj tree lhs = gimple_call_lhs (call); 2280*38fd1498Szrj 2281*38fd1498Szrj /* To avoid fixing alloca expands in targets we handle 2282*38fd1498Szrj it separately. */ 2283*38fd1498Szrj if (fndecl 2284*38fd1498Szrj && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL 2285*38fd1498Szrj && ALLOCA_FUNCTION_CODE_P (DECL_FUNCTION_CODE (fndecl))) 2286*38fd1498Szrj { 2287*38fd1498Szrj tree size = gimple_call_arg (call, 0); 2288*38fd1498Szrj gimple_stmt_iterator iter = gsi_for_stmt (call); 2289*38fd1498Szrj bounds = chkp_make_bounds (lhs, size, &iter, true); 2290*38fd1498Szrj } 2291*38fd1498Szrj /* We know bounds returned by set_bounds builtin call. */ 2292*38fd1498Szrj else if (fndecl 2293*38fd1498Szrj && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL 2294*38fd1498Szrj && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_SET_PTR_BOUNDS) 2295*38fd1498Szrj { 2296*38fd1498Szrj tree lb = gimple_call_arg (call, 0); 2297*38fd1498Szrj tree size = gimple_call_arg (call, 1); 2298*38fd1498Szrj gimple_stmt_iterator iter = gsi_for_stmt (call); 2299*38fd1498Szrj bounds = chkp_make_bounds (lb, size, &iter, true); 2300*38fd1498Szrj } 2301*38fd1498Szrj /* Detect bounds initialization calls. */ 2302*38fd1498Szrj else if (fndecl 2303*38fd1498Szrj && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL 2304*38fd1498Szrj && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_INIT_PTR_BOUNDS) 2305*38fd1498Szrj bounds = chkp_get_zero_bounds (); 2306*38fd1498Szrj /* Detect bounds nullification calls. */ 2307*38fd1498Szrj else if (fndecl 2308*38fd1498Szrj && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL 2309*38fd1498Szrj && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_NULL_PTR_BOUNDS) 2310*38fd1498Szrj bounds = chkp_get_none_bounds (); 2311*38fd1498Szrj /* Detect bounds copy calls. */ 2312*38fd1498Szrj else if (fndecl 2313*38fd1498Szrj && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL 2314*38fd1498Szrj && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_COPY_PTR_BOUNDS) 2315*38fd1498Szrj { 2316*38fd1498Szrj gimple_stmt_iterator iter = gsi_for_stmt (call); 2317*38fd1498Szrj bounds = chkp_find_bounds (gimple_call_arg (call, 1), &iter); 2318*38fd1498Szrj } 2319*38fd1498Szrj /* Do not use retbnd when returned bounds are equal to some 2320*38fd1498Szrj of passed bounds. */ 2321*38fd1498Szrj else if (((retflags = gimple_call_return_flags (call)) & ERF_RETURNS_ARG) 2322*38fd1498Szrj && (retflags & ERF_RETURN_ARG_MASK) < gimple_call_num_args (call)) 2323*38fd1498Szrj { 2324*38fd1498Szrj gimple_stmt_iterator iter = gsi_for_stmt (call); 2325*38fd1498Szrj unsigned int retarg = retflags & ERF_RETURN_ARG_MASK, argno; 2326*38fd1498Szrj if (gimple_call_with_bounds_p (call)) 2327*38fd1498Szrj { 2328*38fd1498Szrj for (argno = 0; argno < gimple_call_num_args (call); argno++) 2329*38fd1498Szrj if (!POINTER_BOUNDS_P (gimple_call_arg (call, argno))) 2330*38fd1498Szrj { 2331*38fd1498Szrj if (retarg) 2332*38fd1498Szrj retarg--; 2333*38fd1498Szrj else 2334*38fd1498Szrj break; 2335*38fd1498Szrj } 2336*38fd1498Szrj } 2337*38fd1498Szrj else 2338*38fd1498Szrj argno = retarg; 2339*38fd1498Szrj 2340*38fd1498Szrj bounds = chkp_find_bounds (gimple_call_arg (call, argno), &iter); 2341*38fd1498Szrj } 2342*38fd1498Szrj else if (chkp_call_returns_bounds_p (call) 2343*38fd1498Szrj && BOUNDED_P (lhs)) 2344*38fd1498Szrj { 2345*38fd1498Szrj gcc_assert (TREE_CODE (lhs) == SSA_NAME); 2346*38fd1498Szrj 2347*38fd1498Szrj /* In general case build checker builtin call to 2348*38fd1498Szrj obtain returned bounds. */ 2349*38fd1498Szrj stmt = gimple_build_call (chkp_ret_bnd_fndecl, 1, 2350*38fd1498Szrj gimple_call_lhs (call)); 2351*38fd1498Szrj chkp_mark_stmt (stmt); 2352*38fd1498Szrj 2353*38fd1498Szrj gsi = gsi_for_stmt (call); 2354*38fd1498Szrj gsi_insert_after (&gsi, stmt, GSI_SAME_STMT); 2355*38fd1498Szrj 2356*38fd1498Szrj bounds = chkp_get_tmp_reg (stmt); 2357*38fd1498Szrj gimple_call_set_lhs (stmt, bounds); 2358*38fd1498Szrj 2359*38fd1498Szrj update_stmt (stmt); 2360*38fd1498Szrj } 2361*38fd1498Szrj else 2362*38fd1498Szrj bounds = chkp_get_zero_bounds (); 2363*38fd1498Szrj 2364*38fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS)) 2365*38fd1498Szrj { 2366*38fd1498Szrj fprintf (dump_file, "Built returned bounds ("); 2367*38fd1498Szrj print_generic_expr (dump_file, bounds); 2368*38fd1498Szrj fprintf (dump_file, ") for call: "); 2369*38fd1498Szrj print_gimple_stmt (dump_file, call, 0, TDF_VOPS | TDF_MEMSYMS); 2370*38fd1498Szrj } 2371*38fd1498Szrj 2372*38fd1498Szrj bounds = chkp_maybe_copy_and_register_bounds (lhs, bounds); 2373*38fd1498Szrj 2374*38fd1498Szrj return bounds; 2375*38fd1498Szrj } 2376*38fd1498Szrj 2377*38fd1498Szrj /* Return bounds used as returned by call 2378*38fd1498Szrj which produced SSA name VAL. */ 2379*38fd1498Szrj gcall * 2380*38fd1498Szrj chkp_retbnd_call_by_val (tree val) 2381*38fd1498Szrj { 2382*38fd1498Szrj if (TREE_CODE (val) != SSA_NAME) 2383*38fd1498Szrj return NULL; 2384*38fd1498Szrj 2385*38fd1498Szrj gcc_assert (gimple_code (SSA_NAME_DEF_STMT (val)) == GIMPLE_CALL); 2386*38fd1498Szrj 2387*38fd1498Szrj imm_use_iterator use_iter; 2388*38fd1498Szrj use_operand_p use_p; 2389*38fd1498Szrj FOR_EACH_IMM_USE_FAST (use_p, use_iter, val) 2390*38fd1498Szrj if (chkp_gimple_call_builtin_p (USE_STMT (use_p), BUILT_IN_CHKP_BNDRET)) 2391*38fd1498Szrj return as_a <gcall *> (USE_STMT (use_p)); 2392*38fd1498Szrj 2393*38fd1498Szrj return NULL; 2394*38fd1498Szrj } 2395*38fd1498Szrj 2396*38fd1498Szrj /* Check the next parameter for the given PARM is bounds 2397*38fd1498Szrj and return it's default SSA_NAME (create if required). */ 2398*38fd1498Szrj static tree 2399*38fd1498Szrj chkp_get_next_bounds_parm (tree parm) 2400*38fd1498Szrj { 2401*38fd1498Szrj tree bounds = TREE_CHAIN (parm); 2402*38fd1498Szrj gcc_assert (POINTER_BOUNDS_P (bounds)); 2403*38fd1498Szrj bounds = ssa_default_def (cfun, bounds); 2404*38fd1498Szrj if (!bounds) 2405*38fd1498Szrj { 2406*38fd1498Szrj bounds = make_ssa_name (TREE_CHAIN (parm), gimple_build_nop ()); 2407*38fd1498Szrj set_ssa_default_def (cfun, TREE_CHAIN (parm), bounds); 2408*38fd1498Szrj } 2409*38fd1498Szrj return bounds; 2410*38fd1498Szrj } 2411*38fd1498Szrj 2412*38fd1498Szrj /* Return bounds to be used for input argument PARM. */ 2413*38fd1498Szrj static tree 2414*38fd1498Szrj chkp_get_bound_for_parm (tree parm) 2415*38fd1498Szrj { 2416*38fd1498Szrj tree decl = SSA_NAME_VAR (parm); 2417*38fd1498Szrj tree bounds; 2418*38fd1498Szrj 2419*38fd1498Szrj gcc_assert (TREE_CODE (decl) == PARM_DECL); 2420*38fd1498Szrj 2421*38fd1498Szrj bounds = chkp_get_registered_bounds (parm); 2422*38fd1498Szrj 2423*38fd1498Szrj if (!bounds) 2424*38fd1498Szrj bounds = chkp_get_registered_bounds (decl); 2425*38fd1498Szrj 2426*38fd1498Szrj if (!bounds) 2427*38fd1498Szrj { 2428*38fd1498Szrj tree orig_decl = cgraph_node::get (cfun->decl)->orig_decl; 2429*38fd1498Szrj 2430*38fd1498Szrj /* For static chain param we return zero bounds 2431*38fd1498Szrj because currently we do not check dereferences 2432*38fd1498Szrj of this pointer. */ 2433*38fd1498Szrj if (cfun->static_chain_decl == decl) 2434*38fd1498Szrj bounds = chkp_get_zero_bounds (); 2435*38fd1498Szrj /* If non instrumented runtime is used then it may be useful 2436*38fd1498Szrj to use zero bounds for input arguments of main 2437*38fd1498Szrj function. */ 2438*38fd1498Szrj else if (flag_chkp_zero_input_bounds_for_main 2439*38fd1498Szrj && id_equal (DECL_ASSEMBLER_NAME (orig_decl), "main")) 2440*38fd1498Szrj bounds = chkp_get_zero_bounds (); 2441*38fd1498Szrj else if (BOUNDED_P (parm)) 2442*38fd1498Szrj { 2443*38fd1498Szrj bounds = chkp_get_next_bounds_parm (decl); 2444*38fd1498Szrj bounds = chkp_maybe_copy_and_register_bounds (decl, bounds); 2445*38fd1498Szrj 2446*38fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS)) 2447*38fd1498Szrj { 2448*38fd1498Szrj fprintf (dump_file, "Built arg bounds ("); 2449*38fd1498Szrj print_generic_expr (dump_file, bounds); 2450*38fd1498Szrj fprintf (dump_file, ") for arg: "); 2451*38fd1498Szrj print_node (dump_file, "", decl, 0); 2452*38fd1498Szrj } 2453*38fd1498Szrj } 2454*38fd1498Szrj else 2455*38fd1498Szrj bounds = chkp_get_zero_bounds (); 2456*38fd1498Szrj } 2457*38fd1498Szrj 2458*38fd1498Szrj if (!chkp_get_registered_bounds (parm)) 2459*38fd1498Szrj bounds = chkp_maybe_copy_and_register_bounds (parm, bounds); 2460*38fd1498Szrj 2461*38fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS)) 2462*38fd1498Szrj { 2463*38fd1498Szrj fprintf (dump_file, "Using bounds "); 2464*38fd1498Szrj print_generic_expr (dump_file, bounds); 2465*38fd1498Szrj fprintf (dump_file, " for parm "); 2466*38fd1498Szrj print_generic_expr (dump_file, parm); 2467*38fd1498Szrj fprintf (dump_file, " of type "); 2468*38fd1498Szrj print_generic_expr (dump_file, TREE_TYPE (parm)); 2469*38fd1498Szrj fprintf (dump_file, ".\n"); 2470*38fd1498Szrj } 2471*38fd1498Szrj 2472*38fd1498Szrj return bounds; 2473*38fd1498Szrj } 2474*38fd1498Szrj 2475*38fd1498Szrj /* Build and return CALL_EXPR for bndstx builtin with specified 2476*38fd1498Szrj arguments. */ 2477*38fd1498Szrj tree 2478*38fd1498Szrj chkp_build_bndldx_call (tree addr, tree ptr) 2479*38fd1498Szrj { 2480*38fd1498Szrj tree fn = build1 (ADDR_EXPR, 2481*38fd1498Szrj build_pointer_type (TREE_TYPE (chkp_bndldx_fndecl)), 2482*38fd1498Szrj chkp_bndldx_fndecl); 2483*38fd1498Szrj tree call = build_call_nary (TREE_TYPE (TREE_TYPE (chkp_bndldx_fndecl)), 2484*38fd1498Szrj fn, 2, addr, ptr); 2485*38fd1498Szrj CALL_WITH_BOUNDS_P (call) = true; 2486*38fd1498Szrj return call; 2487*38fd1498Szrj } 2488*38fd1498Szrj 2489*38fd1498Szrj /* Insert code to load bounds for PTR located by ADDR. 2490*38fd1498Szrj Code is inserted after position pointed by GSI. 2491*38fd1498Szrj Loaded bounds are returned. */ 2492*38fd1498Szrj static tree 2493*38fd1498Szrj chkp_build_bndldx (tree addr, tree ptr, gimple_stmt_iterator *gsi) 2494*38fd1498Szrj { 2495*38fd1498Szrj gimple_seq seq; 2496*38fd1498Szrj gimple *stmt; 2497*38fd1498Szrj tree bounds; 2498*38fd1498Szrj 2499*38fd1498Szrj seq = NULL; 2500*38fd1498Szrj 2501*38fd1498Szrj addr = chkp_force_gimple_call_op (addr, &seq); 2502*38fd1498Szrj ptr = chkp_force_gimple_call_op (ptr, &seq); 2503*38fd1498Szrj 2504*38fd1498Szrj stmt = gimple_build_call (chkp_bndldx_fndecl, 2, addr, ptr); 2505*38fd1498Szrj chkp_mark_stmt (stmt); 2506*38fd1498Szrj bounds = chkp_get_tmp_reg (stmt); 2507*38fd1498Szrj gimple_call_set_lhs (stmt, bounds); 2508*38fd1498Szrj 2509*38fd1498Szrj gimple_seq_add_stmt (&seq, stmt); 2510*38fd1498Szrj 2511*38fd1498Szrj gsi_insert_seq_after (gsi, seq, GSI_CONTINUE_LINKING); 2512*38fd1498Szrj 2513*38fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS)) 2514*38fd1498Szrj { 2515*38fd1498Szrj fprintf (dump_file, "Generated bndldx for pointer "); 2516*38fd1498Szrj print_generic_expr (dump_file, ptr); 2517*38fd1498Szrj fprintf (dump_file, ": "); 2518*38fd1498Szrj print_gimple_stmt (dump_file, stmt, 0, TDF_VOPS | TDF_MEMSYMS); 2519*38fd1498Szrj } 2520*38fd1498Szrj 2521*38fd1498Szrj return bounds; 2522*38fd1498Szrj } 2523*38fd1498Szrj 2524*38fd1498Szrj /* Build and return CALL_EXPR for bndstx builtin with specified 2525*38fd1498Szrj arguments. */ 2526*38fd1498Szrj tree 2527*38fd1498Szrj chkp_build_bndstx_call (tree addr, tree ptr, tree bounds) 2528*38fd1498Szrj { 2529*38fd1498Szrj tree fn = build1 (ADDR_EXPR, 2530*38fd1498Szrj build_pointer_type (TREE_TYPE (chkp_bndstx_fndecl)), 2531*38fd1498Szrj chkp_bndstx_fndecl); 2532*38fd1498Szrj tree call = build_call_nary (TREE_TYPE (TREE_TYPE (chkp_bndstx_fndecl)), 2533*38fd1498Szrj fn, 3, ptr, bounds, addr); 2534*38fd1498Szrj CALL_WITH_BOUNDS_P (call) = true; 2535*38fd1498Szrj return call; 2536*38fd1498Szrj } 2537*38fd1498Szrj 2538*38fd1498Szrj /* Insert code to store BOUNDS for PTR stored by ADDR. 2539*38fd1498Szrj New statements are inserted after position pointed 2540*38fd1498Szrj by GSI. */ 2541*38fd1498Szrj void 2542*38fd1498Szrj chkp_build_bndstx (tree addr, tree ptr, tree bounds, 2543*38fd1498Szrj gimple_stmt_iterator *gsi) 2544*38fd1498Szrj { 2545*38fd1498Szrj gimple_seq seq; 2546*38fd1498Szrj gimple *stmt; 2547*38fd1498Szrj 2548*38fd1498Szrj seq = NULL; 2549*38fd1498Szrj 2550*38fd1498Szrj addr = chkp_force_gimple_call_op (addr, &seq); 2551*38fd1498Szrj ptr = chkp_force_gimple_call_op (ptr, &seq); 2552*38fd1498Szrj 2553*38fd1498Szrj stmt = gimple_build_call (chkp_bndstx_fndecl, 3, ptr, bounds, addr); 2554*38fd1498Szrj chkp_mark_stmt (stmt); 2555*38fd1498Szrj gimple_call_set_with_bounds (stmt, true); 2556*38fd1498Szrj 2557*38fd1498Szrj gimple_seq_add_stmt (&seq, stmt); 2558*38fd1498Szrj 2559*38fd1498Szrj gsi_insert_seq_after (gsi, seq, GSI_CONTINUE_LINKING); 2560*38fd1498Szrj 2561*38fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS)) 2562*38fd1498Szrj { 2563*38fd1498Szrj fprintf (dump_file, "Generated bndstx for pointer store "); 2564*38fd1498Szrj print_gimple_stmt (dump_file, gsi_stmt (*gsi), 0, TDF_VOPS|TDF_MEMSYMS); 2565*38fd1498Szrj print_gimple_stmt (dump_file, stmt, 2, TDF_VOPS|TDF_MEMSYMS); 2566*38fd1498Szrj } 2567*38fd1498Szrj } 2568*38fd1498Szrj 2569*38fd1498Szrj /* This function is called when call statement 2570*38fd1498Szrj is inlined and therefore we can't use bndret 2571*38fd1498Szrj for its LHS anymore. Function fixes bndret 2572*38fd1498Szrj call using new RHS value if possible. */ 2573*38fd1498Szrj void 2574*38fd1498Szrj chkp_fixup_inlined_call (tree lhs, tree rhs) 2575*38fd1498Szrj { 2576*38fd1498Szrj tree addr, bounds; 2577*38fd1498Szrj gcall *retbnd, *bndldx; 2578*38fd1498Szrj 2579*38fd1498Szrj if (!BOUNDED_P (lhs)) 2580*38fd1498Szrj return; 2581*38fd1498Szrj 2582*38fd1498Szrj /* Search for retbnd call. */ 2583*38fd1498Szrj retbnd = chkp_retbnd_call_by_val (lhs); 2584*38fd1498Szrj if (!retbnd) 2585*38fd1498Szrj return; 2586*38fd1498Szrj 2587*38fd1498Szrj /* Currently only handle cases when call is replaced 2588*38fd1498Szrj with a memory access. In this case bndret call 2589*38fd1498Szrj may be replaced with bndldx call. Otherwise we 2590*38fd1498Szrj have to search for bounds which may cause wrong 2591*38fd1498Szrj result due to various optimizations applied. */ 2592*38fd1498Szrj switch (TREE_CODE (rhs)) 2593*38fd1498Szrj { 2594*38fd1498Szrj case VAR_DECL: 2595*38fd1498Szrj if (DECL_REGISTER (rhs)) 2596*38fd1498Szrj return; 2597*38fd1498Szrj break; 2598*38fd1498Szrj 2599*38fd1498Szrj case MEM_REF: 2600*38fd1498Szrj break; 2601*38fd1498Szrj 2602*38fd1498Szrj case ARRAY_REF: 2603*38fd1498Szrj case COMPONENT_REF: 2604*38fd1498Szrj addr = get_base_address (rhs); 2605*38fd1498Szrj if (!DECL_P (addr) 2606*38fd1498Szrj && TREE_CODE (addr) != MEM_REF) 2607*38fd1498Szrj return; 2608*38fd1498Szrj if (DECL_P (addr) && DECL_REGISTER (addr)) 2609*38fd1498Szrj return; 2610*38fd1498Szrj break; 2611*38fd1498Szrj 2612*38fd1498Szrj default: 2613*38fd1498Szrj return; 2614*38fd1498Szrj } 2615*38fd1498Szrj 2616*38fd1498Szrj /* Create a new statements sequence with bndldx call. */ 2617*38fd1498Szrj gimple_stmt_iterator gsi = gsi_for_stmt (retbnd); 2618*38fd1498Szrj addr = build_fold_addr_expr (rhs); 2619*38fd1498Szrj chkp_build_bndldx (addr, lhs, &gsi); 2620*38fd1498Szrj bndldx = as_a <gcall *> (gsi_stmt (gsi)); 2621*38fd1498Szrj 2622*38fd1498Szrj /* Remove bndret call. */ 2623*38fd1498Szrj bounds = gimple_call_lhs (retbnd); 2624*38fd1498Szrj gsi = gsi_for_stmt (retbnd); 2625*38fd1498Szrj gsi_remove (&gsi, true); 2626*38fd1498Szrj 2627*38fd1498Szrj /* Link new bndldx call. */ 2628*38fd1498Szrj gimple_call_set_lhs (bndldx, bounds); 2629*38fd1498Szrj update_stmt (bndldx); 2630*38fd1498Szrj } 2631*38fd1498Szrj 2632*38fd1498Szrj /* Compute bounds for pointer NODE which was assigned in 2633*38fd1498Szrj assignment statement ASSIGN. Return computed bounds. */ 2634*38fd1498Szrj static tree 2635*38fd1498Szrj chkp_compute_bounds_for_assignment (tree node, gimple *assign) 2636*38fd1498Szrj { 2637*38fd1498Szrj enum tree_code rhs_code = gimple_assign_rhs_code (assign); 2638*38fd1498Szrj tree rhs1 = gimple_assign_rhs1 (assign); 2639*38fd1498Szrj tree bounds = NULL_TREE; 2640*38fd1498Szrj gimple_stmt_iterator iter = gsi_for_stmt (assign); 2641*38fd1498Szrj tree base = NULL; 2642*38fd1498Szrj 2643*38fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS)) 2644*38fd1498Szrj { 2645*38fd1498Szrj fprintf (dump_file, "Computing bounds for assignment: "); 2646*38fd1498Szrj print_gimple_stmt (dump_file, assign, 0, TDF_VOPS|TDF_MEMSYMS); 2647*38fd1498Szrj } 2648*38fd1498Szrj 2649*38fd1498Szrj switch (rhs_code) 2650*38fd1498Szrj { 2651*38fd1498Szrj case MEM_REF: 2652*38fd1498Szrj case TARGET_MEM_REF: 2653*38fd1498Szrj case COMPONENT_REF: 2654*38fd1498Szrj case ARRAY_REF: 2655*38fd1498Szrj /* We need to load bounds from the bounds table. */ 2656*38fd1498Szrj bounds = chkp_find_bounds_loaded (node, rhs1, &iter); 2657*38fd1498Szrj break; 2658*38fd1498Szrj 2659*38fd1498Szrj case VAR_DECL: 2660*38fd1498Szrj case SSA_NAME: 2661*38fd1498Szrj case ADDR_EXPR: 2662*38fd1498Szrj case POINTER_PLUS_EXPR: 2663*38fd1498Szrj case NOP_EXPR: 2664*38fd1498Szrj case CONVERT_EXPR: 2665*38fd1498Szrj case INTEGER_CST: 2666*38fd1498Szrj /* Bounds are just propagated from RHS. */ 2667*38fd1498Szrj bounds = chkp_find_bounds (rhs1, &iter); 2668*38fd1498Szrj base = rhs1; 2669*38fd1498Szrj break; 2670*38fd1498Szrj 2671*38fd1498Szrj case VIEW_CONVERT_EXPR: 2672*38fd1498Szrj /* Bounds are just propagated from RHS. */ 2673*38fd1498Szrj bounds = chkp_find_bounds (TREE_OPERAND (rhs1, 0), &iter); 2674*38fd1498Szrj break; 2675*38fd1498Szrj 2676*38fd1498Szrj case PARM_DECL: 2677*38fd1498Szrj if (BOUNDED_P (rhs1)) 2678*38fd1498Szrj { 2679*38fd1498Szrj /* We need to load bounds from the bounds table. */ 2680*38fd1498Szrj bounds = chkp_build_bndldx (chkp_build_addr_expr (rhs1), 2681*38fd1498Szrj node, &iter); 2682*38fd1498Szrj TREE_ADDRESSABLE (rhs1) = 1; 2683*38fd1498Szrj } 2684*38fd1498Szrj else 2685*38fd1498Szrj bounds = chkp_get_nonpointer_load_bounds (); 2686*38fd1498Szrj break; 2687*38fd1498Szrj 2688*38fd1498Szrj case MINUS_EXPR: 2689*38fd1498Szrj case PLUS_EXPR: 2690*38fd1498Szrj case BIT_AND_EXPR: 2691*38fd1498Szrj case BIT_IOR_EXPR: 2692*38fd1498Szrj case BIT_XOR_EXPR: 2693*38fd1498Szrj { 2694*38fd1498Szrj tree rhs2 = gimple_assign_rhs2 (assign); 2695*38fd1498Szrj tree bnd1 = chkp_find_bounds (rhs1, &iter); 2696*38fd1498Szrj tree bnd2 = chkp_find_bounds (rhs2, &iter); 2697*38fd1498Szrj 2698*38fd1498Szrj /* First we try to check types of operands. If it 2699*38fd1498Szrj does not help then look at bound values. 2700*38fd1498Szrj 2701*38fd1498Szrj If some bounds are incomplete and other are 2702*38fd1498Szrj not proven to be valid (i.e. also incomplete 2703*38fd1498Szrj or invalid because value is not pointer) then 2704*38fd1498Szrj resulting value is incomplete and will be 2705*38fd1498Szrj recomputed later in chkp_finish_incomplete_bounds. */ 2706*38fd1498Szrj if (BOUNDED_P (rhs1) 2707*38fd1498Szrj && !BOUNDED_P (rhs2)) 2708*38fd1498Szrj bounds = bnd1; 2709*38fd1498Szrj else if (BOUNDED_P (rhs2) 2710*38fd1498Szrj && !BOUNDED_P (rhs1) 2711*38fd1498Szrj && rhs_code != MINUS_EXPR) 2712*38fd1498Szrj bounds = bnd2; 2713*38fd1498Szrj else if (chkp_incomplete_bounds (bnd1)) 2714*38fd1498Szrj if (chkp_valid_bounds (bnd2) && rhs_code != MINUS_EXPR 2715*38fd1498Szrj && !chkp_incomplete_bounds (bnd2)) 2716*38fd1498Szrj bounds = bnd2; 2717*38fd1498Szrj else 2718*38fd1498Szrj bounds = incomplete_bounds; 2719*38fd1498Szrj else if (chkp_incomplete_bounds (bnd2)) 2720*38fd1498Szrj if (chkp_valid_bounds (bnd1) 2721*38fd1498Szrj && !chkp_incomplete_bounds (bnd1)) 2722*38fd1498Szrj bounds = bnd1; 2723*38fd1498Szrj else 2724*38fd1498Szrj bounds = incomplete_bounds; 2725*38fd1498Szrj else if (!chkp_valid_bounds (bnd1)) 2726*38fd1498Szrj if (chkp_valid_bounds (bnd2) && rhs_code != MINUS_EXPR) 2727*38fd1498Szrj bounds = bnd2; 2728*38fd1498Szrj else if (bnd2 == chkp_get_zero_bounds ()) 2729*38fd1498Szrj bounds = bnd2; 2730*38fd1498Szrj else 2731*38fd1498Szrj bounds = bnd1; 2732*38fd1498Szrj else if (!chkp_valid_bounds (bnd2)) 2733*38fd1498Szrj bounds = bnd1; 2734*38fd1498Szrj else 2735*38fd1498Szrj /* Seems both operands may have valid bounds 2736*38fd1498Szrj (e.g. pointer minus pointer). In such case 2737*38fd1498Szrj use default invalid op bounds. */ 2738*38fd1498Szrj bounds = chkp_get_invalid_op_bounds (); 2739*38fd1498Szrj 2740*38fd1498Szrj base = (bounds == bnd1) ? rhs1 : (bounds == bnd2) ? rhs2 : NULL; 2741*38fd1498Szrj } 2742*38fd1498Szrj break; 2743*38fd1498Szrj 2744*38fd1498Szrj case BIT_NOT_EXPR: 2745*38fd1498Szrj case NEGATE_EXPR: 2746*38fd1498Szrj case LSHIFT_EXPR: 2747*38fd1498Szrj case RSHIFT_EXPR: 2748*38fd1498Szrj case LROTATE_EXPR: 2749*38fd1498Szrj case RROTATE_EXPR: 2750*38fd1498Szrj case EQ_EXPR: 2751*38fd1498Szrj case NE_EXPR: 2752*38fd1498Szrj case LT_EXPR: 2753*38fd1498Szrj case LE_EXPR: 2754*38fd1498Szrj case GT_EXPR: 2755*38fd1498Szrj case GE_EXPR: 2756*38fd1498Szrj case MULT_EXPR: 2757*38fd1498Szrj case RDIV_EXPR: 2758*38fd1498Szrj case TRUNC_DIV_EXPR: 2759*38fd1498Szrj case FLOOR_DIV_EXPR: 2760*38fd1498Szrj case CEIL_DIV_EXPR: 2761*38fd1498Szrj case ROUND_DIV_EXPR: 2762*38fd1498Szrj case TRUNC_MOD_EXPR: 2763*38fd1498Szrj case FLOOR_MOD_EXPR: 2764*38fd1498Szrj case CEIL_MOD_EXPR: 2765*38fd1498Szrj case ROUND_MOD_EXPR: 2766*38fd1498Szrj case EXACT_DIV_EXPR: 2767*38fd1498Szrj case FIX_TRUNC_EXPR: 2768*38fd1498Szrj case FLOAT_EXPR: 2769*38fd1498Szrj case REALPART_EXPR: 2770*38fd1498Szrj case IMAGPART_EXPR: 2771*38fd1498Szrj case POINTER_DIFF_EXPR: 2772*38fd1498Szrj /* No valid bounds may be produced by these exprs. */ 2773*38fd1498Szrj bounds = chkp_get_invalid_op_bounds (); 2774*38fd1498Szrj break; 2775*38fd1498Szrj 2776*38fd1498Szrj case COND_EXPR: 2777*38fd1498Szrj { 2778*38fd1498Szrj tree val1 = gimple_assign_rhs2 (assign); 2779*38fd1498Szrj tree val2 = gimple_assign_rhs3 (assign); 2780*38fd1498Szrj tree bnd1 = chkp_find_bounds (val1, &iter); 2781*38fd1498Szrj tree bnd2 = chkp_find_bounds (val2, &iter); 2782*38fd1498Szrj gimple *stmt; 2783*38fd1498Szrj 2784*38fd1498Szrj if (chkp_incomplete_bounds (bnd1) || chkp_incomplete_bounds (bnd2)) 2785*38fd1498Szrj bounds = incomplete_bounds; 2786*38fd1498Szrj else if (bnd1 == bnd2) 2787*38fd1498Szrj bounds = bnd1; 2788*38fd1498Szrj else 2789*38fd1498Szrj { 2790*38fd1498Szrj rhs1 = unshare_expr (rhs1); 2791*38fd1498Szrj 2792*38fd1498Szrj bounds = chkp_get_tmp_reg (assign); 2793*38fd1498Szrj stmt = gimple_build_assign (bounds, COND_EXPR, rhs1, bnd1, bnd2); 2794*38fd1498Szrj gsi_insert_after (&iter, stmt, GSI_SAME_STMT); 2795*38fd1498Szrj 2796*38fd1498Szrj if (!chkp_valid_bounds (bnd1) && !chkp_valid_bounds (bnd2)) 2797*38fd1498Szrj chkp_mark_invalid_bounds (bounds); 2798*38fd1498Szrj } 2799*38fd1498Szrj } 2800*38fd1498Szrj break; 2801*38fd1498Szrj 2802*38fd1498Szrj case MAX_EXPR: 2803*38fd1498Szrj case MIN_EXPR: 2804*38fd1498Szrj { 2805*38fd1498Szrj tree rhs2 = gimple_assign_rhs2 (assign); 2806*38fd1498Szrj tree bnd1 = chkp_find_bounds (rhs1, &iter); 2807*38fd1498Szrj tree bnd2 = chkp_find_bounds (rhs2, &iter); 2808*38fd1498Szrj 2809*38fd1498Szrj if (chkp_incomplete_bounds (bnd1) || chkp_incomplete_bounds (bnd2)) 2810*38fd1498Szrj bounds = incomplete_bounds; 2811*38fd1498Szrj else if (bnd1 == bnd2) 2812*38fd1498Szrj bounds = bnd1; 2813*38fd1498Szrj else 2814*38fd1498Szrj { 2815*38fd1498Szrj gimple *stmt; 2816*38fd1498Szrj tree cond = build2 (rhs_code == MAX_EXPR ? GT_EXPR : LT_EXPR, 2817*38fd1498Szrj boolean_type_node, rhs1, rhs2); 2818*38fd1498Szrj bounds = chkp_get_tmp_reg (assign); 2819*38fd1498Szrj stmt = gimple_build_assign (bounds, COND_EXPR, cond, bnd1, bnd2); 2820*38fd1498Szrj 2821*38fd1498Szrj gsi_insert_after (&iter, stmt, GSI_SAME_STMT); 2822*38fd1498Szrj 2823*38fd1498Szrj if (!chkp_valid_bounds (bnd1) && !chkp_valid_bounds (bnd2)) 2824*38fd1498Szrj chkp_mark_invalid_bounds (bounds); 2825*38fd1498Szrj } 2826*38fd1498Szrj } 2827*38fd1498Szrj break; 2828*38fd1498Szrj 2829*38fd1498Szrj default: 2830*38fd1498Szrj bounds = chkp_get_zero_bounds (); 2831*38fd1498Szrj warning (0, "pointer bounds were lost due to unexpected expression %s", 2832*38fd1498Szrj get_tree_code_name (rhs_code)); 2833*38fd1498Szrj } 2834*38fd1498Szrj 2835*38fd1498Szrj gcc_assert (bounds); 2836*38fd1498Szrj 2837*38fd1498Szrj /* We may reuse bounds of other pointer we copy/modify. But it is not 2838*38fd1498Szrj allowed for abnormal ssa names. If we produced a pointer using 2839*38fd1498Szrj abnormal ssa name, we better make a bounds copy to avoid coalescing 2840*38fd1498Szrj issues. */ 2841*38fd1498Szrj if (base 2842*38fd1498Szrj && TREE_CODE (base) == SSA_NAME 2843*38fd1498Szrj && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (base)) 2844*38fd1498Szrj { 2845*38fd1498Szrj gimple *stmt = gimple_build_assign (chkp_get_tmp_reg (NULL), bounds); 2846*38fd1498Szrj gsi_insert_after (&iter, stmt, GSI_SAME_STMT); 2847*38fd1498Szrj bounds = gimple_assign_lhs (stmt); 2848*38fd1498Szrj } 2849*38fd1498Szrj 2850*38fd1498Szrj if (node) 2851*38fd1498Szrj bounds = chkp_maybe_copy_and_register_bounds (node, bounds); 2852*38fd1498Szrj 2853*38fd1498Szrj return bounds; 2854*38fd1498Szrj } 2855*38fd1498Szrj 2856*38fd1498Szrj /* Compute bounds for ssa name NODE defined by DEF_STMT pointed by ITER. 2857*38fd1498Szrj 2858*38fd1498Szrj There are just few statement codes allowed: NOP (for default ssa names), 2859*38fd1498Szrj ASSIGN, CALL, PHI, ASM. 2860*38fd1498Szrj 2861*38fd1498Szrj Return computed bounds. */ 2862*38fd1498Szrj static tree 2863*38fd1498Szrj chkp_get_bounds_by_definition (tree node, gimple *def_stmt, 2864*38fd1498Szrj gphi_iterator *iter) 2865*38fd1498Szrj { 2866*38fd1498Szrj tree var, bounds; 2867*38fd1498Szrj enum gimple_code code = gimple_code (def_stmt); 2868*38fd1498Szrj gphi *stmt; 2869*38fd1498Szrj 2870*38fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS)) 2871*38fd1498Szrj { 2872*38fd1498Szrj fprintf (dump_file, "Searching for bounds for node: "); 2873*38fd1498Szrj print_generic_expr (dump_file, node); 2874*38fd1498Szrj 2875*38fd1498Szrj fprintf (dump_file, " using its definition: "); 2876*38fd1498Szrj print_gimple_stmt (dump_file, def_stmt, 0, TDF_VOPS | TDF_MEMSYMS); 2877*38fd1498Szrj } 2878*38fd1498Szrj 2879*38fd1498Szrj switch (code) 2880*38fd1498Szrj { 2881*38fd1498Szrj case GIMPLE_NOP: 2882*38fd1498Szrj var = SSA_NAME_VAR (node); 2883*38fd1498Szrj switch (TREE_CODE (var)) 2884*38fd1498Szrj { 2885*38fd1498Szrj case PARM_DECL: 2886*38fd1498Szrj bounds = chkp_get_bound_for_parm (node); 2887*38fd1498Szrj break; 2888*38fd1498Szrj 2889*38fd1498Szrj case VAR_DECL: 2890*38fd1498Szrj /* For uninitialized pointers use none bounds. */ 2891*38fd1498Szrj bounds = chkp_get_none_bounds (); 2892*38fd1498Szrj bounds = chkp_maybe_copy_and_register_bounds (node, bounds); 2893*38fd1498Szrj break; 2894*38fd1498Szrj 2895*38fd1498Szrj case RESULT_DECL: 2896*38fd1498Szrj { 2897*38fd1498Szrj tree base_type; 2898*38fd1498Szrj 2899*38fd1498Szrj gcc_assert (TREE_CODE (TREE_TYPE (node)) == REFERENCE_TYPE); 2900*38fd1498Szrj 2901*38fd1498Szrj base_type = TREE_TYPE (TREE_TYPE (node)); 2902*38fd1498Szrj 2903*38fd1498Szrj gcc_assert (TYPE_SIZE (base_type) 2904*38fd1498Szrj && TREE_CODE (TYPE_SIZE (base_type)) == INTEGER_CST 2905*38fd1498Szrj && tree_to_uhwi (TYPE_SIZE (base_type)) != 0); 2906*38fd1498Szrj 2907*38fd1498Szrj bounds = chkp_make_bounds (node, TYPE_SIZE_UNIT (base_type), 2908*38fd1498Szrj NULL, false); 2909*38fd1498Szrj bounds = chkp_maybe_copy_and_register_bounds (node, bounds); 2910*38fd1498Szrj } 2911*38fd1498Szrj break; 2912*38fd1498Szrj 2913*38fd1498Szrj default: 2914*38fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS)) 2915*38fd1498Szrj { 2916*38fd1498Szrj fprintf (dump_file, "Unexpected var with no definition\n"); 2917*38fd1498Szrj print_generic_expr (dump_file, var); 2918*38fd1498Szrj } 2919*38fd1498Szrj internal_error ("chkp_get_bounds_by_definition: Unexpected var of type %s", 2920*38fd1498Szrj get_tree_code_name (TREE_CODE (var))); 2921*38fd1498Szrj } 2922*38fd1498Szrj break; 2923*38fd1498Szrj 2924*38fd1498Szrj case GIMPLE_ASSIGN: 2925*38fd1498Szrj bounds = chkp_compute_bounds_for_assignment (node, def_stmt); 2926*38fd1498Szrj break; 2927*38fd1498Szrj 2928*38fd1498Szrj case GIMPLE_CALL: 2929*38fd1498Szrj bounds = chkp_build_returned_bound (as_a <gcall *> (def_stmt)); 2930*38fd1498Szrj break; 2931*38fd1498Szrj 2932*38fd1498Szrj case GIMPLE_PHI: 2933*38fd1498Szrj if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (node)) 2934*38fd1498Szrj if (SSA_NAME_VAR (node)) 2935*38fd1498Szrj var = chkp_get_bounds_var (SSA_NAME_VAR (node)); 2936*38fd1498Szrj else 2937*38fd1498Szrj var = make_temp_ssa_name (pointer_bounds_type_node, 2938*38fd1498Szrj NULL, 2939*38fd1498Szrj CHKP_BOUND_TMP_NAME); 2940*38fd1498Szrj else 2941*38fd1498Szrj var = chkp_get_tmp_var (); 2942*38fd1498Szrj stmt = create_phi_node (var, gimple_bb (def_stmt)); 2943*38fd1498Szrj bounds = gimple_phi_result (stmt); 2944*38fd1498Szrj *iter = gsi_for_phi (stmt); 2945*38fd1498Szrj 2946*38fd1498Szrj bounds = chkp_maybe_copy_and_register_bounds (node, bounds); 2947*38fd1498Szrj 2948*38fd1498Szrj /* Created bounds do not have all phi args computed and 2949*38fd1498Szrj therefore we do not know if there is a valid source 2950*38fd1498Szrj of bounds for that node. Therefore we mark bounds 2951*38fd1498Szrj as incomplete and then recompute them when all phi 2952*38fd1498Szrj args are computed. */ 2953*38fd1498Szrj chkp_register_incomplete_bounds (bounds, node); 2954*38fd1498Szrj break; 2955*38fd1498Szrj 2956*38fd1498Szrj case GIMPLE_ASM: 2957*38fd1498Szrj bounds = chkp_get_zero_bounds (); 2958*38fd1498Szrj bounds = chkp_maybe_copy_and_register_bounds (node, bounds); 2959*38fd1498Szrj break; 2960*38fd1498Szrj 2961*38fd1498Szrj default: 2962*38fd1498Szrj internal_error ("chkp_get_bounds_by_definition: Unexpected GIMPLE code %s", 2963*38fd1498Szrj gimple_code_name[code]); 2964*38fd1498Szrj } 2965*38fd1498Szrj 2966*38fd1498Szrj return bounds; 2967*38fd1498Szrj } 2968*38fd1498Szrj 2969*38fd1498Szrj /* Return CALL_EXPR for bndmk with specified LOWER_BOUND and SIZE. */ 2970*38fd1498Szrj tree 2971*38fd1498Szrj chkp_build_make_bounds_call (tree lower_bound, tree size) 2972*38fd1498Szrj { 2973*38fd1498Szrj tree call = build1 (ADDR_EXPR, 2974*38fd1498Szrj build_pointer_type (TREE_TYPE (chkp_bndmk_fndecl)), 2975*38fd1498Szrj chkp_bndmk_fndecl); 2976*38fd1498Szrj return build_call_nary (TREE_TYPE (TREE_TYPE (chkp_bndmk_fndecl)), 2977*38fd1498Szrj call, 2, lower_bound, size); 2978*38fd1498Szrj } 2979*38fd1498Szrj 2980*38fd1498Szrj /* Create static bounds var of specfified OBJ which is 2981*38fd1498Szrj is either VAR_DECL or string constant. */ 2982*38fd1498Szrj static tree 2983*38fd1498Szrj chkp_make_static_bounds (tree obj) 2984*38fd1498Szrj { 2985*38fd1498Szrj static int string_id = 1; 2986*38fd1498Szrj static int var_id = 1; 2987*38fd1498Szrj tree *slot; 2988*38fd1498Szrj const char *var_name; 2989*38fd1498Szrj char *bnd_var_name; 2990*38fd1498Szrj tree bnd_var; 2991*38fd1498Szrj 2992*38fd1498Szrj /* First check if we already have required var. */ 2993*38fd1498Szrj if (chkp_static_var_bounds) 2994*38fd1498Szrj { 2995*38fd1498Szrj /* For vars we use assembler name as a key in 2996*38fd1498Szrj chkp_static_var_bounds map. It allows to 2997*38fd1498Szrj avoid duplicating bound vars for decls 2998*38fd1498Szrj sharing assembler name. */ 2999*38fd1498Szrj if (VAR_P (obj)) 3000*38fd1498Szrj { 3001*38fd1498Szrj tree name = DECL_ASSEMBLER_NAME (obj); 3002*38fd1498Szrj slot = chkp_static_var_bounds->get (name); 3003*38fd1498Szrj if (slot) 3004*38fd1498Szrj return *slot; 3005*38fd1498Szrj } 3006*38fd1498Szrj else 3007*38fd1498Szrj { 3008*38fd1498Szrj slot = chkp_static_var_bounds->get (obj); 3009*38fd1498Szrj if (slot) 3010*38fd1498Szrj return *slot; 3011*38fd1498Szrj } 3012*38fd1498Szrj } 3013*38fd1498Szrj 3014*38fd1498Szrj /* Build decl for bounds var. */ 3015*38fd1498Szrj if (VAR_P (obj)) 3016*38fd1498Szrj { 3017*38fd1498Szrj if (DECL_IGNORED_P (obj)) 3018*38fd1498Szrj { 3019*38fd1498Szrj bnd_var_name = (char *) xmalloc (strlen (CHKP_VAR_BOUNDS_PREFIX) + 10); 3020*38fd1498Szrj sprintf (bnd_var_name, "%s%d", CHKP_VAR_BOUNDS_PREFIX, var_id++); 3021*38fd1498Szrj } 3022*38fd1498Szrj else 3023*38fd1498Szrj { 3024*38fd1498Szrj var_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (obj)); 3025*38fd1498Szrj 3026*38fd1498Szrj /* For hidden symbols we want to skip first '*' char. */ 3027*38fd1498Szrj if (*var_name == '*') 3028*38fd1498Szrj var_name++; 3029*38fd1498Szrj 3030*38fd1498Szrj bnd_var_name = (char *) xmalloc (strlen (var_name) 3031*38fd1498Szrj + strlen (CHKP_BOUNDS_OF_SYMBOL_PREFIX) + 1); 3032*38fd1498Szrj strcpy (bnd_var_name, CHKP_BOUNDS_OF_SYMBOL_PREFIX); 3033*38fd1498Szrj strcat (bnd_var_name, var_name); 3034*38fd1498Szrj } 3035*38fd1498Szrj 3036*38fd1498Szrj bnd_var = build_decl (UNKNOWN_LOCATION, VAR_DECL, 3037*38fd1498Szrj get_identifier (bnd_var_name), 3038*38fd1498Szrj pointer_bounds_type_node); 3039*38fd1498Szrj 3040*38fd1498Szrj /* Address of the obj will be used as lower bound. */ 3041*38fd1498Szrj TREE_ADDRESSABLE (obj) = 1; 3042*38fd1498Szrj } 3043*38fd1498Szrj else 3044*38fd1498Szrj { 3045*38fd1498Szrj bnd_var_name = (char *) xmalloc (strlen (CHKP_STRING_BOUNDS_PREFIX) + 10); 3046*38fd1498Szrj sprintf (bnd_var_name, "%s%d", CHKP_STRING_BOUNDS_PREFIX, string_id++); 3047*38fd1498Szrj 3048*38fd1498Szrj bnd_var = build_decl (UNKNOWN_LOCATION, VAR_DECL, 3049*38fd1498Szrj get_identifier (bnd_var_name), 3050*38fd1498Szrj pointer_bounds_type_node); 3051*38fd1498Szrj } 3052*38fd1498Szrj 3053*38fd1498Szrj free (bnd_var_name); 3054*38fd1498Szrj 3055*38fd1498Szrj TREE_PUBLIC (bnd_var) = 0; 3056*38fd1498Szrj TREE_USED (bnd_var) = 1; 3057*38fd1498Szrj TREE_READONLY (bnd_var) = 0; 3058*38fd1498Szrj TREE_STATIC (bnd_var) = 1; 3059*38fd1498Szrj TREE_ADDRESSABLE (bnd_var) = 0; 3060*38fd1498Szrj DECL_ARTIFICIAL (bnd_var) = 1; 3061*38fd1498Szrj DECL_COMMON (bnd_var) = 1; 3062*38fd1498Szrj DECL_COMDAT (bnd_var) = 1; 3063*38fd1498Szrj DECL_READ_P (bnd_var) = 1; 3064*38fd1498Szrj DECL_INITIAL (bnd_var) = chkp_build_addr_expr (obj); 3065*38fd1498Szrj /* Force output similar to constant bounds. 3066*38fd1498Szrj See chkp_make_static_const_bounds. */ 3067*38fd1498Szrj varpool_node::get_create (bnd_var)->force_output = 1; 3068*38fd1498Szrj /* Mark symbol as requiring bounds initialization. */ 3069*38fd1498Szrj varpool_node::get_create (bnd_var)->need_bounds_init = 1; 3070*38fd1498Szrj varpool_node::finalize_decl (bnd_var); 3071*38fd1498Szrj 3072*38fd1498Szrj /* Add created var to the map to use it for other references 3073*38fd1498Szrj to obj. */ 3074*38fd1498Szrj if (!chkp_static_var_bounds) 3075*38fd1498Szrj chkp_static_var_bounds = new hash_map<tree, tree>; 3076*38fd1498Szrj 3077*38fd1498Szrj if (VAR_P (obj)) 3078*38fd1498Szrj { 3079*38fd1498Szrj tree name = DECL_ASSEMBLER_NAME (obj); 3080*38fd1498Szrj chkp_static_var_bounds->put (name, bnd_var); 3081*38fd1498Szrj } 3082*38fd1498Szrj else 3083*38fd1498Szrj chkp_static_var_bounds->put (obj, bnd_var); 3084*38fd1498Szrj 3085*38fd1498Szrj return bnd_var; 3086*38fd1498Szrj } 3087*38fd1498Szrj 3088*38fd1498Szrj /* When var has incomplete type we cannot get size to 3089*38fd1498Szrj compute its bounds. In such cases we use checker 3090*38fd1498Szrj builtin call which determines object size at runtime. */ 3091*38fd1498Szrj static tree 3092*38fd1498Szrj chkp_generate_extern_var_bounds (tree var) 3093*38fd1498Szrj { 3094*38fd1498Szrj tree bounds, size_reloc, lb, size, max_size, cond; 3095*38fd1498Szrj gimple_stmt_iterator gsi; 3096*38fd1498Szrj gimple_seq seq = NULL; 3097*38fd1498Szrj gimple *stmt; 3098*38fd1498Szrj 3099*38fd1498Szrj /* If instrumentation is not enabled for vars having 3100*38fd1498Szrj incomplete type then just return zero bounds to avoid 3101*38fd1498Szrj checks for this var. */ 3102*38fd1498Szrj if (!flag_chkp_incomplete_type) 3103*38fd1498Szrj return chkp_get_zero_bounds (); 3104*38fd1498Szrj 3105*38fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS)) 3106*38fd1498Szrj { 3107*38fd1498Szrj fprintf (dump_file, "Generating bounds for extern symbol '"); 3108*38fd1498Szrj print_generic_expr (dump_file, var); 3109*38fd1498Szrj fprintf (dump_file, "'\n"); 3110*38fd1498Szrj } 3111*38fd1498Szrj 3112*38fd1498Szrj stmt = gimple_build_call (chkp_sizeof_fndecl, 1, var); 3113*38fd1498Szrj 3114*38fd1498Szrj size_reloc = create_tmp_reg (chkp_uintptr_type, CHKP_SIZE_TMP_NAME); 3115*38fd1498Szrj gimple_call_set_lhs (stmt, size_reloc); 3116*38fd1498Szrj 3117*38fd1498Szrj gimple_seq_add_stmt (&seq, stmt); 3118*38fd1498Szrj 3119*38fd1498Szrj lb = chkp_build_addr_expr (var); 3120*38fd1498Szrj size = make_ssa_name (chkp_get_size_tmp_var ()); 3121*38fd1498Szrj 3122*38fd1498Szrj if (flag_chkp_zero_dynamic_size_as_infinite) 3123*38fd1498Szrj { 3124*38fd1498Szrj /* We should check that size relocation was resolved. 3125*38fd1498Szrj If it was not then use maximum possible size for the var. */ 3126*38fd1498Szrj max_size = build2 (MINUS_EXPR, chkp_uintptr_type, integer_zero_node, 3127*38fd1498Szrj fold_convert (chkp_uintptr_type, lb)); 3128*38fd1498Szrj max_size = chkp_force_gimple_call_op (max_size, &seq); 3129*38fd1498Szrj 3130*38fd1498Szrj cond = build2 (NE_EXPR, boolean_type_node, 3131*38fd1498Szrj size_reloc, integer_zero_node); 3132*38fd1498Szrj stmt = gimple_build_assign (size, COND_EXPR, cond, size_reloc, max_size); 3133*38fd1498Szrj gimple_seq_add_stmt (&seq, stmt); 3134*38fd1498Szrj } 3135*38fd1498Szrj else 3136*38fd1498Szrj { 3137*38fd1498Szrj stmt = gimple_build_assign (size, size_reloc); 3138*38fd1498Szrj gimple_seq_add_stmt (&seq, stmt); 3139*38fd1498Szrj } 3140*38fd1498Szrj 3141*38fd1498Szrj gsi = gsi_start_bb (chkp_get_entry_block ()); 3142*38fd1498Szrj gsi_insert_seq_after (&gsi, seq, GSI_CONTINUE_LINKING); 3143*38fd1498Szrj 3144*38fd1498Szrj bounds = chkp_make_bounds (lb, size, &gsi, true); 3145*38fd1498Szrj 3146*38fd1498Szrj return bounds; 3147*38fd1498Szrj } 3148*38fd1498Szrj 3149*38fd1498Szrj /* Return 1 if TYPE has fields with zero size or fields 3150*38fd1498Szrj marked with chkp_variable_size attribute. */ 3151*38fd1498Szrj bool 3152*38fd1498Szrj chkp_variable_size_type (tree type) 3153*38fd1498Szrj { 3154*38fd1498Szrj bool res = false; 3155*38fd1498Szrj tree field; 3156*38fd1498Szrj 3157*38fd1498Szrj if (RECORD_OR_UNION_TYPE_P (type)) 3158*38fd1498Szrj for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) 3159*38fd1498Szrj { 3160*38fd1498Szrj if (TREE_CODE (field) == FIELD_DECL) 3161*38fd1498Szrj res = res 3162*38fd1498Szrj || lookup_attribute ("bnd_variable_size", DECL_ATTRIBUTES (field)) 3163*38fd1498Szrj || chkp_variable_size_type (TREE_TYPE (field)); 3164*38fd1498Szrj } 3165*38fd1498Szrj else 3166*38fd1498Szrj res = !TYPE_SIZE (type) 3167*38fd1498Szrj || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST 3168*38fd1498Szrj || tree_to_uhwi (TYPE_SIZE (type)) == 0; 3169*38fd1498Szrj 3170*38fd1498Szrj return res; 3171*38fd1498Szrj } 3172*38fd1498Szrj 3173*38fd1498Szrj /* Compute and return bounds for address of DECL which is 3174*38fd1498Szrj one of VAR_DECL, PARM_DECL, RESULT_DECL. */ 3175*38fd1498Szrj static tree 3176*38fd1498Szrj chkp_get_bounds_for_decl_addr (tree decl) 3177*38fd1498Szrj { 3178*38fd1498Szrj tree bounds; 3179*38fd1498Szrj 3180*38fd1498Szrj gcc_assert (VAR_P (decl) 3181*38fd1498Szrj || TREE_CODE (decl) == PARM_DECL 3182*38fd1498Szrj || TREE_CODE (decl) == RESULT_DECL); 3183*38fd1498Szrj 3184*38fd1498Szrj bounds = chkp_get_registered_addr_bounds (decl); 3185*38fd1498Szrj 3186*38fd1498Szrj if (bounds) 3187*38fd1498Szrj return bounds; 3188*38fd1498Szrj 3189*38fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS)) 3190*38fd1498Szrj { 3191*38fd1498Szrj fprintf (dump_file, "Building bounds for address of decl "); 3192*38fd1498Szrj print_generic_expr (dump_file, decl); 3193*38fd1498Szrj fprintf (dump_file, "\n"); 3194*38fd1498Szrj } 3195*38fd1498Szrj 3196*38fd1498Szrj /* Use zero bounds if size is unknown and checks for 3197*38fd1498Szrj unknown sizes are restricted. */ 3198*38fd1498Szrj if ((!DECL_SIZE (decl) 3199*38fd1498Szrj || (chkp_variable_size_type (TREE_TYPE (decl)) 3200*38fd1498Szrj && (TREE_STATIC (decl) 3201*38fd1498Szrj || DECL_EXTERNAL (decl) 3202*38fd1498Szrj || TREE_PUBLIC (decl)))) 3203*38fd1498Szrj && !flag_chkp_incomplete_type) 3204*38fd1498Szrj return chkp_get_zero_bounds (); 3205*38fd1498Szrj 3206*38fd1498Szrj if (VOID_TYPE_P (TREE_TYPE (decl))) 3207*38fd1498Szrj return chkp_get_zero_bounds (); 3208*38fd1498Szrj 3209*38fd1498Szrj if (flag_chkp_use_static_bounds 3210*38fd1498Szrj && VAR_P (decl) 3211*38fd1498Szrj && (TREE_STATIC (decl) 3212*38fd1498Szrj || DECL_EXTERNAL (decl) 3213*38fd1498Szrj || TREE_PUBLIC (decl)) 3214*38fd1498Szrj && !DECL_THREAD_LOCAL_P (decl)) 3215*38fd1498Szrj { 3216*38fd1498Szrj tree bnd_var = chkp_make_static_bounds (decl); 3217*38fd1498Szrj gimple_stmt_iterator gsi = gsi_start_bb (chkp_get_entry_block ()); 3218*38fd1498Szrj gimple *stmt; 3219*38fd1498Szrj 3220*38fd1498Szrj bounds = chkp_get_tmp_reg (NULL); 3221*38fd1498Szrj stmt = gimple_build_assign (bounds, bnd_var); 3222*38fd1498Szrj gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); 3223*38fd1498Szrj } 3224*38fd1498Szrj else if (!DECL_SIZE (decl) 3225*38fd1498Szrj || (chkp_variable_size_type (TREE_TYPE (decl)) 3226*38fd1498Szrj && (TREE_STATIC (decl) 3227*38fd1498Szrj || DECL_EXTERNAL (decl) 3228*38fd1498Szrj || TREE_PUBLIC (decl)))) 3229*38fd1498Szrj { 3230*38fd1498Szrj gcc_assert (VAR_P (decl)); 3231*38fd1498Szrj bounds = chkp_generate_extern_var_bounds (decl); 3232*38fd1498Szrj } 3233*38fd1498Szrj else 3234*38fd1498Szrj { 3235*38fd1498Szrj tree lb = chkp_build_addr_expr (decl); 3236*38fd1498Szrj bounds = chkp_make_bounds (lb, DECL_SIZE_UNIT (decl), NULL, false); 3237*38fd1498Szrj } 3238*38fd1498Szrj 3239*38fd1498Szrj return bounds; 3240*38fd1498Szrj } 3241*38fd1498Szrj 3242*38fd1498Szrj /* Compute and return bounds for constant string. */ 3243*38fd1498Szrj static tree 3244*38fd1498Szrj chkp_get_bounds_for_string_cst (tree cst) 3245*38fd1498Szrj { 3246*38fd1498Szrj tree bounds; 3247*38fd1498Szrj tree lb; 3248*38fd1498Szrj tree size; 3249*38fd1498Szrj 3250*38fd1498Szrj gcc_assert (TREE_CODE (cst) == STRING_CST); 3251*38fd1498Szrj 3252*38fd1498Szrj bounds = chkp_get_registered_bounds (cst); 3253*38fd1498Szrj 3254*38fd1498Szrj if (bounds) 3255*38fd1498Szrj return bounds; 3256*38fd1498Szrj 3257*38fd1498Szrj if ((flag_chkp_use_static_bounds && flag_chkp_use_static_const_bounds) 3258*38fd1498Szrj || flag_chkp_use_static_const_bounds > 0) 3259*38fd1498Szrj { 3260*38fd1498Szrj tree bnd_var = chkp_make_static_bounds (cst); 3261*38fd1498Szrj gimple_stmt_iterator gsi = gsi_start_bb (chkp_get_entry_block ()); 3262*38fd1498Szrj gimple *stmt; 3263*38fd1498Szrj 3264*38fd1498Szrj bounds = chkp_get_tmp_reg (NULL); 3265*38fd1498Szrj stmt = gimple_build_assign (bounds, bnd_var); 3266*38fd1498Szrj gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); 3267*38fd1498Szrj } 3268*38fd1498Szrj else 3269*38fd1498Szrj { 3270*38fd1498Szrj lb = chkp_build_addr_expr (cst); 3271*38fd1498Szrj size = build_int_cst (chkp_uintptr_type, TREE_STRING_LENGTH (cst)); 3272*38fd1498Szrj bounds = chkp_make_bounds (lb, size, NULL, false); 3273*38fd1498Szrj } 3274*38fd1498Szrj 3275*38fd1498Szrj bounds = chkp_maybe_copy_and_register_bounds (cst, bounds); 3276*38fd1498Szrj 3277*38fd1498Szrj return bounds; 3278*38fd1498Szrj } 3279*38fd1498Szrj 3280*38fd1498Szrj /* Generate code to instersect bounds BOUNDS1 and BOUNDS2 and 3281*38fd1498Szrj return the result. if ITER is not NULL then Code is inserted 3282*38fd1498Szrj before position pointed by ITER. Otherwise code is added to 3283*38fd1498Szrj entry block. */ 3284*38fd1498Szrj static tree 3285*38fd1498Szrj chkp_intersect_bounds (tree bounds1, tree bounds2, gimple_stmt_iterator *iter) 3286*38fd1498Szrj { 3287*38fd1498Szrj if (!bounds1 || bounds1 == chkp_get_zero_bounds ()) 3288*38fd1498Szrj return bounds2 ? bounds2 : bounds1; 3289*38fd1498Szrj else if (!bounds2 || bounds2 == chkp_get_zero_bounds ()) 3290*38fd1498Szrj return bounds1; 3291*38fd1498Szrj else 3292*38fd1498Szrj { 3293*38fd1498Szrj gimple_seq seq; 3294*38fd1498Szrj gimple *stmt; 3295*38fd1498Szrj tree bounds; 3296*38fd1498Szrj 3297*38fd1498Szrj seq = NULL; 3298*38fd1498Szrj 3299*38fd1498Szrj stmt = gimple_build_call (chkp_intersect_fndecl, 2, bounds1, bounds2); 3300*38fd1498Szrj chkp_mark_stmt (stmt); 3301*38fd1498Szrj 3302*38fd1498Szrj bounds = chkp_get_tmp_reg (stmt); 3303*38fd1498Szrj gimple_call_set_lhs (stmt, bounds); 3304*38fd1498Szrj 3305*38fd1498Szrj gimple_seq_add_stmt (&seq, stmt); 3306*38fd1498Szrj 3307*38fd1498Szrj /* We are probably doing narrowing for constant expression. 3308*38fd1498Szrj In such case iter may be undefined. */ 3309*38fd1498Szrj if (!iter) 3310*38fd1498Szrj { 3311*38fd1498Szrj gimple_stmt_iterator gsi = gsi_last_bb (chkp_get_entry_block ()); 3312*38fd1498Szrj iter = &gsi; 3313*38fd1498Szrj gsi_insert_seq_after (iter, seq, GSI_SAME_STMT); 3314*38fd1498Szrj } 3315*38fd1498Szrj else 3316*38fd1498Szrj gsi_insert_seq_before (iter, seq, GSI_SAME_STMT); 3317*38fd1498Szrj 3318*38fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS)) 3319*38fd1498Szrj { 3320*38fd1498Szrj fprintf (dump_file, "Bounds intersection: "); 3321*38fd1498Szrj print_gimple_stmt (dump_file, stmt, 0, TDF_VOPS|TDF_MEMSYMS); 3322*38fd1498Szrj fprintf (dump_file, " inserted before statement: "); 3323*38fd1498Szrj print_gimple_stmt (dump_file, gsi_stmt (*iter), 0, 3324*38fd1498Szrj TDF_VOPS|TDF_MEMSYMS); 3325*38fd1498Szrj } 3326*38fd1498Szrj 3327*38fd1498Szrj return bounds; 3328*38fd1498Szrj } 3329*38fd1498Szrj } 3330*38fd1498Szrj 3331*38fd1498Szrj /* Return 1 if we are allowed to narrow bounds for addressed FIELD 3332*38fd1498Szrj and 0 othersize. REF is reference to the field. */ 3333*38fd1498Szrj 3334*38fd1498Szrj static bool 3335*38fd1498Szrj chkp_may_narrow_to_field (tree ref, tree field) 3336*38fd1498Szrj { 3337*38fd1498Szrj return DECL_SIZE (field) && TREE_CODE (DECL_SIZE (field)) == INTEGER_CST 3338*38fd1498Szrj && tree_to_uhwi (DECL_SIZE (field)) != 0 3339*38fd1498Szrj && !(flag_chkp_flexible_struct_trailing_arrays 3340*38fd1498Szrj && array_at_struct_end_p (ref)) 3341*38fd1498Szrj && (!DECL_FIELD_OFFSET (field) 3342*38fd1498Szrj || TREE_CODE (DECL_FIELD_OFFSET (field)) == INTEGER_CST) 3343*38fd1498Szrj && (!DECL_FIELD_BIT_OFFSET (field) 3344*38fd1498Szrj || TREE_CODE (DECL_FIELD_BIT_OFFSET (field)) == INTEGER_CST) 3345*38fd1498Szrj && !lookup_attribute ("bnd_variable_size", DECL_ATTRIBUTES (field)) 3346*38fd1498Szrj && !chkp_variable_size_type (TREE_TYPE (field)); 3347*38fd1498Szrj } 3348*38fd1498Szrj 3349*38fd1498Szrj /* Return 1 if bounds for FIELD should be narrowed to 3350*38fd1498Szrj field's own size. REF is reference to the field. */ 3351*38fd1498Szrj 3352*38fd1498Szrj static bool 3353*38fd1498Szrj chkp_narrow_bounds_for_field (tree ref, tree field) 3354*38fd1498Szrj { 3355*38fd1498Szrj HOST_WIDE_INT offs; 3356*38fd1498Szrj HOST_WIDE_INT bit_offs; 3357*38fd1498Szrj 3358*38fd1498Szrj if (!chkp_may_narrow_to_field (ref, field)) 3359*38fd1498Szrj return false; 3360*38fd1498Szrj 3361*38fd1498Szrj /* Access to compiler generated fields should not cause 3362*38fd1498Szrj bounds narrowing. */ 3363*38fd1498Szrj if (DECL_ARTIFICIAL (field)) 3364*38fd1498Szrj return false; 3365*38fd1498Szrj 3366*38fd1498Szrj offs = tree_to_uhwi (DECL_FIELD_OFFSET (field)); 3367*38fd1498Szrj bit_offs = tree_to_uhwi (DECL_FIELD_BIT_OFFSET (field)); 3368*38fd1498Szrj 3369*38fd1498Szrj return (flag_chkp_narrow_bounds 3370*38fd1498Szrj && (flag_chkp_first_field_has_own_bounds 3371*38fd1498Szrj || offs 3372*38fd1498Szrj || bit_offs)); 3373*38fd1498Szrj } 3374*38fd1498Szrj 3375*38fd1498Szrj /* Perform narrowing for BOUNDS of an INNER reference. Shift boundary 3376*38fd1498Szrj by OFFSET bytes and limit to SIZE bytes. Newly created statements are 3377*38fd1498Szrj added to ITER. */ 3378*38fd1498Szrj 3379*38fd1498Szrj static tree 3380*38fd1498Szrj chkp_narrow_size_and_offset (tree bounds, tree inner, tree offset, 3381*38fd1498Szrj tree size, gimple_stmt_iterator *iter) 3382*38fd1498Szrj { 3383*38fd1498Szrj tree addr = chkp_build_addr_expr (unshare_expr (inner)); 3384*38fd1498Szrj tree t = TREE_TYPE (addr); 3385*38fd1498Szrj 3386*38fd1498Szrj gimple *stmt = gimple_build_assign (NULL_TREE, addr); 3387*38fd1498Szrj addr = make_temp_ssa_name (t, stmt, CHKP_BOUND_TMP_NAME); 3388*38fd1498Szrj gimple_assign_set_lhs (stmt, addr); 3389*38fd1498Szrj gsi_insert_seq_before (iter, stmt, GSI_SAME_STMT); 3390*38fd1498Szrj 3391*38fd1498Szrj stmt = gimple_build_assign (NULL_TREE, POINTER_PLUS_EXPR, addr, offset); 3392*38fd1498Szrj tree shifted = make_temp_ssa_name (t, stmt, CHKP_BOUND_TMP_NAME); 3393*38fd1498Szrj gimple_assign_set_lhs (stmt, shifted); 3394*38fd1498Szrj gsi_insert_seq_before (iter, stmt, GSI_SAME_STMT); 3395*38fd1498Szrj 3396*38fd1498Szrj tree bounds2 = chkp_make_bounds (shifted, size, iter, false); 3397*38fd1498Szrj 3398*38fd1498Szrj return chkp_intersect_bounds (bounds, bounds2, iter); 3399*38fd1498Szrj } 3400*38fd1498Szrj 3401*38fd1498Szrj /* Perform narrowing for BOUNDS using bounds computed for field 3402*38fd1498Szrj access COMPONENT. ITER meaning is the same as for 3403*38fd1498Szrj chkp_intersect_bounds. */ 3404*38fd1498Szrj 3405*38fd1498Szrj static tree 3406*38fd1498Szrj chkp_narrow_bounds_to_field (tree bounds, tree component, 3407*38fd1498Szrj gimple_stmt_iterator *iter) 3408*38fd1498Szrj { 3409*38fd1498Szrj tree field = TREE_OPERAND (component, 1); 3410*38fd1498Szrj tree size = DECL_SIZE_UNIT (field); 3411*38fd1498Szrj tree field_ptr = chkp_build_addr_expr (component); 3412*38fd1498Szrj tree field_bounds; 3413*38fd1498Szrj 3414*38fd1498Szrj field_bounds = chkp_make_bounds (field_ptr, size, iter, false); 3415*38fd1498Szrj 3416*38fd1498Szrj return chkp_intersect_bounds (field_bounds, bounds, iter); 3417*38fd1498Szrj } 3418*38fd1498Szrj 3419*38fd1498Szrj /* Parse field or array access NODE. 3420*38fd1498Szrj 3421*38fd1498Szrj PTR ouput parameter holds a pointer to the outermost 3422*38fd1498Szrj object. 3423*38fd1498Szrj 3424*38fd1498Szrj BITFIELD output parameter is set to 1 if bitfield is 3425*38fd1498Szrj accessed and to 0 otherwise. If it is 1 then ELT holds 3426*38fd1498Szrj outer component for accessed bit field. 3427*38fd1498Szrj 3428*38fd1498Szrj SAFE outer parameter is set to 1 if access is safe and 3429*38fd1498Szrj checks are not required. 3430*38fd1498Szrj 3431*38fd1498Szrj BOUNDS outer parameter holds bounds to be used to check 3432*38fd1498Szrj access (may be NULL). 3433*38fd1498Szrj 3434*38fd1498Szrj If INNERMOST_BOUNDS is 1 then try to narrow bounds to the 3435*38fd1498Szrj innermost accessed component. */ 3436*38fd1498Szrj static void 3437*38fd1498Szrj chkp_parse_array_and_component_ref (tree node, tree *ptr, 3438*38fd1498Szrj tree *elt, bool *safe, 3439*38fd1498Szrj bool *bitfield, 3440*38fd1498Szrj tree *bounds, 3441*38fd1498Szrj gimple_stmt_iterator *iter, 3442*38fd1498Szrj bool innermost_bounds) 3443*38fd1498Szrj { 3444*38fd1498Szrj tree comp_to_narrow = NULL_TREE; 3445*38fd1498Szrj tree last_comp = NULL_TREE; 3446*38fd1498Szrj bool array_ref_found = false; 3447*38fd1498Szrj tree *nodes; 3448*38fd1498Szrj tree var; 3449*38fd1498Szrj int len; 3450*38fd1498Szrj int i; 3451*38fd1498Szrj 3452*38fd1498Szrj /* Compute tree height for expression. */ 3453*38fd1498Szrj var = node; 3454*38fd1498Szrj len = 1; 3455*38fd1498Szrj while (TREE_CODE (var) == COMPONENT_REF 3456*38fd1498Szrj || TREE_CODE (var) == ARRAY_REF 3457*38fd1498Szrj || TREE_CODE (var) == VIEW_CONVERT_EXPR 3458*38fd1498Szrj || TREE_CODE (var) == BIT_FIELD_REF) 3459*38fd1498Szrj { 3460*38fd1498Szrj var = TREE_OPERAND (var, 0); 3461*38fd1498Szrj len++; 3462*38fd1498Szrj } 3463*38fd1498Szrj 3464*38fd1498Szrj gcc_assert (len > 1); 3465*38fd1498Szrj 3466*38fd1498Szrj /* It is more convenient for us to scan left-to-right, 3467*38fd1498Szrj so walk tree again and put all node to nodes vector 3468*38fd1498Szrj in reversed order. */ 3469*38fd1498Szrj nodes = XALLOCAVEC (tree, len); 3470*38fd1498Szrj nodes[len - 1] = node; 3471*38fd1498Szrj for (i = len - 2; i >= 0; i--) 3472*38fd1498Szrj nodes[i] = TREE_OPERAND (nodes[i + 1], 0); 3473*38fd1498Szrj 3474*38fd1498Szrj if (bounds) 3475*38fd1498Szrj *bounds = NULL; 3476*38fd1498Szrj *safe = true; 3477*38fd1498Szrj *bitfield = ((TREE_CODE (node) == COMPONENT_REF 3478*38fd1498Szrj && DECL_BIT_FIELD_TYPE (TREE_OPERAND (node, 1))) 3479*38fd1498Szrj || TREE_CODE (node) == BIT_FIELD_REF); 3480*38fd1498Szrj /* To get bitfield address we will need outer element. */ 3481*38fd1498Szrj if (*bitfield) 3482*38fd1498Szrj *elt = nodes[len - 2]; 3483*38fd1498Szrj else 3484*38fd1498Szrj *elt = NULL_TREE; 3485*38fd1498Szrj 3486*38fd1498Szrj /* If we have indirection in expression then compute 3487*38fd1498Szrj outermost structure bounds. Computed bounds may be 3488*38fd1498Szrj narrowed later. */ 3489*38fd1498Szrj if (TREE_CODE (nodes[0]) == MEM_REF || INDIRECT_REF_P (nodes[0])) 3490*38fd1498Szrj { 3491*38fd1498Szrj *safe = false; 3492*38fd1498Szrj *ptr = TREE_OPERAND (nodes[0], 0); 3493*38fd1498Szrj if (bounds) 3494*38fd1498Szrj *bounds = chkp_find_bounds (*ptr, iter); 3495*38fd1498Szrj } 3496*38fd1498Szrj else 3497*38fd1498Szrj { 3498*38fd1498Szrj gcc_assert (VAR_P (var) 3499*38fd1498Szrj || TREE_CODE (var) == PARM_DECL 3500*38fd1498Szrj || TREE_CODE (var) == RESULT_DECL 3501*38fd1498Szrj || TREE_CODE (var) == STRING_CST 3502*38fd1498Szrj || TREE_CODE (var) == SSA_NAME); 3503*38fd1498Szrj 3504*38fd1498Szrj *ptr = chkp_build_addr_expr (var); 3505*38fd1498Szrj 3506*38fd1498Szrj /* For hard register cases chkp_build_addr_expr returns INTEGER_CST 3507*38fd1498Szrj and later on chkp_find_bounds will fail to find proper bounds. 3508*38fd1498Szrj In order to avoid that, we find/create bounds right aways using 3509*38fd1498Szrj the var itself. */ 3510*38fd1498Szrj if (VAR_P (var) && DECL_HARD_REGISTER (var)) 3511*38fd1498Szrj *bounds = chkp_make_addressed_object_bounds (var, iter); 3512*38fd1498Szrj } 3513*38fd1498Szrj 3514*38fd1498Szrj /* In this loop we are trying to find a field access 3515*38fd1498Szrj requiring narrowing. There are two simple rules 3516*38fd1498Szrj for search: 3517*38fd1498Szrj 1. Leftmost array_ref is chosen if any. 3518*38fd1498Szrj 2. Rightmost suitable component_ref is chosen if innermost 3519*38fd1498Szrj bounds are required and no array_ref exists. */ 3520*38fd1498Szrj for (i = 1; i < len; i++) 3521*38fd1498Szrj { 3522*38fd1498Szrj var = nodes[i]; 3523*38fd1498Szrj 3524*38fd1498Szrj if (TREE_CODE (var) == ARRAY_REF) 3525*38fd1498Szrj { 3526*38fd1498Szrj *safe = false; 3527*38fd1498Szrj array_ref_found = true; 3528*38fd1498Szrj if (flag_chkp_narrow_bounds 3529*38fd1498Szrj && !flag_chkp_narrow_to_innermost_arrray 3530*38fd1498Szrj && (!last_comp 3531*38fd1498Szrj || chkp_may_narrow_to_field (var, 3532*38fd1498Szrj TREE_OPERAND (last_comp, 1)))) 3533*38fd1498Szrj { 3534*38fd1498Szrj comp_to_narrow = last_comp; 3535*38fd1498Szrj break; 3536*38fd1498Szrj } 3537*38fd1498Szrj } 3538*38fd1498Szrj else if (TREE_CODE (var) == COMPONENT_REF) 3539*38fd1498Szrj { 3540*38fd1498Szrj tree field = TREE_OPERAND (var, 1); 3541*38fd1498Szrj 3542*38fd1498Szrj if (innermost_bounds 3543*38fd1498Szrj && !array_ref_found 3544*38fd1498Szrj && chkp_narrow_bounds_for_field (var, field)) 3545*38fd1498Szrj comp_to_narrow = var; 3546*38fd1498Szrj last_comp = var; 3547*38fd1498Szrj 3548*38fd1498Szrj if (flag_chkp_narrow_bounds 3549*38fd1498Szrj && flag_chkp_narrow_to_innermost_arrray 3550*38fd1498Szrj && TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE) 3551*38fd1498Szrj { 3552*38fd1498Szrj if (bounds) 3553*38fd1498Szrj *bounds = chkp_narrow_bounds_to_field (*bounds, var, iter); 3554*38fd1498Szrj comp_to_narrow = NULL; 3555*38fd1498Szrj } 3556*38fd1498Szrj } 3557*38fd1498Szrj else if (TREE_CODE (var) == BIT_FIELD_REF) 3558*38fd1498Szrj { 3559*38fd1498Szrj if (flag_chkp_narrow_bounds && bounds) 3560*38fd1498Szrj { 3561*38fd1498Szrj tree offset, size; 3562*38fd1498Szrj chkp_parse_bit_field_ref (var, UNKNOWN_LOCATION, &offset, &size); 3563*38fd1498Szrj *bounds 3564*38fd1498Szrj = chkp_narrow_size_and_offset (*bounds, TREE_OPERAND (var, 0), 3565*38fd1498Szrj offset, size, iter); 3566*38fd1498Szrj } 3567*38fd1498Szrj } 3568*38fd1498Szrj else if (TREE_CODE (var) == VIEW_CONVERT_EXPR) 3569*38fd1498Szrj /* Nothing to do for it. */ 3570*38fd1498Szrj ; 3571*38fd1498Szrj else 3572*38fd1498Szrj gcc_unreachable (); 3573*38fd1498Szrj } 3574*38fd1498Szrj 3575*38fd1498Szrj if (comp_to_narrow && DECL_SIZE (TREE_OPERAND (comp_to_narrow, 1)) && bounds) 3576*38fd1498Szrj *bounds = chkp_narrow_bounds_to_field (*bounds, comp_to_narrow, iter); 3577*38fd1498Szrj 3578*38fd1498Szrj if (innermost_bounds && bounds && !*bounds) 3579*38fd1498Szrj *bounds = chkp_find_bounds (*ptr, iter); 3580*38fd1498Szrj } 3581*38fd1498Szrj 3582*38fd1498Szrj /* Parse BIT_FIELD_REF to a NODE for a given location LOC. Return OFFSET 3583*38fd1498Szrj and SIZE in bytes. */ 3584*38fd1498Szrj 3585*38fd1498Szrj static 3586*38fd1498Szrj void chkp_parse_bit_field_ref (tree node, location_t loc, tree *offset, 3587*38fd1498Szrj tree *size) 3588*38fd1498Szrj { 3589*38fd1498Szrj tree bpu = fold_convert (size_type_node, bitsize_int (BITS_PER_UNIT)); 3590*38fd1498Szrj tree offs = fold_convert (size_type_node, TREE_OPERAND (node, 2)); 3591*38fd1498Szrj tree rem = size_binop_loc (loc, TRUNC_MOD_EXPR, offs, bpu); 3592*38fd1498Szrj offs = size_binop_loc (loc, TRUNC_DIV_EXPR, offs, bpu); 3593*38fd1498Szrj 3594*38fd1498Szrj tree s = fold_convert (size_type_node, TREE_OPERAND (node, 1)); 3595*38fd1498Szrj s = size_binop_loc (loc, PLUS_EXPR, s, rem); 3596*38fd1498Szrj s = size_binop_loc (loc, CEIL_DIV_EXPR, s, bpu); 3597*38fd1498Szrj s = fold_convert (size_type_node, s); 3598*38fd1498Szrj 3599*38fd1498Szrj *offset = offs; 3600*38fd1498Szrj *size = s; 3601*38fd1498Szrj } 3602*38fd1498Szrj 3603*38fd1498Szrj /* Compute and return bounds for address of OBJ. */ 3604*38fd1498Szrj static tree 3605*38fd1498Szrj chkp_make_addressed_object_bounds (tree obj, gimple_stmt_iterator *iter) 3606*38fd1498Szrj { 3607*38fd1498Szrj tree bounds = chkp_get_registered_addr_bounds (obj); 3608*38fd1498Szrj 3609*38fd1498Szrj if (bounds) 3610*38fd1498Szrj return bounds; 3611*38fd1498Szrj 3612*38fd1498Szrj switch (TREE_CODE (obj)) 3613*38fd1498Szrj { 3614*38fd1498Szrj case VAR_DECL: 3615*38fd1498Szrj case PARM_DECL: 3616*38fd1498Szrj case RESULT_DECL: 3617*38fd1498Szrj bounds = chkp_get_bounds_for_decl_addr (obj); 3618*38fd1498Szrj break; 3619*38fd1498Szrj 3620*38fd1498Szrj case STRING_CST: 3621*38fd1498Szrj bounds = chkp_get_bounds_for_string_cst (obj); 3622*38fd1498Szrj break; 3623*38fd1498Szrj 3624*38fd1498Szrj case ARRAY_REF: 3625*38fd1498Szrj case COMPONENT_REF: 3626*38fd1498Szrj case BIT_FIELD_REF: 3627*38fd1498Szrj { 3628*38fd1498Szrj tree elt; 3629*38fd1498Szrj tree ptr; 3630*38fd1498Szrj bool safe; 3631*38fd1498Szrj bool bitfield; 3632*38fd1498Szrj 3633*38fd1498Szrj chkp_parse_array_and_component_ref (obj, &ptr, &elt, &safe, 3634*38fd1498Szrj &bitfield, &bounds, iter, true); 3635*38fd1498Szrj 3636*38fd1498Szrj gcc_assert (bounds); 3637*38fd1498Szrj } 3638*38fd1498Szrj break; 3639*38fd1498Szrj 3640*38fd1498Szrj case FUNCTION_DECL: 3641*38fd1498Szrj case LABEL_DECL: 3642*38fd1498Szrj bounds = chkp_get_zero_bounds (); 3643*38fd1498Szrj break; 3644*38fd1498Szrj 3645*38fd1498Szrj case MEM_REF: 3646*38fd1498Szrj bounds = chkp_find_bounds (TREE_OPERAND (obj, 0), iter); 3647*38fd1498Szrj break; 3648*38fd1498Szrj 3649*38fd1498Szrj case REALPART_EXPR: 3650*38fd1498Szrj case IMAGPART_EXPR: 3651*38fd1498Szrj bounds = chkp_make_addressed_object_bounds (TREE_OPERAND (obj, 0), iter); 3652*38fd1498Szrj break; 3653*38fd1498Szrj 3654*38fd1498Szrj default: 3655*38fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS)) 3656*38fd1498Szrj { 3657*38fd1498Szrj fprintf (dump_file, "chkp_make_addressed_object_bounds: " 3658*38fd1498Szrj "unexpected object of type %s\n", 3659*38fd1498Szrj get_tree_code_name (TREE_CODE (obj))); 3660*38fd1498Szrj print_node (dump_file, "", obj, 0); 3661*38fd1498Szrj } 3662*38fd1498Szrj internal_error ("chkp_make_addressed_object_bounds: " 3663*38fd1498Szrj "Unexpected tree code %s", 3664*38fd1498Szrj get_tree_code_name (TREE_CODE (obj))); 3665*38fd1498Szrj } 3666*38fd1498Szrj 3667*38fd1498Szrj chkp_register_addr_bounds (obj, bounds); 3668*38fd1498Szrj 3669*38fd1498Szrj return bounds; 3670*38fd1498Szrj } 3671*38fd1498Szrj 3672*38fd1498Szrj /* Compute bounds for pointer PTR loaded from PTR_SRC. Generate statements 3673*38fd1498Szrj to compute bounds if required. Computed bounds should be available at 3674*38fd1498Szrj position pointed by ITER. 3675*38fd1498Szrj 3676*38fd1498Szrj If PTR_SRC is NULL_TREE then pointer definition is identified. 3677*38fd1498Szrj 3678*38fd1498Szrj If PTR_SRC is not NULL_TREE then ITER points to statements which loads 3679*38fd1498Szrj PTR. If PTR is a any memory reference then ITER points to a statement 3680*38fd1498Szrj after which bndldx will be inserterd. In both cases ITER will be updated 3681*38fd1498Szrj to point to the inserted bndldx statement. */ 3682*38fd1498Szrj 3683*38fd1498Szrj static tree 3684*38fd1498Szrj chkp_find_bounds_1 (tree ptr, tree ptr_src, gimple_stmt_iterator *iter) 3685*38fd1498Szrj { 3686*38fd1498Szrj tree addr = NULL_TREE; 3687*38fd1498Szrj tree bounds = NULL_TREE; 3688*38fd1498Szrj 3689*38fd1498Szrj if (!ptr_src) 3690*38fd1498Szrj ptr_src = ptr; 3691*38fd1498Szrj 3692*38fd1498Szrj bounds = chkp_get_registered_bounds (ptr_src); 3693*38fd1498Szrj 3694*38fd1498Szrj if (bounds) 3695*38fd1498Szrj return bounds; 3696*38fd1498Szrj 3697*38fd1498Szrj switch (TREE_CODE (ptr_src)) 3698*38fd1498Szrj { 3699*38fd1498Szrj case MEM_REF: 3700*38fd1498Szrj case VAR_DECL: 3701*38fd1498Szrj if (BOUNDED_P (ptr_src)) 3702*38fd1498Szrj if (VAR_P (ptr) && DECL_REGISTER (ptr)) 3703*38fd1498Szrj bounds = chkp_get_zero_bounds (); 3704*38fd1498Szrj else 3705*38fd1498Szrj { 3706*38fd1498Szrj addr = chkp_build_addr_expr (ptr_src); 3707*38fd1498Szrj bounds = chkp_build_bndldx (addr, ptr, iter); 3708*38fd1498Szrj } 3709*38fd1498Szrj else 3710*38fd1498Szrj bounds = chkp_get_nonpointer_load_bounds (); 3711*38fd1498Szrj break; 3712*38fd1498Szrj 3713*38fd1498Szrj case ARRAY_REF: 3714*38fd1498Szrj case COMPONENT_REF: 3715*38fd1498Szrj addr = get_base_address (ptr_src); 3716*38fd1498Szrj if (VAR_P (addr) && DECL_HARD_REGISTER (addr)) 3717*38fd1498Szrj { 3718*38fd1498Szrj bounds = chkp_get_zero_bounds (); 3719*38fd1498Szrj break; 3720*38fd1498Szrj } 3721*38fd1498Szrj if (DECL_P (addr) 3722*38fd1498Szrj || TREE_CODE (addr) == MEM_REF 3723*38fd1498Szrj || TREE_CODE (addr) == TARGET_MEM_REF) 3724*38fd1498Szrj { 3725*38fd1498Szrj if (BOUNDED_P (ptr_src)) 3726*38fd1498Szrj if (VAR_P (ptr) && DECL_REGISTER (ptr)) 3727*38fd1498Szrj bounds = chkp_get_zero_bounds (); 3728*38fd1498Szrj else 3729*38fd1498Szrj { 3730*38fd1498Szrj addr = chkp_build_addr_expr (ptr_src); 3731*38fd1498Szrj bounds = chkp_build_bndldx (addr, ptr, iter); 3732*38fd1498Szrj } 3733*38fd1498Szrj else 3734*38fd1498Szrj bounds = chkp_get_nonpointer_load_bounds (); 3735*38fd1498Szrj } 3736*38fd1498Szrj else 3737*38fd1498Szrj { 3738*38fd1498Szrj gcc_assert (TREE_CODE (addr) == SSA_NAME); 3739*38fd1498Szrj bounds = chkp_find_bounds (addr, iter); 3740*38fd1498Szrj } 3741*38fd1498Szrj break; 3742*38fd1498Szrj 3743*38fd1498Szrj case PARM_DECL: 3744*38fd1498Szrj /* Handled above but failed. */ 3745*38fd1498Szrj bounds = chkp_get_invalid_op_bounds (); 3746*38fd1498Szrj break; 3747*38fd1498Szrj 3748*38fd1498Szrj case TARGET_MEM_REF: 3749*38fd1498Szrj addr = chkp_build_addr_expr (ptr_src); 3750*38fd1498Szrj bounds = chkp_build_bndldx (addr, ptr, iter); 3751*38fd1498Szrj break; 3752*38fd1498Szrj 3753*38fd1498Szrj case SSA_NAME: 3754*38fd1498Szrj bounds = chkp_get_registered_bounds (ptr_src); 3755*38fd1498Szrj if (!bounds) 3756*38fd1498Szrj { 3757*38fd1498Szrj gimple *def_stmt = SSA_NAME_DEF_STMT (ptr_src); 3758*38fd1498Szrj gphi_iterator phi_iter; 3759*38fd1498Szrj 3760*38fd1498Szrj bounds = chkp_get_bounds_by_definition (ptr_src, def_stmt, &phi_iter); 3761*38fd1498Szrj 3762*38fd1498Szrj gcc_assert (bounds); 3763*38fd1498Szrj 3764*38fd1498Szrj if (gphi *def_phi = dyn_cast <gphi *> (def_stmt)) 3765*38fd1498Szrj { 3766*38fd1498Szrj unsigned i; 3767*38fd1498Szrj 3768*38fd1498Szrj for (i = 0; i < gimple_phi_num_args (def_phi); i++) 3769*38fd1498Szrj { 3770*38fd1498Szrj tree arg = gimple_phi_arg_def (def_phi, i); 3771*38fd1498Szrj tree arg_bnd; 3772*38fd1498Szrj gphi *phi_bnd; 3773*38fd1498Szrj 3774*38fd1498Szrj arg_bnd = chkp_find_bounds (arg, NULL); 3775*38fd1498Szrj 3776*38fd1498Szrj /* chkp_get_bounds_by_definition created new phi 3777*38fd1498Szrj statement and phi_iter points to it. 3778*38fd1498Szrj 3779*38fd1498Szrj Previous call to chkp_find_bounds could create 3780*38fd1498Szrj new basic block and therefore change phi statement 3781*38fd1498Szrj phi_iter points to. */ 3782*38fd1498Szrj phi_bnd = phi_iter.phi (); 3783*38fd1498Szrj 3784*38fd1498Szrj add_phi_arg (phi_bnd, arg_bnd, 3785*38fd1498Szrj gimple_phi_arg_edge (def_phi, i), 3786*38fd1498Szrj UNKNOWN_LOCATION); 3787*38fd1498Szrj } 3788*38fd1498Szrj 3789*38fd1498Szrj /* If all bound phi nodes have their arg computed 3790*38fd1498Szrj then we may finish its computation. See 3791*38fd1498Szrj chkp_finish_incomplete_bounds for more details. */ 3792*38fd1498Szrj if (chkp_may_finish_incomplete_bounds ()) 3793*38fd1498Szrj chkp_finish_incomplete_bounds (); 3794*38fd1498Szrj } 3795*38fd1498Szrj 3796*38fd1498Szrj gcc_assert (bounds == chkp_get_registered_bounds (ptr_src) 3797*38fd1498Szrj || chkp_incomplete_bounds (bounds)); 3798*38fd1498Szrj } 3799*38fd1498Szrj break; 3800*38fd1498Szrj 3801*38fd1498Szrj case ADDR_EXPR: 3802*38fd1498Szrj case WITH_SIZE_EXPR: 3803*38fd1498Szrj bounds = chkp_make_addressed_object_bounds (TREE_OPERAND (ptr_src, 0), iter); 3804*38fd1498Szrj break; 3805*38fd1498Szrj 3806*38fd1498Szrj case INTEGER_CST: 3807*38fd1498Szrj case COMPLEX_CST: 3808*38fd1498Szrj case VECTOR_CST: 3809*38fd1498Szrj if (integer_zerop (ptr_src)) 3810*38fd1498Szrj bounds = chkp_get_none_bounds (); 3811*38fd1498Szrj else 3812*38fd1498Szrj bounds = chkp_get_invalid_op_bounds (); 3813*38fd1498Szrj break; 3814*38fd1498Szrj 3815*38fd1498Szrj default: 3816*38fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS)) 3817*38fd1498Szrj { 3818*38fd1498Szrj fprintf (dump_file, "chkp_find_bounds: unexpected ptr of type %s\n", 3819*38fd1498Szrj get_tree_code_name (TREE_CODE (ptr_src))); 3820*38fd1498Szrj print_node (dump_file, "", ptr_src, 0); 3821*38fd1498Szrj } 3822*38fd1498Szrj internal_error ("chkp_find_bounds: Unexpected tree code %s", 3823*38fd1498Szrj get_tree_code_name (TREE_CODE (ptr_src))); 3824*38fd1498Szrj } 3825*38fd1498Szrj 3826*38fd1498Szrj if (!bounds) 3827*38fd1498Szrj { 3828*38fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS)) 3829*38fd1498Szrj { 3830*38fd1498Szrj fprintf (stderr, "chkp_find_bounds: cannot find bounds for pointer\n"); 3831*38fd1498Szrj print_node (dump_file, "", ptr_src, 0); 3832*38fd1498Szrj } 3833*38fd1498Szrj internal_error ("chkp_find_bounds: Cannot find bounds for pointer"); 3834*38fd1498Szrj } 3835*38fd1498Szrj 3836*38fd1498Szrj return bounds; 3837*38fd1498Szrj } 3838*38fd1498Szrj 3839*38fd1498Szrj /* Normal case for bounds search without forced narrowing. */ 3840*38fd1498Szrj static tree 3841*38fd1498Szrj chkp_find_bounds (tree ptr, gimple_stmt_iterator *iter) 3842*38fd1498Szrj { 3843*38fd1498Szrj return chkp_find_bounds_1 (ptr, NULL_TREE, iter); 3844*38fd1498Szrj } 3845*38fd1498Szrj 3846*38fd1498Szrj /* Search bounds for pointer PTR loaded from PTR_SRC 3847*38fd1498Szrj by statement *ITER points to. */ 3848*38fd1498Szrj static tree 3849*38fd1498Szrj chkp_find_bounds_loaded (tree ptr, tree ptr_src, gimple_stmt_iterator *iter) 3850*38fd1498Szrj { 3851*38fd1498Szrj return chkp_find_bounds_1 (ptr, ptr_src, iter); 3852*38fd1498Szrj } 3853*38fd1498Szrj 3854*38fd1498Szrj /* Helper function which checks type of RHS and finds all pointers in 3855*38fd1498Szrj it. For each found pointer we build it's accesses in LHS and RHS 3856*38fd1498Szrj objects and then call HANDLER for them. Function is used to copy 3857*38fd1498Szrj or initilize bounds for copied object. */ 3858*38fd1498Szrj static void 3859*38fd1498Szrj chkp_walk_pointer_assignments (tree lhs, tree rhs, void *arg, 3860*38fd1498Szrj assign_handler handler) 3861*38fd1498Szrj { 3862*38fd1498Szrj tree type = TREE_TYPE (lhs); 3863*38fd1498Szrj 3864*38fd1498Szrj /* We have nothing to do with clobbers. */ 3865*38fd1498Szrj if (TREE_CLOBBER_P (rhs)) 3866*38fd1498Szrj return; 3867*38fd1498Szrj 3868*38fd1498Szrj if (BOUNDED_TYPE_P (type)) 3869*38fd1498Szrj handler (lhs, rhs, arg); 3870*38fd1498Szrj else if (RECORD_OR_UNION_TYPE_P (type)) 3871*38fd1498Szrj { 3872*38fd1498Szrj tree field; 3873*38fd1498Szrj 3874*38fd1498Szrj if (TREE_CODE (rhs) == CONSTRUCTOR) 3875*38fd1498Szrj { 3876*38fd1498Szrj unsigned HOST_WIDE_INT cnt; 3877*38fd1498Szrj tree val; 3878*38fd1498Szrj 3879*38fd1498Szrj FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (rhs), cnt, field, val) 3880*38fd1498Szrj { 3881*38fd1498Szrj if (field && chkp_type_has_pointer (TREE_TYPE (field))) 3882*38fd1498Szrj { 3883*38fd1498Szrj tree lhs_field = chkp_build_component_ref (lhs, field); 3884*38fd1498Szrj chkp_walk_pointer_assignments (lhs_field, val, arg, handler); 3885*38fd1498Szrj } 3886*38fd1498Szrj } 3887*38fd1498Szrj } 3888*38fd1498Szrj else 3889*38fd1498Szrj for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) 3890*38fd1498Szrj if (TREE_CODE (field) == FIELD_DECL 3891*38fd1498Szrj && chkp_type_has_pointer (TREE_TYPE (field))) 3892*38fd1498Szrj { 3893*38fd1498Szrj tree rhs_field = chkp_build_component_ref (rhs, field); 3894*38fd1498Szrj tree lhs_field = chkp_build_component_ref (lhs, field); 3895*38fd1498Szrj chkp_walk_pointer_assignments (lhs_field, rhs_field, arg, handler); 3896*38fd1498Szrj } 3897*38fd1498Szrj } 3898*38fd1498Szrj else if (TREE_CODE (type) == ARRAY_TYPE) 3899*38fd1498Szrj { 3900*38fd1498Szrj unsigned HOST_WIDE_INT cur = 0; 3901*38fd1498Szrj tree maxval = TYPE_MAX_VALUE (TYPE_DOMAIN (type)); 3902*38fd1498Szrj tree etype = TREE_TYPE (type); 3903*38fd1498Szrj tree esize = TYPE_SIZE (etype); 3904*38fd1498Szrj 3905*38fd1498Szrj if (TREE_CODE (rhs) == CONSTRUCTOR) 3906*38fd1498Szrj { 3907*38fd1498Szrj unsigned HOST_WIDE_INT cnt; 3908*38fd1498Szrj tree purp, val, lhs_elem; 3909*38fd1498Szrj 3910*38fd1498Szrj FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (rhs), cnt, purp, val) 3911*38fd1498Szrj { 3912*38fd1498Szrj if (purp && TREE_CODE (purp) == RANGE_EXPR) 3913*38fd1498Szrj { 3914*38fd1498Szrj tree lo_index = TREE_OPERAND (purp, 0); 3915*38fd1498Szrj tree hi_index = TREE_OPERAND (purp, 1); 3916*38fd1498Szrj 3917*38fd1498Szrj for (cur = (unsigned)tree_to_uhwi (lo_index); 3918*38fd1498Szrj cur <= (unsigned)tree_to_uhwi (hi_index); 3919*38fd1498Szrj cur++) 3920*38fd1498Szrj { 3921*38fd1498Szrj lhs_elem = chkp_build_array_ref (lhs, etype, esize, cur); 3922*38fd1498Szrj chkp_walk_pointer_assignments (lhs_elem, val, arg, handler); 3923*38fd1498Szrj } 3924*38fd1498Szrj } 3925*38fd1498Szrj else 3926*38fd1498Szrj { 3927*38fd1498Szrj if (purp) 3928*38fd1498Szrj { 3929*38fd1498Szrj gcc_assert (TREE_CODE (purp) == INTEGER_CST); 3930*38fd1498Szrj cur = tree_to_uhwi (purp); 3931*38fd1498Szrj } 3932*38fd1498Szrj 3933*38fd1498Szrj lhs_elem = chkp_build_array_ref (lhs, etype, esize, cur++); 3934*38fd1498Szrj 3935*38fd1498Szrj chkp_walk_pointer_assignments (lhs_elem, val, arg, handler); 3936*38fd1498Szrj } 3937*38fd1498Szrj } 3938*38fd1498Szrj } 3939*38fd1498Szrj /* Copy array only when size is known. */ 3940*38fd1498Szrj else if (maxval && !integer_minus_onep (maxval)) 3941*38fd1498Szrj for (cur = 0; cur <= TREE_INT_CST_LOW (maxval); cur++) 3942*38fd1498Szrj { 3943*38fd1498Szrj tree lhs_elem = chkp_build_array_ref (lhs, etype, esize, cur); 3944*38fd1498Szrj tree rhs_elem = chkp_build_array_ref (rhs, etype, esize, cur); 3945*38fd1498Szrj chkp_walk_pointer_assignments (lhs_elem, rhs_elem, arg, handler); 3946*38fd1498Szrj } 3947*38fd1498Szrj } 3948*38fd1498Szrj else 3949*38fd1498Szrj internal_error("chkp_walk_pointer_assignments: unexpected RHS type: %s", 3950*38fd1498Szrj get_tree_code_name (TREE_CODE (type))); 3951*38fd1498Szrj } 3952*38fd1498Szrj 3953*38fd1498Szrj /* Add code to copy bounds for assignment of RHS to LHS. 3954*38fd1498Szrj ARG is an iterator pointing ne code position. */ 3955*38fd1498Szrj static void 3956*38fd1498Szrj chkp_copy_bounds_for_elem (tree lhs, tree rhs, void *arg) 3957*38fd1498Szrj { 3958*38fd1498Szrj gimple_stmt_iterator *iter = (gimple_stmt_iterator *)arg; 3959*38fd1498Szrj tree bounds = chkp_find_bounds (rhs, iter); 3960*38fd1498Szrj tree addr = chkp_build_addr_expr(lhs); 3961*38fd1498Szrj 3962*38fd1498Szrj chkp_build_bndstx (addr, rhs, bounds, iter); 3963*38fd1498Szrj } 3964*38fd1498Szrj 3965*38fd1498Szrj /* Emit static bound initilizers and size vars. */ 3966*38fd1498Szrj void 3967*38fd1498Szrj chkp_finish_file (void) 3968*38fd1498Szrj { 3969*38fd1498Szrj struct varpool_node *node; 3970*38fd1498Szrj struct chkp_ctor_stmt_list stmts; 3971*38fd1498Szrj 3972*38fd1498Szrj if (seen_error ()) 3973*38fd1498Szrj return; 3974*38fd1498Szrj 3975*38fd1498Szrj /* Iterate through varpool and generate bounds initialization 3976*38fd1498Szrj constructors for all statically initialized pointers. */ 3977*38fd1498Szrj stmts.avail = MAX_STMTS_IN_STATIC_CHKP_CTOR; 3978*38fd1498Szrj stmts.stmts = NULL; 3979*38fd1498Szrj FOR_EACH_VARIABLE (node) 3980*38fd1498Szrj /* Check that var is actually emitted and we need and may initialize 3981*38fd1498Szrj its bounds. */ 3982*38fd1498Szrj if (node->need_bounds_init 3983*38fd1498Szrj && !POINTER_BOUNDS_P (node->decl) 3984*38fd1498Szrj && DECL_RTL (node->decl) 3985*38fd1498Szrj && MEM_P (DECL_RTL (node->decl)) 3986*38fd1498Szrj && TREE_ASM_WRITTEN (node->decl)) 3987*38fd1498Szrj { 3988*38fd1498Szrj chkp_walk_pointer_assignments (node->decl, 3989*38fd1498Szrj DECL_INITIAL (node->decl), 3990*38fd1498Szrj &stmts, 3991*38fd1498Szrj chkp_add_modification_to_stmt_list); 3992*38fd1498Szrj 3993*38fd1498Szrj if (stmts.avail <= 0) 3994*38fd1498Szrj { 3995*38fd1498Szrj cgraph_build_static_cdtor ('P', stmts.stmts, 3996*38fd1498Szrj MAX_RESERVED_INIT_PRIORITY + 3); 3997*38fd1498Szrj stmts.avail = MAX_STMTS_IN_STATIC_CHKP_CTOR; 3998*38fd1498Szrj stmts.stmts = NULL; 3999*38fd1498Szrj } 4000*38fd1498Szrj } 4001*38fd1498Szrj 4002*38fd1498Szrj if (stmts.stmts) 4003*38fd1498Szrj cgraph_build_static_cdtor ('P', stmts.stmts, 4004*38fd1498Szrj MAX_RESERVED_INIT_PRIORITY + 3); 4005*38fd1498Szrj 4006*38fd1498Szrj /* Iterate through varpool and generate bounds initialization 4007*38fd1498Szrj constructors for all static bounds vars. */ 4008*38fd1498Szrj stmts.avail = MAX_STMTS_IN_STATIC_CHKP_CTOR; 4009*38fd1498Szrj stmts.stmts = NULL; 4010*38fd1498Szrj FOR_EACH_VARIABLE (node) 4011*38fd1498Szrj if (node->need_bounds_init 4012*38fd1498Szrj && POINTER_BOUNDS_P (node->decl) 4013*38fd1498Szrj && TREE_ASM_WRITTEN (node->decl)) 4014*38fd1498Szrj { 4015*38fd1498Szrj tree bnd = node->decl; 4016*38fd1498Szrj tree var; 4017*38fd1498Szrj 4018*38fd1498Szrj gcc_assert (DECL_INITIAL (bnd) 4019*38fd1498Szrj && TREE_CODE (DECL_INITIAL (bnd)) == ADDR_EXPR); 4020*38fd1498Szrj 4021*38fd1498Szrj var = TREE_OPERAND (DECL_INITIAL (bnd), 0); 4022*38fd1498Szrj chkp_output_static_bounds (bnd, var, &stmts); 4023*38fd1498Szrj } 4024*38fd1498Szrj 4025*38fd1498Szrj if (stmts.stmts) 4026*38fd1498Szrj cgraph_build_static_cdtor ('B', stmts.stmts, 4027*38fd1498Szrj MAX_RESERVED_INIT_PRIORITY + 2); 4028*38fd1498Szrj 4029*38fd1498Szrj delete chkp_static_var_bounds; 4030*38fd1498Szrj delete chkp_bounds_map; 4031*38fd1498Szrj } 4032*38fd1498Szrj 4033*38fd1498Szrj /* An instrumentation function which is called for each statement 4034*38fd1498Szrj having memory access we want to instrument. It inserts check 4035*38fd1498Szrj code and bounds copy code. 4036*38fd1498Szrj 4037*38fd1498Szrj ITER points to statement to instrument. 4038*38fd1498Szrj 4039*38fd1498Szrj NODE holds memory access in statement to check. 4040*38fd1498Szrj 4041*38fd1498Szrj LOC holds the location information for statement. 4042*38fd1498Szrj 4043*38fd1498Szrj DIRFLAGS determines whether access is read or write. 4044*38fd1498Szrj 4045*38fd1498Szrj ACCESS_OFFS should be added to address used in NODE 4046*38fd1498Szrj before check. 4047*38fd1498Szrj 4048*38fd1498Szrj ACCESS_SIZE holds size of checked access. 4049*38fd1498Szrj 4050*38fd1498Szrj SAFE indicates if NODE access is safe and should not be 4051*38fd1498Szrj checked. */ 4052*38fd1498Szrj static void 4053*38fd1498Szrj chkp_process_stmt (gimple_stmt_iterator *iter, tree node, 4054*38fd1498Szrj location_t loc, tree dirflag, 4055*38fd1498Szrj tree access_offs, tree access_size, 4056*38fd1498Szrj bool safe) 4057*38fd1498Szrj { 4058*38fd1498Szrj tree node_type = TREE_TYPE (node); 4059*38fd1498Szrj tree size = access_size ? access_size : TYPE_SIZE_UNIT (node_type); 4060*38fd1498Szrj tree addr_first = NULL_TREE; /* address of the first accessed byte */ 4061*38fd1498Szrj tree addr_last = NULL_TREE; /* address of the last accessed byte */ 4062*38fd1498Szrj tree ptr = NULL_TREE; /* a pointer used for dereference */ 4063*38fd1498Szrj tree bounds = NULL_TREE; 4064*38fd1498Szrj bool reg_store = false; 4065*38fd1498Szrj 4066*38fd1498Szrj /* We do not need instrumentation for clobbers. */ 4067*38fd1498Szrj if (dirflag == integer_one_node 4068*38fd1498Szrj && gimple_code (gsi_stmt (*iter)) == GIMPLE_ASSIGN 4069*38fd1498Szrj && TREE_CLOBBER_P (gimple_assign_rhs1 (gsi_stmt (*iter)))) 4070*38fd1498Szrj return; 4071*38fd1498Szrj 4072*38fd1498Szrj switch (TREE_CODE (node)) 4073*38fd1498Szrj { 4074*38fd1498Szrj case ARRAY_REF: 4075*38fd1498Szrj case COMPONENT_REF: 4076*38fd1498Szrj { 4077*38fd1498Szrj bool bitfield; 4078*38fd1498Szrj tree elt; 4079*38fd1498Szrj 4080*38fd1498Szrj if (safe) 4081*38fd1498Szrj { 4082*38fd1498Szrj /* We are not going to generate any checks, so do not 4083*38fd1498Szrj generate bounds as well. */ 4084*38fd1498Szrj addr_first = chkp_build_addr_expr (node); 4085*38fd1498Szrj break; 4086*38fd1498Szrj } 4087*38fd1498Szrj 4088*38fd1498Szrj chkp_parse_array_and_component_ref (node, &ptr, &elt, &safe, 4089*38fd1498Szrj &bitfield, &bounds, iter, false); 4090*38fd1498Szrj 4091*38fd1498Szrj /* Break if there is no dereference and operation is safe. */ 4092*38fd1498Szrj 4093*38fd1498Szrj if (bitfield) 4094*38fd1498Szrj { 4095*38fd1498Szrj tree field = TREE_OPERAND (node, 1); 4096*38fd1498Szrj 4097*38fd1498Szrj if (TREE_CODE (DECL_SIZE_UNIT (field)) == INTEGER_CST) 4098*38fd1498Szrj size = DECL_SIZE_UNIT (field); 4099*38fd1498Szrj 4100*38fd1498Szrj if (elt) 4101*38fd1498Szrj elt = chkp_build_addr_expr (elt); 4102*38fd1498Szrj addr_first = fold_convert_loc (loc, ptr_type_node, elt ? elt : ptr); 4103*38fd1498Szrj addr_first = fold_build_pointer_plus_loc (loc, 4104*38fd1498Szrj addr_first, 4105*38fd1498Szrj byte_position (field)); 4106*38fd1498Szrj } 4107*38fd1498Szrj else 4108*38fd1498Szrj addr_first = chkp_build_addr_expr (node); 4109*38fd1498Szrj } 4110*38fd1498Szrj break; 4111*38fd1498Szrj 4112*38fd1498Szrj case INDIRECT_REF: 4113*38fd1498Szrj ptr = TREE_OPERAND (node, 0); 4114*38fd1498Szrj addr_first = ptr; 4115*38fd1498Szrj break; 4116*38fd1498Szrj 4117*38fd1498Szrj case MEM_REF: 4118*38fd1498Szrj ptr = TREE_OPERAND (node, 0); 4119*38fd1498Szrj addr_first = chkp_build_addr_expr (node); 4120*38fd1498Szrj break; 4121*38fd1498Szrj 4122*38fd1498Szrj case TARGET_MEM_REF: 4123*38fd1498Szrj ptr = TMR_BASE (node); 4124*38fd1498Szrj addr_first = chkp_build_addr_expr (node); 4125*38fd1498Szrj break; 4126*38fd1498Szrj 4127*38fd1498Szrj case ARRAY_RANGE_REF: 4128*38fd1498Szrj printf("ARRAY_RANGE_REF\n"); 4129*38fd1498Szrj debug_gimple_stmt(gsi_stmt(*iter)); 4130*38fd1498Szrj debug_tree(node); 4131*38fd1498Szrj gcc_unreachable (); 4132*38fd1498Szrj break; 4133*38fd1498Szrj 4134*38fd1498Szrj case BIT_FIELD_REF: 4135*38fd1498Szrj { 4136*38fd1498Szrj tree offset, size; 4137*38fd1498Szrj 4138*38fd1498Szrj gcc_assert (!access_offs); 4139*38fd1498Szrj gcc_assert (!access_size); 4140*38fd1498Szrj 4141*38fd1498Szrj chkp_parse_bit_field_ref (node, loc, &offset, &size); 4142*38fd1498Szrj 4143*38fd1498Szrj chkp_process_stmt (iter, TREE_OPERAND (node, 0), loc, 4144*38fd1498Szrj dirflag, offset, size, safe); 4145*38fd1498Szrj return; 4146*38fd1498Szrj } 4147*38fd1498Szrj break; 4148*38fd1498Szrj 4149*38fd1498Szrj case VAR_DECL: 4150*38fd1498Szrj case RESULT_DECL: 4151*38fd1498Szrj case PARM_DECL: 4152*38fd1498Szrj if (dirflag != integer_one_node 4153*38fd1498Szrj || DECL_REGISTER (node)) 4154*38fd1498Szrj return; 4155*38fd1498Szrj 4156*38fd1498Szrj safe = true; 4157*38fd1498Szrj addr_first = chkp_build_addr_expr (node); 4158*38fd1498Szrj break; 4159*38fd1498Szrj 4160*38fd1498Szrj default: 4161*38fd1498Szrj return; 4162*38fd1498Szrj } 4163*38fd1498Szrj 4164*38fd1498Szrj /* If addr_last was not computed then use (addr_first + size - 1) 4165*38fd1498Szrj expression to compute it. */ 4166*38fd1498Szrj if (!addr_last) 4167*38fd1498Szrj { 4168*38fd1498Szrj addr_last = fold_build_pointer_plus_loc (loc, addr_first, size); 4169*38fd1498Szrj addr_last = fold_build_pointer_plus_hwi_loc (loc, addr_last, -1); 4170*38fd1498Szrj } 4171*38fd1498Szrj 4172*38fd1498Szrj /* Shift both first_addr and last_addr by access_offs if specified. */ 4173*38fd1498Szrj if (access_offs) 4174*38fd1498Szrj { 4175*38fd1498Szrj addr_first = fold_build_pointer_plus_loc (loc, addr_first, access_offs); 4176*38fd1498Szrj addr_last = fold_build_pointer_plus_loc (loc, addr_last, access_offs); 4177*38fd1498Szrj } 4178*38fd1498Szrj 4179*38fd1498Szrj if (dirflag == integer_one_node) 4180*38fd1498Szrj { 4181*38fd1498Szrj tree base = get_base_address (node); 4182*38fd1498Szrj if (VAR_P (base) && DECL_HARD_REGISTER (base)) 4183*38fd1498Szrj reg_store = true; 4184*38fd1498Szrj } 4185*38fd1498Szrj 4186*38fd1498Szrj /* Generate bndcl/bndcu checks if memory access is not safe. */ 4187*38fd1498Szrj if (!safe) 4188*38fd1498Szrj { 4189*38fd1498Szrj gimple_stmt_iterator stmt_iter = *iter; 4190*38fd1498Szrj 4191*38fd1498Szrj if (!bounds) 4192*38fd1498Szrj bounds = chkp_find_bounds (ptr, iter); 4193*38fd1498Szrj 4194*38fd1498Szrj chkp_check_mem_access (addr_first, addr_last, bounds, 4195*38fd1498Szrj stmt_iter, loc, dirflag); 4196*38fd1498Szrj } 4197*38fd1498Szrj 4198*38fd1498Szrj /* We need to store bounds in case pointer is stored. */ 4199*38fd1498Szrj if (dirflag == integer_one_node 4200*38fd1498Szrj && !reg_store 4201*38fd1498Szrj && chkp_type_has_pointer (node_type) 4202*38fd1498Szrj && flag_chkp_store_bounds) 4203*38fd1498Szrj { 4204*38fd1498Szrj gimple *stmt = gsi_stmt (*iter); 4205*38fd1498Szrj tree rhs1 = gimple_assign_rhs1 (stmt); 4206*38fd1498Szrj enum tree_code rhs_code = gimple_assign_rhs_code (stmt); 4207*38fd1498Szrj 4208*38fd1498Szrj if (get_gimple_rhs_class (rhs_code) == GIMPLE_SINGLE_RHS) 4209*38fd1498Szrj chkp_walk_pointer_assignments (node, rhs1, iter, 4210*38fd1498Szrj chkp_copy_bounds_for_elem); 4211*38fd1498Szrj else 4212*38fd1498Szrj { 4213*38fd1498Szrj bounds = chkp_compute_bounds_for_assignment (NULL_TREE, stmt); 4214*38fd1498Szrj chkp_build_bndstx (addr_first, rhs1, bounds, iter); 4215*38fd1498Szrj } 4216*38fd1498Szrj } 4217*38fd1498Szrj } 4218*38fd1498Szrj 4219*38fd1498Szrj /* Add code to copy bounds for all pointers copied 4220*38fd1498Szrj in ASSIGN created during inline of EDGE. */ 4221*38fd1498Szrj void 4222*38fd1498Szrj chkp_copy_bounds_for_assign (gimple *assign, struct cgraph_edge *edge) 4223*38fd1498Szrj { 4224*38fd1498Szrj tree lhs = gimple_assign_lhs (assign); 4225*38fd1498Szrj tree rhs = gimple_assign_rhs1 (assign); 4226*38fd1498Szrj gimple_stmt_iterator iter = gsi_for_stmt (assign); 4227*38fd1498Szrj 4228*38fd1498Szrj if (!flag_chkp_store_bounds) 4229*38fd1498Szrj return; 4230*38fd1498Szrj 4231*38fd1498Szrj chkp_walk_pointer_assignments (lhs, rhs, &iter, chkp_copy_bounds_for_elem); 4232*38fd1498Szrj 4233*38fd1498Szrj /* We should create edges for all created calls to bndldx and bndstx. */ 4234*38fd1498Szrj while (gsi_stmt (iter) != assign) 4235*38fd1498Szrj { 4236*38fd1498Szrj gimple *stmt = gsi_stmt (iter); 4237*38fd1498Szrj if (gimple_code (stmt) == GIMPLE_CALL) 4238*38fd1498Szrj { 4239*38fd1498Szrj tree fndecl = gimple_call_fndecl (stmt); 4240*38fd1498Szrj struct cgraph_node *callee = cgraph_node::get_create (fndecl); 4241*38fd1498Szrj 4242*38fd1498Szrj gcc_assert (chkp_gimple_call_builtin_p (stmt, BUILT_IN_CHKP_BNDSTX) 4243*38fd1498Szrj || chkp_gimple_call_builtin_p (stmt, BUILT_IN_CHKP_BNDLDX) 4244*38fd1498Szrj || chkp_gimple_call_builtin_p (stmt, BUILT_IN_CHKP_BNDRET)); 4245*38fd1498Szrj 4246*38fd1498Szrj edge->caller->create_edge (callee, as_a <gcall *> (stmt), edge->count); 4247*38fd1498Szrj } 4248*38fd1498Szrj gsi_prev (&iter); 4249*38fd1498Szrj } 4250*38fd1498Szrj } 4251*38fd1498Szrj 4252*38fd1498Szrj /* Some code transformation made during instrumentation pass 4253*38fd1498Szrj may put code into inconsistent state. Here we find and fix 4254*38fd1498Szrj such flaws. */ 4255*38fd1498Szrj void 4256*38fd1498Szrj chkp_fix_cfg () 4257*38fd1498Szrj { 4258*38fd1498Szrj basic_block bb; 4259*38fd1498Szrj gimple_stmt_iterator i; 4260*38fd1498Szrj 4261*38fd1498Szrj /* We could insert some code right after stmt which ends bb. 4262*38fd1498Szrj We wanted to put this code on fallthru edge but did not 4263*38fd1498Szrj add new edges from the beginning because it may cause new 4264*38fd1498Szrj phi node creation which may be incorrect due to incomplete 4265*38fd1498Szrj bound phi nodes. */ 4266*38fd1498Szrj FOR_ALL_BB_FN (bb, cfun) 4267*38fd1498Szrj for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i)) 4268*38fd1498Szrj { 4269*38fd1498Szrj gimple *stmt = gsi_stmt (i); 4270*38fd1498Szrj gimple_stmt_iterator next = i; 4271*38fd1498Szrj 4272*38fd1498Szrj gsi_next (&next); 4273*38fd1498Szrj 4274*38fd1498Szrj if (stmt_ends_bb_p (stmt) 4275*38fd1498Szrj && !gsi_end_p (next)) 4276*38fd1498Szrj { 4277*38fd1498Szrj edge fall = find_fallthru_edge (bb->succs); 4278*38fd1498Szrj basic_block dest = NULL; 4279*38fd1498Szrj int flags = 0; 4280*38fd1498Szrj 4281*38fd1498Szrj gcc_assert (fall); 4282*38fd1498Szrj 4283*38fd1498Szrj /* We cannot split abnormal edge. Therefore we 4284*38fd1498Szrj store its params, make it regular and then 4285*38fd1498Szrj rebuild abnormal edge after split. */ 4286*38fd1498Szrj if (fall->flags & EDGE_ABNORMAL) 4287*38fd1498Szrj { 4288*38fd1498Szrj flags = fall->flags & ~EDGE_FALLTHRU; 4289*38fd1498Szrj dest = fall->dest; 4290*38fd1498Szrj 4291*38fd1498Szrj fall->flags &= ~EDGE_COMPLEX; 4292*38fd1498Szrj } 4293*38fd1498Szrj 4294*38fd1498Szrj while (!gsi_end_p (next)) 4295*38fd1498Szrj { 4296*38fd1498Szrj gimple *next_stmt = gsi_stmt (next); 4297*38fd1498Szrj gsi_remove (&next, false); 4298*38fd1498Szrj gsi_insert_on_edge (fall, next_stmt); 4299*38fd1498Szrj } 4300*38fd1498Szrj 4301*38fd1498Szrj gsi_commit_edge_inserts (); 4302*38fd1498Szrj 4303*38fd1498Szrj /* Re-create abnormal edge. */ 4304*38fd1498Szrj if (dest) 4305*38fd1498Szrj make_edge (bb, dest, flags); 4306*38fd1498Szrj } 4307*38fd1498Szrj } 4308*38fd1498Szrj } 4309*38fd1498Szrj 4310*38fd1498Szrj /* Walker callback for chkp_replace_function_pointers. Replaces 4311*38fd1498Szrj function pointer in the specified operand with pointer to the 4312*38fd1498Szrj instrumented function version. */ 4313*38fd1498Szrj static tree 4314*38fd1498Szrj chkp_replace_function_pointer (tree *op, int *walk_subtrees, 4315*38fd1498Szrj void *data ATTRIBUTE_UNUSED) 4316*38fd1498Szrj { 4317*38fd1498Szrj if (TREE_CODE (*op) == FUNCTION_DECL 4318*38fd1498Szrj && chkp_instrumentable_p (*op) 4319*38fd1498Szrj && (DECL_BUILT_IN_CLASS (*op) == NOT_BUILT_IN 4320*38fd1498Szrj /* For builtins we replace pointers only for selected 4321*38fd1498Szrj function and functions having definitions. */ 4322*38fd1498Szrj || (DECL_BUILT_IN_CLASS (*op) == BUILT_IN_NORMAL 4323*38fd1498Szrj && (chkp_instrument_normal_builtin (*op) 4324*38fd1498Szrj || gimple_has_body_p (*op))))) 4325*38fd1498Szrj { 4326*38fd1498Szrj struct cgraph_node *node = cgraph_node::get_create (*op); 4327*38fd1498Szrj struct cgraph_node *clone = NULL; 4328*38fd1498Szrj 4329*38fd1498Szrj if (!node->instrumentation_clone) 4330*38fd1498Szrj clone = chkp_maybe_create_clone (*op); 4331*38fd1498Szrj 4332*38fd1498Szrj if (clone) 4333*38fd1498Szrj *op = clone->decl; 4334*38fd1498Szrj *walk_subtrees = 0; 4335*38fd1498Szrj } 4336*38fd1498Szrj 4337*38fd1498Szrj return NULL; 4338*38fd1498Szrj } 4339*38fd1498Szrj 4340*38fd1498Szrj /* This function searches for function pointers in statement 4341*38fd1498Szrj pointed by GSI and replaces them with pointers to instrumented 4342*38fd1498Szrj function versions. */ 4343*38fd1498Szrj static void 4344*38fd1498Szrj chkp_replace_function_pointers (gimple_stmt_iterator *gsi) 4345*38fd1498Szrj { 4346*38fd1498Szrj gimple *stmt = gsi_stmt (*gsi); 4347*38fd1498Szrj /* For calls we want to walk call args only. */ 4348*38fd1498Szrj if (gimple_code (stmt) == GIMPLE_CALL) 4349*38fd1498Szrj { 4350*38fd1498Szrj unsigned i; 4351*38fd1498Szrj for (i = 0; i < gimple_call_num_args (stmt); i++) 4352*38fd1498Szrj walk_tree (gimple_call_arg_ptr (stmt, i), 4353*38fd1498Szrj chkp_replace_function_pointer, NULL, NULL); 4354*38fd1498Szrj } 4355*38fd1498Szrj else 4356*38fd1498Szrj walk_gimple_stmt (gsi, NULL, chkp_replace_function_pointer, NULL); 4357*38fd1498Szrj } 4358*38fd1498Szrj 4359*38fd1498Szrj /* This function instruments all statements working with memory, 4360*38fd1498Szrj calls and rets. 4361*38fd1498Szrj 4362*38fd1498Szrj It also removes excess statements from static initializers. */ 4363*38fd1498Szrj static void 4364*38fd1498Szrj chkp_instrument_function (void) 4365*38fd1498Szrj { 4366*38fd1498Szrj basic_block bb, next; 4367*38fd1498Szrj gimple_stmt_iterator i; 4368*38fd1498Szrj enum gimple_rhs_class grhs_class; 4369*38fd1498Szrj bool safe = lookup_attribute ("chkp ctor", DECL_ATTRIBUTES (cfun->decl)); 4370*38fd1498Szrj 4371*38fd1498Szrj bb = ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb; 4372*38fd1498Szrj do 4373*38fd1498Szrj { 4374*38fd1498Szrj next = bb->next_bb; 4375*38fd1498Szrj for (i = gsi_start_bb (bb); !gsi_end_p (i); ) 4376*38fd1498Szrj { 4377*38fd1498Szrj gimple *s = gsi_stmt (i); 4378*38fd1498Szrj 4379*38fd1498Szrj /* Skip statement marked to not be instrumented. */ 4380*38fd1498Szrj if (chkp_marked_stmt_p (s)) 4381*38fd1498Szrj { 4382*38fd1498Szrj gsi_next (&i); 4383*38fd1498Szrj continue; 4384*38fd1498Szrj } 4385*38fd1498Szrj 4386*38fd1498Szrj chkp_replace_function_pointers (&i); 4387*38fd1498Szrj 4388*38fd1498Szrj switch (gimple_code (s)) 4389*38fd1498Szrj { 4390*38fd1498Szrj case GIMPLE_ASSIGN: 4391*38fd1498Szrj chkp_process_stmt (&i, gimple_assign_lhs (s), 4392*38fd1498Szrj gimple_location (s), integer_one_node, 4393*38fd1498Szrj NULL_TREE, NULL_TREE, safe); 4394*38fd1498Szrj chkp_process_stmt (&i, gimple_assign_rhs1 (s), 4395*38fd1498Szrj gimple_location (s), integer_zero_node, 4396*38fd1498Szrj NULL_TREE, NULL_TREE, safe); 4397*38fd1498Szrj grhs_class = get_gimple_rhs_class (gimple_assign_rhs_code (s)); 4398*38fd1498Szrj if (grhs_class == GIMPLE_BINARY_RHS) 4399*38fd1498Szrj chkp_process_stmt (&i, gimple_assign_rhs2 (s), 4400*38fd1498Szrj gimple_location (s), integer_zero_node, 4401*38fd1498Szrj NULL_TREE, NULL_TREE, safe); 4402*38fd1498Szrj break; 4403*38fd1498Szrj 4404*38fd1498Szrj case GIMPLE_RETURN: 4405*38fd1498Szrj { 4406*38fd1498Szrj greturn *r = as_a <greturn *> (s); 4407*38fd1498Szrj if (gimple_return_retval (r) != NULL_TREE) 4408*38fd1498Szrj { 4409*38fd1498Szrj chkp_process_stmt (&i, gimple_return_retval (r), 4410*38fd1498Szrj gimple_location (r), 4411*38fd1498Szrj integer_zero_node, 4412*38fd1498Szrj NULL_TREE, NULL_TREE, safe); 4413*38fd1498Szrj 4414*38fd1498Szrj /* Additionally we need to add bounds 4415*38fd1498Szrj to return statement. */ 4416*38fd1498Szrj chkp_add_bounds_to_ret_stmt (&i); 4417*38fd1498Szrj } 4418*38fd1498Szrj } 4419*38fd1498Szrj break; 4420*38fd1498Szrj 4421*38fd1498Szrj case GIMPLE_CALL: 4422*38fd1498Szrj chkp_add_bounds_to_call_stmt (&i); 4423*38fd1498Szrj break; 4424*38fd1498Szrj 4425*38fd1498Szrj default: 4426*38fd1498Szrj ; 4427*38fd1498Szrj } 4428*38fd1498Szrj 4429*38fd1498Szrj gsi_next (&i); 4430*38fd1498Szrj 4431*38fd1498Szrj /* We do not need any actual pointer stores in checker 4432*38fd1498Szrj static initializer. */ 4433*38fd1498Szrj if (lookup_attribute ("chkp ctor", DECL_ATTRIBUTES (cfun->decl)) 4434*38fd1498Szrj && gimple_code (s) == GIMPLE_ASSIGN 4435*38fd1498Szrj && gimple_store_p (s)) 4436*38fd1498Szrj { 4437*38fd1498Szrj gimple_stmt_iterator del_iter = gsi_for_stmt (s); 4438*38fd1498Szrj gsi_remove (&del_iter, true); 4439*38fd1498Szrj unlink_stmt_vdef (s); 4440*38fd1498Szrj release_defs(s); 4441*38fd1498Szrj } 4442*38fd1498Szrj } 4443*38fd1498Szrj bb = next; 4444*38fd1498Szrj } 4445*38fd1498Szrj while (bb); 4446*38fd1498Szrj 4447*38fd1498Szrj /* Some input params may have bounds and be address taken. In this case 4448*38fd1498Szrj we should store incoming bounds into bounds table. */ 4449*38fd1498Szrj tree arg; 4450*38fd1498Szrj if (flag_chkp_store_bounds) 4451*38fd1498Szrj for (arg = DECL_ARGUMENTS (cfun->decl); arg; arg = DECL_CHAIN (arg)) 4452*38fd1498Szrj if (TREE_ADDRESSABLE (arg)) 4453*38fd1498Szrj { 4454*38fd1498Szrj if (BOUNDED_P (arg)) 4455*38fd1498Szrj { 4456*38fd1498Szrj tree bounds = chkp_get_next_bounds_parm (arg); 4457*38fd1498Szrj tree def_ptr = ssa_default_def (cfun, arg); 4458*38fd1498Szrj gimple_stmt_iterator iter 4459*38fd1498Szrj = gsi_start_bb (chkp_get_entry_block ()); 4460*38fd1498Szrj chkp_build_bndstx (chkp_build_addr_expr (arg), 4461*38fd1498Szrj def_ptr ? def_ptr : arg, 4462*38fd1498Szrj bounds, &iter); 4463*38fd1498Szrj 4464*38fd1498Szrj /* Skip bounds arg. */ 4465*38fd1498Szrj arg = TREE_CHAIN (arg); 4466*38fd1498Szrj } 4467*38fd1498Szrj else if (chkp_type_has_pointer (TREE_TYPE (arg))) 4468*38fd1498Szrj { 4469*38fd1498Szrj tree orig_arg = arg; 4470*38fd1498Szrj bitmap slots = BITMAP_ALLOC (NULL); 4471*38fd1498Szrj gimple_stmt_iterator iter 4472*38fd1498Szrj = gsi_start_bb (chkp_get_entry_block ()); 4473*38fd1498Szrj bitmap_iterator bi; 4474*38fd1498Szrj unsigned bnd_no; 4475*38fd1498Szrj 4476*38fd1498Szrj chkp_find_bound_slots (TREE_TYPE (arg), slots); 4477*38fd1498Szrj 4478*38fd1498Szrj EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi) 4479*38fd1498Szrj { 4480*38fd1498Szrj tree bounds = chkp_get_next_bounds_parm (arg); 4481*38fd1498Szrj HOST_WIDE_INT offs = bnd_no * POINTER_SIZE / BITS_PER_UNIT; 4482*38fd1498Szrj tree addr = chkp_build_addr_expr (orig_arg); 4483*38fd1498Szrj tree ptr = build2 (MEM_REF, ptr_type_node, addr, 4484*38fd1498Szrj build_int_cst (ptr_type_node, offs)); 4485*38fd1498Szrj chkp_build_bndstx (chkp_build_addr_expr (ptr), ptr, 4486*38fd1498Szrj bounds, &iter); 4487*38fd1498Szrj 4488*38fd1498Szrj arg = DECL_CHAIN (arg); 4489*38fd1498Szrj } 4490*38fd1498Szrj BITMAP_FREE (slots); 4491*38fd1498Szrj } 4492*38fd1498Szrj } 4493*38fd1498Szrj } 4494*38fd1498Szrj 4495*38fd1498Szrj /* Find init/null/copy_ptr_bounds calls and replace them 4496*38fd1498Szrj with assignments. It should allow better code 4497*38fd1498Szrj optimization. */ 4498*38fd1498Szrj 4499*38fd1498Szrj static void 4500*38fd1498Szrj chkp_remove_useless_builtins () 4501*38fd1498Szrj { 4502*38fd1498Szrj basic_block bb; 4503*38fd1498Szrj gimple_stmt_iterator gsi; 4504*38fd1498Szrj 4505*38fd1498Szrj FOR_EACH_BB_FN (bb, cfun) 4506*38fd1498Szrj { 4507*38fd1498Szrj for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) 4508*38fd1498Szrj { 4509*38fd1498Szrj gimple *stmt = gsi_stmt (gsi); 4510*38fd1498Szrj tree fndecl; 4511*38fd1498Szrj enum built_in_function fcode; 4512*38fd1498Szrj 4513*38fd1498Szrj /* Find builtins returning first arg and replace 4514*38fd1498Szrj them with assignments. */ 4515*38fd1498Szrj if (gimple_code (stmt) == GIMPLE_CALL 4516*38fd1498Szrj && (fndecl = gimple_call_fndecl (stmt)) 4517*38fd1498Szrj && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL 4518*38fd1498Szrj && (fcode = DECL_FUNCTION_CODE (fndecl)) 4519*38fd1498Szrj && (fcode == BUILT_IN_CHKP_INIT_PTR_BOUNDS 4520*38fd1498Szrj || fcode == BUILT_IN_CHKP_NULL_PTR_BOUNDS 4521*38fd1498Szrj || fcode == BUILT_IN_CHKP_COPY_PTR_BOUNDS 4522*38fd1498Szrj || fcode == BUILT_IN_CHKP_SET_PTR_BOUNDS)) 4523*38fd1498Szrj { 4524*38fd1498Szrj tree res = gimple_call_arg (stmt, 0); 4525*38fd1498Szrj update_call_from_tree (&gsi, res); 4526*38fd1498Szrj stmt = gsi_stmt (gsi); 4527*38fd1498Szrj update_stmt (stmt); 4528*38fd1498Szrj } 4529*38fd1498Szrj } 4530*38fd1498Szrj } 4531*38fd1498Szrj } 4532*38fd1498Szrj 4533*38fd1498Szrj /* Initialize pass. */ 4534*38fd1498Szrj static void 4535*38fd1498Szrj chkp_init (void) 4536*38fd1498Szrj { 4537*38fd1498Szrj basic_block bb; 4538*38fd1498Szrj gimple_stmt_iterator i; 4539*38fd1498Szrj 4540*38fd1498Szrj in_chkp_pass = true; 4541*38fd1498Szrj 4542*38fd1498Szrj for (bb = ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb; bb; bb = bb->next_bb) 4543*38fd1498Szrj for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i)) 4544*38fd1498Szrj chkp_unmark_stmt (gsi_stmt (i)); 4545*38fd1498Szrj 4546*38fd1498Szrj chkp_invalid_bounds = new hash_set<tree>; 4547*38fd1498Szrj chkp_completed_bounds_set = new hash_set<tree>; 4548*38fd1498Szrj delete chkp_reg_bounds; 4549*38fd1498Szrj chkp_reg_bounds = new hash_map<tree, tree>; 4550*38fd1498Szrj delete chkp_bound_vars; 4551*38fd1498Szrj chkp_bound_vars = new hash_map<tree, tree>; 4552*38fd1498Szrj chkp_reg_addr_bounds = new hash_map<tree, tree>; 4553*38fd1498Szrj chkp_incomplete_bounds_map = new hash_map<tree, tree>; 4554*38fd1498Szrj delete chkp_bounds_map; 4555*38fd1498Szrj chkp_bounds_map = new hash_map<tree, tree>; 4556*38fd1498Szrj chkp_abnormal_copies = BITMAP_GGC_ALLOC (); 4557*38fd1498Szrj 4558*38fd1498Szrj entry_block = NULL; 4559*38fd1498Szrj zero_bounds = NULL_TREE; 4560*38fd1498Szrj none_bounds = NULL_TREE; 4561*38fd1498Szrj incomplete_bounds = integer_zero_node; 4562*38fd1498Szrj tmp_var = NULL_TREE; 4563*38fd1498Szrj size_tmp_var = NULL_TREE; 4564*38fd1498Szrj 4565*38fd1498Szrj chkp_uintptr_type = lang_hooks.types.type_for_mode (ptr_mode, true); 4566*38fd1498Szrj 4567*38fd1498Szrj /* We create these constant bounds once for each object file. 4568*38fd1498Szrj These symbols go to comdat section and result in single copy 4569*38fd1498Szrj of each one in the final binary. */ 4570*38fd1498Szrj chkp_get_zero_bounds_var (); 4571*38fd1498Szrj chkp_get_none_bounds_var (); 4572*38fd1498Szrj 4573*38fd1498Szrj calculate_dominance_info (CDI_DOMINATORS); 4574*38fd1498Szrj calculate_dominance_info (CDI_POST_DOMINATORS); 4575*38fd1498Szrj 4576*38fd1498Szrj bitmap_obstack_initialize (NULL); 4577*38fd1498Szrj } 4578*38fd1498Szrj 4579*38fd1498Szrj /* Finalize instrumentation pass. */ 4580*38fd1498Szrj static void 4581*38fd1498Szrj chkp_fini (void) 4582*38fd1498Szrj { 4583*38fd1498Szrj in_chkp_pass = false; 4584*38fd1498Szrj 4585*38fd1498Szrj delete chkp_invalid_bounds; 4586*38fd1498Szrj delete chkp_completed_bounds_set; 4587*38fd1498Szrj delete chkp_reg_addr_bounds; 4588*38fd1498Szrj delete chkp_incomplete_bounds_map; 4589*38fd1498Szrj 4590*38fd1498Szrj free_dominance_info (CDI_DOMINATORS); 4591*38fd1498Szrj free_dominance_info (CDI_POST_DOMINATORS); 4592*38fd1498Szrj 4593*38fd1498Szrj bitmap_obstack_release (NULL); 4594*38fd1498Szrj 4595*38fd1498Szrj entry_block = NULL; 4596*38fd1498Szrj zero_bounds = NULL_TREE; 4597*38fd1498Szrj none_bounds = NULL_TREE; 4598*38fd1498Szrj } 4599*38fd1498Szrj 4600*38fd1498Szrj /* Main instrumentation pass function. */ 4601*38fd1498Szrj static unsigned int 4602*38fd1498Szrj chkp_execute (void) 4603*38fd1498Szrj { 4604*38fd1498Szrj chkp_init (); 4605*38fd1498Szrj 4606*38fd1498Szrj chkp_instrument_function (); 4607*38fd1498Szrj 4608*38fd1498Szrj chkp_remove_useless_builtins (); 4609*38fd1498Szrj 4610*38fd1498Szrj chkp_function_mark_instrumented (cfun->decl); 4611*38fd1498Szrj 4612*38fd1498Szrj chkp_fix_cfg (); 4613*38fd1498Szrj 4614*38fd1498Szrj chkp_fini (); 4615*38fd1498Szrj 4616*38fd1498Szrj return 0; 4617*38fd1498Szrj } 4618*38fd1498Szrj 4619*38fd1498Szrj /* Instrumentation pass gate. */ 4620*38fd1498Szrj static bool 4621*38fd1498Szrj chkp_gate (void) 4622*38fd1498Szrj { 4623*38fd1498Szrj cgraph_node *node = cgraph_node::get (cfun->decl); 4624*38fd1498Szrj return ((node != NULL 4625*38fd1498Szrj && node->instrumentation_clone) 4626*38fd1498Szrj || lookup_attribute ("chkp ctor", DECL_ATTRIBUTES (cfun->decl))); 4627*38fd1498Szrj } 4628*38fd1498Szrj 4629*38fd1498Szrj namespace { 4630*38fd1498Szrj 4631*38fd1498Szrj const pass_data pass_data_chkp = 4632*38fd1498Szrj { 4633*38fd1498Szrj GIMPLE_PASS, /* type */ 4634*38fd1498Szrj "chkp", /* name */ 4635*38fd1498Szrj OPTGROUP_NONE, /* optinfo_flags */ 4636*38fd1498Szrj TV_NONE, /* tv_id */ 4637*38fd1498Szrj PROP_ssa | PROP_cfg, /* properties_required */ 4638*38fd1498Szrj 0, /* properties_provided */ 4639*38fd1498Szrj 0, /* properties_destroyed */ 4640*38fd1498Szrj 0, /* todo_flags_start */ 4641*38fd1498Szrj TODO_verify_il 4642*38fd1498Szrj | TODO_update_ssa /* todo_flags_finish */ 4643*38fd1498Szrj }; 4644*38fd1498Szrj 4645*38fd1498Szrj class pass_chkp : public gimple_opt_pass 4646*38fd1498Szrj { 4647*38fd1498Szrj public: 4648*38fd1498Szrj pass_chkp (gcc::context *ctxt) 4649*38fd1498Szrj : gimple_opt_pass (pass_data_chkp, ctxt) 4650*38fd1498Szrj {} 4651*38fd1498Szrj 4652*38fd1498Szrj /* opt_pass methods: */ 4653*38fd1498Szrj virtual opt_pass * clone () 4654*38fd1498Szrj { 4655*38fd1498Szrj return new pass_chkp (m_ctxt); 4656*38fd1498Szrj } 4657*38fd1498Szrj 4658*38fd1498Szrj virtual bool gate (function *) 4659*38fd1498Szrj { 4660*38fd1498Szrj return chkp_gate (); 4661*38fd1498Szrj } 4662*38fd1498Szrj 4663*38fd1498Szrj virtual unsigned int execute (function *) 4664*38fd1498Szrj { 4665*38fd1498Szrj return chkp_execute (); 4666*38fd1498Szrj } 4667*38fd1498Szrj 4668*38fd1498Szrj }; // class pass_chkp 4669*38fd1498Szrj 4670*38fd1498Szrj } // anon namespace 4671*38fd1498Szrj 4672*38fd1498Szrj gimple_opt_pass * 4673*38fd1498Szrj make_pass_chkp (gcc::context *ctxt) 4674*38fd1498Szrj { 4675*38fd1498Szrj return new pass_chkp (ctxt); 4676*38fd1498Szrj } 4677*38fd1498Szrj 4678*38fd1498Szrj #include "gt-tree-chkp.h" 4679