blob: eca26eb1b9af3aee17c5d10acfc2e45294649cac [file] [log] [blame]
/*
* gcc3 name demangler.
*/
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <mach.h>
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;
}