OSDN Git Service

* gcc.dg/guality/guality.h: Include stdint.h. Drop unnecessary
[pf3gnuchains/gcc-fork.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 <stdint.h>
25
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.
29
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.
36
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.
41
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.
46
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.
55 */
56
57 /* This is the type we use to pass values to guality_check.  */
58
59 typedef intmax_t gualchk_t;
60
61 /* Convert a pointer or integral type to the widest integral type,
62    as expected by guality_check.  */
63
64 #define GUALCVT(val)                                            \
65   ((gualchk_t)__builtin_choose_expr                             \
66    (__builtin_types_compatible_p (__typeof (val), gualchk_t),   \
67     (val), (intptr_t)(val)))
68
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.  */
74
75 #define GUALCHKXPRVAL(expr, val, unkok) \
76   guality_check ((expr), (val), (unkok))
77
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.  */
84
85 #define GUALCHKXPR(expr) \
86   GUALCHKXPRVAL (#expr, GUALCVT (expr), 1)
87
88 /* Same as GUALCHKXPR, but issue an error if the variable is optimized
89    away.  */
90
91 #define GUALCHKVAL(expr) \
92   GUALCHKXPRVAL (#expr, GUALCVT (expr), 0)
93
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.  */
100
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)
108
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.  */
115
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
123
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.  */
129
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
140
141 /* Kinds of results communicated as exit status from child process
142    that runs gdb to the parent process that's being monitored.  */
143
144 enum guality_counter { PASS, INCORRECT, INCOMPLETE };
145
146 /* Count of passes and errors.  */
147
148 static int guality_count[INCOMPLETE+1];
149
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.  */
153
154 static int guality_skip;
155
156 /* This is a file descriptor to which we'll issue gdb commands to
157    probe and test.  */
158 FILE *guality_gdb_input;
159
160 /* This holds the line number where we're supposed to set a
161    breakpoint.  */
162 int guality_breakpoint_line;
163
164 /* GDB should set this to true once it's connected.  */
165 int volatile guality_attached;
166
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.  */
171
172 extern int guality_main (int argc, char *argv[]);
173
174 static void __attribute__((noinline))
175 guality_check (const char *name, gualchk_t value, int unknown_ok);
176
177 /* Set things up, run guality_main, then print a summary and quit.  */
178
179 int
180 main (int argc, char *argv[])
181 {
182   int i;
183   char *argv0 = argv[0];
184
185   guality_gdb_command = getenv ("GUALITY_GDB");
186   if (!guality_gdb_command)
187     {
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
192         {
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;
198         }
199     }
200
201   for (i = 1; i < argc; i++)
202     if (strcmp (argv[i], "--guality-skip") == 0)
203       guality_skip = 1;
204     else
205       break;
206
207   if (!guality_skip)
208     {
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))
221         {
222           perror ("gdb");
223           abort ();
224         }
225     }
226
227   argv[--i] = argv0;
228
229   guality_main (argc - i, argv + i);
230
231   i = guality_count[INCORRECT];
232
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]);
237
238   return i;
239 }
240
241 #define main guality_main
242
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.  */
246
247 static void __attribute__((noinline))
248 guality_check (const char *name, gualchk_t value, int unknown_ok)
249 {
250   int result;
251
252   if (guality_skip)
253     return;
254
255   {
256     volatile gualchk_t xvalue = -1;
257     volatile int unavailable = 0;
258     if (name)
259       {
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))
278           {
279             perror ("gdb");
280             abort ();
281           }
282         else if (!guality_attached)
283           {
284             unsigned int timeout = 0;
285
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)
292               ;
293             if (!timeout && !guality_attached)
294               {
295                 fprintf (stderr, "gdb: took too long to attach\n");
296                 abort ();
297               }
298           }
299       }
300     else
301       {
302         guality_breakpoint_line = __LINE__ + 5;
303         return;
304       }
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))
308       {
309         if (xvalue == value)
310           result = PASS;
311         else
312           result = INCORRECT;
313       }
314     else
315       result = INCOMPLETE;
316     asm ("" : : "X" (name), "X" (value), "X" (unknown_ok), "m" (xvalue));
317     switch (result)
318       {
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 ();
333       }
334   }
335
336   switch (result)
337     {
338     case PASS:
339     case INCORRECT:
340     case INCOMPLETE:
341       ++guality_count[result];
342       break;
343
344     default:
345       abort ();
346     }
347 }