1169695Skan/* Demangler test program,
2169695Skan   Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
3169695Skan   Written by Zack Weinberg <zack@codesourcery.com
4169695Skan
5169695Skan   This file is part of GNU libiberty.
6169695Skan
7169695Skan   This program is free software; you can redistribute it and/or modify
8169695Skan   it under the terms of the GNU General Public License as published by
9169695Skan   the Free Software Foundation; either version 2 of the License, or
10169695Skan   (at your option) any later version.
11169695Skan
12169695Skan   This program is distributed in the hope that it will be useful,
13169695Skan   but WITHOUT ANY WARRANTY; without even the implied warranty of
14169695Skan   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15169695Skan   GNU General Public License for more details.
16169695Skan
17169695Skan   You should have received a copy of the GNU General Public License
18169695Skan   along with this program; if not, write to the Free Software
19169695Skan   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20169695Skan*/
21169695Skan
22169695Skan#ifdef HAVE_CONFIG_H
23169695Skan#include "config.h"
24169695Skan#endif
25169695Skan#include "ansidecl.h"
26169695Skan#include <stdio.h>
27169695Skan#include "libiberty.h"
28169695Skan#include "demangle.h"
29169695Skan#ifdef HAVE_STRING_H
30169695Skan#include <string.h>
31169695Skan#endif
32169695Skan#if HAVE_STDLIB_H
33169695Skan# include <stdlib.h>
34169695Skan#endif
35169695Skan
36169695Skanstruct line
37169695Skan{
38169695Skan  size_t alloced;
39169695Skan  char *data;
40169695Skan};
41169695Skan
42169695Skanstatic unsigned int lineno;
43169695Skan
44169695Skan/* Safely read a single line of arbitrary length from standard input.  */
45169695Skan
46169695Skan#define LINELEN 80
47169695Skan
48169695Skanstatic void
49169695Skangetline(buf)
50169695Skan     struct line *buf;
51169695Skan{
52169695Skan  char *data = buf->data;
53169695Skan  size_t alloc = buf->alloced;
54169695Skan  size_t count = 0;
55169695Skan  int c;
56169695Skan
57169695Skan  if (data == 0)
58169695Skan    {
59169695Skan      data = xmalloc (LINELEN);
60169695Skan      alloc = LINELEN;
61169695Skan    }
62169695Skan
63169695Skan  /* Skip comment lines.  */
64169695Skan  while ((c = getchar()) == '#')
65169695Skan    {
66169695Skan      while ((c = getchar()) != EOF && c != '\n');
67169695Skan      lineno++;
68169695Skan    }
69169695Skan
70169695Skan  /* c is the first character on the line, and it's not a comment
71169695Skan     line: copy this line into the buffer and return.  */
72169695Skan  while (c != EOF && c != '\n')
73169695Skan    {
74169695Skan      if (count + 1 >= alloc)
75169695Skan	{
76169695Skan	  alloc *= 2;
77169695Skan	  data = xrealloc (data, alloc);
78169695Skan	}
79169695Skan      data[count++] = c;
80169695Skan      c = getchar();
81169695Skan    }
82169695Skan  lineno++;
83169695Skan  data[count] = '\0';
84169695Skan
85169695Skan  buf->data = data;
86169695Skan  buf->alloced = alloc;
87169695Skan}
88169695Skan
89258817Spfg/* If we have mmap() and mprotect(), copy the string S just before a
90258817Spfg   protected page, so that if the demangler runs over the end of the
91258817Spfg   string we'll get a fault, and return the address of the new string.
92258817Spfg   If no mmap, or it fails, or it looks too hard, just return S.  */
93258817Spfg
94258817Spfg#ifdef HAVE_SYS_MMAN_H
95258817Spfg#include <sys/mman.h>
96258817Spfg#endif
97258817Spfg#if defined(MAP_ANON) && ! defined (MAP_ANONYMOUS)
98258817Spfg#define MAP_ANONYMOUS MAP_ANON
99258817Spfg#endif
100258817Spfg
101258817Spfgstatic const char *
102258817Spfgprotect_end (const char * s)
103258817Spfg{
104258817Spfg#if defined(HAVE_MMAP) && defined (MAP_ANONYMOUS)
105258817Spfg  size_t pagesize = getpagesize();
106258817Spfg  static char * buf;
107258817Spfg  size_t s_len = strlen (s);
108258817Spfg  char * result;
109258817Spfg
110258817Spfg  /* Don't try if S is too long.  */
111258817Spfg  if (s_len >= pagesize)
112258817Spfg    return s;
113258817Spfg
114258817Spfg  /* Allocate one page of allocated space followed by an unmapped
115258817Spfg     page.  */
116258817Spfg  if (buf == NULL)
117258817Spfg    {
118258817Spfg      buf = mmap (NULL, pagesize * 2, PROT_READ | PROT_WRITE,
119258817Spfg		  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
120258817Spfg      if (! buf)
121258817Spfg	return s;
122258817Spfg      munmap (buf + pagesize, pagesize);
123258817Spfg    }
124258817Spfg
125258817Spfg  result = buf + (pagesize - s_len - 1);
126258817Spfg  memcpy (result, s, s_len + 1);
127258817Spfg  return result;
128258817Spfg#else
129258817Spfg  return s;
130258817Spfg#endif
131258817Spfg}
132258817Spfg
133169695Skanstatic void
134169695Skanfail (lineno, opts, in, out, exp)
135169695Skan     int lineno;
136169695Skan     const char *opts;
137169695Skan     const char *in;
138169695Skan     const char *out;
139169695Skan     const char *exp;
140169695Skan{
141169695Skan  printf ("\
142169695SkanFAIL at line %d, options %s:\n\
143169695Skanin:  %s\n\
144169695Skanout: %s\n\
145169695Skanexp: %s\n",
146169695Skan	  lineno, opts, in, out != NULL ? out : "(null)", exp);
147169695Skan}
148169695Skan
149169695Skan/* The tester operates on a data file consisting of groups of lines:
150169695Skan   options
151169695Skan   input to be demangled
152169695Skan   expected output
153169695Skan
154169695Skan   Supported options:
155169695Skan     --format=<name>     Sets the demangling style.
156169695Skan     --no-params         There are two lines of expected output; the first
157169695Skan                         is with DMGL_PARAMS, the second is without it.
158169695Skan     --is-v3-ctor        Calls is_gnu_v3_mangled_ctor on input; expected
159169695Skan                         output is an integer representing ctor_kind.
160169695Skan     --is-v3-dtor        Likewise, but for dtors.
161169695Skan     --ret-postfix       Passes the DMGL_RET_POSTFIX option
162169695Skan
163169695Skan   For compatibility, just in case it matters, the options line may be
164169695Skan   empty, to mean --format=auto.  If it doesn't start with --, then it
165169695Skan   may contain only a format name.
166169695Skan*/
167169695Skan
168169695Skanint
169169695Skanmain(argc, argv)
170169695Skan     int argc;
171169695Skan     char **argv;
172169695Skan{
173169695Skan  enum demangling_styles style = auto_demangling;
174169695Skan  int no_params;
175169695Skan  int is_v3_ctor;
176169695Skan  int is_v3_dtor;
177169695Skan  int ret_postfix;
178169695Skan  struct line format;
179169695Skan  struct line input;
180169695Skan  struct line expect;
181169695Skan  char *result;
182169695Skan  int failures = 0;
183169695Skan  int tests = 0;
184169695Skan
185169695Skan  if (argc > 1)
186169695Skan    {
187169695Skan      fprintf (stderr, "usage: %s < test-set\n", argv[0]);
188169695Skan      return 2;
189169695Skan    }
190169695Skan
191169695Skan  format.data = 0;
192169695Skan  input.data = 0;
193169695Skan  expect.data = 0;
194169695Skan
195169695Skan  for (;;)
196169695Skan    {
197258817Spfg      const char *inp;
198258817Spfg
199169695Skan      getline (&format);
200169695Skan      if (feof (stdin))
201169695Skan	break;
202169695Skan
203169695Skan      getline (&input);
204169695Skan      getline (&expect);
205169695Skan
206258817Spfg      inp = protect_end (input.data);
207258817Spfg
208169695Skan      tests++;
209169695Skan
210169695Skan      no_params = 0;
211169695Skan      ret_postfix = 0;
212169695Skan      is_v3_ctor = 0;
213169695Skan      is_v3_dtor = 0;
214169695Skan      if (format.data[0] == '\0')
215169695Skan	style = auto_demangling;
216169695Skan      else if (format.data[0] != '-')
217169695Skan	{
218169695Skan	  style = cplus_demangle_name_to_style (format.data);
219169695Skan	  if (style == unknown_demangling)
220169695Skan	    {
221169695Skan	      printf ("FAIL at line %d: unknown demangling style %s\n",
222169695Skan		      lineno, format.data);
223169695Skan	      failures++;
224169695Skan	      continue;
225169695Skan	    }
226169695Skan	}
227169695Skan      else
228169695Skan	{
229169695Skan	  char *p;
230169695Skan	  char *opt;
231169695Skan
232169695Skan	  p = format.data;
233169695Skan	  while (*p != '\0')
234169695Skan	    {
235169695Skan	      char c;
236169695Skan
237169695Skan	      opt = p;
238169695Skan	      p += strcspn (p, " \t=");
239169695Skan	      c = *p;
240169695Skan	      *p = '\0';
241169695Skan	      if (strcmp (opt, "--format") == 0 && c == '=')
242169695Skan		{
243169695Skan		  char *fstyle;
244169695Skan
245169695Skan		  *p = c;
246169695Skan		  ++p;
247169695Skan		  fstyle = p;
248169695Skan		  p += strcspn (p, " \t");
249169695Skan		  c = *p;
250169695Skan		  *p = '\0';
251169695Skan		  style = cplus_demangle_name_to_style (fstyle);
252169695Skan		  if (style == unknown_demangling)
253169695Skan		    {
254169695Skan		      printf ("FAIL at line %d: unknown demangling style %s\n",
255169695Skan			      lineno, fstyle);
256169695Skan		      failures++;
257169695Skan		      continue;
258169695Skan		    }
259169695Skan		}
260169695Skan	      else if (strcmp (opt, "--no-params") == 0)
261169695Skan		no_params = 1;
262169695Skan	      else if (strcmp (opt, "--is-v3-ctor") == 0)
263169695Skan		is_v3_ctor = 1;
264169695Skan	      else if (strcmp (opt, "--is-v3-dtor") == 0)
265169695Skan		is_v3_dtor = 1;
266169695Skan	      else if (strcmp (opt, "--ret-postfix") == 0)
267169695Skan		ret_postfix = 1;
268169695Skan	      else
269169695Skan		{
270169695Skan		  printf ("FAIL at line %d: unrecognized option %s\n",
271169695Skan			  lineno, opt);
272169695Skan		  failures++;
273169695Skan		  continue;
274169695Skan		}
275169695Skan	      *p = c;
276169695Skan	      p += strspn (p, " \t");
277169695Skan	    }
278169695Skan	}
279169695Skan
280169695Skan      if (is_v3_ctor || is_v3_dtor)
281169695Skan	{
282169695Skan	  char buf[20];
283169695Skan
284169695Skan	  if (is_v3_ctor)
285169695Skan	    {
286169695Skan	      enum gnu_v3_ctor_kinds kc;
287169695Skan
288258817Spfg	      kc = is_gnu_v3_mangled_ctor (inp);
289169695Skan	      sprintf (buf, "%d", (int) kc);
290169695Skan	    }
291169695Skan	  else
292169695Skan	    {
293169695Skan	      enum gnu_v3_dtor_kinds kd;
294169695Skan
295258817Spfg	      kd = is_gnu_v3_mangled_dtor (inp);
296169695Skan	      sprintf (buf, "%d", (int) kd);
297169695Skan	    }
298169695Skan
299169695Skan	  if (strcmp (buf, expect.data) != 0)
300169695Skan	    {
301169695Skan	      fail (lineno, format.data, input.data, buf, expect.data);
302169695Skan	      failures++;
303169695Skan	    }
304169695Skan
305169695Skan	  continue;
306169695Skan	}
307169695Skan
308169695Skan      cplus_demangle_set_style (style);
309169695Skan
310258817Spfg      result = cplus_demangle (inp,
311169695Skan			       DMGL_PARAMS|DMGL_ANSI|DMGL_TYPES
312169695Skan			       |(ret_postfix ? DMGL_RET_POSTFIX : 0));
313169695Skan
314169695Skan      if (result
315169695Skan	  ? strcmp (result, expect.data)
316169695Skan	  : strcmp (input.data, expect.data))
317169695Skan	{
318169695Skan	  fail (lineno, format.data, input.data, result, expect.data);
319169695Skan	  failures++;
320169695Skan	}
321169695Skan      free (result);
322169695Skan
323169695Skan      if (no_params)
324169695Skan	{
325169695Skan	  getline (&expect);
326258817Spfg	  result = cplus_demangle (inp, DMGL_ANSI|DMGL_TYPES);
327169695Skan
328169695Skan	  if (result
329169695Skan	      ? strcmp (result, expect.data)
330169695Skan	      : strcmp (input.data, expect.data))
331169695Skan	    {
332169695Skan	      fail (lineno, format.data, input.data, result, expect.data);
333169695Skan	      failures++;
334169695Skan	    }
335169695Skan	  free (result);
336169695Skan	}
337169695Skan    }
338169695Skan
339169695Skan  free (format.data);
340169695Skan  free (input.data);
341169695Skan  free (expect.data);
342169695Skan
343169695Skan  printf ("%s: %d tests, %d failures\n", argv[0], tests, failures);
344169695Skan  return failures ? 1 : 0;
345169695Skan}
346