comparison gcc/testsuite/gcc.dg/guality/guality.h @ 111:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents
children 84e7813d76e9
comparison
equal deleted inserted replaced
68:561a7518be6b 111:04ced10e8804
1 /* Infrastructure to test the quality of debug information.
2 Copyright (C) 2008, 2009, 2010 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 #include <unistd.h>
26
27 /* This is a first cut at checking that debug information matches
28 run-time. The idea is to annotate programs with GUALCHK* macros
29 that guide the tests.
30
31 In the current implementation, all of the macros expand to function
32 calls. On the one hand, this interferes with optimizations; on the
33 other hand, it establishes an optimization barrier and a clear
34 inspection point, where previous operations (as in the abstract
35 machine) should have been completed and have their effects visible,
36 and future operations shouldn't have started yet.
37
38 In the current implementation of guality_check(), we fork a child
39 process that runs gdb, attaches to the parent process (the one that
40 called guality_check), moves up one stack frame (to the caller of
41 guality_check) and then examines the given expression.
42
43 If it matches the expected value, we have a PASS. If it differs,
44 we have a FAILure. If it is missing, we'll have a FAIL or an
45 UNRESOLVED depending on whether the variable or expression might be
46 unavailable at that point, as indicated by the third argument.
47
48 We envision a future alternate implementation with two compilation
49 and execution cycles, say one that runs the program and uses the
50 macros to log expressions and expected values, another in which the
51 macros expand to nothing and the logs are used to guide a debug
52 session that tests the values. How to identify the inspection
53 points in the second case is yet to be determined. It is
54 recommended that GUALCHK* macros be by themselves in source lines,
55 so that __FILE__ and __LINE__ will be usable to identify them.
56 */
57
58 #define GUALITY_TEST "guality/guality.h"
59
60 /* This is the type we use to pass values to guality_check. */
61
62 typedef intmax_t gualchk_t;
63
64 /* Convert a pointer or integral type to the widest integral type,
65 as expected by guality_check. */
66
67 #ifndef __cplusplus
68 #define GUALCVT(val) \
69 ((gualchk_t)__builtin_choose_expr \
70 (__builtin_types_compatible_p (__typeof (val), gualchk_t), \
71 (val), \
72 __builtin_choose_expr \
73 (__builtin_classify_type (val) \
74 == __builtin_classify_type (&guality_skip), \
75 (uintptr_t)(val),(intptr_t)(val))))
76 #else
77 template <typename T>
78 inline __attribute__((always_inline)) gualchk_t
79 gualcvt (T *val)
80 {
81 return (uintptr_t) val;
82 }
83
84 template <typename T>
85 inline __attribute__((always_inline)) gualchk_t
86 gualcvt (T val)
87 {
88 return (intptr_t) val;
89 }
90
91 template <>
92 inline __attribute__((always_inline)) gualchk_t
93 gualcvt<gualchk_t> (gualchk_t val)
94 {
95 return val;
96 }
97
98 #define GUALCVT(val) gualcvt (val)
99 #endif
100
101 /* Attach a debugger to the current process and verify that the string
102 EXPR, evaluated by the debugger, yields the gualchk_t number VAL.
103 If the debugger cannot compute the expression, say because the
104 variable is unavailable, this will count as an error, unless unkok
105 is nonzero. */
106
107 #define GUALCHKXPRVAL(expr, val, unkok) \
108 guality_check ((expr), (val), (unkok))
109
110 /* Check that a debugger knows that EXPR evaluates to the run-time
111 value of EXPR. Unknown values are marked as acceptable,
112 considering that EXPR may die right after this call. This will
113 affect the generated code in that EXPR will be evaluated and forced
114 to remain live at least until right before the call to
115 guality_check, although not necessarily after the call. */
116
117 #define GUALCHKXPR(expr) \
118 GUALCHKXPRVAL (#expr, GUALCVT (expr), 1)
119
120 /* Same as GUALCHKXPR, but issue an error if the variable is optimized
121 away. */
122
123 #define GUALCHKVAL(expr) \
124 GUALCHKXPRVAL (#expr, GUALCVT (expr), 0)
125
126 /* Check that a debugger knows that EXPR evaluates to the run-time
127 value of EXPR. Unknown values are marked as errors, because the
128 value of EXPR is forced to be available right after the call, for a
129 range of at least one instruction. This will affect the generated
130 code, in that EXPR *will* be evaluated before and preserved until
131 after the call to guality_check. */
132
133 #define GUALCHKFLA(expr) do { \
134 __typeof(expr) volatile __preserve_after; \
135 __typeof(expr) __preserve_before = (expr); \
136 GUALCHKXPRVAL (#expr, GUALCVT (__preserve_before), 0); \
137 __preserve_after = __preserve_before; \
138 asm ("" : : "m" (__preserve_after)); \
139 } while (0)
140
141 /* GUALCHK is the simplest way to assert that debug information for an
142 expression matches its run-time value. Whether to force the
143 expression live after the call, so as to flag incompleteness
144 errors, can be disabled by defining GUALITY_DONT_FORCE_LIVE_AFTER.
145 Setting it to -1, an error is issued for optimized out variables,
146 even though they are not forced live. */
147
148 #if ! GUALITY_DONT_FORCE_LIVE_AFTER
149 #define GUALCHK(var) GUALCHKFLA(var)
150 #elif GUALITY_DONT_FORCE_LIVE_AFTER < 0
151 #define GUALCHK(var) GUALCHKVAL(var)
152 #else
153 #define GUALCHK(var) GUALCHKXPR(var)
154 #endif
155
156 /* The name of the GDB program, with arguments to make it quiet. This
157 is GUALITY_GDB_DEFAULT GUALITY_GDB_ARGS by default, but it can be
158 overridden by setting the GUALITY_GDB environment variable, whereas
159 GUALITY_GDB_DEFAULT can be overridden by setting the
160 GUALITY_GDB_NAME environment variable. */
161
162 static const char *guality_gdb_command;
163 #define GUALITY_GDB_DEFAULT "gdb"
164 #if defined(__unix)
165 # define GUALITY_GDB_REDIRECT " > /dev/null 2>&1"
166 #elif defined (_WIN32) || defined (MSDOS)
167 # define GUALITY_GDB_REDIRECT " > nul"
168 #else
169 # define GUALITY_GDB_REDIRECT ""
170 #endif
171 #define GUALITY_GDB_ARGS " -nx -nw --quiet" GUALITY_GDB_REDIRECT
172
173 /* Kinds of results communicated as exit status from child process
174 that runs gdb to the parent process that's being monitored. */
175
176 enum guality_counter { PASS, INCORRECT, INCOMPLETE };
177
178 /* Count of passes and errors. */
179
180 static int guality_count[INCOMPLETE+1];
181
182 /* If --guality-skip is given in the command line, all the monitoring,
183 forking and debugger-attaching action will be disabled. This is
184 useful to run the monitor program within a debugger. */
185
186 static int guality_skip;
187
188 /* This is a file descriptor to which we'll issue gdb commands to
189 probe and test. */
190 FILE *guality_gdb_input;
191
192 /* This holds the line number where we're supposed to set a
193 breakpoint. */
194 int guality_breakpoint_line;
195
196 /* GDB should set this to true once it's connected. */
197 int volatile guality_attached;
198
199 /* This function is the main guality program. It may actually be
200 defined as main, because we #define main to it afterwards. Because
201 of this wrapping, guality_main may not have an empty argument
202 list. */
203
204 extern int guality_main (int argc, char *argv[]);
205
206 static void __attribute__((noinline))
207 guality_check (const char *name, gualchk_t value, int unknown_ok);
208
209 /* Set things up, run guality_main, then print a summary and quit. */
210
211 int
212 main (int argc, char *argv[])
213 {
214 int i;
215 char *argv0 = argv[0];
216
217 guality_gdb_command = getenv ("GUALITY_GDB");
218 if (!guality_gdb_command)
219 {
220 guality_gdb_command = getenv ("GUALITY_GDB_NAME");
221 if (!guality_gdb_command)
222 guality_gdb_command = GUALITY_GDB_DEFAULT GUALITY_GDB_ARGS;
223 else
224 {
225 int len = strlen (guality_gdb_command) + sizeof (GUALITY_GDB_ARGS);
226 char *buf = (char *) __builtin_alloca (len);
227 strcpy (buf, guality_gdb_command);
228 strcat (buf, GUALITY_GDB_ARGS);
229 guality_gdb_command = buf;
230 }
231 }
232
233 if (argv[0])
234 {
235 int len = strlen (guality_gdb_command) + 1 + strlen (argv[0]);
236 char *buf = (char *) __builtin_alloca (len);
237 strcpy (buf, guality_gdb_command);
238 strcat (buf, " ");
239 strcat (buf, argv[0]);
240 guality_gdb_command = buf;
241 }
242
243 for (i = 1; i < argc; i++)
244 if (strcmp (argv[i], "--guality-skip") == 0)
245 guality_skip = 1;
246 else
247 break;
248
249 if (!guality_skip)
250 {
251 guality_gdb_input = popen (guality_gdb_command, "w");
252 /* This call sets guality_breakpoint_line. */
253 guality_check (NULL, 0, 0);
254 if (!guality_gdb_input
255 || fprintf (guality_gdb_input, "\
256 set height 0\n\
257 handle SIGINT pass nostop\n\
258 handle SIGTERM pass nostop\n\
259 handle SIGSEGV pass nostop\n\
260 handle SIGBUS pass nostop\n\
261 attach %i\n\
262 set guality_attached = 1\n\
263 b %i\n\
264 continue\n\
265 ", (int)getpid (), guality_breakpoint_line) <= 0
266 || fflush (guality_gdb_input))
267 {
268 perror ("gdb");
269 abort ();
270 }
271 }
272
273 argv[--i] = argv0;
274
275 guality_main (argc - i, argv + i);
276
277 i = guality_count[INCORRECT];
278
279 fprintf (stderr, "%s: " GUALITY_TEST ": %i PASS, %i FAIL, %i UNRESOLVED\n",
280 i ? "FAIL" : "PASS",
281 guality_count[PASS], guality_count[INCORRECT],
282 guality_count[INCOMPLETE]);
283
284 return i;
285 }
286
287 #define main guality_main
288
289 /* Tell the GDB child process to evaluate NAME in the caller. If it
290 matches VALUE, we have a PASS; if it's unknown and UNKNOWN_OK, we
291 have an UNRESOLVED. Otherwise, it's a FAIL. */
292
293 static void __attribute__((noinline))
294 guality_check (const char *name, gualchk_t value, int unknown_ok)
295 {
296 int result;
297
298 if (guality_skip)
299 return;
300
301 {
302 volatile gualchk_t xvalue = -1;
303 volatile int unavailable = 0;
304 if (name)
305 {
306 /* The sequence below cannot distinguish an optimized away
307 variable from one mapped to a non-lvalue zero. */
308 if (fprintf (guality_gdb_input, "\
309 up\n\
310 set $value1 = 0\n\
311 set $value1 = (%s)\n\
312 set $value2 = -1\n\
313 set $value2 = (%s)\n\
314 set $value3 = $value1 - 1\n\
315 set $value4 = $value1 + 1\n\
316 set $value3 = (%s)++\n\
317 set $value4 = --(%s)\n\
318 down\n\
319 set xvalue = $value1\n\
320 set unavailable = $value1 != $value2 ? -1 : $value3 != $value4 ? 1 : 0\n\
321 continue\n\
322 ", name, name, name, name) <= 0
323 || fflush (guality_gdb_input))
324 {
325 perror ("gdb");
326 abort ();
327 }
328 else if (!guality_attached)
329 {
330 unsigned int timeout = 0;
331
332 /* Give GDB some more time to attach. Wrapping around a
333 32-bit counter takes some seconds, it should be plenty
334 of time for GDB to get a chance to start up and attach,
335 but not long enough that, if GDB is unavailable or
336 broken, we'll take far too long to give up. */
337 while (--timeout && !guality_attached)
338 ;
339 if (!timeout && !guality_attached)
340 {
341 fprintf (stderr, "gdb: took too long to attach\n");
342 abort ();
343 }
344 }
345 }
346 else
347 {
348 guality_breakpoint_line = __LINE__ + 5;
349 return;
350 }
351 /* Do NOT add lines between the __LINE__ above and the line below,
352 without also adjusting the added constant to match. */
353 if (!unavailable || (unavailable > 0 && xvalue))
354 {
355 if (xvalue == value)
356 result = PASS;
357 else
358 result = INCORRECT;
359 }
360 else
361 result = INCOMPLETE;
362 asm ("" : : "X" (name), "X" (value), "X" (unknown_ok), "m" (xvalue));
363 switch (result)
364 {
365 case PASS:
366 fprintf (stderr, "PASS: " GUALITY_TEST ": %s is %lli\n", name, value);
367 break;
368 case INCORRECT:
369 fprintf (stderr, "FAIL: " GUALITY_TEST ": %s is %lli, not %lli\n", name, xvalue, value);
370 break;
371 case INCOMPLETE:
372 fprintf (stderr, "%s: " GUALITY_TEST ": %s is %s, expected %lli\n",
373 unknown_ok ? "UNRESOLVED" : "FAIL", name,
374 unavailable < 0 ? "not computable" : "optimized away", value);
375 result = unknown_ok ? INCOMPLETE : INCORRECT;
376 break;
377 default:
378 abort ();
379 }
380 }
381
382 switch (result)
383 {
384 case PASS:
385 case INCORRECT:
386 case INCOMPLETE:
387 ++guality_count[result];
388 break;
389
390 default:
391 abort ();
392 }
393 }