diff options
Diffstat (limited to 'gcc-4.8.1/gcc/asan.c')
-rw-r--r-- | gcc-4.8.1/gcc/asan.c | 2332 |
1 files changed, 0 insertions, 2332 deletions
diff --git a/gcc-4.8.1/gcc/asan.c b/gcc-4.8.1/gcc/asan.c deleted file mode 100644 index 52a2dbc5d..000000000 --- a/gcc-4.8.1/gcc/asan.c +++ /dev/null @@ -1,2332 +0,0 @@ -/* AddressSanitizer, a fast memory error detector. - Copyright (C) 2012-2013 Free Software Foundation, Inc. - Contributed by Kostya Serebryany <kcc@google.com> - -This file is part of GCC. - -GCC is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 3, or (at your option) any later -version. - -GCC is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. */ - - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "gimple.h" -#include "tree-iterator.h" -#include "tree-flow.h" -#include "tree-pass.h" -#include "asan.h" -#include "gimple-pretty-print.h" -#include "target.h" -#include "expr.h" -#include "optabs.h" -#include "output.h" -#include "tm_p.h" -#include "langhooks.h" -#include "hash-table.h" -#include "alloc-pool.h" - -/* AddressSanitizer finds out-of-bounds and use-after-free bugs - with <2x slowdown on average. - - The tool consists of two parts: - instrumentation module (this file) and a run-time library. - The instrumentation module adds a run-time check before every memory insn. - For a 8- or 16- byte load accessing address X: - ShadowAddr = (X >> 3) + Offset - ShadowValue = *(char*)ShadowAddr; // *(short*) for 16-byte access. - if (ShadowValue) - __asan_report_load8(X); - For a load of N bytes (N=1, 2 or 4) from address X: - ShadowAddr = (X >> 3) + Offset - ShadowValue = *(char*)ShadowAddr; - if (ShadowValue) - if ((X & 7) + N - 1 > ShadowValue) - __asan_report_loadN(X); - Stores are instrumented similarly, but using __asan_report_storeN functions. - A call too __asan_init() is inserted to the list of module CTORs. - - The run-time library redefines malloc (so that redzone are inserted around - the allocated memory) and free (so that reuse of free-ed memory is delayed), - provides __asan_report* and __asan_init functions. - - Read more: - http://code.google.com/p/address-sanitizer/wiki/AddressSanitizerAlgorithm - - The current implementation supports detection of out-of-bounds and - use-after-free in the heap, on the stack and for global variables. - - [Protection of stack variables] - - To understand how detection of out-of-bounds and use-after-free works - for stack variables, lets look at this example on x86_64 where the - stack grows downward: - - int - foo () - { - char a[23] = {0}; - int b[2] = {0}; - - a[5] = 1; - b[1] = 2; - - return a[5] + b[1]; - } - - For this function, the stack protected by asan will be organized as - follows, from the top of the stack to the bottom: - - Slot 1/ [red zone of 32 bytes called 'RIGHT RedZone'] - - Slot 2/ [8 bytes of red zone, that adds up to the space of 'a' to make - the next slot be 32 bytes aligned; this one is called Partial - Redzone; this 32 bytes alignment is an asan constraint] - - Slot 3/ [24 bytes for variable 'a'] - - Slot 4/ [red zone of 32 bytes called 'Middle RedZone'] - - Slot 5/ [24 bytes of Partial Red Zone (similar to slot 2] - - Slot 6/ [8 bytes for variable 'b'] - - Slot 7/ [32 bytes of Red Zone at the bottom of the stack, called - 'LEFT RedZone'] - - The 32 bytes of LEFT red zone at the bottom of the stack can be - decomposed as such: - - 1/ The first 8 bytes contain a magical asan number that is always - 0x41B58AB3. - - 2/ The following 8 bytes contains a pointer to a string (to be - parsed at runtime by the runtime asan library), which format is - the following: - - "<function-name> <space> <num-of-variables-on-the-stack> - (<32-bytes-aligned-offset-in-bytes-of-variable> <space> - <length-of-var-in-bytes> ){n} " - - where '(...){n}' means the content inside the parenthesis occurs 'n' - times, with 'n' being the number of variables on the stack. - - 3/ The following 16 bytes of the red zone have no particular - format. - - The shadow memory for that stack layout is going to look like this: - - - content of shadow memory 8 bytes for slot 7: 0xF1F1F1F1. - The F1 byte pattern is a magic number called - ASAN_STACK_MAGIC_LEFT and is a way for the runtime to know that - the memory for that shadow byte is part of a the LEFT red zone - intended to seat at the bottom of the variables on the stack. - - - content of shadow memory 8 bytes for slots 6 and 5: - 0xF4F4F400. The F4 byte pattern is a magic number - called ASAN_STACK_MAGIC_PARTIAL. It flags the fact that the - memory region for this shadow byte is a PARTIAL red zone - intended to pad a variable A, so that the slot following - {A,padding} is 32 bytes aligned. - - Note that the fact that the least significant byte of this - shadow memory content is 00 means that 8 bytes of its - corresponding memory (which corresponds to the memory of - variable 'b') is addressable. - - - content of shadow memory 8 bytes for slot 4: 0xF2F2F2F2. - The F2 byte pattern is a magic number called - ASAN_STACK_MAGIC_MIDDLE. It flags the fact that the memory - region for this shadow byte is a MIDDLE red zone intended to - seat between two 32 aligned slots of {variable,padding}. - - - content of shadow memory 8 bytes for slot 3 and 2: - 0xF4000000. This represents is the concatenation of - variable 'a' and the partial red zone following it, like what we - had for variable 'b'. The least significant 3 bytes being 00 - means that the 3 bytes of variable 'a' are addressable. - - - content of shadow memory 8 bytes for slot 1: 0xF3F3F3F3. - The F3 byte pattern is a magic number called - ASAN_STACK_MAGIC_RIGHT. It flags the fact that the memory - region for this shadow byte is a RIGHT red zone intended to seat - at the top of the variables of the stack. - - Note that the real variable layout is done in expand_used_vars in - cfgexpand.c. As far as Address Sanitizer is concerned, it lays out - stack variables as well as the different red zones, emits some - prologue code to populate the shadow memory as to poison (mark as - non-accessible) the regions of the red zones and mark the regions of - stack variables as accessible, and emit some epilogue code to - un-poison (mark as accessible) the regions of red zones right before - the function exits. - - [Protection of global variables] - - The basic idea is to insert a red zone between two global variables - and install a constructor function that calls the asan runtime to do - the populating of the relevant shadow memory regions at load time. - - So the global variables are laid out as to insert a red zone between - them. The size of the red zones is so that each variable starts on a - 32 bytes boundary. - - Then a constructor function is installed so that, for each global - variable, it calls the runtime asan library function - __asan_register_globals_with an instance of this type: - - struct __asan_global - { - // Address of the beginning of the global variable. - const void *__beg; - - // Initial size of the global variable. - uptr __size; - - // Size of the global variable + size of the red zone. This - // size is 32 bytes aligned. - uptr __size_with_redzone; - - // Name of the global variable. - const void *__name; - - // This is always set to NULL for now. - uptr __has_dynamic_init; - } - - A destructor function that calls the runtime asan library function - _asan_unregister_globals is also installed. */ - -alias_set_type asan_shadow_set = -1; - -/* Pointer types to 1 resp. 2 byte integers in shadow memory. A separate - alias set is used for all shadow memory accesses. */ -static GTY(()) tree shadow_ptr_types[2]; - -/* Hashtable support for memory references used by gimple - statements. */ - -/* This type represents a reference to a memory region. */ -struct asan_mem_ref -{ - /* The expression of the begining of the memory region. */ - tree start; - - /* The size of the access (can be 1, 2, 4, 8, 16 for now). */ - char access_size; -}; - -static alloc_pool asan_mem_ref_alloc_pool; - -/* This creates the alloc pool used to store the instances of - asan_mem_ref that are stored in the hash table asan_mem_ref_ht. */ - -static alloc_pool -asan_mem_ref_get_alloc_pool () -{ - if (asan_mem_ref_alloc_pool == NULL) - asan_mem_ref_alloc_pool = create_alloc_pool ("asan_mem_ref", - sizeof (asan_mem_ref), - 10); - return asan_mem_ref_alloc_pool; - -} - -/* Initializes an instance of asan_mem_ref. */ - -static void -asan_mem_ref_init (asan_mem_ref *ref, tree start, char access_size) -{ - ref->start = start; - ref->access_size = access_size; -} - -/* Allocates memory for an instance of asan_mem_ref into the memory - pool returned by asan_mem_ref_get_alloc_pool and initialize it. - START is the address of (or the expression pointing to) the - beginning of memory reference. ACCESS_SIZE is the size of the - access to the referenced memory. */ - -static asan_mem_ref* -asan_mem_ref_new (tree start, char access_size) -{ - asan_mem_ref *ref = - (asan_mem_ref *) pool_alloc (asan_mem_ref_get_alloc_pool ()); - - asan_mem_ref_init (ref, start, access_size); - return ref; -} - -/* This builds and returns a pointer to the end of the memory region - that starts at START and of length LEN. */ - -tree -asan_mem_ref_get_end (tree start, tree len) -{ - if (len == NULL_TREE || integer_zerop (len)) - return start; - - return fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (start), start, len); -} - -/* Return a tree expression that represents the end of the referenced - memory region. Beware that this function can actually build a new - tree expression. */ - -tree -asan_mem_ref_get_end (const asan_mem_ref *ref, tree len) -{ - return asan_mem_ref_get_end (ref->start, len); -} - -struct asan_mem_ref_hasher - : typed_noop_remove <asan_mem_ref> -{ - typedef asan_mem_ref value_type; - typedef asan_mem_ref compare_type; - - static inline hashval_t hash (const value_type *); - static inline bool equal (const value_type *, const compare_type *); -}; - -/* Hash a memory reference. */ - -inline hashval_t -asan_mem_ref_hasher::hash (const asan_mem_ref *mem_ref) -{ - hashval_t h = iterative_hash_expr (mem_ref->start, 0); - h = iterative_hash_hashval_t (h, mem_ref->access_size); - return h; -} - -/* Compare two memory references. We accept the length of either - memory references to be NULL_TREE. */ - -inline bool -asan_mem_ref_hasher::equal (const asan_mem_ref *m1, - const asan_mem_ref *m2) -{ - return (m1->access_size == m2->access_size - && operand_equal_p (m1->start, m2->start, 0)); -} - -static hash_table <asan_mem_ref_hasher> asan_mem_ref_ht; - -/* Returns a reference to the hash table containing memory references. - This function ensures that the hash table is created. Note that - this hash table is updated by the function - update_mem_ref_hash_table. */ - -static hash_table <asan_mem_ref_hasher> & -get_mem_ref_hash_table () -{ - if (!asan_mem_ref_ht.is_created ()) - asan_mem_ref_ht.create (10); - - return asan_mem_ref_ht; -} - -/* Clear all entries from the memory references hash table. */ - -static void -empty_mem_ref_hash_table () -{ - if (asan_mem_ref_ht.is_created ()) - asan_mem_ref_ht.empty (); -} - -/* Free the memory references hash table. */ - -static void -free_mem_ref_resources () -{ - if (asan_mem_ref_ht.is_created ()) - asan_mem_ref_ht.dispose (); - - if (asan_mem_ref_alloc_pool) - { - free_alloc_pool (asan_mem_ref_alloc_pool); - asan_mem_ref_alloc_pool = NULL; - } -} - -/* Return true iff the memory reference REF has been instrumented. */ - -static bool -has_mem_ref_been_instrumented (tree ref, char access_size) -{ - asan_mem_ref r; - asan_mem_ref_init (&r, ref, access_size); - - return (get_mem_ref_hash_table ().find (&r) != NULL); -} - -/* Return true iff the memory reference REF has been instrumented. */ - -static bool -has_mem_ref_been_instrumented (const asan_mem_ref *ref) -{ - return has_mem_ref_been_instrumented (ref->start, ref->access_size); -} - -/* Return true iff access to memory region starting at REF and of - length LEN has been instrumented. */ - -static bool -has_mem_ref_been_instrumented (const asan_mem_ref *ref, tree len) -{ - /* First let's see if the address of the beginning of REF has been - instrumented. */ - if (!has_mem_ref_been_instrumented (ref)) - return false; - - if (len != 0) - { - /* Let's see if the end of the region has been instrumented. */ - if (!has_mem_ref_been_instrumented (asan_mem_ref_get_end (ref, len), - ref->access_size)) - return false; - } - return true; -} - -/* Set REF to the memory reference present in a gimple assignment - ASSIGNMENT. Return true upon successful completion, false - otherwise. */ - -static bool -get_mem_ref_of_assignment (const gimple assignment, - asan_mem_ref *ref, - bool *ref_is_store) -{ - gcc_assert (gimple_assign_single_p (assignment)); - - if (gimple_store_p (assignment)) - { - ref->start = gimple_assign_lhs (assignment); - *ref_is_store = true; - } - else if (gimple_assign_load_p (assignment)) - { - ref->start = gimple_assign_rhs1 (assignment); - *ref_is_store = false; - } - else - return false; - - ref->access_size = int_size_in_bytes (TREE_TYPE (ref->start)); - return true; -} - -/* Return the memory references contained in a gimple statement - representing a builtin call that has to do with memory access. */ - -static bool -get_mem_refs_of_builtin_call (const gimple call, - asan_mem_ref *src0, - tree *src0_len, - bool *src0_is_store, - asan_mem_ref *src1, - tree *src1_len, - bool *src1_is_store, - asan_mem_ref *dst, - tree *dst_len, - bool *dst_is_store, - bool *dest_is_deref) -{ - gcc_checking_assert (gimple_call_builtin_p (call, BUILT_IN_NORMAL)); - - tree callee = gimple_call_fndecl (call); - tree source0 = NULL_TREE, source1 = NULL_TREE, - dest = NULL_TREE, len = NULL_TREE; - bool is_store = true, got_reference_p = false; - char access_size = 1; - - switch (DECL_FUNCTION_CODE (callee)) - { - /* (s, s, n) style memops. */ - case BUILT_IN_BCMP: - case BUILT_IN_MEMCMP: - source0 = gimple_call_arg (call, 0); - source1 = gimple_call_arg (call, 1); - len = gimple_call_arg (call, 2); - break; - - /* (src, dest, n) style memops. */ - case BUILT_IN_BCOPY: - source0 = gimple_call_arg (call, 0); - dest = gimple_call_arg (call, 1); - len = gimple_call_arg (call, 2); - break; - - /* (dest, src, n) style memops. */ - case BUILT_IN_MEMCPY: - case BUILT_IN_MEMCPY_CHK: - case BUILT_IN_MEMMOVE: - case BUILT_IN_MEMMOVE_CHK: - case BUILT_IN_MEMPCPY: - case BUILT_IN_MEMPCPY_CHK: - dest = gimple_call_arg (call, 0); - source0 = gimple_call_arg (call, 1); - len = gimple_call_arg (call, 2); - break; - - /* (dest, n) style memops. */ - case BUILT_IN_BZERO: - dest = gimple_call_arg (call, 0); - len = gimple_call_arg (call, 1); - break; - - /* (dest, x, n) style memops*/ - case BUILT_IN_MEMSET: - case BUILT_IN_MEMSET_CHK: - dest = gimple_call_arg (call, 0); - len = gimple_call_arg (call, 2); - break; - - case BUILT_IN_STRLEN: - source0 = gimple_call_arg (call, 0); - len = gimple_call_lhs (call); - break ; - - /* And now the __atomic* and __sync builtins. - These are handled differently from the classical memory memory - access builtins above. */ - - case BUILT_IN_ATOMIC_LOAD_1: - case BUILT_IN_ATOMIC_LOAD_2: - case BUILT_IN_ATOMIC_LOAD_4: - case BUILT_IN_ATOMIC_LOAD_8: - case BUILT_IN_ATOMIC_LOAD_16: - is_store = false; - /* fall through. */ - - case BUILT_IN_SYNC_FETCH_AND_ADD_1: - case BUILT_IN_SYNC_FETCH_AND_ADD_2: - case BUILT_IN_SYNC_FETCH_AND_ADD_4: - case BUILT_IN_SYNC_FETCH_AND_ADD_8: - case BUILT_IN_SYNC_FETCH_AND_ADD_16: - - case BUILT_IN_SYNC_FETCH_AND_SUB_1: - case BUILT_IN_SYNC_FETCH_AND_SUB_2: - case BUILT_IN_SYNC_FETCH_AND_SUB_4: - case BUILT_IN_SYNC_FETCH_AND_SUB_8: - case BUILT_IN_SYNC_FETCH_AND_SUB_16: - - case BUILT_IN_SYNC_FETCH_AND_OR_1: - case BUILT_IN_SYNC_FETCH_AND_OR_2: - case BUILT_IN_SYNC_FETCH_AND_OR_4: - case BUILT_IN_SYNC_FETCH_AND_OR_8: - case BUILT_IN_SYNC_FETCH_AND_OR_16: - - case BUILT_IN_SYNC_FETCH_AND_AND_1: - case BUILT_IN_SYNC_FETCH_AND_AND_2: - case BUILT_IN_SYNC_FETCH_AND_AND_4: - case BUILT_IN_SYNC_FETCH_AND_AND_8: - case BUILT_IN_SYNC_FETCH_AND_AND_16: - - case BUILT_IN_SYNC_FETCH_AND_XOR_1: - case BUILT_IN_SYNC_FETCH_AND_XOR_2: - case BUILT_IN_SYNC_FETCH_AND_XOR_4: - case BUILT_IN_SYNC_FETCH_AND_XOR_8: - case BUILT_IN_SYNC_FETCH_AND_XOR_16: - - case BUILT_IN_SYNC_FETCH_AND_NAND_1: - case BUILT_IN_SYNC_FETCH_AND_NAND_2: - case BUILT_IN_SYNC_FETCH_AND_NAND_4: - case BUILT_IN_SYNC_FETCH_AND_NAND_8: - - case BUILT_IN_SYNC_ADD_AND_FETCH_1: - case BUILT_IN_SYNC_ADD_AND_FETCH_2: - case BUILT_IN_SYNC_ADD_AND_FETCH_4: - case BUILT_IN_SYNC_ADD_AND_FETCH_8: - case BUILT_IN_SYNC_ADD_AND_FETCH_16: - - case BUILT_IN_SYNC_SUB_AND_FETCH_1: - case BUILT_IN_SYNC_SUB_AND_FETCH_2: - case BUILT_IN_SYNC_SUB_AND_FETCH_4: - case BUILT_IN_SYNC_SUB_AND_FETCH_8: - case BUILT_IN_SYNC_SUB_AND_FETCH_16: - - case BUILT_IN_SYNC_OR_AND_FETCH_1: - case BUILT_IN_SYNC_OR_AND_FETCH_2: - case BUILT_IN_SYNC_OR_AND_FETCH_4: - case BUILT_IN_SYNC_OR_AND_FETCH_8: - case BUILT_IN_SYNC_OR_AND_FETCH_16: - - case BUILT_IN_SYNC_AND_AND_FETCH_1: - case BUILT_IN_SYNC_AND_AND_FETCH_2: - case BUILT_IN_SYNC_AND_AND_FETCH_4: - case BUILT_IN_SYNC_AND_AND_FETCH_8: - case BUILT_IN_SYNC_AND_AND_FETCH_16: - - case BUILT_IN_SYNC_XOR_AND_FETCH_1: - case BUILT_IN_SYNC_XOR_AND_FETCH_2: - case BUILT_IN_SYNC_XOR_AND_FETCH_4: - case BUILT_IN_SYNC_XOR_AND_FETCH_8: - case BUILT_IN_SYNC_XOR_AND_FETCH_16: - - case BUILT_IN_SYNC_NAND_AND_FETCH_1: - case BUILT_IN_SYNC_NAND_AND_FETCH_2: - case BUILT_IN_SYNC_NAND_AND_FETCH_4: - case BUILT_IN_SYNC_NAND_AND_FETCH_8: - - case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_1: - case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_2: - case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_4: - case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_8: - case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_16: - - case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_1: - case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_2: - case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_4: - case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_8: - case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_16: - - case BUILT_IN_SYNC_LOCK_TEST_AND_SET_1: - case BUILT_IN_SYNC_LOCK_TEST_AND_SET_2: - case BUILT_IN_SYNC_LOCK_TEST_AND_SET_4: - case BUILT_IN_SYNC_LOCK_TEST_AND_SET_8: - case BUILT_IN_SYNC_LOCK_TEST_AND_SET_16: - - case BUILT_IN_SYNC_LOCK_RELEASE_1: - case BUILT_IN_SYNC_LOCK_RELEASE_2: - case BUILT_IN_SYNC_LOCK_RELEASE_4: - case BUILT_IN_SYNC_LOCK_RELEASE_8: - case BUILT_IN_SYNC_LOCK_RELEASE_16: - - case BUILT_IN_ATOMIC_EXCHANGE_1: - case BUILT_IN_ATOMIC_EXCHANGE_2: - case BUILT_IN_ATOMIC_EXCHANGE_4: - case BUILT_IN_ATOMIC_EXCHANGE_8: - case BUILT_IN_ATOMIC_EXCHANGE_16: - - case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_1: - case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_2: - case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_4: - case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_8: - case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_16: - - case BUILT_IN_ATOMIC_STORE_1: - case BUILT_IN_ATOMIC_STORE_2: - case BUILT_IN_ATOMIC_STORE_4: - case BUILT_IN_ATOMIC_STORE_8: - case BUILT_IN_ATOMIC_STORE_16: - - case BUILT_IN_ATOMIC_ADD_FETCH_1: - case BUILT_IN_ATOMIC_ADD_FETCH_2: - case BUILT_IN_ATOMIC_ADD_FETCH_4: - case BUILT_IN_ATOMIC_ADD_FETCH_8: - case BUILT_IN_ATOMIC_ADD_FETCH_16: - - case BUILT_IN_ATOMIC_SUB_FETCH_1: - case BUILT_IN_ATOMIC_SUB_FETCH_2: - case BUILT_IN_ATOMIC_SUB_FETCH_4: - case BUILT_IN_ATOMIC_SUB_FETCH_8: - case BUILT_IN_ATOMIC_SUB_FETCH_16: - - case BUILT_IN_ATOMIC_AND_FETCH_1: - case BUILT_IN_ATOMIC_AND_FETCH_2: - case BUILT_IN_ATOMIC_AND_FETCH_4: - case BUILT_IN_ATOMIC_AND_FETCH_8: - case BUILT_IN_ATOMIC_AND_FETCH_16: - - case BUILT_IN_ATOMIC_NAND_FETCH_1: - case BUILT_IN_ATOMIC_NAND_FETCH_2: - case BUILT_IN_ATOMIC_NAND_FETCH_4: - case BUILT_IN_ATOMIC_NAND_FETCH_8: - case BUILT_IN_ATOMIC_NAND_FETCH_16: - - case BUILT_IN_ATOMIC_XOR_FETCH_1: - case BUILT_IN_ATOMIC_XOR_FETCH_2: - case BUILT_IN_ATOMIC_XOR_FETCH_4: - case BUILT_IN_ATOMIC_XOR_FETCH_8: - case BUILT_IN_ATOMIC_XOR_FETCH_16: - - case BUILT_IN_ATOMIC_OR_FETCH_1: - case BUILT_IN_ATOMIC_OR_FETCH_2: - case BUILT_IN_ATOMIC_OR_FETCH_4: - case BUILT_IN_ATOMIC_OR_FETCH_8: - case BUILT_IN_ATOMIC_OR_FETCH_16: - - case BUILT_IN_ATOMIC_FETCH_ADD_1: - case BUILT_IN_ATOMIC_FETCH_ADD_2: - case BUILT_IN_ATOMIC_FETCH_ADD_4: - case BUILT_IN_ATOMIC_FETCH_ADD_8: - case BUILT_IN_ATOMIC_FETCH_ADD_16: - - case BUILT_IN_ATOMIC_FETCH_SUB_1: - case BUILT_IN_ATOMIC_FETCH_SUB_2: - case BUILT_IN_ATOMIC_FETCH_SUB_4: - case BUILT_IN_ATOMIC_FETCH_SUB_8: - case BUILT_IN_ATOMIC_FETCH_SUB_16: - - case BUILT_IN_ATOMIC_FETCH_AND_1: - case BUILT_IN_ATOMIC_FETCH_AND_2: - case BUILT_IN_ATOMIC_FETCH_AND_4: - case BUILT_IN_ATOMIC_FETCH_AND_8: - case BUILT_IN_ATOMIC_FETCH_AND_16: - - case BUILT_IN_ATOMIC_FETCH_NAND_1: - case BUILT_IN_ATOMIC_FETCH_NAND_2: - case BUILT_IN_ATOMIC_FETCH_NAND_4: - case BUILT_IN_ATOMIC_FETCH_NAND_8: - case BUILT_IN_ATOMIC_FETCH_NAND_16: - - case BUILT_IN_ATOMIC_FETCH_XOR_1: - case BUILT_IN_ATOMIC_FETCH_XOR_2: - case BUILT_IN_ATOMIC_FETCH_XOR_4: - case BUILT_IN_ATOMIC_FETCH_XOR_8: - case BUILT_IN_ATOMIC_FETCH_XOR_16: - - case BUILT_IN_ATOMIC_FETCH_OR_1: - case BUILT_IN_ATOMIC_FETCH_OR_2: - case BUILT_IN_ATOMIC_FETCH_OR_4: - case BUILT_IN_ATOMIC_FETCH_OR_8: - case BUILT_IN_ATOMIC_FETCH_OR_16: - { - dest = gimple_call_arg (call, 0); - /* DEST represents the address of a memory location. - instrument_derefs wants the memory location, so lets - dereference the address DEST before handing it to - instrument_derefs. */ - if (TREE_CODE (dest) == ADDR_EXPR) - dest = TREE_OPERAND (dest, 0); - else if (TREE_CODE (dest) == SSA_NAME) - dest = build2 (MEM_REF, TREE_TYPE (TREE_TYPE (dest)), - dest, build_int_cst (TREE_TYPE (dest), 0)); - else - gcc_unreachable (); - - access_size = int_size_in_bytes (TREE_TYPE (dest)); - } - - default: - /* The other builtins memory access are not instrumented in this - function because they either don't have any length parameter, - or their length parameter is just a limit. */ - break; - } - - if (len != NULL_TREE) - { - if (source0 != NULL_TREE) - { - src0->start = source0; - src0->access_size = access_size; - *src0_len = len; - *src0_is_store = false; - } - - if (source1 != NULL_TREE) - { - src1->start = source1; - src1->access_size = access_size; - *src1_len = len; - *src1_is_store = false; - } - - if (dest != NULL_TREE) - { - dst->start = dest; - dst->access_size = access_size; - *dst_len = len; - *dst_is_store = true; - } - - got_reference_p = true; - } - else if (dest) - { - dst->start = dest; - dst->access_size = access_size; - *dst_len = NULL_TREE; - *dst_is_store = is_store; - *dest_is_deref = true; - got_reference_p = true; - } - - return got_reference_p; -} - -/* Return true iff a given gimple statement has been instrumented. - Note that the statement is "defined" by the memory references it - contains. */ - -static bool -has_stmt_been_instrumented_p (gimple stmt) -{ - if (gimple_assign_single_p (stmt)) - { - bool r_is_store; - asan_mem_ref r; - asan_mem_ref_init (&r, NULL, 1); - - if (get_mem_ref_of_assignment (stmt, &r, &r_is_store)) - return has_mem_ref_been_instrumented (&r); - } - else if (gimple_call_builtin_p (stmt, BUILT_IN_NORMAL)) - { - asan_mem_ref src0, src1, dest; - asan_mem_ref_init (&src0, NULL, 1); - asan_mem_ref_init (&src1, NULL, 1); - asan_mem_ref_init (&dest, NULL, 1); - - tree src0_len = NULL_TREE, src1_len = NULL_TREE, dest_len = NULL_TREE; - bool src0_is_store = false, src1_is_store = false, - dest_is_store = false, dest_is_deref = false; - if (get_mem_refs_of_builtin_call (stmt, - &src0, &src0_len, &src0_is_store, - &src1, &src1_len, &src1_is_store, - &dest, &dest_len, &dest_is_store, - &dest_is_deref)) - { - if (src0.start != NULL_TREE - && !has_mem_ref_been_instrumented (&src0, src0_len)) - return false; - - if (src1.start != NULL_TREE - && !has_mem_ref_been_instrumented (&src1, src1_len)) - return false; - - if (dest.start != NULL_TREE - && !has_mem_ref_been_instrumented (&dest, dest_len)) - return false; - - return true; - } - } - return false; -} - -/* Insert a memory reference into the hash table. */ - -static void -update_mem_ref_hash_table (tree ref, char access_size) -{ - hash_table <asan_mem_ref_hasher> ht = get_mem_ref_hash_table (); - - asan_mem_ref r; - asan_mem_ref_init (&r, ref, access_size); - - asan_mem_ref **slot = ht.find_slot (&r, INSERT); - if (*slot == NULL) - *slot = asan_mem_ref_new (ref, access_size); -} - -/* Initialize shadow_ptr_types array. */ - -static void -asan_init_shadow_ptr_types (void) -{ - asan_shadow_set = new_alias_set (); - shadow_ptr_types[0] = build_distinct_type_copy (signed_char_type_node); - TYPE_ALIAS_SET (shadow_ptr_types[0]) = asan_shadow_set; - shadow_ptr_types[0] = build_pointer_type (shadow_ptr_types[0]); - shadow_ptr_types[1] = build_distinct_type_copy (short_integer_type_node); - TYPE_ALIAS_SET (shadow_ptr_types[1]) = asan_shadow_set; - shadow_ptr_types[1] = build_pointer_type (shadow_ptr_types[1]); - initialize_sanitizer_builtins (); -} - -/* Asan pretty-printer, used for buidling of the description STRING_CSTs. */ -static pretty_printer asan_pp; -static bool asan_pp_initialized; - -/* Initialize asan_pp. */ - -static void -asan_pp_initialize (void) -{ - pp_construct (&asan_pp, /* prefix */NULL, /* line-width */0); - asan_pp_initialized = true; -} - -/* Create ADDR_EXPR of STRING_CST with asan_pp text. */ - -static tree -asan_pp_string (void) -{ - const char *buf = pp_base_formatted_text (&asan_pp); - size_t len = strlen (buf); - tree ret = build_string (len + 1, buf); - TREE_TYPE (ret) - = build_array_type (TREE_TYPE (shadow_ptr_types[0]), - build_index_type (size_int (len))); - TREE_READONLY (ret) = 1; - TREE_STATIC (ret) = 1; - return build1 (ADDR_EXPR, shadow_ptr_types[0], ret); -} - -/* Return a CONST_INT representing 4 subsequent shadow memory bytes. */ - -static rtx -asan_shadow_cst (unsigned char shadow_bytes[4]) -{ - int i; - unsigned HOST_WIDE_INT val = 0; - gcc_assert (WORDS_BIG_ENDIAN == BYTES_BIG_ENDIAN); - for (i = 0; i < 4; i++) - val |= (unsigned HOST_WIDE_INT) shadow_bytes[BYTES_BIG_ENDIAN ? 3 - i : i] - << (BITS_PER_UNIT * i); - return GEN_INT (trunc_int_for_mode (val, SImode)); -} - -/* Clear shadow memory at SHADOW_MEM, LEN bytes. Can't call a library call here - though. */ - -static void -asan_clear_shadow (rtx shadow_mem, HOST_WIDE_INT len) -{ - rtx insn, insns, top_label, end, addr, tmp, jump; - - start_sequence (); - clear_storage (shadow_mem, GEN_INT (len), BLOCK_OP_NORMAL); - insns = get_insns (); - end_sequence (); - for (insn = insns; insn; insn = NEXT_INSN (insn)) - if (CALL_P (insn)) - break; - if (insn == NULL_RTX) - { - emit_insn (insns); - return; - } - - gcc_assert ((len & 3) == 0); - top_label = gen_label_rtx (); - addr = force_reg (Pmode, XEXP (shadow_mem, 0)); - shadow_mem = adjust_automodify_address (shadow_mem, SImode, addr, 0); - end = force_reg (Pmode, plus_constant (Pmode, addr, len)); - emit_label (top_label); - - emit_move_insn (shadow_mem, const0_rtx); - tmp = expand_simple_binop (Pmode, PLUS, addr, GEN_INT (4), addr, - true, OPTAB_LIB_WIDEN); - if (tmp != addr) - emit_move_insn (addr, tmp); - emit_cmp_and_jump_insns (addr, end, LT, NULL_RTX, Pmode, true, top_label); - jump = get_last_insn (); - gcc_assert (JUMP_P (jump)); - add_reg_note (jump, REG_BR_PROB, GEN_INT (REG_BR_PROB_BASE * 80 / 100)); -} - -/* Insert code to protect stack vars. The prologue sequence should be emitted - directly, epilogue sequence returned. BASE is the register holding the - stack base, against which OFFSETS array offsets are relative to, OFFSETS - array contains pairs of offsets in reverse order, always the end offset - of some gap that needs protection followed by starting offset, - and DECLS is an array of representative decls for each var partition. - LENGTH is the length of the OFFSETS array, DECLS array is LENGTH / 2 - 1 - elements long (OFFSETS include gap before the first variable as well - as gaps after each stack variable). */ - -rtx -asan_emit_stack_protection (rtx base, HOST_WIDE_INT *offsets, tree *decls, - int length) -{ - rtx shadow_base, shadow_mem, ret, mem; - unsigned char shadow_bytes[4]; - HOST_WIDE_INT base_offset = offsets[length - 1], offset, prev_offset; - HOST_WIDE_INT last_offset, last_size; - int l; - unsigned char cur_shadow_byte = ASAN_STACK_MAGIC_LEFT; - tree str_cst; - - if (shadow_ptr_types[0] == NULL_TREE) - asan_init_shadow_ptr_types (); - - /* First of all, prepare the description string. */ - if (!asan_pp_initialized) - asan_pp_initialize (); - - pp_clear_output_area (&asan_pp); - if (DECL_NAME (current_function_decl)) - pp_base_tree_identifier (&asan_pp, DECL_NAME (current_function_decl)); - else - pp_string (&asan_pp, "<unknown>"); - pp_space (&asan_pp); - pp_decimal_int (&asan_pp, length / 2 - 1); - pp_space (&asan_pp); - for (l = length - 2; l; l -= 2) - { - tree decl = decls[l / 2 - 1]; - pp_wide_integer (&asan_pp, offsets[l] - base_offset); - pp_space (&asan_pp); - pp_wide_integer (&asan_pp, offsets[l - 1] - offsets[l]); - pp_space (&asan_pp); - if (DECL_P (decl) && DECL_NAME (decl)) - { - pp_decimal_int (&asan_pp, IDENTIFIER_LENGTH (DECL_NAME (decl))); - pp_space (&asan_pp); - pp_base_tree_identifier (&asan_pp, DECL_NAME (decl)); - } - else - pp_string (&asan_pp, "9 <unknown>"); - pp_space (&asan_pp); - } - str_cst = asan_pp_string (); - - /* Emit the prologue sequence. */ - base = expand_binop (Pmode, add_optab, base, GEN_INT (base_offset), - NULL_RTX, 1, OPTAB_DIRECT); - mem = gen_rtx_MEM (ptr_mode, base); - emit_move_insn (mem, GEN_INT (ASAN_STACK_FRAME_MAGIC)); - mem = adjust_address (mem, VOIDmode, GET_MODE_SIZE (ptr_mode)); - emit_move_insn (mem, expand_normal (str_cst)); - shadow_base = expand_binop (Pmode, lshr_optab, base, - GEN_INT (ASAN_SHADOW_SHIFT), - NULL_RTX, 1, OPTAB_DIRECT); - shadow_base = expand_binop (Pmode, add_optab, shadow_base, - GEN_INT (targetm.asan_shadow_offset ()), - NULL_RTX, 1, OPTAB_DIRECT); - gcc_assert (asan_shadow_set != -1 - && (ASAN_RED_ZONE_SIZE >> ASAN_SHADOW_SHIFT) == 4); - shadow_mem = gen_rtx_MEM (SImode, shadow_base); - set_mem_alias_set (shadow_mem, asan_shadow_set); - prev_offset = base_offset; - for (l = length; l; l -= 2) - { - if (l == 2) - cur_shadow_byte = ASAN_STACK_MAGIC_RIGHT; - offset = offsets[l - 1]; - if ((offset - base_offset) & (ASAN_RED_ZONE_SIZE - 1)) - { - int i; - HOST_WIDE_INT aoff - = base_offset + ((offset - base_offset) - & ~(ASAN_RED_ZONE_SIZE - HOST_WIDE_INT_1)); - shadow_mem = adjust_address (shadow_mem, VOIDmode, - (aoff - prev_offset) - >> ASAN_SHADOW_SHIFT); - prev_offset = aoff; - for (i = 0; i < 4; i++, aoff += (1 << ASAN_SHADOW_SHIFT)) - if (aoff < offset) - { - if (aoff < offset - (1 << ASAN_SHADOW_SHIFT) + 1) - shadow_bytes[i] = 0; - else - shadow_bytes[i] = offset - aoff; - } - else - shadow_bytes[i] = ASAN_STACK_MAGIC_PARTIAL; - emit_move_insn (shadow_mem, asan_shadow_cst (shadow_bytes)); - offset = aoff; - } - while (offset <= offsets[l - 2] - ASAN_RED_ZONE_SIZE) - { - shadow_mem = adjust_address (shadow_mem, VOIDmode, - (offset - prev_offset) - >> ASAN_SHADOW_SHIFT); - prev_offset = offset; - memset (shadow_bytes, cur_shadow_byte, 4); - emit_move_insn (shadow_mem, asan_shadow_cst (shadow_bytes)); - offset += ASAN_RED_ZONE_SIZE; - } - cur_shadow_byte = ASAN_STACK_MAGIC_MIDDLE; - } - do_pending_stack_adjust (); - - /* Construct epilogue sequence. */ - start_sequence (); - - shadow_mem = gen_rtx_MEM (BLKmode, shadow_base); - set_mem_alias_set (shadow_mem, asan_shadow_set); - prev_offset = base_offset; - last_offset = base_offset; - last_size = 0; - for (l = length; l; l -= 2) - { - offset = base_offset + ((offsets[l - 1] - base_offset) - & ~(ASAN_RED_ZONE_SIZE - HOST_WIDE_INT_1)); - if (last_offset + last_size != offset) - { - shadow_mem = adjust_address (shadow_mem, VOIDmode, - (last_offset - prev_offset) - >> ASAN_SHADOW_SHIFT); - prev_offset = last_offset; - asan_clear_shadow (shadow_mem, last_size >> ASAN_SHADOW_SHIFT); - last_offset = offset; - last_size = 0; - } - last_size += base_offset + ((offsets[l - 2] - base_offset) - & ~(ASAN_RED_ZONE_SIZE - HOST_WIDE_INT_1)) - - offset; - } - if (last_size) - { - shadow_mem = adjust_address (shadow_mem, VOIDmode, - (last_offset - prev_offset) - >> ASAN_SHADOW_SHIFT); - asan_clear_shadow (shadow_mem, last_size >> ASAN_SHADOW_SHIFT); - } - - do_pending_stack_adjust (); - - ret = get_insns (); - end_sequence (); - return ret; -} - -/* Return true if DECL, a global var, might be overridden and needs - therefore a local alias. */ - -static bool -asan_needs_local_alias (tree decl) -{ - return DECL_WEAK (decl) || !targetm.binds_local_p (decl); -} - -/* Return true if DECL is a VAR_DECL that should be protected - by Address Sanitizer, by appending a red zone with protected - shadow memory after it and aligning it to at least - ASAN_RED_ZONE_SIZE bytes. */ - -bool -asan_protect_global (tree decl) -{ - rtx rtl, symbol; - - if (TREE_CODE (decl) == STRING_CST) - { - /* Instrument all STRING_CSTs except those created - by asan_pp_string here. */ - if (shadow_ptr_types[0] != NULL_TREE - && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE - && TREE_TYPE (TREE_TYPE (decl)) == TREE_TYPE (shadow_ptr_types[0])) - return false; - return true; - } - if (TREE_CODE (decl) != VAR_DECL - /* TLS vars aren't statically protectable. */ - || DECL_THREAD_LOCAL_P (decl) - /* Externs will be protected elsewhere. */ - || DECL_EXTERNAL (decl) - || !DECL_RTL_SET_P (decl) - /* Comdat vars pose an ABI problem, we can't know if - the var that is selected by the linker will have - padding or not. */ - || DECL_ONE_ONLY (decl) - /* Similarly for common vars. People can use -fno-common. */ - || (DECL_COMMON (decl) && TREE_PUBLIC (decl)) - /* Don't protect if using user section, often vars placed - into user section from multiple TUs are then assumed - to be an array of such vars, putting padding in there - breaks this assumption. */ - || (DECL_SECTION_NAME (decl) != NULL_TREE - && !DECL_HAS_IMPLICIT_SECTION_NAME_P (decl)) - || DECL_SIZE (decl) == 0 - || ASAN_RED_ZONE_SIZE * BITS_PER_UNIT > MAX_OFILE_ALIGNMENT - || !valid_constant_size_p (DECL_SIZE_UNIT (decl)) - || DECL_ALIGN_UNIT (decl) > 2 * ASAN_RED_ZONE_SIZE) - return false; - - rtl = DECL_RTL (decl); - if (!MEM_P (rtl) || GET_CODE (XEXP (rtl, 0)) != SYMBOL_REF) - return false; - symbol = XEXP (rtl, 0); - - if (CONSTANT_POOL_ADDRESS_P (symbol) - || TREE_CONSTANT_POOL_ADDRESS_P (symbol)) - return false; - - if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl))) - return false; - -#ifndef ASM_OUTPUT_DEF - if (asan_needs_local_alias (decl)) - return false; -#endif - - return true; -} - -/* Construct a function tree for __asan_report_{load,store}{1,2,4,8,16}. - IS_STORE is either 1 (for a store) or 0 (for a load). - SIZE_IN_BYTES is one of 1, 2, 4, 8, 16. */ - -static tree -report_error_func (bool is_store, int size_in_bytes) -{ - static enum built_in_function report[2][5] - = { { BUILT_IN_ASAN_REPORT_LOAD1, BUILT_IN_ASAN_REPORT_LOAD2, - BUILT_IN_ASAN_REPORT_LOAD4, BUILT_IN_ASAN_REPORT_LOAD8, - BUILT_IN_ASAN_REPORT_LOAD16 }, - { BUILT_IN_ASAN_REPORT_STORE1, BUILT_IN_ASAN_REPORT_STORE2, - BUILT_IN_ASAN_REPORT_STORE4, BUILT_IN_ASAN_REPORT_STORE8, - BUILT_IN_ASAN_REPORT_STORE16 } }; - return builtin_decl_implicit (report[is_store][exact_log2 (size_in_bytes)]); -} - -#define PROB_VERY_UNLIKELY (REG_BR_PROB_BASE / 2000 - 1) -#define PROB_ALWAYS (REG_BR_PROB_BASE) - -/* Split the current basic block and create a condition statement - insertion point right before or after the statement pointed to by - ITER. Return an iterator to the point at which the caller might - safely insert the condition statement. - - THEN_BLOCK must be set to the address of an uninitialized instance - of basic_block. The function will then set *THEN_BLOCK to the - 'then block' of the condition statement to be inserted by the - caller. - - If CREATE_THEN_FALLTHRU_EDGE is false, no edge will be created from - *THEN_BLOCK to *FALLTHROUGH_BLOCK. - - Similarly, the function will set *FALLTRHOUGH_BLOCK to the 'else - block' of the condition statement to be inserted by the caller. - - Note that *FALLTHROUGH_BLOCK is a new block that contains the - statements starting from *ITER, and *THEN_BLOCK is a new empty - block. - - *ITER is adjusted to point to always point to the first statement - of the basic block * FALLTHROUGH_BLOCK. That statement is the - same as what ITER was pointing to prior to calling this function, - if BEFORE_P is true; otherwise, it is its following statement. */ - -static gimple_stmt_iterator -create_cond_insert_point (gimple_stmt_iterator *iter, - bool before_p, - bool then_more_likely_p, - bool create_then_fallthru_edge, - basic_block *then_block, - basic_block *fallthrough_block) -{ - gimple_stmt_iterator gsi = *iter; - - if (!gsi_end_p (gsi) && before_p) - gsi_prev (&gsi); - - basic_block cur_bb = gsi_bb (*iter); - - edge e = split_block (cur_bb, gsi_stmt (gsi)); - - /* Get a hold on the 'condition block', the 'then block' and the - 'else block'. */ - basic_block cond_bb = e->src; - basic_block fallthru_bb = e->dest; - basic_block then_bb = create_empty_bb (cond_bb); - - /* Set up the newly created 'then block'. */ - e = make_edge (cond_bb, then_bb, EDGE_TRUE_VALUE); - int fallthrough_probability - = then_more_likely_p - ? PROB_VERY_UNLIKELY - : PROB_ALWAYS - PROB_VERY_UNLIKELY; - e->probability = PROB_ALWAYS - fallthrough_probability; - if (create_then_fallthru_edge) - make_single_succ_edge (then_bb, fallthru_bb, EDGE_FALLTHRU); - - /* Set up the fallthrough basic block. */ - e = find_edge (cond_bb, fallthru_bb); - e->flags = EDGE_FALSE_VALUE; - e->count = cond_bb->count; - e->probability = fallthrough_probability; - - /* Update dominance info for the newly created then_bb; note that - fallthru_bb's dominance info has already been updated by - split_bock. */ - if (dom_info_available_p (CDI_DOMINATORS)) - set_immediate_dominator (CDI_DOMINATORS, then_bb, cond_bb); - - *then_block = then_bb; - *fallthrough_block = fallthru_bb; - *iter = gsi_start_bb (fallthru_bb); - - return gsi_last_bb (cond_bb); -} - -/* Insert an if condition followed by a 'then block' right before the - statement pointed to by ITER. The fallthrough block -- which is the - else block of the condition as well as the destination of the - outcoming edge of the 'then block' -- starts with the statement - pointed to by ITER. - - COND is the condition of the if. - - If THEN_MORE_LIKELY_P is true, the probability of the edge to the - 'then block' is higher than the probability of the edge to the - fallthrough block. - - Upon completion of the function, *THEN_BB is set to the newly - inserted 'then block' and similarly, *FALLTHROUGH_BB is set to the - fallthrough block. - - *ITER is adjusted to still point to the same statement it was - pointing to initially. */ - -static void -insert_if_then_before_iter (gimple cond, - gimple_stmt_iterator *iter, - bool then_more_likely_p, - basic_block *then_bb, - basic_block *fallthrough_bb) -{ - gimple_stmt_iterator cond_insert_point = - create_cond_insert_point (iter, - /*before_p=*/true, - then_more_likely_p, - /*create_then_fallthru_edge=*/true, - then_bb, - fallthrough_bb); - gsi_insert_after (&cond_insert_point, cond, GSI_NEW_STMT); -} - -/* Instrument the memory access instruction BASE. Insert new - statements before or after ITER. - - Note that the memory access represented by BASE can be either an - SSA_NAME, or a non-SSA expression. LOCATION is the source code - location. IS_STORE is TRUE for a store, FALSE for a load. - BEFORE_P is TRUE for inserting the instrumentation code before - ITER, FALSE for inserting it after ITER. SIZE_IN_BYTES is one of - 1, 2, 4, 8, 16. - - If BEFORE_P is TRUE, *ITER is arranged to still point to the - statement it was pointing to prior to calling this function, - otherwise, it points to the statement logically following it. */ - -static void -build_check_stmt (location_t location, tree base, gimple_stmt_iterator *iter, - bool before_p, bool is_store, int size_in_bytes) -{ - gimple_stmt_iterator gsi; - basic_block then_bb, else_bb; - tree t, base_addr, shadow; - gimple g; - tree shadow_ptr_type = shadow_ptr_types[size_in_bytes == 16 ? 1 : 0]; - tree shadow_type = TREE_TYPE (shadow_ptr_type); - tree uintptr_type - = build_nonstandard_integer_type (TYPE_PRECISION (TREE_TYPE (base)), 1); - tree base_ssa = base; - - /* Get an iterator on the point where we can add the condition - statement for the instrumentation. */ - gsi = create_cond_insert_point (iter, before_p, - /*then_more_likely_p=*/false, - /*create_then_fallthru_edge=*/false, - &then_bb, - &else_bb); - - base = unshare_expr (base); - - /* BASE can already be an SSA_NAME; in that case, do not create a - new SSA_NAME for it. */ - if (TREE_CODE (base) != SSA_NAME) - { - g = gimple_build_assign_with_ops (TREE_CODE (base), - make_ssa_name (TREE_TYPE (base), NULL), - base, NULL_TREE); - gimple_set_location (g, location); - gsi_insert_after (&gsi, g, GSI_NEW_STMT); - base_ssa = gimple_assign_lhs (g); - } - - g = gimple_build_assign_with_ops (NOP_EXPR, - make_ssa_name (uintptr_type, NULL), - base_ssa, NULL_TREE); - gimple_set_location (g, location); - gsi_insert_after (&gsi, g, GSI_NEW_STMT); - base_addr = gimple_assign_lhs (g); - - /* Build - (base_addr >> ASAN_SHADOW_SHIFT) + targetm.asan_shadow_offset (). */ - - t = build_int_cst (uintptr_type, ASAN_SHADOW_SHIFT); - g = gimple_build_assign_with_ops (RSHIFT_EXPR, - make_ssa_name (uintptr_type, NULL), - base_addr, t); - gimple_set_location (g, location); - gsi_insert_after (&gsi, g, GSI_NEW_STMT); - - t = build_int_cst (uintptr_type, targetm.asan_shadow_offset ()); - g = gimple_build_assign_with_ops (PLUS_EXPR, - make_ssa_name (uintptr_type, NULL), - gimple_assign_lhs (g), t); - gimple_set_location (g, location); - gsi_insert_after (&gsi, g, GSI_NEW_STMT); - - g = gimple_build_assign_with_ops (NOP_EXPR, - make_ssa_name (shadow_ptr_type, NULL), - gimple_assign_lhs (g), NULL_TREE); - gimple_set_location (g, location); - gsi_insert_after (&gsi, g, GSI_NEW_STMT); - - t = build2 (MEM_REF, shadow_type, gimple_assign_lhs (g), - build_int_cst (shadow_ptr_type, 0)); - g = gimple_build_assign_with_ops (MEM_REF, - make_ssa_name (shadow_type, NULL), - t, NULL_TREE); - gimple_set_location (g, location); - gsi_insert_after (&gsi, g, GSI_NEW_STMT); - shadow = gimple_assign_lhs (g); - - if (size_in_bytes < 8) - { - /* Slow path for 1, 2 and 4 byte accesses. - Test (shadow != 0) - & ((base_addr & 7) + (size_in_bytes - 1)) >= shadow). */ - g = gimple_build_assign_with_ops (NE_EXPR, - make_ssa_name (boolean_type_node, - NULL), - shadow, - build_int_cst (shadow_type, 0)); - gimple_set_location (g, location); - gsi_insert_after (&gsi, g, GSI_NEW_STMT); - t = gimple_assign_lhs (g); - - g = gimple_build_assign_with_ops (BIT_AND_EXPR, - make_ssa_name (uintptr_type, - NULL), - base_addr, - build_int_cst (uintptr_type, 7)); - gimple_set_location (g, location); - gsi_insert_after (&gsi, g, GSI_NEW_STMT); - - g = gimple_build_assign_with_ops (NOP_EXPR, - make_ssa_name (shadow_type, - NULL), - gimple_assign_lhs (g), NULL_TREE); - gimple_set_location (g, location); - gsi_insert_after (&gsi, g, GSI_NEW_STMT); - - if (size_in_bytes > 1) - { - g = gimple_build_assign_with_ops (PLUS_EXPR, - make_ssa_name (shadow_type, - NULL), - gimple_assign_lhs (g), - build_int_cst (shadow_type, - size_in_bytes - 1)); - gimple_set_location (g, location); - gsi_insert_after (&gsi, g, GSI_NEW_STMT); - } - - g = gimple_build_assign_with_ops (GE_EXPR, - make_ssa_name (boolean_type_node, - NULL), - gimple_assign_lhs (g), - shadow); - gimple_set_location (g, location); - gsi_insert_after (&gsi, g, GSI_NEW_STMT); - - g = gimple_build_assign_with_ops (BIT_AND_EXPR, - make_ssa_name (boolean_type_node, - NULL), - t, gimple_assign_lhs (g)); - gimple_set_location (g, location); - gsi_insert_after (&gsi, g, GSI_NEW_STMT); - t = gimple_assign_lhs (g); - } - else - t = shadow; - - g = gimple_build_cond (NE_EXPR, t, build_int_cst (TREE_TYPE (t), 0), - NULL_TREE, NULL_TREE); - gimple_set_location (g, location); - gsi_insert_after (&gsi, g, GSI_NEW_STMT); - - /* Generate call to the run-time library (e.g. __asan_report_load8). */ - gsi = gsi_start_bb (then_bb); - g = gimple_build_call (report_error_func (is_store, size_in_bytes), - 1, base_addr); - gimple_set_location (g, location); - gsi_insert_after (&gsi, g, GSI_NEW_STMT); - - *iter = gsi_start_bb (else_bb); -} - -/* If T represents a memory access, add instrumentation code before ITER. - LOCATION is source code location. - IS_STORE is either TRUE (for a store) or FALSE (for a load). */ - -static void -instrument_derefs (gimple_stmt_iterator *iter, tree t, - location_t location, bool is_store) -{ - tree type, base; - HOST_WIDE_INT size_in_bytes; - - type = TREE_TYPE (t); - switch (TREE_CODE (t)) - { - case ARRAY_REF: - case COMPONENT_REF: - case INDIRECT_REF: - case MEM_REF: - break; - default: - return; - } - - size_in_bytes = int_size_in_bytes (type); - if ((size_in_bytes & (size_in_bytes - 1)) != 0 - || (unsigned HOST_WIDE_INT) size_in_bytes - 1 >= 16) - return; - - HOST_WIDE_INT bitsize, bitpos; - tree offset; - enum machine_mode mode; - int volatilep = 0, unsignedp = 0; - get_inner_reference (t, &bitsize, &bitpos, &offset, - &mode, &unsignedp, &volatilep, false); - if (bitpos % (size_in_bytes * BITS_PER_UNIT) - || bitsize != size_in_bytes * BITS_PER_UNIT) - { - if (TREE_CODE (t) == COMPONENT_REF - && DECL_BIT_FIELD_REPRESENTATIVE (TREE_OPERAND (t, 1)) != NULL_TREE) - { - tree repr = DECL_BIT_FIELD_REPRESENTATIVE (TREE_OPERAND (t, 1)); - instrument_derefs (iter, build3 (COMPONENT_REF, TREE_TYPE (repr), - TREE_OPERAND (t, 0), repr, - NULL_TREE), location, is_store); - } - return; - } - - base = build_fold_addr_expr (t); - if (!has_mem_ref_been_instrumented (base, size_in_bytes)) - { - build_check_stmt (location, base, iter, /*before_p=*/true, - is_store, size_in_bytes); - update_mem_ref_hash_table (base, size_in_bytes); - update_mem_ref_hash_table (t, size_in_bytes); - } - -} - -/* Instrument an access to a contiguous memory region that starts at - the address pointed to by BASE, over a length of LEN (expressed in - the sizeof (*BASE) bytes). ITER points to the instruction before - which the instrumentation instructions must be inserted. LOCATION - is the source location that the instrumentation instructions must - have. If IS_STORE is true, then the memory access is a store; - otherwise, it's a load. */ - -static void -instrument_mem_region_access (tree base, tree len, - gimple_stmt_iterator *iter, - location_t location, bool is_store) -{ - if (!POINTER_TYPE_P (TREE_TYPE (base)) - || !INTEGRAL_TYPE_P (TREE_TYPE (len)) - || integer_zerop (len)) - return; - - gimple_stmt_iterator gsi = *iter; - - basic_block fallthrough_bb = NULL, then_bb = NULL; - - /* If the beginning of the memory region has already been - instrumented, do not instrument it. */ - bool start_instrumented = has_mem_ref_been_instrumented (base, 1); - - /* If the end of the memory region has already been instrumented, do - not instrument it. */ - tree end = asan_mem_ref_get_end (base, len); - bool end_instrumented = has_mem_ref_been_instrumented (end, 1); - - if (start_instrumented && end_instrumented) - return; - - if (!is_gimple_constant (len)) - { - /* So, the length of the memory area to asan-protect is - non-constant. Let's guard the generated instrumentation code - like: - - if (len != 0) - { - //asan instrumentation code goes here. - } - // falltrough instructions, starting with *ITER. */ - - gimple g = gimple_build_cond (NE_EXPR, - len, - build_int_cst (TREE_TYPE (len), 0), - NULL_TREE, NULL_TREE); - gimple_set_location (g, location); - insert_if_then_before_iter (g, iter, /*then_more_likely_p=*/true, - &then_bb, &fallthrough_bb); - /* Note that fallthrough_bb starts with the statement that was - pointed to by ITER. */ - - /* The 'then block' of the 'if (len != 0) condition is where - we'll generate the asan instrumentation code now. */ - gsi = gsi_last_bb (then_bb); - } - - if (!start_instrumented) - { - /* Instrument the beginning of the memory region to be accessed, - and arrange for the rest of the intrumentation code to be - inserted in the then block *after* the current gsi. */ - build_check_stmt (location, base, &gsi, /*before_p=*/true, is_store, 1); - - if (then_bb) - /* We are in the case where the length of the region is not - constant; so instrumentation code is being generated in the - 'then block' of the 'if (len != 0) condition. Let's arrange - for the subsequent instrumentation statements to go in the - 'then block'. */ - gsi = gsi_last_bb (then_bb); - else - { - *iter = gsi; - /* Don't remember this access as instrumented, if length - is unknown. It might be zero and not being actually - instrumented, so we can't rely on it being instrumented. */ - update_mem_ref_hash_table (base, 1); - } - } - - if (end_instrumented) - return; - - /* We want to instrument the access at the end of the memory region, - which is at (base + len - 1). */ - - /* offset = len - 1; */ - len = unshare_expr (len); - tree offset; - gimple_seq seq = NULL; - if (TREE_CODE (len) == INTEGER_CST) - offset = fold_build2 (MINUS_EXPR, size_type_node, - fold_convert (size_type_node, len), - build_int_cst (size_type_node, 1)); - else - { - gimple g; - tree t; - - if (TREE_CODE (len) != SSA_NAME) - { - t = make_ssa_name (TREE_TYPE (len), NULL); - g = gimple_build_assign_with_ops (TREE_CODE (len), t, len, NULL); - gimple_set_location (g, location); - gimple_seq_add_stmt_without_update (&seq, g); - len = t; - } - if (!useless_type_conversion_p (size_type_node, TREE_TYPE (len))) - { - t = make_ssa_name (size_type_node, NULL); - g = gimple_build_assign_with_ops (NOP_EXPR, t, len, NULL); - gimple_set_location (g, location); - gimple_seq_add_stmt_without_update (&seq, g); - len = t; - } - - t = make_ssa_name (size_type_node, NULL); - g = gimple_build_assign_with_ops (MINUS_EXPR, t, len, - build_int_cst (size_type_node, 1)); - gimple_set_location (g, location); - gimple_seq_add_stmt_without_update (&seq, g); - offset = gimple_assign_lhs (g); - } - - /* _1 = base; */ - base = unshare_expr (base); - gimple region_end = - gimple_build_assign_with_ops (TREE_CODE (base), - make_ssa_name (TREE_TYPE (base), NULL), - base, NULL); - gimple_set_location (region_end, location); - gimple_seq_add_stmt_without_update (&seq, region_end); - - /* _2 = _1 + offset; */ - region_end = - gimple_build_assign_with_ops (POINTER_PLUS_EXPR, - make_ssa_name (TREE_TYPE (base), NULL), - gimple_assign_lhs (region_end), - offset); - gimple_set_location (region_end, location); - gimple_seq_add_stmt_without_update (&seq, region_end); - gsi_insert_seq_before (&gsi, seq, GSI_SAME_STMT); - - /* instrument access at _2; */ - gsi = gsi_for_stmt (region_end); - build_check_stmt (location, gimple_assign_lhs (region_end), - &gsi, /*before_p=*/false, is_store, 1); - - if (then_bb == NULL) - update_mem_ref_hash_table (end, 1); - - *iter = gsi_for_stmt (gsi_stmt (*iter)); -} - -/* Instrument the call (to the builtin strlen function) pointed to by - ITER. - - This function instruments the access to the first byte of the - argument, right before the call. After the call it instruments the - access to the last byte of the argument; it uses the result of the - call to deduce the offset of that last byte. - - Upon completion, iff the call has actullay been instrumented, this - function returns TRUE and *ITER points to the statement logically - following the built-in strlen function call *ITER was initially - pointing to. Otherwise, the function returns FALSE and *ITER - remains unchanged. */ - -static bool -instrument_strlen_call (gimple_stmt_iterator *iter) -{ - gimple call = gsi_stmt (*iter); - gcc_assert (is_gimple_call (call)); - - tree callee = gimple_call_fndecl (call); - gcc_assert (is_builtin_fn (callee) - && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL - && DECL_FUNCTION_CODE (callee) == BUILT_IN_STRLEN); - - tree len = gimple_call_lhs (call); - if (len == NULL) - /* Some passes might clear the return value of the strlen call; - bail out in that case. Return FALSE as we are not advancing - *ITER. */ - return false; - gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (len))); - - location_t loc = gimple_location (call); - tree str_arg = gimple_call_arg (call, 0); - - /* Instrument the access to the first byte of str_arg. i.e: - - _1 = str_arg; instrument (_1); */ - gimple str_arg_ssa = - gimple_build_assign_with_ops (NOP_EXPR, - make_ssa_name (build_pointer_type - (char_type_node), NULL), - str_arg, NULL); - gimple_set_location (str_arg_ssa, loc); - gimple_stmt_iterator gsi = *iter; - gsi_insert_before (&gsi, str_arg_ssa, GSI_NEW_STMT); - build_check_stmt (loc, gimple_assign_lhs (str_arg_ssa), &gsi, - /*before_p=*/false, /*is_store=*/false, 1); - - /* If we initially had an instruction like: - - int n = strlen (str) - - we now want to instrument the access to str[n], after the - instruction above.*/ - - /* So let's build the access to str[n] that is, access through the - pointer_plus expr: (_1 + len). */ - gimple stmt = - gimple_build_assign_with_ops (POINTER_PLUS_EXPR, - make_ssa_name (TREE_TYPE (str_arg), - NULL), - gimple_assign_lhs (str_arg_ssa), - len); - gimple_set_location (stmt, loc); - gsi_insert_after (&gsi, stmt, GSI_NEW_STMT); - - build_check_stmt (loc, gimple_assign_lhs (stmt), &gsi, - /*before_p=*/false, /*is_store=*/false, 1); - - /* Ensure that iter points to the statement logically following the - one it was initially pointing to. */ - *iter = gsi; - /* As *ITER has been advanced to point to the next statement, let's - return true to inform transform_statements that it shouldn't - advance *ITER anymore; otherwises it will skip that next - statement, which wouldn't be instrumented. */ - return true; -} - -/* Instrument the call to a built-in memory access function that is - pointed to by the iterator ITER. - - Upon completion, return TRUE iff *ITER has been advanced to the - statement following the one it was originally pointing to. */ - -static bool -instrument_builtin_call (gimple_stmt_iterator *iter) -{ - bool iter_advanced_p = false; - gimple call = gsi_stmt (*iter); - - gcc_checking_assert (gimple_call_builtin_p (call, BUILT_IN_NORMAL)); - - tree callee = gimple_call_fndecl (call); - location_t loc = gimple_location (call); - - if (DECL_FUNCTION_CODE (callee) == BUILT_IN_STRLEN) - iter_advanced_p = instrument_strlen_call (iter); - else - { - asan_mem_ref src0, src1, dest; - asan_mem_ref_init (&src0, NULL, 1); - asan_mem_ref_init (&src1, NULL, 1); - asan_mem_ref_init (&dest, NULL, 1); - - tree src0_len = NULL_TREE, src1_len = NULL_TREE, dest_len = NULL_TREE; - bool src0_is_store = false, src1_is_store = false, - dest_is_store = false, dest_is_deref = false; - - if (get_mem_refs_of_builtin_call (call, - &src0, &src0_len, &src0_is_store, - &src1, &src1_len, &src1_is_store, - &dest, &dest_len, &dest_is_store, - &dest_is_deref)) - { - if (dest_is_deref) - { - instrument_derefs (iter, dest.start, loc, dest_is_store); - gsi_next (iter); - iter_advanced_p = true; - } - else if (src0_len || src1_len || dest_len) - { - if (src0.start != NULL_TREE) - instrument_mem_region_access (src0.start, src0_len, - iter, loc, /*is_store=*/false); - if (src1.start != NULL_TREE) - instrument_mem_region_access (src1.start, src1_len, - iter, loc, /*is_store=*/false); - if (dest.start != NULL_TREE) - instrument_mem_region_access (dest.start, dest_len, - iter, loc, /*is_store=*/true); - *iter = gsi_for_stmt (call); - gsi_next (iter); - iter_advanced_p = true; - } - } - } - return iter_advanced_p; -} - -/* Instrument the assignment statement ITER if it is subject to - instrumentation. Return TRUE iff instrumentation actually - happened. In that case, the iterator ITER is advanced to the next - logical expression following the one initially pointed to by ITER, - and the relevant memory reference that which access has been - instrumented is added to the memory references hash table. */ - -static bool -maybe_instrument_assignment (gimple_stmt_iterator *iter) -{ - gimple s = gsi_stmt (*iter); - - gcc_assert (gimple_assign_single_p (s)); - - tree ref_expr = NULL_TREE; - bool is_store, is_instrumented = false; - - if (gimple_store_p (s)) - { - ref_expr = gimple_assign_lhs (s); - is_store = true; - instrument_derefs (iter, ref_expr, - gimple_location (s), - is_store); - is_instrumented = true; - } - - if (gimple_assign_load_p (s)) - { - ref_expr = gimple_assign_rhs1 (s); - is_store = false; - instrument_derefs (iter, ref_expr, - gimple_location (s), - is_store); - is_instrumented = true; - } - - if (is_instrumented) - gsi_next (iter); - - return is_instrumented; -} - -/* Instrument the function call pointed to by the iterator ITER, if it - is subject to instrumentation. At the moment, the only function - calls that are instrumented are some built-in functions that access - memory. Look at instrument_builtin_call to learn more. - - Upon completion return TRUE iff *ITER was advanced to the statement - following the one it was originally pointing to. */ - -static bool -maybe_instrument_call (gimple_stmt_iterator *iter) -{ - gimple stmt = gsi_stmt (*iter); - bool is_builtin = gimple_call_builtin_p (stmt, BUILT_IN_NORMAL); - - if (is_builtin && instrument_builtin_call (iter)) - return true; - - if (gimple_call_noreturn_p (stmt)) - { - if (is_builtin) - { - tree callee = gimple_call_fndecl (stmt); - switch (DECL_FUNCTION_CODE (callee)) - { - case BUILT_IN_UNREACHABLE: - case BUILT_IN_TRAP: - /* Don't instrument these. */ - return false; - } - } - tree decl = builtin_decl_implicit (BUILT_IN_ASAN_HANDLE_NO_RETURN); - gimple g = gimple_build_call (decl, 0); - gimple_set_location (g, gimple_location (stmt)); - gsi_insert_before (iter, g, GSI_SAME_STMT); - } - return false; -} - -/* Walk each instruction of all basic block and instrument those that - represent memory references: loads, stores, or function calls. - In a given basic block, this function avoids instrumenting memory - references that have already been instrumented. */ - -static void -transform_statements (void) -{ - basic_block bb, last_bb = NULL; - gimple_stmt_iterator i; - int saved_last_basic_block = last_basic_block; - - FOR_EACH_BB (bb) - { - basic_block prev_bb = bb; - - if (bb->index >= saved_last_basic_block) continue; - - /* Flush the mem ref hash table, if current bb doesn't have - exactly one predecessor, or if that predecessor (skipping - over asan created basic blocks) isn't the last processed - basic block. Thus we effectively flush on extended basic - block boundaries. */ - while (single_pred_p (prev_bb)) - { - prev_bb = single_pred (prev_bb); - if (prev_bb->index < saved_last_basic_block) - break; - } - if (prev_bb != last_bb) - empty_mem_ref_hash_table (); - last_bb = bb; - - for (i = gsi_start_bb (bb); !gsi_end_p (i);) - { - gimple s = gsi_stmt (i); - - if (has_stmt_been_instrumented_p (s)) - gsi_next (&i); - else if (gimple_assign_single_p (s) - && maybe_instrument_assignment (&i)) - /* Nothing to do as maybe_instrument_assignment advanced - the iterator I. */; - else if (is_gimple_call (s) && maybe_instrument_call (&i)) - /* Nothing to do as maybe_instrument_call - advanced the iterator I. */; - else - { - /* No instrumentation happened. - - If the current instruction is a function call that - might free something, let's forget about the memory - references that got instrumented. Otherwise we might - miss some instrumentation opportunities. */ - if (is_gimple_call (s) && !nonfreeing_call_p (s)) - empty_mem_ref_hash_table (); - - gsi_next (&i); - } - } - } - free_mem_ref_resources (); -} - -/* Build - struct __asan_global - { - const void *__beg; - uptr __size; - uptr __size_with_redzone; - const void *__name; - uptr __has_dynamic_init; - } type. */ - -static tree -asan_global_struct (void) -{ - static const char *field_names[5] - = { "__beg", "__size", "__size_with_redzone", - "__name", "__has_dynamic_init" }; - tree fields[5], ret; - int i; - - ret = make_node (RECORD_TYPE); - for (i = 0; i < 5; i++) - { - fields[i] - = build_decl (UNKNOWN_LOCATION, FIELD_DECL, - get_identifier (field_names[i]), - (i == 0 || i == 3) ? const_ptr_type_node - : build_nonstandard_integer_type (POINTER_SIZE, 1)); - DECL_CONTEXT (fields[i]) = ret; - if (i) - DECL_CHAIN (fields[i - 1]) = fields[i]; - } - TYPE_FIELDS (ret) = fields[0]; - TYPE_NAME (ret) = get_identifier ("__asan_global"); - layout_type (ret); - return ret; -} - -/* Append description of a single global DECL into vector V. - TYPE is __asan_global struct type as returned by asan_global_struct. */ - -static void -asan_add_global (tree decl, tree type, vec<constructor_elt, va_gc> *v) -{ - tree init, uptr = TREE_TYPE (DECL_CHAIN (TYPE_FIELDS (type))); - unsigned HOST_WIDE_INT size; - tree str_cst, refdecl = decl; - vec<constructor_elt, va_gc> *vinner = NULL; - - if (!asan_pp_initialized) - asan_pp_initialize (); - - pp_clear_output_area (&asan_pp); - if (DECL_NAME (decl)) - pp_base_tree_identifier (&asan_pp, DECL_NAME (decl)); - else - pp_string (&asan_pp, "<unknown>"); - pp_space (&asan_pp); - pp_left_paren (&asan_pp); - pp_string (&asan_pp, main_input_filename); - pp_right_paren (&asan_pp); - str_cst = asan_pp_string (); - - if (asan_needs_local_alias (decl)) - { - char buf[20]; - ASM_GENERATE_INTERNAL_LABEL (buf, "LASAN", vec_safe_length (v) + 1); - refdecl = build_decl (DECL_SOURCE_LOCATION (decl), - VAR_DECL, get_identifier (buf), TREE_TYPE (decl)); - TREE_ADDRESSABLE (refdecl) = TREE_ADDRESSABLE (decl); - TREE_READONLY (refdecl) = TREE_READONLY (decl); - TREE_THIS_VOLATILE (refdecl) = TREE_THIS_VOLATILE (decl); - DECL_GIMPLE_REG_P (refdecl) = DECL_GIMPLE_REG_P (decl); - DECL_ARTIFICIAL (refdecl) = DECL_ARTIFICIAL (decl); - DECL_IGNORED_P (refdecl) = DECL_IGNORED_P (decl); - TREE_STATIC (refdecl) = 1; - TREE_PUBLIC (refdecl) = 0; - TREE_USED (refdecl) = 1; - assemble_alias (refdecl, DECL_ASSEMBLER_NAME (decl)); - } - - CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE, - fold_convert (const_ptr_type_node, - build_fold_addr_expr (refdecl))); - size = tree_low_cst (DECL_SIZE_UNIT (decl), 1); - CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE, build_int_cst (uptr, size)); - size += asan_red_zone_size (size); - CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE, build_int_cst (uptr, size)); - CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE, - fold_convert (const_ptr_type_node, str_cst)); - CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE, build_int_cst (uptr, 0)); - init = build_constructor (type, vinner); - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, init); -} - -/* Initialize sanitizer.def builtins if the FE hasn't initialized them. */ -void -initialize_sanitizer_builtins (void) -{ - tree decl; - - if (builtin_decl_implicit_p (BUILT_IN_ASAN_INIT)) - return; - - tree BT_FN_VOID = build_function_type_list (void_type_node, NULL_TREE); - tree BT_FN_VOID_PTR - = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE); - tree BT_FN_VOID_PTR_PTRMODE - = build_function_type_list (void_type_node, ptr_type_node, - build_nonstandard_integer_type (POINTER_SIZE, - 1), NULL_TREE); - tree BT_FN_VOID_INT - = build_function_type_list (void_type_node, integer_type_node, NULL_TREE); - tree BT_FN_BOOL_VPTR_PTR_IX_INT_INT[5]; - tree BT_FN_IX_CONST_VPTR_INT[5]; - tree BT_FN_IX_VPTR_IX_INT[5]; - tree BT_FN_VOID_VPTR_IX_INT[5]; - tree vptr - = build_pointer_type (build_qualified_type (void_type_node, - TYPE_QUAL_VOLATILE)); - tree cvptr - = build_pointer_type (build_qualified_type (void_type_node, - TYPE_QUAL_VOLATILE - |TYPE_QUAL_CONST)); - tree boolt - = lang_hooks.types.type_for_size (BOOL_TYPE_SIZE, 1); - int i; - for (i = 0; i < 5; i++) - { - tree ix = build_nonstandard_integer_type (BITS_PER_UNIT * (1 << i), 1); - BT_FN_BOOL_VPTR_PTR_IX_INT_INT[i] - = build_function_type_list (boolt, vptr, ptr_type_node, ix, - integer_type_node, integer_type_node, - NULL_TREE); - BT_FN_IX_CONST_VPTR_INT[i] - = build_function_type_list (ix, cvptr, integer_type_node, NULL_TREE); - BT_FN_IX_VPTR_IX_INT[i] - = build_function_type_list (ix, vptr, ix, integer_type_node, - NULL_TREE); - BT_FN_VOID_VPTR_IX_INT[i] - = build_function_type_list (void_type_node, vptr, ix, - integer_type_node, NULL_TREE); - } -#define BT_FN_BOOL_VPTR_PTR_I1_INT_INT BT_FN_BOOL_VPTR_PTR_IX_INT_INT[0] -#define BT_FN_I1_CONST_VPTR_INT BT_FN_IX_CONST_VPTR_INT[0] -#define BT_FN_I1_VPTR_I1_INT BT_FN_IX_VPTR_IX_INT[0] -#define BT_FN_VOID_VPTR_I1_INT BT_FN_VOID_VPTR_IX_INT[0] -#define BT_FN_BOOL_VPTR_PTR_I2_INT_INT BT_FN_BOOL_VPTR_PTR_IX_INT_INT[1] -#define BT_FN_I2_CONST_VPTR_INT BT_FN_IX_CONST_VPTR_INT[1] -#define BT_FN_I2_VPTR_I2_INT BT_FN_IX_VPTR_IX_INT[1] -#define BT_FN_VOID_VPTR_I2_INT BT_FN_VOID_VPTR_IX_INT[1] -#define BT_FN_BOOL_VPTR_PTR_I4_INT_INT BT_FN_BOOL_VPTR_PTR_IX_INT_INT[2] -#define BT_FN_I4_CONST_VPTR_INT BT_FN_IX_CONST_VPTR_INT[2] -#define BT_FN_I4_VPTR_I4_INT BT_FN_IX_VPTR_IX_INT[2] -#define BT_FN_VOID_VPTR_I4_INT BT_FN_VOID_VPTR_IX_INT[2] -#define BT_FN_BOOL_VPTR_PTR_I8_INT_INT BT_FN_BOOL_VPTR_PTR_IX_INT_INT[3] -#define BT_FN_I8_CONST_VPTR_INT BT_FN_IX_CONST_VPTR_INT[3] -#define BT_FN_I8_VPTR_I8_INT BT_FN_IX_VPTR_IX_INT[3] -#define BT_FN_VOID_VPTR_I8_INT BT_FN_VOID_VPTR_IX_INT[3] -#define BT_FN_BOOL_VPTR_PTR_I16_INT_INT BT_FN_BOOL_VPTR_PTR_IX_INT_INT[4] -#define BT_FN_I16_CONST_VPTR_INT BT_FN_IX_CONST_VPTR_INT[4] -#define BT_FN_I16_VPTR_I16_INT BT_FN_IX_VPTR_IX_INT[4] -#define BT_FN_VOID_VPTR_I16_INT BT_FN_VOID_VPTR_IX_INT[4] -#undef ATTR_NOTHROW_LEAF_LIST -#define ATTR_NOTHROW_LEAF_LIST ECF_NOTHROW | ECF_LEAF -#undef ATTR_TMPURE_NOTHROW_LEAF_LIST -#define ATTR_TMPURE_NOTHROW_LEAF_LIST ECF_TM_PURE | ATTR_NOTHROW_LEAF_LIST -#undef ATTR_NORETURN_NOTHROW_LEAF_LIST -#define ATTR_NORETURN_NOTHROW_LEAF_LIST ECF_NORETURN | ATTR_NOTHROW_LEAF_LIST -#undef ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST -#define ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST \ - ECF_TM_PURE | ATTR_NORETURN_NOTHROW_LEAF_LIST -#undef DEF_SANITIZER_BUILTIN -#define DEF_SANITIZER_BUILTIN(ENUM, NAME, TYPE, ATTRS) \ - decl = add_builtin_function ("__builtin_" NAME, TYPE, ENUM, \ - BUILT_IN_NORMAL, NAME, NULL_TREE); \ - set_call_expr_flags (decl, ATTRS); \ - set_builtin_decl (ENUM, decl, true); - -#include "sanitizer.def" - -#undef DEF_SANITIZER_BUILTIN -} - -/* Called via htab_traverse. Count number of emitted - STRING_CSTs in the constant hash table. */ - -static int -count_string_csts (void **slot, void *data) -{ - struct constant_descriptor_tree *desc - = (struct constant_descriptor_tree *) *slot; - if (TREE_CODE (desc->value) == STRING_CST - && TREE_ASM_WRITTEN (desc->value) - && asan_protect_global (desc->value)) - ++*((unsigned HOST_WIDE_INT *) data); - return 1; -} - -/* Helper structure to pass two parameters to - add_string_csts. */ - -struct asan_add_string_csts_data -{ - tree type; - vec<constructor_elt, va_gc> *v; -}; - -/* Called via htab_traverse. Call asan_add_global - on emitted STRING_CSTs from the constant hash table. */ - -static int -add_string_csts (void **slot, void *data) -{ - struct constant_descriptor_tree *desc - = (struct constant_descriptor_tree *) *slot; - if (TREE_CODE (desc->value) == STRING_CST - && TREE_ASM_WRITTEN (desc->value) - && asan_protect_global (desc->value)) - { - struct asan_add_string_csts_data *aascd - = (struct asan_add_string_csts_data *) data; - asan_add_global (SYMBOL_REF_DECL (XEXP (desc->rtl, 0)), - aascd->type, aascd->v); - } - return 1; -} - -/* Needs to be GTY(()), because cgraph_build_static_cdtor may - invoke ggc_collect. */ -static GTY(()) tree asan_ctor_statements; - -/* Module-level instrumentation. - - Insert __asan_init() into the list of CTORs. - - TODO: insert redzones around globals. - */ - -void -asan_finish_file (void) -{ - struct varpool_node *vnode; - unsigned HOST_WIDE_INT gcount = 0; - - if (shadow_ptr_types[0] == NULL_TREE) - asan_init_shadow_ptr_types (); - /* Avoid instrumenting code in the asan ctors/dtors. - We don't need to insert padding after the description strings, - nor after .LASAN* array. */ - flag_asan = 0; - - tree fn = builtin_decl_implicit (BUILT_IN_ASAN_INIT); - append_to_statement_list (build_call_expr (fn, 0), &asan_ctor_statements); - FOR_EACH_DEFINED_VARIABLE (vnode) - if (TREE_ASM_WRITTEN (vnode->symbol.decl) - && asan_protect_global (vnode->symbol.decl)) - ++gcount; - htab_t const_desc_htab = constant_pool_htab (); - htab_traverse (const_desc_htab, count_string_csts, &gcount); - if (gcount) - { - tree type = asan_global_struct (), var, ctor; - tree uptr = build_nonstandard_integer_type (POINTER_SIZE, 1); - tree dtor_statements = NULL_TREE; - vec<constructor_elt, va_gc> *v; - char buf[20]; - - type = build_array_type_nelts (type, gcount); - ASM_GENERATE_INTERNAL_LABEL (buf, "LASAN", 0); - var = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (buf), - type); - TREE_STATIC (var) = 1; - TREE_PUBLIC (var) = 0; - DECL_ARTIFICIAL (var) = 1; - DECL_IGNORED_P (var) = 1; - vec_alloc (v, gcount); - FOR_EACH_DEFINED_VARIABLE (vnode) - if (TREE_ASM_WRITTEN (vnode->symbol.decl) - && asan_protect_global (vnode->symbol.decl)) - asan_add_global (vnode->symbol.decl, TREE_TYPE (type), v); - struct asan_add_string_csts_data aascd; - aascd.type = TREE_TYPE (type); - aascd.v = v; - htab_traverse (const_desc_htab, add_string_csts, &aascd); - ctor = build_constructor (type, v); - TREE_CONSTANT (ctor) = 1; - TREE_STATIC (ctor) = 1; - DECL_INITIAL (var) = ctor; - varpool_assemble_decl (varpool_node_for_decl (var)); - - fn = builtin_decl_implicit (BUILT_IN_ASAN_REGISTER_GLOBALS); - append_to_statement_list (build_call_expr (fn, 2, - build_fold_addr_expr (var), - build_int_cst (uptr, gcount)), - &asan_ctor_statements); - - fn = builtin_decl_implicit (BUILT_IN_ASAN_UNREGISTER_GLOBALS); - append_to_statement_list (build_call_expr (fn, 2, - build_fold_addr_expr (var), - build_int_cst (uptr, gcount)), - &dtor_statements); - cgraph_build_static_cdtor ('D', dtor_statements, - MAX_RESERVED_INIT_PRIORITY - 1); - } - cgraph_build_static_cdtor ('I', asan_ctor_statements, - MAX_RESERVED_INIT_PRIORITY - 1); - flag_asan = 1; -} - -/* Instrument the current function. */ - -static unsigned int -asan_instrument (void) -{ - if (shadow_ptr_types[0] == NULL_TREE) - asan_init_shadow_ptr_types (); - transform_statements (); - return 0; -} - -static bool -gate_asan (void) -{ - return flag_asan != 0 - && !lookup_attribute ("no_sanitize_address", - DECL_ATTRIBUTES (current_function_decl)); -} - -struct gimple_opt_pass pass_asan = -{ - { - GIMPLE_PASS, - "asan", /* name */ - OPTGROUP_NONE, /* optinfo_flags */ - gate_asan, /* gate */ - asan_instrument, /* execute */ - NULL, /* sub */ - NULL, /* next */ - 0, /* static_pass_number */ - TV_NONE, /* tv_id */ - PROP_ssa | PROP_cfg | PROP_gimple_leh,/* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - TODO_verify_flow | TODO_verify_stmts - | TODO_update_ssa /* todo_flags_finish */ - } -}; - -static bool -gate_asan_O0 (void) -{ - return !optimize && gate_asan (); -} - -struct gimple_opt_pass pass_asan_O0 = -{ - { - GIMPLE_PASS, - "asan0", /* name */ - OPTGROUP_NONE, /* optinfo_flags */ - gate_asan_O0, /* gate */ - asan_instrument, /* execute */ - NULL, /* sub */ - NULL, /* next */ - 0, /* static_pass_number */ - TV_NONE, /* tv_id */ - PROP_ssa | PROP_cfg | PROP_gimple_leh,/* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - TODO_verify_flow | TODO_verify_stmts - | TODO_update_ssa /* todo_flags_finish */ - } -}; - -#include "gt-asan.h" |