|
|
1.1 ! root 1: /* Demangler for GNU C++ ! 2: Copyright 1989, 1991 Free Software Foundation, Inc. ! 3: Written by James Clark ([email protected]) ! 4: Rewritten by Fred Fish ([email protected]) for ARM and Lucid demangling ! 5: ! 6: This file is part of the libiberty library. ! 7: Libiberty is free software; you can redistribute it and/or ! 8: modify it under the terms of the GNU Library General Public ! 9: License as published by the Free Software Foundation; either ! 10: version 2 of the License, or (at your option) any later version. ! 11: ! 12: Libiberty 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 GNU ! 15: Library General Public License for more details. ! 16: ! 17: You should have received a copy of the GNU Library General Public ! 18: License along with libiberty; see the file COPYING.LIB. If ! 19: not, write to the Free Software Foundation, Inc., 675 Mass Ave, ! 20: Cambridge, MA 02139, USA. */ ! 21: ! 22: /* This file exports two functions; cplus_mangle_opname and cplus_demangle. ! 23: ! 24: This file imports xmalloc and xrealloc, which are like malloc and ! 25: realloc except that they generate a fatal error if there is no ! 26: available memory. */ ! 27: ! 28: #include "demangle.h" ! 29: #undef CURRENT_DEMANGLING_STYLE ! 30: #define CURRENT_DEMANGLING_STYLE work->options ! 31: #include <ctype.h> ! 32: #include <string.h> ! 33: #include <stdio.h> ! 34: ! 35: extern char *xmalloc PARAMS((long)); ! 36: extern char *xrealloc PARAMS((PTR, long)); ! 37: extern char *strstr PARAMS ((const char *, const char *)); ! 38: extern void free PARAMS((PTR)); ! 39: ! 40: /* In order to allow a single demangler executable to demangle strings ! 41: using various common values of CPLUS_MARKER, as well as any specific ! 42: one set at compile time, we maintain a string containing all the ! 43: commonly used ones, and check to see if the marker we are looking for ! 44: is in that string. CPLUS_MARKER is usually '$' on systems where the ! 45: assembler can deal with that. Where the assembler can't, it's usually ! 46: '.' (but on many systems '.' is used for other things). We put the ! 47: current defined CPLUS_MARKER first (which defaults to '$'), followed ! 48: by the next most common value, followed by an explicit '$' in case ! 49: the value of CPLUS_MARKER is not '$'. ! 50: ! 51: We could avoid this if we could just get g++ to tell us what the actual ! 52: cplus marker character is as part of the debug information, perhaps by ! 53: ensuring that it is the character that terminates the gcc<n>_compiled ! 54: marker symbol (FIXME). */ ! 55: ! 56: #if !defined (CPLUS_MARKER) ! 57: #define CPLUS_MARKER '$' ! 58: #endif ! 59: ! 60: enum demangling_styles current_demangling_style = gnu_demangling; ! 61: ! 62: static char cplus_markers[] = { CPLUS_MARKER, '.', '$', '\0' }; ! 63: ! 64: void ! 65: set_cplus_marker_for_demangling (ch) ! 66: int ch; ! 67: { ! 68: cplus_markers[0] = ch; ! 69: } ! 70: ! 71: /* Stuff that is shared between sub-routines. ! 72: * Using a shared structure allows cplus_demangle to be reentrant. */ ! 73: ! 74: struct work_stuff ! 75: { ! 76: int options; ! 77: char **typevec; ! 78: int ntypes; ! 79: int typevec_size; ! 80: int constructor; ! 81: int destructor; ! 82: int static_type; /* A static member function */ ! 83: int const_type; /* A const member function */ ! 84: }; ! 85: ! 86: #define PRINT_ANSI_QUALIFIERS (work -> options & DMGL_ANSI) ! 87: #define PRINT_ARG_TYPES (work -> options & DMGL_PARAMS) ! 88: ! 89: static CONST struct optable ! 90: { ! 91: CONST char *in; ! 92: CONST char *out; ! 93: int flags; ! 94: } optable[] = { ! 95: {"nw", " new", DMGL_ANSI}, /* new (1.92, ansi) */ ! 96: {"dl", " delete", DMGL_ANSI}, /* new (1.92, ansi) */ ! 97: {"new", " new", 0}, /* old (1.91, and 1.x) */ ! 98: {"delete", " delete", 0}, /* old (1.91, and 1.x) */ ! 99: {"as", "=", DMGL_ANSI}, /* ansi */ ! 100: {"ne", "!=", DMGL_ANSI}, /* old, ansi */ ! 101: {"eq", "==", DMGL_ANSI}, /* old, ansi */ ! 102: {"ge", ">=", DMGL_ANSI}, /* old, ansi */ ! 103: {"gt", ">", DMGL_ANSI}, /* old, ansi */ ! 104: {"le", "<=", DMGL_ANSI}, /* old, ansi */ ! 105: {"lt", "<", DMGL_ANSI}, /* old, ansi */ ! 106: {"plus", "+", 0}, /* old */ ! 107: {"pl", "+", DMGL_ANSI}, /* ansi */ ! 108: {"apl", "+=", DMGL_ANSI}, /* ansi */ ! 109: {"minus", "-", 0}, /* old */ ! 110: {"mi", "-", DMGL_ANSI}, /* ansi */ ! 111: {"ami", "-=", DMGL_ANSI}, /* ansi */ ! 112: {"mult", "*", 0}, /* old */ ! 113: {"ml", "*", DMGL_ANSI}, /* ansi */ ! 114: {"amu", "*=", DMGL_ANSI}, /* ansi (ARM/Lucid) */ ! 115: {"aml", "*=", DMGL_ANSI}, /* ansi (GNU/g++) */ ! 116: {"convert", "+", 0}, /* old (unary +) */ ! 117: {"negate", "-", 0}, /* old (unary -) */ ! 118: {"trunc_mod", "%", 0}, /* old */ ! 119: {"md", "%", DMGL_ANSI}, /* ansi */ ! 120: {"amd", "%=", DMGL_ANSI}, /* ansi */ ! 121: {"trunc_div", "/", 0}, /* old */ ! 122: {"dv", "/", DMGL_ANSI}, /* ansi */ ! 123: {"adv", "/=", DMGL_ANSI}, /* ansi */ ! 124: {"truth_andif", "&&", 0}, /* old */ ! 125: {"aa", "&&", DMGL_ANSI}, /* ansi */ ! 126: {"truth_orif", "||", 0}, /* old */ ! 127: {"oo", "||", DMGL_ANSI}, /* ansi */ ! 128: {"truth_not", "!", 0}, /* old */ ! 129: {"nt", "!", DMGL_ANSI}, /* ansi */ ! 130: {"postincrement","++", 0}, /* old */ ! 131: {"pp", "++", DMGL_ANSI}, /* ansi */ ! 132: {"postdecrement","--", 0}, /* old */ ! 133: {"mm", "--", DMGL_ANSI}, /* ansi */ ! 134: {"bit_ior", "|", 0}, /* old */ ! 135: {"or", "|", DMGL_ANSI}, /* ansi */ ! 136: {"aor", "|=", DMGL_ANSI}, /* ansi */ ! 137: {"bit_xor", "^", 0}, /* old */ ! 138: {"er", "^", DMGL_ANSI}, /* ansi */ ! 139: {"aer", "^=", DMGL_ANSI}, /* ansi */ ! 140: {"bit_and", "&", 0}, /* old */ ! 141: {"ad", "&", DMGL_ANSI}, /* ansi */ ! 142: {"aad", "&=", DMGL_ANSI}, /* ansi */ ! 143: {"bit_not", "~", 0}, /* old */ ! 144: {"co", "~", DMGL_ANSI}, /* ansi */ ! 145: {"call", "()", 0}, /* old */ ! 146: {"cl", "()", DMGL_ANSI}, /* ansi */ ! 147: {"alshift", "<<", 0}, /* old */ ! 148: {"ls", "<<", DMGL_ANSI}, /* ansi */ ! 149: {"als", "<<=", DMGL_ANSI}, /* ansi */ ! 150: {"arshift", ">>", 0}, /* old */ ! 151: {"rs", ">>", DMGL_ANSI}, /* ansi */ ! 152: {"ars", ">>=", DMGL_ANSI}, /* ansi */ ! 153: {"component", "->", 0}, /* old */ ! 154: {"pt", "->", DMGL_ANSI}, /* ansi; Lucid C++ form */ ! 155: {"rf", "->", DMGL_ANSI}, /* ansi; ARM/GNU form */ ! 156: {"indirect", "*", 0}, /* old */ ! 157: {"method_call", "->()", 0}, /* old */ ! 158: {"addr", "&", 0}, /* old (unary &) */ ! 159: {"array", "[]", 0}, /* old */ ! 160: {"vc", "[]", DMGL_ANSI}, /* ansi */ ! 161: {"compound", ", ", 0}, /* old */ ! 162: {"cm", ", ", DMGL_ANSI}, /* ansi */ ! 163: {"cond", "?:", 0}, /* old */ ! 164: {"cn", "?:", DMGL_ANSI}, /* psuedo-ansi */ ! 165: {"max", ">?", 0}, /* old */ ! 166: {"mx", ">?", DMGL_ANSI}, /* psuedo-ansi */ ! 167: {"min", "<?", 0}, /* old */ ! 168: {"mn", "<?", DMGL_ANSI}, /* psuedo-ansi */ ! 169: {"nop", "", 0}, /* old (for operator=) */ ! 170: {"rm", "->*", DMGL_ANSI} /* ansi */ ! 171: }; ! 172: ! 173: ! 174: typedef struct string /* Beware: these aren't required to be */ ! 175: { /* '\0' terminated. */ ! 176: char *b; /* pointer to start of string */ ! 177: char *p; /* pointer after last character */ ! 178: char *e; /* pointer after end of allocated space */ ! 179: } string; ! 180: ! 181: #define STRING_EMPTY(str) ((str) -> b == (str) -> p) ! 182: #define PREPEND_BLANK(str) {if (!STRING_EMPTY(str)) \ ! 183: string_prepend(str, " ");} ! 184: #define APPEND_BLANK(str) {if (!STRING_EMPTY(str)) \ ! 185: string_append(str, " ");} ! 186: ! 187: #define ARM_VTABLE_STRING "__vtbl__" /* Lucid/ARM virtual table prefix */ ! 188: #define ARM_VTABLE_STRLEN 8 /* strlen (ARM_VTABLE_STRING) */ ! 189: ! 190: /* Prototypes for local functions */ ! 191: ! 192: static char * ! 193: mop_up PARAMS ((struct work_stuff *, string *, int)); ! 194: ! 195: #if 0 ! 196: static int ! 197: demangle_method_args PARAMS ((struct work_stuff *work, CONST char **, string *)); ! 198: #endif ! 199: ! 200: static int ! 201: demangle_template PARAMS ((struct work_stuff *work, CONST char **, string *, ! 202: string *)); ! 203: ! 204: static int ! 205: demangle_qualified PARAMS ((struct work_stuff *, CONST char **, string *, ! 206: int, int)); ! 207: ! 208: static int ! 209: demangle_class PARAMS ((struct work_stuff *, CONST char **, string *)); ! 210: ! 211: static int ! 212: demangle_fund_type PARAMS ((struct work_stuff *, CONST char **, string *)); ! 213: ! 214: static int ! 215: demangle_signature PARAMS ((struct work_stuff *, CONST char **, string *)); ! 216: ! 217: static int ! 218: demangle_prefix PARAMS ((struct work_stuff *, CONST char **, string *)); ! 219: ! 220: static int ! 221: gnu_special PARAMS ((struct work_stuff *, CONST char **, string *)); ! 222: ! 223: static int ! 224: arm_special PARAMS ((struct work_stuff *, CONST char **, string *)); ! 225: ! 226: static void ! 227: string_need PARAMS ((string *, int)); ! 228: ! 229: static void ! 230: string_delete PARAMS ((string *)); ! 231: ! 232: static void ! 233: string_init PARAMS ((string *)); ! 234: ! 235: static void ! 236: string_clear PARAMS ((string *)); ! 237: ! 238: #if 0 ! 239: static int ! 240: string_empty PARAMS ((string *)); ! 241: #endif ! 242: ! 243: static void ! 244: string_append PARAMS ((string *, CONST char *)); ! 245: ! 246: static void ! 247: string_appends PARAMS ((string *, string *)); ! 248: ! 249: static void ! 250: string_appendn PARAMS ((string *, CONST char *, int)); ! 251: ! 252: static void ! 253: string_prepend PARAMS ((string *, CONST char *)); ! 254: ! 255: static void ! 256: string_prependn PARAMS ((string *, CONST char *, int)); ! 257: ! 258: static int ! 259: get_count PARAMS ((CONST char **, int *)); ! 260: ! 261: static int ! 262: consume_count PARAMS ((CONST char **)); ! 263: ! 264: static int ! 265: demangle_args PARAMS ((struct work_stuff *, CONST char **, string *)); ! 266: ! 267: static int ! 268: do_type PARAMS ((struct work_stuff *, CONST char **, string *)); ! 269: ! 270: static int ! 271: do_arg PARAMS ((struct work_stuff *, CONST char **, string *)); ! 272: ! 273: static void ! 274: demangle_function_name PARAMS ((struct work_stuff *, CONST char **, string *, ! 275: CONST char *)); ! 276: ! 277: static void ! 278: remember_type PARAMS ((struct work_stuff *, CONST char *, int)); ! 279: ! 280: static void ! 281: forget_types PARAMS ((struct work_stuff *)); ! 282: ! 283: static void ! 284: string_prepends PARAMS ((string *, string *)); ! 285: ! 286: /* Translate count to integer, consuming tokens in the process. ! 287: Conversion terminates on the first non-digit character. ! 288: Trying to consume something that isn't a count results in ! 289: no consumption of input and a return of 0. */ ! 290: ! 291: static int ! 292: consume_count (type) ! 293: CONST char **type; ! 294: { ! 295: int count = 0; ! 296: ! 297: while (isdigit (**type)) ! 298: { ! 299: count *= 10; ! 300: count += **type - '0'; ! 301: (*type)++; ! 302: } ! 303: return (count); ! 304: } ! 305: ! 306: /* Takes operator name as e.g. "++" and returns mangled ! 307: operator name (e.g. "postincrement_expr"), or NULL if not found. ! 308: ! 309: If OPTIONS & DMGL_ANSI == 1, return the ANSI name; ! 310: if OPTIONS & DMGL_ANSI == 0, return the old GNU name. */ ! 311: ! 312: char * ! 313: cplus_mangle_opname (opname, options) ! 314: char *opname; ! 315: int options; ! 316: { ! 317: int i; ! 318: int len; ! 319: ! 320: len = strlen (opname); ! 321: for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++) ! 322: { ! 323: if (strlen (optable[i].out) == len ! 324: && (options & DMGL_ANSI) == (optable[i].flags & DMGL_ANSI) ! 325: && memcmp (optable[i].out, opname, len) == 0) ! 326: return ((char *)optable[i].in); ! 327: } ! 328: return (0); ! 329: } ! 330: ! 331: /* check to see whether MANGLED can match TEXT in the first TEXT_LEN ! 332: characters. */ ! 333: ! 334: int cplus_match (mangled, text, text_len) ! 335: CONST char *mangled; ! 336: char *text; ! 337: int text_len; ! 338: { ! 339: if (strncmp (mangled, text, text_len) != 0) { ! 340: return(0); /* cannot match either */ ! 341: } else { ! 342: return(1); /* matches mangled, may match demangled */ ! 343: } ! 344: } ! 345: ! 346: /* char *cplus_demangle (const char *mangled, int options) ! 347: ! 348: If MANGLED is a mangled function name produced by GNU C++, then ! 349: a pointer to a malloced string giving a C++ representation ! 350: of the name will be returned; otherwise NULL will be returned. ! 351: It is the caller's responsibility to free the string which ! 352: is returned. ! 353: ! 354: The OPTIONS arg may contain one or more of the following bits: ! 355: ! 356: DMGL_ANSI ANSI qualifiers such as `const' and `void' are ! 357: included. ! 358: DMGL_PARAMS Function parameters are included. ! 359: ! 360: For example, ! 361: ! 362: cplus_demangle ("foo__1Ai", DMGL_PARAMS) => "A::foo(int)" ! 363: cplus_demangle ("foo__1Ai", DMGL_PARAMS | DMGL_ANSI) => "A::foo(int)" ! 364: cplus_demangle ("foo__1Ai", 0) => "A::foo" ! 365: ! 366: cplus_demangle ("foo__1Afe", DMGL_PARAMS) => "A::foo(float,...)" ! 367: cplus_demangle ("foo__1Afe", DMGL_PARAMS | DMGL_ANSI)=> "A::foo(float,...)" ! 368: cplus_demangle ("foo__1Afe", 0) => "A::foo" ! 369: ! 370: Note that any leading underscores, or other such characters prepended by ! 371: the compilation system, are presumed to have already been stripped from ! 372: MANGLED. */ ! 373: ! 374: char * ! 375: cplus_demangle (mangled, options) ! 376: CONST char *mangled; ! 377: int options; ! 378: { ! 379: string decl; ! 380: int success = 0; ! 381: struct work_stuff work[1]; ! 382: char *demangled = NULL; ! 383: ! 384: if ((mangled != NULL) && (*mangled != '\0')) ! 385: { ! 386: memset ((char *) work, 0, sizeof (work)); ! 387: work -> options = options; ! 388: if ((work->options & DMGL_STYLE_MASK) == 0) ! 389: work->options |= (int)current_demangling_style & DMGL_STYLE_MASK; ! 390: ! 391: string_init (&decl); ! 392: ! 393: /* First check to see if gnu style demangling is active and if the ! 394: string to be demangled contains a CPLUS_MARKER. If so, attempt to ! 395: recognize one of the gnu special forms rather than looking for a ! 396: standard prefix. In particular, don't worry about whether there ! 397: is a "__" string in the mangled string. Consider "_$_5__foo" for ! 398: example. */ ! 399: ! 400: if ((AUTO_DEMANGLING || GNU_DEMANGLING)) ! 401: { ! 402: success = gnu_special (work, &mangled, &decl); ! 403: } ! 404: if (!success) ! 405: { ! 406: success = demangle_prefix (work, &mangled, &decl); ! 407: } ! 408: if (success && (*mangled != '\0')) ! 409: { ! 410: success = demangle_signature (work, &mangled, &decl); ! 411: } ! 412: if (work->constructor == 2) ! 413: { ! 414: string_prepend(&decl, "global constructors keyed to "); ! 415: work->constructor = 0; ! 416: } ! 417: else if (work->destructor == 2) ! 418: { ! 419: string_prepend(&decl, "global destructors keyed to "); ! 420: work->destructor = 0; ! 421: } ! 422: demangled = mop_up (work, &decl, success); ! 423: } ! 424: return (demangled); ! 425: } ! 426: ! 427: static char * ! 428: mop_up (work, declp, success) ! 429: struct work_stuff *work; ! 430: string *declp; ! 431: int success; ! 432: { ! 433: char *demangled = NULL; ! 434: ! 435: /* Discard the remembered types, if any. */ ! 436: ! 437: forget_types (work); ! 438: if (work -> typevec != NULL) ! 439: { ! 440: free ((char *) work -> typevec); ! 441: } ! 442: ! 443: /* If demangling was successful, ensure that the demangled string is null ! 444: terminated and return it. Otherwise, free the demangling decl. */ ! 445: ! 446: if (!success) ! 447: { ! 448: string_delete (declp); ! 449: } ! 450: else ! 451: { ! 452: string_appendn (declp, "", 1); ! 453: demangled = declp -> b; ! 454: } ! 455: return (demangled); ! 456: } ! 457: ! 458: /* ! 459: ! 460: LOCAL FUNCTION ! 461: ! 462: demangle_signature -- demangle the signature part of a mangled name ! 463: ! 464: SYNOPSIS ! 465: ! 466: static int ! 467: demangle_signature (struct work_stuff *work, const char **mangled, ! 468: string *declp); ! 469: ! 470: DESCRIPTION ! 471: ! 472: Consume and demangle the signature portion of the mangled name. ! 473: ! 474: DECLP is the string where demangled output is being built. At ! 475: entry it contains the demangled root name from the mangled name ! 476: prefix. I.E. either a demangled operator name or the root function ! 477: name. In some special cases, it may contain nothing. ! 478: ! 479: *MANGLED points to the current unconsumed location in the mangled ! 480: name. As tokens are consumed and demangling is performed, the ! 481: pointer is updated to continuously point at the next token to ! 482: be consumed. ! 483: ! 484: Demangling GNU style mangled names is nasty because there is no ! 485: explicit token that marks the start of the outermost function ! 486: argument list. ! 487: */ ! 488: ! 489: static int ! 490: demangle_signature (work, mangled, declp) ! 491: struct work_stuff *work; ! 492: CONST char **mangled; ! 493: string *declp; ! 494: { ! 495: int success = 1; ! 496: int func_done = 0; ! 497: int expect_func = 0; ! 498: CONST char *oldmangled = NULL; ! 499: string trawname; ! 500: string tname; ! 501: ! 502: while (success && (**mangled != '\0')) ! 503: { ! 504: switch (**mangled) ! 505: { ! 506: case 'Q': ! 507: oldmangled = *mangled; ! 508: success = demangle_qualified (work, mangled, declp, 1, 0); ! 509: if (success) ! 510: { ! 511: remember_type (work, oldmangled, *mangled - oldmangled); ! 512: } ! 513: if (AUTO_DEMANGLING || GNU_DEMANGLING) ! 514: { ! 515: expect_func = 1; ! 516: } ! 517: oldmangled = NULL; ! 518: break; ! 519: ! 520: case 'S': ! 521: /* Static member function */ ! 522: if (oldmangled == NULL) ! 523: { ! 524: oldmangled = *mangled; ! 525: } ! 526: (*mangled)++; ! 527: work -> static_type = 1; ! 528: break; ! 529: ! 530: case 'C': ! 531: /* a const member function */ ! 532: if (oldmangled == NULL) ! 533: { ! 534: oldmangled = *mangled; ! 535: } ! 536: (*mangled)++; ! 537: work -> const_type = 1; ! 538: break; ! 539: ! 540: case '0': case '1': case '2': case '3': case '4': ! 541: case '5': case '6': case '7': case '8': case '9': ! 542: if (oldmangled == NULL) ! 543: { ! 544: oldmangled = *mangled; ! 545: } ! 546: success = demangle_class (work, mangled, declp); ! 547: if (success) ! 548: { ! 549: remember_type (work, oldmangled, *mangled - oldmangled); ! 550: } ! 551: if (AUTO_DEMANGLING || GNU_DEMANGLING) ! 552: { ! 553: expect_func = 1; ! 554: } ! 555: oldmangled = NULL; ! 556: break; ! 557: ! 558: case 'F': ! 559: /* Function */ ! 560: /* ARM style demangling includes a specific 'F' character after ! 561: the class name. For GNU style, it is just implied. So we can ! 562: safely just consume any 'F' at this point and be compatible ! 563: with either style. */ ! 564: ! 565: oldmangled = NULL; ! 566: func_done = 1; ! 567: (*mangled)++; ! 568: ! 569: /* For lucid/ARM style we have to forget any types we might ! 570: have remembered up to this point, since they were not argument ! 571: types. GNU style considers all types seen as available for ! 572: back references. See comment in demangle_args() */ ! 573: ! 574: if (LUCID_DEMANGLING || ARM_DEMANGLING) ! 575: { ! 576: forget_types (work); ! 577: } ! 578: success = demangle_args (work, mangled, declp); ! 579: break; ! 580: ! 581: case 't': ! 582: /* G++ Template */ ! 583: string_init(&trawname); ! 584: string_init(&tname); ! 585: success = demangle_template (work, mangled, &tname, &trawname); ! 586: string_append(&tname, "::"); ! 587: string_prepends(declp, &tname); ! 588: if (work -> destructor & 1) ! 589: { ! 590: string_prepend (&trawname, "~"); ! 591: string_appends (declp, &trawname); ! 592: work->destructor -= 1; ! 593: } ! 594: if ((work->constructor & 1) || (work->destructor & 1)) ! 595: { ! 596: string_appends (declp, &trawname); ! 597: work->constructor -= 1; ! 598: } ! 599: string_delete(&trawname); ! 600: string_delete(&tname); ! 601: expect_func = 1; ! 602: break; ! 603: ! 604: case '_': ! 605: /* At the outermost level, we cannot have a return type specified, ! 606: so if we run into another '_' at this point we are dealing with ! 607: a mangled name that is either bogus, or has been mangled by ! 608: some algorithm we don't know how to deal with. So just ! 609: reject the entire demangling. */ ! 610: success = 0; ! 611: break; ! 612: ! 613: default: ! 614: if (AUTO_DEMANGLING || GNU_DEMANGLING) ! 615: { ! 616: /* Assume we have stumbled onto the first outermost function ! 617: argument token, and start processing args. */ ! 618: func_done = 1; ! 619: success = demangle_args (work, mangled, declp); ! 620: } ! 621: else ! 622: { ! 623: /* Non-GNU demanglers use a specific token to mark the start ! 624: of the outermost function argument tokens. Typically 'F', ! 625: for ARM-demangling, for example. So if we find something ! 626: we are not prepared for, it must be an error. */ ! 627: success = 0; ! 628: } ! 629: break; ! 630: } ! 631: if (AUTO_DEMANGLING || GNU_DEMANGLING) ! 632: { ! 633: if (success && expect_func) ! 634: { ! 635: func_done = 1; ! 636: success = demangle_args (work, mangled, declp); ! 637: } ! 638: } ! 639: } ! 640: if (success && !func_done) ! 641: { ! 642: if (AUTO_DEMANGLING || GNU_DEMANGLING) ! 643: { ! 644: /* With GNU style demangling, bar__3foo is 'foo::bar(void)', and ! 645: bar__3fooi is 'foo::bar(int)'. We get here when we find the ! 646: first case, and need to ensure that the '(void)' gets added to ! 647: the current declp. Note that with ARM, the first case ! 648: represents the name of a static data member 'foo::bar', ! 649: which is in the current declp, so we leave it alone. */ ! 650: success = demangle_args (work, mangled, declp); ! 651: } ! 652: } ! 653: if (success && work -> static_type && PRINT_ARG_TYPES) ! 654: { ! 655: string_append (declp, " static"); ! 656: } ! 657: if (success && work -> const_type && PRINT_ARG_TYPES) ! 658: { ! 659: string_append (declp, " const"); ! 660: } ! 661: return (success); ! 662: } ! 663: ! 664: #if 0 ! 665: ! 666: static int ! 667: demangle_method_args (work, mangled, declp) ! 668: struct work_stuff *work; ! 669: CONST char **mangled; ! 670: string *declp; ! 671: { ! 672: int success = 0; ! 673: ! 674: if (work -> static_type) ! 675: { ! 676: string_append (declp, *mangled + 1); ! 677: *mangled += strlen (*mangled); ! 678: success = 1; ! 679: } ! 680: else ! 681: { ! 682: success = demangle_args (work, mangled, declp); ! 683: } ! 684: return (success); ! 685: } ! 686: ! 687: #endif ! 688: ! 689: static int ! 690: demangle_template (work, mangled, tname, trawname) ! 691: struct work_stuff *work; ! 692: CONST char **mangled; ! 693: string *tname; ! 694: string *trawname; ! 695: { ! 696: int i; ! 697: int is_pointer; ! 698: int is_real; ! 699: int is_integral; ! 700: int r; ! 701: int need_comma = 0; ! 702: int success = 0; ! 703: int done; ! 704: CONST char *old_p; ! 705: CONST char *start; ! 706: int symbol_len; ! 707: string temp; ! 708: ! 709: (*mangled)++; ! 710: start = *mangled; ! 711: /* get template name */ ! 712: if ((r = consume_count (mangled)) == 0) ! 713: { ! 714: return (0); ! 715: } ! 716: if (trawname) ! 717: string_appendn (trawname, *mangled, r); ! 718: string_appendn (tname, *mangled, r); ! 719: *mangled += r; ! 720: string_append (tname, "<"); ! 721: /* get size of template parameter list */ ! 722: if (!get_count (mangled, &r)) ! 723: { ! 724: return (0); ! 725: } ! 726: for (i = 0; i < r; i++) ! 727: { ! 728: if (need_comma) ! 729: { ! 730: string_append (tname, ", "); ! 731: } ! 732: /* Z for type parameters */ ! 733: if (**mangled == 'Z') ! 734: { ! 735: (*mangled)++; ! 736: /* temp is initialized in do_type */ ! 737: success = do_type (work, mangled, &temp); ! 738: if (success) ! 739: { ! 740: string_appends (tname, &temp); ! 741: } ! 742: string_delete(&temp); ! 743: if (!success) ! 744: { ! 745: break; ! 746: } ! 747: } ! 748: else ! 749: { ! 750: /* otherwise, value parameter */ ! 751: old_p = *mangled; ! 752: is_pointer = 0; ! 753: is_real = 0; ! 754: is_integral = 0; ! 755: done = 0; ! 756: /* temp is initialized in do_type */ ! 757: success = do_type (work, mangled, &temp); ! 758: if (success) ! 759: { ! 760: string_appends (tname, &temp); ! 761: } ! 762: string_delete(&temp); ! 763: if (!success) ! 764: { ! 765: break; ! 766: } ! 767: string_append (tname, "="); ! 768: while (*old_p && !done) ! 769: { ! 770: switch (*old_p) ! 771: { ! 772: case 'P': ! 773: case 'R': ! 774: done = is_pointer = 1; ! 775: break; ! 776: case 'C': /* const */ ! 777: case 'S': /* explicitly signed [char] */ ! 778: case 'U': /* unsigned */ ! 779: case 'V': /* volatile */ ! 780: case 'F': /* function */ ! 781: case 'M': /* member function */ ! 782: case 'O': /* ??? */ ! 783: old_p++; ! 784: continue; ! 785: case 'Q': /* repetition of following */ ! 786: case 'T': /* remembered type */ ! 787: abort (); ! 788: break; ! 789: case 'v': /* void */ ! 790: abort (); ! 791: break; ! 792: case 'x': /* long long */ ! 793: case 'l': /* long */ ! 794: case 'i': /* int */ ! 795: case 's': /* short */ ! 796: case 'c': /* char */ ! 797: case 'w': /* wchar_t */ ! 798: done = is_integral = 1; ! 799: break; ! 800: case 'r': /* long double */ ! 801: case 'd': /* double */ ! 802: case 'f': /* float */ ! 803: done = is_real = 1; ! 804: break; ! 805: default: ! 806: abort (); ! 807: } ! 808: } ! 809: if (is_integral) ! 810: { ! 811: if (**mangled == 'm') ! 812: { ! 813: string_appendn (tname, "-", 1); ! 814: (*mangled)++; ! 815: } ! 816: while (isdigit (**mangled)) ! 817: { ! 818: string_appendn (tname, *mangled, 1); ! 819: (*mangled)++; ! 820: } ! 821: } ! 822: else if (is_real) ! 823: { ! 824: if (**mangled == 'm') ! 825: { ! 826: string_appendn (tname, "-", 1); ! 827: (*mangled)++; ! 828: } ! 829: while (isdigit (**mangled)) ! 830: { ! 831: string_appendn (tname, *mangled, 1); ! 832: (*mangled)++; ! 833: } ! 834: if (**mangled == '.') /* fraction */ ! 835: { ! 836: string_appendn (tname, ".", 1); ! 837: (*mangled)++; ! 838: while (isdigit (**mangled)) ! 839: { ! 840: string_appendn (tname, *mangled, 1); ! 841: (*mangled)++; ! 842: } ! 843: } ! 844: if (**mangled == 'e') /* exponent */ ! 845: { ! 846: string_appendn (tname, "e", 1); ! 847: (*mangled)++; ! 848: while (isdigit (**mangled)) ! 849: { ! 850: string_appendn (tname, *mangled, 1); ! 851: (*mangled)++; ! 852: } ! 853: } ! 854: } ! 855: else if (is_pointer) ! 856: { ! 857: if (!get_count (mangled, &symbol_len)) ! 858: { ! 859: success = 0; ! 860: break; ! 861: } ! 862: string_appendn (tname, *mangled, symbol_len); ! 863: *mangled += symbol_len; ! 864: } ! 865: } ! 866: need_comma = 1; ! 867: } ! 868: string_append (tname, ">"); ! 869: ! 870: /* ! 871: if (work -> static_type) ! 872: { ! 873: string_append (declp, *mangled + 1); ! 874: *mangled += strlen (*mangled); ! 875: success = 1; ! 876: } ! 877: else ! 878: { ! 879: success = demangle_args (work, mangled, declp); ! 880: } ! 881: } ! 882: */ ! 883: return (success); ! 884: } ! 885: ! 886: static int ! 887: arm_pt (work, mangled, n, anchor, args) ! 888: struct work_stuff *work; ! 889: CONST char *mangled; ! 890: int n; ! 891: CONST char **anchor, **args; ! 892: { ! 893: /* ARM template? */ ! 894: if (ARM_DEMANGLING && (*anchor = strstr(mangled, "__pt__"))) ! 895: { ! 896: int len; ! 897: *args = *anchor + 6; ! 898: len = consume_count (args); ! 899: if (*args + len == mangled + n && **args == '_') ! 900: { ! 901: ++*args; ! 902: return 1; ! 903: } ! 904: } ! 905: return 0; ! 906: } ! 907: ! 908: static int ! 909: demangle_class_name (work, mangled, declp) ! 910: struct work_stuff *work; ! 911: CONST char **mangled; ! 912: string *declp; ! 913: { ! 914: int n; ! 915: int success = 0; ! 916: ! 917: n = consume_count (mangled); ! 918: if (strlen (*mangled) >= n) ! 919: { ! 920: CONST char *p; ! 921: CONST char *args; ! 922: CONST char *e = *mangled + n; ! 923: /* ARM template? */ ! 924: if (arm_pt (work, *mangled, n, &p, &args)) ! 925: { ! 926: string arg; ! 927: string_init (&arg); ! 928: string_appendn (declp, *mangled, p - *mangled); ! 929: string_append (declp, "<"); ! 930: /* should do error checking here */ ! 931: while (args < e) { ! 932: string_clear (&arg); ! 933: do_type (work, &args, &arg); ! 934: string_appends (declp, &arg); ! 935: string_append (declp, ","); ! 936: } ! 937: string_delete (&arg); ! 938: --declp->p; ! 939: string_append (declp, ">"); ! 940: } ! 941: else ! 942: { ! 943: string_appendn (declp, *mangled, n); ! 944: } ! 945: *mangled += n; ! 946: success = 1; ! 947: } ! 948: return (success); ! 949: } ! 950: ! 951: /* ! 952: ! 953: LOCAL FUNCTION ! 954: ! 955: demangle_class -- demangle a mangled class sequence ! 956: ! 957: SYNOPSIS ! 958: ! 959: static int ! 960: demangle_class (struct work_stuff *work, const char **mangled, ! 961: strint *declp) ! 962: ! 963: DESCRIPTION ! 964: ! 965: DECLP points to the buffer into which demangling is being done. ! 966: ! 967: *MANGLED points to the current token to be demangled. On input, ! 968: it points to a mangled class (I.E. "3foo", "13verylongclass", etc.) ! 969: On exit, it points to the next token after the mangled class on ! 970: success, or the first unconsumed token on failure. ! 971: ! 972: If the CONSTRUCTOR or DESTRUCTOR flags are set in WORK, then ! 973: we are demangling a constructor or destructor. In this case ! 974: we prepend "class::class" or "class::~class" to DECLP. ! 975: ! 976: Otherwise, we prepend "class::" to the current DECLP. ! 977: ! 978: Reset the constructor/destructor flags once they have been ! 979: "consumed". This allows demangle_class to be called later during ! 980: the same demangling, to do normal class demangling. ! 981: ! 982: Returns 1 if demangling is successful, 0 otherwise. ! 983: ! 984: */ ! 985: ! 986: static int ! 987: demangle_class (work, mangled, declp) ! 988: struct work_stuff *work; ! 989: CONST char **mangled; ! 990: string *declp; ! 991: { ! 992: int success = 0; ! 993: string class_name; ! 994: ! 995: string_init (&class_name); ! 996: if (demangle_class_name (work, mangled, &class_name)) ! 997: { ! 998: if ((work->constructor & 1) || (work->destructor & 1)) ! 999: { ! 1000: string_prepends (declp, &class_name); ! 1001: if (work -> destructor & 1) ! 1002: { ! 1003: string_prepend (declp, "~"); ! 1004: work -> destructor -= 1; ! 1005: } ! 1006: else ! 1007: { ! 1008: work -> constructor -= 1; ! 1009: } ! 1010: } ! 1011: string_prepend (declp, "::"); ! 1012: string_prepends (declp, &class_name); ! 1013: success = 1; ! 1014: } ! 1015: string_delete (&class_name); ! 1016: return (success); ! 1017: } ! 1018: ! 1019: /* ! 1020: ! 1021: LOCAL FUNCTION ! 1022: ! 1023: demangle_prefix -- consume the mangled name prefix and find signature ! 1024: ! 1025: SYNOPSIS ! 1026: ! 1027: static int ! 1028: demangle_prefix (struct work_stuff *work, const char **mangled, ! 1029: string *declp); ! 1030: ! 1031: DESCRIPTION ! 1032: ! 1033: Consume and demangle the prefix of the mangled name. ! 1034: ! 1035: DECLP points to the string buffer into which demangled output is ! 1036: placed. On entry, the buffer is empty. On exit it contains ! 1037: the root function name, the demangled operator name, or in some ! 1038: special cases either nothing or the completely demangled result. ! 1039: ! 1040: MANGLED points to the current pointer into the mangled name. As each ! 1041: token of the mangled name is consumed, it is updated. Upon entry ! 1042: the current mangled name pointer points to the first character of ! 1043: the mangled name. Upon exit, it should point to the first character ! 1044: of the signature if demangling was successful, or to the first ! 1045: unconsumed character if demangling of the prefix was unsuccessful. ! 1046: ! 1047: Returns 1 on success, 0 otherwise. ! 1048: */ ! 1049: ! 1050: static int ! 1051: demangle_prefix (work, mangled, declp) ! 1052: struct work_stuff *work; ! 1053: CONST char **mangled; ! 1054: string *declp; ! 1055: { ! 1056: int success = 1; ! 1057: CONST char *scan; ! 1058: int i; ! 1059: ! 1060: if (strncmp(*mangled, "_GLOBAL_$D$", 11) == 0) ! 1061: { ! 1062: /* it's a GNU global destructor to be executed at program exit */ ! 1063: (*mangled) += 11; ! 1064: work->destructor = 2; ! 1065: } ! 1066: else if (strncmp(*mangled, "_GLOBAL_$I$", 11) == 0) ! 1067: { ! 1068: /* it's a GNU global constructor to be executed at program initial */ ! 1069: (*mangled) += 11; ! 1070: work->constructor = 2; ! 1071: } ! 1072: else if (ARM_DEMANGLING && strncmp(*mangled, "__std__", 7) == 0) ! 1073: { ! 1074: /* it's a ARM global destructor to be executed at program exit */ ! 1075: (*mangled) += 7; ! 1076: work->destructor = 2; ! 1077: } ! 1078: else if (ARM_DEMANGLING && strncmp(*mangled, "__sti__", 7) == 0) ! 1079: { ! 1080: /* it's a ARM global constructor to be executed at program initial */ ! 1081: (*mangled) += 7; ! 1082: work->constructor = 2; ! 1083: } ! 1084: ! 1085: /* This block of code is a reduction in strength time optimization ! 1086: of: ! 1087: scan = strstr (*mangled, "__"); */ ! 1088: ! 1089: { ! 1090: scan = *mangled; ! 1091: ! 1092: do { ! 1093: scan = strchr (scan, '_'); ! 1094: } while (scan != NULL && *++scan != '_'); ! 1095: ! 1096: if (scan != NULL) --scan; ! 1097: } ! 1098: ! 1099: if (scan != NULL) ! 1100: { ! 1101: /* We found a sequence of two or more '_', ensure that we start at ! 1102: the last pair in the sequence. */ ! 1103: i = strspn (scan, "_"); ! 1104: if (i > 2) ! 1105: { ! 1106: scan += (i - 2); ! 1107: } ! 1108: } ! 1109: ! 1110: if (scan == NULL) ! 1111: { ! 1112: success = 0; ! 1113: } ! 1114: else if (work -> static_type) ! 1115: { ! 1116: if (!isdigit (scan[0]) && (scan[0] != 't')) ! 1117: { ! 1118: success = 0; ! 1119: } ! 1120: } ! 1121: else if ((scan == *mangled) && ! 1122: (isdigit (scan[2]) || (scan[2] == 'Q') || (scan[2] == 't'))) ! 1123: { ! 1124: /* The ARM says nothing about the mangling of local variables. ! 1125: But cfront mangles local variables by prepending __<nesting_level> ! 1126: to them. As an extension to ARM demangling we handle this case. */ ! 1127: if ((LUCID_DEMANGLING || ARM_DEMANGLING) && isdigit (scan[2])) ! 1128: { ! 1129: *mangled = scan + 2; ! 1130: consume_count (mangled); ! 1131: string_append (declp, *mangled); ! 1132: *mangled += strlen (*mangled); ! 1133: success = 1; ! 1134: } ! 1135: else ! 1136: { ! 1137: /* A GNU style constructor starts with "__[0-9Qt]. */ ! 1138: work -> constructor += 1; ! 1139: *mangled = scan + 2; ! 1140: } ! 1141: } ! 1142: else if ((scan == *mangled) && !isdigit (scan[2]) && (scan[2] != 't')) ! 1143: { ! 1144: /* Mangled name starts with "__". Skip over any leading '_' characters, ! 1145: then find the next "__" that separates the prefix from the signature. ! 1146: */ ! 1147: if (!(ARM_DEMANGLING || LUCID_DEMANGLING) ! 1148: || (arm_special (work, mangled, declp) == 0)) ! 1149: { ! 1150: while (*scan == '_') ! 1151: { ! 1152: scan++; ! 1153: } ! 1154: if ((scan = strstr (scan, "__")) == NULL || (*(scan + 2) == '\0')) ! 1155: { ! 1156: /* No separator (I.E. "__not_mangled"), or empty signature ! 1157: (I.E. "__not_mangled_either__") */ ! 1158: success = 0; ! 1159: } ! 1160: else ! 1161: { ! 1162: demangle_function_name (work, mangled, declp, scan); ! 1163: } ! 1164: } ! 1165: } ! 1166: else if (*(scan + 2) != '\0') ! 1167: { ! 1168: /* Mangled name does not start with "__" but does have one somewhere ! 1169: in there with non empty stuff after it. Looks like a global ! 1170: function name. */ ! 1171: demangle_function_name (work, mangled, declp, scan); ! 1172: } ! 1173: else ! 1174: { ! 1175: /* Doesn't look like a mangled name */ ! 1176: success = 0; ! 1177: } ! 1178: ! 1179: if (!success && (work->constructor == 2 || work->destructor == 2)) ! 1180: { ! 1181: string_append (declp, *mangled); ! 1182: *mangled += strlen (*mangled); ! 1183: success = 1; ! 1184: } ! 1185: return (success); ! 1186: } ! 1187: ! 1188: /* ! 1189: ! 1190: LOCAL FUNCTION ! 1191: ! 1192: gnu_special -- special handling of gnu mangled strings ! 1193: ! 1194: SYNOPSIS ! 1195: ! 1196: static int ! 1197: gnu_special (struct work_stuff *work, const char **mangled, ! 1198: string *declp); ! 1199: ! 1200: ! 1201: DESCRIPTION ! 1202: ! 1203: Process some special GNU style mangling forms that don't fit ! 1204: the normal pattern. For example: ! 1205: ! 1206: _$_3foo (destructor for class foo) ! 1207: _vt$foo (foo virtual table) ! 1208: _vt$foo$bar (foo::bar virtual table) ! 1209: _3foo$varname (static data member) ! 1210: _Q22rs2tu$vw (static data member) ! 1211: __t6vector1Zii (constructor with template) ! 1212: */ ! 1213: ! 1214: static int ! 1215: gnu_special (work, mangled, declp) ! 1216: struct work_stuff *work; ! 1217: CONST char **mangled; ! 1218: string *declp; ! 1219: { ! 1220: int n; ! 1221: int success = 1; ! 1222: CONST char *p; ! 1223: ! 1224: if ((*mangled)[0] == '_' ! 1225: && strchr (cplus_markers, (*mangled)[1]) != NULL ! 1226: && (*mangled)[2] == '_') ! 1227: { ! 1228: /* Found a GNU style destructor, get past "_<CPLUS_MARKER>_" */ ! 1229: (*mangled) += 3; ! 1230: work -> destructor += 1; ! 1231: } ! 1232: else if ((*mangled)[0] == '_' ! 1233: && (*mangled)[1] == 'v' ! 1234: && (*mangled)[2] == 't' ! 1235: && strchr (cplus_markers, (*mangled)[3]) != NULL) ! 1236: { ! 1237: /* Found a GNU style virtual table, get past "_vt<CPLUS_MARKER>" ! 1238: and create the decl. Note that we consume the entire mangled ! 1239: input string, which means that demangle_signature has no work ! 1240: to do. */ ! 1241: (*mangled) += 4; ! 1242: while (**mangled != '\0') ! 1243: { ! 1244: if (isdigit(*mangled[0])) ! 1245: { ! 1246: n = consume_count(mangled); ! 1247: } ! 1248: else ! 1249: { ! 1250: n = strcspn (*mangled, cplus_markers); ! 1251: } ! 1252: string_appendn (declp, *mangled, n); ! 1253: (*mangled) += n; ! 1254: ! 1255: if (**mangled != '\0') ! 1256: { ! 1257: string_append (declp, "::"); ! 1258: (*mangled)++; ! 1259: } ! 1260: } ! 1261: string_append (declp, " virtual table"); ! 1262: } ! 1263: else if ((*mangled)[0] == '_' ! 1264: && (strchr("0123456789Qt", (*mangled)[1]) != NULL) ! 1265: && (p = strpbrk (*mangled, cplus_markers)) != NULL) ! 1266: { ! 1267: /* static data member, "_3foo$varname" for example */ ! 1268: (*mangled)++; ! 1269: switch (**mangled) ! 1270: { ! 1271: case 'Q': ! 1272: success = demangle_qualified (work, mangled, declp, 0, 1); ! 1273: break; ! 1274: case 't': ! 1275: success = demangle_template (work, mangled, declp, 0); ! 1276: break; ! 1277: default: ! 1278: n = consume_count (mangled); ! 1279: string_appendn (declp, *mangled, n); ! 1280: (*mangled) += n; ! 1281: } ! 1282: if (success && (p == *mangled)) ! 1283: { ! 1284: /* Consumed everything up to the cplus_marker, append the ! 1285: variable name. */ ! 1286: (*mangled)++; ! 1287: string_append (declp, "::"); ! 1288: n = strlen (*mangled); ! 1289: string_appendn (declp, *mangled, n); ! 1290: (*mangled) += n; ! 1291: } ! 1292: else ! 1293: { ! 1294: success = 0; ! 1295: } ! 1296: } ! 1297: else ! 1298: { ! 1299: success = 0; ! 1300: } ! 1301: return (success); ! 1302: } ! 1303: ! 1304: /* ! 1305: ! 1306: LOCAL FUNCTION ! 1307: ! 1308: arm_special -- special handling of ARM/lucid mangled strings ! 1309: ! 1310: SYNOPSIS ! 1311: ! 1312: static int ! 1313: arm_special (struct work_stuff *work, const char **mangled, ! 1314: string *declp); ! 1315: ! 1316: ! 1317: DESCRIPTION ! 1318: ! 1319: Process some special ARM style mangling forms that don't fit ! 1320: the normal pattern. For example: ! 1321: ! 1322: __vtbl__3foo (foo virtual table) ! 1323: __vtbl__3foo__3bar (bar::foo virtual table) ! 1324: ! 1325: */ ! 1326: ! 1327: static int ! 1328: arm_special (work, mangled, declp) ! 1329: struct work_stuff *work; ! 1330: CONST char **mangled; ! 1331: string *declp; ! 1332: { ! 1333: int n; ! 1334: int success = 1; ! 1335: CONST char *scan; ! 1336: ! 1337: if (strncmp (*mangled, ARM_VTABLE_STRING, ARM_VTABLE_STRLEN) == 0) ! 1338: { ! 1339: /* Found a ARM style virtual table, get past ARM_VTABLE_STRING ! 1340: and create the decl. Note that we consume the entire mangled ! 1341: input string, which means that demangle_signature has no work ! 1342: to do. */ ! 1343: scan = *mangled + ARM_VTABLE_STRLEN; ! 1344: while (*scan != '\0') /* first check it can be demangled */ ! 1345: { ! 1346: n = consume_count (&scan); ! 1347: if (n==0) ! 1348: { ! 1349: return (0); /* no good */ ! 1350: } ! 1351: scan += n; ! 1352: if (scan[0] == '_' && scan[1] == '_') ! 1353: { ! 1354: scan += 2; ! 1355: } ! 1356: } ! 1357: (*mangled) += ARM_VTABLE_STRLEN; ! 1358: while (**mangled != '\0') ! 1359: { ! 1360: n = consume_count (mangled); ! 1361: string_prependn (declp, *mangled, n); ! 1362: (*mangled) += n; ! 1363: if ((*mangled)[0] == '_' && (*mangled)[1] == '_') ! 1364: { ! 1365: string_prepend (declp, "::"); ! 1366: (*mangled) += 2; ! 1367: } ! 1368: } ! 1369: string_append (declp, " virtual table"); ! 1370: } ! 1371: else ! 1372: { ! 1373: success = 0; ! 1374: } ! 1375: return (success); ! 1376: } ! 1377: ! 1378: /* ! 1379: ! 1380: LOCAL FUNCTION ! 1381: ! 1382: demangle_qualified -- demangle 'Q' qualified name strings ! 1383: ! 1384: SYNOPSIS ! 1385: ! 1386: static int ! 1387: demangle_qualified (struct work_stuff *, const char *mangled, ! 1388: string *result, int isfuncname, int append); ! 1389: ! 1390: DESCRIPTION ! 1391: ! 1392: Demangle a qualified name, such as "Q25Outer5Inner" which is ! 1393: the mangled form of "Outer::Inner". The demangled output is ! 1394: prepended or appended to the result string according to the ! 1395: state of the append flag. ! 1396: ! 1397: If isfuncname is nonzero, then the qualified name we are building ! 1398: is going to be used as a member function name, so if it is a ! 1399: constructor or destructor function, append an appropriate ! 1400: constructor or destructor name. I.E. for the above example, ! 1401: the result for use as a constructor is "Outer::Inner::Inner" ! 1402: and the result for use as a destructor is "Outer::Inner::~Inner". ! 1403: ! 1404: BUGS ! 1405: ! 1406: Numeric conversion is ASCII dependent (FIXME). ! 1407: ! 1408: */ ! 1409: ! 1410: static int ! 1411: demangle_qualified (work, mangled, result, isfuncname, append) ! 1412: struct work_stuff *work; ! 1413: CONST char **mangled; ! 1414: string *result; ! 1415: int isfuncname; ! 1416: int append; ! 1417: { ! 1418: int qualifiers; ! 1419: int namelength; ! 1420: int success = 1; ! 1421: CONST char *p; ! 1422: char num[2]; ! 1423: string temp; ! 1424: ! 1425: string_init (&temp); ! 1426: switch ((*mangled)[1]) ! 1427: { ! 1428: case '_': ! 1429: /* GNU mangled name with more than 9 classes. The count is preceded ! 1430: by an underscore (to distinguish it from the <= 9 case) and followed ! 1431: by an underscore. */ ! 1432: p = *mangled + 2; ! 1433: qualifiers = atoi (p); ! 1434: if (!isdigit (*p) || *p == '0') ! 1435: success = 0; ! 1436: ! 1437: /* Skip the digits. */ ! 1438: while (isdigit (*p)) ! 1439: ++p; ! 1440: ! 1441: if (*p != '_') ! 1442: success = 0; ! 1443: ! 1444: *mangled = p + 1; ! 1445: break; ! 1446: ! 1447: case '1': ! 1448: case '2': ! 1449: case '3': ! 1450: case '4': ! 1451: case '5': ! 1452: case '6': ! 1453: case '7': ! 1454: case '8': ! 1455: case '9': ! 1456: /* The count is in a single digit. */ ! 1457: num[0] = (*mangled)[1]; ! 1458: num[1] = '\0'; ! 1459: qualifiers = atoi (num); ! 1460: ! 1461: /* If there is an underscore after the digit, skip it. This is ! 1462: said to be for ARM-qualified names, but the ARM makes no ! 1463: mention of such an underscore. Perhaps cfront uses one. */ ! 1464: if ((*mangled)[2] == '_') ! 1465: { ! 1466: (*mangled)++; ! 1467: } ! 1468: (*mangled) += 2; ! 1469: break; ! 1470: ! 1471: case '0': ! 1472: default: ! 1473: success = 0; ! 1474: } ! 1475: ! 1476: if (!success) ! 1477: return success; ! 1478: ! 1479: /* Pick off the names and collect them in the temp buffer in the order ! 1480: in which they are found, separated by '::'. */ ! 1481: ! 1482: while (qualifiers-- > 0) ! 1483: { ! 1484: if (*mangled[0] == 't') ! 1485: { ! 1486: success = demangle_template(work, mangled, &temp, 0); ! 1487: if (!success) break; ! 1488: } ! 1489: else ! 1490: { ! 1491: namelength = consume_count (mangled); ! 1492: if (strlen (*mangled) < namelength) ! 1493: { ! 1494: /* Simple sanity check failed */ ! 1495: success = 0; ! 1496: break; ! 1497: } ! 1498: string_appendn (&temp, *mangled, namelength); ! 1499: *mangled += namelength; ! 1500: } ! 1501: if (qualifiers > 0) ! 1502: { ! 1503: string_appendn (&temp, "::", 2); ! 1504: } ! 1505: } ! 1506: ! 1507: /* If we are using the result as a function name, we need to append ! 1508: the appropriate '::' separated constructor or destructor name. ! 1509: We do this here because this is the most convenient place, where ! 1510: we already have a pointer to the name and the length of the name. */ ! 1511: ! 1512: if (isfuncname && (work->constructor & 1 || work->destructor & 1)) ! 1513: { ! 1514: string_appendn (&temp, "::", 2); ! 1515: if (work -> destructor & 1) ! 1516: { ! 1517: string_append (&temp, "~"); ! 1518: } ! 1519: string_appendn (&temp, (*mangled) - namelength, namelength); ! 1520: } ! 1521: ! 1522: /* Now either prepend the temp buffer to the result, or append it, ! 1523: depending upon the state of the append flag. */ ! 1524: ! 1525: if (append) ! 1526: { ! 1527: string_appends (result, &temp); ! 1528: } ! 1529: else ! 1530: { ! 1531: if (!STRING_EMPTY (result)) ! 1532: { ! 1533: string_appendn (&temp, "::", 2); ! 1534: } ! 1535: string_prepends (result, &temp); ! 1536: } ! 1537: ! 1538: string_delete (&temp); ! 1539: return (success); ! 1540: } ! 1541: ! 1542: /* ! 1543: ! 1544: LOCAL FUNCTION ! 1545: ! 1546: get_count -- convert an ascii count to integer, consuming tokens ! 1547: ! 1548: SYNOPSIS ! 1549: ! 1550: static int ! 1551: get_count (const char **type, int *count) ! 1552: ! 1553: DESCRIPTION ! 1554: ! 1555: Return 0 if no conversion is performed, 1 if a string is converted. ! 1556: */ ! 1557: ! 1558: static int ! 1559: get_count (type, count) ! 1560: CONST char **type; ! 1561: int *count; ! 1562: { ! 1563: CONST char *p; ! 1564: int n; ! 1565: ! 1566: if (!isdigit (**type)) ! 1567: { ! 1568: return (0); ! 1569: } ! 1570: else ! 1571: { ! 1572: *count = **type - '0'; ! 1573: (*type)++; ! 1574: if (isdigit (**type)) ! 1575: { ! 1576: p = *type; ! 1577: n = *count; ! 1578: do ! 1579: { ! 1580: n *= 10; ! 1581: n += *p - '0'; ! 1582: p++; ! 1583: } ! 1584: while (isdigit (*p)); ! 1585: if (*p == '_') ! 1586: { ! 1587: *type = p + 1; ! 1588: *count = n; ! 1589: } ! 1590: } ! 1591: } ! 1592: return (1); ! 1593: } ! 1594: ! 1595: /* result will be initialised here; it will be freed on failure */ ! 1596: ! 1597: static int ! 1598: do_type (work, mangled, result) ! 1599: struct work_stuff *work; ! 1600: CONST char **mangled; ! 1601: string *result; ! 1602: { ! 1603: int n; ! 1604: int done; ! 1605: int success; ! 1606: string decl; ! 1607: CONST char *remembered_type; ! 1608: int constp; ! 1609: int volatilep; ! 1610: ! 1611: string_init (&decl); ! 1612: string_init (result); ! 1613: ! 1614: done = 0; ! 1615: success = 1; ! 1616: while (success && !done) ! 1617: { ! 1618: int member; ! 1619: switch (**mangled) ! 1620: { ! 1621: ! 1622: /* A pointer type */ ! 1623: case 'P': ! 1624: (*mangled)++; ! 1625: string_prepend (&decl, "*"); ! 1626: break; ! 1627: ! 1628: /* A reference type */ ! 1629: case 'R': ! 1630: (*mangled)++; ! 1631: string_prepend (&decl, "&"); ! 1632: break; ! 1633: ! 1634: /* An array */ ! 1635: case 'A': ! 1636: { ! 1637: CONST char *p = ++(*mangled); ! 1638: ! 1639: string_prepend (&decl, "("); ! 1640: string_append (&decl, ")["); ! 1641: /* Copy anything up until the next underscore (the size of the ! 1642: array). */ ! 1643: while (**mangled && **mangled != '_') ! 1644: ++(*mangled); ! 1645: if (**mangled == '_') ! 1646: { ! 1647: string_appendn (&decl, p, *mangled - p); ! 1648: string_append (&decl, "]"); ! 1649: *mangled += 1; ! 1650: } ! 1651: else ! 1652: success = 0; ! 1653: break; ! 1654: } ! 1655: ! 1656: /* A back reference to a previously seen type */ ! 1657: case 'T': ! 1658: (*mangled)++; ! 1659: if (!get_count (mangled, &n) || n >= work -> ntypes) ! 1660: { ! 1661: success = 0; ! 1662: } ! 1663: else ! 1664: { ! 1665: remembered_type = work -> typevec[n]; ! 1666: mangled = &remembered_type; ! 1667: } ! 1668: break; ! 1669: ! 1670: /* A function */ ! 1671: case 'F': ! 1672: (*mangled)++; ! 1673: if (!STRING_EMPTY (&decl) && decl.b[0] == '*') ! 1674: { ! 1675: string_prepend (&decl, "("); ! 1676: string_append (&decl, ")"); ! 1677: } ! 1678: /* After picking off the function args, we expect to either find the ! 1679: function return type (preceded by an '_') or the end of the ! 1680: string. */ ! 1681: if (!demangle_args (work, mangled, &decl) ! 1682: || (**mangled != '_' && **mangled != '\0')) ! 1683: { ! 1684: success = 0; ! 1685: } ! 1686: if (success && (**mangled == '_')) ! 1687: { ! 1688: (*mangled)++; ! 1689: } ! 1690: break; ! 1691: ! 1692: case 'M': ! 1693: case 'O': ! 1694: { ! 1695: constp = 0; ! 1696: volatilep = 0; ! 1697: ! 1698: member = **mangled == 'M'; ! 1699: (*mangled)++; ! 1700: if (!isdigit (**mangled)) ! 1701: { ! 1702: success = 0; ! 1703: break; ! 1704: } ! 1705: n = consume_count (mangled); ! 1706: if (strlen (*mangled) < n) ! 1707: { ! 1708: success = 0; ! 1709: break; ! 1710: } ! 1711: string_append (&decl, ")"); ! 1712: string_prepend (&decl, "::"); ! 1713: string_prependn (&decl, *mangled, n); ! 1714: string_prepend (&decl, "("); ! 1715: *mangled += n; ! 1716: if (member) ! 1717: { ! 1718: if (**mangled == 'C') ! 1719: { ! 1720: (*mangled)++; ! 1721: constp = 1; ! 1722: } ! 1723: if (**mangled == 'V') ! 1724: { ! 1725: (*mangled)++; ! 1726: volatilep = 1; ! 1727: } ! 1728: if (*(*mangled)++ != 'F') ! 1729: { ! 1730: success = 0; ! 1731: break; ! 1732: } ! 1733: } ! 1734: if ((member && !demangle_args (work, mangled, &decl)) ! 1735: || **mangled != '_') ! 1736: { ! 1737: success = 0; ! 1738: break; ! 1739: } ! 1740: (*mangled)++; ! 1741: if (! PRINT_ANSI_QUALIFIERS) ! 1742: { ! 1743: break; ! 1744: } ! 1745: if (constp) ! 1746: { ! 1747: APPEND_BLANK (&decl); ! 1748: string_append (&decl, "const"); ! 1749: } ! 1750: if (volatilep) ! 1751: { ! 1752: APPEND_BLANK (&decl); ! 1753: string_append (&decl, "volatile"); ! 1754: } ! 1755: break; ! 1756: } ! 1757: case 'G': ! 1758: (*mangled)++; ! 1759: break; ! 1760: ! 1761: case 'C': ! 1762: (*mangled)++; ! 1763: /* ! 1764: if ((*mangled)[1] == 'P') ! 1765: { ! 1766: */ ! 1767: if (PRINT_ANSI_QUALIFIERS) ! 1768: { ! 1769: if (!STRING_EMPTY (&decl)) ! 1770: { ! 1771: string_prepend (&decl, " "); ! 1772: } ! 1773: string_prepend (&decl, "const"); ! 1774: } ! 1775: break; ! 1776: /* ! 1777: } ! 1778: */ ! 1779: ! 1780: /* fall through */ ! 1781: default: ! 1782: done = 1; ! 1783: break; ! 1784: } ! 1785: } ! 1786: ! 1787: switch (**mangled) ! 1788: { ! 1789: /* A qualified name, such as "Outer::Inner". */ ! 1790: case 'Q': ! 1791: success = demangle_qualified (work, mangled, result, 0, 1); ! 1792: break; ! 1793: ! 1794: default: ! 1795: success = demangle_fund_type (work, mangled, result); ! 1796: break; ! 1797: } ! 1798: ! 1799: if (success) ! 1800: { ! 1801: if (!STRING_EMPTY (&decl)) ! 1802: { ! 1803: string_append (result, " "); ! 1804: string_appends (result, &decl); ! 1805: } ! 1806: } ! 1807: else ! 1808: { ! 1809: string_delete (result); ! 1810: } ! 1811: string_delete (&decl); ! 1812: return (success); ! 1813: } ! 1814: ! 1815: /* Given a pointer to a type string that represents a fundamental type ! 1816: argument (int, long, unsigned int, etc) in TYPE, a pointer to the ! 1817: string in which the demangled output is being built in RESULT, and ! 1818: the WORK structure, decode the types and add them to the result. ! 1819: ! 1820: For example: ! 1821: ! 1822: "Ci" => "const int" ! 1823: "Sl" => "signed long" ! 1824: "CUs" => "const unsigned short" ! 1825: ! 1826: */ ! 1827: ! 1828: static int ! 1829: demangle_fund_type (work, mangled, result) ! 1830: struct work_stuff *work; ! 1831: CONST char **mangled; ! 1832: string *result; ! 1833: { ! 1834: int done = 0; ! 1835: int success = 1; ! 1836: ! 1837: /* First pick off any type qualifiers. There can be more than one. */ ! 1838: ! 1839: while (!done) ! 1840: { ! 1841: switch (**mangled) ! 1842: { ! 1843: case 'C': ! 1844: (*mangled)++; ! 1845: if (PRINT_ANSI_QUALIFIERS) ! 1846: { ! 1847: APPEND_BLANK (result); ! 1848: string_append (result, "const"); ! 1849: } ! 1850: break; ! 1851: case 'U': ! 1852: (*mangled)++; ! 1853: APPEND_BLANK (result); ! 1854: string_append (result, "unsigned"); ! 1855: break; ! 1856: case 'S': /* signed char only */ ! 1857: (*mangled)++; ! 1858: APPEND_BLANK (result); ! 1859: string_append (result, "signed"); ! 1860: break; ! 1861: case 'V': ! 1862: (*mangled)++; ! 1863: if (PRINT_ANSI_QUALIFIERS) ! 1864: { ! 1865: APPEND_BLANK (result); ! 1866: string_append (result, "volatile"); ! 1867: } ! 1868: break; ! 1869: default: ! 1870: done = 1; ! 1871: break; ! 1872: } ! 1873: } ! 1874: ! 1875: /* Now pick off the fundamental type. There can be only one. */ ! 1876: ! 1877: switch (**mangled) ! 1878: { ! 1879: case '\0': ! 1880: case '_': ! 1881: break; ! 1882: case 'v': ! 1883: (*mangled)++; ! 1884: APPEND_BLANK (result); ! 1885: string_append (result, "void"); ! 1886: break; ! 1887: case 'x': ! 1888: (*mangled)++; ! 1889: APPEND_BLANK (result); ! 1890: string_append (result, "long long"); ! 1891: break; ! 1892: case 'l': ! 1893: (*mangled)++; ! 1894: APPEND_BLANK (result); ! 1895: string_append (result, "long"); ! 1896: break; ! 1897: case 'i': ! 1898: (*mangled)++; ! 1899: APPEND_BLANK (result); ! 1900: string_append (result, "int"); ! 1901: break; ! 1902: case 's': ! 1903: (*mangled)++; ! 1904: APPEND_BLANK (result); ! 1905: string_append (result, "short"); ! 1906: break; ! 1907: case 'c': ! 1908: (*mangled)++; ! 1909: APPEND_BLANK (result); ! 1910: string_append (result, "char"); ! 1911: break; ! 1912: case 'w': ! 1913: (*mangled)++; ! 1914: APPEND_BLANK (result); ! 1915: string_append (result, "wchar_t"); ! 1916: break; ! 1917: case 'r': ! 1918: (*mangled)++; ! 1919: APPEND_BLANK (result); ! 1920: string_append (result, "long double"); ! 1921: break; ! 1922: case 'd': ! 1923: (*mangled)++; ! 1924: APPEND_BLANK (result); ! 1925: string_append (result, "double"); ! 1926: break; ! 1927: case 'f': ! 1928: (*mangled)++; ! 1929: APPEND_BLANK (result); ! 1930: string_append (result, "float"); ! 1931: break; ! 1932: case 'G': ! 1933: (*mangled)++; ! 1934: if (!isdigit (**mangled)) ! 1935: { ! 1936: success = 0; ! 1937: break; ! 1938: } ! 1939: /* fall through */ ! 1940: /* An explicit type, such as "6mytype" or "7integer" */ ! 1941: case '0': ! 1942: case '1': ! 1943: case '2': ! 1944: case '3': ! 1945: case '4': ! 1946: case '5': ! 1947: case '6': ! 1948: case '7': ! 1949: case '8': ! 1950: case '9': ! 1951: APPEND_BLANK (result); ! 1952: if (!demangle_class_name (work, mangled, result)) { ! 1953: --result->p; ! 1954: success = 0; ! 1955: } ! 1956: break; ! 1957: case 't': ! 1958: success = demangle_template(work,mangled, result, 0); ! 1959: break; ! 1960: default: ! 1961: success = 0; ! 1962: break; ! 1963: } ! 1964: ! 1965: return (success); ! 1966: } ! 1967: ! 1968: /* `result' will be initialized in do_type; it will be freed on failure */ ! 1969: ! 1970: static int ! 1971: do_arg (work, mangled, result) ! 1972: struct work_stuff *work; ! 1973: CONST char **mangled; ! 1974: string *result; ! 1975: { ! 1976: CONST char *start = *mangled; ! 1977: ! 1978: if (!do_type (work, mangled, result)) ! 1979: { ! 1980: return (0); ! 1981: } ! 1982: else ! 1983: { ! 1984: remember_type (work, start, *mangled - start); ! 1985: return (1); ! 1986: } ! 1987: } ! 1988: ! 1989: static void ! 1990: remember_type (work, start, len) ! 1991: struct work_stuff *work; ! 1992: CONST char *start; ! 1993: int len; ! 1994: { ! 1995: char *tem; ! 1996: ! 1997: if (work -> ntypes >= work -> typevec_size) ! 1998: { ! 1999: if (work -> typevec_size == 0) ! 2000: { ! 2001: work -> typevec_size = 3; ! 2002: work -> typevec = ! 2003: (char **) xmalloc (sizeof (char *) * work -> typevec_size); ! 2004: } ! 2005: else ! 2006: { ! 2007: work -> typevec_size *= 2; ! 2008: work -> typevec = ! 2009: (char **) xrealloc ((char *)work -> typevec, ! 2010: sizeof (char *) * work -> typevec_size); ! 2011: } ! 2012: } ! 2013: tem = xmalloc (len + 1); ! 2014: memcpy (tem, start, len); ! 2015: tem[len] = '\0'; ! 2016: work -> typevec[work -> ntypes++] = tem; ! 2017: } ! 2018: ! 2019: /* Forget the remembered types, but not the type vector itself. */ ! 2020: ! 2021: static void ! 2022: forget_types (work) ! 2023: struct work_stuff *work; ! 2024: { ! 2025: int i; ! 2026: ! 2027: while (work -> ntypes > 0) ! 2028: { ! 2029: i = --(work -> ntypes); ! 2030: if (work -> typevec[i] != NULL) ! 2031: { ! 2032: free (work -> typevec[i]); ! 2033: work -> typevec[i] = NULL; ! 2034: } ! 2035: } ! 2036: } ! 2037: ! 2038: /* Process the argument list part of the signature, after any class spec ! 2039: has been consumed, as well as the first 'F' character (if any). For ! 2040: example: ! 2041: ! 2042: "__als__3fooRT0" => process "RT0" ! 2043: "complexfunc5__FPFPc_PFl_i" => process "PFPc_PFl_i" ! 2044: ! 2045: DECLP must be already initialised, usually non-empty. It won't be freed ! 2046: on failure. ! 2047: ! 2048: Note that g++ differs significantly from ARM and lucid style mangling ! 2049: with regards to references to previously seen types. For example, given ! 2050: the source fragment: ! 2051: ! 2052: class foo { ! 2053: public: ! 2054: foo::foo (int, foo &ia, int, foo &ib, int, foo &ic); ! 2055: }; ! 2056: ! 2057: foo::foo (int, foo &ia, int, foo &ib, int, foo &ic) { ia = ib = ic; } ! 2058: void foo (int, foo &ia, int, foo &ib, int, foo &ic) { ia = ib = ic; } ! 2059: ! 2060: g++ produces the names: ! 2061: ! 2062: __3fooiRT0iT2iT2 ! 2063: foo__FiR3fooiT1iT1 ! 2064: ! 2065: while lcc (and presumably other ARM style compilers as well) produces: ! 2066: ! 2067: foo__FiR3fooT1T2T1T2 ! 2068: __ct__3fooFiR3fooT1T2T1T2 ! 2069: ! 2070: Note that g++ bases it's type numbers starting at zero and counts all ! 2071: previously seen types, while lucid/ARM bases it's type numbers starting ! 2072: at one and only considers types after it has seen the 'F' character ! 2073: indicating the start of the function args. For lucid/ARM style, we ! 2074: account for this difference by discarding any previously seen types when ! 2075: we see the 'F' character, and subtracting one from the type number ! 2076: reference. ! 2077: ! 2078: */ ! 2079: ! 2080: static int ! 2081: demangle_args (work, mangled, declp) ! 2082: struct work_stuff *work; ! 2083: CONST char **mangled; ! 2084: string *declp; ! 2085: { ! 2086: string arg; ! 2087: int need_comma = 0; ! 2088: int r; ! 2089: int t; ! 2090: CONST char *tem; ! 2091: char temptype; ! 2092: ! 2093: if (PRINT_ARG_TYPES) ! 2094: { ! 2095: string_append (declp, "("); ! 2096: if (**mangled == '\0') ! 2097: { ! 2098: string_append (declp, "void"); ! 2099: } ! 2100: } ! 2101: ! 2102: while (**mangled != '_' && **mangled != '\0' && **mangled != 'e') ! 2103: { ! 2104: if ((**mangled == 'N') || (**mangled == 'T')) ! 2105: { ! 2106: temptype = *(*mangled)++; ! 2107: ! 2108: if (temptype == 'N') ! 2109: { ! 2110: if (!get_count (mangled, &r)) ! 2111: { ! 2112: return (0); ! 2113: } ! 2114: } ! 2115: else ! 2116: { ! 2117: r = 1; ! 2118: } ! 2119: if (!get_count (mangled, &t)) ! 2120: { ! 2121: return (0); ! 2122: } ! 2123: if (LUCID_DEMANGLING || ARM_DEMANGLING) ! 2124: { ! 2125: t--; ! 2126: } ! 2127: /* Validate the type index. Protect against illegal indices from ! 2128: malformed type strings. */ ! 2129: if ((t < 0) || (t >= work -> ntypes)) ! 2130: { ! 2131: return (0); ! 2132: } ! 2133: while (--r >= 0) ! 2134: { ! 2135: tem = work -> typevec[t]; ! 2136: if (need_comma && PRINT_ARG_TYPES) ! 2137: { ! 2138: string_append (declp, ", "); ! 2139: } ! 2140: if (!do_arg (work, &tem, &arg)) ! 2141: { ! 2142: return (0); ! 2143: } ! 2144: if (PRINT_ARG_TYPES) ! 2145: { ! 2146: string_appends (declp, &arg); ! 2147: } ! 2148: string_delete (&arg); ! 2149: need_comma = 1; ! 2150: } ! 2151: } ! 2152: else ! 2153: { ! 2154: if (need_comma & PRINT_ARG_TYPES) ! 2155: { ! 2156: string_append (declp, ", "); ! 2157: } ! 2158: if (!do_arg (work, mangled, &arg)) ! 2159: { ! 2160: return (0); ! 2161: } ! 2162: if (PRINT_ARG_TYPES) ! 2163: { ! 2164: string_appends (declp, &arg); ! 2165: } ! 2166: string_delete (&arg); ! 2167: need_comma = 1; ! 2168: } ! 2169: } ! 2170: ! 2171: if (**mangled == 'e') ! 2172: { ! 2173: (*mangled)++; ! 2174: if (PRINT_ARG_TYPES) ! 2175: { ! 2176: if (need_comma) ! 2177: { ! 2178: string_append (declp, ","); ! 2179: } ! 2180: string_append (declp, "..."); ! 2181: } ! 2182: } ! 2183: ! 2184: if (PRINT_ARG_TYPES) ! 2185: { ! 2186: string_append (declp, ")"); ! 2187: } ! 2188: return (1); ! 2189: } ! 2190: ! 2191: static void ! 2192: demangle_function_name (work, mangled, declp, scan) ! 2193: struct work_stuff *work; ! 2194: CONST char **mangled; ! 2195: string *declp; ! 2196: CONST char *scan; ! 2197: { ! 2198: int i; ! 2199: int len; ! 2200: string type; ! 2201: CONST char *tem; ! 2202: ! 2203: string_appendn (declp, (*mangled), scan - (*mangled)); ! 2204: string_need (declp, 1); ! 2205: *(declp -> p) = '\0'; ! 2206: ! 2207: /* Consume the function name, including the "__" separating the name ! 2208: from the signature. We are guaranteed that SCAN points to the ! 2209: separator. */ ! 2210: ! 2211: (*mangled) = scan + 2; ! 2212: ! 2213: if (LUCID_DEMANGLING || ARM_DEMANGLING) ! 2214: { ! 2215: ! 2216: /* See if we have an ARM style constructor or destructor operator. ! 2217: If so, then just record it, clear the decl, and return. ! 2218: We can't build the actual constructor/destructor decl until later, ! 2219: when we recover the class name from the signature. */ ! 2220: ! 2221: if (strcmp (declp -> b, "__ct") == 0) ! 2222: { ! 2223: work -> constructor += 1; ! 2224: string_clear (declp); ! 2225: return; ! 2226: } ! 2227: else if (strcmp (declp -> b, "__dt") == 0) ! 2228: { ! 2229: work -> destructor += 1; ! 2230: string_clear (declp); ! 2231: return; ! 2232: } ! 2233: } ! 2234: ! 2235: if (declp->p - declp->b >= 3 ! 2236: && declp->b[0] == 'o' ! 2237: && declp->b[1] == 'p' ! 2238: && strchr (cplus_markers, declp->b[2]) != NULL) ! 2239: { ! 2240: /* see if it's an assignment expression */ ! 2241: if (declp->p - declp->b >= 10 /* op$assign_ */ ! 2242: && memcmp (declp->b + 3, "assign_", 7) == 0) ! 2243: { ! 2244: for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++) ! 2245: { ! 2246: len = declp->p - declp->b - 10; ! 2247: if (strlen (optable[i].in) == len ! 2248: && memcmp (optable[i].in, declp->b + 10, len) == 0) ! 2249: { ! 2250: string_clear (declp); ! 2251: string_append (declp, "operator"); ! 2252: string_append (declp, optable[i].out); ! 2253: string_append (declp, "="); ! 2254: break; ! 2255: } ! 2256: } ! 2257: } ! 2258: else ! 2259: { ! 2260: for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++) ! 2261: { ! 2262: int len = declp->p - declp->b - 3; ! 2263: if (strlen (optable[i].in) == len ! 2264: && memcmp (optable[i].in, declp->b + 3, len) == 0) ! 2265: { ! 2266: string_clear (declp); ! 2267: string_append (declp, "operator"); ! 2268: string_append (declp, optable[i].out); ! 2269: break; ! 2270: } ! 2271: } ! 2272: } ! 2273: } ! 2274: else if (declp->p - declp->b >= 5 && memcmp (declp->b, "type$", 5) == 0) ! 2275: { ! 2276: /* type conversion operator */ ! 2277: tem = declp->b + 5; ! 2278: if (do_type (work, &tem, &type)) ! 2279: { ! 2280: string_clear (declp); ! 2281: string_append (declp, "operator "); ! 2282: string_appends (declp, &type); ! 2283: string_delete (&type); ! 2284: } ! 2285: } ! 2286: else if (declp->b[0] == '_' && declp->b[1] == '_' ! 2287: && declp->b[2] == 'o' && declp->b[3] == 'p') ! 2288: { ! 2289: /* ANSI. */ ! 2290: /* type conversion operator. */ ! 2291: tem = declp->b + 4; ! 2292: if (do_type (work, &tem, &type)) ! 2293: { ! 2294: string_clear (declp); ! 2295: string_append (declp, "operator "); ! 2296: string_appends (declp, &type); ! 2297: string_delete (&type); ! 2298: } ! 2299: } ! 2300: else if (declp->b[0] == '_' && declp->b[1] == '_' ! 2301: && declp->b[2] >= 'a' && declp->b[2] <= 'z' ! 2302: && declp->b[3] >= 'a' && declp->b[3] <= 'z') ! 2303: { ! 2304: if (declp->b[4] == '\0') ! 2305: { ! 2306: /* Operator. */ ! 2307: for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++) ! 2308: { ! 2309: if (strlen (optable[i].in) == 2 ! 2310: && memcmp (optable[i].in, declp->b + 2, 2) == 0) ! 2311: { ! 2312: string_clear (declp); ! 2313: string_append (declp, "operator"); ! 2314: string_append (declp, optable[i].out); ! 2315: break; ! 2316: } ! 2317: } ! 2318: } ! 2319: else ! 2320: { ! 2321: if (declp->b[2] == 'a' && declp->b[5] == '\0') ! 2322: { ! 2323: /* Assignment. */ ! 2324: for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++) ! 2325: { ! 2326: if (strlen (optable[i].in) == 3 ! 2327: && memcmp (optable[i].in, declp->b + 2, 3) == 0) ! 2328: { ! 2329: string_clear (declp); ! 2330: string_append (declp, "operator"); ! 2331: string_append (declp, optable[i].out); ! 2332: break; ! 2333: } ! 2334: } ! 2335: } ! 2336: } ! 2337: } ! 2338: } ! 2339: ! 2340: /* a mini string-handling package */ ! 2341: ! 2342: static void ! 2343: string_need (s, n) ! 2344: string *s; ! 2345: int n; ! 2346: { ! 2347: int tem; ! 2348: ! 2349: if (s->b == NULL) ! 2350: { ! 2351: if (n < 32) ! 2352: { ! 2353: n = 32; ! 2354: } ! 2355: s->p = s->b = xmalloc (n); ! 2356: s->e = s->b + n; ! 2357: } ! 2358: else if (s->e - s->p < n) ! 2359: { ! 2360: tem = s->p - s->b; ! 2361: n += tem; ! 2362: n *= 2; ! 2363: s->b = xrealloc (s->b, n); ! 2364: s->p = s->b + tem; ! 2365: s->e = s->b + n; ! 2366: } ! 2367: } ! 2368: ! 2369: static void ! 2370: string_delete (s) ! 2371: string *s; ! 2372: { ! 2373: if (s->b != NULL) ! 2374: { ! 2375: free (s->b); ! 2376: s->b = s->e = s->p = NULL; ! 2377: } ! 2378: } ! 2379: ! 2380: static void ! 2381: string_init (s) ! 2382: string *s; ! 2383: { ! 2384: s->b = s->p = s->e = NULL; ! 2385: } ! 2386: ! 2387: static void ! 2388: string_clear (s) ! 2389: string *s; ! 2390: { ! 2391: s->p = s->b; ! 2392: } ! 2393: ! 2394: #if 0 ! 2395: ! 2396: static int ! 2397: string_empty (s) ! 2398: string *s; ! 2399: { ! 2400: return (s->b == s->p); ! 2401: } ! 2402: ! 2403: #endif ! 2404: ! 2405: static void ! 2406: string_append (p, s) ! 2407: string *p; ! 2408: CONST char *s; ! 2409: { ! 2410: int n; ! 2411: if (s == NULL || *s == '\0') ! 2412: return; ! 2413: n = strlen (s); ! 2414: string_need (p, n); ! 2415: memcpy (p->p, s, n); ! 2416: p->p += n; ! 2417: } ! 2418: ! 2419: static void ! 2420: string_appends (p, s) ! 2421: string *p, *s; ! 2422: { ! 2423: int n; ! 2424: ! 2425: if (s->b != s->p) ! 2426: { ! 2427: n = s->p - s->b; ! 2428: string_need (p, n); ! 2429: memcpy (p->p, s->b, n); ! 2430: p->p += n; ! 2431: } ! 2432: } ! 2433: ! 2434: static void ! 2435: string_appendn (p, s, n) ! 2436: string *p; ! 2437: CONST char *s; ! 2438: int n; ! 2439: { ! 2440: if (n != 0) ! 2441: { ! 2442: string_need (p, n); ! 2443: memcpy (p->p, s, n); ! 2444: p->p += n; ! 2445: } ! 2446: } ! 2447: ! 2448: static void ! 2449: string_prepend (p, s) ! 2450: string *p; ! 2451: CONST char *s; ! 2452: { ! 2453: if (s != NULL && *s != '\0') ! 2454: { ! 2455: string_prependn (p, s, strlen (s)); ! 2456: } ! 2457: } ! 2458: ! 2459: static void ! 2460: string_prepends (p, s) ! 2461: string *p, *s; ! 2462: { ! 2463: if (s->b != s->p) ! 2464: { ! 2465: string_prependn (p, s->b, s->p - s->b); ! 2466: } ! 2467: } ! 2468: ! 2469: static void ! 2470: string_prependn (p, s, n) ! 2471: string *p; ! 2472: CONST char *s; ! 2473: int n; ! 2474: { ! 2475: char *q; ! 2476: ! 2477: if (n != 0) ! 2478: { ! 2479: string_need (p, n); ! 2480: for (q = p->p - 1; q >= p->b; q--) ! 2481: { ! 2482: q[n] = q[0]; ! 2483: } ! 2484: memcpy (p->b, s, n); ! 2485: p->p += n; ! 2486: } ! 2487: } ! 2488: ! 2489: /* To generate a standalone demangler program for testing purposes, just ! 2490: compile and link this file with -DMAIN. When run, it demangles each ! 2491: command line arg, or each stdin string, and prints the result on stdout. */ ! 2492: ! 2493: #ifdef MAIN ! 2494: ! 2495: static void ! 2496: demangle_it (mangled_name) ! 2497: char *mangled_name; ! 2498: { ! 2499: char *result; ! 2500: ! 2501: result = cplus_demangle (mangled_name, DMGL_PARAMS | DMGL_ANSI); ! 2502: if (result == NULL) ! 2503: { ! 2504: printf ("%s\n", mangled_name); ! 2505: } ! 2506: else ! 2507: { ! 2508: printf ("%s\n", result); ! 2509: free (result); ! 2510: } ! 2511: } ! 2512: ! 2513: char * ! 2514: xmalloc (size) ! 2515: long size; ! 2516: { ! 2517: char * newmem; ! 2518: ! 2519: if ((newmem = (char *) malloc ((int) size)) == NULL) ! 2520: { ! 2521: fprintf (stderr, "\nCan't allocate %u bytes\n", size); ! 2522: exit (1); ! 2523: } ! 2524: return (newmem); ! 2525: } ! 2526: ! 2527: char * ! 2528: xrealloc (oldmem, size) ! 2529: PTR oldmem; ! 2530: long size; ! 2531: { ! 2532: char * newmem; ! 2533: ! 2534: if ((newmem = (char *) realloc ((char *) oldmem, (int) size)) == NULL) ! 2535: { ! 2536: fprintf (stderr, "\nCan't reallocate %u bytes\n", size); ! 2537: exit (1); ! 2538: } ! 2539: return (newmem); ! 2540: } ! 2541: ! 2542: #include "getopt.h" ! 2543: ! 2544: static char *program_name; ! 2545: extern char *program_version; ! 2546: ! 2547: static void ! 2548: usage (stream, status) ! 2549: FILE *stream; ! 2550: int status; ! 2551: { ! 2552: fprintf (stream, "\ ! 2553: Usage: %s [-_] [-s {gnu,lucid,arm}] [--strip-underscores]\n\ ! 2554: [--format={gnu,lucid,arm}] [--help] [--version] [arg...]\n", ! 2555: program_name); ! 2556: exit (status); ! 2557: } ! 2558: ! 2559: #define MBUF_SIZE 512 ! 2560: char mbuffer[MBUF_SIZE]; ! 2561: ! 2562: /* Defined in the automatically-generated ../binutils/underscore.c. */ ! 2563: extern int prepends_underscore; ! 2564: ! 2565: int strip_underscore = 0; ! 2566: ! 2567: static struct option long_options[] = { ! 2568: {"strip-underscores", no_argument, 0, '_'}, ! 2569: {"format", required_argument, 0, 's'}, ! 2570: {"help", no_argument, 0, 'h'}, ! 2571: {"version", no_argument, 0, 'v'}, ! 2572: {0, no_argument, 0, 0} ! 2573: }; ! 2574: ! 2575: int ! 2576: main (argc, argv) ! 2577: int argc; ! 2578: char **argv; ! 2579: { ! 2580: char *result; ! 2581: int c; ! 2582: ! 2583: program_name = argv[0]; ! 2584: strip_underscore = prepends_underscore; ! 2585: ! 2586: while ((c = getopt_long (argc, argv, "_s:", long_options, (int *) 0)) != EOF) ! 2587: { ! 2588: switch (c) ! 2589: { ! 2590: case '?': ! 2591: usage (stderr, 1); ! 2592: break; ! 2593: case 'h': ! 2594: usage (stdout, 0); ! 2595: case 'v': ! 2596: printf ("GNU %s version %s\n", program_name, program_version); ! 2597: exit (0); ! 2598: case '_': ! 2599: strip_underscore = 1; ! 2600: break; ! 2601: case 's': ! 2602: if (strcmp (optarg, "gnu") == 0) ! 2603: { ! 2604: current_demangling_style = gnu_demangling; ! 2605: } ! 2606: else if (strcmp (optarg, "lucid") == 0) ! 2607: { ! 2608: current_demangling_style = lucid_demangling; ! 2609: } ! 2610: else if (strcmp (optarg, "arm") == 0) ! 2611: { ! 2612: current_demangling_style = arm_demangling; ! 2613: } ! 2614: else ! 2615: { ! 2616: fprintf (stderr, "%s: unknown demangling style `%s'\n", ! 2617: program_name, optarg); ! 2618: exit (1); ! 2619: } ! 2620: break; ! 2621: } ! 2622: } ! 2623: ! 2624: if (optind < argc) ! 2625: { ! 2626: for ( ; optind < argc; optind++) ! 2627: { ! 2628: demangle_it (argv[optind]); ! 2629: } ! 2630: } ! 2631: else ! 2632: { ! 2633: for (;;) ! 2634: { ! 2635: int i = 0; ! 2636: c = getchar (); ! 2637: /* Try to read a label. */ ! 2638: while (c != EOF && (isalnum(c) || c == '_' || c == '$' || c == '.')) ! 2639: { ! 2640: if (i >= MBUF_SIZE-1) ! 2641: break; ! 2642: mbuffer[i++] = c; ! 2643: c = getchar (); ! 2644: } ! 2645: if (i > 0) ! 2646: { ! 2647: int skip_first = strip_underscore && i > 1 && mbuffer[0] == '_'; ! 2648: mbuffer[i] = 0; ! 2649: ! 2650: result = cplus_demangle (mbuffer+skip_first, ! 2651: DMGL_PARAMS | DMGL_ANSI); ! 2652: if (result) ! 2653: { ! 2654: fputs (result, stdout); ! 2655: free (result); ! 2656: } ! 2657: else ! 2658: fputs (mbuffer + skip_first, stdout); ! 2659: } ! 2660: if (c == EOF) ! 2661: break; ! 2662: putchar (c); ! 2663: } ! 2664: } ! 2665: ! 2666: exit (0); ! 2667: } ! 2668: ! 2669: #endif /* main */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.