OSDN Git Service

6025da8b0282efbb935b697dcdd7b77d87c2a548
[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 <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 }