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)
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/>. */
26 /* This is a first cut at checking that debug information matches
27 run-time. The idea is to annotate programs with GUALCHK* macros
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
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
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)); \
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)
121 #define GUALCHK(var) GUALCHKXPR(var)
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"
133 # define GUALITY_GDB_REDIRECT " > /dev/null 2>&1"
134 #elif defined (_WIN32) || defined (MSDOS)
135 # define GUALITY_GDB_REDIRECT " > nul"
137 # define GUALITY_GDB_REDRECT ""
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
158 FILE *guality_gdb_input
;
160 /* This holds the line number where we're supposed to set a
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
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
[])
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
;
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)
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
, "\
216 set guality_attached = 1\n\
219 ", (int)getpid (), guality_breakpoint_line
) <= 0
220 || fflush (guality_gdb_input
))
229 guality_main (argc
- i
, argv
+ i
);
231 i
= guality_count
[INCORRECT
];
233 fprintf (stderr
, "%s: %i PASS, %i FAIL, %i UNRESOLVED\n",
235 guality_count
[PASS
], guality_count
[INCORRECT
],
236 guality_count
[INCOMPLETE
]);
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
)
256 volatile gualchk_t xvalue
= -1;
257 volatile int unavailable
= 0;
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
, "\
265 set $value1 = (%s)\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\
273 set xvalue = $value1\n\
274 set unavailable = $value1 != $value2 ? -1 : $value3 != $value4 ? 1 : 0\n\
276 ", name
, name
, name
, name
) <= 0
277 || fflush (guality_gdb_input
))
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");
302 guality_breakpoint_line
= __LINE__
+ 5;
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
))
316 asm ("" : : "X" (name
), "X" (value
), "X" (unknown_ok
), "m" (xvalue
));
320 fprintf (stderr
, "PASS: %s is %lli\n", name
, value
);
323 fprintf (stderr
, "FAIL: %s is %lli, not %lli\n", name
, xvalue
, value
);
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
;
341 ++guality_count
[result
];