cplus-dem.c revision 33965
133965Sjdp/* Demangler for GNU C++ 233965Sjdp Copyright 1989, 1991, 1994, 1995, 1996, 1997 Free Software Foundation, Inc. 333965Sjdp Written by James Clark (jjc@jclark.uucp) 433965Sjdp Rewritten by Fred Fish (fnf@cygnus.com) for ARM and Lucid demangling 533965Sjdp 633965SjdpThis file is part of the libiberty library. 733965SjdpLibiberty is free software; you can redistribute it and/or 833965Sjdpmodify it under the terms of the GNU Library General Public 933965SjdpLicense as published by the Free Software Foundation; either 1033965Sjdpversion 2 of the License, or (at your option) any later version. 1133965Sjdp 1233965SjdpLibiberty is distributed in the hope that it will be useful, 1333965Sjdpbut WITHOUT ANY WARRANTY; without even the implied warranty of 1433965SjdpMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1533965SjdpLibrary General Public License for more details. 1633965Sjdp 1733965SjdpYou should have received a copy of the GNU Library General Public 1833965SjdpLicense along with libiberty; see the file COPYING.LIB. If 1933965Sjdpnot, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 2033965SjdpBoston, MA 02111-1307, USA. */ 2133965Sjdp 2233965Sjdp/* This file exports two functions; cplus_mangle_opname and cplus_demangle. 2333965Sjdp 2433965Sjdp This file imports xmalloc and xrealloc, which are like malloc and 2533965Sjdp realloc except that they generate a fatal error if there is no 2633965Sjdp available memory. */ 2733965Sjdp 2833965Sjdp/* This file lives in both GCC and libiberty. When making changes, please 2933965Sjdp try not to break either. */ 3033965Sjdp 3133965Sjdp#include <ctype.h> 3233965Sjdp#include <string.h> 3333965Sjdp#include <stdio.h> 3433965Sjdp 3533965Sjdp#include <demangle.h> 3633965Sjdp#undef CURRENT_DEMANGLING_STYLE 3733965Sjdp#define CURRENT_DEMANGLING_STYLE work->options 3833965Sjdp 3933965Sjdpextern char *xmalloc PARAMS((unsigned)); 4033965Sjdpextern char *xrealloc PARAMS((char *, unsigned)); 4133965Sjdp 4233965Sjdpstatic const char *mystrstr PARAMS ((const char *, const char *)); 4333965Sjdp 4433965Sjdpstatic const char * 4533965Sjdpmystrstr (s1, s2) 4633965Sjdp const char *s1, *s2; 4733965Sjdp{ 4833965Sjdp register const char *p = s1; 4933965Sjdp register int len = strlen (s2); 5033965Sjdp 5133965Sjdp for (; (p = strchr (p, *s2)) != 0; p++) 5233965Sjdp { 5333965Sjdp if (strncmp (p, s2, len) == 0) 5433965Sjdp { 5533965Sjdp return (p); 5633965Sjdp } 5733965Sjdp } 5833965Sjdp return (0); 5933965Sjdp} 6033965Sjdp 6133965Sjdp/* In order to allow a single demangler executable to demangle strings 6233965Sjdp using various common values of CPLUS_MARKER, as well as any specific 6333965Sjdp one set at compile time, we maintain a string containing all the 6433965Sjdp commonly used ones, and check to see if the marker we are looking for 6533965Sjdp is in that string. CPLUS_MARKER is usually '$' on systems where the 6633965Sjdp assembler can deal with that. Where the assembler can't, it's usually 6733965Sjdp '.' (but on many systems '.' is used for other things). We put the 6833965Sjdp current defined CPLUS_MARKER first (which defaults to '$'), followed 6933965Sjdp by the next most common value, followed by an explicit '$' in case 7033965Sjdp the value of CPLUS_MARKER is not '$'. 7133965Sjdp 7233965Sjdp We could avoid this if we could just get g++ to tell us what the actual 7333965Sjdp cplus marker character is as part of the debug information, perhaps by 7433965Sjdp ensuring that it is the character that terminates the gcc<n>_compiled 7533965Sjdp marker symbol (FIXME). */ 7633965Sjdp 7733965Sjdp#if !defined (CPLUS_MARKER) 7833965Sjdp#define CPLUS_MARKER '$' 7933965Sjdp#endif 8033965Sjdp 8133965Sjdpenum demangling_styles current_demangling_style = gnu_demangling; 8233965Sjdp 8333965Sjdpstatic char cplus_markers[] = { CPLUS_MARKER, '.', '$', '\0' }; 8433965Sjdp 8533965Sjdpvoid 8633965Sjdpset_cplus_marker_for_demangling (ch) 8733965Sjdp int ch; 8833965Sjdp{ 8933965Sjdp cplus_markers[0] = ch; 9033965Sjdp} 9133965Sjdp 9233965Sjdp/* Stuff that is shared between sub-routines. 9333965Sjdp Using a shared structure allows cplus_demangle to be reentrant. */ 9433965Sjdp 9533965Sjdpstruct work_stuff 9633965Sjdp{ 9733965Sjdp int options; 9833965Sjdp char **typevec; 9933965Sjdp int ntypes; 10033965Sjdp int typevec_size; 10133965Sjdp int constructor; 10233965Sjdp int destructor; 10333965Sjdp int static_type; /* A static member function */ 10433965Sjdp int const_type; /* A const member function */ 10533965Sjdp}; 10633965Sjdp 10733965Sjdp#define PRINT_ANSI_QUALIFIERS (work -> options & DMGL_ANSI) 10833965Sjdp#define PRINT_ARG_TYPES (work -> options & DMGL_PARAMS) 10933965Sjdp 11033965Sjdpstatic const struct optable 11133965Sjdp{ 11233965Sjdp const char *in; 11333965Sjdp const char *out; 11433965Sjdp int flags; 11533965Sjdp} optable[] = { 11633965Sjdp {"nw", " new", DMGL_ANSI}, /* new (1.92, ansi) */ 11733965Sjdp {"dl", " delete", DMGL_ANSI}, /* new (1.92, ansi) */ 11833965Sjdp {"new", " new", 0}, /* old (1.91, and 1.x) */ 11933965Sjdp {"delete", " delete", 0}, /* old (1.91, and 1.x) */ 12033965Sjdp {"vn", " new []", DMGL_ANSI}, /* GNU, pending ansi */ 12133965Sjdp {"vd", " delete []", DMGL_ANSI}, /* GNU, pending ansi */ 12233965Sjdp {"as", "=", DMGL_ANSI}, /* ansi */ 12333965Sjdp {"ne", "!=", DMGL_ANSI}, /* old, ansi */ 12433965Sjdp {"eq", "==", DMGL_ANSI}, /* old, ansi */ 12533965Sjdp {"ge", ">=", DMGL_ANSI}, /* old, ansi */ 12633965Sjdp {"gt", ">", DMGL_ANSI}, /* old, ansi */ 12733965Sjdp {"le", "<=", DMGL_ANSI}, /* old, ansi */ 12833965Sjdp {"lt", "<", DMGL_ANSI}, /* old, ansi */ 12933965Sjdp {"plus", "+", 0}, /* old */ 13033965Sjdp {"pl", "+", DMGL_ANSI}, /* ansi */ 13133965Sjdp {"apl", "+=", DMGL_ANSI}, /* ansi */ 13233965Sjdp {"minus", "-", 0}, /* old */ 13333965Sjdp {"mi", "-", DMGL_ANSI}, /* ansi */ 13433965Sjdp {"ami", "-=", DMGL_ANSI}, /* ansi */ 13533965Sjdp {"mult", "*", 0}, /* old */ 13633965Sjdp {"ml", "*", DMGL_ANSI}, /* ansi */ 13733965Sjdp {"amu", "*=", DMGL_ANSI}, /* ansi (ARM/Lucid) */ 13833965Sjdp {"aml", "*=", DMGL_ANSI}, /* ansi (GNU/g++) */ 13933965Sjdp {"convert", "+", 0}, /* old (unary +) */ 14033965Sjdp {"negate", "-", 0}, /* old (unary -) */ 14133965Sjdp {"trunc_mod", "%", 0}, /* old */ 14233965Sjdp {"md", "%", DMGL_ANSI}, /* ansi */ 14333965Sjdp {"amd", "%=", DMGL_ANSI}, /* ansi */ 14433965Sjdp {"trunc_div", "/", 0}, /* old */ 14533965Sjdp {"dv", "/", DMGL_ANSI}, /* ansi */ 14633965Sjdp {"adv", "/=", DMGL_ANSI}, /* ansi */ 14733965Sjdp {"truth_andif", "&&", 0}, /* old */ 14833965Sjdp {"aa", "&&", DMGL_ANSI}, /* ansi */ 14933965Sjdp {"truth_orif", "||", 0}, /* old */ 15033965Sjdp {"oo", "||", DMGL_ANSI}, /* ansi */ 15133965Sjdp {"truth_not", "!", 0}, /* old */ 15233965Sjdp {"nt", "!", DMGL_ANSI}, /* ansi */ 15333965Sjdp {"postincrement","++", 0}, /* old */ 15433965Sjdp {"pp", "++", DMGL_ANSI}, /* ansi */ 15533965Sjdp {"postdecrement","--", 0}, /* old */ 15633965Sjdp {"mm", "--", DMGL_ANSI}, /* ansi */ 15733965Sjdp {"bit_ior", "|", 0}, /* old */ 15833965Sjdp {"or", "|", DMGL_ANSI}, /* ansi */ 15933965Sjdp {"aor", "|=", DMGL_ANSI}, /* ansi */ 16033965Sjdp {"bit_xor", "^", 0}, /* old */ 16133965Sjdp {"er", "^", DMGL_ANSI}, /* ansi */ 16233965Sjdp {"aer", "^=", DMGL_ANSI}, /* ansi */ 16333965Sjdp {"bit_and", "&", 0}, /* old */ 16433965Sjdp {"ad", "&", DMGL_ANSI}, /* ansi */ 16533965Sjdp {"aad", "&=", DMGL_ANSI}, /* ansi */ 16633965Sjdp {"bit_not", "~", 0}, /* old */ 16733965Sjdp {"co", "~", DMGL_ANSI}, /* ansi */ 16833965Sjdp {"call", "()", 0}, /* old */ 16933965Sjdp {"cl", "()", DMGL_ANSI}, /* ansi */ 17033965Sjdp {"alshift", "<<", 0}, /* old */ 17133965Sjdp {"ls", "<<", DMGL_ANSI}, /* ansi */ 17233965Sjdp {"als", "<<=", DMGL_ANSI}, /* ansi */ 17333965Sjdp {"arshift", ">>", 0}, /* old */ 17433965Sjdp {"rs", ">>", DMGL_ANSI}, /* ansi */ 17533965Sjdp {"ars", ">>=", DMGL_ANSI}, /* ansi */ 17633965Sjdp {"component", "->", 0}, /* old */ 17733965Sjdp {"pt", "->", DMGL_ANSI}, /* ansi; Lucid C++ form */ 17833965Sjdp {"rf", "->", DMGL_ANSI}, /* ansi; ARM/GNU form */ 17933965Sjdp {"indirect", "*", 0}, /* old */ 18033965Sjdp {"method_call", "->()", 0}, /* old */ 18133965Sjdp {"addr", "&", 0}, /* old (unary &) */ 18233965Sjdp {"array", "[]", 0}, /* old */ 18333965Sjdp {"vc", "[]", DMGL_ANSI}, /* ansi */ 18433965Sjdp {"compound", ", ", 0}, /* old */ 18533965Sjdp {"cm", ", ", DMGL_ANSI}, /* ansi */ 18633965Sjdp {"cond", "?:", 0}, /* old */ 18733965Sjdp {"cn", "?:", DMGL_ANSI}, /* pseudo-ansi */ 18833965Sjdp {"max", ">?", 0}, /* old */ 18933965Sjdp {"mx", ">?", DMGL_ANSI}, /* pseudo-ansi */ 19033965Sjdp {"min", "<?", 0}, /* old */ 19133965Sjdp {"mn", "<?", DMGL_ANSI}, /* pseudo-ansi */ 19233965Sjdp {"nop", "", 0}, /* old (for operator=) */ 19333965Sjdp {"rm", "->*", DMGL_ANSI} /* ansi */ 19433965Sjdp}; 19533965Sjdp 19633965Sjdp 19733965Sjdptypedef struct string /* Beware: these aren't required to be */ 19833965Sjdp{ /* '\0' terminated. */ 19933965Sjdp char *b; /* pointer to start of string */ 20033965Sjdp char *p; /* pointer after last character */ 20133965Sjdp char *e; /* pointer after end of allocated space */ 20233965Sjdp} string; 20333965Sjdp 20433965Sjdp#define STRING_EMPTY(str) ((str) -> b == (str) -> p) 20533965Sjdp#define PREPEND_BLANK(str) {if (!STRING_EMPTY(str)) \ 20633965Sjdp string_prepend(str, " ");} 20733965Sjdp#define APPEND_BLANK(str) {if (!STRING_EMPTY(str)) \ 20833965Sjdp string_append(str, " ");} 20933965Sjdp 21033965Sjdp#define ARM_VTABLE_STRING "__vtbl__" /* Lucid/ARM virtual table prefix */ 21133965Sjdp#define ARM_VTABLE_STRLEN 8 /* strlen (ARM_VTABLE_STRING) */ 21233965Sjdp 21333965Sjdp/* Prototypes for local functions */ 21433965Sjdp 21533965Sjdpstatic char * 21633965Sjdpmop_up PARAMS ((struct work_stuff *, string *, int)); 21733965Sjdp 21833965Sjdp#if 0 21933965Sjdpstatic int 22033965Sjdpdemangle_method_args PARAMS ((struct work_stuff *work, const char **, string *)); 22133965Sjdp#endif 22233965Sjdp 22333965Sjdpstatic int 22433965Sjdpdemangle_template PARAMS ((struct work_stuff *work, const char **, string *, 22533965Sjdp string *)); 22633965Sjdp 22733965Sjdpstatic int 22833965Sjdparm_pt PARAMS ((struct work_stuff *, const char *, int, const char **, 22933965Sjdp const char **)); 23033965Sjdp 23133965Sjdpstatic void 23233965Sjdpdemangle_arm_pt PARAMS ((struct work_stuff *, const char **, int, string *)); 23333965Sjdp 23433965Sjdpstatic int 23533965Sjdpdemangle_class_name PARAMS ((struct work_stuff *, const char **, string *)); 23633965Sjdp 23733965Sjdpstatic int 23833965Sjdpdemangle_qualified PARAMS ((struct work_stuff *, const char **, string *, 23933965Sjdp int, int)); 24033965Sjdp 24133965Sjdpstatic int 24233965Sjdpdemangle_class PARAMS ((struct work_stuff *, const char **, string *)); 24333965Sjdp 24433965Sjdpstatic int 24533965Sjdpdemangle_fund_type PARAMS ((struct work_stuff *, const char **, string *)); 24633965Sjdp 24733965Sjdpstatic int 24833965Sjdpdemangle_signature PARAMS ((struct work_stuff *, const char **, string *)); 24933965Sjdp 25033965Sjdpstatic int 25133965Sjdpdemangle_prefix PARAMS ((struct work_stuff *, const char **, string *)); 25233965Sjdp 25333965Sjdpstatic int 25433965Sjdpgnu_special PARAMS ((struct work_stuff *, const char **, string *)); 25533965Sjdp 25633965Sjdpstatic int 25733965Sjdparm_special PARAMS ((struct work_stuff *, const char **, string *)); 25833965Sjdp 25933965Sjdpstatic void 26033965Sjdpstring_need PARAMS ((string *, int)); 26133965Sjdp 26233965Sjdpstatic void 26333965Sjdpstring_delete PARAMS ((string *)); 26433965Sjdp 26533965Sjdpstatic void 26633965Sjdpstring_init PARAMS ((string *)); 26733965Sjdp 26833965Sjdpstatic void 26933965Sjdpstring_clear PARAMS ((string *)); 27033965Sjdp 27133965Sjdp#if 0 27233965Sjdpstatic int 27333965Sjdpstring_empty PARAMS ((string *)); 27433965Sjdp#endif 27533965Sjdp 27633965Sjdpstatic void 27733965Sjdpstring_append PARAMS ((string *, const char *)); 27833965Sjdp 27933965Sjdpstatic void 28033965Sjdpstring_appends PARAMS ((string *, string *)); 28133965Sjdp 28233965Sjdpstatic void 28333965Sjdpstring_appendn PARAMS ((string *, const char *, int)); 28433965Sjdp 28533965Sjdpstatic void 28633965Sjdpstring_prepend PARAMS ((string *, const char *)); 28733965Sjdp 28833965Sjdpstatic void 28933965Sjdpstring_prependn PARAMS ((string *, const char *, int)); 29033965Sjdp 29133965Sjdpstatic int 29233965Sjdpget_count PARAMS ((const char **, int *)); 29333965Sjdp 29433965Sjdpstatic int 29533965Sjdpconsume_count PARAMS ((const char **)); 29633965Sjdp 29733965Sjdpstatic int 29833965Sjdpdemangle_args PARAMS ((struct work_stuff *, const char **, string *)); 29933965Sjdp 30033965Sjdpstatic int 30133965Sjdpdo_type PARAMS ((struct work_stuff *, const char **, string *)); 30233965Sjdp 30333965Sjdpstatic int 30433965Sjdpdo_arg PARAMS ((struct work_stuff *, const char **, string *)); 30533965Sjdp 30633965Sjdpstatic void 30733965Sjdpdemangle_function_name PARAMS ((struct work_stuff *, const char **, string *, 30833965Sjdp const char *)); 30933965Sjdp 31033965Sjdpstatic void 31133965Sjdpremember_type PARAMS ((struct work_stuff *, const char *, int)); 31233965Sjdp 31333965Sjdpstatic void 31433965Sjdpforget_types PARAMS ((struct work_stuff *)); 31533965Sjdp 31633965Sjdpstatic void 31733965Sjdpstring_prepends PARAMS ((string *, string *)); 31833965Sjdp 31933965Sjdp/* Translate count to integer, consuming tokens in the process. 32033965Sjdp Conversion terminates on the first non-digit character. 32133965Sjdp Trying to consume something that isn't a count results in 32233965Sjdp no consumption of input and a return of 0. */ 32333965Sjdp 32433965Sjdpstatic int 32533965Sjdpconsume_count (type) 32633965Sjdp const char **type; 32733965Sjdp{ 32833965Sjdp int count = 0; 32933965Sjdp 33033965Sjdp while (isdigit (**type)) 33133965Sjdp { 33233965Sjdp count *= 10; 33333965Sjdp count += **type - '0'; 33433965Sjdp (*type)++; 33533965Sjdp } 33633965Sjdp return (count); 33733965Sjdp} 33833965Sjdp 33933965Sjdpint 34033965Sjdpcplus_demangle_opname (opname, result, options) 34133965Sjdp const char *opname; 34233965Sjdp char *result; 34333965Sjdp int options; 34433965Sjdp{ 34533965Sjdp int len, i, len1, ret; 34633965Sjdp string type; 34733965Sjdp struct work_stuff work[1]; 34833965Sjdp const char *tem; 34933965Sjdp 35033965Sjdp len = strlen(opname); 35133965Sjdp result[0] = '\0'; 35233965Sjdp ret = 0; 35333965Sjdp work->options = options; 35433965Sjdp 35533965Sjdp if (opname[0] == '_' && opname[1] == '_' 35633965Sjdp && opname[2] == 'o' && opname[3] == 'p') 35733965Sjdp { 35833965Sjdp /* ANSI. */ 35933965Sjdp /* type conversion operator. */ 36033965Sjdp tem = opname + 4; 36133965Sjdp if (do_type (work, &tem, &type)) 36233965Sjdp { 36333965Sjdp strcat (result, "operator "); 36433965Sjdp strncat (result, type.b, type.p - type.b); 36533965Sjdp string_delete (&type); 36633965Sjdp ret = 1; 36733965Sjdp } 36833965Sjdp } 36933965Sjdp else if (opname[0] == '_' && opname[1] == '_' 37033965Sjdp && opname[2] >= 'a' && opname[2] <= 'z' 37133965Sjdp && opname[3] >= 'a' && opname[3] <= 'z') 37233965Sjdp { 37333965Sjdp if (opname[4] == '\0') 37433965Sjdp { 37533965Sjdp /* Operator. */ 37633965Sjdp for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++) 37733965Sjdp { 37833965Sjdp if (strlen (optable[i].in) == 2 37933965Sjdp && memcmp (optable[i].in, opname + 2, 2) == 0) 38033965Sjdp { 38133965Sjdp strcat (result, "operator"); 38233965Sjdp strcat (result, optable[i].out); 38333965Sjdp ret = 1; 38433965Sjdp break; 38533965Sjdp } 38633965Sjdp } 38733965Sjdp } 38833965Sjdp else 38933965Sjdp { 39033965Sjdp if (opname[2] == 'a' && opname[5] == '\0') 39133965Sjdp { 39233965Sjdp /* Assignment. */ 39333965Sjdp for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++) 39433965Sjdp { 39533965Sjdp if (strlen (optable[i].in) == 3 39633965Sjdp && memcmp (optable[i].in, opname + 2, 3) == 0) 39733965Sjdp { 39833965Sjdp strcat (result, "operator"); 39933965Sjdp strcat (result, optable[i].out); 40033965Sjdp ret = 1; 40133965Sjdp break; 40233965Sjdp } 40333965Sjdp } 40433965Sjdp } 40533965Sjdp } 40633965Sjdp } 40733965Sjdp else if (len >= 3 40833965Sjdp && opname[0] == 'o' 40933965Sjdp && opname[1] == 'p' 41033965Sjdp && strchr (cplus_markers, opname[2]) != NULL) 41133965Sjdp { 41233965Sjdp /* see if it's an assignment expression */ 41333965Sjdp if (len >= 10 /* op$assign_ */ 41433965Sjdp && memcmp (opname + 3, "assign_", 7) == 0) 41533965Sjdp { 41633965Sjdp for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++) 41733965Sjdp { 41833965Sjdp len1 = len - 10; 41933965Sjdp if (strlen (optable[i].in) == len1 42033965Sjdp && memcmp (optable[i].in, opname + 10, len1) == 0) 42133965Sjdp { 42233965Sjdp strcat (result, "operator"); 42333965Sjdp strcat (result, optable[i].out); 42433965Sjdp strcat (result, "="); 42533965Sjdp ret = 1; 42633965Sjdp break; 42733965Sjdp } 42833965Sjdp } 42933965Sjdp } 43033965Sjdp else 43133965Sjdp { 43233965Sjdp for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++) 43333965Sjdp { 43433965Sjdp len1 = len - 3; 43533965Sjdp if (strlen (optable[i].in) == len1 43633965Sjdp && memcmp (optable[i].in, opname + 3, len1) == 0) 43733965Sjdp { 43833965Sjdp strcat (result, "operator"); 43933965Sjdp strcat (result, optable[i].out); 44033965Sjdp ret = 1; 44133965Sjdp break; 44233965Sjdp } 44333965Sjdp } 44433965Sjdp } 44533965Sjdp } 44633965Sjdp else if (len >= 5 && memcmp (opname, "type", 4) == 0 44733965Sjdp && strchr (cplus_markers, opname[4]) != NULL) 44833965Sjdp { 44933965Sjdp /* type conversion operator */ 45033965Sjdp tem = opname + 5; 45133965Sjdp if (do_type (work, &tem, &type)) 45233965Sjdp { 45333965Sjdp strcat (result, "operator "); 45433965Sjdp strncat (result, type.b, type.p - type.b); 45533965Sjdp string_delete (&type); 45633965Sjdp ret = 1; 45733965Sjdp } 45833965Sjdp } 45933965Sjdp return ret; 46033965Sjdp 46133965Sjdp} 46233965Sjdp/* Takes operator name as e.g. "++" and returns mangled 46333965Sjdp operator name (e.g. "postincrement_expr"), or NULL if not found. 46433965Sjdp 46533965Sjdp If OPTIONS & DMGL_ANSI == 1, return the ANSI name; 46633965Sjdp if OPTIONS & DMGL_ANSI == 0, return the old GNU name. */ 46733965Sjdp 46833965Sjdpconst char * 46933965Sjdpcplus_mangle_opname (opname, options) 47033965Sjdp const char *opname; 47133965Sjdp int options; 47233965Sjdp{ 47333965Sjdp int i; 47433965Sjdp int len; 47533965Sjdp 47633965Sjdp len = strlen (opname); 47733965Sjdp for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++) 47833965Sjdp { 47933965Sjdp if (strlen (optable[i].out) == len 48033965Sjdp && (options & DMGL_ANSI) == (optable[i].flags & DMGL_ANSI) 48133965Sjdp && memcmp (optable[i].out, opname, len) == 0) 48233965Sjdp return optable[i].in; 48333965Sjdp } 48433965Sjdp return (0); 48533965Sjdp} 48633965Sjdp 48733965Sjdp/* char *cplus_demangle (const char *mangled, int options) 48833965Sjdp 48933965Sjdp If MANGLED is a mangled function name produced by GNU C++, then 49033965Sjdp a pointer to a malloced string giving a C++ representation 49133965Sjdp of the name will be returned; otherwise NULL will be returned. 49233965Sjdp It is the caller's responsibility to free the string which 49333965Sjdp is returned. 49433965Sjdp 49533965Sjdp The OPTIONS arg may contain one or more of the following bits: 49633965Sjdp 49733965Sjdp DMGL_ANSI ANSI qualifiers such as `const' and `void' are 49833965Sjdp included. 49933965Sjdp DMGL_PARAMS Function parameters are included. 50033965Sjdp 50133965Sjdp For example, 50233965Sjdp 50333965Sjdp cplus_demangle ("foo__1Ai", DMGL_PARAMS) => "A::foo(int)" 50433965Sjdp cplus_demangle ("foo__1Ai", DMGL_PARAMS | DMGL_ANSI) => "A::foo(int)" 50533965Sjdp cplus_demangle ("foo__1Ai", 0) => "A::foo" 50633965Sjdp 50733965Sjdp cplus_demangle ("foo__1Afe", DMGL_PARAMS) => "A::foo(float,...)" 50833965Sjdp cplus_demangle ("foo__1Afe", DMGL_PARAMS | DMGL_ANSI)=> "A::foo(float,...)" 50933965Sjdp cplus_demangle ("foo__1Afe", 0) => "A::foo" 51033965Sjdp 51133965Sjdp Note that any leading underscores, or other such characters prepended by 51233965Sjdp the compilation system, are presumed to have already been stripped from 51333965Sjdp MANGLED. */ 51433965Sjdp 51533965Sjdpchar * 51633965Sjdpcplus_demangle (mangled, options) 51733965Sjdp const char *mangled; 51833965Sjdp int options; 51933965Sjdp{ 52033965Sjdp string decl; 52133965Sjdp int success = 0; 52233965Sjdp struct work_stuff work[1]; 52333965Sjdp char *demangled = NULL; 52433965Sjdp 52533965Sjdp if ((mangled != NULL) && (*mangled != '\0')) 52633965Sjdp { 52733965Sjdp memset ((char *) work, 0, sizeof (work)); 52833965Sjdp work -> options = options; 52933965Sjdp if ((work->options & DMGL_STYLE_MASK) == 0) 53033965Sjdp work->options |= (int)current_demangling_style & DMGL_STYLE_MASK; 53133965Sjdp 53233965Sjdp string_init (&decl); 53333965Sjdp 53433965Sjdp /* First check to see if gnu style demangling is active and if the 53533965Sjdp string to be demangled contains a CPLUS_MARKER. If so, attempt to 53633965Sjdp recognize one of the gnu special forms rather than looking for a 53733965Sjdp standard prefix. In particular, don't worry about whether there 53833965Sjdp is a "__" string in the mangled string. Consider "_$_5__foo" for 53933965Sjdp example. */ 54033965Sjdp 54133965Sjdp if ((AUTO_DEMANGLING || GNU_DEMANGLING)) 54233965Sjdp { 54333965Sjdp success = gnu_special (work, &mangled, &decl); 54433965Sjdp } 54533965Sjdp if (!success) 54633965Sjdp { 54733965Sjdp success = demangle_prefix (work, &mangled, &decl); 54833965Sjdp } 54933965Sjdp if (success && (*mangled != '\0')) 55033965Sjdp { 55133965Sjdp success = demangle_signature (work, &mangled, &decl); 55233965Sjdp } 55333965Sjdp if (work->constructor == 2) 55433965Sjdp { 55533965Sjdp string_prepend(&decl, "global constructors keyed to "); 55633965Sjdp work->constructor = 0; 55733965Sjdp } 55833965Sjdp else if (work->destructor == 2) 55933965Sjdp { 56033965Sjdp string_prepend(&decl, "global destructors keyed to "); 56133965Sjdp work->destructor = 0; 56233965Sjdp } 56333965Sjdp demangled = mop_up (work, &decl, success); 56433965Sjdp } 56533965Sjdp return (demangled); 56633965Sjdp} 56733965Sjdp 56833965Sjdpstatic char * 56933965Sjdpmop_up (work, declp, success) 57033965Sjdp struct work_stuff *work; 57133965Sjdp string *declp; 57233965Sjdp int success; 57333965Sjdp{ 57433965Sjdp char *demangled = NULL; 57533965Sjdp 57633965Sjdp /* Discard the remembered types, if any. */ 57733965Sjdp 57833965Sjdp forget_types (work); 57933965Sjdp if (work -> typevec != NULL) 58033965Sjdp { 58133965Sjdp free ((char *) work -> typevec); 58233965Sjdp } 58333965Sjdp 58433965Sjdp /* If demangling was successful, ensure that the demangled string is null 58533965Sjdp terminated and return it. Otherwise, free the demangling decl. */ 58633965Sjdp 58733965Sjdp if (!success) 58833965Sjdp { 58933965Sjdp string_delete (declp); 59033965Sjdp } 59133965Sjdp else 59233965Sjdp { 59333965Sjdp string_appendn (declp, "", 1); 59433965Sjdp demangled = declp -> b; 59533965Sjdp } 59633965Sjdp return (demangled); 59733965Sjdp} 59833965Sjdp 59933965Sjdp/* 60033965Sjdp 60133965SjdpLOCAL FUNCTION 60233965Sjdp 60333965Sjdp demangle_signature -- demangle the signature part of a mangled name 60433965Sjdp 60533965SjdpSYNOPSIS 60633965Sjdp 60733965Sjdp static int 60833965Sjdp demangle_signature (struct work_stuff *work, const char **mangled, 60933965Sjdp string *declp); 61033965Sjdp 61133965SjdpDESCRIPTION 61233965Sjdp 61333965Sjdp Consume and demangle the signature portion of the mangled name. 61433965Sjdp 61533965Sjdp DECLP is the string where demangled output is being built. At 61633965Sjdp entry it contains the demangled root name from the mangled name 61733965Sjdp prefix. I.E. either a demangled operator name or the root function 61833965Sjdp name. In some special cases, it may contain nothing. 61933965Sjdp 62033965Sjdp *MANGLED points to the current unconsumed location in the mangled 62133965Sjdp name. As tokens are consumed and demangling is performed, the 62233965Sjdp pointer is updated to continuously point at the next token to 62333965Sjdp be consumed. 62433965Sjdp 62533965Sjdp Demangling GNU style mangled names is nasty because there is no 62633965Sjdp explicit token that marks the start of the outermost function 62733965Sjdp argument list. */ 62833965Sjdp 62933965Sjdpstatic int 63033965Sjdpdemangle_signature (work, mangled, declp) 63133965Sjdp struct work_stuff *work; 63233965Sjdp const char **mangled; 63333965Sjdp string *declp; 63433965Sjdp{ 63533965Sjdp int success = 1; 63633965Sjdp int func_done = 0; 63733965Sjdp int expect_func = 0; 63833965Sjdp const char *oldmangled = NULL; 63933965Sjdp string trawname; 64033965Sjdp string tname; 64133965Sjdp 64233965Sjdp while (success && (**mangled != '\0')) 64333965Sjdp { 64433965Sjdp switch (**mangled) 64533965Sjdp { 64633965Sjdp case 'Q': 64733965Sjdp oldmangled = *mangled; 64833965Sjdp success = demangle_qualified (work, mangled, declp, 1, 0); 64933965Sjdp if (success) 65033965Sjdp { 65133965Sjdp remember_type (work, oldmangled, *mangled - oldmangled); 65233965Sjdp } 65333965Sjdp if (AUTO_DEMANGLING || GNU_DEMANGLING) 65433965Sjdp { 65533965Sjdp expect_func = 1; 65633965Sjdp } 65733965Sjdp oldmangled = NULL; 65833965Sjdp break; 65933965Sjdp 66033965Sjdp case 'S': 66133965Sjdp /* Static member function */ 66233965Sjdp if (oldmangled == NULL) 66333965Sjdp { 66433965Sjdp oldmangled = *mangled; 66533965Sjdp } 66633965Sjdp (*mangled)++; 66733965Sjdp work -> static_type = 1; 66833965Sjdp break; 66933965Sjdp 67033965Sjdp case 'C': 67133965Sjdp /* a const member function */ 67233965Sjdp if (oldmangled == NULL) 67333965Sjdp { 67433965Sjdp oldmangled = *mangled; 67533965Sjdp } 67633965Sjdp (*mangled)++; 67733965Sjdp work -> const_type = 1; 67833965Sjdp break; 67933965Sjdp 68033965Sjdp case '0': case '1': case '2': case '3': case '4': 68133965Sjdp case '5': case '6': case '7': case '8': case '9': 68233965Sjdp if (oldmangled == NULL) 68333965Sjdp { 68433965Sjdp oldmangled = *mangled; 68533965Sjdp } 68633965Sjdp success = demangle_class (work, mangled, declp); 68733965Sjdp if (success) 68833965Sjdp { 68933965Sjdp remember_type (work, oldmangled, *mangled - oldmangled); 69033965Sjdp } 69133965Sjdp if (AUTO_DEMANGLING || GNU_DEMANGLING) 69233965Sjdp { 69333965Sjdp expect_func = 1; 69433965Sjdp } 69533965Sjdp oldmangled = NULL; 69633965Sjdp break; 69733965Sjdp 69833965Sjdp case 'F': 69933965Sjdp /* Function */ 70033965Sjdp /* ARM style demangling includes a specific 'F' character after 70133965Sjdp the class name. For GNU style, it is just implied. So we can 70233965Sjdp safely just consume any 'F' at this point and be compatible 70333965Sjdp with either style. */ 70433965Sjdp 70533965Sjdp oldmangled = NULL; 70633965Sjdp func_done = 1; 70733965Sjdp (*mangled)++; 70833965Sjdp 70933965Sjdp /* For lucid/ARM style we have to forget any types we might 71033965Sjdp have remembered up to this point, since they were not argument 71133965Sjdp types. GNU style considers all types seen as available for 71233965Sjdp back references. See comment in demangle_args() */ 71333965Sjdp 71433965Sjdp if (LUCID_DEMANGLING || ARM_DEMANGLING) 71533965Sjdp { 71633965Sjdp forget_types (work); 71733965Sjdp } 71833965Sjdp success = demangle_args (work, mangled, declp); 71933965Sjdp break; 72033965Sjdp 72133965Sjdp case 't': 72233965Sjdp /* G++ Template */ 72333965Sjdp string_init(&trawname); 72433965Sjdp string_init(&tname); 72533965Sjdp if (oldmangled == NULL) 72633965Sjdp { 72733965Sjdp oldmangled = *mangled; 72833965Sjdp } 72933965Sjdp success = demangle_template (work, mangled, &tname, &trawname); 73033965Sjdp if (success) 73133965Sjdp { 73233965Sjdp remember_type (work, oldmangled, *mangled - oldmangled); 73333965Sjdp } 73433965Sjdp string_append(&tname, "::"); 73533965Sjdp string_prepends(declp, &tname); 73633965Sjdp if (work -> destructor & 1) 73733965Sjdp { 73833965Sjdp string_prepend (&trawname, "~"); 73933965Sjdp string_appends (declp, &trawname); 74033965Sjdp work->destructor -= 1; 74133965Sjdp } 74233965Sjdp if ((work->constructor & 1) || (work->destructor & 1)) 74333965Sjdp { 74433965Sjdp string_appends (declp, &trawname); 74533965Sjdp work->constructor -= 1; 74633965Sjdp } 74733965Sjdp string_delete(&trawname); 74833965Sjdp string_delete(&tname); 74933965Sjdp oldmangled = NULL; 75033965Sjdp expect_func = 1; 75133965Sjdp break; 75233965Sjdp 75333965Sjdp case '_': 75433965Sjdp /* At the outermost level, we cannot have a return type specified, 75533965Sjdp so if we run into another '_' at this point we are dealing with 75633965Sjdp a mangled name that is either bogus, or has been mangled by 75733965Sjdp some algorithm we don't know how to deal with. So just 75833965Sjdp reject the entire demangling. */ 75933965Sjdp success = 0; 76033965Sjdp break; 76133965Sjdp 76233965Sjdp default: 76333965Sjdp if (AUTO_DEMANGLING || GNU_DEMANGLING) 76433965Sjdp { 76533965Sjdp /* Assume we have stumbled onto the first outermost function 76633965Sjdp argument token, and start processing args. */ 76733965Sjdp func_done = 1; 76833965Sjdp success = demangle_args (work, mangled, declp); 76933965Sjdp } 77033965Sjdp else 77133965Sjdp { 77233965Sjdp /* Non-GNU demanglers use a specific token to mark the start 77333965Sjdp of the outermost function argument tokens. Typically 'F', 77433965Sjdp for ARM-demangling, for example. So if we find something 77533965Sjdp we are not prepared for, it must be an error. */ 77633965Sjdp success = 0; 77733965Sjdp } 77833965Sjdp break; 77933965Sjdp } 78033965Sjdp /* 78133965Sjdp if (AUTO_DEMANGLING || GNU_DEMANGLING) 78233965Sjdp */ 78333965Sjdp { 78433965Sjdp if (success && expect_func) 78533965Sjdp { 78633965Sjdp func_done = 1; 78733965Sjdp success = demangle_args (work, mangled, declp); 78833965Sjdp } 78933965Sjdp } 79033965Sjdp } 79133965Sjdp if (success && !func_done) 79233965Sjdp { 79333965Sjdp if (AUTO_DEMANGLING || GNU_DEMANGLING) 79433965Sjdp { 79533965Sjdp /* With GNU style demangling, bar__3foo is 'foo::bar(void)', and 79633965Sjdp bar__3fooi is 'foo::bar(int)'. We get here when we find the 79733965Sjdp first case, and need to ensure that the '(void)' gets added to 79833965Sjdp the current declp. Note that with ARM, the first case 79933965Sjdp represents the name of a static data member 'foo::bar', 80033965Sjdp which is in the current declp, so we leave it alone. */ 80133965Sjdp success = demangle_args (work, mangled, declp); 80233965Sjdp } 80333965Sjdp } 80433965Sjdp if (success && work -> static_type && PRINT_ARG_TYPES) 80533965Sjdp { 80633965Sjdp string_append (declp, " static"); 80733965Sjdp } 80833965Sjdp if (success && work -> const_type && PRINT_ARG_TYPES) 80933965Sjdp { 81033965Sjdp string_append (declp, " const"); 81133965Sjdp } 81233965Sjdp return (success); 81333965Sjdp} 81433965Sjdp 81533965Sjdp#if 0 81633965Sjdp 81733965Sjdpstatic int 81833965Sjdpdemangle_method_args (work, mangled, declp) 81933965Sjdp struct work_stuff *work; 82033965Sjdp const char **mangled; 82133965Sjdp string *declp; 82233965Sjdp{ 82333965Sjdp int success = 0; 82433965Sjdp 82533965Sjdp if (work -> static_type) 82633965Sjdp { 82733965Sjdp string_append (declp, *mangled + 1); 82833965Sjdp *mangled += strlen (*mangled); 82933965Sjdp success = 1; 83033965Sjdp } 83133965Sjdp else 83233965Sjdp { 83333965Sjdp success = demangle_args (work, mangled, declp); 83433965Sjdp } 83533965Sjdp return (success); 83633965Sjdp} 83733965Sjdp 83833965Sjdp#endif 83933965Sjdp 84033965Sjdpstatic int 84133965Sjdpdemangle_template (work, mangled, tname, trawname) 84233965Sjdp struct work_stuff *work; 84333965Sjdp const char **mangled; 84433965Sjdp string *tname; 84533965Sjdp string *trawname; 84633965Sjdp{ 84733965Sjdp int i; 84833965Sjdp int is_pointer; 84933965Sjdp int is_real; 85033965Sjdp int is_integral; 85133965Sjdp int is_char; 85233965Sjdp int is_bool; 85333965Sjdp int r; 85433965Sjdp int need_comma = 0; 85533965Sjdp int success = 0; 85633965Sjdp int done; 85733965Sjdp const char *old_p; 85833965Sjdp const char *start; 85933965Sjdp int symbol_len; 86033965Sjdp string temp; 86133965Sjdp 86233965Sjdp (*mangled)++; 86333965Sjdp start = *mangled; 86433965Sjdp /* get template name */ 86533965Sjdp if ((r = consume_count (mangled)) == 0 || strlen (*mangled) < r) 86633965Sjdp { 86733965Sjdp return (0); 86833965Sjdp } 86933965Sjdp if (trawname) 87033965Sjdp string_appendn (trawname, *mangled, r); 87133965Sjdp string_appendn (tname, *mangled, r); 87233965Sjdp *mangled += r; 87333965Sjdp string_append (tname, "<"); 87433965Sjdp /* get size of template parameter list */ 87533965Sjdp if (!get_count (mangled, &r)) 87633965Sjdp { 87733965Sjdp return (0); 87833965Sjdp } 87933965Sjdp for (i = 0; i < r; i++) 88033965Sjdp { 88133965Sjdp if (need_comma) 88233965Sjdp { 88333965Sjdp string_append (tname, ", "); 88433965Sjdp } 88533965Sjdp /* Z for type parameters */ 88633965Sjdp if (**mangled == 'Z') 88733965Sjdp { 88833965Sjdp (*mangled)++; 88933965Sjdp /* temp is initialized in do_type */ 89033965Sjdp success = do_type (work, mangled, &temp); 89133965Sjdp if (success) 89233965Sjdp { 89333965Sjdp string_appends (tname, &temp); 89433965Sjdp } 89533965Sjdp string_delete(&temp); 89633965Sjdp if (!success) 89733965Sjdp { 89833965Sjdp break; 89933965Sjdp } 90033965Sjdp } 90133965Sjdp else 90233965Sjdp { 90333965Sjdp /* otherwise, value parameter */ 90433965Sjdp old_p = *mangled; 90533965Sjdp is_pointer = 0; 90633965Sjdp is_real = 0; 90733965Sjdp is_integral = 0; 90833965Sjdp is_char = 0; 90933965Sjdp is_bool = 0; 91033965Sjdp done = 0; 91133965Sjdp /* temp is initialized in do_type */ 91233965Sjdp success = do_type (work, mangled, &temp); 91333965Sjdp /* 91433965Sjdp if (success) 91533965Sjdp { 91633965Sjdp string_appends (tname, &temp); 91733965Sjdp } 91833965Sjdp */ 91933965Sjdp string_delete(&temp); 92033965Sjdp if (!success) 92133965Sjdp { 92233965Sjdp break; 92333965Sjdp } 92433965Sjdp /* 92533965Sjdp string_append (tname, "="); 92633965Sjdp */ 92733965Sjdp while (*old_p && !done) 92833965Sjdp { 92933965Sjdp switch (*old_p) 93033965Sjdp { 93133965Sjdp case 'P': 93233965Sjdp case 'p': 93333965Sjdp case 'R': 93433965Sjdp done = is_pointer = 1; 93533965Sjdp break; 93633965Sjdp case 'C': /* const */ 93733965Sjdp case 'S': /* explicitly signed [char] */ 93833965Sjdp case 'U': /* unsigned */ 93933965Sjdp case 'V': /* volatile */ 94033965Sjdp case 'F': /* function */ 94133965Sjdp case 'M': /* member function */ 94233965Sjdp case 'O': /* ??? */ 94333965Sjdp old_p++; 94433965Sjdp continue; 94533965Sjdp case 'Q': /* qualified name */ 94633965Sjdp done = is_integral = 1; 94733965Sjdp break; 94833965Sjdp case 'T': /* remembered type */ 94933965Sjdp abort (); 95033965Sjdp break; 95133965Sjdp case 'v': /* void */ 95233965Sjdp abort (); 95333965Sjdp break; 95433965Sjdp case 'x': /* long long */ 95533965Sjdp case 'l': /* long */ 95633965Sjdp case 'i': /* int */ 95733965Sjdp case 's': /* short */ 95833965Sjdp case 'w': /* wchar_t */ 95933965Sjdp done = is_integral = 1; 96033965Sjdp break; 96133965Sjdp case 'b': /* bool */ 96233965Sjdp done = is_bool = 1; 96333965Sjdp break; 96433965Sjdp case 'c': /* char */ 96533965Sjdp done = is_char = 1; 96633965Sjdp break; 96733965Sjdp case 'r': /* long double */ 96833965Sjdp case 'd': /* double */ 96933965Sjdp case 'f': /* float */ 97033965Sjdp done = is_real = 1; 97133965Sjdp break; 97233965Sjdp default: 97333965Sjdp /* it's probably user defined type, let's assume 97433965Sjdp it's integral, it seems hard to figure out 97533965Sjdp what it really is */ 97633965Sjdp done = is_integral = 1; 97733965Sjdp } 97833965Sjdp } 97933965Sjdp if (is_integral) 98033965Sjdp { 98133965Sjdp if (**mangled == 'm') 98233965Sjdp { 98333965Sjdp string_appendn (tname, "-", 1); 98433965Sjdp (*mangled)++; 98533965Sjdp } 98633965Sjdp while (isdigit (**mangled)) 98733965Sjdp { 98833965Sjdp string_appendn (tname, *mangled, 1); 98933965Sjdp (*mangled)++; 99033965Sjdp } 99133965Sjdp } 99233965Sjdp else if (is_char) 99333965Sjdp { 99433965Sjdp char tmp[2]; 99533965Sjdp int val; 99633965Sjdp if (**mangled == 'm') 99733965Sjdp { 99833965Sjdp string_appendn (tname, "-", 1); 99933965Sjdp (*mangled)++; 100033965Sjdp } 100133965Sjdp string_appendn (tname, "'", 1); 100233965Sjdp val = consume_count(mangled); 100333965Sjdp if (val == 0) 100433965Sjdp { 100533965Sjdp success = 0; 100633965Sjdp break; 100733965Sjdp } 100833965Sjdp tmp[0] = (char)val; 100933965Sjdp tmp[1] = '\0'; 101033965Sjdp string_appendn (tname, &tmp[0], 1); 101133965Sjdp string_appendn (tname, "'", 1); 101233965Sjdp } 101333965Sjdp else if (is_bool) 101433965Sjdp { 101533965Sjdp int val = consume_count (mangled); 101633965Sjdp if (val == 0) 101733965Sjdp string_appendn (tname, "false", 5); 101833965Sjdp else if (val == 1) 101933965Sjdp string_appendn (tname, "true", 4); 102033965Sjdp else 102133965Sjdp success = 0; 102233965Sjdp } 102333965Sjdp else if (is_real) 102433965Sjdp { 102533965Sjdp if (**mangled == 'm') 102633965Sjdp { 102733965Sjdp string_appendn (tname, "-", 1); 102833965Sjdp (*mangled)++; 102933965Sjdp } 103033965Sjdp while (isdigit (**mangled)) 103133965Sjdp { 103233965Sjdp string_appendn (tname, *mangled, 1); 103333965Sjdp (*mangled)++; 103433965Sjdp } 103533965Sjdp if (**mangled == '.') /* fraction */ 103633965Sjdp { 103733965Sjdp string_appendn (tname, ".", 1); 103833965Sjdp (*mangled)++; 103933965Sjdp while (isdigit (**mangled)) 104033965Sjdp { 104133965Sjdp string_appendn (tname, *mangled, 1); 104233965Sjdp (*mangled)++; 104333965Sjdp } 104433965Sjdp } 104533965Sjdp if (**mangled == 'e') /* exponent */ 104633965Sjdp { 104733965Sjdp string_appendn (tname, "e", 1); 104833965Sjdp (*mangled)++; 104933965Sjdp while (isdigit (**mangled)) 105033965Sjdp { 105133965Sjdp string_appendn (tname, *mangled, 1); 105233965Sjdp (*mangled)++; 105333965Sjdp } 105433965Sjdp } 105533965Sjdp } 105633965Sjdp else if (is_pointer) 105733965Sjdp { 105833965Sjdp symbol_len = consume_count (mangled); 105933965Sjdp if (symbol_len == 0) 106033965Sjdp { 106133965Sjdp success = 0; 106233965Sjdp break; 106333965Sjdp } 106433965Sjdp if (symbol_len == 0) 106533965Sjdp string_appendn (tname, "0", 1); 106633965Sjdp else 106733965Sjdp { 106833965Sjdp char *p = xmalloc (symbol_len + 1), *q; 106933965Sjdp strncpy (p, *mangled, symbol_len); 107033965Sjdp p [symbol_len] = '\0'; 107133965Sjdp q = cplus_demangle (p, work->options); 107233965Sjdp string_appendn (tname, "&", 1); 107333965Sjdp if (q) 107433965Sjdp { 107533965Sjdp string_append (tname, q); 107633965Sjdp free (q); 107733965Sjdp } 107833965Sjdp else 107933965Sjdp string_append (tname, p); 108033965Sjdp free (p); 108133965Sjdp } 108233965Sjdp *mangled += symbol_len; 108333965Sjdp } 108433965Sjdp } 108533965Sjdp need_comma = 1; 108633965Sjdp } 108733965Sjdp if (tname->p[-1] == '>') 108833965Sjdp string_append (tname, " "); 108933965Sjdp string_append (tname, ">"); 109033965Sjdp 109133965Sjdp /* 109233965Sjdp if (work -> static_type) 109333965Sjdp { 109433965Sjdp string_append (declp, *mangled + 1); 109533965Sjdp *mangled += strlen (*mangled); 109633965Sjdp success = 1; 109733965Sjdp } 109833965Sjdp else 109933965Sjdp { 110033965Sjdp success = demangle_args (work, mangled, declp); 110133965Sjdp } 110233965Sjdp } 110333965Sjdp */ 110433965Sjdp return (success); 110533965Sjdp} 110633965Sjdp 110733965Sjdpstatic int 110833965Sjdparm_pt (work, mangled, n, anchor, args) 110933965Sjdp struct work_stuff *work; 111033965Sjdp const char *mangled; 111133965Sjdp int n; 111233965Sjdp const char **anchor, **args; 111333965Sjdp{ 111433965Sjdp /* ARM template? */ 111533965Sjdp if (ARM_DEMANGLING && (*anchor = mystrstr (mangled, "__pt__"))) 111633965Sjdp { 111733965Sjdp int len; 111833965Sjdp *args = *anchor + 6; 111933965Sjdp len = consume_count (args); 112033965Sjdp if (*args + len == mangled + n && **args == '_') 112133965Sjdp { 112233965Sjdp ++*args; 112333965Sjdp return 1; 112433965Sjdp } 112533965Sjdp } 112633965Sjdp return 0; 112733965Sjdp} 112833965Sjdp 112933965Sjdpstatic void 113033965Sjdpdemangle_arm_pt (work, mangled, n, declp) 113133965Sjdp struct work_stuff *work; 113233965Sjdp const char **mangled; 113333965Sjdp int n; 113433965Sjdp string *declp; 113533965Sjdp{ 113633965Sjdp const char *p; 113733965Sjdp const char *args; 113833965Sjdp const char *e = *mangled + n; 113933965Sjdp 114033965Sjdp /* ARM template? */ 114133965Sjdp if (arm_pt (work, *mangled, n, &p, &args)) 114233965Sjdp { 114333965Sjdp string arg; 114433965Sjdp string_init (&arg); 114533965Sjdp string_appendn (declp, *mangled, p - *mangled); 114633965Sjdp string_append (declp, "<"); 114733965Sjdp /* should do error checking here */ 114833965Sjdp while (args < e) { 114933965Sjdp string_clear (&arg); 115033965Sjdp do_type (work, &args, &arg); 115133965Sjdp string_appends (declp, &arg); 115233965Sjdp string_append (declp, ","); 115333965Sjdp } 115433965Sjdp string_delete (&arg); 115533965Sjdp --declp->p; 115633965Sjdp string_append (declp, ">"); 115733965Sjdp } 115833965Sjdp else 115933965Sjdp { 116033965Sjdp string_appendn (declp, *mangled, n); 116133965Sjdp } 116233965Sjdp *mangled += n; 116333965Sjdp} 116433965Sjdp 116533965Sjdpstatic int 116633965Sjdpdemangle_class_name (work, mangled, declp) 116733965Sjdp struct work_stuff *work; 116833965Sjdp const char **mangled; 116933965Sjdp string *declp; 117033965Sjdp{ 117133965Sjdp int n; 117233965Sjdp int success = 0; 117333965Sjdp 117433965Sjdp n = consume_count (mangled); 117533965Sjdp if (strlen (*mangled) >= n) 117633965Sjdp { 117733965Sjdp demangle_arm_pt (work, mangled, n, declp); 117833965Sjdp success = 1; 117933965Sjdp } 118033965Sjdp 118133965Sjdp return (success); 118233965Sjdp} 118333965Sjdp 118433965Sjdp/* 118533965Sjdp 118633965SjdpLOCAL FUNCTION 118733965Sjdp 118833965Sjdp demangle_class -- demangle a mangled class sequence 118933965Sjdp 119033965SjdpSYNOPSIS 119133965Sjdp 119233965Sjdp static int 119333965Sjdp demangle_class (struct work_stuff *work, const char **mangled, 119433965Sjdp strint *declp) 119533965Sjdp 119633965SjdpDESCRIPTION 119733965Sjdp 119833965Sjdp DECLP points to the buffer into which demangling is being done. 119933965Sjdp 120033965Sjdp *MANGLED points to the current token to be demangled. On input, 120133965Sjdp it points to a mangled class (I.E. "3foo", "13verylongclass", etc.) 120233965Sjdp On exit, it points to the next token after the mangled class on 120333965Sjdp success, or the first unconsumed token on failure. 120433965Sjdp 120533965Sjdp If the CONSTRUCTOR or DESTRUCTOR flags are set in WORK, then 120633965Sjdp we are demangling a constructor or destructor. In this case 120733965Sjdp we prepend "class::class" or "class::~class" to DECLP. 120833965Sjdp 120933965Sjdp Otherwise, we prepend "class::" to the current DECLP. 121033965Sjdp 121133965Sjdp Reset the constructor/destructor flags once they have been 121233965Sjdp "consumed". This allows demangle_class to be called later during 121333965Sjdp the same demangling, to do normal class demangling. 121433965Sjdp 121533965Sjdp Returns 1 if demangling is successful, 0 otherwise. 121633965Sjdp 121733965Sjdp*/ 121833965Sjdp 121933965Sjdpstatic int 122033965Sjdpdemangle_class (work, mangled, declp) 122133965Sjdp struct work_stuff *work; 122233965Sjdp const char **mangled; 122333965Sjdp string *declp; 122433965Sjdp{ 122533965Sjdp int success = 0; 122633965Sjdp string class_name; 122733965Sjdp 122833965Sjdp string_init (&class_name); 122933965Sjdp if (demangle_class_name (work, mangled, &class_name)) 123033965Sjdp { 123133965Sjdp if ((work->constructor & 1) || (work->destructor & 1)) 123233965Sjdp { 123333965Sjdp string_prepends (declp, &class_name); 123433965Sjdp if (work -> destructor & 1) 123533965Sjdp { 123633965Sjdp string_prepend (declp, "~"); 123733965Sjdp work -> destructor -= 1; 123833965Sjdp } 123933965Sjdp else 124033965Sjdp { 124133965Sjdp work -> constructor -= 1; 124233965Sjdp } 124333965Sjdp } 124433965Sjdp string_prepend (declp, "::"); 124533965Sjdp string_prepends (declp, &class_name); 124633965Sjdp success = 1; 124733965Sjdp } 124833965Sjdp string_delete (&class_name); 124933965Sjdp return (success); 125033965Sjdp} 125133965Sjdp 125233965Sjdp/* 125333965Sjdp 125433965SjdpLOCAL FUNCTION 125533965Sjdp 125633965Sjdp demangle_prefix -- consume the mangled name prefix and find signature 125733965Sjdp 125833965SjdpSYNOPSIS 125933965Sjdp 126033965Sjdp static int 126133965Sjdp demangle_prefix (struct work_stuff *work, const char **mangled, 126233965Sjdp string *declp); 126333965Sjdp 126433965SjdpDESCRIPTION 126533965Sjdp 126633965Sjdp Consume and demangle the prefix of the mangled name. 126733965Sjdp 126833965Sjdp DECLP points to the string buffer into which demangled output is 126933965Sjdp placed. On entry, the buffer is empty. On exit it contains 127033965Sjdp the root function name, the demangled operator name, or in some 127133965Sjdp special cases either nothing or the completely demangled result. 127233965Sjdp 127333965Sjdp MANGLED points to the current pointer into the mangled name. As each 127433965Sjdp token of the mangled name is consumed, it is updated. Upon entry 127533965Sjdp the current mangled name pointer points to the first character of 127633965Sjdp the mangled name. Upon exit, it should point to the first character 127733965Sjdp of the signature if demangling was successful, or to the first 127833965Sjdp unconsumed character if demangling of the prefix was unsuccessful. 127933965Sjdp 128033965Sjdp Returns 1 on success, 0 otherwise. 128133965Sjdp */ 128233965Sjdp 128333965Sjdpstatic int 128433965Sjdpdemangle_prefix (work, mangled, declp) 128533965Sjdp struct work_stuff *work; 128633965Sjdp const char **mangled; 128733965Sjdp string *declp; 128833965Sjdp{ 128933965Sjdp int success = 1; 129033965Sjdp const char *scan; 129133965Sjdp int i; 129233965Sjdp 129333965Sjdp if (strlen(*mangled) >= 11 && strncmp(*mangled, "_GLOBAL_", 8) == 0) 129433965Sjdp { 129533965Sjdp char *marker = strchr (cplus_markers, (*mangled)[8]); 129633965Sjdp if (marker != NULL && *marker == (*mangled)[10]) 129733965Sjdp { 129833965Sjdp if ((*mangled)[9] == 'D') 129933965Sjdp { 130033965Sjdp /* it's a GNU global destructor to be executed at program exit */ 130133965Sjdp (*mangled) += 11; 130233965Sjdp work->destructor = 2; 130333965Sjdp if (gnu_special (work, mangled, declp)) 130433965Sjdp return success; 130533965Sjdp } 130633965Sjdp else if ((*mangled)[9] == 'I') 130733965Sjdp { 130833965Sjdp /* it's a GNU global constructor to be executed at program init */ 130933965Sjdp (*mangled) += 11; 131033965Sjdp work->constructor = 2; 131133965Sjdp if (gnu_special (work, mangled, declp)) 131233965Sjdp return success; 131333965Sjdp } 131433965Sjdp } 131533965Sjdp } 131633965Sjdp else if (ARM_DEMANGLING && strncmp(*mangled, "__std__", 7) == 0) 131733965Sjdp { 131833965Sjdp /* it's a ARM global destructor to be executed at program exit */ 131933965Sjdp (*mangled) += 7; 132033965Sjdp work->destructor = 2; 132133965Sjdp } 132233965Sjdp else if (ARM_DEMANGLING && strncmp(*mangled, "__sti__", 7) == 0) 132333965Sjdp { 132433965Sjdp /* it's a ARM global constructor to be executed at program initial */ 132533965Sjdp (*mangled) += 7; 132633965Sjdp work->constructor = 2; 132733965Sjdp } 132833965Sjdp 132933965Sjdp /* This block of code is a reduction in strength time optimization 133033965Sjdp of: 133133965Sjdp scan = mystrstr (*mangled, "__"); */ 133233965Sjdp 133333965Sjdp { 133433965Sjdp scan = *mangled; 133533965Sjdp 133633965Sjdp do { 133733965Sjdp scan = strchr (scan, '_'); 133833965Sjdp } while (scan != NULL && *++scan != '_'); 133933965Sjdp 134033965Sjdp if (scan != NULL) --scan; 134133965Sjdp } 134233965Sjdp 134333965Sjdp if (scan != NULL) 134433965Sjdp { 134533965Sjdp /* We found a sequence of two or more '_', ensure that we start at 134633965Sjdp the last pair in the sequence. */ 134733965Sjdp i = strspn (scan, "_"); 134833965Sjdp if (i > 2) 134933965Sjdp { 135033965Sjdp scan += (i - 2); 135133965Sjdp } 135233965Sjdp } 135333965Sjdp 135433965Sjdp if (scan == NULL) 135533965Sjdp { 135633965Sjdp success = 0; 135733965Sjdp } 135833965Sjdp else if (work -> static_type) 135933965Sjdp { 136033965Sjdp if (!isdigit (scan[0]) && (scan[0] != 't')) 136133965Sjdp { 136233965Sjdp success = 0; 136333965Sjdp } 136433965Sjdp } 136533965Sjdp else if ((scan == *mangled) && 136633965Sjdp (isdigit (scan[2]) || (scan[2] == 'Q') || (scan[2] == 't'))) 136733965Sjdp { 136833965Sjdp /* The ARM says nothing about the mangling of local variables. 136933965Sjdp But cfront mangles local variables by prepending __<nesting_level> 137033965Sjdp to them. As an extension to ARM demangling we handle this case. */ 137133965Sjdp if ((LUCID_DEMANGLING || ARM_DEMANGLING) && isdigit (scan[2])) 137233965Sjdp { 137333965Sjdp *mangled = scan + 2; 137433965Sjdp consume_count (mangled); 137533965Sjdp string_append (declp, *mangled); 137633965Sjdp *mangled += strlen (*mangled); 137733965Sjdp success = 1; 137833965Sjdp } 137933965Sjdp else 138033965Sjdp { 138133965Sjdp /* A GNU style constructor starts with __[0-9Qt]. But cfront uses 138233965Sjdp names like __Q2_3foo3bar for nested type names. So don't accept 138333965Sjdp this style of constructor for cfront demangling. */ 138433965Sjdp if (!(LUCID_DEMANGLING || ARM_DEMANGLING)) 138533965Sjdp work -> constructor += 1; 138633965Sjdp *mangled = scan + 2; 138733965Sjdp } 138833965Sjdp } 138933965Sjdp else if ((scan == *mangled) && !isdigit (scan[2]) && (scan[2] != 't')) 139033965Sjdp { 139133965Sjdp /* Mangled name starts with "__". Skip over any leading '_' characters, 139233965Sjdp then find the next "__" that separates the prefix from the signature. 139333965Sjdp */ 139433965Sjdp if (!(ARM_DEMANGLING || LUCID_DEMANGLING) 139533965Sjdp || (arm_special (work, mangled, declp) == 0)) 139633965Sjdp { 139733965Sjdp while (*scan == '_') 139833965Sjdp { 139933965Sjdp scan++; 140033965Sjdp } 140133965Sjdp if ((scan = mystrstr (scan, "__")) == NULL || (*(scan + 2) == '\0')) 140233965Sjdp { 140333965Sjdp /* No separator (I.E. "__not_mangled"), or empty signature 140433965Sjdp (I.E. "__not_mangled_either__") */ 140533965Sjdp success = 0; 140633965Sjdp } 140733965Sjdp else 140833965Sjdp { 140933965Sjdp demangle_function_name (work, mangled, declp, scan); 141033965Sjdp } 141133965Sjdp } 141233965Sjdp } 141333965Sjdp else if (ARM_DEMANGLING && scan[2] == 'p' && scan[3] == 't') 141433965Sjdp { 141533965Sjdp /* Cfront-style parameterized type. Handled later as a signature. */ 141633965Sjdp success = 1; 141733965Sjdp 141833965Sjdp /* ARM template? */ 141933965Sjdp demangle_arm_pt (work, mangled, strlen (*mangled), declp); 142033965Sjdp } 142133965Sjdp else if (*(scan + 2) != '\0') 142233965Sjdp { 142333965Sjdp /* Mangled name does not start with "__" but does have one somewhere 142433965Sjdp in there with non empty stuff after it. Looks like a global 142533965Sjdp function name. */ 142633965Sjdp demangle_function_name (work, mangled, declp, scan); 142733965Sjdp } 142833965Sjdp else 142933965Sjdp { 143033965Sjdp /* Doesn't look like a mangled name */ 143133965Sjdp success = 0; 143233965Sjdp } 143333965Sjdp 143433965Sjdp if (!success && (work->constructor == 2 || work->destructor == 2)) 143533965Sjdp { 143633965Sjdp string_append (declp, *mangled); 143733965Sjdp *mangled += strlen (*mangled); 143833965Sjdp success = 1; 143933965Sjdp } 144033965Sjdp return (success); 144133965Sjdp} 144233965Sjdp 144333965Sjdp/* 144433965Sjdp 144533965SjdpLOCAL FUNCTION 144633965Sjdp 144733965Sjdp gnu_special -- special handling of gnu mangled strings 144833965Sjdp 144933965SjdpSYNOPSIS 145033965Sjdp 145133965Sjdp static int 145233965Sjdp gnu_special (struct work_stuff *work, const char **mangled, 145333965Sjdp string *declp); 145433965Sjdp 145533965Sjdp 145633965SjdpDESCRIPTION 145733965Sjdp 145833965Sjdp Process some special GNU style mangling forms that don't fit 145933965Sjdp the normal pattern. For example: 146033965Sjdp 146133965Sjdp _$_3foo (destructor for class foo) 146233965Sjdp _vt$foo (foo virtual table) 146333965Sjdp _vt$foo$bar (foo::bar virtual table) 146433965Sjdp __vt_foo (foo virtual table, new style with thunks) 146533965Sjdp _3foo$varname (static data member) 146633965Sjdp _Q22rs2tu$vw (static data member) 146733965Sjdp __t6vector1Zii (constructor with template) 146833965Sjdp __thunk_4__$_7ostream (virtual function thunk) 146933965Sjdp */ 147033965Sjdp 147133965Sjdpstatic int 147233965Sjdpgnu_special (work, mangled, declp) 147333965Sjdp struct work_stuff *work; 147433965Sjdp const char **mangled; 147533965Sjdp string *declp; 147633965Sjdp{ 147733965Sjdp int n; 147833965Sjdp int success = 1; 147933965Sjdp const char *p; 148033965Sjdp 148133965Sjdp if ((*mangled)[0] == '_' 148233965Sjdp && strchr (cplus_markers, (*mangled)[1]) != NULL 148333965Sjdp && (*mangled)[2] == '_') 148433965Sjdp { 148533965Sjdp /* Found a GNU style destructor, get past "_<CPLUS_MARKER>_" */ 148633965Sjdp (*mangled) += 3; 148733965Sjdp work -> destructor += 1; 148833965Sjdp } 148933965Sjdp else if ((*mangled)[0] == '_' 149033965Sjdp && (((*mangled)[1] == '_' 149133965Sjdp && (*mangled)[2] == 'v' 149233965Sjdp && (*mangled)[3] == 't' 149333965Sjdp && (*mangled)[4] == '_') 149433965Sjdp || ((*mangled)[1] == 'v' 149533965Sjdp && (*mangled)[2] == 't' 149633965Sjdp && strchr (cplus_markers, (*mangled)[3]) != NULL))) 149733965Sjdp { 149833965Sjdp /* Found a GNU style virtual table, get past "_vt<CPLUS_MARKER>" 149933965Sjdp and create the decl. Note that we consume the entire mangled 150033965Sjdp input string, which means that demangle_signature has no work 150133965Sjdp to do. */ 150233965Sjdp if ((*mangled)[2] == 'v') 150333965Sjdp (*mangled) += 5; /* New style, with thunks: "__vt_" */ 150433965Sjdp else 150533965Sjdp (*mangled) += 4; /* Old style, no thunks: "_vt<CPLUS_MARKER>" */ 150633965Sjdp while (**mangled != '\0') 150733965Sjdp { 150833965Sjdp p = strpbrk (*mangled, cplus_markers); 150933965Sjdp switch (**mangled) 151033965Sjdp { 151133965Sjdp case 'Q': 151233965Sjdp success = demangle_qualified (work, mangled, declp, 0, 1); 151333965Sjdp break; 151433965Sjdp case 't': 151533965Sjdp success = demangle_template (work, mangled, declp, 0); 151633965Sjdp break; 151733965Sjdp default: 151833965Sjdp if (isdigit(*mangled[0])) 151933965Sjdp { 152033965Sjdp n = consume_count(mangled); 152133965Sjdp } 152233965Sjdp else 152333965Sjdp { 152433965Sjdp n = strcspn (*mangled, cplus_markers); 152533965Sjdp } 152633965Sjdp string_appendn (declp, *mangled, n); 152733965Sjdp (*mangled) += n; 152833965Sjdp } 152933965Sjdp 153033965Sjdp if (success && ((p == NULL) || (p == *mangled))) 153133965Sjdp { 153233965Sjdp if (p != NULL) 153333965Sjdp { 153433965Sjdp string_append (declp, "::"); 153533965Sjdp (*mangled)++; 153633965Sjdp } 153733965Sjdp } 153833965Sjdp else 153933965Sjdp { 154033965Sjdp success = 0; 154133965Sjdp break; 154233965Sjdp } 154333965Sjdp } 154433965Sjdp if (success) 154533965Sjdp string_append (declp, " virtual table"); 154633965Sjdp } 154733965Sjdp else if ((*mangled)[0] == '_' 154833965Sjdp && (strchr("0123456789Qt", (*mangled)[1]) != NULL) 154933965Sjdp && (p = strpbrk (*mangled, cplus_markers)) != NULL) 155033965Sjdp { 155133965Sjdp /* static data member, "_3foo$varname" for example */ 155233965Sjdp (*mangled)++; 155333965Sjdp switch (**mangled) 155433965Sjdp { 155533965Sjdp case 'Q': 155633965Sjdp success = demangle_qualified (work, mangled, declp, 0, 1); 155733965Sjdp break; 155833965Sjdp case 't': 155933965Sjdp success = demangle_template (work, mangled, declp, 0); 156033965Sjdp break; 156133965Sjdp default: 156233965Sjdp n = consume_count (mangled); 156333965Sjdp string_appendn (declp, *mangled, n); 156433965Sjdp (*mangled) += n; 156533965Sjdp } 156633965Sjdp if (success && (p == *mangled)) 156733965Sjdp { 156833965Sjdp /* Consumed everything up to the cplus_marker, append the 156933965Sjdp variable name. */ 157033965Sjdp (*mangled)++; 157133965Sjdp string_append (declp, "::"); 157233965Sjdp n = strlen (*mangled); 157333965Sjdp string_appendn (declp, *mangled, n); 157433965Sjdp (*mangled) += n; 157533965Sjdp } 157633965Sjdp else 157733965Sjdp { 157833965Sjdp success = 0; 157933965Sjdp } 158033965Sjdp } 158133965Sjdp else if (strncmp (*mangled, "__thunk_", 8) == 0) 158233965Sjdp { 158333965Sjdp int delta = ((*mangled) += 8, consume_count (mangled)); 158433965Sjdp char *method = cplus_demangle (++*mangled, work->options); 158533965Sjdp if (method) 158633965Sjdp { 158733965Sjdp char buf[50]; 158833965Sjdp sprintf (buf, "virtual function thunk (delta:%d) for ", -delta); 158933965Sjdp string_append (declp, buf); 159033965Sjdp string_append (declp, method); 159133965Sjdp free (method); 159233965Sjdp n = strlen (*mangled); 159333965Sjdp (*mangled) += n; 159433965Sjdp } 159533965Sjdp else 159633965Sjdp { 159733965Sjdp success = 0; 159833965Sjdp } 159933965Sjdp } 160033965Sjdp else if (strncmp (*mangled, "__t", 3) == 0 160133965Sjdp && ((*mangled)[3] == 'i' || (*mangled)[3] == 'f')) 160233965Sjdp { 160333965Sjdp p = (*mangled)[3] == 'i' ? " type_info node" : " type_info function"; 160433965Sjdp (*mangled) += 4; 160533965Sjdp switch (**mangled) 160633965Sjdp { 160733965Sjdp case 'Q': 160833965Sjdp success = demangle_qualified (work, mangled, declp, 0, 1); 160933965Sjdp break; 161033965Sjdp case 't': 161133965Sjdp success = demangle_template (work, mangled, declp, 0); 161233965Sjdp break; 161333965Sjdp default: 161433965Sjdp success = demangle_fund_type (work, mangled, declp); 161533965Sjdp break; 161633965Sjdp } 161733965Sjdp if (success && **mangled != '\0') 161833965Sjdp success = 0; 161933965Sjdp if (success) 162033965Sjdp string_append (declp, p); 162133965Sjdp } 162233965Sjdp else 162333965Sjdp { 162433965Sjdp success = 0; 162533965Sjdp } 162633965Sjdp return (success); 162733965Sjdp} 162833965Sjdp 162933965Sjdp/* 163033965Sjdp 163133965SjdpLOCAL FUNCTION 163233965Sjdp 163333965Sjdp arm_special -- special handling of ARM/lucid mangled strings 163433965Sjdp 163533965SjdpSYNOPSIS 163633965Sjdp 163733965Sjdp static int 163833965Sjdp arm_special (struct work_stuff *work, const char **mangled, 163933965Sjdp string *declp); 164033965Sjdp 164133965Sjdp 164233965SjdpDESCRIPTION 164333965Sjdp 164433965Sjdp Process some special ARM style mangling forms that don't fit 164533965Sjdp the normal pattern. For example: 164633965Sjdp 164733965Sjdp __vtbl__3foo (foo virtual table) 164833965Sjdp __vtbl__3foo__3bar (bar::foo virtual table) 164933965Sjdp 165033965Sjdp */ 165133965Sjdp 165233965Sjdpstatic int 165333965Sjdparm_special (work, mangled, declp) 165433965Sjdp struct work_stuff *work; 165533965Sjdp const char **mangled; 165633965Sjdp string *declp; 165733965Sjdp{ 165833965Sjdp int n; 165933965Sjdp int success = 1; 166033965Sjdp const char *scan; 166133965Sjdp 166233965Sjdp if (strncmp (*mangled, ARM_VTABLE_STRING, ARM_VTABLE_STRLEN) == 0) 166333965Sjdp { 166433965Sjdp /* Found a ARM style virtual table, get past ARM_VTABLE_STRING 166533965Sjdp and create the decl. Note that we consume the entire mangled 166633965Sjdp input string, which means that demangle_signature has no work 166733965Sjdp to do. */ 166833965Sjdp scan = *mangled + ARM_VTABLE_STRLEN; 166933965Sjdp while (*scan != '\0') /* first check it can be demangled */ 167033965Sjdp { 167133965Sjdp n = consume_count (&scan); 167233965Sjdp if (n==0) 167333965Sjdp { 167433965Sjdp return (0); /* no good */ 167533965Sjdp } 167633965Sjdp scan += n; 167733965Sjdp if (scan[0] == '_' && scan[1] == '_') 167833965Sjdp { 167933965Sjdp scan += 2; 168033965Sjdp } 168133965Sjdp } 168233965Sjdp (*mangled) += ARM_VTABLE_STRLEN; 168333965Sjdp while (**mangled != '\0') 168433965Sjdp { 168533965Sjdp n = consume_count (mangled); 168633965Sjdp string_prependn (declp, *mangled, n); 168733965Sjdp (*mangled) += n; 168833965Sjdp if ((*mangled)[0] == '_' && (*mangled)[1] == '_') 168933965Sjdp { 169033965Sjdp string_prepend (declp, "::"); 169133965Sjdp (*mangled) += 2; 169233965Sjdp } 169333965Sjdp } 169433965Sjdp string_append (declp, " virtual table"); 169533965Sjdp } 169633965Sjdp else 169733965Sjdp { 169833965Sjdp success = 0; 169933965Sjdp } 170033965Sjdp return (success); 170133965Sjdp} 170233965Sjdp 170333965Sjdp/* 170433965Sjdp 170533965SjdpLOCAL FUNCTION 170633965Sjdp 170733965Sjdp demangle_qualified -- demangle 'Q' qualified name strings 170833965Sjdp 170933965SjdpSYNOPSIS 171033965Sjdp 171133965Sjdp static int 171233965Sjdp demangle_qualified (struct work_stuff *, const char *mangled, 171333965Sjdp string *result, int isfuncname, int append); 171433965Sjdp 171533965SjdpDESCRIPTION 171633965Sjdp 171733965Sjdp Demangle a qualified name, such as "Q25Outer5Inner" which is 171833965Sjdp the mangled form of "Outer::Inner". The demangled output is 171933965Sjdp prepended or appended to the result string according to the 172033965Sjdp state of the append flag. 172133965Sjdp 172233965Sjdp If isfuncname is nonzero, then the qualified name we are building 172333965Sjdp is going to be used as a member function name, so if it is a 172433965Sjdp constructor or destructor function, append an appropriate 172533965Sjdp constructor or destructor name. I.E. for the above example, 172633965Sjdp the result for use as a constructor is "Outer::Inner::Inner" 172733965Sjdp and the result for use as a destructor is "Outer::Inner::~Inner". 172833965Sjdp 172933965SjdpBUGS 173033965Sjdp 173133965Sjdp Numeric conversion is ASCII dependent (FIXME). 173233965Sjdp 173333965Sjdp */ 173433965Sjdp 173533965Sjdpstatic int 173633965Sjdpdemangle_qualified (work, mangled, result, isfuncname, append) 173733965Sjdp struct work_stuff *work; 173833965Sjdp const char **mangled; 173933965Sjdp string *result; 174033965Sjdp int isfuncname; 174133965Sjdp int append; 174233965Sjdp{ 174333965Sjdp int qualifiers; 174433965Sjdp int namelength; 174533965Sjdp int success = 1; 174633965Sjdp const char *p; 174733965Sjdp char num[2]; 174833965Sjdp string temp; 174933965Sjdp 175033965Sjdp string_init (&temp); 175133965Sjdp switch ((*mangled)[1]) 175233965Sjdp { 175333965Sjdp case '_': 175433965Sjdp /* GNU mangled name with more than 9 classes. The count is preceded 175533965Sjdp by an underscore (to distinguish it from the <= 9 case) and followed 175633965Sjdp by an underscore. */ 175733965Sjdp p = *mangled + 2; 175833965Sjdp qualifiers = atoi (p); 175933965Sjdp if (!isdigit (*p) || *p == '0') 176033965Sjdp success = 0; 176133965Sjdp 176233965Sjdp /* Skip the digits. */ 176333965Sjdp while (isdigit (*p)) 176433965Sjdp ++p; 176533965Sjdp 176633965Sjdp if (*p != '_') 176733965Sjdp success = 0; 176833965Sjdp 176933965Sjdp *mangled = p + 1; 177033965Sjdp break; 177133965Sjdp 177233965Sjdp case '1': 177333965Sjdp case '2': 177433965Sjdp case '3': 177533965Sjdp case '4': 177633965Sjdp case '5': 177733965Sjdp case '6': 177833965Sjdp case '7': 177933965Sjdp case '8': 178033965Sjdp case '9': 178133965Sjdp /* The count is in a single digit. */ 178233965Sjdp num[0] = (*mangled)[1]; 178333965Sjdp num[1] = '\0'; 178433965Sjdp qualifiers = atoi (num); 178533965Sjdp 178633965Sjdp /* If there is an underscore after the digit, skip it. This is 178733965Sjdp said to be for ARM-qualified names, but the ARM makes no 178833965Sjdp mention of such an underscore. Perhaps cfront uses one. */ 178933965Sjdp if ((*mangled)[2] == '_') 179033965Sjdp { 179133965Sjdp (*mangled)++; 179233965Sjdp } 179333965Sjdp (*mangled) += 2; 179433965Sjdp break; 179533965Sjdp 179633965Sjdp case '0': 179733965Sjdp default: 179833965Sjdp success = 0; 179933965Sjdp } 180033965Sjdp 180133965Sjdp if (!success) 180233965Sjdp return success; 180333965Sjdp 180433965Sjdp /* Pick off the names and collect them in the temp buffer in the order 180533965Sjdp in which they are found, separated by '::'. */ 180633965Sjdp 180733965Sjdp while (qualifiers-- > 0) 180833965Sjdp { 180933965Sjdp if (*mangled[0] == '_') 181033965Sjdp *mangled = *mangled + 1; 181133965Sjdp if (*mangled[0] == 't') 181233965Sjdp { 181333965Sjdp success = demangle_template(work, mangled, &temp, 0); 181433965Sjdp if (!success) break; 181533965Sjdp } 181633965Sjdp else 181733965Sjdp { 181833965Sjdp namelength = consume_count (mangled); 181933965Sjdp if (strlen (*mangled) < namelength) 182033965Sjdp { 182133965Sjdp /* Simple sanity check failed */ 182233965Sjdp success = 0; 182333965Sjdp break; 182433965Sjdp } 182533965Sjdp string_appendn (&temp, *mangled, namelength); 182633965Sjdp *mangled += namelength; 182733965Sjdp } 182833965Sjdp if (qualifiers > 0) 182933965Sjdp { 183033965Sjdp string_appendn (&temp, "::", 2); 183133965Sjdp } 183233965Sjdp } 183333965Sjdp 183433965Sjdp /* If we are using the result as a function name, we need to append 183533965Sjdp the appropriate '::' separated constructor or destructor name. 183633965Sjdp We do this here because this is the most convenient place, where 183733965Sjdp we already have a pointer to the name and the length of the name. */ 183833965Sjdp 183933965Sjdp if (isfuncname && (work->constructor & 1 || work->destructor & 1)) 184033965Sjdp { 184133965Sjdp string_appendn (&temp, "::", 2); 184233965Sjdp if (work -> destructor & 1) 184333965Sjdp { 184433965Sjdp string_append (&temp, "~"); 184533965Sjdp } 184633965Sjdp string_appendn (&temp, (*mangled) - namelength, namelength); 184733965Sjdp } 184833965Sjdp 184933965Sjdp /* Now either prepend the temp buffer to the result, or append it, 185033965Sjdp depending upon the state of the append flag. */ 185133965Sjdp 185233965Sjdp if (append) 185333965Sjdp { 185433965Sjdp string_appends (result, &temp); 185533965Sjdp } 185633965Sjdp else 185733965Sjdp { 185833965Sjdp if (!STRING_EMPTY (result)) 185933965Sjdp { 186033965Sjdp string_appendn (&temp, "::", 2); 186133965Sjdp } 186233965Sjdp string_prepends (result, &temp); 186333965Sjdp } 186433965Sjdp 186533965Sjdp string_delete (&temp); 186633965Sjdp return (success); 186733965Sjdp} 186833965Sjdp 186933965Sjdp/* 187033965Sjdp 187133965SjdpLOCAL FUNCTION 187233965Sjdp 187333965Sjdp get_count -- convert an ascii count to integer, consuming tokens 187433965Sjdp 187533965SjdpSYNOPSIS 187633965Sjdp 187733965Sjdp static int 187833965Sjdp get_count (const char **type, int *count) 187933965Sjdp 188033965SjdpDESCRIPTION 188133965Sjdp 188233965Sjdp Return 0 if no conversion is performed, 1 if a string is converted. 188333965Sjdp*/ 188433965Sjdp 188533965Sjdpstatic int 188633965Sjdpget_count (type, count) 188733965Sjdp const char **type; 188833965Sjdp int *count; 188933965Sjdp{ 189033965Sjdp const char *p; 189133965Sjdp int n; 189233965Sjdp 189333965Sjdp if (!isdigit (**type)) 189433965Sjdp { 189533965Sjdp return (0); 189633965Sjdp } 189733965Sjdp else 189833965Sjdp { 189933965Sjdp *count = **type - '0'; 190033965Sjdp (*type)++; 190133965Sjdp if (isdigit (**type)) 190233965Sjdp { 190333965Sjdp p = *type; 190433965Sjdp n = *count; 190533965Sjdp do 190633965Sjdp { 190733965Sjdp n *= 10; 190833965Sjdp n += *p - '0'; 190933965Sjdp p++; 191033965Sjdp } 191133965Sjdp while (isdigit (*p)); 191233965Sjdp if (*p == '_') 191333965Sjdp { 191433965Sjdp *type = p + 1; 191533965Sjdp *count = n; 191633965Sjdp } 191733965Sjdp } 191833965Sjdp } 191933965Sjdp return (1); 192033965Sjdp} 192133965Sjdp 192233965Sjdp/* result will be initialised here; it will be freed on failure */ 192333965Sjdp 192433965Sjdpstatic int 192533965Sjdpdo_type (work, mangled, result) 192633965Sjdp struct work_stuff *work; 192733965Sjdp const char **mangled; 192833965Sjdp string *result; 192933965Sjdp{ 193033965Sjdp int n; 193133965Sjdp int done; 193233965Sjdp int success; 193333965Sjdp string decl; 193433965Sjdp const char *remembered_type; 193533965Sjdp int constp; 193633965Sjdp int volatilep; 193733965Sjdp 193833965Sjdp string_init (&decl); 193933965Sjdp string_init (result); 194033965Sjdp 194133965Sjdp done = 0; 194233965Sjdp success = 1; 194333965Sjdp while (success && !done) 194433965Sjdp { 194533965Sjdp int member; 194633965Sjdp switch (**mangled) 194733965Sjdp { 194833965Sjdp 194933965Sjdp /* A pointer type */ 195033965Sjdp case 'P': 195133965Sjdp case 'p': 195233965Sjdp (*mangled)++; 195333965Sjdp string_prepend (&decl, "*"); 195433965Sjdp break; 195533965Sjdp 195633965Sjdp /* A reference type */ 195733965Sjdp case 'R': 195833965Sjdp (*mangled)++; 195933965Sjdp string_prepend (&decl, "&"); 196033965Sjdp break; 196133965Sjdp 196233965Sjdp /* An array */ 196333965Sjdp case 'A': 196433965Sjdp { 196533965Sjdp const char *p = ++(*mangled); 196633965Sjdp 196733965Sjdp string_prepend (&decl, "("); 196833965Sjdp string_append (&decl, ")["); 196933965Sjdp /* Copy anything up until the next underscore (the size of the 197033965Sjdp array). */ 197133965Sjdp while (**mangled && **mangled != '_') 197233965Sjdp ++(*mangled); 197333965Sjdp if (**mangled == '_') 197433965Sjdp { 197533965Sjdp string_appendn (&decl, p, *mangled - p); 197633965Sjdp string_append (&decl, "]"); 197733965Sjdp *mangled += 1; 197833965Sjdp } 197933965Sjdp else 198033965Sjdp success = 0; 198133965Sjdp break; 198233965Sjdp } 198333965Sjdp 198433965Sjdp /* A back reference to a previously seen type */ 198533965Sjdp case 'T': 198633965Sjdp (*mangled)++; 198733965Sjdp if (!get_count (mangled, &n) || n >= work -> ntypes) 198833965Sjdp { 198933965Sjdp success = 0; 199033965Sjdp } 199133965Sjdp else 199233965Sjdp { 199333965Sjdp remembered_type = work -> typevec[n]; 199433965Sjdp mangled = &remembered_type; 199533965Sjdp } 199633965Sjdp break; 199733965Sjdp 199833965Sjdp /* A function */ 199933965Sjdp case 'F': 200033965Sjdp (*mangled)++; 200133965Sjdp if (!STRING_EMPTY (&decl) && decl.b[0] == '*') 200233965Sjdp { 200333965Sjdp string_prepend (&decl, "("); 200433965Sjdp string_append (&decl, ")"); 200533965Sjdp } 200633965Sjdp /* After picking off the function args, we expect to either find the 200733965Sjdp function return type (preceded by an '_') or the end of the 200833965Sjdp string. */ 200933965Sjdp if (!demangle_args (work, mangled, &decl) 201033965Sjdp || (**mangled != '_' && **mangled != '\0')) 201133965Sjdp { 201233965Sjdp success = 0; 201333965Sjdp } 201433965Sjdp if (success && (**mangled == '_')) 201533965Sjdp { 201633965Sjdp (*mangled)++; 201733965Sjdp } 201833965Sjdp break; 201933965Sjdp 202033965Sjdp case 'M': 202133965Sjdp case 'O': 202233965Sjdp { 202333965Sjdp constp = 0; 202433965Sjdp volatilep = 0; 202533965Sjdp 202633965Sjdp member = **mangled == 'M'; 202733965Sjdp (*mangled)++; 202833965Sjdp if (!isdigit (**mangled) && **mangled != 't') 202933965Sjdp { 203033965Sjdp success = 0; 203133965Sjdp break; 203233965Sjdp } 203333965Sjdp 203433965Sjdp string_append (&decl, ")"); 203533965Sjdp string_prepend (&decl, "::"); 203633965Sjdp if (isdigit (**mangled)) 203733965Sjdp { 203833965Sjdp n = consume_count (mangled); 203933965Sjdp if (strlen (*mangled) < n) 204033965Sjdp { 204133965Sjdp success = 0; 204233965Sjdp break; 204333965Sjdp } 204433965Sjdp string_prependn (&decl, *mangled, n); 204533965Sjdp *mangled += n; 204633965Sjdp } 204733965Sjdp else 204833965Sjdp { 204933965Sjdp string temp; 205033965Sjdp string_init (&temp); 205133965Sjdp success = demangle_template (work, mangled, &temp, NULL); 205233965Sjdp if (success) 205333965Sjdp { 205433965Sjdp string_prependn (&decl, temp.b, temp.p - temp.b); 205533965Sjdp string_clear (&temp); 205633965Sjdp } 205733965Sjdp else 205833965Sjdp break; 205933965Sjdp } 206033965Sjdp string_prepend (&decl, "("); 206133965Sjdp if (member) 206233965Sjdp { 206333965Sjdp if (**mangled == 'C') 206433965Sjdp { 206533965Sjdp (*mangled)++; 206633965Sjdp constp = 1; 206733965Sjdp } 206833965Sjdp if (**mangled == 'V') 206933965Sjdp { 207033965Sjdp (*mangled)++; 207133965Sjdp volatilep = 1; 207233965Sjdp } 207333965Sjdp if (*(*mangled)++ != 'F') 207433965Sjdp { 207533965Sjdp success = 0; 207633965Sjdp break; 207733965Sjdp } 207833965Sjdp } 207933965Sjdp if ((member && !demangle_args (work, mangled, &decl)) 208033965Sjdp || **mangled != '_') 208133965Sjdp { 208233965Sjdp success = 0; 208333965Sjdp break; 208433965Sjdp } 208533965Sjdp (*mangled)++; 208633965Sjdp if (! PRINT_ANSI_QUALIFIERS) 208733965Sjdp { 208833965Sjdp break; 208933965Sjdp } 209033965Sjdp if (constp) 209133965Sjdp { 209233965Sjdp APPEND_BLANK (&decl); 209333965Sjdp string_append (&decl, "const"); 209433965Sjdp } 209533965Sjdp if (volatilep) 209633965Sjdp { 209733965Sjdp APPEND_BLANK (&decl); 209833965Sjdp string_append (&decl, "volatile"); 209933965Sjdp } 210033965Sjdp break; 210133965Sjdp } 210233965Sjdp case 'G': 210333965Sjdp (*mangled)++; 210433965Sjdp break; 210533965Sjdp 210633965Sjdp case 'C': 210733965Sjdp (*mangled)++; 210833965Sjdp /* 210933965Sjdp if ((*mangled)[1] == 'P') 211033965Sjdp { 211133965Sjdp */ 211233965Sjdp if (PRINT_ANSI_QUALIFIERS) 211333965Sjdp { 211433965Sjdp if (!STRING_EMPTY (&decl)) 211533965Sjdp { 211633965Sjdp string_prepend (&decl, " "); 211733965Sjdp } 211833965Sjdp string_prepend (&decl, "const"); 211933965Sjdp } 212033965Sjdp break; 212133965Sjdp /* 212233965Sjdp } 212333965Sjdp */ 212433965Sjdp 212533965Sjdp /* fall through */ 212633965Sjdp default: 212733965Sjdp done = 1; 212833965Sjdp break; 212933965Sjdp } 213033965Sjdp } 213133965Sjdp 213233965Sjdp switch (**mangled) 213333965Sjdp { 213433965Sjdp /* A qualified name, such as "Outer::Inner". */ 213533965Sjdp case 'Q': 213633965Sjdp success = demangle_qualified (work, mangled, result, 0, 1); 213733965Sjdp break; 213833965Sjdp 213933965Sjdp default: 214033965Sjdp success = demangle_fund_type (work, mangled, result); 214133965Sjdp break; 214233965Sjdp } 214333965Sjdp 214433965Sjdp if (success) 214533965Sjdp { 214633965Sjdp if (!STRING_EMPTY (&decl)) 214733965Sjdp { 214833965Sjdp string_append (result, " "); 214933965Sjdp string_appends (result, &decl); 215033965Sjdp } 215133965Sjdp } 215233965Sjdp else 215333965Sjdp { 215433965Sjdp string_delete (result); 215533965Sjdp } 215633965Sjdp string_delete (&decl); 215733965Sjdp return (success); 215833965Sjdp} 215933965Sjdp 216033965Sjdp/* Given a pointer to a type string that represents a fundamental type 216133965Sjdp argument (int, long, unsigned int, etc) in TYPE, a pointer to the 216233965Sjdp string in which the demangled output is being built in RESULT, and 216333965Sjdp the WORK structure, decode the types and add them to the result. 216433965Sjdp 216533965Sjdp For example: 216633965Sjdp 216733965Sjdp "Ci" => "const int" 216833965Sjdp "Sl" => "signed long" 216933965Sjdp "CUs" => "const unsigned short" 217033965Sjdp 217133965Sjdp */ 217233965Sjdp 217333965Sjdpstatic int 217433965Sjdpdemangle_fund_type (work, mangled, result) 217533965Sjdp struct work_stuff *work; 217633965Sjdp const char **mangled; 217733965Sjdp string *result; 217833965Sjdp{ 217933965Sjdp int done = 0; 218033965Sjdp int success = 1; 218133965Sjdp 218233965Sjdp /* First pick off any type qualifiers. There can be more than one. */ 218333965Sjdp 218433965Sjdp while (!done) 218533965Sjdp { 218633965Sjdp switch (**mangled) 218733965Sjdp { 218833965Sjdp case 'C': 218933965Sjdp (*mangled)++; 219033965Sjdp if (PRINT_ANSI_QUALIFIERS) 219133965Sjdp { 219233965Sjdp APPEND_BLANK (result); 219333965Sjdp string_append (result, "const"); 219433965Sjdp } 219533965Sjdp break; 219633965Sjdp case 'U': 219733965Sjdp (*mangled)++; 219833965Sjdp APPEND_BLANK (result); 219933965Sjdp string_append (result, "unsigned"); 220033965Sjdp break; 220133965Sjdp case 'S': /* signed char only */ 220233965Sjdp (*mangled)++; 220333965Sjdp APPEND_BLANK (result); 220433965Sjdp string_append (result, "signed"); 220533965Sjdp break; 220633965Sjdp case 'V': 220733965Sjdp (*mangled)++; 220833965Sjdp if (PRINT_ANSI_QUALIFIERS) 220933965Sjdp { 221033965Sjdp APPEND_BLANK (result); 221133965Sjdp string_append (result, "volatile"); 221233965Sjdp } 221333965Sjdp break; 221433965Sjdp default: 221533965Sjdp done = 1; 221633965Sjdp break; 221733965Sjdp } 221833965Sjdp } 221933965Sjdp 222033965Sjdp /* Now pick off the fundamental type. There can be only one. */ 222133965Sjdp 222233965Sjdp switch (**mangled) 222333965Sjdp { 222433965Sjdp case '\0': 222533965Sjdp case '_': 222633965Sjdp break; 222733965Sjdp case 'v': 222833965Sjdp (*mangled)++; 222933965Sjdp APPEND_BLANK (result); 223033965Sjdp string_append (result, "void"); 223133965Sjdp break; 223233965Sjdp case 'x': 223333965Sjdp (*mangled)++; 223433965Sjdp APPEND_BLANK (result); 223533965Sjdp string_append (result, "long long"); 223633965Sjdp break; 223733965Sjdp case 'l': 223833965Sjdp (*mangled)++; 223933965Sjdp APPEND_BLANK (result); 224033965Sjdp string_append (result, "long"); 224133965Sjdp break; 224233965Sjdp case 'i': 224333965Sjdp (*mangled)++; 224433965Sjdp APPEND_BLANK (result); 224533965Sjdp string_append (result, "int"); 224633965Sjdp break; 224733965Sjdp case 's': 224833965Sjdp (*mangled)++; 224933965Sjdp APPEND_BLANK (result); 225033965Sjdp string_append (result, "short"); 225133965Sjdp break; 225233965Sjdp case 'b': 225333965Sjdp (*mangled)++; 225433965Sjdp APPEND_BLANK (result); 225533965Sjdp string_append (result, "bool"); 225633965Sjdp break; 225733965Sjdp case 'c': 225833965Sjdp (*mangled)++; 225933965Sjdp APPEND_BLANK (result); 226033965Sjdp string_append (result, "char"); 226133965Sjdp break; 226233965Sjdp case 'w': 226333965Sjdp (*mangled)++; 226433965Sjdp APPEND_BLANK (result); 226533965Sjdp string_append (result, "wchar_t"); 226633965Sjdp break; 226733965Sjdp case 'r': 226833965Sjdp (*mangled)++; 226933965Sjdp APPEND_BLANK (result); 227033965Sjdp string_append (result, "long double"); 227133965Sjdp break; 227233965Sjdp case 'd': 227333965Sjdp (*mangled)++; 227433965Sjdp APPEND_BLANK (result); 227533965Sjdp string_append (result, "double"); 227633965Sjdp break; 227733965Sjdp case 'f': 227833965Sjdp (*mangled)++; 227933965Sjdp APPEND_BLANK (result); 228033965Sjdp string_append (result, "float"); 228133965Sjdp break; 228233965Sjdp case 'G': 228333965Sjdp (*mangled)++; 228433965Sjdp if (!isdigit (**mangled)) 228533965Sjdp { 228633965Sjdp success = 0; 228733965Sjdp break; 228833965Sjdp } 228933965Sjdp /* fall through */ 229033965Sjdp /* An explicit type, such as "6mytype" or "7integer" */ 229133965Sjdp case '0': 229233965Sjdp case '1': 229333965Sjdp case '2': 229433965Sjdp case '3': 229533965Sjdp case '4': 229633965Sjdp case '5': 229733965Sjdp case '6': 229833965Sjdp case '7': 229933965Sjdp case '8': 230033965Sjdp case '9': 230133965Sjdp APPEND_BLANK (result); 230233965Sjdp if (!demangle_class_name (work, mangled, result)) { 230333965Sjdp --result->p; 230433965Sjdp success = 0; 230533965Sjdp } 230633965Sjdp break; 230733965Sjdp case 't': 230833965Sjdp success = demangle_template(work,mangled, result, 0); 230933965Sjdp break; 231033965Sjdp default: 231133965Sjdp success = 0; 231233965Sjdp break; 231333965Sjdp } 231433965Sjdp 231533965Sjdp return (success); 231633965Sjdp} 231733965Sjdp 231833965Sjdp/* `result' will be initialized in do_type; it will be freed on failure */ 231933965Sjdp 232033965Sjdpstatic int 232133965Sjdpdo_arg (work, mangled, result) 232233965Sjdp struct work_stuff *work; 232333965Sjdp const char **mangled; 232433965Sjdp string *result; 232533965Sjdp{ 232633965Sjdp const char *start = *mangled; 232733965Sjdp 232833965Sjdp if (!do_type (work, mangled, result)) 232933965Sjdp { 233033965Sjdp return (0); 233133965Sjdp } 233233965Sjdp else 233333965Sjdp { 233433965Sjdp remember_type (work, start, *mangled - start); 233533965Sjdp return (1); 233633965Sjdp } 233733965Sjdp} 233833965Sjdp 233933965Sjdpstatic void 234033965Sjdpremember_type (work, start, len) 234133965Sjdp struct work_stuff *work; 234233965Sjdp const char *start; 234333965Sjdp int len; 234433965Sjdp{ 234533965Sjdp char *tem; 234633965Sjdp 234733965Sjdp if (work -> ntypes >= work -> typevec_size) 234833965Sjdp { 234933965Sjdp if (work -> typevec_size == 0) 235033965Sjdp { 235133965Sjdp work -> typevec_size = 3; 235233965Sjdp work -> typevec = 235333965Sjdp (char **) xmalloc (sizeof (char *) * work -> typevec_size); 235433965Sjdp } 235533965Sjdp else 235633965Sjdp { 235733965Sjdp work -> typevec_size *= 2; 235833965Sjdp work -> typevec = 235933965Sjdp (char **) xrealloc ((char *)work -> typevec, 236033965Sjdp sizeof (char *) * work -> typevec_size); 236133965Sjdp } 236233965Sjdp } 236333965Sjdp tem = xmalloc (len + 1); 236433965Sjdp memcpy (tem, start, len); 236533965Sjdp tem[len] = '\0'; 236633965Sjdp work -> typevec[work -> ntypes++] = tem; 236733965Sjdp} 236833965Sjdp 236933965Sjdp/* Forget the remembered types, but not the type vector itself. */ 237033965Sjdp 237133965Sjdpstatic void 237233965Sjdpforget_types (work) 237333965Sjdp struct work_stuff *work; 237433965Sjdp{ 237533965Sjdp int i; 237633965Sjdp 237733965Sjdp while (work -> ntypes > 0) 237833965Sjdp { 237933965Sjdp i = --(work -> ntypes); 238033965Sjdp if (work -> typevec[i] != NULL) 238133965Sjdp { 238233965Sjdp free (work -> typevec[i]); 238333965Sjdp work -> typevec[i] = NULL; 238433965Sjdp } 238533965Sjdp } 238633965Sjdp} 238733965Sjdp 238833965Sjdp/* Process the argument list part of the signature, after any class spec 238933965Sjdp has been consumed, as well as the first 'F' character (if any). For 239033965Sjdp example: 239133965Sjdp 239233965Sjdp "__als__3fooRT0" => process "RT0" 239333965Sjdp "complexfunc5__FPFPc_PFl_i" => process "PFPc_PFl_i" 239433965Sjdp 239533965Sjdp DECLP must be already initialised, usually non-empty. It won't be freed 239633965Sjdp on failure. 239733965Sjdp 239833965Sjdp Note that g++ differs significantly from ARM and lucid style mangling 239933965Sjdp with regards to references to previously seen types. For example, given 240033965Sjdp the source fragment: 240133965Sjdp 240233965Sjdp class foo { 240333965Sjdp public: 240433965Sjdp foo::foo (int, foo &ia, int, foo &ib, int, foo &ic); 240533965Sjdp }; 240633965Sjdp 240733965Sjdp foo::foo (int, foo &ia, int, foo &ib, int, foo &ic) { ia = ib = ic; } 240833965Sjdp void foo (int, foo &ia, int, foo &ib, int, foo &ic) { ia = ib = ic; } 240933965Sjdp 241033965Sjdp g++ produces the names: 241133965Sjdp 241233965Sjdp __3fooiRT0iT2iT2 241333965Sjdp foo__FiR3fooiT1iT1 241433965Sjdp 241533965Sjdp while lcc (and presumably other ARM style compilers as well) produces: 241633965Sjdp 241733965Sjdp foo__FiR3fooT1T2T1T2 241833965Sjdp __ct__3fooFiR3fooT1T2T1T2 241933965Sjdp 242033965Sjdp Note that g++ bases it's type numbers starting at zero and counts all 242133965Sjdp previously seen types, while lucid/ARM bases it's type numbers starting 242233965Sjdp at one and only considers types after it has seen the 'F' character 242333965Sjdp indicating the start of the function args. For lucid/ARM style, we 242433965Sjdp account for this difference by discarding any previously seen types when 242533965Sjdp we see the 'F' character, and subtracting one from the type number 242633965Sjdp reference. 242733965Sjdp 242833965Sjdp */ 242933965Sjdp 243033965Sjdpstatic int 243133965Sjdpdemangle_args (work, mangled, declp) 243233965Sjdp struct work_stuff *work; 243333965Sjdp const char **mangled; 243433965Sjdp string *declp; 243533965Sjdp{ 243633965Sjdp string arg; 243733965Sjdp int need_comma = 0; 243833965Sjdp int r; 243933965Sjdp int t; 244033965Sjdp const char *tem; 244133965Sjdp char temptype; 244233965Sjdp 244333965Sjdp if (PRINT_ARG_TYPES) 244433965Sjdp { 244533965Sjdp string_append (declp, "("); 244633965Sjdp if (**mangled == '\0') 244733965Sjdp { 244833965Sjdp string_append (declp, "void"); 244933965Sjdp } 245033965Sjdp } 245133965Sjdp 245233965Sjdp while (**mangled != '_' && **mangled != '\0' && **mangled != 'e') 245333965Sjdp { 245433965Sjdp if ((**mangled == 'N') || (**mangled == 'T')) 245533965Sjdp { 245633965Sjdp temptype = *(*mangled)++; 245733965Sjdp 245833965Sjdp if (temptype == 'N') 245933965Sjdp { 246033965Sjdp if (!get_count (mangled, &r)) 246133965Sjdp { 246233965Sjdp return (0); 246333965Sjdp } 246433965Sjdp } 246533965Sjdp else 246633965Sjdp { 246733965Sjdp r = 1; 246833965Sjdp } 246933965Sjdp if (ARM_DEMANGLING && work -> ntypes >= 10) 247033965Sjdp { 247133965Sjdp /* If we have 10 or more types we might have more than a 1 digit 247233965Sjdp index so we'll have to consume the whole count here. This 247333965Sjdp will lose if the next thing is a type name preceded by a 247433965Sjdp count but it's impossible to demangle that case properly 247533965Sjdp anyway. Eg if we already have 12 types is T12Pc "(..., type1, 247633965Sjdp Pc, ...)" or "(..., type12, char *, ...)" */ 247733965Sjdp if ((t = consume_count(mangled)) == 0) 247833965Sjdp { 247933965Sjdp return (0); 248033965Sjdp } 248133965Sjdp } 248233965Sjdp else 248333965Sjdp { 248433965Sjdp if (!get_count (mangled, &t)) 248533965Sjdp { 248633965Sjdp return (0); 248733965Sjdp } 248833965Sjdp } 248933965Sjdp if (LUCID_DEMANGLING || ARM_DEMANGLING) 249033965Sjdp { 249133965Sjdp t--; 249233965Sjdp } 249333965Sjdp /* Validate the type index. Protect against illegal indices from 249433965Sjdp malformed type strings. */ 249533965Sjdp if ((t < 0) || (t >= work -> ntypes)) 249633965Sjdp { 249733965Sjdp return (0); 249833965Sjdp } 249933965Sjdp while (--r >= 0) 250033965Sjdp { 250133965Sjdp tem = work -> typevec[t]; 250233965Sjdp if (need_comma && PRINT_ARG_TYPES) 250333965Sjdp { 250433965Sjdp string_append (declp, ", "); 250533965Sjdp } 250633965Sjdp if (!do_arg (work, &tem, &arg)) 250733965Sjdp { 250833965Sjdp return (0); 250933965Sjdp } 251033965Sjdp if (PRINT_ARG_TYPES) 251133965Sjdp { 251233965Sjdp string_appends (declp, &arg); 251333965Sjdp } 251433965Sjdp string_delete (&arg); 251533965Sjdp need_comma = 1; 251633965Sjdp } 251733965Sjdp } 251833965Sjdp else 251933965Sjdp { 252033965Sjdp if (need_comma & PRINT_ARG_TYPES) 252133965Sjdp { 252233965Sjdp string_append (declp, ", "); 252333965Sjdp } 252433965Sjdp if (!do_arg (work, mangled, &arg)) 252533965Sjdp { 252633965Sjdp return (0); 252733965Sjdp } 252833965Sjdp if (PRINT_ARG_TYPES) 252933965Sjdp { 253033965Sjdp string_appends (declp, &arg); 253133965Sjdp } 253233965Sjdp string_delete (&arg); 253333965Sjdp need_comma = 1; 253433965Sjdp } 253533965Sjdp } 253633965Sjdp 253733965Sjdp if (**mangled == 'e') 253833965Sjdp { 253933965Sjdp (*mangled)++; 254033965Sjdp if (PRINT_ARG_TYPES) 254133965Sjdp { 254233965Sjdp if (need_comma) 254333965Sjdp { 254433965Sjdp string_append (declp, ","); 254533965Sjdp } 254633965Sjdp string_append (declp, "..."); 254733965Sjdp } 254833965Sjdp } 254933965Sjdp 255033965Sjdp if (PRINT_ARG_TYPES) 255133965Sjdp { 255233965Sjdp string_append (declp, ")"); 255333965Sjdp } 255433965Sjdp return (1); 255533965Sjdp} 255633965Sjdp 255733965Sjdpstatic void 255833965Sjdpdemangle_function_name (work, mangled, declp, scan) 255933965Sjdp struct work_stuff *work; 256033965Sjdp const char **mangled; 256133965Sjdp string *declp; 256233965Sjdp const char *scan; 256333965Sjdp{ 256433965Sjdp int i; 256533965Sjdp int len; 256633965Sjdp string type; 256733965Sjdp const char *tem; 256833965Sjdp 256933965Sjdp string_appendn (declp, (*mangled), scan - (*mangled)); 257033965Sjdp string_need (declp, 1); 257133965Sjdp *(declp -> p) = '\0'; 257233965Sjdp 257333965Sjdp /* Consume the function name, including the "__" separating the name 257433965Sjdp from the signature. We are guaranteed that SCAN points to the 257533965Sjdp separator. */ 257633965Sjdp 257733965Sjdp (*mangled) = scan + 2; 257833965Sjdp 257933965Sjdp if (LUCID_DEMANGLING || ARM_DEMANGLING) 258033965Sjdp { 258133965Sjdp 258233965Sjdp /* See if we have an ARM style constructor or destructor operator. 258333965Sjdp If so, then just record it, clear the decl, and return. 258433965Sjdp We can't build the actual constructor/destructor decl until later, 258533965Sjdp when we recover the class name from the signature. */ 258633965Sjdp 258733965Sjdp if (strcmp (declp -> b, "__ct") == 0) 258833965Sjdp { 258933965Sjdp work -> constructor += 1; 259033965Sjdp string_clear (declp); 259133965Sjdp return; 259233965Sjdp } 259333965Sjdp else if (strcmp (declp -> b, "__dt") == 0) 259433965Sjdp { 259533965Sjdp work -> destructor += 1; 259633965Sjdp string_clear (declp); 259733965Sjdp return; 259833965Sjdp } 259933965Sjdp } 260033965Sjdp 260133965Sjdp if (declp->p - declp->b >= 3 260233965Sjdp && declp->b[0] == 'o' 260333965Sjdp && declp->b[1] == 'p' 260433965Sjdp && strchr (cplus_markers, declp->b[2]) != NULL) 260533965Sjdp { 260633965Sjdp /* see if it's an assignment expression */ 260733965Sjdp if (declp->p - declp->b >= 10 /* op$assign_ */ 260833965Sjdp && memcmp (declp->b + 3, "assign_", 7) == 0) 260933965Sjdp { 261033965Sjdp for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++) 261133965Sjdp { 261233965Sjdp len = declp->p - declp->b - 10; 261333965Sjdp if (strlen (optable[i].in) == len 261433965Sjdp && memcmp (optable[i].in, declp->b + 10, len) == 0) 261533965Sjdp { 261633965Sjdp string_clear (declp); 261733965Sjdp string_append (declp, "operator"); 261833965Sjdp string_append (declp, optable[i].out); 261933965Sjdp string_append (declp, "="); 262033965Sjdp break; 262133965Sjdp } 262233965Sjdp } 262333965Sjdp } 262433965Sjdp else 262533965Sjdp { 262633965Sjdp for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++) 262733965Sjdp { 262833965Sjdp int len = declp->p - declp->b - 3; 262933965Sjdp if (strlen (optable[i].in) == len 263033965Sjdp && memcmp (optable[i].in, declp->b + 3, len) == 0) 263133965Sjdp { 263233965Sjdp string_clear (declp); 263333965Sjdp string_append (declp, "operator"); 263433965Sjdp string_append (declp, optable[i].out); 263533965Sjdp break; 263633965Sjdp } 263733965Sjdp } 263833965Sjdp } 263933965Sjdp } 264033965Sjdp else if (declp->p - declp->b >= 5 && memcmp (declp->b, "type", 4) == 0 264133965Sjdp && strchr (cplus_markers, declp->b[4]) != NULL) 264233965Sjdp { 264333965Sjdp /* type conversion operator */ 264433965Sjdp tem = declp->b + 5; 264533965Sjdp if (do_type (work, &tem, &type)) 264633965Sjdp { 264733965Sjdp string_clear (declp); 264833965Sjdp string_append (declp, "operator "); 264933965Sjdp string_appends (declp, &type); 265033965Sjdp string_delete (&type); 265133965Sjdp } 265233965Sjdp } 265333965Sjdp else if (declp->b[0] == '_' && declp->b[1] == '_' 265433965Sjdp && declp->b[2] == 'o' && declp->b[3] == 'p') 265533965Sjdp { 265633965Sjdp /* ANSI. */ 265733965Sjdp /* type conversion operator. */ 265833965Sjdp tem = declp->b + 4; 265933965Sjdp if (do_type (work, &tem, &type)) 266033965Sjdp { 266133965Sjdp string_clear (declp); 266233965Sjdp string_append (declp, "operator "); 266333965Sjdp string_appends (declp, &type); 266433965Sjdp string_delete (&type); 266533965Sjdp } 266633965Sjdp } 266733965Sjdp else if (declp->b[0] == '_' && declp->b[1] == '_' 266833965Sjdp && declp->b[2] >= 'a' && declp->b[2] <= 'z' 266933965Sjdp && declp->b[3] >= 'a' && declp->b[3] <= 'z') 267033965Sjdp { 267133965Sjdp if (declp->b[4] == '\0') 267233965Sjdp { 267333965Sjdp /* Operator. */ 267433965Sjdp for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++) 267533965Sjdp { 267633965Sjdp if (strlen (optable[i].in) == 2 267733965Sjdp && memcmp (optable[i].in, declp->b + 2, 2) == 0) 267833965Sjdp { 267933965Sjdp string_clear (declp); 268033965Sjdp string_append (declp, "operator"); 268133965Sjdp string_append (declp, optable[i].out); 268233965Sjdp break; 268333965Sjdp } 268433965Sjdp } 268533965Sjdp } 268633965Sjdp else 268733965Sjdp { 268833965Sjdp if (declp->b[2] == 'a' && declp->b[5] == '\0') 268933965Sjdp { 269033965Sjdp /* Assignment. */ 269133965Sjdp for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++) 269233965Sjdp { 269333965Sjdp if (strlen (optable[i].in) == 3 269433965Sjdp && memcmp (optable[i].in, declp->b + 2, 3) == 0) 269533965Sjdp { 269633965Sjdp string_clear (declp); 269733965Sjdp string_append (declp, "operator"); 269833965Sjdp string_append (declp, optable[i].out); 269933965Sjdp break; 270033965Sjdp } 270133965Sjdp } 270233965Sjdp } 270333965Sjdp } 270433965Sjdp } 270533965Sjdp} 270633965Sjdp 270733965Sjdp/* a mini string-handling package */ 270833965Sjdp 270933965Sjdpstatic void 271033965Sjdpstring_need (s, n) 271133965Sjdp string *s; 271233965Sjdp int n; 271333965Sjdp{ 271433965Sjdp int tem; 271533965Sjdp 271633965Sjdp if (s->b == NULL) 271733965Sjdp { 271833965Sjdp if (n < 32) 271933965Sjdp { 272033965Sjdp n = 32; 272133965Sjdp } 272233965Sjdp s->p = s->b = xmalloc (n); 272333965Sjdp s->e = s->b + n; 272433965Sjdp } 272533965Sjdp else if (s->e - s->p < n) 272633965Sjdp { 272733965Sjdp tem = s->p - s->b; 272833965Sjdp n += tem; 272933965Sjdp n *= 2; 273033965Sjdp s->b = xrealloc (s->b, n); 273133965Sjdp s->p = s->b + tem; 273233965Sjdp s->e = s->b + n; 273333965Sjdp } 273433965Sjdp} 273533965Sjdp 273633965Sjdpstatic void 273733965Sjdpstring_delete (s) 273833965Sjdp string *s; 273933965Sjdp{ 274033965Sjdp if (s->b != NULL) 274133965Sjdp { 274233965Sjdp free (s->b); 274333965Sjdp s->b = s->e = s->p = NULL; 274433965Sjdp } 274533965Sjdp} 274633965Sjdp 274733965Sjdpstatic void 274833965Sjdpstring_init (s) 274933965Sjdp string *s; 275033965Sjdp{ 275133965Sjdp s->b = s->p = s->e = NULL; 275233965Sjdp} 275333965Sjdp 275433965Sjdpstatic void 275533965Sjdpstring_clear (s) 275633965Sjdp string *s; 275733965Sjdp{ 275833965Sjdp s->p = s->b; 275933965Sjdp} 276033965Sjdp 276133965Sjdp#if 0 276233965Sjdp 276333965Sjdpstatic int 276433965Sjdpstring_empty (s) 276533965Sjdp string *s; 276633965Sjdp{ 276733965Sjdp return (s->b == s->p); 276833965Sjdp} 276933965Sjdp 277033965Sjdp#endif 277133965Sjdp 277233965Sjdpstatic void 277333965Sjdpstring_append (p, s) 277433965Sjdp string *p; 277533965Sjdp const char *s; 277633965Sjdp{ 277733965Sjdp int n; 277833965Sjdp if (s == NULL || *s == '\0') 277933965Sjdp return; 278033965Sjdp n = strlen (s); 278133965Sjdp string_need (p, n); 278233965Sjdp memcpy (p->p, s, n); 278333965Sjdp p->p += n; 278433965Sjdp} 278533965Sjdp 278633965Sjdpstatic void 278733965Sjdpstring_appends (p, s) 278833965Sjdp string *p, *s; 278933965Sjdp{ 279033965Sjdp int n; 279133965Sjdp 279233965Sjdp if (s->b != s->p) 279333965Sjdp { 279433965Sjdp n = s->p - s->b; 279533965Sjdp string_need (p, n); 279633965Sjdp memcpy (p->p, s->b, n); 279733965Sjdp p->p += n; 279833965Sjdp } 279933965Sjdp} 280033965Sjdp 280133965Sjdpstatic void 280233965Sjdpstring_appendn (p, s, n) 280333965Sjdp string *p; 280433965Sjdp const char *s; 280533965Sjdp int n; 280633965Sjdp{ 280733965Sjdp if (n != 0) 280833965Sjdp { 280933965Sjdp string_need (p, n); 281033965Sjdp memcpy (p->p, s, n); 281133965Sjdp p->p += n; 281233965Sjdp } 281333965Sjdp} 281433965Sjdp 281533965Sjdpstatic void 281633965Sjdpstring_prepend (p, s) 281733965Sjdp string *p; 281833965Sjdp const char *s; 281933965Sjdp{ 282033965Sjdp if (s != NULL && *s != '\0') 282133965Sjdp { 282233965Sjdp string_prependn (p, s, strlen (s)); 282333965Sjdp } 282433965Sjdp} 282533965Sjdp 282633965Sjdpstatic void 282733965Sjdpstring_prepends (p, s) 282833965Sjdp string *p, *s; 282933965Sjdp{ 283033965Sjdp if (s->b != s->p) 283133965Sjdp { 283233965Sjdp string_prependn (p, s->b, s->p - s->b); 283333965Sjdp } 283433965Sjdp} 283533965Sjdp 283633965Sjdpstatic void 283733965Sjdpstring_prependn (p, s, n) 283833965Sjdp string *p; 283933965Sjdp const char *s; 284033965Sjdp int n; 284133965Sjdp{ 284233965Sjdp char *q; 284333965Sjdp 284433965Sjdp if (n != 0) 284533965Sjdp { 284633965Sjdp string_need (p, n); 284733965Sjdp for (q = p->p - 1; q >= p->b; q--) 284833965Sjdp { 284933965Sjdp q[n] = q[0]; 285033965Sjdp } 285133965Sjdp memcpy (p->b, s, n); 285233965Sjdp p->p += n; 285333965Sjdp } 285433965Sjdp} 285533965Sjdp 285633965Sjdp/* To generate a standalone demangler program for testing purposes, 285733965Sjdp just compile and link this file with -DMAIN and libiberty.a. When 285833965Sjdp run, it demangles each command line arg, or each stdin string, and 285933965Sjdp prints the result on stdout. */ 286033965Sjdp 286133965Sjdp#ifdef MAIN 286233965Sjdp 286333965Sjdpstatic void demangle_it PARAMS ((char *)); 286433965Sjdpstatic void usage PARAMS ((FILE *, int)); 286533965Sjdpstatic void fatal PARAMS ((char *)); 286633965Sjdp 286733965Sjdpstatic void 286833965Sjdpdemangle_it (mangled_name) 286933965Sjdp char *mangled_name; 287033965Sjdp{ 287133965Sjdp char *result; 287233965Sjdp 287333965Sjdp result = cplus_demangle (mangled_name, DMGL_PARAMS | DMGL_ANSI); 287433965Sjdp if (result == NULL) 287533965Sjdp { 287633965Sjdp printf ("%s\n", mangled_name); 287733965Sjdp } 287833965Sjdp else 287933965Sjdp { 288033965Sjdp printf ("%s\n", result); 288133965Sjdp free (result); 288233965Sjdp } 288333965Sjdp} 288433965Sjdp 288533965Sjdp#include "getopt.h" 288633965Sjdp 288733965Sjdpstatic char *program_name; 288833965Sjdpstatic char *program_version = VERSION; 288933965Sjdp 289033965Sjdpstatic void 289133965Sjdpusage (stream, status) 289233965Sjdp FILE *stream; 289333965Sjdp int status; 289433965Sjdp{ 289533965Sjdp fprintf (stream, "\ 289633965SjdpUsage: %s [-_] [-n] [-s {gnu,lucid,arm}] [--strip-underscores]\n\ 289733965Sjdp[--no-strip-underscores] [--format={gnu,lucid,arm}]\n\ 289833965Sjdp[--help] [--version] [arg...]\n", 289933965Sjdp program_name); 290033965Sjdp exit (status); 290133965Sjdp} 290233965Sjdp 290333965Sjdp#define MBUF_SIZE 512 290433965Sjdpchar mbuffer[MBUF_SIZE]; 290533965Sjdp 290633965Sjdp/* Defined in the automatically-generated underscore.c. */ 290733965Sjdpextern int prepends_underscore; 290833965Sjdp 290933965Sjdpint strip_underscore = 0; 291033965Sjdp 291133965Sjdpstatic struct option long_options[] = { 291233965Sjdp {"strip-underscores", no_argument, 0, '_'}, 291333965Sjdp {"format", required_argument, 0, 's'}, 291433965Sjdp {"help", no_argument, 0, 'h'}, 291533965Sjdp {"no-strip-underscores", no_argument, 0, 'n'}, 291633965Sjdp {"version", no_argument, 0, 'v'}, 291733965Sjdp {0, no_argument, 0, 0} 291833965Sjdp}; 291933965Sjdp 292033965Sjdpint 292133965Sjdpmain (argc, argv) 292233965Sjdp int argc; 292333965Sjdp char **argv; 292433965Sjdp{ 292533965Sjdp char *result; 292633965Sjdp int c; 292733965Sjdp 292833965Sjdp program_name = argv[0]; 292933965Sjdp 293033965Sjdp strip_underscore = prepends_underscore; 293133965Sjdp 293233965Sjdp while ((c = getopt_long (argc, argv, "_ns:", long_options, (int *) 0)) != EOF) 293333965Sjdp { 293433965Sjdp switch (c) 293533965Sjdp { 293633965Sjdp case '?': 293733965Sjdp usage (stderr, 1); 293833965Sjdp break; 293933965Sjdp case 'h': 294033965Sjdp usage (stdout, 0); 294133965Sjdp case 'n': 294233965Sjdp strip_underscore = 0; 294333965Sjdp break; 294433965Sjdp case 'v': 294533965Sjdp printf ("GNU %s version %s\n", program_name, program_version); 294633965Sjdp exit (0); 294733965Sjdp case '_': 294833965Sjdp strip_underscore = 1; 294933965Sjdp break; 295033965Sjdp case 's': 295133965Sjdp if (strcmp (optarg, "gnu") == 0) 295233965Sjdp { 295333965Sjdp current_demangling_style = gnu_demangling; 295433965Sjdp } 295533965Sjdp else if (strcmp (optarg, "lucid") == 0) 295633965Sjdp { 295733965Sjdp current_demangling_style = lucid_demangling; 295833965Sjdp } 295933965Sjdp else if (strcmp (optarg, "arm") == 0) 296033965Sjdp { 296133965Sjdp current_demangling_style = arm_demangling; 296233965Sjdp } 296333965Sjdp else 296433965Sjdp { 296533965Sjdp fprintf (stderr, "%s: unknown demangling style `%s'\n", 296633965Sjdp program_name, optarg); 296733965Sjdp exit (1); 296833965Sjdp } 296933965Sjdp break; 297033965Sjdp } 297133965Sjdp } 297233965Sjdp 297333965Sjdp if (optind < argc) 297433965Sjdp { 297533965Sjdp for ( ; optind < argc; optind++) 297633965Sjdp { 297733965Sjdp demangle_it (argv[optind]); 297833965Sjdp } 297933965Sjdp } 298033965Sjdp else 298133965Sjdp { 298233965Sjdp for (;;) 298333965Sjdp { 298433965Sjdp int i = 0; 298533965Sjdp c = getchar (); 298633965Sjdp /* Try to read a label. */ 298733965Sjdp while (c != EOF && (isalnum(c) || c == '_' || c == '$' || c == '.')) 298833965Sjdp { 298933965Sjdp if (i >= MBUF_SIZE-1) 299033965Sjdp break; 299133965Sjdp mbuffer[i++] = c; 299233965Sjdp c = getchar (); 299333965Sjdp } 299433965Sjdp if (i > 0) 299533965Sjdp { 299633965Sjdp int skip_first = 0; 299733965Sjdp 299833965Sjdp if (mbuffer[0] == '.') 299933965Sjdp ++skip_first; 300033965Sjdp if (strip_underscore && mbuffer[skip_first] == '_') 300133965Sjdp ++skip_first; 300233965Sjdp 300333965Sjdp if (skip_first > i) 300433965Sjdp skip_first = i; 300533965Sjdp 300633965Sjdp mbuffer[i] = 0; 300733965Sjdp 300833965Sjdp result = cplus_demangle (mbuffer + skip_first, 300933965Sjdp DMGL_PARAMS | DMGL_ANSI); 301033965Sjdp if (result) 301133965Sjdp { 301233965Sjdp if (mbuffer[0] == '.') 301333965Sjdp putc ('.', stdout); 301433965Sjdp fputs (result, stdout); 301533965Sjdp free (result); 301633965Sjdp } 301733965Sjdp else 301833965Sjdp fputs (mbuffer, stdout); 301933965Sjdp 302033965Sjdp fflush (stdout); 302133965Sjdp } 302233965Sjdp if (c == EOF) 302333965Sjdp break; 302433965Sjdp putchar (c); 302533965Sjdp } 302633965Sjdp } 302733965Sjdp 302833965Sjdp exit (0); 302933965Sjdp} 303033965Sjdp 303133965Sjdpstatic void 303233965Sjdpfatal (str) 303333965Sjdp char *str; 303433965Sjdp{ 303533965Sjdp fprintf (stderr, "%s: %s\n", program_name, str); 303633965Sjdp exit (1); 303733965Sjdp} 303833965Sjdp 303933965Sjdpchar * malloc (); 304033965Sjdpchar * realloc (); 304133965Sjdp 304233965Sjdpchar * 304333965Sjdpxmalloc (size) 304433965Sjdp unsigned size; 304533965Sjdp{ 304633965Sjdp register char *value = (char *) malloc (size); 304733965Sjdp if (value == 0) 304833965Sjdp fatal ("virtual memory exhausted"); 304933965Sjdp return value; 305033965Sjdp} 305133965Sjdp 305233965Sjdpchar * 305333965Sjdpxrealloc (ptr, size) 305433965Sjdp char *ptr; 305533965Sjdp unsigned size; 305633965Sjdp{ 305733965Sjdp register char *value = (char *) realloc (ptr, size); 305833965Sjdp if (value == 0) 305933965Sjdp fatal ("virtual memory exhausted"); 306033965Sjdp return value; 306133965Sjdp} 306233965Sjdp#endif /* main */ 3063