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 89259694Spfg/* If we have mmap() and mprotect(), copy the string S just before a 90259694Spfg protected page, so that if the demangler runs over the end of the 91259694Spfg string we'll get a fault, and return the address of the new string. 92259694Spfg If no mmap, or it fails, or it looks too hard, just return S. */ 93259694Spfg 94259694Spfg#ifdef HAVE_SYS_MMAN_H 95259694Spfg#include <sys/mman.h> 96259694Spfg#endif 97259694Spfg#if defined(MAP_ANON) && ! defined (MAP_ANONYMOUS) 98259694Spfg#define MAP_ANONYMOUS MAP_ANON 99259694Spfg#endif 100259694Spfg 101259694Spfgstatic const char * 102259694Spfgprotect_end (const char * s) 103259694Spfg{ 104259694Spfg#if defined(HAVE_MMAP) && defined (MAP_ANONYMOUS) 105259694Spfg size_t pagesize = getpagesize(); 106259694Spfg static char * buf; 107259694Spfg size_t s_len = strlen (s); 108259694Spfg char * result; 109259694Spfg 110259694Spfg /* Don't try if S is too long. */ 111259694Spfg if (s_len >= pagesize) 112259694Spfg return s; 113259694Spfg 114259694Spfg /* Allocate one page of allocated space followed by an unmapped 115259694Spfg page. */ 116259694Spfg if (buf == NULL) 117259694Spfg { 118259694Spfg buf = mmap (NULL, pagesize * 2, PROT_READ | PROT_WRITE, 119259694Spfg MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 120259694Spfg if (! buf) 121259694Spfg return s; 122259694Spfg munmap (buf + pagesize, pagesize); 123259694Spfg } 124259694Spfg 125259694Spfg result = buf + (pagesize - s_len - 1); 126259694Spfg memcpy (result, s, s_len + 1); 127259694Spfg return result; 128259694Spfg#else 129259694Spfg return s; 130259694Spfg#endif 131259694Spfg} 132259694Spfg 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 { 197259694Spfg const char *inp; 198259694Spfg 199169695Skan getline (&format); 200169695Skan if (feof (stdin)) 201169695Skan break; 202169695Skan 203169695Skan getline (&input); 204169695Skan getline (&expect); 205169695Skan 206259694Spfg inp = protect_end (input.data); 207259694Spfg 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 288259694Spfg 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 295259694Spfg 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 310259694Spfg 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); 326259694Spfg 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