1 /* Demangler test program,
   2    Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
   3    Written by Zack Weinberg <zack@codesourcery.com
   4 
   5    This file is part of GNU libiberty.
   6 
   7    This program 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 2 of the License, or
  10    (at your option) any later version.
  11 
  12    This program 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 this program; if not, write to the Free Software
  19    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 
  20 */
  21 
  22 #ifdef HAVE_CONFIG_H
  23 #include "config.h"
  24 #endif
  25 #include "ansidecl.h"
  26 #include <stdio.h>
  27 #include "libiberty.h"
  28 #include "demangle.h"
  29 #ifdef HAVE_STRING_H
  30 #include <string.h>
  31 #endif
  32 #if HAVE_STDLIB_H
  33 # include <stdlib.h>
  34 #endif
  35 
  36 struct line
  37 {
  38   size_t alloced;
  39   char *data;
  40 };
  41 
  42 static unsigned int lineno;
  43 
  44 /* Safely read a single line of arbitrary length from standard input.  */
  45 
  46 #define LINELEN 80
  47 
  48 static void
  49 _getline(buf)
  50      struct line *buf;
  51 {
  52   char *data = buf->data;
  53   size_t alloc = buf->alloced;
  54   size_t count = 0;
  55   int c;
  56 
  57   if (data == 0)
  58     {
  59       data = xmalloc (LINELEN);
  60       alloc = LINELEN;
  61     }
  62 
  63   /* Skip comment lines.  */
  64   while ((c = getchar()) == '#')
  65     {
  66       while ((c = getchar()) != EOF && c != '\n');
  67       lineno++;
  68     }
  69 
  70   /* c is the first character on the line, and it's not a comment
  71      line: copy this line into the buffer and return.  */
  72   while (c != EOF && c != '\n')
  73     {
  74       if (count + 1 >= alloc)
  75         {
  76           alloc *= 2;
  77           data = xrealloc (data, alloc);
  78         }
  79       data[count++] = c;
  80       c = getchar();
  81     }
  82   lineno++;
  83   data[count] = '\0';
  84 
  85   buf->data = data;
  86   buf->alloced = alloc;
  87 }
  88 
  89 /* If we have mmap() and mprotect(), copy the string S just before a
  90    protected page, so that if the demangler runs over the end of the
  91    string we'll get a fault, and return the address of the new string.
  92    If no mmap, or it fails, or it looks too hard, just return S.  */
  93 
  94 #ifdef HAVE_SYS_MMAN_H
  95 #include <sys/mman.h>
  96 #endif
  97 #if defined(MAP_ANON) && ! defined (MAP_ANONYMOUS)
  98 #define MAP_ANONYMOUS MAP_ANON
  99 #endif
 100 
 101 static const char *
 102 protect_end (const char * s)
 103 {
 104 #if defined(HAVE_MMAP) && defined (MAP_ANONYMOUS)
 105   size_t pagesize = getpagesize();
 106   static char * buf;
 107   size_t s_len = strlen (s);
 108   char * result;
 109   
 110   /* Don't try if S is too long.  */
 111   if (s_len >= pagesize)
 112     return s;
 113 
 114   /* Allocate one page of allocated space followed by an unmapped
 115      page.  */
 116   if (buf == NULL)
 117     {
 118       buf = mmap (NULL, pagesize * 2, PROT_READ | PROT_WRITE,
 119                   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
 120       if (! buf)
 121         return s;
 122       munmap (buf + pagesize, pagesize);
 123     }
 124   
 125   result = buf + (pagesize - s_len - 1);
 126   memcpy (result, s, s_len + 1);
 127   return result;
 128 #else
 129   return s;
 130 #endif
 131 }
 132 
 133 static void
 134 fail (lineno, opts, in, out, exp)
 135      int lineno;
 136      const char *opts;
 137      const char *in;
 138      const char *out;
 139      const char *exp;
 140 {
 141   printf ("\
 142 FAIL at line %d, options %s:\n\
 143 in:  %s\n\
 144 out: %s\n\
 145 exp: %s\n",
 146           lineno, opts, in, out != NULL ? out : "(null)", exp);
 147 }
 148 
 149 /* The tester operates on a data file consisting of groups of lines:
 150    options
 151    input to be demangled
 152    expected output
 153 
 154    Supported options:
 155      --format=<name>     Sets the demangling style.
 156      --no-params         There are two lines of expected output; the first
 157                          is with DMGL_PARAMS, the second is without it.
 158      --is-v3-ctor        Calls is_gnu_v3_mangled_ctor on input; expected
 159                          output is an integer representing ctor_kind.
 160      --is-v3-dtor        Likewise, but for dtors.
 161      --ret-postfix       Passes the DMGL_RET_POSTFIX option
 162 
 163    For compatibility, just in case it matters, the options line may be
 164    empty, to mean --format=auto.  If it doesn't start with --, then it
 165    may contain only a format name.
 166 */
 167 
 168 int
 169 main(argc, argv)
 170      int argc;
 171      char **argv;
 172 {
 173   enum demangling_styles style = auto_demangling;
 174   int no_params;
 175   int is_v3_ctor;
 176   int is_v3_dtor;
 177   int ret_postfix;
 178   struct line format;
 179   struct line input;
 180   struct line expect;
 181   char *result;
 182   int failures = 0;
 183   int tests = 0;
 184 
 185   if (argc > 1)
 186     {
 187       fprintf (stderr, "usage: %s < test-set\n", argv[0]);
 188       return 2;
 189     }
 190 
 191   format.data = 0;
 192   input.data = 0;
 193   expect.data = 0;
 194 
 195   for (;;)
 196     {
 197       const char *inp;
 198       
 199       _getline (&format);
 200       if (feof (stdin))
 201         break;
 202 
 203       _getline (&input);
 204       _getline (&expect);
 205 
 206       inp = protect_end (input.data);
 207 
 208       tests++;
 209 
 210       no_params = 0;
 211       ret_postfix = 0;
 212       is_v3_ctor = 0;
 213       is_v3_dtor = 0;
 214       if (format.data[0] == '\0')
 215         style = auto_demangling;
 216       else if (format.data[0] != '-')
 217         {
 218           style = cplus_demangle_name_to_style (format.data);
 219           if (style == unknown_demangling)
 220             {
 221               printf ("FAIL at line %d: unknown demangling style %s\n",
 222                       lineno, format.data);
 223               failures++;
 224               continue;
 225             }
 226         }
 227       else
 228         {
 229           char *p;
 230           char *opt;
 231 
 232           p = format.data;
 233           while (*p != '\0')
 234             {
 235               char c;
 236 
 237               opt = p;
 238               p += strcspn (p, " \t=");
 239               c = *p;
 240               *p = '\0';
 241               if (strcmp (opt, "--format") == 0 && c == '=')
 242                 {
 243                   char *fstyle;
 244 
 245                   *p = c;
 246                   ++p;
 247                   fstyle = p;
 248                   p += strcspn (p, " \t");
 249                   c = *p;
 250                   *p = '\0';
 251                   style = cplus_demangle_name_to_style (fstyle);
 252                   if (style == unknown_demangling)
 253                     {
 254                       printf ("FAIL at line %d: unknown demangling style %s\n",
 255                               lineno, fstyle);
 256                       failures++;
 257                       continue;
 258                     }
 259                 }
 260               else if (strcmp (opt, "--no-params") == 0)
 261                 no_params = 1;
 262               else if (strcmp (opt, "--is-v3-ctor") == 0)
 263                 is_v3_ctor = 1;
 264               else if (strcmp (opt, "--is-v3-dtor") == 0)
 265                 is_v3_dtor = 1;
 266               else if (strcmp (opt, "--ret-postfix") == 0)
 267                 ret_postfix = 1;
 268               else
 269                 {
 270                   printf ("FAIL at line %d: unrecognized option %s\n",
 271                           lineno, opt);
 272                   failures++;
 273                   continue;
 274                 }
 275               *p = c;
 276               p += strspn (p, " \t");
 277             }
 278         }
 279 
 280       if (is_v3_ctor || is_v3_dtor)
 281         {
 282           char buf[20];
 283 
 284           if (is_v3_ctor)
 285             {
 286               enum gnu_v3_ctor_kinds kc;
 287 
 288               kc = is_gnu_v3_mangled_ctor (inp);
 289               sprintf (buf, "%d", (int) kc);
 290             }
 291           else
 292             {
 293               enum gnu_v3_dtor_kinds kd;
 294 
 295               kd = is_gnu_v3_mangled_dtor (inp);
 296               sprintf (buf, "%d", (int) kd);
 297             }
 298 
 299           if (strcmp (buf, expect.data) != 0)
 300             {
 301               fail (lineno, format.data, input.data, buf, expect.data);
 302               failures++;
 303             }
 304 
 305           continue;
 306         }
 307 
 308       cplus_demangle_set_style (style);
 309 
 310       result = cplus_demangle (inp,
 311                                DMGL_PARAMS|DMGL_ANSI|DMGL_TYPES
 312                                |(ret_postfix ? DMGL_RET_POSTFIX : 0));
 313 
 314       if (result
 315           ? strcmp (result, expect.data)
 316           : strcmp (input.data, expect.data))
 317         {
 318           fail (lineno, format.data, input.data, result, expect.data);
 319           failures++;
 320         }
 321       free (result);
 322 
 323       if (no_params)
 324         {
 325           _getline (&expect);
 326           result = cplus_demangle (inp, DMGL_ANSI|DMGL_TYPES);
 327 
 328           if (result
 329               ? strcmp (result, expect.data)
 330               : strcmp (input.data, expect.data))
 331             {
 332               fail (lineno, format.data, input.data, result, expect.data);
 333               failures++;
 334             }
 335           free (result);
 336         }
 337     }
 338 
 339   free (format.data);
 340   free (input.data);
 341   free (expect.data);
 342 
 343   printf ("%s: %d tests, %d failures\n", argv[0], tests, failures);
 344   return failures ? 1 : 0;
 345 }