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
36struct line
37{
38  size_t alloced;
39  char *data;
40};
41
42static unsigned int lineno;
43
44/* Safely read a single line of arbitrary length from standard input.  */
45
46#define LINELEN 80
47
48static void
49getline(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
101static const char *
102protect_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
133static void
134fail (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 ("\
142FAIL at line %d, options %s:\n\
143in:  %s\n\
144out: %s\n\
145exp: %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
168int
169main(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}
346