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