339 lines
5.6 KiB
C
339 lines
5.6 KiB
C
/*
|
|
* 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;
|
|
}
|
|
|