]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/testsuite/gcc.dg/guality/guality.h
invoke.texi (-fvar-tracking-assignments): New.
[thirdparty/gcc.git] / gcc / testsuite / gcc.dg / guality / guality.h
1 /* Infrastructure to test the quality of debug information.
2 Copyright (C) 2008, 2009 Free Software Foundation, Inc.
3 Contributed by Alexandre Oliva <aoliva@redhat.com>.
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11
12 GCC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <sys/types.h>
26 #include <sys/wait.h>
27
28 /* This is a first cut at checking that debug information matches
29 run-time. The idea is to annotate programs with GUALCHK* macros
30 that guide the tests.
31
32 In the current implementation, all of the macros expand to function
33 calls. On the one hand, this interferes with optimizations; on the
34 other hand, it establishes an optimization barrier and a clear
35 inspection point, where previous operations (as in the abstract
36 machine) should have been completed and have their effects visible,
37 and future operations shouldn't have started yet.
38
39 In the current implementation of guality_check(), we fork a child
40 process that runs gdb, attaches to the parent process (the one that
41 called guality_check), moves up one stack frame (to the caller of
42 guality_check) and then examines the given expression.
43
44 If it matches the expected value, we have a PASS. If it differs,
45 we have a FAILure. If it is missing, we'll have a FAIL or an
46 UNRESOLVED depending on whether the variable or expression might be
47 unavailable at that point, as indicated by the third argument.
48
49 We envision a future alternate implementation with two compilation
50 and execution cycles, say one that runs the program and uses the
51 macros to log expressions and expected values, another in which the
52 macros expand to nothing and the logs are used to guide a debug
53 session that tests the values. How to identify the inspection
54 points in the second case is yet to be determined. It is
55 recommended that GUALCHK* macros be by themselves in source lines,
56 so that __FILE__ and __LINE__ will be usable to identify them.
57 */
58
59 /* Attach a debugger to the current process and verify that the string
60 EXPR, evaluated by the debugger, yields the long long number VAL.
61 If the debugger cannot compute the expression, say because the
62 variable is unavailable, this will count as an error, unless unkok
63 is nonzero. */
64
65 #define GUALCHKXPRVAL(expr, val, unkok) \
66 guality_check ((expr), (val), (unkok))
67
68 /* Check that a debugger knows that EXPR evaluates to the run-time
69 value of EXPR. Unknown values are marked as acceptable,
70 considering that EXPR may die right after this call. This will
71 affect the generated code in that EXPR will be evaluated and forced
72 to remain live at least until right before the call to
73 guality_check, although not necessarily after the call. */
74
75 #define GUALCHKXPR(expr) \
76 GUALCHKXPRVAL (#expr, (long long)(expr), 1)
77
78 /* Same as GUALCHKXPR, but issue an error if the variable is optimized
79 away. */
80
81 #define GUALCHKVAL(expr) \
82 GUALCHKXPRVAL (#expr, (long long)(expr), 0)
83
84 /* Check that a debugger knows that EXPR evaluates to the run-time
85 value of EXPR. Unknown values are marked as errors, because the
86 value of EXPR is forced to be available right after the call, for a
87 range of at least one instruction. This will affect the generated
88 code, in that EXPR *will* be evaluated before and preserved until
89 after the call to guality_check. */
90
91 #define GUALCHKFLA(expr) do { \
92 __typeof(expr) volatile __preserve_after; \
93 __typeof(expr) __preserve_before = (expr); \
94 GUALCHKXPRVAL (#expr, (long long)(__preserve_before), 0); \
95 __preserve_after = __preserve_before; \
96 asm ("" : : "m" (__preserve_after)); \
97 } while (0)
98
99 /* GUALCHK is the simplest way to assert that debug information for an
100 expression matches its run-time value. Whether to force the
101 expression live after the call, so as to flag incompleteness
102 errors, can be disabled by defining GUALITY_DONT_FORCE_LIVE_AFTER.
103 Setting it to -1, an error is issued for optimized out variables,
104 even though they are not forced live. */
105
106 #if ! GUALITY_DONT_FORCE_LIVE_AFTER
107 #define GUALCHK(var) GUALCHKFLA(var)
108 #elif GUALITY_DONT_FORCE_LIVE_AFTER < 0
109 #define GUALCHK(var) GUALCHKVAL(var)
110 #else
111 #define GUALCHK(var) GUALCHKXPR(var)
112 #endif
113
114 /* The name of the GDB program, with arguments to make it quiet. This
115 is GUALITY_GDB_DEFAULT GUALITY_GDB_ARGS by default, but it can be
116 overridden by setting the GUALITY_GDB environment variable, whereas
117 GUALITY_GDB_DEFAULT can be overridden by setting the
118 GUALITY_GDB_NAME environment variable. */
119
120 static const char *guality_gdb_command;
121 #define GUALITY_GDB_DEFAULT "gdb"
122 #define GUALITY_GDB_ARGS " -nx -nw --quiet > /dev/null 2>&1"
123
124 /* Kinds of results communicated as exit status from child process
125 that runs gdb to the parent process that's being monitored. */
126
127 enum guality_counter { PASS, INCORRECT, INCOMPLETE };
128
129 /* Count of passes and errors. */
130
131 static int guality_count[INCOMPLETE+1];
132
133 /* If --guality-skip is given in the command line, all the monitoring,
134 forking and debugger-attaching action will be disabled. This is
135 useful to run the monitor program within a debugger. */
136
137 static int guality_skip;
138
139 /* This is a file descriptor to which we'll issue gdb commands to
140 probe and test. */
141 FILE *guality_gdb_input;
142
143 /* This holds the line number where we're supposed to set a
144 breakpoint. */
145 int guality_breakpoint_line;
146
147 /* GDB should set this to true once it's connected. */
148 int volatile guality_attached;
149
150 /* This function is the main guality program. It may actually be
151 defined as main, because we #define main to it afterwards. Because
152 of this wrapping, guality_main may not have an empty argument
153 list. */
154
155 extern int guality_main (int argc, char *argv[]);
156
157 static void __attribute__((noinline))
158 guality_check (const char *name, long long value, int unknown_ok);
159
160 /* Set things up, run guality_main, then print a summary and quit. */
161
162 int
163 main (int argc, char *argv[])
164 {
165 int i;
166 char *argv0 = argv[0];
167
168 guality_gdb_command = getenv ("GUALITY_GDB");
169 if (!guality_gdb_command)
170 {
171 guality_gdb_command = getenv ("GUALITY_GDB_NAME");
172 if (!guality_gdb_command)
173 guality_gdb_command = GUALITY_GDB_DEFAULT GUALITY_GDB_ARGS;
174 else
175 {
176 int len = strlen (guality_gdb_command) + sizeof (GUALITY_GDB_ARGS);
177 char *buf = __builtin_alloca (len);
178 strcpy (buf, guality_gdb_command);
179 strcat (buf, GUALITY_GDB_ARGS);
180 guality_gdb_command = buf;
181 }
182 }
183
184 for (i = 1; i < argc; i++)
185 if (strcmp (argv[i], "--guality-skip") == 0)
186 guality_skip = 1;
187 else
188 break;
189
190 if (!guality_skip)
191 {
192 guality_gdb_input = popen (guality_gdb_command, "w");
193 /* This call sets guality_breakpoint_line. */
194 guality_check (NULL, 0, 0);
195 if (!guality_gdb_input
196 || fprintf (guality_gdb_input, "\
197 set height 0\n\
198 attach %i\n\
199 set guality_attached = 1\n\
200 b %i\n\
201 continue\n\
202 ", (int)getpid (), guality_breakpoint_line) <= 0
203 || fflush (guality_gdb_input))
204 {
205 perror ("gdb");
206 abort ();
207 }
208 }
209
210 argv[--i] = argv0;
211
212 guality_main (argc - i, argv + i);
213
214 i = guality_count[INCORRECT];
215
216 fprintf (stderr, "%s: %i PASS, %i FAIL, %i UNRESOLVED\n",
217 i ? "FAIL" : "PASS",
218 guality_count[PASS], guality_count[INCORRECT],
219 guality_count[INCOMPLETE]);
220
221 return i;
222 }
223
224 #define main guality_main
225
226 /* Tell the GDB child process to evaluate NAME in the caller. If it
227 matches VALUE, we have a PASS; if it's unknown and UNKNOWN_OK, we
228 have an UNRESOLVED. Otherwise, it's a FAIL. */
229
230 static void __attribute__((noinline))
231 guality_check (const char *name, long long value, int unknown_ok)
232 {
233 int result;
234
235 if (guality_skip)
236 return;
237
238 {
239 volatile long long xvalue = -1;
240 volatile int unavailable = 0;
241 if (name)
242 {
243 /* The sequence below cannot distinguish an optimized away
244 variable from one mapped to a non-lvalue zero. */
245 if (fprintf (guality_gdb_input, "\
246 up\n\
247 set $value1 = 0\n\
248 set $value1 = (%s)\n\
249 set $value2 = -1\n\
250 set $value2 = (%s)\n\
251 set $value3 = $value1 - 1\n\
252 set $value4 = $value1 + 1\n\
253 set $value3 = (%s)++\n\
254 set $value4 = --(%s)\n\
255 down\n\
256 set xvalue = $value1\n\
257 set unavailable = $value1 != $value2 ? -1 : $value3 != $value4 ? 1 : 0\n\
258 continue\n\
259 ", name, name, name, name) <= 0
260 || fflush (guality_gdb_input))
261 {
262 perror ("gdb");
263 abort ();
264 }
265 else if (!guality_attached)
266 {
267 unsigned int timeout = 0;
268
269 /* Give GDB some more time to attach. Wrapping around a
270 32-bit counter takes some seconds, it should be plenty
271 of time for GDB to get a chance to start up and attach,
272 but not long enough that, if GDB is unavailable or
273 broken, we'll take far too long to give up. */
274 while (--timeout && !guality_attached)
275 ;
276 if (!timeout && !guality_attached)
277 {
278 fprintf (stderr, "gdb: took too long to attach\n");
279 abort ();
280 }
281 }
282 }
283 else
284 {
285 guality_breakpoint_line = __LINE__ + 5;
286 return;
287 }
288 /* Do NOT add lines between the __LINE__ above and the line below,
289 without also adjusting the added constant to match. */
290 if (!unavailable || (unavailable > 0 && xvalue))
291 {
292 if (xvalue == value)
293 result = PASS;
294 else
295 result = INCORRECT;
296 }
297 else
298 result = INCOMPLETE;
299 asm ("" : : "X" (name), "X" (value), "X" (unknown_ok), "m" (xvalue));
300 switch (result)
301 {
302 case PASS:
303 fprintf (stderr, "PASS: %s is %lli\n", name, value);
304 break;
305 case INCORRECT:
306 fprintf (stderr, "FAIL: %s is %lli, not %lli\n", name, xvalue, value);
307 break;
308 case INCOMPLETE:
309 fprintf (stderr, "%s: %s is %s, expected %lli\n",
310 unknown_ok ? "UNRESOLVED" : "FAIL", name,
311 unavailable < 0 ? "not computable" : "optimized away", value);
312 result = unknown_ok ? INCOMPLETE : INCORRECT;
313 break;
314 default:
315 abort ();
316 }
317 }
318
319 switch (result)
320 {
321 case PASS:
322 case INCORRECT:
323 case INCOMPLETE:
324 ++guality_count[result];
325 break;
326
327 default:
328 abort ();
329 }
330 }