Home | History | Annotate | Download | only in tests
      1 /* libunwind - a platform-independent unwind library
      2    Copyright (C) 2004-2005 Hewlett-Packard Co
      3 	Contributed by David Mosberger-Tang <davidm (at) hpl.hp.com>
      4 
      5 This file is part of libunwind.
      6 
      7 Permission is hereby granted, free of charge, to any person obtaining
      8 a copy of this software and associated documentation files (the
      9 "Software"), to deal in the Software without restriction, including
     10 without limitation the rights to use, copy, modify, merge, publish,
     11 distribute, sublicense, and/or sell copies of the Software, and to
     12 permit persons to whom the Software is furnished to do so, subject to
     13 the following conditions:
     14 
     15 The above copyright notice and this permission notice shall be
     16 included in all copies or substantial portions of the Software.
     17 
     18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     21 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
     22 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
     23 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
     24 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
     25 
     26 /* This file tests corner-cases of NaT-bit handling.  */
     27 
     28 #include <errno.h>
     29 #include <stdio.h>
     30 #include <stdlib.h>
     31 #include <string.h>
     32 
     33 #include <libunwind.h>
     34 #include "compiler.h"
     35 
     36 #ifdef HAVE_SYS_UC_ACCESS_H
     37 # include <sys/uc_access.h>
     38 #endif
     39 
     40 #include "tdep-ia64/rse.h"
     41 
     42 #define NUM_RUNS		1024
     43 //#define NUM_RUNS		1
     44 #define MAX_CHECKS		1024
     45 //#define MAX_CHECKS		2
     46 #define MAX_VALUES_PER_FUNC	4
     47 
     48 #define panic(args...)							  \
     49 	do { printf (args); ++nerrors; } while (0)
     50 
     51 typedef void save_func_t (void *funcs, unsigned long *vals);
     52 typedef unw_word_t *check_func_t (unw_cursor_t *c, unsigned long *vals);
     53 
     54 extern void flushrs (void);
     55 
     56 extern save_func_t save_static_to_stacked;
     57 static check_func_t check_static_to_stacked;
     58 
     59 extern save_func_t save_static_to_fr;
     60 static check_func_t check_static_to_fr;
     61 
     62 extern save_func_t save_static_to_br;
     63 static check_func_t check_static_to_br;
     64 
     65 extern save_func_t save_static_to_mem;
     66 static check_func_t check_static_to_mem;
     67 
     68 extern save_func_t save_static_to_mem2;
     69 static check_func_t check_static_to_mem2;
     70 
     71 extern save_func_t save_static_to_mem3;
     72 static check_func_t check_static_to_mem3;
     73 
     74 extern save_func_t save_static_to_mem4;
     75 static check_func_t check_static_to_mem4;
     76 
     77 extern save_func_t save_static_to_mem5;
     78 static check_func_t check_static_to_mem5;
     79 
     80 extern save_func_t save_static_to_scratch;
     81 static check_func_t check_static_to_scratch;
     82 
     83 extern save_func_t rotate_regs;
     84 static check_func_t check_rotate_regs;
     85 
     86 extern save_func_t save_pr;
     87 static check_func_t check_pr;
     88 
     89 static int verbose;
     90 static int nerrors;
     91 
     92 static int num_checks;
     93 static save_func_t *funcs[MAX_CHECKS + 1];
     94 static check_func_t *checks[MAX_CHECKS];
     95 static unw_word_t values[MAX_CHECKS*MAX_VALUES_PER_FUNC];
     96 
     97 static struct
     98   {
     99     save_func_t *func;
    100     check_func_t *check;
    101   }
    102 all_funcs[] =
    103   {
    104     { save_static_to_stacked,	check_static_to_stacked },
    105     { save_static_to_fr,	check_static_to_fr },
    106     { save_static_to_br,	check_static_to_br },
    107     { save_static_to_mem,	check_static_to_mem },
    108     { save_static_to_mem2,	check_static_to_mem2 },
    109     { save_static_to_mem3,	check_static_to_mem3 },
    110     { save_static_to_mem4,	check_static_to_mem4 },
    111     { save_static_to_mem5,	check_static_to_mem5 },
    112     { save_static_to_scratch,	check_static_to_scratch },
    113     { save_pr,			check_pr },
    114     { rotate_regs,		check_rotate_regs },
    115   };
    116 
    117 static unw_word_t
    118 random_word (void)
    119 {
    120   unw_word_t val = random ();
    121 
    122   if (sizeof (unw_word_t) > 4)
    123     val |= ((unw_word_t) random ()) << 32;
    124 
    125   return val;
    126 }
    127 
    128 void
    129 sighandler (int signal, void *siginfo, void *context)
    130 {
    131   unsigned long *bsp, *arg1;
    132   save_func_t **arg0;
    133   ucontext_t *uc = context;
    134 
    135 #if defined(__linux)
    136   {
    137     long sof;
    138     int sp;
    139 
    140     if (verbose)
    141       printf ("sighandler: signal %d sp=%p nat=%08lx pr=%lx\n",
    142 	      signal, &sp, uc->uc_mcontext.sc_nat, uc->uc_mcontext.sc_pr);
    143     sof = uc->uc_mcontext.sc_cfm & 0x7f;
    144     bsp = (unsigned long *) rse_skip_regs (uc->uc_mcontext.sc_ar_bsp, -sof);
    145   }
    146 #elif defined(__hpux)
    147   if (__uc_get_ar (uc, UNW_IA64_AR_BSP - UNW_IA64_AR, &bsp) != 0)
    148     {
    149       panic ("%s: reading of ar.bsp failed, errno=%d", __FUNCTION__, errno);
    150       return;
    151     }
    152 #endif
    153 
    154   flushrs ();
    155   arg0 = (save_func_t **) *bsp;
    156   bsp = (unsigned long *) rse_skip_regs ((uint64_t) bsp, 1);
    157   arg1 = (unsigned long *) *bsp;
    158 
    159   (*arg0[0]) (arg0 + 1, arg1);
    160 
    161   /* skip over the instruction which triggered sighandler() */
    162 #if defined(__linux)
    163   ++uc->uc_mcontext.sc_ip;
    164 #elif defined(HAVE_SYS_UC_ACCESS_H)
    165   {
    166     unsigned long ip;
    167 
    168     if (__uc_get_ip (uc, &ip) != 0)
    169       {
    170 	panic ("%s: reading of ip failed, errno=%d", __FUNCTION__, errno);
    171 	return;
    172       }
    173     if (__uc_set_ip (uc, ip) != 0)
    174       {
    175 	panic ("%s: writing of ip failed, errno=%d", __FUNCTION__, errno);
    176 	return;
    177       }
    178   }
    179 #endif
    180 }
    181 
    182 static void
    183 enable_sighandler (void)
    184 {
    185   struct sigaction act;
    186 
    187   memset (&act, 0, sizeof (act));
    188   act.sa_handler = (void (*)(int)) sighandler;
    189   act.sa_flags = SA_SIGINFO | SA_NODEFER;
    190   if (sigaction (SIGSEGV, &act, NULL) < 0)
    191     panic ("sigaction: %s\n", strerror (errno));
    192 }
    193 
    194 static void
    195 disable_sighandler (void)
    196 {
    197   struct sigaction act;
    198 
    199   memset (&act, 0, sizeof (act));
    200   act.sa_handler = SIG_DFL;
    201   act.sa_flags = SA_SIGINFO | SA_NODEFER;
    202   if (sigaction (SIGSEGV, &act, NULL) < 0)
    203     panic ("sigaction: %s\n", strerror (errno));
    204 }
    205 
    206 static unw_word_t *
    207 check_static_to_stacked (unw_cursor_t *c, unw_word_t *vals)
    208 {
    209   unw_word_t r[4];
    210   unw_word_t nat[4];
    211   int i, ret;
    212 
    213   if (verbose)
    214     printf ("  %s()\n", __FUNCTION__);
    215 
    216   vals -= 4;
    217 
    218   for (i = 0; i < 4; ++i)
    219     if ((ret = unw_get_reg (c, UNW_IA64_GR + 4 + i, &r[i])) < 0)
    220       panic ("%s: failed to read register r%d, error=%d\n",
    221 	     __FUNCTION__, 4 + i, ret);
    222 
    223   for (i = 0; i < 4; ++i)
    224     if ((ret = unw_get_reg (c, UNW_IA64_NAT + 4 + i, &nat[i])) < 0)
    225       panic ("%s: failed to read register nat%d, error=%d\n",
    226 	     __FUNCTION__, 4 + i, ret);
    227 
    228   for (i = 0; i < 4; ++i)
    229     {
    230       if (verbose)
    231 	printf ("    r%d = %c%016lx (expected %c%016lx)\n",
    232 		4 + i, nat[i] ? '*' : ' ', r[i],
    233 		(vals[i] & 1) ? '*' : ' ', vals[i]);
    234 
    235       if (vals[i] & 1)
    236 	{
    237 	  if (!nat[i])
    238 	    panic ("%s: r%d not a NaT!\n", __FUNCTION__, 4 + i);
    239 	}
    240       else
    241 	{
    242 	  if (nat[i])
    243 	    panic ("%s: r%d a NaT!\n", __FUNCTION__, 4 + i);
    244 	  if (r[i] != vals[i])
    245 	    panic ("%s: r%d=%lx instead of %lx!\n",
    246 		   __FUNCTION__, 4 + i, r[i], vals[i]);
    247 	}
    248     }
    249   return vals;
    250 }
    251 
    252 static unw_word_t *
    253 check_static_to_fr (unw_cursor_t *c, unw_word_t *vals)
    254 {
    255   unw_word_t r4;
    256   unw_word_t nat4;
    257   int ret;
    258 
    259   if (verbose)
    260     printf ("  %s()\n", __FUNCTION__);
    261 
    262   vals -= 1;
    263 
    264   if ((ret = unw_get_reg (c, UNW_IA64_GR + 4, &r4)) < 0)
    265     panic ("%s: failed to read register r4, error=%d\n", __FUNCTION__, ret);
    266 
    267   if ((ret = unw_get_reg (c, UNW_IA64_NAT + 4, &nat4)) < 0)
    268     panic ("%s: failed to read register nat4, error=%d\n", __FUNCTION__, ret);
    269 
    270   if (verbose)
    271     printf ("    r4 = %c%016lx (expected %c%016lx)\n",
    272 	    nat4 ? '*' : ' ', r4, (vals[0] & 1) ? '*' : ' ', vals[0]);
    273 
    274   if (vals[0] & 1)
    275     {
    276       if (!nat4)
    277 	panic ("%s: r4 not a NaT!\n", __FUNCTION__);
    278     }
    279   else
    280     {
    281       if (nat4)
    282 	panic ("%s: r4 a NaT!\n", __FUNCTION__);
    283       if (r4 != vals[0])
    284 	panic ("%s: r4=%lx instead of %lx!\n", __FUNCTION__, r4, vals[0]);
    285     }
    286   return vals;
    287 }
    288 
    289 static unw_word_t *
    290 check_static_to_br (unw_cursor_t *c, unw_word_t *vals)
    291 {
    292   unw_word_t r4, nat4;
    293   int ret;
    294 
    295   if (verbose)
    296     printf ("  %s()\n", __FUNCTION__);
    297 
    298   vals -= 1;
    299 
    300   if ((ret = unw_get_reg (c, UNW_IA64_GR + 4, &r4)) < 0)
    301     panic ("%s: failed to read register r4, error=%d\n", __FUNCTION__, ret);
    302 
    303   if ((ret = unw_get_reg (c, UNW_IA64_NAT + 4, &nat4)) < 0)
    304     panic ("%s: failed to read register nat4, error=%d\n", __FUNCTION__, ret);
    305 
    306   if (verbose)
    307     printf ("    r4 = %c%016lx (expected %c%016lx)\n",
    308 	    nat4 ? '*' : ' ', r4, (vals[0] & 1) ? '*' : ' ', vals[0]);
    309 
    310   if (vals[0] & 1)
    311     {
    312       if (!nat4)
    313 	panic ("%s: r4 not a NaT!\n", __FUNCTION__);
    314     }
    315   else
    316     {
    317       if (nat4)
    318 	panic ("%s: r4 a NaT!\n", __FUNCTION__);
    319       if (r4 != vals[0])
    320 	panic ("%s: r4=%lx instead of %lx!\n", __FUNCTION__, r4, vals[0]);
    321     }
    322   return vals;
    323 }
    324 
    325 static unw_word_t *
    326 check_static_to_mem (unw_cursor_t *c, unw_word_t *vals)
    327 {
    328   unw_word_t r5, nat5;
    329   int ret;
    330 
    331   if (verbose)
    332     printf ("  %s()\n", __FUNCTION__);
    333 
    334   vals -= 1;
    335 
    336   if ((ret = unw_get_reg (c, UNW_IA64_GR + 5, &r5)) < 0)
    337     panic ("%s: failed to read register r5, error=%d\n", __FUNCTION__, ret);
    338 
    339   if ((ret = unw_get_reg (c, UNW_IA64_NAT + 5, &nat5)) < 0)
    340     panic ("%s: failed to read register nat5, error=%d\n", __FUNCTION__, ret);
    341 
    342   if (verbose)
    343     printf ("    r5 = %c%016lx (expected %c%016lx)\n",
    344 	    nat5 ? '*' : ' ', r5, (vals[0] & 1) ? '*' : ' ', vals[0]);
    345 
    346   if (vals[0] & 1)
    347     {
    348       if (!nat5)
    349 	panic ("%s: r5 not a NaT!\n", __FUNCTION__);
    350     }
    351   else
    352     {
    353       if (nat5)
    354 	panic ("%s: r5 a NaT!\n", __FUNCTION__);
    355       if (r5 != vals[0])
    356 	panic ("%s: r5=%lx instead of %lx!\n", __FUNCTION__, r5, vals[0]);
    357     }
    358   return vals;
    359 }
    360 
    361 static unw_word_t *
    362 check_static_to_memN (unw_cursor_t *c, unw_word_t *vals, const char *func)
    363 {
    364   unw_word_t r6, nat6;
    365   int ret;
    366 
    367   if (verbose)
    368     printf ("  %s()\n", func);
    369 
    370   vals -= 1;
    371 
    372   if ((ret = unw_get_reg (c, UNW_IA64_GR + 6, &r6)) < 0)
    373     panic ("%s: failed to read register r6, error=%d\n", __FUNCTION__, ret);
    374 
    375   if ((ret = unw_get_reg (c, UNW_IA64_NAT + 6, &nat6)) < 0)
    376     panic ("%s: failed to read register nat6, error=%d\n", __FUNCTION__, ret);
    377 
    378   if (verbose)
    379     printf ("    r6 = %c%016lx (expected %c%016lx)\n",
    380 	    nat6 ? '*' : ' ', r6, (vals[0] & 1) ? '*' : ' ', vals[0]);
    381 
    382   if (vals[0] & 1)
    383     {
    384       if (!nat6)
    385 	panic ("%s: r6 not a NaT!\n", __FUNCTION__);
    386     }
    387   else
    388     {
    389       if (nat6)
    390 	panic ("%s: r6 a NaT!\n", __FUNCTION__);
    391       if (r6 != vals[0])
    392 	panic ("%s: r6=%lx instead of %lx!\n", __FUNCTION__, r6, vals[0]);
    393     }
    394   return vals;
    395 }
    396 
    397 static unw_word_t *
    398 check_static_to_mem2 (unw_cursor_t *c, unw_word_t *vals)
    399 {
    400   return check_static_to_memN (c, vals, __FUNCTION__);
    401 }
    402 
    403 static unw_word_t *
    404 check_static_to_mem3 (unw_cursor_t *c, unw_word_t *vals)
    405 {
    406   return check_static_to_memN (c, vals, __FUNCTION__);
    407 }
    408 
    409 static unw_word_t *
    410 check_static_to_mem4 (unw_cursor_t *c, unw_word_t *vals)
    411 {
    412   return check_static_to_memN (c, vals, __FUNCTION__);
    413 }
    414 
    415 static unw_word_t *
    416 check_static_to_mem5 (unw_cursor_t *c, unw_word_t *vals)
    417 {
    418   return check_static_to_memN (c, vals, __FUNCTION__);
    419 }
    420 
    421 static unw_word_t *
    422 check_static_to_scratch (unw_cursor_t *c, unw_word_t *vals)
    423 {
    424   unw_word_t r[4], nat[4], ec, expected;
    425   unw_fpreg_t f4;
    426   int i, ret;
    427 
    428   if (verbose)
    429     printf ("  %s()\n", __FUNCTION__);
    430 
    431   vals -= 4;
    432 
    433   while (!unw_is_signal_frame (c))
    434     if ((ret = unw_step (c)) < 0)
    435       panic ("%s: unw_step (ret=%d): Failed to skip over signal handler\n",
    436 	     __FUNCTION__, ret);
    437   if ((ret = unw_step (c)) < 0)
    438     panic ("%s: unw_step (ret=%d): Failed to skip over signal handler\n",
    439 	   __FUNCTION__, ret);
    440 
    441   for (i = 0; i < 4; ++i)
    442     if ((ret = unw_get_reg (c, UNW_IA64_GR + 4 + i, &r[i])) < 0)
    443       panic ("%s: failed to read register r%d, error=%d\n",
    444 	     __FUNCTION__, 4 + i, ret);
    445 
    446   for (i = 0; i < 4; ++i)
    447     if ((ret = unw_get_reg (c, UNW_IA64_NAT + 4 + i, &nat[i])) < 0)
    448       panic ("%s: failed to read register nat%d, error=%d\n",
    449 	     __FUNCTION__, 4 + i, ret);
    450 
    451   for (i = 0; i < 4; ++i)
    452     {
    453       if (verbose)
    454 	printf ("    r%d = %c%016lx (expected %c%016lx)\n",
    455 		4 + i, nat[i] ? '*' : ' ', r[i],
    456 		(vals[i] & 1) ? '*' : ' ', vals[i]);
    457 
    458       if (vals[i] & 1)
    459 	{
    460 	  if (!nat[i])
    461 	    panic ("%s: r%d not a NaT!\n", __FUNCTION__, 4 + i);
    462 	}
    463       else
    464 	{
    465 	  if (nat[i])
    466 	    panic ("%s: r%d a NaT!\n", __FUNCTION__, 4 + i);
    467 	  if (r[i] != vals[i])
    468 	    panic ("%s: r%d=%lx instead of %lx!\n",
    469 		   __FUNCTION__, 4 + i, r[i], vals[i]);
    470 	}
    471     }
    472   if ((ret = unw_get_fpreg (c, UNW_IA64_FR + 4, &f4)) < 0)
    473     panic ("%s: failed to read f4, error=%d\n", __FUNCTION__, ret);
    474 
    475   /* These tests are little-endian specific: */
    476   if (nat[0])
    477     {
    478       if (f4.raw.bits[0] != 0 || f4.raw.bits[1] != 0x1fffe)
    479 	panic ("%s: f4=%016lx.%016lx instead of NaTVal!\n",
    480 	       __FUNCTION__, f4.raw.bits[1], f4.raw.bits[0]);
    481     }
    482   else
    483     {
    484       if (f4.raw.bits[0] != r[0] || f4.raw.bits[1] != 0x1003e)
    485 	panic ("%s: f4=%016lx.%016lx instead of %lx!\n",
    486 	       __FUNCTION__, f4.raw.bits[1], f4.raw.bits[0], r[0]);
    487     }
    488 
    489   if ((unw_get_reg (c, UNW_IA64_AR_EC, &ec)) < 0)
    490     panic ("%s: failed to read register ar.ec, error=%d\n", __FUNCTION__, ret);
    491 
    492   expected = vals[0] & 0x3f;
    493   if (ec != expected)
    494     panic ("%s: ar.ec=%016lx instead of %016lx!\n",
    495 	   __FUNCTION__, ec, expected);
    496 
    497   return vals;
    498 }
    499 
    500 static unw_word_t *
    501 check_pr (unw_cursor_t *c, unw_word_t *vals)
    502 {
    503   unw_word_t pr, expected;
    504   int ret;
    505 # define BIT(n) ((unw_word_t) 1 << (n))
    506 # define DONTCARE (BIT( 6) | BIT( 7) | BIT( 8) | BIT( 9) | BIT(10) \
    507 		 | BIT(11) | BIT(12) | BIT(13) | BIT(14) | BIT(15))
    508 
    509   if (verbose)
    510     printf ("  %s()\n", __FUNCTION__);
    511 
    512   vals -= 1;
    513 
    514   if ((ret = unw_get_reg (c, UNW_IA64_PR, &pr)) < 0)
    515     panic ("%s: failed to read register pr, error=%d\n", __FUNCTION__, ret);
    516 
    517   pr &= ~DONTCARE;
    518   expected = (vals[0] & ~DONTCARE) | 1;
    519 
    520   if (verbose)
    521     printf ("    pr = %016lx (expected %016lx)\n", pr, expected);
    522 
    523   if (pr != expected)
    524     panic ("%s: pr=%lx instead of %lx!\n", __FUNCTION__, pr, expected);
    525 
    526   if ((ret = unw_set_reg (c, UNW_IA64_PR, vals[0])) < 0)
    527     panic ("%s: failed to write register pr, error=%d\n", __FUNCTION__, ret);
    528 
    529   if ((ret = unw_get_reg (c, UNW_IA64_PR, &pr)) < 0)
    530     panic ("%s: failed to read register pr, error=%d\n", __FUNCTION__, ret);
    531 
    532   if (pr != vals[0])
    533     panic ("%s: secondary pr=%lx instead of %lx!\n",
    534 	   __FUNCTION__, pr, vals[0]);
    535   return vals;
    536 }
    537 
    538 static unw_word_t *
    539 check_rotate_regs (unw_cursor_t *c, unw_word_t *vals)
    540 {
    541   if (verbose)
    542     printf ("  %s()\n", __FUNCTION__);
    543   return check_pr (c, vals - 1);
    544 }
    545 
    546 static void
    547 start_checks (void *funcs, unsigned long *vals)
    548 {
    549   unw_context_t uc;
    550   unw_cursor_t c;
    551   int i, ret;
    552 
    553   disable_sighandler ();
    554 
    555   unw_getcontext (&uc);
    556 
    557   if ((ret = unw_init_local (&c, &uc)) < 0)
    558     panic ("%s: unw_init_local (ret=%d)\n", __FUNCTION__, ret);
    559 
    560   if ((ret = unw_step (&c)) < 0)
    561     panic ("%s: unw_step (ret=%d)\n", __FUNCTION__, ret);
    562 
    563   for (i = 0; i < num_checks; ++i)
    564     {
    565       vals = (*checks[num_checks - 1 - i]) (&c, vals);
    566 
    567       if ((ret = unw_step (&c)) < 0)
    568 	panic ("%s: unw_step (ret=%d)\n", __FUNCTION__, ret);
    569     }
    570 }
    571 
    572 static void
    573 run_check (int test)
    574 {
    575   int index, i;
    576 
    577   if (test == 1)
    578     /* Make first test always go the full depth... */
    579     num_checks = MAX_CHECKS;
    580   else
    581     num_checks = (random () % MAX_CHECKS) + 1;
    582 
    583   for (i = 0; i < num_checks * MAX_VALUES_PER_FUNC; ++i)
    584     values[i] = random_word ();
    585 
    586   for (i = 0; i < num_checks; ++i)
    587     {
    588       if (test == 1)
    589 	/* Make first test once go through each test... */
    590 	index = i % (int) ARRAY_SIZE (all_funcs);
    591       else
    592 	index = random () % (int) ARRAY_SIZE (all_funcs);
    593       funcs[i] = all_funcs[index].func;
    594       checks[i] = all_funcs[index].check;
    595     }
    596 
    597   funcs[num_checks] = start_checks;
    598 
    599   enable_sighandler ();
    600   (*funcs[0]) (funcs + 1, values);
    601 }
    602 
    603 int
    604 main (int argc, char **argv)
    605 {
    606   int i;
    607 
    608   if (argc > 1)
    609     verbose = 1;
    610 
    611   for (i = 0; i < NUM_RUNS; ++i)
    612     {
    613       if (verbose)
    614 	printf ("Run %d\n", i + 1);
    615       run_check (i + 1);
    616     }
    617 
    618   if (nerrors > 0)
    619     {
    620       fprintf (stderr, "FAILURE: detected %d errors\n", nerrors);
    621       exit (-1);
    622     }
    623   if (verbose)
    624     printf ("SUCCESS.\n");
    625   return 0;
    626 }
    627