/* * gcc3 name demangler. */ #include #include #include #include typedef struct Chartab Chartab; struct Chartab { char c; char *s; }; static char* chartabsearch(Chartab *ct, int c) { for(; ct->c; ct++) if(ct->c == c) return ct->s; return nil; } typedef struct Gccstate Gccstate; struct Gccstate { char *name[128]; int nname; }; static int gccname(char**, char**, Gccstate*); char* demanglegcc3(char *s, char *buf) { char *p, *os; Gccstate state; state.nname = 0; os = s; /* mangled names always start with _Z */ if(s[0] != '_' || s[1] != 'Z') return s; s += 2; p = buf; if(!gccname(&s, &p, &state)){ if(strchr(os, '@') == nil) fprint(2, "demangle: %s\n"); return os; } if(*s){ /* the rest of the name is the argument types */ *p++ = '('; while(*s != 0 && gccname(&s, &p, &state)) *p++ = ','; if(*(p-1) == ',') p--; *p++ = ')'; } *p = 0; return buf; } static Chartab stdnames[] = { 'a', "std::allocator", 'b', "std::basic_string", 'd', "std::iostream", 'i', "std::istream", 'o', "std::ostream", 's', "std::string", 0, 0 }; static Chartab typetab[] = { 'b', "bool", 'c', "char", 'd', "double", 'i', "int", 'j', "uint", 'v', "void", 0, 0 }; static struct { char *shrt; char *actual; char *lng; } operators[] = { "aN", "&=", "andeq", "aS", "=", "assign", "aa", "&&", "andand", "ad", "&", "and", "an", "&", "and", "cl", "()", "construct", "cm", ",", "comma", "co", "~", "twiddle", "dV", "/=", "diveq", "da", "delete[]", "deletearray", "de", "*", "star", "dl", "delete", "delete", "dv", "/", "div", "eO", "^=", "xoreq", "eo", "^", "xor", "eq", "==", "eq", "ge", ">=", "geq", "gt", ">", "gt", "ix", "[]", "index", "IS", "<<=", "lsheq", "le", "<=", "leq", "ls", "<<", "lsh", "lt", "<", "lt", "ml", "-=", "subeq", "mL", "*=", "muleq", "mi", "-", "sub", "mI", "*", "mul", "mm", "--", "dec", "na", "new[]", "newarray", "ne", "!=", "neq", "ng", "-", "neg", "nt", "!", "not", "nw", "new", "new", "oR", "|=", "oreq", "oo", "||", "oror", "or", "|", "or", "pL", "+=", "addeq", "pl", "+", "add", "pm", "->*", "pointstoderef", "pp", "++", "inc", "ps", "+", "pos", "pt", "->", "pointsto", "qu", "?", "question", "rM", "%=", "modeq", "rS", ">>=", "rsheq", "rm", "%", "mod", "rs", ">>", "rsh", "st", "sizeof", "sizeoftype", "sz", "sizeof", "sizeofexpr", 0,0,0 }; /* * Pick apart the next mangled name section. * Names and types are treated as the same. * Let's see how far we can go before that becomes a problem. */ static int gccname(char **ps, char **pp, Gccstate *state) { int i, n; char *os, *s, *t, *p; Gccstate nstate; s = *ps; os = s; p = *pp; /* print("\tgccname: %s\n", s); */ /* overloaded operators */ for(i=0; operators[i].shrt; i++){ if(memcmp(operators[i].shrt, s, 2) == 0){ strcpy(p, "operator$"); strcat(p, operators[i].lng); p += strlen(p); s += 2; goto suffix; } } /* basic types */ if((t = chartabsearch(typetab, *s)) != nil){ s++; strcpy(p, t); p += strlen(t); goto suffix; } switch(*s){ default: bad: fprint(2, "bad name: %s\n", s); return 0; case '1': case '2': case '3': case '4': /* name length */ case '5': case '6': case '7': case '8': case '9': n = strtol(s, &s, 10); memmove(p, s, n); p += n; s += n; break; case 'C': /* C1: constructor? */ strtol(s+1, &s, 10); strcpy(p, "constructor"); p += strlen(p); break; case 'D': /* D1: destructor? */ strtol(s+1, &s, 10); strcpy(p, "destructor"); p += strlen(p); break; case 'K': /* const */ s++; strcpy(p, "const "); p += strlen(p); if(!gccname(&s, &p, state)) return 0; break; case 'L': /* default value */ t = s; s++; if(!gccname(&s, &p, state)) return 0; if(!isdigit((uchar)*s)){ fprint(2, "bad value: %s\n", t); return 0; } n = strtol(s, &s, 10); if(*s != 'E'){ fprint(2, "bad value2: %s\n", t); return 0; } sprint(p, "=%d", n); p += strlen(p); s++; break; case 'N': /* hierarchical name */ s++; while(*s != 'E'){ if(!gccname(&s, &p, state)){ fprint(2, "bad name in hierarchy: %s in %s\n", s, os); return 0; } strcpy(p, "::"); p += 2; } p -= 2; s++; break; case 'P': /* pointer to */ s++; if(!gccname(&s, &p, state)) return 0; *p++ = '*'; break; case 'R': /* reference to */ s++; if(!gccname(&s, &p, state)) return 0; *p++ = '&'; break; case 'S': /* standard or previously-seen name */ s++; if('0' <= *s && *s <= '9'){ /* previously seen */ t = s-1; n = strtol(s, &s, 10); if(*s != '_'){ fprint(2, "bad S: %s\n", t); return 0; } s++; sprint(p, "S%d_", n); p += strlen(p); break; } /* SA_ ??? */ if(*s == 'A' && *(s+1) == '_'){ strcpy(p, "SA_"); p += 3; s += 2; break; } /* standard name */ if(*s == 't'){ strcpy(p, "std::"); p += 5; s++; if(!gccname(&s, &p, state)) return 0; }else if((t = chartabsearch(stdnames, *s)) != nil){ strcpy(p, t); p += strlen(p); s++; }else{ strcpy(p, "std::"); p += 5; *p++ = *s++; } break; case 'T': /* previously-seen type??? T0_ also T_*/ t = s; for(; *s != '_'; s++){ if(*s == 0){ s = t; goto bad; } } s++; memmove(p, t, s-t); p += s-t; break; } suffix: if(*s == 'I'){ /* template suffix */ nstate.nname = 0; *p++ = '<'; s++; while(*s != 'E'){ if(!gccname(&s, &p, &nstate)){ fprint(2, "bad name in template: %s\n", s); return 0; } *p++ = ','; } *(p-1) = '>'; s++; } *ps = s; *pp = p; return 1; }