138fd1498Szrj /* AddressSanitizer, a fast memory error detector.
238fd1498Szrj Copyright (C) 2012-2018 Free Software Foundation, Inc.
338fd1498Szrj Contributed by Kostya Serebryany <kcc@google.com>
438fd1498Szrj
538fd1498Szrj This file is part of GCC.
638fd1498Szrj
738fd1498Szrj GCC is free software; you can redistribute it and/or modify it under
838fd1498Szrj the terms of the GNU General Public License as published by the Free
938fd1498Szrj Software Foundation; either version 3, or (at your option) any later
1038fd1498Szrj version.
1138fd1498Szrj
1238fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY
1338fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or
1438fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1538fd1498Szrj for more details.
1638fd1498Szrj
1738fd1498Szrj You should have received a copy of the GNU General Public License
1838fd1498Szrj along with GCC; see the file COPYING3. If not see
1938fd1498Szrj <http://www.gnu.org/licenses/>. */
2038fd1498Szrj
2138fd1498Szrj
2238fd1498Szrj #include "config.h"
2338fd1498Szrj #include "system.h"
2438fd1498Szrj #include "coretypes.h"
2538fd1498Szrj #include "backend.h"
2638fd1498Szrj #include "target.h"
2738fd1498Szrj #include "rtl.h"
2838fd1498Szrj #include "tree.h"
2938fd1498Szrj #include "gimple.h"
3038fd1498Szrj #include "cfghooks.h"
3138fd1498Szrj #include "alloc-pool.h"
3238fd1498Szrj #include "tree-pass.h"
3338fd1498Szrj #include "memmodel.h"
3438fd1498Szrj #include "tm_p.h"
3538fd1498Szrj #include "ssa.h"
3638fd1498Szrj #include "stringpool.h"
3738fd1498Szrj #include "tree-ssanames.h"
3838fd1498Szrj #include "optabs.h"
3938fd1498Szrj #include "emit-rtl.h"
4038fd1498Szrj #include "cgraph.h"
4138fd1498Szrj #include "gimple-pretty-print.h"
4238fd1498Szrj #include "alias.h"
4338fd1498Szrj #include "fold-const.h"
4438fd1498Szrj #include "cfganal.h"
4538fd1498Szrj #include "gimplify.h"
4638fd1498Szrj #include "gimple-iterator.h"
4738fd1498Szrj #include "varasm.h"
4838fd1498Szrj #include "stor-layout.h"
4938fd1498Szrj #include "tree-iterator.h"
5038fd1498Szrj #include "stringpool.h"
5138fd1498Szrj #include "attribs.h"
5238fd1498Szrj #include "asan.h"
5338fd1498Szrj #include "dojump.h"
5438fd1498Szrj #include "explow.h"
5538fd1498Szrj #include "expr.h"
5638fd1498Szrj #include "output.h"
5738fd1498Szrj #include "langhooks.h"
5838fd1498Szrj #include "cfgloop.h"
5938fd1498Szrj #include "gimple-builder.h"
6038fd1498Szrj #include "gimple-fold.h"
6138fd1498Szrj #include "ubsan.h"
6238fd1498Szrj #include "params.h"
6338fd1498Szrj #include "builtins.h"
6438fd1498Szrj #include "fnmatch.h"
6538fd1498Szrj #include "tree-inline.h"
6638fd1498Szrj
6738fd1498Szrj /* AddressSanitizer finds out-of-bounds and use-after-free bugs
6838fd1498Szrj with <2x slowdown on average.
6938fd1498Szrj
7038fd1498Szrj The tool consists of two parts:
7138fd1498Szrj instrumentation module (this file) and a run-time library.
7238fd1498Szrj The instrumentation module adds a run-time check before every memory insn.
7338fd1498Szrj For a 8- or 16- byte load accessing address X:
7438fd1498Szrj ShadowAddr = (X >> 3) + Offset
7538fd1498Szrj ShadowValue = *(char*)ShadowAddr; // *(short*) for 16-byte access.
7638fd1498Szrj if (ShadowValue)
7738fd1498Szrj __asan_report_load8(X);
7838fd1498Szrj For a load of N bytes (N=1, 2 or 4) from address X:
7938fd1498Szrj ShadowAddr = (X >> 3) + Offset
8038fd1498Szrj ShadowValue = *(char*)ShadowAddr;
8138fd1498Szrj if (ShadowValue)
8238fd1498Szrj if ((X & 7) + N - 1 > ShadowValue)
8338fd1498Szrj __asan_report_loadN(X);
8438fd1498Szrj Stores are instrumented similarly, but using __asan_report_storeN functions.
8538fd1498Szrj A call too __asan_init_vN() is inserted to the list of module CTORs.
8638fd1498Szrj N is the version number of the AddressSanitizer API. The changes between the
8738fd1498Szrj API versions are listed in libsanitizer/asan/asan_interface_internal.h.
8838fd1498Szrj
8938fd1498Szrj The run-time library redefines malloc (so that redzone are inserted around
9038fd1498Szrj the allocated memory) and free (so that reuse of free-ed memory is delayed),
9138fd1498Szrj provides __asan_report* and __asan_init_vN functions.
9238fd1498Szrj
9338fd1498Szrj Read more:
9438fd1498Szrj http://code.google.com/p/address-sanitizer/wiki/AddressSanitizerAlgorithm
9538fd1498Szrj
9638fd1498Szrj The current implementation supports detection of out-of-bounds and
9738fd1498Szrj use-after-free in the heap, on the stack and for global variables.
9838fd1498Szrj
9938fd1498Szrj [Protection of stack variables]
10038fd1498Szrj
10138fd1498Szrj To understand how detection of out-of-bounds and use-after-free works
10238fd1498Szrj for stack variables, lets look at this example on x86_64 where the
10338fd1498Szrj stack grows downward:
10438fd1498Szrj
10538fd1498Szrj int
10638fd1498Szrj foo ()
10738fd1498Szrj {
10838fd1498Szrj char a[23] = {0};
10938fd1498Szrj int b[2] = {0};
11038fd1498Szrj
11138fd1498Szrj a[5] = 1;
11238fd1498Szrj b[1] = 2;
11338fd1498Szrj
11438fd1498Szrj return a[5] + b[1];
11538fd1498Szrj }
11638fd1498Szrj
11738fd1498Szrj For this function, the stack protected by asan will be organized as
11838fd1498Szrj follows, from the top of the stack to the bottom:
11938fd1498Szrj
12038fd1498Szrj Slot 1/ [red zone of 32 bytes called 'RIGHT RedZone']
12138fd1498Szrj
12238fd1498Szrj Slot 2/ [8 bytes of red zone, that adds up to the space of 'a' to make
12338fd1498Szrj the next slot be 32 bytes aligned; this one is called Partial
12438fd1498Szrj Redzone; this 32 bytes alignment is an asan constraint]
12538fd1498Szrj
12638fd1498Szrj Slot 3/ [24 bytes for variable 'a']
12738fd1498Szrj
12838fd1498Szrj Slot 4/ [red zone of 32 bytes called 'Middle RedZone']
12938fd1498Szrj
13038fd1498Szrj Slot 5/ [24 bytes of Partial Red Zone (similar to slot 2]
13138fd1498Szrj
13238fd1498Szrj Slot 6/ [8 bytes for variable 'b']
13338fd1498Szrj
13438fd1498Szrj Slot 7/ [32 bytes of Red Zone at the bottom of the stack, called
13538fd1498Szrj 'LEFT RedZone']
13638fd1498Szrj
13738fd1498Szrj The 32 bytes of LEFT red zone at the bottom of the stack can be
13838fd1498Szrj decomposed as such:
13938fd1498Szrj
14038fd1498Szrj 1/ The first 8 bytes contain a magical asan number that is always
14138fd1498Szrj 0x41B58AB3.
14238fd1498Szrj
14338fd1498Szrj 2/ The following 8 bytes contains a pointer to a string (to be
14438fd1498Szrj parsed at runtime by the runtime asan library), which format is
14538fd1498Szrj the following:
14638fd1498Szrj
14738fd1498Szrj "<function-name> <space> <num-of-variables-on-the-stack>
14838fd1498Szrj (<32-bytes-aligned-offset-in-bytes-of-variable> <space>
14938fd1498Szrj <length-of-var-in-bytes> ){n} "
15038fd1498Szrj
15138fd1498Szrj where '(...){n}' means the content inside the parenthesis occurs 'n'
15238fd1498Szrj times, with 'n' being the number of variables on the stack.
15338fd1498Szrj
15438fd1498Szrj 3/ The following 8 bytes contain the PC of the current function which
15538fd1498Szrj will be used by the run-time library to print an error message.
15638fd1498Szrj
15738fd1498Szrj 4/ The following 8 bytes are reserved for internal use by the run-time.
15838fd1498Szrj
15938fd1498Szrj The shadow memory for that stack layout is going to look like this:
16038fd1498Szrj
16138fd1498Szrj - content of shadow memory 8 bytes for slot 7: 0xF1F1F1F1.
16238fd1498Szrj The F1 byte pattern is a magic number called
16338fd1498Szrj ASAN_STACK_MAGIC_LEFT and is a way for the runtime to know that
16438fd1498Szrj the memory for that shadow byte is part of a the LEFT red zone
16538fd1498Szrj intended to seat at the bottom of the variables on the stack.
16638fd1498Szrj
16738fd1498Szrj - content of shadow memory 8 bytes for slots 6 and 5:
16838fd1498Szrj 0xF4F4F400. The F4 byte pattern is a magic number
16938fd1498Szrj called ASAN_STACK_MAGIC_PARTIAL. It flags the fact that the
17038fd1498Szrj memory region for this shadow byte is a PARTIAL red zone
17138fd1498Szrj intended to pad a variable A, so that the slot following
17238fd1498Szrj {A,padding} is 32 bytes aligned.
17338fd1498Szrj
17438fd1498Szrj Note that the fact that the least significant byte of this
17538fd1498Szrj shadow memory content is 00 means that 8 bytes of its
17638fd1498Szrj corresponding memory (which corresponds to the memory of
17738fd1498Szrj variable 'b') is addressable.
17838fd1498Szrj
17938fd1498Szrj - content of shadow memory 8 bytes for slot 4: 0xF2F2F2F2.
18038fd1498Szrj The F2 byte pattern is a magic number called
18138fd1498Szrj ASAN_STACK_MAGIC_MIDDLE. It flags the fact that the memory
18238fd1498Szrj region for this shadow byte is a MIDDLE red zone intended to
18338fd1498Szrj seat between two 32 aligned slots of {variable,padding}.
18438fd1498Szrj
18538fd1498Szrj - content of shadow memory 8 bytes for slot 3 and 2:
18638fd1498Szrj 0xF4000000. This represents is the concatenation of
18738fd1498Szrj variable 'a' and the partial red zone following it, like what we
18838fd1498Szrj had for variable 'b'. The least significant 3 bytes being 00
18938fd1498Szrj means that the 3 bytes of variable 'a' are addressable.
19038fd1498Szrj
19138fd1498Szrj - content of shadow memory 8 bytes for slot 1: 0xF3F3F3F3.
19238fd1498Szrj The F3 byte pattern is a magic number called
19338fd1498Szrj ASAN_STACK_MAGIC_RIGHT. It flags the fact that the memory
19438fd1498Szrj region for this shadow byte is a RIGHT red zone intended to seat
19538fd1498Szrj at the top of the variables of the stack.
19638fd1498Szrj
19738fd1498Szrj Note that the real variable layout is done in expand_used_vars in
19838fd1498Szrj cfgexpand.c. As far as Address Sanitizer is concerned, it lays out
19938fd1498Szrj stack variables as well as the different red zones, emits some
20038fd1498Szrj prologue code to populate the shadow memory as to poison (mark as
20138fd1498Szrj non-accessible) the regions of the red zones and mark the regions of
20238fd1498Szrj stack variables as accessible, and emit some epilogue code to
20338fd1498Szrj un-poison (mark as accessible) the regions of red zones right before
20438fd1498Szrj the function exits.
20538fd1498Szrj
20638fd1498Szrj [Protection of global variables]
20738fd1498Szrj
20838fd1498Szrj The basic idea is to insert a red zone between two global variables
20938fd1498Szrj and install a constructor function that calls the asan runtime to do
21038fd1498Szrj the populating of the relevant shadow memory regions at load time.
21138fd1498Szrj
21238fd1498Szrj So the global variables are laid out as to insert a red zone between
21338fd1498Szrj them. The size of the red zones is so that each variable starts on a
21438fd1498Szrj 32 bytes boundary.
21538fd1498Szrj
21638fd1498Szrj Then a constructor function is installed so that, for each global
21738fd1498Szrj variable, it calls the runtime asan library function
21838fd1498Szrj __asan_register_globals_with an instance of this type:
21938fd1498Szrj
22038fd1498Szrj struct __asan_global
22138fd1498Szrj {
22238fd1498Szrj // Address of the beginning of the global variable.
22338fd1498Szrj const void *__beg;
22438fd1498Szrj
22538fd1498Szrj // Initial size of the global variable.
22638fd1498Szrj uptr __size;
22738fd1498Szrj
22838fd1498Szrj // Size of the global variable + size of the red zone. This
22938fd1498Szrj // size is 32 bytes aligned.
23038fd1498Szrj uptr __size_with_redzone;
23138fd1498Szrj
23238fd1498Szrj // Name of the global variable.
23338fd1498Szrj const void *__name;
23438fd1498Szrj
23538fd1498Szrj // Name of the module where the global variable is declared.
23638fd1498Szrj const void *__module_name;
23738fd1498Szrj
23838fd1498Szrj // 1 if it has dynamic initialization, 0 otherwise.
23938fd1498Szrj uptr __has_dynamic_init;
24038fd1498Szrj
24138fd1498Szrj // A pointer to struct that contains source location, could be NULL.
24238fd1498Szrj __asan_global_source_location *__location;
24338fd1498Szrj }
24438fd1498Szrj
24538fd1498Szrj A destructor function that calls the runtime asan library function
24638fd1498Szrj _asan_unregister_globals is also installed. */
24738fd1498Szrj
24838fd1498Szrj static unsigned HOST_WIDE_INT asan_shadow_offset_value;
24938fd1498Szrj static bool asan_shadow_offset_computed;
25038fd1498Szrj static vec<char *> sanitized_sections;
25138fd1498Szrj static tree last_alloca_addr;
25238fd1498Szrj
25338fd1498Szrj /* Set of variable declarations that are going to be guarded by
25438fd1498Szrj use-after-scope sanitizer. */
25538fd1498Szrj
256*58e805e6Szrj hash_set<tree> *asan_handled_variables = NULL;
25738fd1498Szrj
25838fd1498Szrj hash_set <tree> *asan_used_labels = NULL;
25938fd1498Szrj
26038fd1498Szrj /* Sets shadow offset to value in string VAL. */
26138fd1498Szrj
26238fd1498Szrj bool
set_asan_shadow_offset(const char * val)26338fd1498Szrj set_asan_shadow_offset (const char *val)
26438fd1498Szrj {
26538fd1498Szrj char *endp;
26638fd1498Szrj
26738fd1498Szrj errno = 0;
26838fd1498Szrj #ifdef HAVE_LONG_LONG
26938fd1498Szrj asan_shadow_offset_value = strtoull (val, &endp, 0);
27038fd1498Szrj #else
27138fd1498Szrj asan_shadow_offset_value = strtoul (val, &endp, 0);
27238fd1498Szrj #endif
27338fd1498Szrj if (!(*val != '\0' && *endp == '\0' && errno == 0))
27438fd1498Szrj return false;
27538fd1498Szrj
27638fd1498Szrj asan_shadow_offset_computed = true;
27738fd1498Szrj
27838fd1498Szrj return true;
27938fd1498Szrj }
28038fd1498Szrj
28138fd1498Szrj /* Set list of user-defined sections that need to be sanitized. */
28238fd1498Szrj
28338fd1498Szrj void
set_sanitized_sections(const char * sections)28438fd1498Szrj set_sanitized_sections (const char *sections)
28538fd1498Szrj {
28638fd1498Szrj char *pat;
28738fd1498Szrj unsigned i;
28838fd1498Szrj FOR_EACH_VEC_ELT (sanitized_sections, i, pat)
28938fd1498Szrj free (pat);
29038fd1498Szrj sanitized_sections.truncate (0);
29138fd1498Szrj
29238fd1498Szrj for (const char *s = sections; *s; )
29338fd1498Szrj {
29438fd1498Szrj const char *end;
29538fd1498Szrj for (end = s; *end && *end != ','; ++end);
29638fd1498Szrj size_t len = end - s;
29738fd1498Szrj sanitized_sections.safe_push (xstrndup (s, len));
29838fd1498Szrj s = *end ? end + 1 : end;
29938fd1498Szrj }
30038fd1498Szrj }
30138fd1498Szrj
30238fd1498Szrj bool
asan_mark_p(gimple * stmt,enum asan_mark_flags flag)30338fd1498Szrj asan_mark_p (gimple *stmt, enum asan_mark_flags flag)
30438fd1498Szrj {
30538fd1498Szrj return (gimple_call_internal_p (stmt, IFN_ASAN_MARK)
30638fd1498Szrj && tree_to_uhwi (gimple_call_arg (stmt, 0)) == flag);
30738fd1498Szrj }
30838fd1498Szrj
30938fd1498Szrj bool
asan_sanitize_stack_p(void)31038fd1498Szrj asan_sanitize_stack_p (void)
31138fd1498Szrj {
31238fd1498Szrj return (sanitize_flags_p (SANITIZE_ADDRESS) && ASAN_STACK);
31338fd1498Szrj }
31438fd1498Szrj
31538fd1498Szrj bool
asan_sanitize_allocas_p(void)31638fd1498Szrj asan_sanitize_allocas_p (void)
31738fd1498Szrj {
31838fd1498Szrj return (asan_sanitize_stack_p () && ASAN_PROTECT_ALLOCAS);
31938fd1498Szrj }
32038fd1498Szrj
32138fd1498Szrj /* Checks whether section SEC should be sanitized. */
32238fd1498Szrj
32338fd1498Szrj static bool
section_sanitized_p(const char * sec)32438fd1498Szrj section_sanitized_p (const char *sec)
32538fd1498Szrj {
32638fd1498Szrj char *pat;
32738fd1498Szrj unsigned i;
32838fd1498Szrj FOR_EACH_VEC_ELT (sanitized_sections, i, pat)
32938fd1498Szrj if (fnmatch (pat, sec, FNM_PERIOD) == 0)
33038fd1498Szrj return true;
33138fd1498Szrj return false;
33238fd1498Szrj }
33338fd1498Szrj
33438fd1498Szrj /* Returns Asan shadow offset. */
33538fd1498Szrj
33638fd1498Szrj static unsigned HOST_WIDE_INT
asan_shadow_offset()33738fd1498Szrj asan_shadow_offset ()
33838fd1498Szrj {
33938fd1498Szrj if (!asan_shadow_offset_computed)
34038fd1498Szrj {
34138fd1498Szrj asan_shadow_offset_computed = true;
34238fd1498Szrj asan_shadow_offset_value = targetm.asan_shadow_offset ();
34338fd1498Szrj }
34438fd1498Szrj return asan_shadow_offset_value;
34538fd1498Szrj }
34638fd1498Szrj
34738fd1498Szrj alias_set_type asan_shadow_set = -1;
34838fd1498Szrj
34938fd1498Szrj /* Pointer types to 1, 2 or 4 byte integers in shadow memory. A separate
35038fd1498Szrj alias set is used for all shadow memory accesses. */
35138fd1498Szrj static GTY(()) tree shadow_ptr_types[3];
35238fd1498Szrj
35338fd1498Szrj /* Decl for __asan_option_detect_stack_use_after_return. */
35438fd1498Szrj static GTY(()) tree asan_detect_stack_use_after_return;
35538fd1498Szrj
35638fd1498Szrj /* Hashtable support for memory references used by gimple
35738fd1498Szrj statements. */
35838fd1498Szrj
35938fd1498Szrj /* This type represents a reference to a memory region. */
36038fd1498Szrj struct asan_mem_ref
36138fd1498Szrj {
36238fd1498Szrj /* The expression of the beginning of the memory region. */
36338fd1498Szrj tree start;
36438fd1498Szrj
36538fd1498Szrj /* The size of the access. */
36638fd1498Szrj HOST_WIDE_INT access_size;
36738fd1498Szrj };
36838fd1498Szrj
36938fd1498Szrj object_allocator <asan_mem_ref> asan_mem_ref_pool ("asan_mem_ref");
37038fd1498Szrj
37138fd1498Szrj /* Initializes an instance of asan_mem_ref. */
37238fd1498Szrj
37338fd1498Szrj static void
asan_mem_ref_init(asan_mem_ref * ref,tree start,HOST_WIDE_INT access_size)37438fd1498Szrj asan_mem_ref_init (asan_mem_ref *ref, tree start, HOST_WIDE_INT access_size)
37538fd1498Szrj {
37638fd1498Szrj ref->start = start;
37738fd1498Szrj ref->access_size = access_size;
37838fd1498Szrj }
37938fd1498Szrj
38038fd1498Szrj /* Allocates memory for an instance of asan_mem_ref into the memory
38138fd1498Szrj pool returned by asan_mem_ref_get_alloc_pool and initialize it.
38238fd1498Szrj START is the address of (or the expression pointing to) the
38338fd1498Szrj beginning of memory reference. ACCESS_SIZE is the size of the
38438fd1498Szrj access to the referenced memory. */
38538fd1498Szrj
38638fd1498Szrj static asan_mem_ref*
asan_mem_ref_new(tree start,HOST_WIDE_INT access_size)38738fd1498Szrj asan_mem_ref_new (tree start, HOST_WIDE_INT access_size)
38838fd1498Szrj {
38938fd1498Szrj asan_mem_ref *ref = asan_mem_ref_pool.allocate ();
39038fd1498Szrj
39138fd1498Szrj asan_mem_ref_init (ref, start, access_size);
39238fd1498Szrj return ref;
39338fd1498Szrj }
39438fd1498Szrj
39538fd1498Szrj /* This builds and returns a pointer to the end of the memory region
39638fd1498Szrj that starts at START and of length LEN. */
39738fd1498Szrj
39838fd1498Szrj tree
asan_mem_ref_get_end(tree start,tree len)39938fd1498Szrj asan_mem_ref_get_end (tree start, tree len)
40038fd1498Szrj {
40138fd1498Szrj if (len == NULL_TREE || integer_zerop (len))
40238fd1498Szrj return start;
40338fd1498Szrj
40438fd1498Szrj if (!ptrofftype_p (len))
40538fd1498Szrj len = convert_to_ptrofftype (len);
40638fd1498Szrj
40738fd1498Szrj return fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (start), start, len);
40838fd1498Szrj }
40938fd1498Szrj
41038fd1498Szrj /* Return a tree expression that represents the end of the referenced
41138fd1498Szrj memory region. Beware that this function can actually build a new
41238fd1498Szrj tree expression. */
41338fd1498Szrj
41438fd1498Szrj tree
asan_mem_ref_get_end(const asan_mem_ref * ref,tree len)41538fd1498Szrj asan_mem_ref_get_end (const asan_mem_ref *ref, tree len)
41638fd1498Szrj {
41738fd1498Szrj return asan_mem_ref_get_end (ref->start, len);
41838fd1498Szrj }
41938fd1498Szrj
42038fd1498Szrj struct asan_mem_ref_hasher : nofree_ptr_hash <asan_mem_ref>
42138fd1498Szrj {
42238fd1498Szrj static inline hashval_t hash (const asan_mem_ref *);
42338fd1498Szrj static inline bool equal (const asan_mem_ref *, const asan_mem_ref *);
42438fd1498Szrj };
42538fd1498Szrj
42638fd1498Szrj /* Hash a memory reference. */
42738fd1498Szrj
42838fd1498Szrj inline hashval_t
hash(const asan_mem_ref * mem_ref)42938fd1498Szrj asan_mem_ref_hasher::hash (const asan_mem_ref *mem_ref)
43038fd1498Szrj {
43138fd1498Szrj return iterative_hash_expr (mem_ref->start, 0);
43238fd1498Szrj }
43338fd1498Szrj
43438fd1498Szrj /* Compare two memory references. We accept the length of either
43538fd1498Szrj memory references to be NULL_TREE. */
43638fd1498Szrj
43738fd1498Szrj inline bool
equal(const asan_mem_ref * m1,const asan_mem_ref * m2)43838fd1498Szrj asan_mem_ref_hasher::equal (const asan_mem_ref *m1,
43938fd1498Szrj const asan_mem_ref *m2)
44038fd1498Szrj {
44138fd1498Szrj return operand_equal_p (m1->start, m2->start, 0);
44238fd1498Szrj }
44338fd1498Szrj
44438fd1498Szrj static hash_table<asan_mem_ref_hasher> *asan_mem_ref_ht;
44538fd1498Szrj
44638fd1498Szrj /* Returns a reference to the hash table containing memory references.
44738fd1498Szrj This function ensures that the hash table is created. Note that
44838fd1498Szrj this hash table is updated by the function
44938fd1498Szrj update_mem_ref_hash_table. */
45038fd1498Szrj
45138fd1498Szrj static hash_table<asan_mem_ref_hasher> *
get_mem_ref_hash_table()45238fd1498Szrj get_mem_ref_hash_table ()
45338fd1498Szrj {
45438fd1498Szrj if (!asan_mem_ref_ht)
45538fd1498Szrj asan_mem_ref_ht = new hash_table<asan_mem_ref_hasher> (10);
45638fd1498Szrj
45738fd1498Szrj return asan_mem_ref_ht;
45838fd1498Szrj }
45938fd1498Szrj
46038fd1498Szrj /* Clear all entries from the memory references hash table. */
46138fd1498Szrj
46238fd1498Szrj static void
empty_mem_ref_hash_table()46338fd1498Szrj empty_mem_ref_hash_table ()
46438fd1498Szrj {
46538fd1498Szrj if (asan_mem_ref_ht)
46638fd1498Szrj asan_mem_ref_ht->empty ();
46738fd1498Szrj }
46838fd1498Szrj
46938fd1498Szrj /* Free the memory references hash table. */
47038fd1498Szrj
47138fd1498Szrj static void
free_mem_ref_resources()47238fd1498Szrj free_mem_ref_resources ()
47338fd1498Szrj {
47438fd1498Szrj delete asan_mem_ref_ht;
47538fd1498Szrj asan_mem_ref_ht = NULL;
47638fd1498Szrj
47738fd1498Szrj asan_mem_ref_pool.release ();
47838fd1498Szrj }
47938fd1498Szrj
48038fd1498Szrj /* Return true iff the memory reference REF has been instrumented. */
48138fd1498Szrj
48238fd1498Szrj static bool
has_mem_ref_been_instrumented(tree ref,HOST_WIDE_INT access_size)48338fd1498Szrj has_mem_ref_been_instrumented (tree ref, HOST_WIDE_INT access_size)
48438fd1498Szrj {
48538fd1498Szrj asan_mem_ref r;
48638fd1498Szrj asan_mem_ref_init (&r, ref, access_size);
48738fd1498Szrj
48838fd1498Szrj asan_mem_ref *saved_ref = get_mem_ref_hash_table ()->find (&r);
48938fd1498Szrj return saved_ref && saved_ref->access_size >= access_size;
49038fd1498Szrj }
49138fd1498Szrj
49238fd1498Szrj /* Return true iff the memory reference REF has been instrumented. */
49338fd1498Szrj
49438fd1498Szrj static bool
has_mem_ref_been_instrumented(const asan_mem_ref * ref)49538fd1498Szrj has_mem_ref_been_instrumented (const asan_mem_ref *ref)
49638fd1498Szrj {
49738fd1498Szrj return has_mem_ref_been_instrumented (ref->start, ref->access_size);
49838fd1498Szrj }
49938fd1498Szrj
50038fd1498Szrj /* Return true iff access to memory region starting at REF and of
50138fd1498Szrj length LEN has been instrumented. */
50238fd1498Szrj
50338fd1498Szrj static bool
has_mem_ref_been_instrumented(const asan_mem_ref * ref,tree len)50438fd1498Szrj has_mem_ref_been_instrumented (const asan_mem_ref *ref, tree len)
50538fd1498Szrj {
50638fd1498Szrj HOST_WIDE_INT size_in_bytes
50738fd1498Szrj = tree_fits_shwi_p (len) ? tree_to_shwi (len) : -1;
50838fd1498Szrj
50938fd1498Szrj return size_in_bytes != -1
51038fd1498Szrj && has_mem_ref_been_instrumented (ref->start, size_in_bytes);
51138fd1498Szrj }
51238fd1498Szrj
51338fd1498Szrj /* Set REF to the memory reference present in a gimple assignment
51438fd1498Szrj ASSIGNMENT. Return true upon successful completion, false
51538fd1498Szrj otherwise. */
51638fd1498Szrj
51738fd1498Szrj static bool
get_mem_ref_of_assignment(const gassign * assignment,asan_mem_ref * ref,bool * ref_is_store)51838fd1498Szrj get_mem_ref_of_assignment (const gassign *assignment,
51938fd1498Szrj asan_mem_ref *ref,
52038fd1498Szrj bool *ref_is_store)
52138fd1498Szrj {
52238fd1498Szrj gcc_assert (gimple_assign_single_p (assignment));
52338fd1498Szrj
52438fd1498Szrj if (gimple_store_p (assignment)
52538fd1498Szrj && !gimple_clobber_p (assignment))
52638fd1498Szrj {
52738fd1498Szrj ref->start = gimple_assign_lhs (assignment);
52838fd1498Szrj *ref_is_store = true;
52938fd1498Szrj }
53038fd1498Szrj else if (gimple_assign_load_p (assignment))
53138fd1498Szrj {
53238fd1498Szrj ref->start = gimple_assign_rhs1 (assignment);
53338fd1498Szrj *ref_is_store = false;
53438fd1498Szrj }
53538fd1498Szrj else
53638fd1498Szrj return false;
53738fd1498Szrj
53838fd1498Szrj ref->access_size = int_size_in_bytes (TREE_TYPE (ref->start));
53938fd1498Szrj return true;
54038fd1498Szrj }
54138fd1498Szrj
54238fd1498Szrj /* Return address of last allocated dynamic alloca. */
54338fd1498Szrj
54438fd1498Szrj static tree
get_last_alloca_addr()54538fd1498Szrj get_last_alloca_addr ()
54638fd1498Szrj {
54738fd1498Szrj if (last_alloca_addr)
54838fd1498Szrj return last_alloca_addr;
54938fd1498Szrj
55038fd1498Szrj last_alloca_addr = create_tmp_reg (ptr_type_node, "last_alloca_addr");
55138fd1498Szrj gassign *g = gimple_build_assign (last_alloca_addr, null_pointer_node);
55238fd1498Szrj edge e = single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun));
55338fd1498Szrj gsi_insert_on_edge_immediate (e, g);
55438fd1498Szrj return last_alloca_addr;
55538fd1498Szrj }
55638fd1498Szrj
55738fd1498Szrj /* Insert __asan_allocas_unpoison (top, bottom) call before
55838fd1498Szrj __builtin_stack_restore (new_sp) call.
55938fd1498Szrj The pseudocode of this routine should look like this:
56038fd1498Szrj top = last_alloca_addr;
56138fd1498Szrj bot = new_sp;
56238fd1498Szrj __asan_allocas_unpoison (top, bot);
56338fd1498Szrj last_alloca_addr = new_sp;
56438fd1498Szrj __builtin_stack_restore (new_sp);
56538fd1498Szrj In general, we can't use new_sp as bot parameter because on some
56638fd1498Szrj architectures SP has non zero offset from dynamic stack area. Moreover, on
56738fd1498Szrj some architectures this offset (STACK_DYNAMIC_OFFSET) becomes known for each
56838fd1498Szrj particular function only after all callees were expanded to rtl.
56938fd1498Szrj The most noticeable example is PowerPC{,64}, see
57038fd1498Szrj http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.html#DYNAM-STACK.
57138fd1498Szrj To overcome the issue we use following trick: pass new_sp as a second
57238fd1498Szrj parameter to __asan_allocas_unpoison and rewrite it during expansion with
57338fd1498Szrj new_sp + (virtual_dynamic_stack_rtx - sp) later in
57438fd1498Szrj expand_asan_emit_allocas_unpoison function. */
57538fd1498Szrj
57638fd1498Szrj static void
handle_builtin_stack_restore(gcall * call,gimple_stmt_iterator * iter)57738fd1498Szrj handle_builtin_stack_restore (gcall *call, gimple_stmt_iterator *iter)
57838fd1498Szrj {
57938fd1498Szrj if (!iter || !asan_sanitize_allocas_p ())
58038fd1498Szrj return;
58138fd1498Szrj
58238fd1498Szrj tree last_alloca = get_last_alloca_addr ();
58338fd1498Szrj tree restored_stack = gimple_call_arg (call, 0);
58438fd1498Szrj tree fn = builtin_decl_implicit (BUILT_IN_ASAN_ALLOCAS_UNPOISON);
58538fd1498Szrj gimple *g = gimple_build_call (fn, 2, last_alloca, restored_stack);
58638fd1498Szrj gsi_insert_before (iter, g, GSI_SAME_STMT);
58738fd1498Szrj g = gimple_build_assign (last_alloca, restored_stack);
58838fd1498Szrj gsi_insert_before (iter, g, GSI_SAME_STMT);
58938fd1498Szrj }
59038fd1498Szrj
59138fd1498Szrj /* Deploy and poison redzones around __builtin_alloca call. To do this, we
59238fd1498Szrj should replace this call with another one with changed parameters and
59338fd1498Szrj replace all its uses with new address, so
59438fd1498Szrj addr = __builtin_alloca (old_size, align);
59538fd1498Szrj is replaced by
59638fd1498Szrj left_redzone_size = max (align, ASAN_RED_ZONE_SIZE);
59738fd1498Szrj Following two statements are optimized out if we know that
59838fd1498Szrj old_size & (ASAN_RED_ZONE_SIZE - 1) == 0, i.e. alloca doesn't need partial
59938fd1498Szrj redzone.
60038fd1498Szrj misalign = old_size & (ASAN_RED_ZONE_SIZE - 1);
60138fd1498Szrj partial_redzone_size = ASAN_RED_ZONE_SIZE - misalign;
60238fd1498Szrj right_redzone_size = ASAN_RED_ZONE_SIZE;
60338fd1498Szrj additional_size = left_redzone_size + partial_redzone_size +
60438fd1498Szrj right_redzone_size;
60538fd1498Szrj new_size = old_size + additional_size;
60638fd1498Szrj new_alloca = __builtin_alloca (new_size, max (align, 32))
60738fd1498Szrj __asan_alloca_poison (new_alloca, old_size)
60838fd1498Szrj addr = new_alloca + max (align, ASAN_RED_ZONE_SIZE);
60938fd1498Szrj last_alloca_addr = new_alloca;
61038fd1498Szrj ADDITIONAL_SIZE is added to make new memory allocation contain not only
61138fd1498Szrj requested memory, but also left, partial and right redzones as well as some
61238fd1498Szrj additional space, required by alignment. */
61338fd1498Szrj
61438fd1498Szrj static void
handle_builtin_alloca(gcall * call,gimple_stmt_iterator * iter)61538fd1498Szrj handle_builtin_alloca (gcall *call, gimple_stmt_iterator *iter)
61638fd1498Szrj {
61738fd1498Szrj if (!iter || !asan_sanitize_allocas_p ())
61838fd1498Szrj return;
61938fd1498Szrj
62038fd1498Szrj gassign *g;
62138fd1498Szrj gcall *gg;
62238fd1498Szrj const HOST_WIDE_INT redzone_mask = ASAN_RED_ZONE_SIZE - 1;
62338fd1498Szrj
62438fd1498Szrj tree last_alloca = get_last_alloca_addr ();
62538fd1498Szrj tree callee = gimple_call_fndecl (call);
62638fd1498Szrj tree old_size = gimple_call_arg (call, 0);
62738fd1498Szrj tree ptr_type = gimple_call_lhs (call) ? TREE_TYPE (gimple_call_lhs (call))
62838fd1498Szrj : ptr_type_node;
62938fd1498Szrj tree partial_size = NULL_TREE;
63038fd1498Szrj unsigned int align
63138fd1498Szrj = DECL_FUNCTION_CODE (callee) == BUILT_IN_ALLOCA
63238fd1498Szrj ? 0 : tree_to_uhwi (gimple_call_arg (call, 1));
63338fd1498Szrj
63438fd1498Szrj /* If ALIGN > ASAN_RED_ZONE_SIZE, we embed left redzone into first ALIGN
63538fd1498Szrj bytes of allocated space. Otherwise, align alloca to ASAN_RED_ZONE_SIZE
63638fd1498Szrj manually. */
63738fd1498Szrj align = MAX (align, ASAN_RED_ZONE_SIZE * BITS_PER_UNIT);
63838fd1498Szrj
63938fd1498Szrj tree alloca_rz_mask = build_int_cst (size_type_node, redzone_mask);
64038fd1498Szrj tree redzone_size = build_int_cst (size_type_node, ASAN_RED_ZONE_SIZE);
64138fd1498Szrj
64238fd1498Szrj /* Extract lower bits from old_size. */
64338fd1498Szrj wide_int size_nonzero_bits = get_nonzero_bits (old_size);
64438fd1498Szrj wide_int rz_mask
64538fd1498Szrj = wi::uhwi (redzone_mask, wi::get_precision (size_nonzero_bits));
64638fd1498Szrj wide_int old_size_lower_bits = wi::bit_and (size_nonzero_bits, rz_mask);
64738fd1498Szrj
64838fd1498Szrj /* If alloca size is aligned to ASAN_RED_ZONE_SIZE, we don't need partial
64938fd1498Szrj redzone. Otherwise, compute its size here. */
65038fd1498Szrj if (wi::ne_p (old_size_lower_bits, 0))
65138fd1498Szrj {
65238fd1498Szrj /* misalign = size & (ASAN_RED_ZONE_SIZE - 1)
65338fd1498Szrj partial_size = ASAN_RED_ZONE_SIZE - misalign. */
65438fd1498Szrj g = gimple_build_assign (make_ssa_name (size_type_node, NULL),
65538fd1498Szrj BIT_AND_EXPR, old_size, alloca_rz_mask);
65638fd1498Szrj gsi_insert_before (iter, g, GSI_SAME_STMT);
65738fd1498Szrj tree misalign = gimple_assign_lhs (g);
65838fd1498Szrj g = gimple_build_assign (make_ssa_name (size_type_node, NULL), MINUS_EXPR,
65938fd1498Szrj redzone_size, misalign);
66038fd1498Szrj gsi_insert_before (iter, g, GSI_SAME_STMT);
66138fd1498Szrj partial_size = gimple_assign_lhs (g);
66238fd1498Szrj }
66338fd1498Szrj
66438fd1498Szrj /* additional_size = align + ASAN_RED_ZONE_SIZE. */
66538fd1498Szrj tree additional_size = build_int_cst (size_type_node, align / BITS_PER_UNIT
66638fd1498Szrj + ASAN_RED_ZONE_SIZE);
66738fd1498Szrj /* If alloca has partial redzone, include it to additional_size too. */
66838fd1498Szrj if (partial_size)
66938fd1498Szrj {
67038fd1498Szrj /* additional_size += partial_size. */
67138fd1498Szrj g = gimple_build_assign (make_ssa_name (size_type_node), PLUS_EXPR,
67238fd1498Szrj partial_size, additional_size);
67338fd1498Szrj gsi_insert_before (iter, g, GSI_SAME_STMT);
67438fd1498Szrj additional_size = gimple_assign_lhs (g);
67538fd1498Szrj }
67638fd1498Szrj
67738fd1498Szrj /* new_size = old_size + additional_size. */
67838fd1498Szrj g = gimple_build_assign (make_ssa_name (size_type_node), PLUS_EXPR, old_size,
67938fd1498Szrj additional_size);
68038fd1498Szrj gsi_insert_before (iter, g, GSI_SAME_STMT);
68138fd1498Szrj tree new_size = gimple_assign_lhs (g);
68238fd1498Szrj
68338fd1498Szrj /* Build new __builtin_alloca call:
68438fd1498Szrj new_alloca_with_rz = __builtin_alloca (new_size, align). */
68538fd1498Szrj tree fn = builtin_decl_implicit (BUILT_IN_ALLOCA_WITH_ALIGN);
68638fd1498Szrj gg = gimple_build_call (fn, 2, new_size,
68738fd1498Szrj build_int_cst (size_type_node, align));
68838fd1498Szrj tree new_alloca_with_rz = make_ssa_name (ptr_type, gg);
68938fd1498Szrj gimple_call_set_lhs (gg, new_alloca_with_rz);
69038fd1498Szrj gsi_insert_before (iter, gg, GSI_SAME_STMT);
69138fd1498Szrj
69238fd1498Szrj /* new_alloca = new_alloca_with_rz + align. */
69338fd1498Szrj g = gimple_build_assign (make_ssa_name (ptr_type), POINTER_PLUS_EXPR,
69438fd1498Szrj new_alloca_with_rz,
69538fd1498Szrj build_int_cst (size_type_node,
69638fd1498Szrj align / BITS_PER_UNIT));
69738fd1498Szrj gsi_insert_before (iter, g, GSI_SAME_STMT);
69838fd1498Szrj tree new_alloca = gimple_assign_lhs (g);
69938fd1498Szrj
70038fd1498Szrj /* Poison newly created alloca redzones:
70138fd1498Szrj __asan_alloca_poison (new_alloca, old_size). */
70238fd1498Szrj fn = builtin_decl_implicit (BUILT_IN_ASAN_ALLOCA_POISON);
70338fd1498Szrj gg = gimple_build_call (fn, 2, new_alloca, old_size);
70438fd1498Szrj gsi_insert_before (iter, gg, GSI_SAME_STMT);
70538fd1498Szrj
70638fd1498Szrj /* Save new_alloca_with_rz value into last_alloca to use it during
70738fd1498Szrj allocas unpoisoning. */
70838fd1498Szrj g = gimple_build_assign (last_alloca, new_alloca_with_rz);
70938fd1498Szrj gsi_insert_before (iter, g, GSI_SAME_STMT);
71038fd1498Szrj
71138fd1498Szrj /* Finally, replace old alloca ptr with NEW_ALLOCA. */
71238fd1498Szrj replace_call_with_value (iter, new_alloca);
71338fd1498Szrj }
71438fd1498Szrj
71538fd1498Szrj /* Return the memory references contained in a gimple statement
71638fd1498Szrj representing a builtin call that has to do with memory access. */
71738fd1498Szrj
71838fd1498Szrj static bool
71938fd1498Szrj get_mem_refs_of_builtin_call (gcall *call,
72038fd1498Szrj asan_mem_ref *src0,
72138fd1498Szrj tree *src0_len,
72238fd1498Szrj bool *src0_is_store,
72338fd1498Szrj asan_mem_ref *src1,
72438fd1498Szrj tree *src1_len,
72538fd1498Szrj bool *src1_is_store,
72638fd1498Szrj asan_mem_ref *dst,
72738fd1498Szrj tree *dst_len,
72838fd1498Szrj bool *dst_is_store,
72938fd1498Szrj bool *dest_is_deref,
73038fd1498Szrj bool *intercepted_p,
73138fd1498Szrj gimple_stmt_iterator *iter = NULL)
73238fd1498Szrj {
73338fd1498Szrj gcc_checking_assert (gimple_call_builtin_p (call, BUILT_IN_NORMAL));
73438fd1498Szrj
73538fd1498Szrj tree callee = gimple_call_fndecl (call);
73638fd1498Szrj tree source0 = NULL_TREE, source1 = NULL_TREE,
73738fd1498Szrj dest = NULL_TREE, len = NULL_TREE;
73838fd1498Szrj bool is_store = true, got_reference_p = false;
73938fd1498Szrj HOST_WIDE_INT access_size = 1;
74038fd1498Szrj
74138fd1498Szrj *intercepted_p = asan_intercepted_p ((DECL_FUNCTION_CODE (callee)));
74238fd1498Szrj
74338fd1498Szrj switch (DECL_FUNCTION_CODE (callee))
74438fd1498Szrj {
74538fd1498Szrj /* (s, s, n) style memops. */
74638fd1498Szrj case BUILT_IN_BCMP:
74738fd1498Szrj case BUILT_IN_MEMCMP:
74838fd1498Szrj source0 = gimple_call_arg (call, 0);
74938fd1498Szrj source1 = gimple_call_arg (call, 1);
75038fd1498Szrj len = gimple_call_arg (call, 2);
75138fd1498Szrj break;
75238fd1498Szrj
75338fd1498Szrj /* (src, dest, n) style memops. */
75438fd1498Szrj case BUILT_IN_BCOPY:
75538fd1498Szrj source0 = gimple_call_arg (call, 0);
75638fd1498Szrj dest = gimple_call_arg (call, 1);
75738fd1498Szrj len = gimple_call_arg (call, 2);
75838fd1498Szrj break;
75938fd1498Szrj
76038fd1498Szrj /* (dest, src, n) style memops. */
76138fd1498Szrj case BUILT_IN_MEMCPY:
76238fd1498Szrj case BUILT_IN_MEMCPY_CHK:
76338fd1498Szrj case BUILT_IN_MEMMOVE:
76438fd1498Szrj case BUILT_IN_MEMMOVE_CHK:
76538fd1498Szrj case BUILT_IN_MEMPCPY:
76638fd1498Szrj case BUILT_IN_MEMPCPY_CHK:
76738fd1498Szrj dest = gimple_call_arg (call, 0);
76838fd1498Szrj source0 = gimple_call_arg (call, 1);
76938fd1498Szrj len = gimple_call_arg (call, 2);
77038fd1498Szrj break;
77138fd1498Szrj
77238fd1498Szrj /* (dest, n) style memops. */
77338fd1498Szrj case BUILT_IN_BZERO:
77438fd1498Szrj dest = gimple_call_arg (call, 0);
77538fd1498Szrj len = gimple_call_arg (call, 1);
77638fd1498Szrj break;
77738fd1498Szrj
77838fd1498Szrj /* (dest, x, n) style memops*/
77938fd1498Szrj case BUILT_IN_MEMSET:
78038fd1498Szrj case BUILT_IN_MEMSET_CHK:
78138fd1498Szrj dest = gimple_call_arg (call, 0);
78238fd1498Szrj len = gimple_call_arg (call, 2);
78338fd1498Szrj break;
78438fd1498Szrj
78538fd1498Szrj case BUILT_IN_STRLEN:
78638fd1498Szrj source0 = gimple_call_arg (call, 0);
78738fd1498Szrj len = gimple_call_lhs (call);
78838fd1498Szrj break;
78938fd1498Szrj
79038fd1498Szrj case BUILT_IN_STACK_RESTORE:
79138fd1498Szrj handle_builtin_stack_restore (call, iter);
79238fd1498Szrj break;
79338fd1498Szrj
79438fd1498Szrj CASE_BUILT_IN_ALLOCA:
79538fd1498Szrj handle_builtin_alloca (call, iter);
79638fd1498Szrj break;
79738fd1498Szrj /* And now the __atomic* and __sync builtins.
79838fd1498Szrj These are handled differently from the classical memory memory
79938fd1498Szrj access builtins above. */
80038fd1498Szrj
80138fd1498Szrj case BUILT_IN_ATOMIC_LOAD_1:
80238fd1498Szrj is_store = false;
80338fd1498Szrj /* FALLTHRU */
80438fd1498Szrj case BUILT_IN_SYNC_FETCH_AND_ADD_1:
80538fd1498Szrj case BUILT_IN_SYNC_FETCH_AND_SUB_1:
80638fd1498Szrj case BUILT_IN_SYNC_FETCH_AND_OR_1:
80738fd1498Szrj case BUILT_IN_SYNC_FETCH_AND_AND_1:
80838fd1498Szrj case BUILT_IN_SYNC_FETCH_AND_XOR_1:
80938fd1498Szrj case BUILT_IN_SYNC_FETCH_AND_NAND_1:
81038fd1498Szrj case BUILT_IN_SYNC_ADD_AND_FETCH_1:
81138fd1498Szrj case BUILT_IN_SYNC_SUB_AND_FETCH_1:
81238fd1498Szrj case BUILT_IN_SYNC_OR_AND_FETCH_1:
81338fd1498Szrj case BUILT_IN_SYNC_AND_AND_FETCH_1:
81438fd1498Szrj case BUILT_IN_SYNC_XOR_AND_FETCH_1:
81538fd1498Szrj case BUILT_IN_SYNC_NAND_AND_FETCH_1:
81638fd1498Szrj case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_1:
81738fd1498Szrj case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_1:
81838fd1498Szrj case BUILT_IN_SYNC_LOCK_TEST_AND_SET_1:
81938fd1498Szrj case BUILT_IN_SYNC_LOCK_RELEASE_1:
82038fd1498Szrj case BUILT_IN_ATOMIC_EXCHANGE_1:
82138fd1498Szrj case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_1:
82238fd1498Szrj case BUILT_IN_ATOMIC_STORE_1:
82338fd1498Szrj case BUILT_IN_ATOMIC_ADD_FETCH_1:
82438fd1498Szrj case BUILT_IN_ATOMIC_SUB_FETCH_1:
82538fd1498Szrj case BUILT_IN_ATOMIC_AND_FETCH_1:
82638fd1498Szrj case BUILT_IN_ATOMIC_NAND_FETCH_1:
82738fd1498Szrj case BUILT_IN_ATOMIC_XOR_FETCH_1:
82838fd1498Szrj case BUILT_IN_ATOMIC_OR_FETCH_1:
82938fd1498Szrj case BUILT_IN_ATOMIC_FETCH_ADD_1:
83038fd1498Szrj case BUILT_IN_ATOMIC_FETCH_SUB_1:
83138fd1498Szrj case BUILT_IN_ATOMIC_FETCH_AND_1:
83238fd1498Szrj case BUILT_IN_ATOMIC_FETCH_NAND_1:
83338fd1498Szrj case BUILT_IN_ATOMIC_FETCH_XOR_1:
83438fd1498Szrj case BUILT_IN_ATOMIC_FETCH_OR_1:
83538fd1498Szrj access_size = 1;
83638fd1498Szrj goto do_atomic;
83738fd1498Szrj
83838fd1498Szrj case BUILT_IN_ATOMIC_LOAD_2:
83938fd1498Szrj is_store = false;
84038fd1498Szrj /* FALLTHRU */
84138fd1498Szrj case BUILT_IN_SYNC_FETCH_AND_ADD_2:
84238fd1498Szrj case BUILT_IN_SYNC_FETCH_AND_SUB_2:
84338fd1498Szrj case BUILT_IN_SYNC_FETCH_AND_OR_2:
84438fd1498Szrj case BUILT_IN_SYNC_FETCH_AND_AND_2:
84538fd1498Szrj case BUILT_IN_SYNC_FETCH_AND_XOR_2:
84638fd1498Szrj case BUILT_IN_SYNC_FETCH_AND_NAND_2:
84738fd1498Szrj case BUILT_IN_SYNC_ADD_AND_FETCH_2:
84838fd1498Szrj case BUILT_IN_SYNC_SUB_AND_FETCH_2:
84938fd1498Szrj case BUILT_IN_SYNC_OR_AND_FETCH_2:
85038fd1498Szrj case BUILT_IN_SYNC_AND_AND_FETCH_2:
85138fd1498Szrj case BUILT_IN_SYNC_XOR_AND_FETCH_2:
85238fd1498Szrj case BUILT_IN_SYNC_NAND_AND_FETCH_2:
85338fd1498Szrj case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_2:
85438fd1498Szrj case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_2:
85538fd1498Szrj case BUILT_IN_SYNC_LOCK_TEST_AND_SET_2:
85638fd1498Szrj case BUILT_IN_SYNC_LOCK_RELEASE_2:
85738fd1498Szrj case BUILT_IN_ATOMIC_EXCHANGE_2:
85838fd1498Szrj case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_2:
85938fd1498Szrj case BUILT_IN_ATOMIC_STORE_2:
86038fd1498Szrj case BUILT_IN_ATOMIC_ADD_FETCH_2:
86138fd1498Szrj case BUILT_IN_ATOMIC_SUB_FETCH_2:
86238fd1498Szrj case BUILT_IN_ATOMIC_AND_FETCH_2:
86338fd1498Szrj case BUILT_IN_ATOMIC_NAND_FETCH_2:
86438fd1498Szrj case BUILT_IN_ATOMIC_XOR_FETCH_2:
86538fd1498Szrj case BUILT_IN_ATOMIC_OR_FETCH_2:
86638fd1498Szrj case BUILT_IN_ATOMIC_FETCH_ADD_2:
86738fd1498Szrj case BUILT_IN_ATOMIC_FETCH_SUB_2:
86838fd1498Szrj case BUILT_IN_ATOMIC_FETCH_AND_2:
86938fd1498Szrj case BUILT_IN_ATOMIC_FETCH_NAND_2:
87038fd1498Szrj case BUILT_IN_ATOMIC_FETCH_XOR_2:
87138fd1498Szrj case BUILT_IN_ATOMIC_FETCH_OR_2:
87238fd1498Szrj access_size = 2;
87338fd1498Szrj goto do_atomic;
87438fd1498Szrj
87538fd1498Szrj case BUILT_IN_ATOMIC_LOAD_4:
87638fd1498Szrj is_store = false;
87738fd1498Szrj /* FALLTHRU */
87838fd1498Szrj case BUILT_IN_SYNC_FETCH_AND_ADD_4:
87938fd1498Szrj case BUILT_IN_SYNC_FETCH_AND_SUB_4:
88038fd1498Szrj case BUILT_IN_SYNC_FETCH_AND_OR_4:
88138fd1498Szrj case BUILT_IN_SYNC_FETCH_AND_AND_4:
88238fd1498Szrj case BUILT_IN_SYNC_FETCH_AND_XOR_4:
88338fd1498Szrj case BUILT_IN_SYNC_FETCH_AND_NAND_4:
88438fd1498Szrj case BUILT_IN_SYNC_ADD_AND_FETCH_4:
88538fd1498Szrj case BUILT_IN_SYNC_SUB_AND_FETCH_4:
88638fd1498Szrj case BUILT_IN_SYNC_OR_AND_FETCH_4:
88738fd1498Szrj case BUILT_IN_SYNC_AND_AND_FETCH_4:
88838fd1498Szrj case BUILT_IN_SYNC_XOR_AND_FETCH_4:
88938fd1498Szrj case BUILT_IN_SYNC_NAND_AND_FETCH_4:
89038fd1498Szrj case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_4:
89138fd1498Szrj case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_4:
89238fd1498Szrj case BUILT_IN_SYNC_LOCK_TEST_AND_SET_4:
89338fd1498Szrj case BUILT_IN_SYNC_LOCK_RELEASE_4:
89438fd1498Szrj case BUILT_IN_ATOMIC_EXCHANGE_4:
89538fd1498Szrj case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_4:
89638fd1498Szrj case BUILT_IN_ATOMIC_STORE_4:
89738fd1498Szrj case BUILT_IN_ATOMIC_ADD_FETCH_4:
89838fd1498Szrj case BUILT_IN_ATOMIC_SUB_FETCH_4:
89938fd1498Szrj case BUILT_IN_ATOMIC_AND_FETCH_4:
90038fd1498Szrj case BUILT_IN_ATOMIC_NAND_FETCH_4:
90138fd1498Szrj case BUILT_IN_ATOMIC_XOR_FETCH_4:
90238fd1498Szrj case BUILT_IN_ATOMIC_OR_FETCH_4:
90338fd1498Szrj case BUILT_IN_ATOMIC_FETCH_ADD_4:
90438fd1498Szrj case BUILT_IN_ATOMIC_FETCH_SUB_4:
90538fd1498Szrj case BUILT_IN_ATOMIC_FETCH_AND_4:
90638fd1498Szrj case BUILT_IN_ATOMIC_FETCH_NAND_4:
90738fd1498Szrj case BUILT_IN_ATOMIC_FETCH_XOR_4:
90838fd1498Szrj case BUILT_IN_ATOMIC_FETCH_OR_4:
90938fd1498Szrj access_size = 4;
91038fd1498Szrj goto do_atomic;
91138fd1498Szrj
91238fd1498Szrj case BUILT_IN_ATOMIC_LOAD_8:
91338fd1498Szrj is_store = false;
91438fd1498Szrj /* FALLTHRU */
91538fd1498Szrj case BUILT_IN_SYNC_FETCH_AND_ADD_8:
91638fd1498Szrj case BUILT_IN_SYNC_FETCH_AND_SUB_8:
91738fd1498Szrj case BUILT_IN_SYNC_FETCH_AND_OR_8:
91838fd1498Szrj case BUILT_IN_SYNC_FETCH_AND_AND_8:
91938fd1498Szrj case BUILT_IN_SYNC_FETCH_AND_XOR_8:
92038fd1498Szrj case BUILT_IN_SYNC_FETCH_AND_NAND_8:
92138fd1498Szrj case BUILT_IN_SYNC_ADD_AND_FETCH_8:
92238fd1498Szrj case BUILT_IN_SYNC_SUB_AND_FETCH_8:
92338fd1498Szrj case BUILT_IN_SYNC_OR_AND_FETCH_8:
92438fd1498Szrj case BUILT_IN_SYNC_AND_AND_FETCH_8:
92538fd1498Szrj case BUILT_IN_SYNC_XOR_AND_FETCH_8:
92638fd1498Szrj case BUILT_IN_SYNC_NAND_AND_FETCH_8:
92738fd1498Szrj case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_8:
92838fd1498Szrj case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_8:
92938fd1498Szrj case BUILT_IN_SYNC_LOCK_TEST_AND_SET_8:
93038fd1498Szrj case BUILT_IN_SYNC_LOCK_RELEASE_8:
93138fd1498Szrj case BUILT_IN_ATOMIC_EXCHANGE_8:
93238fd1498Szrj case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_8:
93338fd1498Szrj case BUILT_IN_ATOMIC_STORE_8:
93438fd1498Szrj case BUILT_IN_ATOMIC_ADD_FETCH_8:
93538fd1498Szrj case BUILT_IN_ATOMIC_SUB_FETCH_8:
93638fd1498Szrj case BUILT_IN_ATOMIC_AND_FETCH_8:
93738fd1498Szrj case BUILT_IN_ATOMIC_NAND_FETCH_8:
93838fd1498Szrj case BUILT_IN_ATOMIC_XOR_FETCH_8:
93938fd1498Szrj case BUILT_IN_ATOMIC_OR_FETCH_8:
94038fd1498Szrj case BUILT_IN_ATOMIC_FETCH_ADD_8:
94138fd1498Szrj case BUILT_IN_ATOMIC_FETCH_SUB_8:
94238fd1498Szrj case BUILT_IN_ATOMIC_FETCH_AND_8:
94338fd1498Szrj case BUILT_IN_ATOMIC_FETCH_NAND_8:
94438fd1498Szrj case BUILT_IN_ATOMIC_FETCH_XOR_8:
94538fd1498Szrj case BUILT_IN_ATOMIC_FETCH_OR_8:
94638fd1498Szrj access_size = 8;
94738fd1498Szrj goto do_atomic;
94838fd1498Szrj
94938fd1498Szrj case BUILT_IN_ATOMIC_LOAD_16:
95038fd1498Szrj is_store = false;
95138fd1498Szrj /* FALLTHRU */
95238fd1498Szrj case BUILT_IN_SYNC_FETCH_AND_ADD_16:
95338fd1498Szrj case BUILT_IN_SYNC_FETCH_AND_SUB_16:
95438fd1498Szrj case BUILT_IN_SYNC_FETCH_AND_OR_16:
95538fd1498Szrj case BUILT_IN_SYNC_FETCH_AND_AND_16:
95638fd1498Szrj case BUILT_IN_SYNC_FETCH_AND_XOR_16:
95738fd1498Szrj case BUILT_IN_SYNC_FETCH_AND_NAND_16:
95838fd1498Szrj case BUILT_IN_SYNC_ADD_AND_FETCH_16:
95938fd1498Szrj case BUILT_IN_SYNC_SUB_AND_FETCH_16:
96038fd1498Szrj case BUILT_IN_SYNC_OR_AND_FETCH_16:
96138fd1498Szrj case BUILT_IN_SYNC_AND_AND_FETCH_16:
96238fd1498Szrj case BUILT_IN_SYNC_XOR_AND_FETCH_16:
96338fd1498Szrj case BUILT_IN_SYNC_NAND_AND_FETCH_16:
96438fd1498Szrj case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_16:
96538fd1498Szrj case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_16:
96638fd1498Szrj case BUILT_IN_SYNC_LOCK_TEST_AND_SET_16:
96738fd1498Szrj case BUILT_IN_SYNC_LOCK_RELEASE_16:
96838fd1498Szrj case BUILT_IN_ATOMIC_EXCHANGE_16:
96938fd1498Szrj case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_16:
97038fd1498Szrj case BUILT_IN_ATOMIC_STORE_16:
97138fd1498Szrj case BUILT_IN_ATOMIC_ADD_FETCH_16:
97238fd1498Szrj case BUILT_IN_ATOMIC_SUB_FETCH_16:
97338fd1498Szrj case BUILT_IN_ATOMIC_AND_FETCH_16:
97438fd1498Szrj case BUILT_IN_ATOMIC_NAND_FETCH_16:
97538fd1498Szrj case BUILT_IN_ATOMIC_XOR_FETCH_16:
97638fd1498Szrj case BUILT_IN_ATOMIC_OR_FETCH_16:
97738fd1498Szrj case BUILT_IN_ATOMIC_FETCH_ADD_16:
97838fd1498Szrj case BUILT_IN_ATOMIC_FETCH_SUB_16:
97938fd1498Szrj case BUILT_IN_ATOMIC_FETCH_AND_16:
98038fd1498Szrj case BUILT_IN_ATOMIC_FETCH_NAND_16:
98138fd1498Szrj case BUILT_IN_ATOMIC_FETCH_XOR_16:
98238fd1498Szrj case BUILT_IN_ATOMIC_FETCH_OR_16:
98338fd1498Szrj access_size = 16;
98438fd1498Szrj /* FALLTHRU */
98538fd1498Szrj do_atomic:
98638fd1498Szrj {
98738fd1498Szrj dest = gimple_call_arg (call, 0);
98838fd1498Szrj /* DEST represents the address of a memory location.
98938fd1498Szrj instrument_derefs wants the memory location, so lets
99038fd1498Szrj dereference the address DEST before handing it to
99138fd1498Szrj instrument_derefs. */
99238fd1498Szrj tree type = build_nonstandard_integer_type (access_size
99338fd1498Szrj * BITS_PER_UNIT, 1);
99438fd1498Szrj dest = build2 (MEM_REF, type, dest,
99538fd1498Szrj build_int_cst (build_pointer_type (char_type_node), 0));
99638fd1498Szrj break;
99738fd1498Szrj }
99838fd1498Szrj
99938fd1498Szrj default:
100038fd1498Szrj /* The other builtins memory access are not instrumented in this
100138fd1498Szrj function because they either don't have any length parameter,
100238fd1498Szrj or their length parameter is just a limit. */
100338fd1498Szrj break;
100438fd1498Szrj }
100538fd1498Szrj
100638fd1498Szrj if (len != NULL_TREE)
100738fd1498Szrj {
100838fd1498Szrj if (source0 != NULL_TREE)
100938fd1498Szrj {
101038fd1498Szrj src0->start = source0;
101138fd1498Szrj src0->access_size = access_size;
101238fd1498Szrj *src0_len = len;
101338fd1498Szrj *src0_is_store = false;
101438fd1498Szrj }
101538fd1498Szrj
101638fd1498Szrj if (source1 != NULL_TREE)
101738fd1498Szrj {
101838fd1498Szrj src1->start = source1;
101938fd1498Szrj src1->access_size = access_size;
102038fd1498Szrj *src1_len = len;
102138fd1498Szrj *src1_is_store = false;
102238fd1498Szrj }
102338fd1498Szrj
102438fd1498Szrj if (dest != NULL_TREE)
102538fd1498Szrj {
102638fd1498Szrj dst->start = dest;
102738fd1498Szrj dst->access_size = access_size;
102838fd1498Szrj *dst_len = len;
102938fd1498Szrj *dst_is_store = true;
103038fd1498Szrj }
103138fd1498Szrj
103238fd1498Szrj got_reference_p = true;
103338fd1498Szrj }
103438fd1498Szrj else if (dest)
103538fd1498Szrj {
103638fd1498Szrj dst->start = dest;
103738fd1498Szrj dst->access_size = access_size;
103838fd1498Szrj *dst_len = NULL_TREE;
103938fd1498Szrj *dst_is_store = is_store;
104038fd1498Szrj *dest_is_deref = true;
104138fd1498Szrj got_reference_p = true;
104238fd1498Szrj }
104338fd1498Szrj
104438fd1498Szrj return got_reference_p;
104538fd1498Szrj }
104638fd1498Szrj
104738fd1498Szrj /* Return true iff a given gimple statement has been instrumented.
104838fd1498Szrj Note that the statement is "defined" by the memory references it
104938fd1498Szrj contains. */
105038fd1498Szrj
105138fd1498Szrj static bool
has_stmt_been_instrumented_p(gimple * stmt)105238fd1498Szrj has_stmt_been_instrumented_p (gimple *stmt)
105338fd1498Szrj {
105438fd1498Szrj if (gimple_assign_single_p (stmt))
105538fd1498Szrj {
105638fd1498Szrj bool r_is_store;
105738fd1498Szrj asan_mem_ref r;
105838fd1498Szrj asan_mem_ref_init (&r, NULL, 1);
105938fd1498Szrj
106038fd1498Szrj if (get_mem_ref_of_assignment (as_a <gassign *> (stmt), &r,
106138fd1498Szrj &r_is_store))
106238fd1498Szrj return has_mem_ref_been_instrumented (&r);
106338fd1498Szrj }
106438fd1498Szrj else if (gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
106538fd1498Szrj {
106638fd1498Szrj asan_mem_ref src0, src1, dest;
106738fd1498Szrj asan_mem_ref_init (&src0, NULL, 1);
106838fd1498Szrj asan_mem_ref_init (&src1, NULL, 1);
106938fd1498Szrj asan_mem_ref_init (&dest, NULL, 1);
107038fd1498Szrj
107138fd1498Szrj tree src0_len = NULL_TREE, src1_len = NULL_TREE, dest_len = NULL_TREE;
107238fd1498Szrj bool src0_is_store = false, src1_is_store = false,
107338fd1498Szrj dest_is_store = false, dest_is_deref = false, intercepted_p = true;
107438fd1498Szrj if (get_mem_refs_of_builtin_call (as_a <gcall *> (stmt),
107538fd1498Szrj &src0, &src0_len, &src0_is_store,
107638fd1498Szrj &src1, &src1_len, &src1_is_store,
107738fd1498Szrj &dest, &dest_len, &dest_is_store,
107838fd1498Szrj &dest_is_deref, &intercepted_p))
107938fd1498Szrj {
108038fd1498Szrj if (src0.start != NULL_TREE
108138fd1498Szrj && !has_mem_ref_been_instrumented (&src0, src0_len))
108238fd1498Szrj return false;
108338fd1498Szrj
108438fd1498Szrj if (src1.start != NULL_TREE
108538fd1498Szrj && !has_mem_ref_been_instrumented (&src1, src1_len))
108638fd1498Szrj return false;
108738fd1498Szrj
108838fd1498Szrj if (dest.start != NULL_TREE
108938fd1498Szrj && !has_mem_ref_been_instrumented (&dest, dest_len))
109038fd1498Szrj return false;
109138fd1498Szrj
109238fd1498Szrj return true;
109338fd1498Szrj }
109438fd1498Szrj }
109538fd1498Szrj else if (is_gimple_call (stmt) && gimple_store_p (stmt))
109638fd1498Szrj {
109738fd1498Szrj asan_mem_ref r;
109838fd1498Szrj asan_mem_ref_init (&r, NULL, 1);
109938fd1498Szrj
110038fd1498Szrj r.start = gimple_call_lhs (stmt);
110138fd1498Szrj r.access_size = int_size_in_bytes (TREE_TYPE (r.start));
110238fd1498Szrj return has_mem_ref_been_instrumented (&r);
110338fd1498Szrj }
110438fd1498Szrj
110538fd1498Szrj return false;
110638fd1498Szrj }
110738fd1498Szrj
110838fd1498Szrj /* Insert a memory reference into the hash table. */
110938fd1498Szrj
111038fd1498Szrj static void
update_mem_ref_hash_table(tree ref,HOST_WIDE_INT access_size)111138fd1498Szrj update_mem_ref_hash_table (tree ref, HOST_WIDE_INT access_size)
111238fd1498Szrj {
111338fd1498Szrj hash_table<asan_mem_ref_hasher> *ht = get_mem_ref_hash_table ();
111438fd1498Szrj
111538fd1498Szrj asan_mem_ref r;
111638fd1498Szrj asan_mem_ref_init (&r, ref, access_size);
111738fd1498Szrj
111838fd1498Szrj asan_mem_ref **slot = ht->find_slot (&r, INSERT);
111938fd1498Szrj if (*slot == NULL || (*slot)->access_size < access_size)
112038fd1498Szrj *slot = asan_mem_ref_new (ref, access_size);
112138fd1498Szrj }
112238fd1498Szrj
112338fd1498Szrj /* Initialize shadow_ptr_types array. */
112438fd1498Szrj
112538fd1498Szrj static void
asan_init_shadow_ptr_types(void)112638fd1498Szrj asan_init_shadow_ptr_types (void)
112738fd1498Szrj {
112838fd1498Szrj asan_shadow_set = new_alias_set ();
112938fd1498Szrj tree types[3] = { signed_char_type_node, short_integer_type_node,
113038fd1498Szrj integer_type_node };
113138fd1498Szrj
113238fd1498Szrj for (unsigned i = 0; i < 3; i++)
113338fd1498Szrj {
113438fd1498Szrj shadow_ptr_types[i] = build_distinct_type_copy (types[i]);
113538fd1498Szrj TYPE_ALIAS_SET (shadow_ptr_types[i]) = asan_shadow_set;
113638fd1498Szrj shadow_ptr_types[i] = build_pointer_type (shadow_ptr_types[i]);
113738fd1498Szrj }
113838fd1498Szrj
113938fd1498Szrj initialize_sanitizer_builtins ();
114038fd1498Szrj }
114138fd1498Szrj
114238fd1498Szrj /* Create ADDR_EXPR of STRING_CST with the PP pretty printer text. */
114338fd1498Szrj
114438fd1498Szrj static tree
asan_pp_string(pretty_printer * pp)114538fd1498Szrj asan_pp_string (pretty_printer *pp)
114638fd1498Szrj {
114738fd1498Szrj const char *buf = pp_formatted_text (pp);
114838fd1498Szrj size_t len = strlen (buf);
114938fd1498Szrj tree ret = build_string (len + 1, buf);
115038fd1498Szrj TREE_TYPE (ret)
115138fd1498Szrj = build_array_type (TREE_TYPE (shadow_ptr_types[0]),
115238fd1498Szrj build_index_type (size_int (len)));
115338fd1498Szrj TREE_READONLY (ret) = 1;
115438fd1498Szrj TREE_STATIC (ret) = 1;
115538fd1498Szrj return build1 (ADDR_EXPR, shadow_ptr_types[0], ret);
115638fd1498Szrj }
115738fd1498Szrj
115838fd1498Szrj /* Return a CONST_INT representing 4 subsequent shadow memory bytes. */
115938fd1498Szrj
116038fd1498Szrj static rtx
asan_shadow_cst(unsigned char shadow_bytes[4])116138fd1498Szrj asan_shadow_cst (unsigned char shadow_bytes[4])
116238fd1498Szrj {
116338fd1498Szrj int i;
116438fd1498Szrj unsigned HOST_WIDE_INT val = 0;
116538fd1498Szrj gcc_assert (WORDS_BIG_ENDIAN == BYTES_BIG_ENDIAN);
116638fd1498Szrj for (i = 0; i < 4; i++)
116738fd1498Szrj val |= (unsigned HOST_WIDE_INT) shadow_bytes[BYTES_BIG_ENDIAN ? 3 - i : i]
116838fd1498Szrj << (BITS_PER_UNIT * i);
116938fd1498Szrj return gen_int_mode (val, SImode);
117038fd1498Szrj }
117138fd1498Szrj
117238fd1498Szrj /* Clear shadow memory at SHADOW_MEM, LEN bytes. Can't call a library call here
117338fd1498Szrj though. */
117438fd1498Szrj
117538fd1498Szrj static void
asan_clear_shadow(rtx shadow_mem,HOST_WIDE_INT len)117638fd1498Szrj asan_clear_shadow (rtx shadow_mem, HOST_WIDE_INT len)
117738fd1498Szrj {
117838fd1498Szrj rtx_insn *insn, *insns, *jump;
117938fd1498Szrj rtx_code_label *top_label;
118038fd1498Szrj rtx end, addr, tmp;
118138fd1498Szrj
118238fd1498Szrj start_sequence ();
118338fd1498Szrj clear_storage (shadow_mem, GEN_INT (len), BLOCK_OP_NORMAL);
118438fd1498Szrj insns = get_insns ();
118538fd1498Szrj end_sequence ();
118638fd1498Szrj for (insn = insns; insn; insn = NEXT_INSN (insn))
118738fd1498Szrj if (CALL_P (insn))
118838fd1498Szrj break;
118938fd1498Szrj if (insn == NULL_RTX)
119038fd1498Szrj {
119138fd1498Szrj emit_insn (insns);
119238fd1498Szrj return;
119338fd1498Szrj }
119438fd1498Szrj
119538fd1498Szrj gcc_assert ((len & 3) == 0);
119638fd1498Szrj top_label = gen_label_rtx ();
119738fd1498Szrj addr = copy_to_mode_reg (Pmode, XEXP (shadow_mem, 0));
119838fd1498Szrj shadow_mem = adjust_automodify_address (shadow_mem, SImode, addr, 0);
119938fd1498Szrj end = force_reg (Pmode, plus_constant (Pmode, addr, len));
120038fd1498Szrj emit_label (top_label);
120138fd1498Szrj
120238fd1498Szrj emit_move_insn (shadow_mem, const0_rtx);
120338fd1498Szrj tmp = expand_simple_binop (Pmode, PLUS, addr, gen_int_mode (4, Pmode), addr,
120438fd1498Szrj true, OPTAB_LIB_WIDEN);
120538fd1498Szrj if (tmp != addr)
120638fd1498Szrj emit_move_insn (addr, tmp);
120738fd1498Szrj emit_cmp_and_jump_insns (addr, end, LT, NULL_RTX, Pmode, true, top_label);
120838fd1498Szrj jump = get_last_insn ();
120938fd1498Szrj gcc_assert (JUMP_P (jump));
121038fd1498Szrj add_reg_br_prob_note (jump,
121138fd1498Szrj profile_probability::guessed_always ()
121238fd1498Szrj .apply_scale (80, 100));
121338fd1498Szrj }
121438fd1498Szrj
121538fd1498Szrj void
asan_function_start(void)121638fd1498Szrj asan_function_start (void)
121738fd1498Szrj {
121838fd1498Szrj section *fnsec = function_section (current_function_decl);
121938fd1498Szrj switch_to_section (fnsec);
122038fd1498Szrj ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LASANPC",
122138fd1498Szrj current_function_funcdef_no);
122238fd1498Szrj }
122338fd1498Szrj
122438fd1498Szrj /* Return number of shadow bytes that are occupied by a local variable
122538fd1498Szrj of SIZE bytes. */
122638fd1498Szrj
122738fd1498Szrj static unsigned HOST_WIDE_INT
shadow_mem_size(unsigned HOST_WIDE_INT size)122838fd1498Szrj shadow_mem_size (unsigned HOST_WIDE_INT size)
122938fd1498Szrj {
123038fd1498Szrj /* It must be possible to align stack variables to granularity
123138fd1498Szrj of shadow memory. */
123238fd1498Szrj gcc_assert (BITS_PER_UNIT
123338fd1498Szrj * ASAN_SHADOW_GRANULARITY <= MAX_SUPPORTED_STACK_ALIGNMENT);
123438fd1498Szrj
123538fd1498Szrj return ROUND_UP (size, ASAN_SHADOW_GRANULARITY) / ASAN_SHADOW_GRANULARITY;
123638fd1498Szrj }
123738fd1498Szrj
123838fd1498Szrj /* Insert code to protect stack vars. The prologue sequence should be emitted
123938fd1498Szrj directly, epilogue sequence returned. BASE is the register holding the
124038fd1498Szrj stack base, against which OFFSETS array offsets are relative to, OFFSETS
124138fd1498Szrj array contains pairs of offsets in reverse order, always the end offset
124238fd1498Szrj of some gap that needs protection followed by starting offset,
124338fd1498Szrj and DECLS is an array of representative decls for each var partition.
124438fd1498Szrj LENGTH is the length of the OFFSETS array, DECLS array is LENGTH / 2 - 1
124538fd1498Szrj elements long (OFFSETS include gap before the first variable as well
124638fd1498Szrj as gaps after each stack variable). PBASE is, if non-NULL, some pseudo
124738fd1498Szrj register which stack vars DECL_RTLs are based on. Either BASE should be
124838fd1498Szrj assigned to PBASE, when not doing use after return protection, or
124938fd1498Szrj corresponding address based on __asan_stack_malloc* return value. */
125038fd1498Szrj
125138fd1498Szrj rtx_insn *
asan_emit_stack_protection(rtx base,rtx pbase,unsigned int alignb,HOST_WIDE_INT * offsets,tree * decls,int length)125238fd1498Szrj asan_emit_stack_protection (rtx base, rtx pbase, unsigned int alignb,
125338fd1498Szrj HOST_WIDE_INT *offsets, tree *decls, int length)
125438fd1498Szrj {
125538fd1498Szrj rtx shadow_base, shadow_mem, ret, mem, orig_base;
125638fd1498Szrj rtx_code_label *lab;
125738fd1498Szrj rtx_insn *insns;
125838fd1498Szrj char buf[32];
125938fd1498Szrj unsigned char shadow_bytes[4];
126038fd1498Szrj HOST_WIDE_INT base_offset = offsets[length - 1];
126138fd1498Szrj HOST_WIDE_INT base_align_bias = 0, offset, prev_offset;
126238fd1498Szrj HOST_WIDE_INT asan_frame_size = offsets[0] - base_offset;
126338fd1498Szrj HOST_WIDE_INT last_offset, last_size;
126438fd1498Szrj int l;
126538fd1498Szrj unsigned char cur_shadow_byte = ASAN_STACK_MAGIC_LEFT;
126638fd1498Szrj tree str_cst, decl, id;
126738fd1498Szrj int use_after_return_class = -1;
126838fd1498Szrj
126938fd1498Szrj if (shadow_ptr_types[0] == NULL_TREE)
127038fd1498Szrj asan_init_shadow_ptr_types ();
127138fd1498Szrj
127238fd1498Szrj /* First of all, prepare the description string. */
127338fd1498Szrj pretty_printer asan_pp;
127438fd1498Szrj
127538fd1498Szrj pp_decimal_int (&asan_pp, length / 2 - 1);
127638fd1498Szrj pp_space (&asan_pp);
127738fd1498Szrj for (l = length - 2; l; l -= 2)
127838fd1498Szrj {
127938fd1498Szrj tree decl = decls[l / 2 - 1];
128038fd1498Szrj pp_wide_integer (&asan_pp, offsets[l] - base_offset);
128138fd1498Szrj pp_space (&asan_pp);
128238fd1498Szrj pp_wide_integer (&asan_pp, offsets[l - 1] - offsets[l]);
128338fd1498Szrj pp_space (&asan_pp);
128438fd1498Szrj if (DECL_P (decl) && DECL_NAME (decl))
128538fd1498Szrj {
128638fd1498Szrj pp_decimal_int (&asan_pp, IDENTIFIER_LENGTH (DECL_NAME (decl)));
128738fd1498Szrj pp_space (&asan_pp);
128838fd1498Szrj pp_tree_identifier (&asan_pp, DECL_NAME (decl));
128938fd1498Szrj }
129038fd1498Szrj else
129138fd1498Szrj pp_string (&asan_pp, "9 <unknown>");
129238fd1498Szrj pp_space (&asan_pp);
129338fd1498Szrj }
129438fd1498Szrj str_cst = asan_pp_string (&asan_pp);
129538fd1498Szrj
129638fd1498Szrj /* Emit the prologue sequence. */
129738fd1498Szrj if (asan_frame_size > 32 && asan_frame_size <= 65536 && pbase
129838fd1498Szrj && ASAN_USE_AFTER_RETURN)
129938fd1498Szrj {
130038fd1498Szrj use_after_return_class = floor_log2 (asan_frame_size - 1) - 5;
130138fd1498Szrj /* __asan_stack_malloc_N guarantees alignment
130238fd1498Szrj N < 6 ? (64 << N) : 4096 bytes. */
130338fd1498Szrj if (alignb > (use_after_return_class < 6
130438fd1498Szrj ? (64U << use_after_return_class) : 4096U))
130538fd1498Szrj use_after_return_class = -1;
130638fd1498Szrj else if (alignb > ASAN_RED_ZONE_SIZE && (asan_frame_size & (alignb - 1)))
130738fd1498Szrj base_align_bias = ((asan_frame_size + alignb - 1)
130838fd1498Szrj & ~(alignb - HOST_WIDE_INT_1)) - asan_frame_size;
130938fd1498Szrj }
131038fd1498Szrj /* Align base if target is STRICT_ALIGNMENT. */
131138fd1498Szrj if (STRICT_ALIGNMENT)
131238fd1498Szrj base = expand_binop (Pmode, and_optab, base,
131338fd1498Szrj gen_int_mode (-((GET_MODE_ALIGNMENT (SImode)
131438fd1498Szrj << ASAN_SHADOW_SHIFT)
131538fd1498Szrj / BITS_PER_UNIT), Pmode), NULL_RTX,
131638fd1498Szrj 1, OPTAB_DIRECT);
131738fd1498Szrj
131838fd1498Szrj if (use_after_return_class == -1 && pbase)
131938fd1498Szrj emit_move_insn (pbase, base);
132038fd1498Szrj
132138fd1498Szrj base = expand_binop (Pmode, add_optab, base,
132238fd1498Szrj gen_int_mode (base_offset - base_align_bias, Pmode),
132338fd1498Szrj NULL_RTX, 1, OPTAB_DIRECT);
132438fd1498Szrj orig_base = NULL_RTX;
132538fd1498Szrj if (use_after_return_class != -1)
132638fd1498Szrj {
132738fd1498Szrj if (asan_detect_stack_use_after_return == NULL_TREE)
132838fd1498Szrj {
132938fd1498Szrj id = get_identifier ("__asan_option_detect_stack_use_after_return");
133038fd1498Szrj decl = build_decl (BUILTINS_LOCATION, VAR_DECL, id,
133138fd1498Szrj integer_type_node);
133238fd1498Szrj SET_DECL_ASSEMBLER_NAME (decl, id);
133338fd1498Szrj TREE_ADDRESSABLE (decl) = 1;
133438fd1498Szrj DECL_ARTIFICIAL (decl) = 1;
133538fd1498Szrj DECL_IGNORED_P (decl) = 1;
133638fd1498Szrj DECL_EXTERNAL (decl) = 1;
133738fd1498Szrj TREE_STATIC (decl) = 1;
133838fd1498Szrj TREE_PUBLIC (decl) = 1;
133938fd1498Szrj TREE_USED (decl) = 1;
134038fd1498Szrj asan_detect_stack_use_after_return = decl;
134138fd1498Szrj }
134238fd1498Szrj orig_base = gen_reg_rtx (Pmode);
134338fd1498Szrj emit_move_insn (orig_base, base);
134438fd1498Szrj ret = expand_normal (asan_detect_stack_use_after_return);
134538fd1498Szrj lab = gen_label_rtx ();
134638fd1498Szrj emit_cmp_and_jump_insns (ret, const0_rtx, EQ, NULL_RTX,
134738fd1498Szrj VOIDmode, 0, lab,
134838fd1498Szrj profile_probability::very_likely ());
134938fd1498Szrj snprintf (buf, sizeof buf, "__asan_stack_malloc_%d",
135038fd1498Szrj use_after_return_class);
135138fd1498Szrj ret = init_one_libfunc (buf);
135238fd1498Szrj ret = emit_library_call_value (ret, NULL_RTX, LCT_NORMAL, ptr_mode,
135338fd1498Szrj GEN_INT (asan_frame_size
135438fd1498Szrj + base_align_bias),
135538fd1498Szrj TYPE_MODE (pointer_sized_int_node));
135638fd1498Szrj /* __asan_stack_malloc_[n] returns a pointer to fake stack if succeeded
135738fd1498Szrj and NULL otherwise. Check RET value is NULL here and jump over the
135838fd1498Szrj BASE reassignment in this case. Otherwise, reassign BASE to RET. */
135938fd1498Szrj emit_cmp_and_jump_insns (ret, const0_rtx, EQ, NULL_RTX,
136038fd1498Szrj VOIDmode, 0, lab,
136138fd1498Szrj profile_probability:: very_unlikely ());
136238fd1498Szrj ret = convert_memory_address (Pmode, ret);
136338fd1498Szrj emit_move_insn (base, ret);
136438fd1498Szrj emit_label (lab);
136538fd1498Szrj emit_move_insn (pbase, expand_binop (Pmode, add_optab, base,
136638fd1498Szrj gen_int_mode (base_align_bias
136738fd1498Szrj - base_offset, Pmode),
136838fd1498Szrj NULL_RTX, 1, OPTAB_DIRECT));
136938fd1498Szrj }
137038fd1498Szrj mem = gen_rtx_MEM (ptr_mode, base);
137138fd1498Szrj mem = adjust_address (mem, VOIDmode, base_align_bias);
137238fd1498Szrj emit_move_insn (mem, gen_int_mode (ASAN_STACK_FRAME_MAGIC, ptr_mode));
137338fd1498Szrj mem = adjust_address (mem, VOIDmode, GET_MODE_SIZE (ptr_mode));
137438fd1498Szrj emit_move_insn (mem, expand_normal (str_cst));
137538fd1498Szrj mem = adjust_address (mem, VOIDmode, GET_MODE_SIZE (ptr_mode));
137638fd1498Szrj ASM_GENERATE_INTERNAL_LABEL (buf, "LASANPC", current_function_funcdef_no);
137738fd1498Szrj id = get_identifier (buf);
137838fd1498Szrj decl = build_decl (DECL_SOURCE_LOCATION (current_function_decl),
137938fd1498Szrj VAR_DECL, id, char_type_node);
138038fd1498Szrj SET_DECL_ASSEMBLER_NAME (decl, id);
138138fd1498Szrj TREE_ADDRESSABLE (decl) = 1;
138238fd1498Szrj TREE_READONLY (decl) = 1;
138338fd1498Szrj DECL_ARTIFICIAL (decl) = 1;
138438fd1498Szrj DECL_IGNORED_P (decl) = 1;
138538fd1498Szrj TREE_STATIC (decl) = 1;
138638fd1498Szrj TREE_PUBLIC (decl) = 0;
138738fd1498Szrj TREE_USED (decl) = 1;
138838fd1498Szrj DECL_INITIAL (decl) = decl;
138938fd1498Szrj TREE_ASM_WRITTEN (decl) = 1;
139038fd1498Szrj TREE_ASM_WRITTEN (id) = 1;
139138fd1498Szrj emit_move_insn (mem, expand_normal (build_fold_addr_expr (decl)));
139238fd1498Szrj shadow_base = expand_binop (Pmode, lshr_optab, base,
139338fd1498Szrj gen_int_shift_amount (Pmode, ASAN_SHADOW_SHIFT),
139438fd1498Szrj NULL_RTX, 1, OPTAB_DIRECT);
139538fd1498Szrj shadow_base
139638fd1498Szrj = plus_constant (Pmode, shadow_base,
139738fd1498Szrj asan_shadow_offset ()
139838fd1498Szrj + (base_align_bias >> ASAN_SHADOW_SHIFT));
139938fd1498Szrj gcc_assert (asan_shadow_set != -1
140038fd1498Szrj && (ASAN_RED_ZONE_SIZE >> ASAN_SHADOW_SHIFT) == 4);
140138fd1498Szrj shadow_mem = gen_rtx_MEM (SImode, shadow_base);
140238fd1498Szrj set_mem_alias_set (shadow_mem, asan_shadow_set);
140338fd1498Szrj if (STRICT_ALIGNMENT)
140438fd1498Szrj set_mem_align (shadow_mem, (GET_MODE_ALIGNMENT (SImode)));
140538fd1498Szrj prev_offset = base_offset;
140638fd1498Szrj for (l = length; l; l -= 2)
140738fd1498Szrj {
140838fd1498Szrj if (l == 2)
140938fd1498Szrj cur_shadow_byte = ASAN_STACK_MAGIC_RIGHT;
141038fd1498Szrj offset = offsets[l - 1];
141138fd1498Szrj if ((offset - base_offset) & (ASAN_RED_ZONE_SIZE - 1))
141238fd1498Szrj {
141338fd1498Szrj int i;
141438fd1498Szrj HOST_WIDE_INT aoff
141538fd1498Szrj = base_offset + ((offset - base_offset)
141638fd1498Szrj & ~(ASAN_RED_ZONE_SIZE - HOST_WIDE_INT_1));
141738fd1498Szrj shadow_mem = adjust_address (shadow_mem, VOIDmode,
141838fd1498Szrj (aoff - prev_offset)
141938fd1498Szrj >> ASAN_SHADOW_SHIFT);
142038fd1498Szrj prev_offset = aoff;
142138fd1498Szrj for (i = 0; i < 4; i++, aoff += ASAN_SHADOW_GRANULARITY)
142238fd1498Szrj if (aoff < offset)
142338fd1498Szrj {
142438fd1498Szrj if (aoff < offset - (HOST_WIDE_INT)ASAN_SHADOW_GRANULARITY + 1)
142538fd1498Szrj shadow_bytes[i] = 0;
142638fd1498Szrj else
142738fd1498Szrj shadow_bytes[i] = offset - aoff;
142838fd1498Szrj }
142938fd1498Szrj else
143038fd1498Szrj shadow_bytes[i] = ASAN_STACK_MAGIC_MIDDLE;
143138fd1498Szrj emit_move_insn (shadow_mem, asan_shadow_cst (shadow_bytes));
143238fd1498Szrj offset = aoff;
143338fd1498Szrj }
143438fd1498Szrj while (offset <= offsets[l - 2] - ASAN_RED_ZONE_SIZE)
143538fd1498Szrj {
143638fd1498Szrj shadow_mem = adjust_address (shadow_mem, VOIDmode,
143738fd1498Szrj (offset - prev_offset)
143838fd1498Szrj >> ASAN_SHADOW_SHIFT);
143938fd1498Szrj prev_offset = offset;
144038fd1498Szrj memset (shadow_bytes, cur_shadow_byte, 4);
144138fd1498Szrj emit_move_insn (shadow_mem, asan_shadow_cst (shadow_bytes));
144238fd1498Szrj offset += ASAN_RED_ZONE_SIZE;
144338fd1498Szrj }
144438fd1498Szrj cur_shadow_byte = ASAN_STACK_MAGIC_MIDDLE;
144538fd1498Szrj }
144638fd1498Szrj do_pending_stack_adjust ();
144738fd1498Szrj
144838fd1498Szrj /* Construct epilogue sequence. */
144938fd1498Szrj start_sequence ();
145038fd1498Szrj
145138fd1498Szrj lab = NULL;
145238fd1498Szrj if (use_after_return_class != -1)
145338fd1498Szrj {
145438fd1498Szrj rtx_code_label *lab2 = gen_label_rtx ();
145538fd1498Szrj char c = (char) ASAN_STACK_MAGIC_USE_AFTER_RET;
145638fd1498Szrj emit_cmp_and_jump_insns (orig_base, base, EQ, NULL_RTX,
145738fd1498Szrj VOIDmode, 0, lab2,
145838fd1498Szrj profile_probability::very_likely ());
145938fd1498Szrj shadow_mem = gen_rtx_MEM (BLKmode, shadow_base);
146038fd1498Szrj set_mem_alias_set (shadow_mem, asan_shadow_set);
146138fd1498Szrj mem = gen_rtx_MEM (ptr_mode, base);
146238fd1498Szrj mem = adjust_address (mem, VOIDmode, base_align_bias);
146338fd1498Szrj emit_move_insn (mem, gen_int_mode (ASAN_STACK_RETIRED_MAGIC, ptr_mode));
146438fd1498Szrj unsigned HOST_WIDE_INT sz = asan_frame_size >> ASAN_SHADOW_SHIFT;
146538fd1498Szrj if (use_after_return_class < 5
146638fd1498Szrj && can_store_by_pieces (sz, builtin_memset_read_str, &c,
146738fd1498Szrj BITS_PER_UNIT, true))
146838fd1498Szrj store_by_pieces (shadow_mem, sz, builtin_memset_read_str, &c,
146938fd1498Szrj BITS_PER_UNIT, true, 0);
147038fd1498Szrj else if (use_after_return_class >= 5
147138fd1498Szrj || !set_storage_via_setmem (shadow_mem,
147238fd1498Szrj GEN_INT (sz),
147338fd1498Szrj gen_int_mode (c, QImode),
147438fd1498Szrj BITS_PER_UNIT, BITS_PER_UNIT,
147538fd1498Szrj -1, sz, sz, sz))
147638fd1498Szrj {
147738fd1498Szrj snprintf (buf, sizeof buf, "__asan_stack_free_%d",
147838fd1498Szrj use_after_return_class);
147938fd1498Szrj ret = init_one_libfunc (buf);
148038fd1498Szrj rtx addr = convert_memory_address (ptr_mode, base);
148138fd1498Szrj rtx orig_addr = convert_memory_address (ptr_mode, orig_base);
148238fd1498Szrj emit_library_call (ret, LCT_NORMAL, ptr_mode, addr, ptr_mode,
148338fd1498Szrj GEN_INT (asan_frame_size + base_align_bias),
148438fd1498Szrj TYPE_MODE (pointer_sized_int_node),
148538fd1498Szrj orig_addr, ptr_mode);
148638fd1498Szrj }
148738fd1498Szrj lab = gen_label_rtx ();
148838fd1498Szrj emit_jump (lab);
148938fd1498Szrj emit_label (lab2);
149038fd1498Szrj }
149138fd1498Szrj
149238fd1498Szrj shadow_mem = gen_rtx_MEM (BLKmode, shadow_base);
149338fd1498Szrj set_mem_alias_set (shadow_mem, asan_shadow_set);
149438fd1498Szrj
149538fd1498Szrj if (STRICT_ALIGNMENT)
149638fd1498Szrj set_mem_align (shadow_mem, (GET_MODE_ALIGNMENT (SImode)));
149738fd1498Szrj
149838fd1498Szrj prev_offset = base_offset;
149938fd1498Szrj last_offset = base_offset;
150038fd1498Szrj last_size = 0;
150138fd1498Szrj for (l = length; l; l -= 2)
150238fd1498Szrj {
150338fd1498Szrj offset = base_offset + ((offsets[l - 1] - base_offset)
150438fd1498Szrj & ~(ASAN_RED_ZONE_SIZE - HOST_WIDE_INT_1));
150538fd1498Szrj if (last_offset + last_size != offset)
150638fd1498Szrj {
150738fd1498Szrj shadow_mem = adjust_address (shadow_mem, VOIDmode,
150838fd1498Szrj (last_offset - prev_offset)
150938fd1498Szrj >> ASAN_SHADOW_SHIFT);
151038fd1498Szrj prev_offset = last_offset;
151138fd1498Szrj asan_clear_shadow (shadow_mem, last_size >> ASAN_SHADOW_SHIFT);
151238fd1498Szrj last_offset = offset;
151338fd1498Szrj last_size = 0;
151438fd1498Szrj }
151538fd1498Szrj last_size += base_offset + ((offsets[l - 2] - base_offset)
151638fd1498Szrj & ~(ASAN_RED_ZONE_SIZE - HOST_WIDE_INT_1))
151738fd1498Szrj - offset;
151838fd1498Szrj
151938fd1498Szrj /* Unpoison shadow memory that corresponds to a variable that is
152038fd1498Szrj is subject of use-after-return sanitization. */
152138fd1498Szrj if (l > 2)
152238fd1498Szrj {
152338fd1498Szrj decl = decls[l / 2 - 2];
152438fd1498Szrj if (asan_handled_variables != NULL
152538fd1498Szrj && asan_handled_variables->contains (decl))
152638fd1498Szrj {
152738fd1498Szrj HOST_WIDE_INT size = offsets[l - 3] - offsets[l - 2];
152838fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
152938fd1498Szrj {
153038fd1498Szrj const char *n = (DECL_NAME (decl)
153138fd1498Szrj ? IDENTIFIER_POINTER (DECL_NAME (decl))
153238fd1498Szrj : "<unknown>");
153338fd1498Szrj fprintf (dump_file, "Unpoisoning shadow stack for variable: "
153438fd1498Szrj "%s (%" PRId64 " B)\n", n, size);
153538fd1498Szrj }
153638fd1498Szrj
153738fd1498Szrj last_size += size & ~(ASAN_RED_ZONE_SIZE - HOST_WIDE_INT_1);
153838fd1498Szrj }
153938fd1498Szrj }
154038fd1498Szrj }
154138fd1498Szrj if (last_size)
154238fd1498Szrj {
154338fd1498Szrj shadow_mem = adjust_address (shadow_mem, VOIDmode,
154438fd1498Szrj (last_offset - prev_offset)
154538fd1498Szrj >> ASAN_SHADOW_SHIFT);
154638fd1498Szrj asan_clear_shadow (shadow_mem, last_size >> ASAN_SHADOW_SHIFT);
154738fd1498Szrj }
154838fd1498Szrj
154938fd1498Szrj /* Clean-up set with instrumented stack variables. */
155038fd1498Szrj delete asan_handled_variables;
155138fd1498Szrj asan_handled_variables = NULL;
155238fd1498Szrj delete asan_used_labels;
155338fd1498Szrj asan_used_labels = NULL;
155438fd1498Szrj
155538fd1498Szrj do_pending_stack_adjust ();
155638fd1498Szrj if (lab)
155738fd1498Szrj emit_label (lab);
155838fd1498Szrj
155938fd1498Szrj insns = get_insns ();
156038fd1498Szrj end_sequence ();
156138fd1498Szrj return insns;
156238fd1498Szrj }
156338fd1498Szrj
156438fd1498Szrj /* Emit __asan_allocas_unpoison (top, bot) call. The BASE parameter corresponds
156538fd1498Szrj to BOT argument, for TOP virtual_stack_dynamic_rtx is used. NEW_SEQUENCE
156638fd1498Szrj indicates whether we're emitting new instructions sequence or not. */
156738fd1498Szrj
156838fd1498Szrj rtx_insn *
asan_emit_allocas_unpoison(rtx top,rtx bot,rtx_insn * before)156938fd1498Szrj asan_emit_allocas_unpoison (rtx top, rtx bot, rtx_insn *before)
157038fd1498Szrj {
157138fd1498Szrj if (before)
157238fd1498Szrj push_to_sequence (before);
157338fd1498Szrj else
157438fd1498Szrj start_sequence ();
157538fd1498Szrj rtx ret = init_one_libfunc ("__asan_allocas_unpoison");
157638fd1498Szrj top = convert_memory_address (ptr_mode, top);
157738fd1498Szrj bot = convert_memory_address (ptr_mode, bot);
157838fd1498Szrj ret = emit_library_call_value (ret, NULL_RTX, LCT_NORMAL, ptr_mode,
157938fd1498Szrj top, ptr_mode, bot, ptr_mode);
158038fd1498Szrj
158138fd1498Szrj do_pending_stack_adjust ();
158238fd1498Szrj rtx_insn *insns = get_insns ();
158338fd1498Szrj end_sequence ();
158438fd1498Szrj return insns;
158538fd1498Szrj }
158638fd1498Szrj
158738fd1498Szrj /* Return true if DECL, a global var, might be overridden and needs
158838fd1498Szrj therefore a local alias. */
158938fd1498Szrj
159038fd1498Szrj static bool
asan_needs_local_alias(tree decl)159138fd1498Szrj asan_needs_local_alias (tree decl)
159238fd1498Szrj {
159338fd1498Szrj return DECL_WEAK (decl) || !targetm.binds_local_p (decl);
159438fd1498Szrj }
159538fd1498Szrj
159638fd1498Szrj /* Return true if DECL, a global var, is an artificial ODR indicator symbol
159738fd1498Szrj therefore doesn't need protection. */
159838fd1498Szrj
159938fd1498Szrj static bool
is_odr_indicator(tree decl)160038fd1498Szrj is_odr_indicator (tree decl)
160138fd1498Szrj {
160238fd1498Szrj return (DECL_ARTIFICIAL (decl)
160338fd1498Szrj && lookup_attribute ("asan odr indicator", DECL_ATTRIBUTES (decl)));
160438fd1498Szrj }
160538fd1498Szrj
160638fd1498Szrj /* Return true if DECL is a VAR_DECL that should be protected
160738fd1498Szrj by Address Sanitizer, by appending a red zone with protected
160838fd1498Szrj shadow memory after it and aligning it to at least
160938fd1498Szrj ASAN_RED_ZONE_SIZE bytes. */
161038fd1498Szrj
161138fd1498Szrj bool
asan_protect_global(tree decl,bool ignore_decl_rtl_set_p)161238fd1498Szrj asan_protect_global (tree decl, bool ignore_decl_rtl_set_p)
161338fd1498Szrj {
161438fd1498Szrj if (!ASAN_GLOBALS)
161538fd1498Szrj return false;
161638fd1498Szrj
161738fd1498Szrj rtx rtl, symbol;
161838fd1498Szrj
161938fd1498Szrj if (TREE_CODE (decl) == STRING_CST)
162038fd1498Szrj {
162138fd1498Szrj /* Instrument all STRING_CSTs except those created
162238fd1498Szrj by asan_pp_string here. */
162338fd1498Szrj if (shadow_ptr_types[0] != NULL_TREE
162438fd1498Szrj && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
162538fd1498Szrj && TREE_TYPE (TREE_TYPE (decl)) == TREE_TYPE (shadow_ptr_types[0]))
162638fd1498Szrj return false;
162738fd1498Szrj return true;
162838fd1498Szrj }
162938fd1498Szrj if (!VAR_P (decl)
163038fd1498Szrj /* TLS vars aren't statically protectable. */
163138fd1498Szrj || DECL_THREAD_LOCAL_P (decl)
163238fd1498Szrj /* Externs will be protected elsewhere. */
163338fd1498Szrj || DECL_EXTERNAL (decl)
163438fd1498Szrj /* PR sanitizer/81697: For architectures that use section anchors first
163538fd1498Szrj call to asan_protect_global may occur before DECL_RTL (decl) is set.
163638fd1498Szrj We should ignore DECL_RTL_SET_P then, because otherwise the first call
163738fd1498Szrj to asan_protect_global will return FALSE and the following calls on the
163838fd1498Szrj same decl after setting DECL_RTL (decl) will return TRUE and we'll end
163938fd1498Szrj up with inconsistency at runtime. */
164038fd1498Szrj || (!DECL_RTL_SET_P (decl) && !ignore_decl_rtl_set_p)
164138fd1498Szrj /* Comdat vars pose an ABI problem, we can't know if
164238fd1498Szrj the var that is selected by the linker will have
164338fd1498Szrj padding or not. */
164438fd1498Szrj || DECL_ONE_ONLY (decl)
164538fd1498Szrj /* Similarly for common vars. People can use -fno-common.
164638fd1498Szrj Note: Linux kernel is built with -fno-common, so we do instrument
164738fd1498Szrj globals there even if it is C. */
164838fd1498Szrj || (DECL_COMMON (decl) && TREE_PUBLIC (decl))
164938fd1498Szrj /* Don't protect if using user section, often vars placed
165038fd1498Szrj into user section from multiple TUs are then assumed
165138fd1498Szrj to be an array of such vars, putting padding in there
165238fd1498Szrj breaks this assumption. */
165338fd1498Szrj || (DECL_SECTION_NAME (decl) != NULL
165438fd1498Szrj && !symtab_node::get (decl)->implicit_section
165538fd1498Szrj && !section_sanitized_p (DECL_SECTION_NAME (decl)))
165638fd1498Szrj || DECL_SIZE (decl) == 0
165738fd1498Szrj || ASAN_RED_ZONE_SIZE * BITS_PER_UNIT > MAX_OFILE_ALIGNMENT
165838fd1498Szrj || TREE_CODE (DECL_SIZE_UNIT (decl)) != INTEGER_CST
165938fd1498Szrj || !valid_constant_size_p (DECL_SIZE_UNIT (decl))
166038fd1498Szrj || DECL_ALIGN_UNIT (decl) > 2 * ASAN_RED_ZONE_SIZE
166138fd1498Szrj || TREE_TYPE (decl) == ubsan_get_source_location_type ()
166238fd1498Szrj || is_odr_indicator (decl))
166338fd1498Szrj return false;
166438fd1498Szrj
166538fd1498Szrj if (!ignore_decl_rtl_set_p || DECL_RTL_SET_P (decl))
166638fd1498Szrj {
166738fd1498Szrj
166838fd1498Szrj rtl = DECL_RTL (decl);
166938fd1498Szrj if (!MEM_P (rtl) || GET_CODE (XEXP (rtl, 0)) != SYMBOL_REF)
167038fd1498Szrj return false;
167138fd1498Szrj symbol = XEXP (rtl, 0);
167238fd1498Szrj
167338fd1498Szrj if (CONSTANT_POOL_ADDRESS_P (symbol)
167438fd1498Szrj || TREE_CONSTANT_POOL_ADDRESS_P (symbol))
167538fd1498Szrj return false;
167638fd1498Szrj }
167738fd1498Szrj
167838fd1498Szrj if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)))
167938fd1498Szrj return false;
168038fd1498Szrj
168138fd1498Szrj if (!TARGET_SUPPORTS_ALIASES && asan_needs_local_alias (decl))
168238fd1498Szrj return false;
168338fd1498Szrj
168438fd1498Szrj return true;
168538fd1498Szrj }
168638fd1498Szrj
168738fd1498Szrj /* Construct a function tree for __asan_report_{load,store}{1,2,4,8,16,_n}.
168838fd1498Szrj IS_STORE is either 1 (for a store) or 0 (for a load). */
168938fd1498Szrj
169038fd1498Szrj static tree
report_error_func(bool is_store,bool recover_p,HOST_WIDE_INT size_in_bytes,int * nargs)169138fd1498Szrj report_error_func (bool is_store, bool recover_p, HOST_WIDE_INT size_in_bytes,
169238fd1498Szrj int *nargs)
169338fd1498Szrj {
169438fd1498Szrj static enum built_in_function report[2][2][6]
169538fd1498Szrj = { { { BUILT_IN_ASAN_REPORT_LOAD1, BUILT_IN_ASAN_REPORT_LOAD2,
169638fd1498Szrj BUILT_IN_ASAN_REPORT_LOAD4, BUILT_IN_ASAN_REPORT_LOAD8,
169738fd1498Szrj BUILT_IN_ASAN_REPORT_LOAD16, BUILT_IN_ASAN_REPORT_LOAD_N },
169838fd1498Szrj { BUILT_IN_ASAN_REPORT_STORE1, BUILT_IN_ASAN_REPORT_STORE2,
169938fd1498Szrj BUILT_IN_ASAN_REPORT_STORE4, BUILT_IN_ASAN_REPORT_STORE8,
170038fd1498Szrj BUILT_IN_ASAN_REPORT_STORE16, BUILT_IN_ASAN_REPORT_STORE_N } },
170138fd1498Szrj { { BUILT_IN_ASAN_REPORT_LOAD1_NOABORT,
170238fd1498Szrj BUILT_IN_ASAN_REPORT_LOAD2_NOABORT,
170338fd1498Szrj BUILT_IN_ASAN_REPORT_LOAD4_NOABORT,
170438fd1498Szrj BUILT_IN_ASAN_REPORT_LOAD8_NOABORT,
170538fd1498Szrj BUILT_IN_ASAN_REPORT_LOAD16_NOABORT,
170638fd1498Szrj BUILT_IN_ASAN_REPORT_LOAD_N_NOABORT },
170738fd1498Szrj { BUILT_IN_ASAN_REPORT_STORE1_NOABORT,
170838fd1498Szrj BUILT_IN_ASAN_REPORT_STORE2_NOABORT,
170938fd1498Szrj BUILT_IN_ASAN_REPORT_STORE4_NOABORT,
171038fd1498Szrj BUILT_IN_ASAN_REPORT_STORE8_NOABORT,
171138fd1498Szrj BUILT_IN_ASAN_REPORT_STORE16_NOABORT,
171238fd1498Szrj BUILT_IN_ASAN_REPORT_STORE_N_NOABORT } } };
171338fd1498Szrj if (size_in_bytes == -1)
171438fd1498Szrj {
171538fd1498Szrj *nargs = 2;
171638fd1498Szrj return builtin_decl_implicit (report[recover_p][is_store][5]);
171738fd1498Szrj }
171838fd1498Szrj *nargs = 1;
171938fd1498Szrj int size_log2 = exact_log2 (size_in_bytes);
172038fd1498Szrj return builtin_decl_implicit (report[recover_p][is_store][size_log2]);
172138fd1498Szrj }
172238fd1498Szrj
172338fd1498Szrj /* Construct a function tree for __asan_{load,store}{1,2,4,8,16,_n}.
172438fd1498Szrj IS_STORE is either 1 (for a store) or 0 (for a load). */
172538fd1498Szrj
172638fd1498Szrj static tree
check_func(bool is_store,bool recover_p,HOST_WIDE_INT size_in_bytes,int * nargs)172738fd1498Szrj check_func (bool is_store, bool recover_p, HOST_WIDE_INT size_in_bytes,
172838fd1498Szrj int *nargs)
172938fd1498Szrj {
173038fd1498Szrj static enum built_in_function check[2][2][6]
173138fd1498Szrj = { { { BUILT_IN_ASAN_LOAD1, BUILT_IN_ASAN_LOAD2,
173238fd1498Szrj BUILT_IN_ASAN_LOAD4, BUILT_IN_ASAN_LOAD8,
173338fd1498Szrj BUILT_IN_ASAN_LOAD16, BUILT_IN_ASAN_LOADN },
173438fd1498Szrj { BUILT_IN_ASAN_STORE1, BUILT_IN_ASAN_STORE2,
173538fd1498Szrj BUILT_IN_ASAN_STORE4, BUILT_IN_ASAN_STORE8,
173638fd1498Szrj BUILT_IN_ASAN_STORE16, BUILT_IN_ASAN_STOREN } },
173738fd1498Szrj { { BUILT_IN_ASAN_LOAD1_NOABORT,
173838fd1498Szrj BUILT_IN_ASAN_LOAD2_NOABORT,
173938fd1498Szrj BUILT_IN_ASAN_LOAD4_NOABORT,
174038fd1498Szrj BUILT_IN_ASAN_LOAD8_NOABORT,
174138fd1498Szrj BUILT_IN_ASAN_LOAD16_NOABORT,
174238fd1498Szrj BUILT_IN_ASAN_LOADN_NOABORT },
174338fd1498Szrj { BUILT_IN_ASAN_STORE1_NOABORT,
174438fd1498Szrj BUILT_IN_ASAN_STORE2_NOABORT,
174538fd1498Szrj BUILT_IN_ASAN_STORE4_NOABORT,
174638fd1498Szrj BUILT_IN_ASAN_STORE8_NOABORT,
174738fd1498Szrj BUILT_IN_ASAN_STORE16_NOABORT,
174838fd1498Szrj BUILT_IN_ASAN_STOREN_NOABORT } } };
174938fd1498Szrj if (size_in_bytes == -1)
175038fd1498Szrj {
175138fd1498Szrj *nargs = 2;
175238fd1498Szrj return builtin_decl_implicit (check[recover_p][is_store][5]);
175338fd1498Szrj }
175438fd1498Szrj *nargs = 1;
175538fd1498Szrj int size_log2 = exact_log2 (size_in_bytes);
175638fd1498Szrj return builtin_decl_implicit (check[recover_p][is_store][size_log2]);
175738fd1498Szrj }
175838fd1498Szrj
175938fd1498Szrj /* Split the current basic block and create a condition statement
176038fd1498Szrj insertion point right before or after the statement pointed to by
176138fd1498Szrj ITER. Return an iterator to the point at which the caller might
176238fd1498Szrj safely insert the condition statement.
176338fd1498Szrj
176438fd1498Szrj THEN_BLOCK must be set to the address of an uninitialized instance
176538fd1498Szrj of basic_block. The function will then set *THEN_BLOCK to the
176638fd1498Szrj 'then block' of the condition statement to be inserted by the
176738fd1498Szrj caller.
176838fd1498Szrj
176938fd1498Szrj If CREATE_THEN_FALLTHRU_EDGE is false, no edge will be created from
177038fd1498Szrj *THEN_BLOCK to *FALLTHROUGH_BLOCK.
177138fd1498Szrj
177238fd1498Szrj Similarly, the function will set *FALLTRHOUGH_BLOCK to the 'else
177338fd1498Szrj block' of the condition statement to be inserted by the caller.
177438fd1498Szrj
177538fd1498Szrj Note that *FALLTHROUGH_BLOCK is a new block that contains the
177638fd1498Szrj statements starting from *ITER, and *THEN_BLOCK is a new empty
177738fd1498Szrj block.
177838fd1498Szrj
177938fd1498Szrj *ITER is adjusted to point to always point to the first statement
178038fd1498Szrj of the basic block * FALLTHROUGH_BLOCK. That statement is the
178138fd1498Szrj same as what ITER was pointing to prior to calling this function,
178238fd1498Szrj if BEFORE_P is true; otherwise, it is its following statement. */
178338fd1498Szrj
178438fd1498Szrj 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)178538fd1498Szrj create_cond_insert_point (gimple_stmt_iterator *iter,
178638fd1498Szrj bool before_p,
178738fd1498Szrj bool then_more_likely_p,
178838fd1498Szrj bool create_then_fallthru_edge,
178938fd1498Szrj basic_block *then_block,
179038fd1498Szrj basic_block *fallthrough_block)
179138fd1498Szrj {
179238fd1498Szrj gimple_stmt_iterator gsi = *iter;
179338fd1498Szrj
179438fd1498Szrj if (!gsi_end_p (gsi) && before_p)
179538fd1498Szrj gsi_prev (&gsi);
179638fd1498Szrj
179738fd1498Szrj basic_block cur_bb = gsi_bb (*iter);
179838fd1498Szrj
179938fd1498Szrj edge e = split_block (cur_bb, gsi_stmt (gsi));
180038fd1498Szrj
180138fd1498Szrj /* Get a hold on the 'condition block', the 'then block' and the
180238fd1498Szrj 'else block'. */
180338fd1498Szrj basic_block cond_bb = e->src;
180438fd1498Szrj basic_block fallthru_bb = e->dest;
180538fd1498Szrj basic_block then_bb = create_empty_bb (cond_bb);
180638fd1498Szrj if (current_loops)
180738fd1498Szrj {
180838fd1498Szrj add_bb_to_loop (then_bb, cond_bb->loop_father);
180938fd1498Szrj loops_state_set (LOOPS_NEED_FIXUP);
181038fd1498Szrj }
181138fd1498Szrj
181238fd1498Szrj /* Set up the newly created 'then block'. */
181338fd1498Szrj e = make_edge (cond_bb, then_bb, EDGE_TRUE_VALUE);
181438fd1498Szrj profile_probability fallthrough_probability
181538fd1498Szrj = then_more_likely_p
181638fd1498Szrj ? profile_probability::very_unlikely ()
181738fd1498Szrj : profile_probability::very_likely ();
181838fd1498Szrj e->probability = fallthrough_probability.invert ();
181938fd1498Szrj then_bb->count = e->count ();
182038fd1498Szrj if (create_then_fallthru_edge)
182138fd1498Szrj make_single_succ_edge (then_bb, fallthru_bb, EDGE_FALLTHRU);
182238fd1498Szrj
182338fd1498Szrj /* Set up the fallthrough basic block. */
182438fd1498Szrj e = find_edge (cond_bb, fallthru_bb);
182538fd1498Szrj e->flags = EDGE_FALSE_VALUE;
182638fd1498Szrj e->probability = fallthrough_probability;
182738fd1498Szrj
182838fd1498Szrj /* Update dominance info for the newly created then_bb; note that
182938fd1498Szrj fallthru_bb's dominance info has already been updated by
183038fd1498Szrj split_bock. */
183138fd1498Szrj if (dom_info_available_p (CDI_DOMINATORS))
183238fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, then_bb, cond_bb);
183338fd1498Szrj
183438fd1498Szrj *then_block = then_bb;
183538fd1498Szrj *fallthrough_block = fallthru_bb;
183638fd1498Szrj *iter = gsi_start_bb (fallthru_bb);
183738fd1498Szrj
183838fd1498Szrj return gsi_last_bb (cond_bb);
183938fd1498Szrj }
184038fd1498Szrj
184138fd1498Szrj /* Insert an if condition followed by a 'then block' right before the
184238fd1498Szrj statement pointed to by ITER. The fallthrough block -- which is the
184338fd1498Szrj else block of the condition as well as the destination of the
184438fd1498Szrj outcoming edge of the 'then block' -- starts with the statement
184538fd1498Szrj pointed to by ITER.
184638fd1498Szrj
184738fd1498Szrj COND is the condition of the if.
184838fd1498Szrj
184938fd1498Szrj If THEN_MORE_LIKELY_P is true, the probability of the edge to the
185038fd1498Szrj 'then block' is higher than the probability of the edge to the
185138fd1498Szrj fallthrough block.
185238fd1498Szrj
185338fd1498Szrj Upon completion of the function, *THEN_BB is set to the newly
185438fd1498Szrj inserted 'then block' and similarly, *FALLTHROUGH_BB is set to the
185538fd1498Szrj fallthrough block.
185638fd1498Szrj
185738fd1498Szrj *ITER is adjusted to still point to the same statement it was
185838fd1498Szrj pointing to initially. */
185938fd1498Szrj
186038fd1498Szrj static void
insert_if_then_before_iter(gcond * cond,gimple_stmt_iterator * iter,bool then_more_likely_p,basic_block * then_bb,basic_block * fallthrough_bb)186138fd1498Szrj insert_if_then_before_iter (gcond *cond,
186238fd1498Szrj gimple_stmt_iterator *iter,
186338fd1498Szrj bool then_more_likely_p,
186438fd1498Szrj basic_block *then_bb,
186538fd1498Szrj basic_block *fallthrough_bb)
186638fd1498Szrj {
186738fd1498Szrj gimple_stmt_iterator cond_insert_point =
186838fd1498Szrj create_cond_insert_point (iter,
186938fd1498Szrj /*before_p=*/true,
187038fd1498Szrj then_more_likely_p,
187138fd1498Szrj /*create_then_fallthru_edge=*/true,
187238fd1498Szrj then_bb,
187338fd1498Szrj fallthrough_bb);
187438fd1498Szrj gsi_insert_after (&cond_insert_point, cond, GSI_NEW_STMT);
187538fd1498Szrj }
187638fd1498Szrj
187738fd1498Szrj /* Build (base_addr >> ASAN_SHADOW_SHIFT) + asan_shadow_offset ().
187838fd1498Szrj If RETURN_ADDRESS is set to true, return memory location instread
187938fd1498Szrj of a value in the shadow memory. */
188038fd1498Szrj
188138fd1498Szrj static tree
188238fd1498Szrj build_shadow_mem_access (gimple_stmt_iterator *gsi, location_t location,
188338fd1498Szrj tree base_addr, tree shadow_ptr_type,
188438fd1498Szrj bool return_address = false)
188538fd1498Szrj {
188638fd1498Szrj tree t, uintptr_type = TREE_TYPE (base_addr);
188738fd1498Szrj tree shadow_type = TREE_TYPE (shadow_ptr_type);
188838fd1498Szrj gimple *g;
188938fd1498Szrj
189038fd1498Szrj t = build_int_cst (uintptr_type, ASAN_SHADOW_SHIFT);
189138fd1498Szrj g = gimple_build_assign (make_ssa_name (uintptr_type), RSHIFT_EXPR,
189238fd1498Szrj base_addr, t);
189338fd1498Szrj gimple_set_location (g, location);
189438fd1498Szrj gsi_insert_after (gsi, g, GSI_NEW_STMT);
189538fd1498Szrj
189638fd1498Szrj t = build_int_cst (uintptr_type, asan_shadow_offset ());
189738fd1498Szrj g = gimple_build_assign (make_ssa_name (uintptr_type), PLUS_EXPR,
189838fd1498Szrj gimple_assign_lhs (g), t);
189938fd1498Szrj gimple_set_location (g, location);
190038fd1498Szrj gsi_insert_after (gsi, g, GSI_NEW_STMT);
190138fd1498Szrj
190238fd1498Szrj g = gimple_build_assign (make_ssa_name (shadow_ptr_type), NOP_EXPR,
190338fd1498Szrj gimple_assign_lhs (g));
190438fd1498Szrj gimple_set_location (g, location);
190538fd1498Szrj gsi_insert_after (gsi, g, GSI_NEW_STMT);
190638fd1498Szrj
190738fd1498Szrj if (!return_address)
190838fd1498Szrj {
190938fd1498Szrj t = build2 (MEM_REF, shadow_type, gimple_assign_lhs (g),
191038fd1498Szrj build_int_cst (shadow_ptr_type, 0));
191138fd1498Szrj g = gimple_build_assign (make_ssa_name (shadow_type), MEM_REF, t);
191238fd1498Szrj gimple_set_location (g, location);
191338fd1498Szrj gsi_insert_after (gsi, g, GSI_NEW_STMT);
191438fd1498Szrj }
191538fd1498Szrj
191638fd1498Szrj return gimple_assign_lhs (g);
191738fd1498Szrj }
191838fd1498Szrj
191938fd1498Szrj /* BASE can already be an SSA_NAME; in that case, do not create a
192038fd1498Szrj new SSA_NAME for it. */
192138fd1498Szrj
192238fd1498Szrj static tree
maybe_create_ssa_name(location_t loc,tree base,gimple_stmt_iterator * iter,bool before_p)192338fd1498Szrj maybe_create_ssa_name (location_t loc, tree base, gimple_stmt_iterator *iter,
192438fd1498Szrj bool before_p)
192538fd1498Szrj {
192638fd1498Szrj if (TREE_CODE (base) == SSA_NAME)
192738fd1498Szrj return base;
192838fd1498Szrj gimple *g = gimple_build_assign (make_ssa_name (TREE_TYPE (base)),
192938fd1498Szrj TREE_CODE (base), base);
193038fd1498Szrj gimple_set_location (g, loc);
193138fd1498Szrj if (before_p)
193238fd1498Szrj gsi_insert_before (iter, g, GSI_SAME_STMT);
193338fd1498Szrj else
193438fd1498Szrj gsi_insert_after (iter, g, GSI_NEW_STMT);
193538fd1498Szrj return gimple_assign_lhs (g);
193638fd1498Szrj }
193738fd1498Szrj
193838fd1498Szrj /* LEN can already have necessary size and precision;
193938fd1498Szrj in that case, do not create a new variable. */
194038fd1498Szrj
194138fd1498Szrj tree
maybe_cast_to_ptrmode(location_t loc,tree len,gimple_stmt_iterator * iter,bool before_p)194238fd1498Szrj maybe_cast_to_ptrmode (location_t loc, tree len, gimple_stmt_iterator *iter,
194338fd1498Szrj bool before_p)
194438fd1498Szrj {
194538fd1498Szrj if (ptrofftype_p (len))
194638fd1498Szrj return len;
194738fd1498Szrj gimple *g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
194838fd1498Szrj NOP_EXPR, len);
194938fd1498Szrj gimple_set_location (g, loc);
195038fd1498Szrj if (before_p)
195138fd1498Szrj gsi_insert_before (iter, g, GSI_SAME_STMT);
195238fd1498Szrj else
195338fd1498Szrj gsi_insert_after (iter, g, GSI_NEW_STMT);
195438fd1498Szrj return gimple_assign_lhs (g);
195538fd1498Szrj }
195638fd1498Szrj
195738fd1498Szrj /* Instrument the memory access instruction BASE. Insert new
195838fd1498Szrj statements before or after ITER.
195938fd1498Szrj
196038fd1498Szrj Note that the memory access represented by BASE can be either an
196138fd1498Szrj SSA_NAME, or a non-SSA expression. LOCATION is the source code
196238fd1498Szrj location. IS_STORE is TRUE for a store, FALSE for a load.
196338fd1498Szrj BEFORE_P is TRUE for inserting the instrumentation code before
196438fd1498Szrj ITER, FALSE for inserting it after ITER. IS_SCALAR_ACCESS is TRUE
196538fd1498Szrj for a scalar memory access and FALSE for memory region access.
196638fd1498Szrj NON_ZERO_P is TRUE if memory region is guaranteed to have non-zero
196738fd1498Szrj length. ALIGN tells alignment of accessed memory object.
196838fd1498Szrj
196938fd1498Szrj START_INSTRUMENTED and END_INSTRUMENTED are TRUE if start/end of
197038fd1498Szrj memory region have already been instrumented.
197138fd1498Szrj
197238fd1498Szrj If BEFORE_P is TRUE, *ITER is arranged to still point to the
197338fd1498Szrj statement it was pointing to prior to calling this function,
197438fd1498Szrj otherwise, it points to the statement logically following it. */
197538fd1498Szrj
197638fd1498Szrj static void
197738fd1498Szrj build_check_stmt (location_t loc, tree base, tree len,
197838fd1498Szrj HOST_WIDE_INT size_in_bytes, gimple_stmt_iterator *iter,
197938fd1498Szrj bool is_non_zero_len, bool before_p, bool is_store,
198038fd1498Szrj bool is_scalar_access, unsigned int align = 0)
198138fd1498Szrj {
198238fd1498Szrj gimple_stmt_iterator gsi = *iter;
198338fd1498Szrj gimple *g;
198438fd1498Szrj
198538fd1498Szrj gcc_assert (!(size_in_bytes > 0 && !is_non_zero_len));
198638fd1498Szrj
198738fd1498Szrj gsi = *iter;
198838fd1498Szrj
198938fd1498Szrj base = unshare_expr (base);
199038fd1498Szrj base = maybe_create_ssa_name (loc, base, &gsi, before_p);
199138fd1498Szrj
199238fd1498Szrj if (len)
199338fd1498Szrj {
199438fd1498Szrj len = unshare_expr (len);
199538fd1498Szrj len = maybe_cast_to_ptrmode (loc, len, iter, before_p);
199638fd1498Szrj }
199738fd1498Szrj else
199838fd1498Szrj {
199938fd1498Szrj gcc_assert (size_in_bytes != -1);
200038fd1498Szrj len = build_int_cst (pointer_sized_int_node, size_in_bytes);
200138fd1498Szrj }
200238fd1498Szrj
200338fd1498Szrj if (size_in_bytes > 1)
200438fd1498Szrj {
200538fd1498Szrj if ((size_in_bytes & (size_in_bytes - 1)) != 0
200638fd1498Szrj || size_in_bytes > 16)
200738fd1498Szrj is_scalar_access = false;
200838fd1498Szrj else if (align && align < size_in_bytes * BITS_PER_UNIT)
200938fd1498Szrj {
201038fd1498Szrj /* On non-strict alignment targets, if
201138fd1498Szrj 16-byte access is just 8-byte aligned,
201238fd1498Szrj this will result in misaligned shadow
201338fd1498Szrj memory 2 byte load, but otherwise can
201438fd1498Szrj be handled using one read. */
201538fd1498Szrj if (size_in_bytes != 16
201638fd1498Szrj || STRICT_ALIGNMENT
201738fd1498Szrj || align < 8 * BITS_PER_UNIT)
201838fd1498Szrj is_scalar_access = false;
201938fd1498Szrj }
202038fd1498Szrj }
202138fd1498Szrj
202238fd1498Szrj HOST_WIDE_INT flags = 0;
202338fd1498Szrj if (is_store)
202438fd1498Szrj flags |= ASAN_CHECK_STORE;
202538fd1498Szrj if (is_non_zero_len)
202638fd1498Szrj flags |= ASAN_CHECK_NON_ZERO_LEN;
202738fd1498Szrj if (is_scalar_access)
202838fd1498Szrj flags |= ASAN_CHECK_SCALAR_ACCESS;
202938fd1498Szrj
203038fd1498Szrj g = gimple_build_call_internal (IFN_ASAN_CHECK, 4,
203138fd1498Szrj build_int_cst (integer_type_node, flags),
203238fd1498Szrj base, len,
203338fd1498Szrj build_int_cst (integer_type_node,
203438fd1498Szrj align / BITS_PER_UNIT));
203538fd1498Szrj gimple_set_location (g, loc);
203638fd1498Szrj if (before_p)
203738fd1498Szrj gsi_insert_before (&gsi, g, GSI_SAME_STMT);
203838fd1498Szrj else
203938fd1498Szrj {
204038fd1498Szrj gsi_insert_after (&gsi, g, GSI_NEW_STMT);
204138fd1498Szrj gsi_next (&gsi);
204238fd1498Szrj *iter = gsi;
204338fd1498Szrj }
204438fd1498Szrj }
204538fd1498Szrj
204638fd1498Szrj /* If T represents a memory access, add instrumentation code before ITER.
204738fd1498Szrj LOCATION is source code location.
204838fd1498Szrj IS_STORE is either TRUE (for a store) or FALSE (for a load). */
204938fd1498Szrj
205038fd1498Szrj static void
instrument_derefs(gimple_stmt_iterator * iter,tree t,location_t location,bool is_store)205138fd1498Szrj instrument_derefs (gimple_stmt_iterator *iter, tree t,
205238fd1498Szrj location_t location, bool is_store)
205338fd1498Szrj {
205438fd1498Szrj if (is_store && !ASAN_INSTRUMENT_WRITES)
205538fd1498Szrj return;
205638fd1498Szrj if (!is_store && !ASAN_INSTRUMENT_READS)
205738fd1498Szrj return;
205838fd1498Szrj
205938fd1498Szrj tree type, base;
206038fd1498Szrj HOST_WIDE_INT size_in_bytes;
206138fd1498Szrj if (location == UNKNOWN_LOCATION)
206238fd1498Szrj location = EXPR_LOCATION (t);
206338fd1498Szrj
206438fd1498Szrj type = TREE_TYPE (t);
206538fd1498Szrj switch (TREE_CODE (t))
206638fd1498Szrj {
206738fd1498Szrj case ARRAY_REF:
206838fd1498Szrj case COMPONENT_REF:
206938fd1498Szrj case INDIRECT_REF:
207038fd1498Szrj case MEM_REF:
207138fd1498Szrj case VAR_DECL:
207238fd1498Szrj case BIT_FIELD_REF:
207338fd1498Szrj break;
207438fd1498Szrj /* FALLTHRU */
207538fd1498Szrj default:
207638fd1498Szrj return;
207738fd1498Szrj }
207838fd1498Szrj
207938fd1498Szrj size_in_bytes = int_size_in_bytes (type);
208038fd1498Szrj if (size_in_bytes <= 0)
208138fd1498Szrj return;
208238fd1498Szrj
208338fd1498Szrj poly_int64 bitsize, bitpos;
208438fd1498Szrj tree offset;
208538fd1498Szrj machine_mode mode;
208638fd1498Szrj int unsignedp, reversep, volatilep = 0;
208738fd1498Szrj tree inner = get_inner_reference (t, &bitsize, &bitpos, &offset, &mode,
208838fd1498Szrj &unsignedp, &reversep, &volatilep);
208938fd1498Szrj
209038fd1498Szrj if (TREE_CODE (t) == COMPONENT_REF
209138fd1498Szrj && DECL_BIT_FIELD_REPRESENTATIVE (TREE_OPERAND (t, 1)) != NULL_TREE)
209238fd1498Szrj {
209338fd1498Szrj tree repr = DECL_BIT_FIELD_REPRESENTATIVE (TREE_OPERAND (t, 1));
209438fd1498Szrj instrument_derefs (iter, build3 (COMPONENT_REF, TREE_TYPE (repr),
209538fd1498Szrj TREE_OPERAND (t, 0), repr,
209638fd1498Szrj TREE_OPERAND (t, 2)),
209738fd1498Szrj location, is_store);
209838fd1498Szrj return;
209938fd1498Szrj }
210038fd1498Szrj
210138fd1498Szrj if (!multiple_p (bitpos, BITS_PER_UNIT)
210238fd1498Szrj || maybe_ne (bitsize, size_in_bytes * BITS_PER_UNIT))
210338fd1498Szrj return;
210438fd1498Szrj
210538fd1498Szrj if (VAR_P (inner) && DECL_HARD_REGISTER (inner))
210638fd1498Szrj return;
210738fd1498Szrj
210838fd1498Szrj poly_int64 decl_size;
210938fd1498Szrj if (VAR_P (inner)
211038fd1498Szrj && offset == NULL_TREE
211138fd1498Szrj && DECL_SIZE (inner)
211238fd1498Szrj && poly_int_tree_p (DECL_SIZE (inner), &decl_size)
211338fd1498Szrj && known_subrange_p (bitpos, bitsize, 0, decl_size))
211438fd1498Szrj {
211538fd1498Szrj if (DECL_THREAD_LOCAL_P (inner))
211638fd1498Szrj return;
211738fd1498Szrj if (!ASAN_GLOBALS && is_global_var (inner))
211838fd1498Szrj return;
211938fd1498Szrj if (!TREE_STATIC (inner))
212038fd1498Szrj {
212138fd1498Szrj /* Automatic vars in the current function will be always
212238fd1498Szrj accessible. */
212338fd1498Szrj if (decl_function_context (inner) == current_function_decl
212438fd1498Szrj && (!asan_sanitize_use_after_scope ()
212538fd1498Szrj || !TREE_ADDRESSABLE (inner)))
212638fd1498Szrj return;
212738fd1498Szrj }
212838fd1498Szrj /* Always instrument external vars, they might be dynamically
212938fd1498Szrj initialized. */
213038fd1498Szrj else if (!DECL_EXTERNAL (inner))
213138fd1498Szrj {
213238fd1498Szrj /* For static vars if they are known not to be dynamically
213338fd1498Szrj initialized, they will be always accessible. */
213438fd1498Szrj varpool_node *vnode = varpool_node::get (inner);
213538fd1498Szrj if (vnode && !vnode->dynamically_initialized)
213638fd1498Szrj return;
213738fd1498Szrj }
213838fd1498Szrj }
213938fd1498Szrj
214038fd1498Szrj base = build_fold_addr_expr (t);
214138fd1498Szrj if (!has_mem_ref_been_instrumented (base, size_in_bytes))
214238fd1498Szrj {
214338fd1498Szrj unsigned int align = get_object_alignment (t);
214438fd1498Szrj build_check_stmt (location, base, NULL_TREE, size_in_bytes, iter,
214538fd1498Szrj /*is_non_zero_len*/size_in_bytes > 0, /*before_p=*/true,
214638fd1498Szrj is_store, /*is_scalar_access*/true, align);
214738fd1498Szrj update_mem_ref_hash_table (base, size_in_bytes);
214838fd1498Szrj update_mem_ref_hash_table (t, size_in_bytes);
214938fd1498Szrj }
215038fd1498Szrj
215138fd1498Szrj }
215238fd1498Szrj
215338fd1498Szrj /* Insert a memory reference into the hash table if access length
215438fd1498Szrj can be determined in compile time. */
215538fd1498Szrj
215638fd1498Szrj static void
maybe_update_mem_ref_hash_table(tree base,tree len)215738fd1498Szrj maybe_update_mem_ref_hash_table (tree base, tree len)
215838fd1498Szrj {
215938fd1498Szrj if (!POINTER_TYPE_P (TREE_TYPE (base))
216038fd1498Szrj || !INTEGRAL_TYPE_P (TREE_TYPE (len)))
216138fd1498Szrj return;
216238fd1498Szrj
216338fd1498Szrj HOST_WIDE_INT size_in_bytes = tree_fits_shwi_p (len) ? tree_to_shwi (len) : -1;
216438fd1498Szrj
216538fd1498Szrj if (size_in_bytes != -1)
216638fd1498Szrj update_mem_ref_hash_table (base, size_in_bytes);
216738fd1498Szrj }
216838fd1498Szrj
216938fd1498Szrj /* Instrument an access to a contiguous memory region that starts at
217038fd1498Szrj the address pointed to by BASE, over a length of LEN (expressed in
217138fd1498Szrj the sizeof (*BASE) bytes). ITER points to the instruction before
217238fd1498Szrj which the instrumentation instructions must be inserted. LOCATION
217338fd1498Szrj is the source location that the instrumentation instructions must
217438fd1498Szrj have. If IS_STORE is true, then the memory access is a store;
217538fd1498Szrj otherwise, it's a load. */
217638fd1498Szrj
217738fd1498Szrj static void
instrument_mem_region_access(tree base,tree len,gimple_stmt_iterator * iter,location_t location,bool is_store)217838fd1498Szrj instrument_mem_region_access (tree base, tree len,
217938fd1498Szrj gimple_stmt_iterator *iter,
218038fd1498Szrj location_t location, bool is_store)
218138fd1498Szrj {
218238fd1498Szrj if (!POINTER_TYPE_P (TREE_TYPE (base))
218338fd1498Szrj || !INTEGRAL_TYPE_P (TREE_TYPE (len))
218438fd1498Szrj || integer_zerop (len))
218538fd1498Szrj return;
218638fd1498Szrj
218738fd1498Szrj HOST_WIDE_INT size_in_bytes = tree_fits_shwi_p (len) ? tree_to_shwi (len) : -1;
218838fd1498Szrj
218938fd1498Szrj if ((size_in_bytes == -1)
219038fd1498Szrj || !has_mem_ref_been_instrumented (base, size_in_bytes))
219138fd1498Szrj {
219238fd1498Szrj build_check_stmt (location, base, len, size_in_bytes, iter,
219338fd1498Szrj /*is_non_zero_len*/size_in_bytes > 0, /*before_p*/true,
219438fd1498Szrj is_store, /*is_scalar_access*/false, /*align*/0);
219538fd1498Szrj }
219638fd1498Szrj
219738fd1498Szrj maybe_update_mem_ref_hash_table (base, len);
219838fd1498Szrj *iter = gsi_for_stmt (gsi_stmt (*iter));
219938fd1498Szrj }
220038fd1498Szrj
220138fd1498Szrj /* Instrument the call to a built-in memory access function that is
220238fd1498Szrj pointed to by the iterator ITER.
220338fd1498Szrj
220438fd1498Szrj Upon completion, return TRUE iff *ITER has been advanced to the
220538fd1498Szrj statement following the one it was originally pointing to. */
220638fd1498Szrj
220738fd1498Szrj static bool
instrument_builtin_call(gimple_stmt_iterator * iter)220838fd1498Szrj instrument_builtin_call (gimple_stmt_iterator *iter)
220938fd1498Szrj {
221038fd1498Szrj if (!ASAN_MEMINTRIN)
221138fd1498Szrj return false;
221238fd1498Szrj
221338fd1498Szrj bool iter_advanced_p = false;
221438fd1498Szrj gcall *call = as_a <gcall *> (gsi_stmt (*iter));
221538fd1498Szrj
221638fd1498Szrj gcc_checking_assert (gimple_call_builtin_p (call, BUILT_IN_NORMAL));
221738fd1498Szrj
221838fd1498Szrj location_t loc = gimple_location (call);
221938fd1498Szrj
222038fd1498Szrj asan_mem_ref src0, src1, dest;
222138fd1498Szrj asan_mem_ref_init (&src0, NULL, 1);
222238fd1498Szrj asan_mem_ref_init (&src1, NULL, 1);
222338fd1498Szrj asan_mem_ref_init (&dest, NULL, 1);
222438fd1498Szrj
222538fd1498Szrj tree src0_len = NULL_TREE, src1_len = NULL_TREE, dest_len = NULL_TREE;
222638fd1498Szrj bool src0_is_store = false, src1_is_store = false, dest_is_store = false,
222738fd1498Szrj dest_is_deref = false, intercepted_p = true;
222838fd1498Szrj
222938fd1498Szrj if (get_mem_refs_of_builtin_call (call,
223038fd1498Szrj &src0, &src0_len, &src0_is_store,
223138fd1498Szrj &src1, &src1_len, &src1_is_store,
223238fd1498Szrj &dest, &dest_len, &dest_is_store,
223338fd1498Szrj &dest_is_deref, &intercepted_p, iter))
223438fd1498Szrj {
223538fd1498Szrj if (dest_is_deref)
223638fd1498Szrj {
223738fd1498Szrj instrument_derefs (iter, dest.start, loc, dest_is_store);
223838fd1498Szrj gsi_next (iter);
223938fd1498Szrj iter_advanced_p = true;
224038fd1498Szrj }
224138fd1498Szrj else if (!intercepted_p
224238fd1498Szrj && (src0_len || src1_len || dest_len))
224338fd1498Szrj {
224438fd1498Szrj if (src0.start != NULL_TREE)
224538fd1498Szrj instrument_mem_region_access (src0.start, src0_len,
224638fd1498Szrj iter, loc, /*is_store=*/false);
224738fd1498Szrj if (src1.start != NULL_TREE)
224838fd1498Szrj instrument_mem_region_access (src1.start, src1_len,
224938fd1498Szrj iter, loc, /*is_store=*/false);
225038fd1498Szrj if (dest.start != NULL_TREE)
225138fd1498Szrj instrument_mem_region_access (dest.start, dest_len,
225238fd1498Szrj iter, loc, /*is_store=*/true);
225338fd1498Szrj
225438fd1498Szrj *iter = gsi_for_stmt (call);
225538fd1498Szrj gsi_next (iter);
225638fd1498Szrj iter_advanced_p = true;
225738fd1498Szrj }
225838fd1498Szrj else
225938fd1498Szrj {
226038fd1498Szrj if (src0.start != NULL_TREE)
226138fd1498Szrj maybe_update_mem_ref_hash_table (src0.start, src0_len);
226238fd1498Szrj if (src1.start != NULL_TREE)
226338fd1498Szrj maybe_update_mem_ref_hash_table (src1.start, src1_len);
226438fd1498Szrj if (dest.start != NULL_TREE)
226538fd1498Szrj maybe_update_mem_ref_hash_table (dest.start, dest_len);
226638fd1498Szrj }
226738fd1498Szrj }
226838fd1498Szrj return iter_advanced_p;
226938fd1498Szrj }
227038fd1498Szrj
227138fd1498Szrj /* Instrument the assignment statement ITER if it is subject to
227238fd1498Szrj instrumentation. Return TRUE iff instrumentation actually
227338fd1498Szrj happened. In that case, the iterator ITER is advanced to the next
227438fd1498Szrj logical expression following the one initially pointed to by ITER,
227538fd1498Szrj and the relevant memory reference that which access has been
227638fd1498Szrj instrumented is added to the memory references hash table. */
227738fd1498Szrj
227838fd1498Szrj static bool
maybe_instrument_assignment(gimple_stmt_iterator * iter)227938fd1498Szrj maybe_instrument_assignment (gimple_stmt_iterator *iter)
228038fd1498Szrj {
228138fd1498Szrj gimple *s = gsi_stmt (*iter);
228238fd1498Szrj
228338fd1498Szrj gcc_assert (gimple_assign_single_p (s));
228438fd1498Szrj
228538fd1498Szrj tree ref_expr = NULL_TREE;
228638fd1498Szrj bool is_store, is_instrumented = false;
228738fd1498Szrj
228838fd1498Szrj if (gimple_store_p (s))
228938fd1498Szrj {
229038fd1498Szrj ref_expr = gimple_assign_lhs (s);
229138fd1498Szrj is_store = true;
229238fd1498Szrj instrument_derefs (iter, ref_expr,
229338fd1498Szrj gimple_location (s),
229438fd1498Szrj is_store);
229538fd1498Szrj is_instrumented = true;
229638fd1498Szrj }
229738fd1498Szrj
229838fd1498Szrj if (gimple_assign_load_p (s))
229938fd1498Szrj {
230038fd1498Szrj ref_expr = gimple_assign_rhs1 (s);
230138fd1498Szrj is_store = false;
230238fd1498Szrj instrument_derefs (iter, ref_expr,
230338fd1498Szrj gimple_location (s),
230438fd1498Szrj is_store);
230538fd1498Szrj is_instrumented = true;
230638fd1498Szrj }
230738fd1498Szrj
230838fd1498Szrj if (is_instrumented)
230938fd1498Szrj gsi_next (iter);
231038fd1498Szrj
231138fd1498Szrj return is_instrumented;
231238fd1498Szrj }
231338fd1498Szrj
231438fd1498Szrj /* Instrument the function call pointed to by the iterator ITER, if it
231538fd1498Szrj is subject to instrumentation. At the moment, the only function
231638fd1498Szrj calls that are instrumented are some built-in functions that access
231738fd1498Szrj memory. Look at instrument_builtin_call to learn more.
231838fd1498Szrj
231938fd1498Szrj Upon completion return TRUE iff *ITER was advanced to the statement
232038fd1498Szrj following the one it was originally pointing to. */
232138fd1498Szrj
232238fd1498Szrj static bool
maybe_instrument_call(gimple_stmt_iterator * iter)232338fd1498Szrj maybe_instrument_call (gimple_stmt_iterator *iter)
232438fd1498Szrj {
232538fd1498Szrj gimple *stmt = gsi_stmt (*iter);
232638fd1498Szrj bool is_builtin = gimple_call_builtin_p (stmt, BUILT_IN_NORMAL);
232738fd1498Szrj
232838fd1498Szrj if (is_builtin && instrument_builtin_call (iter))
232938fd1498Szrj return true;
233038fd1498Szrj
233138fd1498Szrj if (gimple_call_noreturn_p (stmt))
233238fd1498Szrj {
233338fd1498Szrj if (is_builtin)
233438fd1498Szrj {
233538fd1498Szrj tree callee = gimple_call_fndecl (stmt);
233638fd1498Szrj switch (DECL_FUNCTION_CODE (callee))
233738fd1498Szrj {
233838fd1498Szrj case BUILT_IN_UNREACHABLE:
233938fd1498Szrj case BUILT_IN_TRAP:
234038fd1498Szrj /* Don't instrument these. */
234138fd1498Szrj return false;
234238fd1498Szrj default:
234338fd1498Szrj break;
234438fd1498Szrj }
234538fd1498Szrj }
234638fd1498Szrj tree decl = builtin_decl_implicit (BUILT_IN_ASAN_HANDLE_NO_RETURN);
234738fd1498Szrj gimple *g = gimple_build_call (decl, 0);
234838fd1498Szrj gimple_set_location (g, gimple_location (stmt));
234938fd1498Szrj gsi_insert_before (iter, g, GSI_SAME_STMT);
235038fd1498Szrj }
235138fd1498Szrj
235238fd1498Szrj bool instrumented = false;
235338fd1498Szrj if (gimple_store_p (stmt))
235438fd1498Szrj {
235538fd1498Szrj tree ref_expr = gimple_call_lhs (stmt);
235638fd1498Szrj instrument_derefs (iter, ref_expr,
235738fd1498Szrj gimple_location (stmt),
235838fd1498Szrj /*is_store=*/true);
235938fd1498Szrj
236038fd1498Szrj instrumented = true;
236138fd1498Szrj }
236238fd1498Szrj
236338fd1498Szrj /* Walk through gimple_call arguments and check them id needed. */
236438fd1498Szrj unsigned args_num = gimple_call_num_args (stmt);
236538fd1498Szrj for (unsigned i = 0; i < args_num; ++i)
236638fd1498Szrj {
236738fd1498Szrj tree arg = gimple_call_arg (stmt, i);
236838fd1498Szrj /* If ARG is not a non-aggregate register variable, compiler in general
236938fd1498Szrj creates temporary for it and pass it as argument to gimple call.
237038fd1498Szrj But in some cases, e.g. when we pass by value a small structure that
237138fd1498Szrj fits to register, compiler can avoid extra overhead by pulling out
237238fd1498Szrj these temporaries. In this case, we should check the argument. */
237338fd1498Szrj if (!is_gimple_reg (arg) && !is_gimple_min_invariant (arg))
237438fd1498Szrj {
237538fd1498Szrj instrument_derefs (iter, arg,
237638fd1498Szrj gimple_location (stmt),
237738fd1498Szrj /*is_store=*/false);
237838fd1498Szrj instrumented = true;
237938fd1498Szrj }
238038fd1498Szrj }
238138fd1498Szrj if (instrumented)
238238fd1498Szrj gsi_next (iter);
238338fd1498Szrj return instrumented;
238438fd1498Szrj }
238538fd1498Szrj
238638fd1498Szrj /* Walk each instruction of all basic block and instrument those that
238738fd1498Szrj represent memory references: loads, stores, or function calls.
238838fd1498Szrj In a given basic block, this function avoids instrumenting memory
238938fd1498Szrj references that have already been instrumented. */
239038fd1498Szrj
239138fd1498Szrj static void
transform_statements(void)239238fd1498Szrj transform_statements (void)
239338fd1498Szrj {
239438fd1498Szrj basic_block bb, last_bb = NULL;
239538fd1498Szrj gimple_stmt_iterator i;
239638fd1498Szrj int saved_last_basic_block = last_basic_block_for_fn (cfun);
239738fd1498Szrj
239838fd1498Szrj FOR_EACH_BB_FN (bb, cfun)
239938fd1498Szrj {
240038fd1498Szrj basic_block prev_bb = bb;
240138fd1498Szrj
240238fd1498Szrj if (bb->index >= saved_last_basic_block) continue;
240338fd1498Szrj
240438fd1498Szrj /* Flush the mem ref hash table, if current bb doesn't have
240538fd1498Szrj exactly one predecessor, or if that predecessor (skipping
240638fd1498Szrj over asan created basic blocks) isn't the last processed
240738fd1498Szrj basic block. Thus we effectively flush on extended basic
240838fd1498Szrj block boundaries. */
240938fd1498Szrj while (single_pred_p (prev_bb))
241038fd1498Szrj {
241138fd1498Szrj prev_bb = single_pred (prev_bb);
241238fd1498Szrj if (prev_bb->index < saved_last_basic_block)
241338fd1498Szrj break;
241438fd1498Szrj }
241538fd1498Szrj if (prev_bb != last_bb)
241638fd1498Szrj empty_mem_ref_hash_table ();
241738fd1498Szrj last_bb = bb;
241838fd1498Szrj
241938fd1498Szrj for (i = gsi_start_bb (bb); !gsi_end_p (i);)
242038fd1498Szrj {
242138fd1498Szrj gimple *s = gsi_stmt (i);
242238fd1498Szrj
242338fd1498Szrj if (has_stmt_been_instrumented_p (s))
242438fd1498Szrj gsi_next (&i);
242538fd1498Szrj else if (gimple_assign_single_p (s)
242638fd1498Szrj && !gimple_clobber_p (s)
242738fd1498Szrj && maybe_instrument_assignment (&i))
242838fd1498Szrj /* Nothing to do as maybe_instrument_assignment advanced
242938fd1498Szrj the iterator I. */;
243038fd1498Szrj else if (is_gimple_call (s) && maybe_instrument_call (&i))
243138fd1498Szrj /* Nothing to do as maybe_instrument_call
243238fd1498Szrj advanced the iterator I. */;
243338fd1498Szrj else
243438fd1498Szrj {
243538fd1498Szrj /* No instrumentation happened.
243638fd1498Szrj
243738fd1498Szrj If the current instruction is a function call that
243838fd1498Szrj might free something, let's forget about the memory
243938fd1498Szrj references that got instrumented. Otherwise we might
244038fd1498Szrj miss some instrumentation opportunities. Do the same
244138fd1498Szrj for a ASAN_MARK poisoning internal function. */
244238fd1498Szrj if (is_gimple_call (s)
244338fd1498Szrj && (!nonfreeing_call_p (s)
244438fd1498Szrj || asan_mark_p (s, ASAN_MARK_POISON)))
244538fd1498Szrj empty_mem_ref_hash_table ();
244638fd1498Szrj
244738fd1498Szrj gsi_next (&i);
244838fd1498Szrj }
244938fd1498Szrj }
245038fd1498Szrj }
245138fd1498Szrj free_mem_ref_resources ();
245238fd1498Szrj }
245338fd1498Szrj
245438fd1498Szrj /* Build
245538fd1498Szrj __asan_before_dynamic_init (module_name)
245638fd1498Szrj or
245738fd1498Szrj __asan_after_dynamic_init ()
245838fd1498Szrj call. */
245938fd1498Szrj
246038fd1498Szrj tree
asan_dynamic_init_call(bool after_p)246138fd1498Szrj asan_dynamic_init_call (bool after_p)
246238fd1498Szrj {
246338fd1498Szrj if (shadow_ptr_types[0] == NULL_TREE)
246438fd1498Szrj asan_init_shadow_ptr_types ();
246538fd1498Szrj
246638fd1498Szrj tree fn = builtin_decl_implicit (after_p
246738fd1498Szrj ? BUILT_IN_ASAN_AFTER_DYNAMIC_INIT
246838fd1498Szrj : BUILT_IN_ASAN_BEFORE_DYNAMIC_INIT);
246938fd1498Szrj tree module_name_cst = NULL_TREE;
247038fd1498Szrj if (!after_p)
247138fd1498Szrj {
247238fd1498Szrj pretty_printer module_name_pp;
247338fd1498Szrj pp_string (&module_name_pp, main_input_filename);
247438fd1498Szrj
247538fd1498Szrj module_name_cst = asan_pp_string (&module_name_pp);
247638fd1498Szrj module_name_cst = fold_convert (const_ptr_type_node,
247738fd1498Szrj module_name_cst);
247838fd1498Szrj }
247938fd1498Szrj
248038fd1498Szrj return build_call_expr (fn, after_p ? 0 : 1, module_name_cst);
248138fd1498Szrj }
248238fd1498Szrj
248338fd1498Szrj /* Build
248438fd1498Szrj struct __asan_global
248538fd1498Szrj {
248638fd1498Szrj const void *__beg;
248738fd1498Szrj uptr __size;
248838fd1498Szrj uptr __size_with_redzone;
248938fd1498Szrj const void *__name;
249038fd1498Szrj const void *__module_name;
249138fd1498Szrj uptr __has_dynamic_init;
249238fd1498Szrj __asan_global_source_location *__location;
249338fd1498Szrj char *__odr_indicator;
249438fd1498Szrj } type. */
249538fd1498Szrj
249638fd1498Szrj static tree
asan_global_struct(void)249738fd1498Szrj asan_global_struct (void)
249838fd1498Szrj {
249938fd1498Szrj static const char *field_names[]
250038fd1498Szrj = { "__beg", "__size", "__size_with_redzone",
250138fd1498Szrj "__name", "__module_name", "__has_dynamic_init", "__location",
250238fd1498Szrj "__odr_indicator" };
250338fd1498Szrj tree fields[ARRAY_SIZE (field_names)], ret;
250438fd1498Szrj unsigned i;
250538fd1498Szrj
250638fd1498Szrj ret = make_node (RECORD_TYPE);
250738fd1498Szrj for (i = 0; i < ARRAY_SIZE (field_names); i++)
250838fd1498Szrj {
250938fd1498Szrj fields[i]
251038fd1498Szrj = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
251138fd1498Szrj get_identifier (field_names[i]),
251238fd1498Szrj (i == 0 || i == 3) ? const_ptr_type_node
251338fd1498Szrj : pointer_sized_int_node);
251438fd1498Szrj DECL_CONTEXT (fields[i]) = ret;
251538fd1498Szrj if (i)
251638fd1498Szrj DECL_CHAIN (fields[i - 1]) = fields[i];
251738fd1498Szrj }
251838fd1498Szrj tree type_decl = build_decl (input_location, TYPE_DECL,
251938fd1498Szrj get_identifier ("__asan_global"), ret);
252038fd1498Szrj DECL_IGNORED_P (type_decl) = 1;
252138fd1498Szrj DECL_ARTIFICIAL (type_decl) = 1;
252238fd1498Szrj TYPE_FIELDS (ret) = fields[0];
252338fd1498Szrj TYPE_NAME (ret) = type_decl;
252438fd1498Szrj TYPE_STUB_DECL (ret) = type_decl;
252538fd1498Szrj layout_type (ret);
252638fd1498Szrj return ret;
252738fd1498Szrj }
252838fd1498Szrj
252938fd1498Szrj /* Create and return odr indicator symbol for DECL.
253038fd1498Szrj TYPE is __asan_global struct type as returned by asan_global_struct. */
253138fd1498Szrj
253238fd1498Szrj static tree
create_odr_indicator(tree decl,tree type)253338fd1498Szrj create_odr_indicator (tree decl, tree type)
253438fd1498Szrj {
253538fd1498Szrj char *name;
253638fd1498Szrj tree uptr = TREE_TYPE (DECL_CHAIN (TYPE_FIELDS (type)));
253738fd1498Szrj tree decl_name
253838fd1498Szrj = (HAS_DECL_ASSEMBLER_NAME_P (decl) ? DECL_ASSEMBLER_NAME (decl)
253938fd1498Szrj : DECL_NAME (decl));
254038fd1498Szrj /* DECL_NAME theoretically might be NULL. Bail out with 0 in this case. */
254138fd1498Szrj if (decl_name == NULL_TREE)
254238fd1498Szrj return build_int_cst (uptr, 0);
254338fd1498Szrj const char *dname = IDENTIFIER_POINTER (decl_name);
254438fd1498Szrj if (HAS_DECL_ASSEMBLER_NAME_P (decl))
254538fd1498Szrj dname = targetm.strip_name_encoding (dname);
254638fd1498Szrj size_t len = strlen (dname) + sizeof ("__odr_asan_");
254738fd1498Szrj name = XALLOCAVEC (char, len);
254838fd1498Szrj snprintf (name, len, "__odr_asan_%s", dname);
254938fd1498Szrj #ifndef NO_DOT_IN_LABEL
255038fd1498Szrj name[sizeof ("__odr_asan") - 1] = '.';
255138fd1498Szrj #elif !defined(NO_DOLLAR_IN_LABEL)
255238fd1498Szrj name[sizeof ("__odr_asan") - 1] = '$';
255338fd1498Szrj #endif
255438fd1498Szrj tree var = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (name),
255538fd1498Szrj char_type_node);
255638fd1498Szrj TREE_ADDRESSABLE (var) = 1;
255738fd1498Szrj TREE_READONLY (var) = 0;
255838fd1498Szrj TREE_THIS_VOLATILE (var) = 1;
255938fd1498Szrj DECL_GIMPLE_REG_P (var) = 0;
256038fd1498Szrj DECL_ARTIFICIAL (var) = 1;
256138fd1498Szrj DECL_IGNORED_P (var) = 1;
256238fd1498Szrj TREE_STATIC (var) = 1;
256338fd1498Szrj TREE_PUBLIC (var) = 1;
256438fd1498Szrj DECL_VISIBILITY (var) = DECL_VISIBILITY (decl);
256538fd1498Szrj DECL_VISIBILITY_SPECIFIED (var) = DECL_VISIBILITY_SPECIFIED (decl);
256638fd1498Szrj
256738fd1498Szrj TREE_USED (var) = 1;
256838fd1498Szrj tree ctor = build_constructor_va (TREE_TYPE (var), 1, NULL_TREE,
256938fd1498Szrj build_int_cst (unsigned_type_node, 0));
257038fd1498Szrj TREE_CONSTANT (ctor) = 1;
257138fd1498Szrj TREE_STATIC (ctor) = 1;
257238fd1498Szrj DECL_INITIAL (var) = ctor;
257338fd1498Szrj DECL_ATTRIBUTES (var) = tree_cons (get_identifier ("asan odr indicator"),
257438fd1498Szrj NULL, DECL_ATTRIBUTES (var));
257538fd1498Szrj make_decl_rtl (var);
257638fd1498Szrj varpool_node::finalize_decl (var);
257738fd1498Szrj return fold_convert (uptr, build_fold_addr_expr (var));
257838fd1498Szrj }
257938fd1498Szrj
258038fd1498Szrj /* Return true if DECL, a global var, might be overridden and needs
258138fd1498Szrj an additional odr indicator symbol. */
258238fd1498Szrj
258338fd1498Szrj static bool
asan_needs_odr_indicator_p(tree decl)258438fd1498Szrj asan_needs_odr_indicator_p (tree decl)
258538fd1498Szrj {
258638fd1498Szrj /* Don't emit ODR indicators for kernel because:
258738fd1498Szrj a) Kernel is written in C thus doesn't need ODR indicators.
258838fd1498Szrj b) Some kernel code may have assumptions about symbols containing specific
258938fd1498Szrj patterns in their names. Since ODR indicators contain original names
259038fd1498Szrj of symbols they are emitted for, these assumptions would be broken for
259138fd1498Szrj ODR indicator symbols. */
259238fd1498Szrj return (!(flag_sanitize & SANITIZE_KERNEL_ADDRESS)
259338fd1498Szrj && !DECL_ARTIFICIAL (decl)
259438fd1498Szrj && !DECL_WEAK (decl)
259538fd1498Szrj && TREE_PUBLIC (decl));
259638fd1498Szrj }
259738fd1498Szrj
259838fd1498Szrj /* Append description of a single global DECL into vector V.
259938fd1498Szrj TYPE is __asan_global struct type as returned by asan_global_struct. */
260038fd1498Szrj
260138fd1498Szrj static void
asan_add_global(tree decl,tree type,vec<constructor_elt,va_gc> * v)260238fd1498Szrj asan_add_global (tree decl, tree type, vec<constructor_elt, va_gc> *v)
260338fd1498Szrj {
260438fd1498Szrj tree init, uptr = TREE_TYPE (DECL_CHAIN (TYPE_FIELDS (type)));
260538fd1498Szrj unsigned HOST_WIDE_INT size;
260638fd1498Szrj tree str_cst, module_name_cst, refdecl = decl;
260738fd1498Szrj vec<constructor_elt, va_gc> *vinner = NULL;
260838fd1498Szrj
260938fd1498Szrj pretty_printer asan_pp, module_name_pp;
261038fd1498Szrj
261138fd1498Szrj if (DECL_NAME (decl))
261238fd1498Szrj pp_tree_identifier (&asan_pp, DECL_NAME (decl));
261338fd1498Szrj else
261438fd1498Szrj pp_string (&asan_pp, "<unknown>");
261538fd1498Szrj str_cst = asan_pp_string (&asan_pp);
261638fd1498Szrj
261738fd1498Szrj pp_string (&module_name_pp, main_input_filename);
261838fd1498Szrj module_name_cst = asan_pp_string (&module_name_pp);
261938fd1498Szrj
262038fd1498Szrj if (asan_needs_local_alias (decl))
262138fd1498Szrj {
262238fd1498Szrj char buf[20];
262338fd1498Szrj ASM_GENERATE_INTERNAL_LABEL (buf, "LASAN", vec_safe_length (v) + 1);
262438fd1498Szrj refdecl = build_decl (DECL_SOURCE_LOCATION (decl),
262538fd1498Szrj VAR_DECL, get_identifier (buf), TREE_TYPE (decl));
262638fd1498Szrj TREE_ADDRESSABLE (refdecl) = TREE_ADDRESSABLE (decl);
262738fd1498Szrj TREE_READONLY (refdecl) = TREE_READONLY (decl);
262838fd1498Szrj TREE_THIS_VOLATILE (refdecl) = TREE_THIS_VOLATILE (decl);
262938fd1498Szrj DECL_GIMPLE_REG_P (refdecl) = DECL_GIMPLE_REG_P (decl);
263038fd1498Szrj DECL_ARTIFICIAL (refdecl) = DECL_ARTIFICIAL (decl);
263138fd1498Szrj DECL_IGNORED_P (refdecl) = DECL_IGNORED_P (decl);
263238fd1498Szrj TREE_STATIC (refdecl) = 1;
263338fd1498Szrj TREE_PUBLIC (refdecl) = 0;
263438fd1498Szrj TREE_USED (refdecl) = 1;
263538fd1498Szrj assemble_alias (refdecl, DECL_ASSEMBLER_NAME (decl));
263638fd1498Szrj }
263738fd1498Szrj
263838fd1498Szrj tree odr_indicator_ptr
263938fd1498Szrj = (asan_needs_odr_indicator_p (decl) ? create_odr_indicator (decl, type)
264038fd1498Szrj : build_int_cst (uptr, 0));
264138fd1498Szrj CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE,
264238fd1498Szrj fold_convert (const_ptr_type_node,
264338fd1498Szrj build_fold_addr_expr (refdecl)));
264438fd1498Szrj size = tree_to_uhwi (DECL_SIZE_UNIT (decl));
264538fd1498Szrj CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE, build_int_cst (uptr, size));
264638fd1498Szrj size += asan_red_zone_size (size);
264738fd1498Szrj CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE, build_int_cst (uptr, size));
264838fd1498Szrj CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE,
264938fd1498Szrj fold_convert (const_ptr_type_node, str_cst));
265038fd1498Szrj CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE,
265138fd1498Szrj fold_convert (const_ptr_type_node, module_name_cst));
265238fd1498Szrj varpool_node *vnode = varpool_node::get (decl);
265338fd1498Szrj int has_dynamic_init = 0;
265438fd1498Szrj /* FIXME: Enable initialization order fiasco detection in LTO mode once
265538fd1498Szrj proper fix for PR 79061 will be applied. */
265638fd1498Szrj if (!in_lto_p)
265738fd1498Szrj has_dynamic_init = vnode ? vnode->dynamically_initialized : 0;
265838fd1498Szrj CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE,
265938fd1498Szrj build_int_cst (uptr, has_dynamic_init));
266038fd1498Szrj tree locptr = NULL_TREE;
266138fd1498Szrj location_t loc = DECL_SOURCE_LOCATION (decl);
266238fd1498Szrj expanded_location xloc = expand_location (loc);
266338fd1498Szrj if (xloc.file != NULL)
266438fd1498Szrj {
266538fd1498Szrj static int lasanloccnt = 0;
266638fd1498Szrj char buf[25];
266738fd1498Szrj ASM_GENERATE_INTERNAL_LABEL (buf, "LASANLOC", ++lasanloccnt);
266838fd1498Szrj tree var = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (buf),
266938fd1498Szrj ubsan_get_source_location_type ());
267038fd1498Szrj TREE_STATIC (var) = 1;
267138fd1498Szrj TREE_PUBLIC (var) = 0;
267238fd1498Szrj DECL_ARTIFICIAL (var) = 1;
267338fd1498Szrj DECL_IGNORED_P (var) = 1;
267438fd1498Szrj pretty_printer filename_pp;
267538fd1498Szrj pp_string (&filename_pp, xloc.file);
267638fd1498Szrj tree str = asan_pp_string (&filename_pp);
267738fd1498Szrj tree ctor = build_constructor_va (TREE_TYPE (var), 3,
267838fd1498Szrj NULL_TREE, str, NULL_TREE,
267938fd1498Szrj build_int_cst (unsigned_type_node,
268038fd1498Szrj xloc.line), NULL_TREE,
268138fd1498Szrj build_int_cst (unsigned_type_node,
268238fd1498Szrj xloc.column));
268338fd1498Szrj TREE_CONSTANT (ctor) = 1;
268438fd1498Szrj TREE_STATIC (ctor) = 1;
268538fd1498Szrj DECL_INITIAL (var) = ctor;
268638fd1498Szrj varpool_node::finalize_decl (var);
268738fd1498Szrj locptr = fold_convert (uptr, build_fold_addr_expr (var));
268838fd1498Szrj }
268938fd1498Szrj else
269038fd1498Szrj locptr = build_int_cst (uptr, 0);
269138fd1498Szrj CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE, locptr);
269238fd1498Szrj CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE, odr_indicator_ptr);
269338fd1498Szrj init = build_constructor (type, vinner);
269438fd1498Szrj CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, init);
269538fd1498Szrj }
269638fd1498Szrj
269738fd1498Szrj /* Initialize sanitizer.def builtins if the FE hasn't initialized them. */
269838fd1498Szrj void
initialize_sanitizer_builtins(void)269938fd1498Szrj initialize_sanitizer_builtins (void)
270038fd1498Szrj {
270138fd1498Szrj tree decl;
270238fd1498Szrj
270338fd1498Szrj if (builtin_decl_implicit_p (BUILT_IN_ASAN_INIT))
270438fd1498Szrj return;
270538fd1498Szrj
270638fd1498Szrj tree BT_FN_VOID = build_function_type_list (void_type_node, NULL_TREE);
270738fd1498Szrj tree BT_FN_VOID_PTR
270838fd1498Szrj = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
270938fd1498Szrj tree BT_FN_VOID_CONST_PTR
271038fd1498Szrj = build_function_type_list (void_type_node, const_ptr_type_node, NULL_TREE);
271138fd1498Szrj tree BT_FN_VOID_PTR_PTR
271238fd1498Szrj = build_function_type_list (void_type_node, ptr_type_node,
271338fd1498Szrj ptr_type_node, NULL_TREE);
271438fd1498Szrj tree BT_FN_VOID_PTR_PTR_PTR
271538fd1498Szrj = build_function_type_list (void_type_node, ptr_type_node,
271638fd1498Szrj ptr_type_node, ptr_type_node, NULL_TREE);
271738fd1498Szrj tree BT_FN_VOID_PTR_PTRMODE
271838fd1498Szrj = build_function_type_list (void_type_node, ptr_type_node,
271938fd1498Szrj pointer_sized_int_node, NULL_TREE);
272038fd1498Szrj tree BT_FN_VOID_INT
272138fd1498Szrj = build_function_type_list (void_type_node, integer_type_node, NULL_TREE);
272238fd1498Szrj tree BT_FN_SIZE_CONST_PTR_INT
272338fd1498Szrj = build_function_type_list (size_type_node, const_ptr_type_node,
272438fd1498Szrj integer_type_node, NULL_TREE);
272538fd1498Szrj
272638fd1498Szrj tree BT_FN_VOID_UINT8_UINT8
272738fd1498Szrj = build_function_type_list (void_type_node, unsigned_char_type_node,
272838fd1498Szrj unsigned_char_type_node, NULL_TREE);
272938fd1498Szrj tree BT_FN_VOID_UINT16_UINT16
273038fd1498Szrj = build_function_type_list (void_type_node, uint16_type_node,
273138fd1498Szrj uint16_type_node, NULL_TREE);
273238fd1498Szrj tree BT_FN_VOID_UINT32_UINT32
273338fd1498Szrj = build_function_type_list (void_type_node, uint32_type_node,
273438fd1498Szrj uint32_type_node, NULL_TREE);
273538fd1498Szrj tree BT_FN_VOID_UINT64_UINT64
273638fd1498Szrj = build_function_type_list (void_type_node, uint64_type_node,
273738fd1498Szrj uint64_type_node, NULL_TREE);
273838fd1498Szrj tree BT_FN_VOID_FLOAT_FLOAT
273938fd1498Szrj = build_function_type_list (void_type_node, float_type_node,
274038fd1498Szrj float_type_node, NULL_TREE);
274138fd1498Szrj tree BT_FN_VOID_DOUBLE_DOUBLE
274238fd1498Szrj = build_function_type_list (void_type_node, double_type_node,
274338fd1498Szrj double_type_node, NULL_TREE);
274438fd1498Szrj tree BT_FN_VOID_UINT64_PTR
274538fd1498Szrj = build_function_type_list (void_type_node, uint64_type_node,
274638fd1498Szrj ptr_type_node, NULL_TREE);
274738fd1498Szrj
274838fd1498Szrj tree BT_FN_BOOL_VPTR_PTR_IX_INT_INT[5];
274938fd1498Szrj tree BT_FN_IX_CONST_VPTR_INT[5];
275038fd1498Szrj tree BT_FN_IX_VPTR_IX_INT[5];
275138fd1498Szrj tree BT_FN_VOID_VPTR_IX_INT[5];
275238fd1498Szrj tree vptr
275338fd1498Szrj = build_pointer_type (build_qualified_type (void_type_node,
275438fd1498Szrj TYPE_QUAL_VOLATILE));
275538fd1498Szrj tree cvptr
275638fd1498Szrj = build_pointer_type (build_qualified_type (void_type_node,
275738fd1498Szrj TYPE_QUAL_VOLATILE
275838fd1498Szrj |TYPE_QUAL_CONST));
275938fd1498Szrj tree boolt
276038fd1498Szrj = lang_hooks.types.type_for_size (BOOL_TYPE_SIZE, 1);
276138fd1498Szrj int i;
276238fd1498Szrj for (i = 0; i < 5; i++)
276338fd1498Szrj {
276438fd1498Szrj tree ix = build_nonstandard_integer_type (BITS_PER_UNIT * (1 << i), 1);
276538fd1498Szrj BT_FN_BOOL_VPTR_PTR_IX_INT_INT[i]
276638fd1498Szrj = build_function_type_list (boolt, vptr, ptr_type_node, ix,
276738fd1498Szrj integer_type_node, integer_type_node,
276838fd1498Szrj NULL_TREE);
276938fd1498Szrj BT_FN_IX_CONST_VPTR_INT[i]
277038fd1498Szrj = build_function_type_list (ix, cvptr, integer_type_node, NULL_TREE);
277138fd1498Szrj BT_FN_IX_VPTR_IX_INT[i]
277238fd1498Szrj = build_function_type_list (ix, vptr, ix, integer_type_node,
277338fd1498Szrj NULL_TREE);
277438fd1498Szrj BT_FN_VOID_VPTR_IX_INT[i]
277538fd1498Szrj = build_function_type_list (void_type_node, vptr, ix,
277638fd1498Szrj integer_type_node, NULL_TREE);
277738fd1498Szrj }
277838fd1498Szrj #define BT_FN_BOOL_VPTR_PTR_I1_INT_INT BT_FN_BOOL_VPTR_PTR_IX_INT_INT[0]
277938fd1498Szrj #define BT_FN_I1_CONST_VPTR_INT BT_FN_IX_CONST_VPTR_INT[0]
278038fd1498Szrj #define BT_FN_I1_VPTR_I1_INT BT_FN_IX_VPTR_IX_INT[0]
278138fd1498Szrj #define BT_FN_VOID_VPTR_I1_INT BT_FN_VOID_VPTR_IX_INT[0]
278238fd1498Szrj #define BT_FN_BOOL_VPTR_PTR_I2_INT_INT BT_FN_BOOL_VPTR_PTR_IX_INT_INT[1]
278338fd1498Szrj #define BT_FN_I2_CONST_VPTR_INT BT_FN_IX_CONST_VPTR_INT[1]
278438fd1498Szrj #define BT_FN_I2_VPTR_I2_INT BT_FN_IX_VPTR_IX_INT[1]
278538fd1498Szrj #define BT_FN_VOID_VPTR_I2_INT BT_FN_VOID_VPTR_IX_INT[1]
278638fd1498Szrj #define BT_FN_BOOL_VPTR_PTR_I4_INT_INT BT_FN_BOOL_VPTR_PTR_IX_INT_INT[2]
278738fd1498Szrj #define BT_FN_I4_CONST_VPTR_INT BT_FN_IX_CONST_VPTR_INT[2]
278838fd1498Szrj #define BT_FN_I4_VPTR_I4_INT BT_FN_IX_VPTR_IX_INT[2]
278938fd1498Szrj #define BT_FN_VOID_VPTR_I4_INT BT_FN_VOID_VPTR_IX_INT[2]
279038fd1498Szrj #define BT_FN_BOOL_VPTR_PTR_I8_INT_INT BT_FN_BOOL_VPTR_PTR_IX_INT_INT[3]
279138fd1498Szrj #define BT_FN_I8_CONST_VPTR_INT BT_FN_IX_CONST_VPTR_INT[3]
279238fd1498Szrj #define BT_FN_I8_VPTR_I8_INT BT_FN_IX_VPTR_IX_INT[3]
279338fd1498Szrj #define BT_FN_VOID_VPTR_I8_INT BT_FN_VOID_VPTR_IX_INT[3]
279438fd1498Szrj #define BT_FN_BOOL_VPTR_PTR_I16_INT_INT BT_FN_BOOL_VPTR_PTR_IX_INT_INT[4]
279538fd1498Szrj #define BT_FN_I16_CONST_VPTR_INT BT_FN_IX_CONST_VPTR_INT[4]
279638fd1498Szrj #define BT_FN_I16_VPTR_I16_INT BT_FN_IX_VPTR_IX_INT[4]
279738fd1498Szrj #define BT_FN_VOID_VPTR_I16_INT BT_FN_VOID_VPTR_IX_INT[4]
279838fd1498Szrj #undef ATTR_NOTHROW_LEAF_LIST
279938fd1498Szrj #define ATTR_NOTHROW_LEAF_LIST ECF_NOTHROW | ECF_LEAF
280038fd1498Szrj #undef ATTR_TMPURE_NOTHROW_LEAF_LIST
280138fd1498Szrj #define ATTR_TMPURE_NOTHROW_LEAF_LIST ECF_TM_PURE | ATTR_NOTHROW_LEAF_LIST
280238fd1498Szrj #undef ATTR_NORETURN_NOTHROW_LEAF_LIST
280338fd1498Szrj #define ATTR_NORETURN_NOTHROW_LEAF_LIST ECF_NORETURN | ATTR_NOTHROW_LEAF_LIST
280438fd1498Szrj #undef ATTR_CONST_NORETURN_NOTHROW_LEAF_LIST
280538fd1498Szrj #define ATTR_CONST_NORETURN_NOTHROW_LEAF_LIST \
280638fd1498Szrj ECF_CONST | ATTR_NORETURN_NOTHROW_LEAF_LIST
280738fd1498Szrj #undef ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST
280838fd1498Szrj #define ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST \
280938fd1498Szrj ECF_TM_PURE | ATTR_NORETURN_NOTHROW_LEAF_LIST
281038fd1498Szrj #undef ATTR_COLD_NOTHROW_LEAF_LIST
281138fd1498Szrj #define ATTR_COLD_NOTHROW_LEAF_LIST \
281238fd1498Szrj /* ECF_COLD missing */ ATTR_NOTHROW_LEAF_LIST
281338fd1498Szrj #undef ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST
281438fd1498Szrj #define ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST \
281538fd1498Szrj /* ECF_COLD missing */ ATTR_NORETURN_NOTHROW_LEAF_LIST
281638fd1498Szrj #undef ATTR_COLD_CONST_NORETURN_NOTHROW_LEAF_LIST
281738fd1498Szrj #define ATTR_COLD_CONST_NORETURN_NOTHROW_LEAF_LIST \
281838fd1498Szrj /* ECF_COLD missing */ ATTR_CONST_NORETURN_NOTHROW_LEAF_LIST
281938fd1498Szrj #undef ATTR_PURE_NOTHROW_LEAF_LIST
282038fd1498Szrj #define ATTR_PURE_NOTHROW_LEAF_LIST ECF_PURE | ATTR_NOTHROW_LEAF_LIST
282138fd1498Szrj #undef DEF_BUILTIN_STUB
282238fd1498Szrj #define DEF_BUILTIN_STUB(ENUM, NAME)
282338fd1498Szrj #undef DEF_SANITIZER_BUILTIN_1
282438fd1498Szrj #define DEF_SANITIZER_BUILTIN_1(ENUM, NAME, TYPE, ATTRS) \
282538fd1498Szrj do { \
282638fd1498Szrj decl = add_builtin_function ("__builtin_" NAME, TYPE, ENUM, \
282738fd1498Szrj BUILT_IN_NORMAL, NAME, NULL_TREE); \
282838fd1498Szrj set_call_expr_flags (decl, ATTRS); \
282938fd1498Szrj set_builtin_decl (ENUM, decl, true); \
283038fd1498Szrj } while (0)
283138fd1498Szrj #undef DEF_SANITIZER_BUILTIN
283238fd1498Szrj #define DEF_SANITIZER_BUILTIN(ENUM, NAME, TYPE, ATTRS) \
283338fd1498Szrj DEF_SANITIZER_BUILTIN_1 (ENUM, NAME, TYPE, ATTRS);
283438fd1498Szrj
283538fd1498Szrj #include "sanitizer.def"
283638fd1498Szrj
283738fd1498Szrj /* -fsanitize=object-size uses __builtin_object_size, but that might
283838fd1498Szrj not be available for e.g. Fortran at this point. We use
283938fd1498Szrj DEF_SANITIZER_BUILTIN here only as a convenience macro. */
284038fd1498Szrj if ((flag_sanitize & SANITIZE_OBJECT_SIZE)
284138fd1498Szrj && !builtin_decl_implicit_p (BUILT_IN_OBJECT_SIZE))
284238fd1498Szrj DEF_SANITIZER_BUILTIN_1 (BUILT_IN_OBJECT_SIZE, "object_size",
284338fd1498Szrj BT_FN_SIZE_CONST_PTR_INT,
284438fd1498Szrj ATTR_PURE_NOTHROW_LEAF_LIST);
284538fd1498Szrj
284638fd1498Szrj #undef DEF_SANITIZER_BUILTIN_1
284738fd1498Szrj #undef DEF_SANITIZER_BUILTIN
284838fd1498Szrj #undef DEF_BUILTIN_STUB
284938fd1498Szrj }
285038fd1498Szrj
285138fd1498Szrj /* Called via htab_traverse. Count number of emitted
285238fd1498Szrj STRING_CSTs in the constant hash table. */
285338fd1498Szrj
285438fd1498Szrj int
count_string_csts(constant_descriptor_tree ** slot,unsigned HOST_WIDE_INT * data)285538fd1498Szrj count_string_csts (constant_descriptor_tree **slot,
285638fd1498Szrj unsigned HOST_WIDE_INT *data)
285738fd1498Szrj {
285838fd1498Szrj struct constant_descriptor_tree *desc = *slot;
285938fd1498Szrj if (TREE_CODE (desc->value) == STRING_CST
286038fd1498Szrj && TREE_ASM_WRITTEN (desc->value)
286138fd1498Szrj && asan_protect_global (desc->value))
286238fd1498Szrj ++*data;
286338fd1498Szrj return 1;
286438fd1498Szrj }
286538fd1498Szrj
286638fd1498Szrj /* Helper structure to pass two parameters to
286738fd1498Szrj add_string_csts. */
286838fd1498Szrj
286938fd1498Szrj struct asan_add_string_csts_data
287038fd1498Szrj {
287138fd1498Szrj tree type;
287238fd1498Szrj vec<constructor_elt, va_gc> *v;
287338fd1498Szrj };
287438fd1498Szrj
287538fd1498Szrj /* Called via hash_table::traverse. Call asan_add_global
287638fd1498Szrj on emitted STRING_CSTs from the constant hash table. */
287738fd1498Szrj
287838fd1498Szrj int
add_string_csts(constant_descriptor_tree ** slot,asan_add_string_csts_data * aascd)287938fd1498Szrj add_string_csts (constant_descriptor_tree **slot,
288038fd1498Szrj asan_add_string_csts_data *aascd)
288138fd1498Szrj {
288238fd1498Szrj struct constant_descriptor_tree *desc = *slot;
288338fd1498Szrj if (TREE_CODE (desc->value) == STRING_CST
288438fd1498Szrj && TREE_ASM_WRITTEN (desc->value)
288538fd1498Szrj && asan_protect_global (desc->value))
288638fd1498Szrj {
288738fd1498Szrj asan_add_global (SYMBOL_REF_DECL (XEXP (desc->rtl, 0)),
288838fd1498Szrj aascd->type, aascd->v);
288938fd1498Szrj }
289038fd1498Szrj return 1;
289138fd1498Szrj }
289238fd1498Szrj
289338fd1498Szrj /* Needs to be GTY(()), because cgraph_build_static_cdtor may
289438fd1498Szrj invoke ggc_collect. */
289538fd1498Szrj static GTY(()) tree asan_ctor_statements;
289638fd1498Szrj
289738fd1498Szrj /* Module-level instrumentation.
289838fd1498Szrj - Insert __asan_init_vN() into the list of CTORs.
289938fd1498Szrj - TODO: insert redzones around globals.
290038fd1498Szrj */
290138fd1498Szrj
290238fd1498Szrj void
asan_finish_file(void)290338fd1498Szrj asan_finish_file (void)
290438fd1498Szrj {
290538fd1498Szrj varpool_node *vnode;
290638fd1498Szrj unsigned HOST_WIDE_INT gcount = 0;
290738fd1498Szrj
290838fd1498Szrj if (shadow_ptr_types[0] == NULL_TREE)
290938fd1498Szrj asan_init_shadow_ptr_types ();
291038fd1498Szrj /* Avoid instrumenting code in the asan ctors/dtors.
291138fd1498Szrj We don't need to insert padding after the description strings,
291238fd1498Szrj nor after .LASAN* array. */
291338fd1498Szrj flag_sanitize &= ~SANITIZE_ADDRESS;
291438fd1498Szrj
291538fd1498Szrj /* For user-space we want asan constructors to run first.
291638fd1498Szrj Linux kernel does not support priorities other than default, and the only
291738fd1498Szrj other user of constructors is coverage. So we run with the default
291838fd1498Szrj priority. */
291938fd1498Szrj int priority = flag_sanitize & SANITIZE_USER_ADDRESS
292038fd1498Szrj ? MAX_RESERVED_INIT_PRIORITY - 1 : DEFAULT_INIT_PRIORITY;
292138fd1498Szrj
292238fd1498Szrj if (flag_sanitize & SANITIZE_USER_ADDRESS)
292338fd1498Szrj {
292438fd1498Szrj tree fn = builtin_decl_implicit (BUILT_IN_ASAN_INIT);
292538fd1498Szrj append_to_statement_list (build_call_expr (fn, 0), &asan_ctor_statements);
292638fd1498Szrj fn = builtin_decl_implicit (BUILT_IN_ASAN_VERSION_MISMATCH_CHECK);
292738fd1498Szrj append_to_statement_list (build_call_expr (fn, 0), &asan_ctor_statements);
292838fd1498Szrj }
292938fd1498Szrj FOR_EACH_DEFINED_VARIABLE (vnode)
293038fd1498Szrj if (TREE_ASM_WRITTEN (vnode->decl)
293138fd1498Szrj && asan_protect_global (vnode->decl))
293238fd1498Szrj ++gcount;
293338fd1498Szrj hash_table<tree_descriptor_hasher> *const_desc_htab = constant_pool_htab ();
293438fd1498Szrj const_desc_htab->traverse<unsigned HOST_WIDE_INT *, count_string_csts>
293538fd1498Szrj (&gcount);
293638fd1498Szrj if (gcount)
293738fd1498Szrj {
293838fd1498Szrj tree type = asan_global_struct (), var, ctor;
293938fd1498Szrj tree dtor_statements = NULL_TREE;
294038fd1498Szrj vec<constructor_elt, va_gc> *v;
294138fd1498Szrj char buf[20];
294238fd1498Szrj
294338fd1498Szrj type = build_array_type_nelts (type, gcount);
294438fd1498Szrj ASM_GENERATE_INTERNAL_LABEL (buf, "LASAN", 0);
294538fd1498Szrj var = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (buf),
294638fd1498Szrj type);
294738fd1498Szrj TREE_STATIC (var) = 1;
294838fd1498Szrj TREE_PUBLIC (var) = 0;
294938fd1498Szrj DECL_ARTIFICIAL (var) = 1;
295038fd1498Szrj DECL_IGNORED_P (var) = 1;
295138fd1498Szrj vec_alloc (v, gcount);
295238fd1498Szrj FOR_EACH_DEFINED_VARIABLE (vnode)
295338fd1498Szrj if (TREE_ASM_WRITTEN (vnode->decl)
295438fd1498Szrj && asan_protect_global (vnode->decl))
295538fd1498Szrj asan_add_global (vnode->decl, TREE_TYPE (type), v);
295638fd1498Szrj struct asan_add_string_csts_data aascd;
295738fd1498Szrj aascd.type = TREE_TYPE (type);
295838fd1498Szrj aascd.v = v;
295938fd1498Szrj const_desc_htab->traverse<asan_add_string_csts_data *, add_string_csts>
296038fd1498Szrj (&aascd);
296138fd1498Szrj ctor = build_constructor (type, v);
296238fd1498Szrj TREE_CONSTANT (ctor) = 1;
296338fd1498Szrj TREE_STATIC (ctor) = 1;
296438fd1498Szrj DECL_INITIAL (var) = ctor;
296538fd1498Szrj SET_DECL_ALIGN (var, MAX (DECL_ALIGN (var),
296638fd1498Szrj ASAN_SHADOW_GRANULARITY * BITS_PER_UNIT));
296738fd1498Szrj
296838fd1498Szrj varpool_node::finalize_decl (var);
296938fd1498Szrj
297038fd1498Szrj tree fn = builtin_decl_implicit (BUILT_IN_ASAN_REGISTER_GLOBALS);
297138fd1498Szrj tree gcount_tree = build_int_cst (pointer_sized_int_node, gcount);
297238fd1498Szrj append_to_statement_list (build_call_expr (fn, 2,
297338fd1498Szrj build_fold_addr_expr (var),
297438fd1498Szrj gcount_tree),
297538fd1498Szrj &asan_ctor_statements);
297638fd1498Szrj
297738fd1498Szrj fn = builtin_decl_implicit (BUILT_IN_ASAN_UNREGISTER_GLOBALS);
297838fd1498Szrj append_to_statement_list (build_call_expr (fn, 2,
297938fd1498Szrj build_fold_addr_expr (var),
298038fd1498Szrj gcount_tree),
298138fd1498Szrj &dtor_statements);
298238fd1498Szrj cgraph_build_static_cdtor ('D', dtor_statements, priority);
298338fd1498Szrj }
298438fd1498Szrj if (asan_ctor_statements)
298538fd1498Szrj cgraph_build_static_cdtor ('I', asan_ctor_statements, priority);
298638fd1498Szrj flag_sanitize |= SANITIZE_ADDRESS;
298738fd1498Szrj }
298838fd1498Szrj
298938fd1498Szrj /* Poison or unpoison (depending on IS_CLOBBER variable) shadow memory based
299038fd1498Szrj on SHADOW address. Newly added statements will be added to ITER with
299138fd1498Szrj given location LOC. We mark SIZE bytes in shadow memory, where
299238fd1498Szrj LAST_CHUNK_SIZE is greater than zero in situation where we are at the
299338fd1498Szrj end of a variable. */
299438fd1498Szrj
299538fd1498Szrj static void
asan_store_shadow_bytes(gimple_stmt_iterator * iter,location_t loc,tree shadow,unsigned HOST_WIDE_INT base_addr_offset,bool is_clobber,unsigned size,unsigned last_chunk_size)299638fd1498Szrj asan_store_shadow_bytes (gimple_stmt_iterator *iter, location_t loc,
299738fd1498Szrj tree shadow,
299838fd1498Szrj unsigned HOST_WIDE_INT base_addr_offset,
299938fd1498Szrj bool is_clobber, unsigned size,
300038fd1498Szrj unsigned last_chunk_size)
300138fd1498Szrj {
300238fd1498Szrj tree shadow_ptr_type;
300338fd1498Szrj
300438fd1498Szrj switch (size)
300538fd1498Szrj {
300638fd1498Szrj case 1:
300738fd1498Szrj shadow_ptr_type = shadow_ptr_types[0];
300838fd1498Szrj break;
300938fd1498Szrj case 2:
301038fd1498Szrj shadow_ptr_type = shadow_ptr_types[1];
301138fd1498Szrj break;
301238fd1498Szrj case 4:
301338fd1498Szrj shadow_ptr_type = shadow_ptr_types[2];
301438fd1498Szrj break;
301538fd1498Szrj default:
301638fd1498Szrj gcc_unreachable ();
301738fd1498Szrj }
301838fd1498Szrj
301938fd1498Szrj unsigned char c = (char) is_clobber ? ASAN_STACK_MAGIC_USE_AFTER_SCOPE : 0;
302038fd1498Szrj unsigned HOST_WIDE_INT val = 0;
302138fd1498Szrj unsigned last_pos = size;
302238fd1498Szrj if (last_chunk_size && !is_clobber)
302338fd1498Szrj last_pos = BYTES_BIG_ENDIAN ? 0 : size - 1;
302438fd1498Szrj for (unsigned i = 0; i < size; ++i)
302538fd1498Szrj {
302638fd1498Szrj unsigned char shadow_c = c;
302738fd1498Szrj if (i == last_pos)
302838fd1498Szrj shadow_c = last_chunk_size;
302938fd1498Szrj val |= (unsigned HOST_WIDE_INT) shadow_c << (BITS_PER_UNIT * i);
303038fd1498Szrj }
303138fd1498Szrj
303238fd1498Szrj /* Handle last chunk in unpoisoning. */
303338fd1498Szrj tree magic = build_int_cst (TREE_TYPE (shadow_ptr_type), val);
303438fd1498Szrj
303538fd1498Szrj tree dest = build2 (MEM_REF, TREE_TYPE (shadow_ptr_type), shadow,
303638fd1498Szrj build_int_cst (shadow_ptr_type, base_addr_offset));
303738fd1498Szrj
303838fd1498Szrj gimple *g = gimple_build_assign (dest, magic);
303938fd1498Szrj gimple_set_location (g, loc);
304038fd1498Szrj gsi_insert_after (iter, g, GSI_NEW_STMT);
304138fd1498Szrj }
304238fd1498Szrj
304338fd1498Szrj /* Expand the ASAN_MARK builtins. */
304438fd1498Szrj
304538fd1498Szrj bool
asan_expand_mark_ifn(gimple_stmt_iterator * iter)304638fd1498Szrj asan_expand_mark_ifn (gimple_stmt_iterator *iter)
304738fd1498Szrj {
304838fd1498Szrj gimple *g = gsi_stmt (*iter);
304938fd1498Szrj location_t loc = gimple_location (g);
305038fd1498Szrj HOST_WIDE_INT flag = tree_to_shwi (gimple_call_arg (g, 0));
305138fd1498Szrj bool is_poison = ((asan_mark_flags)flag) == ASAN_MARK_POISON;
305238fd1498Szrj
305338fd1498Szrj tree base = gimple_call_arg (g, 1);
305438fd1498Szrj gcc_checking_assert (TREE_CODE (base) == ADDR_EXPR);
305538fd1498Szrj tree decl = TREE_OPERAND (base, 0);
305638fd1498Szrj
305738fd1498Szrj /* For a nested function, we can have: ASAN_MARK (2, &FRAME.2.fp_input, 4) */
305838fd1498Szrj if (TREE_CODE (decl) == COMPONENT_REF
305938fd1498Szrj && DECL_NONLOCAL_FRAME (TREE_OPERAND (decl, 0)))
306038fd1498Szrj decl = TREE_OPERAND (decl, 0);
306138fd1498Szrj
306238fd1498Szrj gcc_checking_assert (TREE_CODE (decl) == VAR_DECL);
306338fd1498Szrj
306438fd1498Szrj if (is_poison)
306538fd1498Szrj {
306638fd1498Szrj if (asan_handled_variables == NULL)
306738fd1498Szrj asan_handled_variables = new hash_set<tree> (16);
306838fd1498Szrj asan_handled_variables->add (decl);
306938fd1498Szrj }
307038fd1498Szrj tree len = gimple_call_arg (g, 2);
307138fd1498Szrj
307238fd1498Szrj gcc_assert (tree_fits_shwi_p (len));
307338fd1498Szrj unsigned HOST_WIDE_INT size_in_bytes = tree_to_shwi (len);
307438fd1498Szrj gcc_assert (size_in_bytes);
307538fd1498Szrj
307638fd1498Szrj g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
307738fd1498Szrj NOP_EXPR, base);
307838fd1498Szrj gimple_set_location (g, loc);
307938fd1498Szrj gsi_replace (iter, g, false);
308038fd1498Szrj tree base_addr = gimple_assign_lhs (g);
308138fd1498Szrj
308238fd1498Szrj /* Generate direct emission if size_in_bytes is small. */
308338fd1498Szrj if (size_in_bytes <= ASAN_PARAM_USE_AFTER_SCOPE_DIRECT_EMISSION_THRESHOLD)
308438fd1498Szrj {
308538fd1498Szrj unsigned HOST_WIDE_INT shadow_size = shadow_mem_size (size_in_bytes);
308638fd1498Szrj
308738fd1498Szrj tree shadow = build_shadow_mem_access (iter, loc, base_addr,
308838fd1498Szrj shadow_ptr_types[0], true);
308938fd1498Szrj
309038fd1498Szrj for (unsigned HOST_WIDE_INT offset = 0; offset < shadow_size;)
309138fd1498Szrj {
309238fd1498Szrj unsigned size = 1;
309338fd1498Szrj if (shadow_size - offset >= 4)
309438fd1498Szrj size = 4;
309538fd1498Szrj else if (shadow_size - offset >= 2)
309638fd1498Szrj size = 2;
309738fd1498Szrj
309838fd1498Szrj unsigned HOST_WIDE_INT last_chunk_size = 0;
309938fd1498Szrj unsigned HOST_WIDE_INT s = (offset + size) * ASAN_SHADOW_GRANULARITY;
310038fd1498Szrj if (s > size_in_bytes)
310138fd1498Szrj last_chunk_size = ASAN_SHADOW_GRANULARITY - (s - size_in_bytes);
310238fd1498Szrj
310338fd1498Szrj asan_store_shadow_bytes (iter, loc, shadow, offset, is_poison,
310438fd1498Szrj size, last_chunk_size);
310538fd1498Szrj offset += size;
310638fd1498Szrj }
310738fd1498Szrj }
310838fd1498Szrj else
310938fd1498Szrj {
311038fd1498Szrj g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
311138fd1498Szrj NOP_EXPR, len);
311238fd1498Szrj gimple_set_location (g, loc);
311338fd1498Szrj gsi_insert_before (iter, g, GSI_SAME_STMT);
311438fd1498Szrj tree sz_arg = gimple_assign_lhs (g);
311538fd1498Szrj
311638fd1498Szrj tree fun
311738fd1498Szrj = builtin_decl_implicit (is_poison ? BUILT_IN_ASAN_POISON_STACK_MEMORY
311838fd1498Szrj : BUILT_IN_ASAN_UNPOISON_STACK_MEMORY);
311938fd1498Szrj g = gimple_build_call (fun, 2, base_addr, sz_arg);
312038fd1498Szrj gimple_set_location (g, loc);
312138fd1498Szrj gsi_insert_after (iter, g, GSI_NEW_STMT);
312238fd1498Szrj }
312338fd1498Szrj
312438fd1498Szrj return false;
312538fd1498Szrj }
312638fd1498Szrj
312738fd1498Szrj /* Expand the ASAN_{LOAD,STORE} builtins. */
312838fd1498Szrj
312938fd1498Szrj bool
asan_expand_check_ifn(gimple_stmt_iterator * iter,bool use_calls)313038fd1498Szrj asan_expand_check_ifn (gimple_stmt_iterator *iter, bool use_calls)
313138fd1498Szrj {
313238fd1498Szrj gimple *g = gsi_stmt (*iter);
313338fd1498Szrj location_t loc = gimple_location (g);
313438fd1498Szrj bool recover_p;
313538fd1498Szrj if (flag_sanitize & SANITIZE_USER_ADDRESS)
313638fd1498Szrj recover_p = (flag_sanitize_recover & SANITIZE_USER_ADDRESS) != 0;
313738fd1498Szrj else
313838fd1498Szrj recover_p = (flag_sanitize_recover & SANITIZE_KERNEL_ADDRESS) != 0;
313938fd1498Szrj
314038fd1498Szrj HOST_WIDE_INT flags = tree_to_shwi (gimple_call_arg (g, 0));
314138fd1498Szrj gcc_assert (flags < ASAN_CHECK_LAST);
314238fd1498Szrj bool is_scalar_access = (flags & ASAN_CHECK_SCALAR_ACCESS) != 0;
314338fd1498Szrj bool is_store = (flags & ASAN_CHECK_STORE) != 0;
314438fd1498Szrj bool is_non_zero_len = (flags & ASAN_CHECK_NON_ZERO_LEN) != 0;
314538fd1498Szrj
314638fd1498Szrj tree base = gimple_call_arg (g, 1);
314738fd1498Szrj tree len = gimple_call_arg (g, 2);
314838fd1498Szrj HOST_WIDE_INT align = tree_to_shwi (gimple_call_arg (g, 3));
314938fd1498Szrj
315038fd1498Szrj HOST_WIDE_INT size_in_bytes
315138fd1498Szrj = is_scalar_access && tree_fits_shwi_p (len) ? tree_to_shwi (len) : -1;
315238fd1498Szrj
315338fd1498Szrj if (use_calls)
315438fd1498Szrj {
315538fd1498Szrj /* Instrument using callbacks. */
315638fd1498Szrj gimple *g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
315738fd1498Szrj NOP_EXPR, base);
315838fd1498Szrj gimple_set_location (g, loc);
315938fd1498Szrj gsi_insert_before (iter, g, GSI_SAME_STMT);
316038fd1498Szrj tree base_addr = gimple_assign_lhs (g);
316138fd1498Szrj
316238fd1498Szrj int nargs;
316338fd1498Szrj tree fun = check_func (is_store, recover_p, size_in_bytes, &nargs);
316438fd1498Szrj if (nargs == 1)
316538fd1498Szrj g = gimple_build_call (fun, 1, base_addr);
316638fd1498Szrj else
316738fd1498Szrj {
316838fd1498Szrj gcc_assert (nargs == 2);
316938fd1498Szrj g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
317038fd1498Szrj NOP_EXPR, len);
317138fd1498Szrj gimple_set_location (g, loc);
317238fd1498Szrj gsi_insert_before (iter, g, GSI_SAME_STMT);
317338fd1498Szrj tree sz_arg = gimple_assign_lhs (g);
317438fd1498Szrj g = gimple_build_call (fun, nargs, base_addr, sz_arg);
317538fd1498Szrj }
317638fd1498Szrj gimple_set_location (g, loc);
317738fd1498Szrj gsi_replace (iter, g, false);
317838fd1498Szrj return false;
317938fd1498Szrj }
318038fd1498Szrj
318138fd1498Szrj HOST_WIDE_INT real_size_in_bytes = size_in_bytes == -1 ? 1 : size_in_bytes;
318238fd1498Szrj
318338fd1498Szrj tree shadow_ptr_type = shadow_ptr_types[real_size_in_bytes == 16 ? 1 : 0];
318438fd1498Szrj tree shadow_type = TREE_TYPE (shadow_ptr_type);
318538fd1498Szrj
318638fd1498Szrj gimple_stmt_iterator gsi = *iter;
318738fd1498Szrj
318838fd1498Szrj if (!is_non_zero_len)
318938fd1498Szrj {
319038fd1498Szrj /* So, the length of the memory area to asan-protect is
319138fd1498Szrj non-constant. Let's guard the generated instrumentation code
319238fd1498Szrj like:
319338fd1498Szrj
319438fd1498Szrj if (len != 0)
319538fd1498Szrj {
319638fd1498Szrj //asan instrumentation code goes here.
319738fd1498Szrj }
319838fd1498Szrj // falltrough instructions, starting with *ITER. */
319938fd1498Szrj
320038fd1498Szrj g = gimple_build_cond (NE_EXPR,
320138fd1498Szrj len,
320238fd1498Szrj build_int_cst (TREE_TYPE (len), 0),
320338fd1498Szrj NULL_TREE, NULL_TREE);
320438fd1498Szrj gimple_set_location (g, loc);
320538fd1498Szrj
320638fd1498Szrj basic_block then_bb, fallthrough_bb;
320738fd1498Szrj insert_if_then_before_iter (as_a <gcond *> (g), iter,
320838fd1498Szrj /*then_more_likely_p=*/true,
320938fd1498Szrj &then_bb, &fallthrough_bb);
321038fd1498Szrj /* Note that fallthrough_bb starts with the statement that was
321138fd1498Szrj pointed to by ITER. */
321238fd1498Szrj
321338fd1498Szrj /* The 'then block' of the 'if (len != 0) condition is where
321438fd1498Szrj we'll generate the asan instrumentation code now. */
321538fd1498Szrj gsi = gsi_last_bb (then_bb);
321638fd1498Szrj }
321738fd1498Szrj
321838fd1498Szrj /* Get an iterator on the point where we can add the condition
321938fd1498Szrj statement for the instrumentation. */
322038fd1498Szrj basic_block then_bb, else_bb;
322138fd1498Szrj gsi = create_cond_insert_point (&gsi, /*before_p*/false,
322238fd1498Szrj /*then_more_likely_p=*/false,
322338fd1498Szrj /*create_then_fallthru_edge*/recover_p,
322438fd1498Szrj &then_bb,
322538fd1498Szrj &else_bb);
322638fd1498Szrj
322738fd1498Szrj g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
322838fd1498Szrj NOP_EXPR, base);
322938fd1498Szrj gimple_set_location (g, loc);
323038fd1498Szrj gsi_insert_before (&gsi, g, GSI_NEW_STMT);
323138fd1498Szrj tree base_addr = gimple_assign_lhs (g);
323238fd1498Szrj
323338fd1498Szrj tree t = NULL_TREE;
323438fd1498Szrj if (real_size_in_bytes >= 8)
323538fd1498Szrj {
323638fd1498Szrj tree shadow = build_shadow_mem_access (&gsi, loc, base_addr,
323738fd1498Szrj shadow_ptr_type);
323838fd1498Szrj t = shadow;
323938fd1498Szrj }
324038fd1498Szrj else
324138fd1498Szrj {
324238fd1498Szrj /* Slow path for 1, 2 and 4 byte accesses. */
324338fd1498Szrj /* Test (shadow != 0)
324438fd1498Szrj & ((base_addr & 7) + (real_size_in_bytes - 1)) >= shadow). */
324538fd1498Szrj tree shadow = build_shadow_mem_access (&gsi, loc, base_addr,
324638fd1498Szrj shadow_ptr_type);
324738fd1498Szrj gimple *shadow_test = build_assign (NE_EXPR, shadow, 0);
324838fd1498Szrj gimple_seq seq = NULL;
324938fd1498Szrj gimple_seq_add_stmt (&seq, shadow_test);
325038fd1498Szrj /* Aligned (>= 8 bytes) can test just
325138fd1498Szrj (real_size_in_bytes - 1 >= shadow), as base_addr & 7 is known
325238fd1498Szrj to be 0. */
325338fd1498Szrj if (align < 8)
325438fd1498Szrj {
325538fd1498Szrj gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR,
325638fd1498Szrj base_addr, 7));
325738fd1498Szrj gimple_seq_add_stmt (&seq,
325838fd1498Szrj build_type_cast (shadow_type,
325938fd1498Szrj gimple_seq_last (seq)));
326038fd1498Szrj if (real_size_in_bytes > 1)
326138fd1498Szrj gimple_seq_add_stmt (&seq,
326238fd1498Szrj build_assign (PLUS_EXPR,
326338fd1498Szrj gimple_seq_last (seq),
326438fd1498Szrj real_size_in_bytes - 1));
326538fd1498Szrj t = gimple_assign_lhs (gimple_seq_last_stmt (seq));
326638fd1498Szrj }
326738fd1498Szrj else
326838fd1498Szrj t = build_int_cst (shadow_type, real_size_in_bytes - 1);
326938fd1498Szrj gimple_seq_add_stmt (&seq, build_assign (GE_EXPR, t, shadow));
327038fd1498Szrj gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR, shadow_test,
327138fd1498Szrj gimple_seq_last (seq)));
327238fd1498Szrj t = gimple_assign_lhs (gimple_seq_last (seq));
327338fd1498Szrj gimple_seq_set_location (seq, loc);
327438fd1498Szrj gsi_insert_seq_after (&gsi, seq, GSI_CONTINUE_LINKING);
327538fd1498Szrj
327638fd1498Szrj /* For non-constant, misaligned or otherwise weird access sizes,
327738fd1498Szrj check first and last byte. */
327838fd1498Szrj if (size_in_bytes == -1)
327938fd1498Szrj {
328038fd1498Szrj g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
328138fd1498Szrj MINUS_EXPR, len,
328238fd1498Szrj build_int_cst (pointer_sized_int_node, 1));
328338fd1498Szrj gimple_set_location (g, loc);
328438fd1498Szrj gsi_insert_after (&gsi, g, GSI_NEW_STMT);
328538fd1498Szrj tree last = gimple_assign_lhs (g);
328638fd1498Szrj g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
328738fd1498Szrj PLUS_EXPR, base_addr, last);
328838fd1498Szrj gimple_set_location (g, loc);
328938fd1498Szrj gsi_insert_after (&gsi, g, GSI_NEW_STMT);
329038fd1498Szrj tree base_end_addr = gimple_assign_lhs (g);
329138fd1498Szrj
329238fd1498Szrj tree shadow = build_shadow_mem_access (&gsi, loc, base_end_addr,
329338fd1498Szrj shadow_ptr_type);
329438fd1498Szrj gimple *shadow_test = build_assign (NE_EXPR, shadow, 0);
329538fd1498Szrj gimple_seq seq = NULL;
329638fd1498Szrj gimple_seq_add_stmt (&seq, shadow_test);
329738fd1498Szrj gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR,
329838fd1498Szrj base_end_addr, 7));
329938fd1498Szrj gimple_seq_add_stmt (&seq, build_type_cast (shadow_type,
330038fd1498Szrj gimple_seq_last (seq)));
330138fd1498Szrj gimple_seq_add_stmt (&seq, build_assign (GE_EXPR,
330238fd1498Szrj gimple_seq_last (seq),
330338fd1498Szrj shadow));
330438fd1498Szrj gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR, shadow_test,
330538fd1498Szrj gimple_seq_last (seq)));
330638fd1498Szrj gimple_seq_add_stmt (&seq, build_assign (BIT_IOR_EXPR, t,
330738fd1498Szrj gimple_seq_last (seq)));
330838fd1498Szrj t = gimple_assign_lhs (gimple_seq_last (seq));
330938fd1498Szrj gimple_seq_set_location (seq, loc);
331038fd1498Szrj gsi_insert_seq_after (&gsi, seq, GSI_CONTINUE_LINKING);
331138fd1498Szrj }
331238fd1498Szrj }
331338fd1498Szrj
331438fd1498Szrj g = gimple_build_cond (NE_EXPR, t, build_int_cst (TREE_TYPE (t), 0),
331538fd1498Szrj NULL_TREE, NULL_TREE);
331638fd1498Szrj gimple_set_location (g, loc);
331738fd1498Szrj gsi_insert_after (&gsi, g, GSI_NEW_STMT);
331838fd1498Szrj
331938fd1498Szrj /* Generate call to the run-time library (e.g. __asan_report_load8). */
332038fd1498Szrj gsi = gsi_start_bb (then_bb);
332138fd1498Szrj int nargs;
332238fd1498Szrj tree fun = report_error_func (is_store, recover_p, size_in_bytes, &nargs);
332338fd1498Szrj g = gimple_build_call (fun, nargs, base_addr, len);
332438fd1498Szrj gimple_set_location (g, loc);
332538fd1498Szrj gsi_insert_after (&gsi, g, GSI_NEW_STMT);
332638fd1498Szrj
332738fd1498Szrj gsi_remove (iter, true);
332838fd1498Szrj *iter = gsi_start_bb (else_bb);
332938fd1498Szrj
333038fd1498Szrj return true;
333138fd1498Szrj }
333238fd1498Szrj
333338fd1498Szrj /* Create ASAN shadow variable for a VAR_DECL which has been rewritten
333438fd1498Szrj into SSA. Already seen VAR_DECLs are stored in SHADOW_VARS_MAPPING. */
333538fd1498Szrj
333638fd1498Szrj static tree
create_asan_shadow_var(tree var_decl,hash_map<tree,tree> & shadow_vars_mapping)333738fd1498Szrj create_asan_shadow_var (tree var_decl,
333838fd1498Szrj hash_map<tree, tree> &shadow_vars_mapping)
333938fd1498Szrj {
334038fd1498Szrj tree *slot = shadow_vars_mapping.get (var_decl);
334138fd1498Szrj if (slot == NULL)
334238fd1498Szrj {
334338fd1498Szrj tree shadow_var = copy_node (var_decl);
334438fd1498Szrj
334538fd1498Szrj copy_body_data id;
334638fd1498Szrj memset (&id, 0, sizeof (copy_body_data));
334738fd1498Szrj id.src_fn = id.dst_fn = current_function_decl;
334838fd1498Szrj copy_decl_for_dup_finish (&id, var_decl, shadow_var);
334938fd1498Szrj
335038fd1498Szrj DECL_ARTIFICIAL (shadow_var) = 1;
335138fd1498Szrj DECL_IGNORED_P (shadow_var) = 1;
335238fd1498Szrj DECL_SEEN_IN_BIND_EXPR_P (shadow_var) = 0;
335338fd1498Szrj gimple_add_tmp_var (shadow_var);
335438fd1498Szrj
335538fd1498Szrj shadow_vars_mapping.put (var_decl, shadow_var);
335638fd1498Szrj return shadow_var;
335738fd1498Szrj }
335838fd1498Szrj else
335938fd1498Szrj return *slot;
336038fd1498Szrj }
336138fd1498Szrj
336238fd1498Szrj /* Expand ASAN_POISON ifn. */
336338fd1498Szrj
336438fd1498Szrj bool
asan_expand_poison_ifn(gimple_stmt_iterator * iter,bool * need_commit_edge_insert,hash_map<tree,tree> & shadow_vars_mapping)336538fd1498Szrj asan_expand_poison_ifn (gimple_stmt_iterator *iter,
336638fd1498Szrj bool *need_commit_edge_insert,
336738fd1498Szrj hash_map<tree, tree> &shadow_vars_mapping)
336838fd1498Szrj {
336938fd1498Szrj gimple *g = gsi_stmt (*iter);
337038fd1498Szrj tree poisoned_var = gimple_call_lhs (g);
337138fd1498Szrj if (!poisoned_var || has_zero_uses (poisoned_var))
337238fd1498Szrj {
337338fd1498Szrj gsi_remove (iter, true);
337438fd1498Szrj return true;
337538fd1498Szrj }
337638fd1498Szrj
337738fd1498Szrj if (SSA_NAME_VAR (poisoned_var) == NULL_TREE)
337838fd1498Szrj SET_SSA_NAME_VAR_OR_IDENTIFIER (poisoned_var,
337938fd1498Szrj create_tmp_var (TREE_TYPE (poisoned_var)));
338038fd1498Szrj
338138fd1498Szrj tree shadow_var = create_asan_shadow_var (SSA_NAME_VAR (poisoned_var),
338238fd1498Szrj shadow_vars_mapping);
338338fd1498Szrj
338438fd1498Szrj bool recover_p;
338538fd1498Szrj if (flag_sanitize & SANITIZE_USER_ADDRESS)
338638fd1498Szrj recover_p = (flag_sanitize_recover & SANITIZE_USER_ADDRESS) != 0;
338738fd1498Szrj else
338838fd1498Szrj recover_p = (flag_sanitize_recover & SANITIZE_KERNEL_ADDRESS) != 0;
338938fd1498Szrj tree size = DECL_SIZE_UNIT (shadow_var);
339038fd1498Szrj gimple *poison_call
339138fd1498Szrj = gimple_build_call_internal (IFN_ASAN_MARK, 3,
339238fd1498Szrj build_int_cst (integer_type_node,
339338fd1498Szrj ASAN_MARK_POISON),
339438fd1498Szrj build_fold_addr_expr (shadow_var), size);
339538fd1498Szrj
339638fd1498Szrj gimple *use;
339738fd1498Szrj imm_use_iterator imm_iter;
339838fd1498Szrj FOR_EACH_IMM_USE_STMT (use, imm_iter, poisoned_var)
339938fd1498Szrj {
340038fd1498Szrj if (is_gimple_debug (use))
340138fd1498Szrj continue;
340238fd1498Szrj
340338fd1498Szrj int nargs;
340438fd1498Szrj bool store_p = gimple_call_internal_p (use, IFN_ASAN_POISON_USE);
340538fd1498Szrj tree fun = report_error_func (store_p, recover_p, tree_to_uhwi (size),
340638fd1498Szrj &nargs);
340738fd1498Szrj
340838fd1498Szrj gcall *call = gimple_build_call (fun, 1,
340938fd1498Szrj build_fold_addr_expr (shadow_var));
341038fd1498Szrj gimple_set_location (call, gimple_location (use));
341138fd1498Szrj gimple *call_to_insert = call;
341238fd1498Szrj
341338fd1498Szrj /* The USE can be a gimple PHI node. If so, insert the call on
341438fd1498Szrj all edges leading to the PHI node. */
341538fd1498Szrj if (is_a <gphi *> (use))
341638fd1498Szrj {
341738fd1498Szrj gphi *phi = dyn_cast<gphi *> (use);
341838fd1498Szrj for (unsigned i = 0; i < gimple_phi_num_args (phi); ++i)
341938fd1498Szrj if (gimple_phi_arg_def (phi, i) == poisoned_var)
342038fd1498Szrj {
342138fd1498Szrj edge e = gimple_phi_arg_edge (phi, i);
342238fd1498Szrj
342338fd1498Szrj /* Do not insert on an edge we can't split. */
342438fd1498Szrj if (e->flags & EDGE_ABNORMAL)
342538fd1498Szrj continue;
342638fd1498Szrj
342738fd1498Szrj if (call_to_insert == NULL)
342838fd1498Szrj call_to_insert = gimple_copy (call);
342938fd1498Szrj
343038fd1498Szrj gsi_insert_seq_on_edge (e, call_to_insert);
343138fd1498Szrj *need_commit_edge_insert = true;
343238fd1498Szrj call_to_insert = NULL;
343338fd1498Szrj }
343438fd1498Szrj }
343538fd1498Szrj else
343638fd1498Szrj {
343738fd1498Szrj gimple_stmt_iterator gsi = gsi_for_stmt (use);
343838fd1498Szrj if (store_p)
343938fd1498Szrj gsi_replace (&gsi, call, true);
344038fd1498Szrj else
344138fd1498Szrj gsi_insert_before (&gsi, call, GSI_NEW_STMT);
344238fd1498Szrj }
344338fd1498Szrj }
344438fd1498Szrj
344538fd1498Szrj SSA_NAME_IS_DEFAULT_DEF (poisoned_var) = true;
344638fd1498Szrj SSA_NAME_DEF_STMT (poisoned_var) = gimple_build_nop ();
344738fd1498Szrj gsi_replace (iter, poison_call, false);
344838fd1498Szrj
344938fd1498Szrj return true;
345038fd1498Szrj }
345138fd1498Szrj
345238fd1498Szrj /* Instrument the current function. */
345338fd1498Szrj
345438fd1498Szrj static unsigned int
asan_instrument(void)345538fd1498Szrj asan_instrument (void)
345638fd1498Szrj {
345738fd1498Szrj if (shadow_ptr_types[0] == NULL_TREE)
345838fd1498Szrj asan_init_shadow_ptr_types ();
345938fd1498Szrj transform_statements ();
346038fd1498Szrj last_alloca_addr = NULL_TREE;
346138fd1498Szrj return 0;
346238fd1498Szrj }
346338fd1498Szrj
346438fd1498Szrj static bool
gate_asan(void)346538fd1498Szrj gate_asan (void)
346638fd1498Szrj {
346738fd1498Szrj return sanitize_flags_p (SANITIZE_ADDRESS);
346838fd1498Szrj }
346938fd1498Szrj
347038fd1498Szrj namespace {
347138fd1498Szrj
347238fd1498Szrj const pass_data pass_data_asan =
347338fd1498Szrj {
347438fd1498Szrj GIMPLE_PASS, /* type */
347538fd1498Szrj "asan", /* name */
347638fd1498Szrj OPTGROUP_NONE, /* optinfo_flags */
347738fd1498Szrj TV_NONE, /* tv_id */
347838fd1498Szrj ( PROP_ssa | PROP_cfg | PROP_gimple_leh ), /* properties_required */
347938fd1498Szrj 0, /* properties_provided */
348038fd1498Szrj 0, /* properties_destroyed */
348138fd1498Szrj 0, /* todo_flags_start */
348238fd1498Szrj TODO_update_ssa, /* todo_flags_finish */
348338fd1498Szrj };
348438fd1498Szrj
348538fd1498Szrj class pass_asan : public gimple_opt_pass
348638fd1498Szrj {
348738fd1498Szrj public:
pass_asan(gcc::context * ctxt)348838fd1498Szrj pass_asan (gcc::context *ctxt)
348938fd1498Szrj : gimple_opt_pass (pass_data_asan, ctxt)
349038fd1498Szrj {}
349138fd1498Szrj
349238fd1498Szrj /* opt_pass methods: */
clone()349338fd1498Szrj opt_pass * clone () { return new pass_asan (m_ctxt); }
gate(function *)349438fd1498Szrj virtual bool gate (function *) { return gate_asan (); }
execute(function *)349538fd1498Szrj virtual unsigned int execute (function *) { return asan_instrument (); }
349638fd1498Szrj
349738fd1498Szrj }; // class pass_asan
349838fd1498Szrj
349938fd1498Szrj } // anon namespace
350038fd1498Szrj
350138fd1498Szrj gimple_opt_pass *
make_pass_asan(gcc::context * ctxt)350238fd1498Szrj make_pass_asan (gcc::context *ctxt)
350338fd1498Szrj {
350438fd1498Szrj return new pass_asan (ctxt);
350538fd1498Szrj }
350638fd1498Szrj
350738fd1498Szrj namespace {
350838fd1498Szrj
350938fd1498Szrj const pass_data pass_data_asan_O0 =
351038fd1498Szrj {
351138fd1498Szrj GIMPLE_PASS, /* type */
351238fd1498Szrj "asan0", /* name */
351338fd1498Szrj OPTGROUP_NONE, /* optinfo_flags */
351438fd1498Szrj TV_NONE, /* tv_id */
351538fd1498Szrj ( PROP_ssa | PROP_cfg | PROP_gimple_leh ), /* properties_required */
351638fd1498Szrj 0, /* properties_provided */
351738fd1498Szrj 0, /* properties_destroyed */
351838fd1498Szrj 0, /* todo_flags_start */
351938fd1498Szrj TODO_update_ssa, /* todo_flags_finish */
352038fd1498Szrj };
352138fd1498Szrj
352238fd1498Szrj class pass_asan_O0 : public gimple_opt_pass
352338fd1498Szrj {
352438fd1498Szrj public:
pass_asan_O0(gcc::context * ctxt)352538fd1498Szrj pass_asan_O0 (gcc::context *ctxt)
352638fd1498Szrj : gimple_opt_pass (pass_data_asan_O0, ctxt)
352738fd1498Szrj {}
352838fd1498Szrj
352938fd1498Szrj /* opt_pass methods: */
gate(function *)353038fd1498Szrj virtual bool gate (function *) { return !optimize && gate_asan (); }
execute(function *)353138fd1498Szrj virtual unsigned int execute (function *) { return asan_instrument (); }
353238fd1498Szrj
353338fd1498Szrj }; // class pass_asan_O0
353438fd1498Szrj
353538fd1498Szrj } // anon namespace
353638fd1498Szrj
353738fd1498Szrj gimple_opt_pass *
make_pass_asan_O0(gcc::context * ctxt)353838fd1498Szrj make_pass_asan_O0 (gcc::context *ctxt)
353938fd1498Szrj {
354038fd1498Szrj return new pass_asan_O0 (ctxt);
354138fd1498Szrj }
354238fd1498Szrj
354338fd1498Szrj #include "gt-asan.h"
3544