Home | History | Annotate | Line # | Download | only in testsuite
      1 /* Demangler test program,
      2    Copyright (C) 2002-2024 Free Software Foundation, Inc.
      3    Written by Zack Weinberg <zack (at) 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 #ifdef HAVE_UNISTD_H
     36 #include <unistd.h>
     37 #endif
     38 
     39 struct line
     40 {
     41   size_t alloced;
     42   char *data;
     43 };
     44 
     45 static unsigned int lineno;
     46 
     47 /* Safely read a single line of arbitrary length from standard input.  */
     48 
     49 #define LINELEN 80
     50 
     51 static void
     52 get_line(struct line *buf)
     53 {
     54   char *data = buf->data;
     55   size_t alloc = buf->alloced;
     56   size_t count = 0;
     57   int c;
     58 
     59   if (data == 0)
     60     {
     61       data = xmalloc (LINELEN);
     62       alloc = LINELEN;
     63     }
     64 
     65   /* Skip comment lines.  */
     66   while ((c = getchar()) == '#')
     67     {
     68       while ((c = getchar()) != EOF && c != '\n');
     69       lineno++;
     70     }
     71 
     72   /* c is the first character on the line, and it's not a comment
     73      line: copy this line into the buffer and return.  */
     74   while (c != EOF && c != '\n')
     75     {
     76       if (count + 1 >= alloc)
     77 	{
     78 	  alloc *= 2;
     79 	  data = xrealloc (data, alloc);
     80 	}
     81       data[count++] = c;
     82       c = getchar();
     83     }
     84   lineno++;
     85   data[count] = '\0';
     86 
     87   buf->data = data;
     88   buf->alloced = alloc;
     89 }
     90 
     91 /* If we have mmap() and mprotect(), copy the string S just before a
     92    protected page, so that if the demangler runs over the end of the
     93    string we'll get a fault, and return the address of the new string.
     94    If no mmap, or it fails, or it looks too hard, just return S.  */
     95 
     96 #ifdef HAVE_SYS_MMAN_H
     97 #include <sys/mman.h>
     98 #endif
     99 #if defined(MAP_ANON) && ! defined (MAP_ANONYMOUS)
    100 #define MAP_ANONYMOUS MAP_ANON
    101 #endif
    102 
    103 static const char *
    104 protect_end (const char * s)
    105 {
    106 #if defined(HAVE_MMAP) && defined (MAP_ANONYMOUS)
    107   size_t pagesize = getpagesize();
    108   static char * buf;
    109   size_t s_len = strlen (s);
    110   char * result;
    111 
    112   /* Don't try if S is too long.  */
    113   if (s_len >= pagesize)
    114     return s;
    115 
    116   /* Allocate one page of allocated space followed by an unmapped
    117      page.  */
    118   if (buf == NULL)
    119     {
    120       buf = mmap (NULL, pagesize * 2, PROT_READ | PROT_WRITE,
    121 		  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    122       if (! buf)
    123 	return s;
    124       munmap (buf + pagesize, pagesize);
    125     }
    126 
    127   result = buf + (pagesize - s_len - 1);
    128   memcpy (result, s, s_len + 1);
    129   return result;
    130 #else
    131   return s;
    132 #endif
    133 }
    134 
    135 static void
    136 fail (int lineno, const char *opts, const char *in,
    137       const char *out, const char *exp)
    138 {
    139   printf ("\
    140 FAIL at line %d, options %s:\n\
    141 in:  %s\n\
    142 out: %s\n\
    143 exp: %s\n",
    144 	  lineno, opts, in, out != NULL ? out : "(null)", exp);
    145 }
    146 
    147 /* The tester operates on a data file consisting of groups of lines:
    148    options
    149    input to be demangled
    150    expected output
    151 
    152    Supported options:
    153      --format=<name>     Sets the demangling style.
    154      --no-params         There are two lines of expected output; the first
    155                          is with DMGL_PARAMS, the second is without it.
    156      --is-v3-ctor        Calls is_gnu_v3_mangled_ctor on input; expected
    157                          output is an integer representing ctor_kind.
    158      --is-v3-dtor        Likewise, but for dtors.
    159      --ret-postfix       Passes the DMGL_RET_POSTFIX option
    160      --ret-drop          Passes the DMGL_RET_DROP option
    161 
    162    For compatibility, just in case it matters, the options line may be
    163    empty, to mean --format=auto.  If it doesn't start with --, then it
    164    may contain only a format name.
    165 */
    166 
    167 int
    168 main(int argc, char **argv)
    169 {
    170   enum demangling_styles style = auto_demangling;
    171   int no_params;
    172   int is_v3_ctor;
    173   int is_v3_dtor;
    174   int ret_postfix, ret_drop;
    175   struct line format;
    176   struct line input;
    177   struct line expect;
    178   char *result;
    179   int failures = 0;
    180   int tests = 0;
    181 
    182   if (argc > 1)
    183     {
    184       fprintf (stderr, "usage: %s < test-set\n", argv[0]);
    185       return 2;
    186     }
    187 
    188   format.data = 0;
    189   input.data = 0;
    190   expect.data = 0;
    191 
    192   for (;;)
    193     {
    194       const char *inp;
    195 
    196       get_line (&format);
    197       if (feof (stdin))
    198 	break;
    199 
    200       get_line (&input);
    201       get_line (&expect);
    202 
    203       inp = protect_end (input.data);
    204 
    205       tests++;
    206 
    207       no_params = 0;
    208       ret_postfix = 0;
    209       ret_drop = 0;
    210       is_v3_ctor = 0;
    211       is_v3_dtor = 0;
    212       if (format.data[0] == '\0')
    213 	style = auto_demangling;
    214       else if (format.data[0] != '-')
    215 	{
    216 	  style = cplus_demangle_name_to_style (format.data);
    217 	  if (style == unknown_demangling)
    218 	    {
    219 	      printf ("FAIL at line %d: unknown demangling style %s\n",
    220 		      lineno, format.data);
    221 	      failures++;
    222 	      continue;
    223 	    }
    224 	}
    225       else
    226 	{
    227 	  char *p;
    228 	  char *opt;
    229 
    230 	  p = format.data;
    231 	  while (*p != '\0')
    232 	    {
    233 	      char c;
    234 
    235 	      opt = p;
    236 	      p += strcspn (p, " \t=");
    237 	      c = *p;
    238 	      *p = '\0';
    239 	      if (strcmp (opt, "--format") == 0 && c == '=')
    240 		{
    241 		  char *fstyle;
    242 
    243 		  *p = c;
    244 		  ++p;
    245 		  fstyle = p;
    246 		  p += strcspn (p, " \t");
    247 		  c = *p;
    248 		  *p = '\0';
    249 		  style = cplus_demangle_name_to_style (fstyle);
    250 		  if (style == unknown_demangling)
    251 		    {
    252 		      printf ("FAIL at line %d: unknown demangling style %s\n",
    253 			      lineno, fstyle);
    254 		      failures++;
    255 		      continue;
    256 		    }
    257 		}
    258 	      else if (strcmp (opt, "--no-params") == 0)
    259 		no_params = 1;
    260 	      else if (strcmp (opt, "--is-v3-ctor") == 0)
    261 		is_v3_ctor = 1;
    262 	      else if (strcmp (opt, "--is-v3-dtor") == 0)
    263 		is_v3_dtor = 1;
    264 	      else if (strcmp (opt, "--ret-postfix") == 0)
    265 		ret_postfix = 1;
    266 	      else if (strcmp (opt, "--ret-drop") == 0)
    267 		ret_drop = 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, (DMGL_PARAMS | DMGL_ANSI | DMGL_TYPES
    311 				     | (ret_postfix ? DMGL_RET_POSTFIX : 0)
    312 				     | (ret_drop ? DMGL_RET_DROP : 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 	  get_line (&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 }
    346