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