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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [gcc/] [testsuite/] [gcc.dg/] [guality/] [guality.h] - Blame information for rev 689

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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