1# Copyright (C) 2020-2021 Free Software Foundation, Inc.
2
3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; either version 3 of the License, or
6# (at your option) any later version.
7#
8# This program is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11# GNU General Public License for more details.
12#
13# You should have received a copy of the GNU General Public License
14# along with GCC; see the file COPYING3.  If not see
15# <http://www.gnu.org/licenses/>.
16
17load_lib asan-dg.exp
18
19# Return 1 if target can compile a binary for hardware address
20# sanitization, 0 otherwise.
21#
22# NOTE: This should only be used between calls to hwasan_init and
23# hwasan_finish.  It is therefore defined here rather than in
24# target-supports.exp.
25
26proc check_effective_target_fsanitize_hwaddress {} {
27    if ![check_no_compiler_messages fsanitize_hwaddress executable {
28	int main (void) { return 0; }
29    }] {
30	return 0;
31    }
32    return 1;
33}
34
35# Return 1 if target can compile and run a binary for hardware address
36# sanitization, 0 otherwise.
37#
38# NOTE: This should only be used between calls to hwasan_init and
39# hwasan_finish.  It is therefore defined here rather than in
40# target-supports.exp.
41
42proc check_effective_target_hwaddress_exec {} {
43    if ![check_runtime hwaddress_exec {
44	#ifdef __cplusplus
45	extern "C" {
46	#endif
47	extern int prctl(int, unsigned long, unsigned long, unsigned long, unsigned long);
48	#ifdef __cplusplus
49	}
50	#endif
51	int main (void) {
52	#define PR_SET_TAGGED_ADDR_CTRL 55
53	#define PR_GET_TAGGED_ADDR_CTRL 56
54	#define PR_TAGGED_ADDR_ENABLE (1UL << 0)
55	  if (prctl (PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0) == -1)
56	    return 1;
57	  if (prctl(PR_SET_TAGGED_ADDR_CTRL, PR_TAGGED_ADDR_ENABLE, 0, 0, 0) == -1
58	      || !prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0))
59	    return 1;
60	  return 0;
61	}
62    }] {
63	return 0;
64    }
65    return 1;
66}
67
68proc hwasan_include_flags {} {
69    global srcdir
70    global TESTING_IN_BUILD_TREE
71
72    set flags ""
73
74    if { [is_remote host] || ! [info exists TESTING_IN_BUILD_TREE] } {
75      return "${flags}"
76    }
77
78    set flags "-I$srcdir/../../libsanitizer/include"
79
80    return "$flags"
81}
82
83#
84# hwasan_link_flags -- compute library path and flags to find libhwasan.
85# (implementation in asan-dg.exp)
86#
87
88proc hwasan_link_flags { paths } {
89    return [asan_link_flags_1 $paths hwasan]
90}
91
92#
93# hwasan_init -- called at the start of each subdir of tests
94#
95
96proc hwasan_init { args } {
97    global TEST_ALWAYS_FLAGS
98    global ALWAYS_CXXFLAGS
99    global TOOL_OPTIONS
100    global hwasan_saved_TEST_ALWAYS_FLAGS
101    global hwasan_saved_ALWAYS_CXXFLAGS
102
103    setenv HWASAN_OPTIONS "random_tags=0"
104
105    set link_flags ""
106    if ![is_remote host] {
107	if [info exists TOOL_OPTIONS] {
108	    set link_flags "[hwasan_link_flags [get_multilibs ${TOOL_OPTIONS}]]"
109	} else {
110	    set link_flags "[hwasan_link_flags [get_multilibs]]"
111	}
112    }
113
114    set include_flags "[hwasan_include_flags]"
115
116    if [info exists TEST_ALWAYS_FLAGS] {
117	set hwasan_saved_TEST_ALWAYS_FLAGS $TEST_ALWAYS_FLAGS
118    }
119    if [info exists ALWAYS_CXXFLAGS] {
120	set hwasan_saved_ALWAYS_CXXFLAGS $ALWAYS_CXXFLAGS
121	set ALWAYS_CXXFLAGS [concat "{ldflags=$link_flags}" $ALWAYS_CXXFLAGS]
122	set ALWAYS_CXXFLAGS [concat "{additional_flags=-fsanitize=hwaddress --param hwasan-random-frame-tag=0 -g $include_flags}" $ALWAYS_CXXFLAGS]
123    } else {
124	if [info exists TEST_ALWAYS_FLAGS] {
125	    set TEST_ALWAYS_FLAGS "$link_flags -fsanitize=hwaddress --param hwasan-random-frame-tag=0 -g $include_flags $TEST_ALWAYS_FLAGS"
126	} else {
127	    set TEST_ALWAYS_FLAGS "$link_flags -fsanitize=hwaddress --param hwasan-random-frame-tag=0 -g $include_flags"
128	}
129    }
130}
131
132#
133# hwasan_finish -- called at the start of each subdir of tests
134#
135
136proc hwasan_finish { args } {
137    global TEST_ALWAYS_FLAGS
138    global hwasan_saved_TEST_ALWAYS_FLAGS
139    global hwasan_saved_ALWAYS_CXXFLAGS
140    global hwasan_saved_library_path
141    global ld_library_path
142
143    unsetenv HWASAN_OPTIONS
144
145    if [info exists hwasan_saved_ALWAYS_CXXFLAGS ] {
146	set ALWAYS_CXXFLAGS $hwasan_saved_ALWAYS_CXXFLAGS
147    } else {
148	if [info exists hwasan_saved_TEST_ALWAYS_FLAGS] {
149	    set TEST_ALWAYS_FLAGS $hwasan_saved_TEST_ALWAYS_FLAGS
150	} else {
151	    unset TEST_ALWAYS_FLAGS
152	}
153    }
154    if [info exists hwasan_saved_library_path] {
155	set ld_library_path $hwasan_saved_library_path
156	set_ld_library_path_env_vars
157    }
158    clear_effective_target_cache
159}
160
161# Utility for running gtest hwasan emulation under dejagnu, invoked via dg-final.
162# Call pass if variable has the desired value, otherwise fail.
163#
164# Argument 0 handles expected failures and the like
165proc hwasan-gtest { args } {
166    asan-gtest {*}$args
167}
168