* gcc.dg/guality/guality.h: Include stdint.h. Drop unnecessary
[official-gcc.git] / gcc / testsuite / gcc.dg / guality / guality.h
blobeec0ab6bedf78bc9abf70adfd67a6d2faabfb9ed
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>.
5 This file is part of GCC.
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.
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.
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/>. */
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdint.h>
26 /* This is a first cut at checking that debug information matches
27 run-time. The idea is to annotate programs with GUALCHK* macros
28 that guide the tests.
30 In the current implementation, all of the macros expand to function
31 calls. On the one hand, this interferes with optimizations; on the
32 other hand, it establishes an optimization barrier and a clear
33 inspection point, where previous operations (as in the abstract
34 machine) should have been completed and have their effects visible,
35 and future operations shouldn't have started yet.
37 In the current implementation of guality_check(), we fork a child
38 process that runs gdb, attaches to the parent process (the one that
39 called guality_check), moves up one stack frame (to the caller of
40 guality_check) and then examines the given expression.
42 If it matches the expected value, we have a PASS. If it differs,
43 we have a FAILure. If it is missing, we'll have a FAIL or an
44 UNRESOLVED depending on whether the variable or expression might be
45 unavailable at that point, as indicated by the third argument.
47 We envision a future alternate implementation with two compilation
48 and execution cycles, say one that runs the program and uses the
49 macros to log expressions and expected values, another in which the
50 macros expand to nothing and the logs are used to guide a debug
51 session that tests the values. How to identify the inspection
52 points in the second case is yet to be determined. It is
53 recommended that GUALCHK* macros be by themselves in source lines,
54 so that __FILE__ and __LINE__ will be usable to identify them.
57 /* This is the type we use to pass values to guality_check. */
59 typedef intmax_t gualchk_t;
61 /* Convert a pointer or integral type to the widest integral type,
62 as expected by guality_check. */
64 #define GUALCVT(val) \
65 ((gualchk_t)__builtin_choose_expr \
66 (__builtin_types_compatible_p (__typeof (val), gualchk_t), \
67 (val), (intptr_t)(val)))
69 /* Attach a debugger to the current process and verify that the string
70 EXPR, evaluated by the debugger, yields the gualchk_t number VAL.
71 If the debugger cannot compute the expression, say because the
72 variable is unavailable, this will count as an error, unless unkok
73 is nonzero. */
75 #define GUALCHKXPRVAL(expr, val, unkok) \
76 guality_check ((expr), (val), (unkok))
78 /* Check that a debugger knows that EXPR evaluates to the run-time
79 value of EXPR. Unknown values are marked as acceptable,
80 considering that EXPR may die right after this call. This will
81 affect the generated code in that EXPR will be evaluated and forced
82 to remain live at least until right before the call to
83 guality_check, although not necessarily after the call. */
85 #define GUALCHKXPR(expr) \
86 GUALCHKXPRVAL (#expr, GUALCVT (expr), 1)
88 /* Same as GUALCHKXPR, but issue an error if the variable is optimized
89 away. */
91 #define GUALCHKVAL(expr) \
92 GUALCHKXPRVAL (#expr, GUALCVT (expr), 0)
94 /* Check that a debugger knows that EXPR evaluates to the run-time
95 value of EXPR. Unknown values are marked as errors, because the
96 value of EXPR is forced to be available right after the call, for a
97 range of at least one instruction. This will affect the generated
98 code, in that EXPR *will* be evaluated before and preserved until
99 after the call to guality_check. */
101 #define GUALCHKFLA(expr) do { \
102 __typeof(expr) volatile __preserve_after; \
103 __typeof(expr) __preserve_before = (expr); \
104 GUALCHKXPRVAL (#expr, GUALCVT (__preserve_before), 0); \
105 __preserve_after = __preserve_before; \
106 asm ("" : : "m" (__preserve_after)); \
107 } while (0)
109 /* GUALCHK is the simplest way to assert that debug information for an
110 expression matches its run-time value. Whether to force the
111 expression live after the call, so as to flag incompleteness
112 errors, can be disabled by defining GUALITY_DONT_FORCE_LIVE_AFTER.
113 Setting it to -1, an error is issued for optimized out variables,
114 even though they are not forced live. */
116 #if ! GUALITY_DONT_FORCE_LIVE_AFTER
117 #define GUALCHK(var) GUALCHKFLA(var)
118 #elif GUALITY_DONT_FORCE_LIVE_AFTER < 0
119 #define GUALCHK(var) GUALCHKVAL(var)
120 #else
121 #define GUALCHK(var) GUALCHKXPR(var)
122 #endif
124 /* The name of the GDB program, with arguments to make it quiet. This
125 is GUALITY_GDB_DEFAULT GUALITY_GDB_ARGS by default, but it can be
126 overridden by setting the GUALITY_GDB environment variable, whereas
127 GUALITY_GDB_DEFAULT can be overridden by setting the
128 GUALITY_GDB_NAME environment variable. */
130 static const char *guality_gdb_command;
131 #define GUALITY_GDB_DEFAULT "gdb"
132 #if defined(__unix)
133 # define GUALITY_GDB_REDIRECT " > /dev/null 2>&1"
134 #elif defined (_WIN32) || defined (MSDOS)
135 # define GUALITY_GDB_REDIRECT " > nul"
136 #else
137 # define GUALITY_GDB_REDRECT ""
138 #endif
139 #define GUALITY_GDB_ARGS " -nx -nw --quiet" GUALITY_GDB_REDIRECT
141 /* Kinds of results communicated as exit status from child process
142 that runs gdb to the parent process that's being monitored. */
144 enum guality_counter { PASS, INCORRECT, INCOMPLETE };
146 /* Count of passes and errors. */
148 static int guality_count[INCOMPLETE+1];
150 /* If --guality-skip is given in the command line, all the monitoring,
151 forking and debugger-attaching action will be disabled. This is
152 useful to run the monitor program within a debugger. */
154 static int guality_skip;
156 /* This is a file descriptor to which we'll issue gdb commands to
157 probe and test. */
158 FILE *guality_gdb_input;
160 /* This holds the line number where we're supposed to set a
161 breakpoint. */
162 int guality_breakpoint_line;
164 /* GDB should set this to true once it's connected. */
165 int volatile guality_attached;
167 /* This function is the main guality program. It may actually be
168 defined as main, because we #define main to it afterwards. Because
169 of this wrapping, guality_main may not have an empty argument
170 list. */
172 extern int guality_main (int argc, char *argv[]);
174 static void __attribute__((noinline))
175 guality_check (const char *name, gualchk_t value, int unknown_ok);
177 /* Set things up, run guality_main, then print a summary and quit. */
180 main (int argc, char *argv[])
182 int i;
183 char *argv0 = argv[0];
185 guality_gdb_command = getenv ("GUALITY_GDB");
186 if (!guality_gdb_command)
188 guality_gdb_command = getenv ("GUALITY_GDB_NAME");
189 if (!guality_gdb_command)
190 guality_gdb_command = GUALITY_GDB_DEFAULT GUALITY_GDB_ARGS;
191 else
193 int len = strlen (guality_gdb_command) + sizeof (GUALITY_GDB_ARGS);
194 char *buf = __builtin_alloca (len);
195 strcpy (buf, guality_gdb_command);
196 strcat (buf, GUALITY_GDB_ARGS);
197 guality_gdb_command = buf;
201 for (i = 1; i < argc; i++)
202 if (strcmp (argv[i], "--guality-skip") == 0)
203 guality_skip = 1;
204 else
205 break;
207 if (!guality_skip)
209 guality_gdb_input = popen (guality_gdb_command, "w");
210 /* This call sets guality_breakpoint_line. */
211 guality_check (NULL, 0, 0);
212 if (!guality_gdb_input
213 || fprintf (guality_gdb_input, "\
214 set height 0\n\
215 attach %i\n\
216 set guality_attached = 1\n\
217 b %i\n\
218 continue\n\
219 ", (int)getpid (), guality_breakpoint_line) <= 0
220 || fflush (guality_gdb_input))
222 perror ("gdb");
223 abort ();
227 argv[--i] = argv0;
229 guality_main (argc - i, argv + i);
231 i = guality_count[INCORRECT];
233 fprintf (stderr, "%s: %i PASS, %i FAIL, %i UNRESOLVED\n",
234 i ? "FAIL" : "PASS",
235 guality_count[PASS], guality_count[INCORRECT],
236 guality_count[INCOMPLETE]);
238 return i;
241 #define main guality_main
243 /* Tell the GDB child process to evaluate NAME in the caller. If it
244 matches VALUE, we have a PASS; if it's unknown and UNKNOWN_OK, we
245 have an UNRESOLVED. Otherwise, it's a FAIL. */
247 static void __attribute__((noinline))
248 guality_check (const char *name, gualchk_t value, int unknown_ok)
250 int result;
252 if (guality_skip)
253 return;
256 volatile gualchk_t xvalue = -1;
257 volatile int unavailable = 0;
258 if (name)
260 /* The sequence below cannot distinguish an optimized away
261 variable from one mapped to a non-lvalue zero. */
262 if (fprintf (guality_gdb_input, "\
263 up\n\
264 set $value1 = 0\n\
265 set $value1 = (%s)\n\
266 set $value2 = -1\n\
267 set $value2 = (%s)\n\
268 set $value3 = $value1 - 1\n\
269 set $value4 = $value1 + 1\n\
270 set $value3 = (%s)++\n\
271 set $value4 = --(%s)\n\
272 down\n\
273 set xvalue = $value1\n\
274 set unavailable = $value1 != $value2 ? -1 : $value3 != $value4 ? 1 : 0\n\
275 continue\n\
276 ", name, name, name, name) <= 0
277 || fflush (guality_gdb_input))
279 perror ("gdb");
280 abort ();
282 else if (!guality_attached)
284 unsigned int timeout = 0;
286 /* Give GDB some more time to attach. Wrapping around a
287 32-bit counter takes some seconds, it should be plenty
288 of time for GDB to get a chance to start up and attach,
289 but not long enough that, if GDB is unavailable or
290 broken, we'll take far too long to give up. */
291 while (--timeout && !guality_attached)
293 if (!timeout && !guality_attached)
295 fprintf (stderr, "gdb: took too long to attach\n");
296 abort ();
300 else
302 guality_breakpoint_line = __LINE__ + 5;
303 return;
305 /* Do NOT add lines between the __LINE__ above and the line below,
306 without also adjusting the added constant to match. */
307 if (!unavailable || (unavailable > 0 && xvalue))
309 if (xvalue == value)
310 result = PASS;
311 else
312 result = INCORRECT;
314 else
315 result = INCOMPLETE;
316 asm ("" : : "X" (name), "X" (value), "X" (unknown_ok), "m" (xvalue));
317 switch (result)
319 case PASS:
320 fprintf (stderr, "PASS: %s is %lli\n", name, value);
321 break;
322 case INCORRECT:
323 fprintf (stderr, "FAIL: %s is %lli, not %lli\n", name, xvalue, value);
324 break;
325 case INCOMPLETE:
326 fprintf (stderr, "%s: %s is %s, expected %lli\n",
327 unknown_ok ? "UNRESOLVED" : "FAIL", name,
328 unavailable < 0 ? "not computable" : "optimized away", value);
329 result = unknown_ok ? INCOMPLETE : INCORRECT;
330 break;
331 default:
332 abort ();
336 switch (result)
338 case PASS:
339 case INCORRECT:
340 case INCOMPLETE:
341 ++guality_count[result];
342 break;
344 default:
345 abort ();