1 /* Demangler test program, 2 Copyright (C) 2002, 2003, 2004 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(buf) 53 struct line *buf; 54 { 55 char *data = buf->data; 56 size_t alloc = buf->alloced; 57 size_t count = 0; 58 int c; 59 60 if (data == 0) 61 { 62 data = xmalloc (LINELEN); 63 alloc = LINELEN; 64 } 65 66 /* Skip comment lines. */ 67 while ((c = getchar()) == '#') 68 { 69 while ((c = getchar()) != EOF && c != '\n'); 70 lineno++; 71 } 72 73 /* c is the first character on the line, and it's not a comment 74 line: copy this line into the buffer and return. */ 75 while (c != EOF && c != '\n') 76 { 77 if (count + 1 >= alloc) 78 { 79 alloc *= 2; 80 data = xrealloc (data, alloc); 81 } 82 data[count++] = c; 83 c = getchar(); 84 } 85 lineno++; 86 data[count] = '\0'; 87 88 buf->data = data; 89 buf->alloced = alloc; 90 } 91 92 /* If we have mmap() and mprotect(), copy the string S just before a 93 protected page, so that if the demangler runs over the end of the 94 string we'll get a fault, and return the address of the new string. 95 If no mmap, or it fails, or it looks too hard, just return S. */ 96 97 #ifdef HAVE_SYS_MMAN_H 98 #include <sys/mman.h> 99 #endif 100 #if defined(MAP_ANON) && ! defined (MAP_ANONYMOUS) 101 #define MAP_ANONYMOUS MAP_ANON 102 #endif 103 104 static const char * 105 protect_end (const char * s) 106 { 107 #if defined(HAVE_MMAP) && defined (MAP_ANONYMOUS) 108 size_t pagesize = getpagesize(); 109 static char * buf; 110 size_t s_len = strlen (s); 111 char * result; 112 113 /* Don't try if S is too long. */ 114 if (s_len >= pagesize) 115 return s; 116 117 /* Allocate one page of allocated space followed by an unmapped 118 page. */ 119 if (buf == NULL) 120 { 121 buf = mmap (NULL, pagesize * 2, PROT_READ | PROT_WRITE, 122 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 123 if (! buf) 124 return s; 125 munmap (buf + pagesize, pagesize); 126 } 127 128 result = buf + (pagesize - s_len - 1); 129 memcpy (result, s, s_len + 1); 130 return result; 131 #else 132 return s; 133 #endif 134 } 135 136 static void 137 fail (lineno, opts, in, out, exp) 138 int lineno; 139 const char *opts; 140 const char *in; 141 const char *out; 142 const char *exp; 143 { 144 printf ("\ 145 FAIL at line %d, options %s:\n\ 146 in: %s\n\ 147 out: %s\n\ 148 exp: %s\n", 149 lineno, opts, in, out != NULL ? out : "(null)", exp); 150 } 151 152 /* The tester operates on a data file consisting of groups of lines: 153 options 154 input to be demangled 155 expected output 156 157 Supported options: 158 --format=<name> Sets the demangling style. 159 --no-params There are two lines of expected output; the first 160 is with DMGL_PARAMS, the second is without it. 161 --is-v3-ctor Calls is_gnu_v3_mangled_ctor on input; expected 162 output is an integer representing ctor_kind. 163 --is-v3-dtor Likewise, but for dtors. 164 --ret-postfix Passes the DMGL_RET_POSTFIX option 165 --ret-drop Passes the DMGL_RET_DROP option 166 167 For compatibility, just in case it matters, the options line may be 168 empty, to mean --format=auto. If it doesn't start with --, then it 169 may contain only a format name. 170 */ 171 172 int 173 main(argc, argv) 174 int argc; 175 char **argv; 176 { 177 enum demangling_styles style = auto_demangling; 178 int no_params; 179 int is_v3_ctor; 180 int is_v3_dtor; 181 int ret_postfix, ret_drop; 182 struct line format; 183 struct line input; 184 struct line expect; 185 char *result; 186 int failures = 0; 187 int tests = 0; 188 189 if (argc > 1) 190 { 191 fprintf (stderr, "usage: %s < test-set\n", argv[0]); 192 return 2; 193 } 194 195 format.data = 0; 196 input.data = 0; 197 expect.data = 0; 198 199 for (;;) 200 { 201 const char *inp; 202 203 get_line (&format); 204 if (feof (stdin)) 205 break; 206 207 get_line (&input); 208 get_line (&expect); 209 210 inp = protect_end (input.data); 211 212 tests++; 213 214 no_params = 0; 215 ret_postfix = 0; 216 ret_drop = 0; 217 is_v3_ctor = 0; 218 is_v3_dtor = 0; 219 if (format.data[0] == '\0') 220 style = auto_demangling; 221 else if (format.data[0] != '-') 222 { 223 style = cplus_demangle_name_to_style (format.data); 224 if (style == unknown_demangling) 225 { 226 printf ("FAIL at line %d: unknown demangling style %s\n", 227 lineno, format.data); 228 failures++; 229 continue; 230 } 231 } 232 else 233 { 234 char *p; 235 char *opt; 236 237 p = format.data; 238 while (*p != '\0') 239 { 240 char c; 241 242 opt = p; 243 p += strcspn (p, " \t="); 244 c = *p; 245 *p = '\0'; 246 if (strcmp (opt, "--format") == 0 && c == '=') 247 { 248 char *fstyle; 249 250 *p = c; 251 ++p; 252 fstyle = p; 253 p += strcspn (p, " \t"); 254 c = *p; 255 *p = '\0'; 256 style = cplus_demangle_name_to_style (fstyle); 257 if (style == unknown_demangling) 258 { 259 printf ("FAIL at line %d: unknown demangling style %s\n", 260 lineno, fstyle); 261 failures++; 262 continue; 263 } 264 } 265 else if (strcmp (opt, "--no-params") == 0) 266 no_params = 1; 267 else if (strcmp (opt, "--is-v3-ctor") == 0) 268 is_v3_ctor = 1; 269 else if (strcmp (opt, "--is-v3-dtor") == 0) 270 is_v3_dtor = 1; 271 else if (strcmp (opt, "--ret-postfix") == 0) 272 ret_postfix = 1; 273 else if (strcmp (opt, "--ret-drop") == 0) 274 ret_drop = 1; 275 else 276 { 277 printf ("FAIL at line %d: unrecognized option %s\n", 278 lineno, opt); 279 failures++; 280 continue; 281 } 282 *p = c; 283 p += strspn (p, " \t"); 284 } 285 } 286 287 if (is_v3_ctor || is_v3_dtor) 288 { 289 char buf[20]; 290 291 if (is_v3_ctor) 292 { 293 enum gnu_v3_ctor_kinds kc; 294 295 kc = is_gnu_v3_mangled_ctor (inp); 296 sprintf (buf, "%d", (int) kc); 297 } 298 else 299 { 300 enum gnu_v3_dtor_kinds kd; 301 302 kd = is_gnu_v3_mangled_dtor (inp); 303 sprintf (buf, "%d", (int) kd); 304 } 305 306 if (strcmp (buf, expect.data) != 0) 307 { 308 fail (lineno, format.data, input.data, buf, expect.data); 309 failures++; 310 } 311 312 continue; 313 } 314 315 cplus_demangle_set_style (style); 316 317 result = cplus_demangle (inp, (DMGL_PARAMS | DMGL_ANSI | DMGL_TYPES 318 | (ret_postfix ? DMGL_RET_POSTFIX : 0) 319 | (ret_drop ? DMGL_RET_DROP : 0))); 320 321 if (result 322 ? strcmp (result, expect.data) 323 : strcmp (input.data, expect.data)) 324 { 325 fail (lineno, format.data, input.data, result, expect.data); 326 failures++; 327 } 328 free (result); 329 330 if (no_params) 331 { 332 get_line (&expect); 333 result = cplus_demangle (inp, DMGL_ANSI|DMGL_TYPES); 334 335 if (result 336 ? strcmp (result, expect.data) 337 : strcmp (input.data, expect.data)) 338 { 339 fail (lineno, format.data, input.data, result, expect.data); 340 failures++; 341 } 342 free (result); 343 } 344 } 345 346 free (format.data); 347 free (input.data); 348 free (expect.data); 349 350 printf ("%s: %d tests, %d failures\n", argv[0], tests, failures); 351 return failures ? 1 : 0; 352 } 353