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/>. */
25 #include <sys/types.h>
28 /* This is a first cut at checking that debug information matches
29 run-time. The idea is to annotate programs with GUALCHK* macros
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.
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.
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.
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.
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
65 #define GUALCHKXPRVAL(expr, val, unkok) \
66 guality_check ((expr), (val), (unkok))
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. */
75 #define GUALCHKXPR(expr) \
76 GUALCHKXPRVAL (#expr, (long long)(expr), 1)
78 /* Same as GUALCHKXPR, but issue an error if the variable is optimized
81 #define GUALCHKVAL(expr) \
82 GUALCHKXPRVAL (#expr, (long long)(expr), 0)
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. */
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)); \
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. */
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)
111 #define GUALCHK(var) GUALCHKXPR(var)
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. */
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"
124 /* Kinds of results communicated as exit status from child process
125 that runs gdb to the parent process that's being monitored. */
127 enum guality_counter
{ PASS
, INCORRECT
, INCOMPLETE
};
129 /* Count of passes and errors. */
131 static int guality_count
[INCOMPLETE
+1];
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. */
137 static int guality_skip
;
139 /* This is a file descriptor to which we'll issue gdb commands to
141 FILE *guality_gdb_input
;
143 /* This holds the line number where we're supposed to set a
145 int guality_breakpoint_line
;
147 /* GDB should set this to true once it's connected. */
148 int volatile guality_attached
;
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
155 extern int guality_main (int argc
, char *argv
[]);
157 static void __attribute__((noinline
))
158 guality_check (const char *name
, long long value
, int unknown_ok
);
160 /* Set things up, run guality_main, then print a summary and quit. */
163 main (int argc
, char *argv
[])
166 char *argv0
= argv
[0];
168 guality_gdb_command
= getenv ("GUALITY_GDB");
169 if (!guality_gdb_command
)
171 guality_gdb_command
= getenv ("GUALITY_GDB_NAME");
172 if (!guality_gdb_command
)
173 guality_gdb_command
= GUALITY_GDB_DEFAULT GUALITY_GDB_ARGS
;
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
;
184 for (i
= 1; i
< argc
; i
++)
185 if (strcmp (argv
[i
], "--guality-skip") == 0)
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
, "\
199 set guality_attached = 1\n\
202 ", (int)getpid (), guality_breakpoint_line
) <= 0
203 || fflush (guality_gdb_input
))
212 guality_main (argc
- i
, argv
+ i
);
214 i
= guality_count
[INCORRECT
];
216 fprintf (stderr
, "%s: %i PASS, %i FAIL, %i UNRESOLVED\n",
218 guality_count
[PASS
], guality_count
[INCORRECT
],
219 guality_count
[INCOMPLETE
]);
224 #define main guality_main
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. */
230 static void __attribute__((noinline
))
231 guality_check (const char *name
, long long value
, int unknown_ok
)
239 volatile long long xvalue
= -1;
240 volatile int unavailable
= 0;
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
, "\
248 set $value1 = (%s)\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\
256 set xvalue = $value1\n\
257 set unavailable = $value1 != $value2 ? -1 : $value3 != $value4 ? 1 : 0\n\
259 ", name
, name
, name
, name
) <= 0
260 || fflush (guality_gdb_input
))
265 else if (!guality_attached
)
267 unsigned int timeout
= 0;
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
)
276 if (!timeout
&& !guality_attached
)
278 fprintf (stderr
, "gdb: took too long to attach\n");
285 guality_breakpoint_line
= __LINE__
+ 5;
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
))
299 asm ("" : : "X" (name
), "X" (value
), "X" (unknown_ok
), "m" (xvalue
));
303 fprintf (stderr
, "PASS: %s is %lli\n", name
, value
);
306 fprintf (stderr
, "FAIL: %s is %lli, not %lli\n", name
, xvalue
, value
);
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
;
324 ++guality_count
[result
];