OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-stable/] [gcc-4.5.1/] [gcc/] [testsuite/] [gcc.dg/] [guality/] [guality.h] - Blame information for rev 826

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 298 jeremybenn
/* 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),                                                      \
68
    __builtin_choose_expr                                       \
69
    (__builtin_classify_type (val)                              \
70
     == __builtin_classify_type (&guality_skip),                \
71
     (uintptr_t)(val),(intptr_t)(val))))
72
 
73
/* Attach a debugger to the current process and verify that the string
74
   EXPR, evaluated by the debugger, yields the gualchk_t number VAL.
75
   If the debugger cannot compute the expression, say because the
76
   variable is unavailable, this will count as an error, unless unkok
77
   is nonzero.  */
78
 
79
#define GUALCHKXPRVAL(expr, val, unkok) \
80
  guality_check ((expr), (val), (unkok))
81
 
82
/* Check that a debugger knows that EXPR evaluates to the run-time
83
   value of EXPR.  Unknown values are marked as acceptable,
84
   considering that EXPR may die right after this call.  This will
85
   affect the generated code in that EXPR will be evaluated and forced
86
   to remain live at least until right before the call to
87
   guality_check, although not necessarily after the call.  */
88
 
89
#define GUALCHKXPR(expr) \
90
  GUALCHKXPRVAL (#expr, GUALCVT (expr), 1)
91
 
92
/* Same as GUALCHKXPR, but issue an error if the variable is optimized
93
   away.  */
94
 
95
#define GUALCHKVAL(expr) \
96
  GUALCHKXPRVAL (#expr, GUALCVT (expr), 0)
97
 
98
/* Check that a debugger knows that EXPR evaluates to the run-time
99
   value of EXPR.  Unknown values are marked as errors, because the
100
   value of EXPR is forced to be available right after the call, for a
101
   range of at least one instruction.  This will affect the generated
102
   code, in that EXPR *will* be evaluated before and preserved until
103
   after the call to guality_check.  */
104
 
105
#define GUALCHKFLA(expr) do {                                   \
106
    __typeof(expr) volatile __preserve_after;                   \
107
    __typeof(expr) __preserve_before = (expr);                  \
108
    GUALCHKXPRVAL (#expr, GUALCVT (__preserve_before), 0);      \
109
    __preserve_after = __preserve_before;                       \
110
    asm ("" : : "m" (__preserve_after));                        \
111
  } while (0)
112
 
113
/* GUALCHK is the simplest way to assert that debug information for an
114
   expression matches its run-time value.  Whether to force the
115
   expression live after the call, so as to flag incompleteness
116
   errors, can be disabled by defining GUALITY_DONT_FORCE_LIVE_AFTER.
117
   Setting it to -1, an error is issued for optimized out variables,
118
   even though they are not forced live.  */
119
 
120
#if ! GUALITY_DONT_FORCE_LIVE_AFTER
121
#define GUALCHK(var) GUALCHKFLA(var)
122
#elif GUALITY_DONT_FORCE_LIVE_AFTER < 0
123
#define GUALCHK(var) GUALCHKVAL(var)
124
#else
125
#define GUALCHK(var) GUALCHKXPR(var)
126
#endif
127
 
128
/* The name of the GDB program, with arguments to make it quiet.  This
129
   is GUALITY_GDB_DEFAULT GUALITY_GDB_ARGS by default, but it can be
130
   overridden by setting the GUALITY_GDB environment variable, whereas
131
   GUALITY_GDB_DEFAULT can be overridden by setting the
132
   GUALITY_GDB_NAME environment variable.  */
133
 
134
static const char *guality_gdb_command;
135
#define GUALITY_GDB_DEFAULT "gdb"
136
#if defined(__unix)
137
# define GUALITY_GDB_REDIRECT " > /dev/null 2>&1"
138
#elif defined (_WIN32) || defined (MSDOS)
139
# define GUALITY_GDB_REDIRECT " > nul"
140
#else
141
# define GUALITY_GDB_REDIRECT ""
142
#endif
143
#define GUALITY_GDB_ARGS " -nx -nw --quiet" GUALITY_GDB_REDIRECT
144
 
145
/* Kinds of results communicated as exit status from child process
146
   that runs gdb to the parent process that's being monitored.  */
147
 
148
enum guality_counter { PASS, INCORRECT, INCOMPLETE };
149
 
150
/* Count of passes and errors.  */
151
 
152
static int guality_count[INCOMPLETE+1];
153
 
154
/* If --guality-skip is given in the command line, all the monitoring,
155
   forking and debugger-attaching action will be disabled.  This is
156
   useful to run the monitor program within a debugger.  */
157
 
158
static int guality_skip;
159
 
160
/* This is a file descriptor to which we'll issue gdb commands to
161
   probe and test.  */
162
FILE *guality_gdb_input;
163
 
164
/* This holds the line number where we're supposed to set a
165
   breakpoint.  */
166
int guality_breakpoint_line;
167
 
168
/* GDB should set this to true once it's connected.  */
169
int volatile guality_attached;
170
 
171
/* This function is the main guality program.  It may actually be
172
   defined as main, because we #define main to it afterwards.  Because
173
   of this wrapping, guality_main may not have an empty argument
174
   list.  */
175
 
176
extern int guality_main (int argc, char *argv[]);
177
 
178
static void __attribute__((noinline))
179
guality_check (const char *name, gualchk_t value, int unknown_ok);
180
 
181
/* Set things up, run guality_main, then print a summary and quit.  */
182
 
183
int
184
main (int argc, char *argv[])
185
{
186
  int i;
187
  char *argv0 = argv[0];
188
 
189
  guality_gdb_command = getenv ("GUALITY_GDB");
190
  if (!guality_gdb_command)
191
    {
192
      guality_gdb_command = getenv ("GUALITY_GDB_NAME");
193
      if (!guality_gdb_command)
194
        guality_gdb_command = GUALITY_GDB_DEFAULT GUALITY_GDB_ARGS;
195
      else
196
        {
197
          int len = strlen (guality_gdb_command) + sizeof (GUALITY_GDB_ARGS);
198
          char *buf = __builtin_alloca (len);
199
          strcpy (buf, guality_gdb_command);
200
          strcat (buf, GUALITY_GDB_ARGS);
201
          guality_gdb_command = buf;
202
        }
203
    }
204
 
205
  for (i = 1; i < argc; i++)
206
    if (strcmp (argv[i], "--guality-skip") == 0)
207
      guality_skip = 1;
208
    else
209
      break;
210
 
211
  if (!guality_skip)
212
    {
213
      guality_gdb_input = popen (guality_gdb_command, "w");
214
      /* This call sets guality_breakpoint_line.  */
215
      guality_check (NULL, 0, 0);
216
      if (!guality_gdb_input
217
          || fprintf (guality_gdb_input, "\
218
set height 0\n\
219
attach %i\n\
220
set guality_attached = 1\n\
221
b %i\n\
222
continue\n\
223
", (int)getpid (), guality_breakpoint_line) <= 0
224
          || fflush (guality_gdb_input))
225
        {
226
          perror ("gdb");
227
          abort ();
228
        }
229
    }
230
 
231
  argv[--i] = argv0;
232
 
233
  guality_main (argc - i, argv + i);
234
 
235
  i = guality_count[INCORRECT];
236
 
237
  fprintf (stderr, "%s: %i PASS, %i FAIL, %i UNRESOLVED\n",
238
           i ? "FAIL" : "PASS",
239
           guality_count[PASS], guality_count[INCORRECT],
240
           guality_count[INCOMPLETE]);
241
 
242
  return i;
243
}
244
 
245
#define main guality_main
246
 
247
/* Tell the GDB child process to evaluate NAME in the caller.  If it
248
   matches VALUE, we have a PASS; if it's unknown and UNKNOWN_OK, we
249
   have an UNRESOLVED.  Otherwise, it's a FAIL.  */
250
 
251
static void __attribute__((noinline))
252
guality_check (const char *name, gualchk_t value, int unknown_ok)
253
{
254
  int result;
255
 
256
  if (guality_skip)
257
    return;
258
 
259
  {
260
    volatile gualchk_t xvalue = -1;
261
    volatile int unavailable = 0;
262
    if (name)
263
      {
264
        /* The sequence below cannot distinguish an optimized away
265
           variable from one mapped to a non-lvalue zero.  */
266
        if (fprintf (guality_gdb_input, "\
267
up\n\
268
set $value1 = 0\n\
269
set $value1 = (%s)\n\
270
set $value2 = -1\n\
271
set $value2 = (%s)\n\
272
set $value3 = $value1 - 1\n\
273
set $value4 = $value1 + 1\n\
274
set $value3 = (%s)++\n\
275
set $value4 = --(%s)\n\
276
down\n\
277
set xvalue = $value1\n\
278
set unavailable = $value1 != $value2 ? -1 : $value3 != $value4 ? 1 : 0\n\
279
continue\n\
280
", name, name, name, name) <= 0
281
            || fflush (guality_gdb_input))
282
          {
283
            perror ("gdb");
284
            abort ();
285
          }
286
        else if (!guality_attached)
287
          {
288
            unsigned int timeout = 0;
289
 
290
            /* Give GDB some more time to attach.  Wrapping around a
291
               32-bit counter takes some seconds, it should be plenty
292
               of time for GDB to get a chance to start up and attach,
293
               but not long enough that, if GDB is unavailable or
294
               broken, we'll take far too long to give up.  */
295
            while (--timeout && !guality_attached)
296
              ;
297
            if (!timeout && !guality_attached)
298
              {
299
                fprintf (stderr, "gdb: took too long to attach\n");
300
                abort ();
301
              }
302
          }
303
      }
304
    else
305
      {
306
        guality_breakpoint_line = __LINE__ + 5;
307
        return;
308
      }
309
    /* Do NOT add lines between the __LINE__ above and the line below,
310
       without also adjusting the added constant to match.  */
311
    if (!unavailable || (unavailable > 0 && xvalue))
312
      {
313
        if (xvalue == value)
314
          result = PASS;
315
        else
316
          result = INCORRECT;
317
      }
318
    else
319
      result = INCOMPLETE;
320
    asm ("" : : "X" (name), "X" (value), "X" (unknown_ok), "m" (xvalue));
321
    switch (result)
322
      {
323
      case PASS:
324
        fprintf (stderr, "PASS: %s is %lli\n", name, value);
325
        break;
326
      case INCORRECT:
327
        fprintf (stderr, "FAIL: %s is %lli, not %lli\n", name, xvalue, value);
328
        break;
329
      case INCOMPLETE:
330
        fprintf (stderr, "%s: %s is %s, expected %lli\n",
331
                 unknown_ok ? "UNRESOLVED" : "FAIL", name,
332
                 unavailable < 0 ? "not computable" : "optimized away", value);
333
        result = unknown_ok ? INCOMPLETE : INCORRECT;
334
        break;
335
      default:
336
        abort ();
337
      }
338
  }
339
 
340
  switch (result)
341
    {
342
    case PASS:
343
    case INCORRECT:
344
    case INCOMPLETE:
345
      ++guality_count[result];
346
      break;
347
 
348
    default:
349
      abort ();
350
    }
351
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.