338 lines
5.3 KiB
C
338 lines
5.3 KiB
C
|
|
/*
|
||
|
|
* gcc2 name demangler.
|
||
|
|
*/
|
||
|
|
#include <u.h>
|
||
|
|
#include <libc.h>
|
||
|
|
#include <bio.h>
|
||
|
|
#include <mach.h>
|
||
|
|
|
||
|
|
#define debug 0
|
||
|
|
|
||
|
|
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*
|
||
|
|
demanglegcc2(char *s, char *buf)
|
||
|
|
{
|
||
|
|
char *p, *os, *name, *t;
|
||
|
|
int namelen;
|
||
|
|
Gccstate state;
|
||
|
|
|
||
|
|
state.nname = 0;
|
||
|
|
os = s;
|
||
|
|
p = buf;
|
||
|
|
|
||
|
|
if(memcmp(os, "_._", 3) == 0){
|
||
|
|
name = "destructor";
|
||
|
|
namelen = strlen(name);
|
||
|
|
s = os+3;
|
||
|
|
}else{
|
||
|
|
/* the mangled part begins with the final __ */
|
||
|
|
if((s = strstr(os, "__")) == nil)
|
||
|
|
return os;
|
||
|
|
do{
|
||
|
|
t = s;
|
||
|
|
if(strchr("123456789FHQt", s[2]))
|
||
|
|
break;
|
||
|
|
}while((s = strstr(t+1, "__")) != nil);
|
||
|
|
|
||
|
|
s = t;
|
||
|
|
name = os;
|
||
|
|
namelen = t - os;
|
||
|
|
if(namelen == 0){
|
||
|
|
name = "constructor";
|
||
|
|
namelen = strlen(name);
|
||
|
|
}
|
||
|
|
s += 2;
|
||
|
|
}
|
||
|
|
|
||
|
|
switch(*s){
|
||
|
|
default:
|
||
|
|
return os;
|
||
|
|
|
||
|
|
case 'F': /* plain function */
|
||
|
|
s++;
|
||
|
|
break;
|
||
|
|
|
||
|
|
case 'Q':
|
||
|
|
case 'H':
|
||
|
|
case 't':
|
||
|
|
case '1': case '2': case '3': case '4':
|
||
|
|
case '5': case '6': case '7': case '8': case '9':
|
||
|
|
if(!gccname(&s, &p, &state)){
|
||
|
|
if(debug) fprint(2, "bad name: %s\n", os);
|
||
|
|
return os;
|
||
|
|
}
|
||
|
|
strcpy(p, "::");
|
||
|
|
p += 2;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
memmove(p, name, namelen);
|
||
|
|
p += namelen;
|
||
|
|
|
||
|
|
if(*s && *s != '_'){
|
||
|
|
/* the rest of the name is the argument types */
|
||
|
|
*p++ = '(';
|
||
|
|
while(*s != 0 && *s != '_' && gccname(&s, &p, &state))
|
||
|
|
*p++ = ',';
|
||
|
|
if(*(p-1) == ',')
|
||
|
|
p--;
|
||
|
|
*p++ = ')';
|
||
|
|
}
|
||
|
|
|
||
|
|
if(*s == '_'){
|
||
|
|
/* the remainder is the type of the return value */
|
||
|
|
}
|
||
|
|
|
||
|
|
*p = 0;
|
||
|
|
return buf;
|
||
|
|
}
|
||
|
|
|
||
|
|
static Chartab typetab[] =
|
||
|
|
{
|
||
|
|
'b', "bool",
|
||
|
|
'c', "char",
|
||
|
|
'd', "double",
|
||
|
|
'i', "int",
|
||
|
|
'l', "long",
|
||
|
|
'v', "void",
|
||
|
|
0, 0
|
||
|
|
};
|
||
|
|
|
||
|
|
static int
|
||
|
|
gccnumber(char **ps, int *pn)
|
||
|
|
{
|
||
|
|
char *s;
|
||
|
|
int n;
|
||
|
|
|
||
|
|
s = *ps;
|
||
|
|
if(!isdigit((uchar)*s))
|
||
|
|
return 0;
|
||
|
|
n = strtol(s, &s, 10);
|
||
|
|
if(*s == '_')
|
||
|
|
s++;
|
||
|
|
*ps = s;
|
||
|
|
*pn = n;
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
* 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, m, val;
|
||
|
|
char c, *os, *s, *t, *p;
|
||
|
|
|
||
|
|
s = *ps;
|
||
|
|
os = s;
|
||
|
|
p = *pp;
|
||
|
|
|
||
|
|
/* print("\tgccname: %s\n", s); */
|
||
|
|
|
||
|
|
#if 0
|
||
|
|
/* 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;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
/* basic types */
|
||
|
|
if((t = chartabsearch(typetab, *s)) != nil){
|
||
|
|
s++;
|
||
|
|
strcpy(p, t);
|
||
|
|
p += strlen(t);
|
||
|
|
goto suffix;
|
||
|
|
}
|
||
|
|
|
||
|
|
switch(*s){
|
||
|
|
default:
|
||
|
|
bad:
|
||
|
|
if(debug) fprint(2, "gccname: %s (%s)\n", os, 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': /* const */
|
||
|
|
s++;
|
||
|
|
strcpy(p, "const ");
|
||
|
|
p += strlen(p);
|
||
|
|
if(!gccname(&s, &p, state))
|
||
|
|
return 0;
|
||
|
|
break;
|
||
|
|
|
||
|
|
case 'U': /* unsigned */
|
||
|
|
s++;
|
||
|
|
strcpy(p, "unsigned ");
|
||
|
|
p += strlen(p);
|
||
|
|
if(!gccname(&s, &p, state))
|
||
|
|
return 0;
|
||
|
|
break;
|
||
|
|
|
||
|
|
#if 0
|
||
|
|
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;
|
||
|
|
#endif
|
||
|
|
|
||
|
|
case 'N': /* repeated name/type */
|
||
|
|
case 'X':
|
||
|
|
c = *s++;
|
||
|
|
if(!isdigit((uchar)*s) || !isdigit((uchar)*(s+1)))
|
||
|
|
goto bad;
|
||
|
|
n = *s++ - '0';
|
||
|
|
m = *s++ - '0';
|
||
|
|
sprint(p, "%c%d/%d", c, n, m);
|
||
|
|
p += strlen(p);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case 'Q': /* hierarchical name */
|
||
|
|
s++;
|
||
|
|
if(!isdigit((uchar)*s))
|
||
|
|
goto bad;
|
||
|
|
n = *s++ - '0';
|
||
|
|
for(i=0; i<n; i++){
|
||
|
|
if(!gccname(&s, &p, state)){
|
||
|
|
if(debug) fprint(2, "bad name in hierarchy: %s in %s\n", s, os);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
if(i+1 < n){
|
||
|
|
strcpy(p, "::");
|
||
|
|
p += 2;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
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;
|
||
|
|
}
|
||
|
|
goto bad;
|
||
|
|
|
||
|
|
case 't': /* named template */
|
||
|
|
c = *s++;
|
||
|
|
if(!gccname(&s, &p, state))
|
||
|
|
return 0;
|
||
|
|
goto template;
|
||
|
|
case 'H': /* nameless template */
|
||
|
|
c = *s++;
|
||
|
|
template:
|
||
|
|
if(!gccnumber(&s, &n))
|
||
|
|
goto bad;
|
||
|
|
*p++ = '<';
|
||
|
|
for(i=0; i<n; i++){
|
||
|
|
val = 1;
|
||
|
|
if(*s == 'Z'){
|
||
|
|
val = 0;
|
||
|
|
s++;
|
||
|
|
}
|
||
|
|
if(!gccname(&s, &p, state))
|
||
|
|
goto bad;
|
||
|
|
if(val){
|
||
|
|
if(!gccnumber(&s, &m))
|
||
|
|
goto bad;
|
||
|
|
sprint(p, "=%d", m);
|
||
|
|
p += strlen(p);
|
||
|
|
}
|
||
|
|
if(i+1 < n)
|
||
|
|
*p++ = ',';
|
||
|
|
}
|
||
|
|
*p++ = '>';
|
||
|
|
if(c == 'H'){
|
||
|
|
if(*s != '_')
|
||
|
|
goto bad;
|
||
|
|
s++;
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
case 'T': /* previously-seen type??? e.g., T2 */
|
||
|
|
t = s;
|
||
|
|
for(s++; isdigit((uchar)*s); s++)
|
||
|
|
;
|
||
|
|
memmove(p, t, s-t);
|
||
|
|
p += s-t;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
suffix:
|
||
|
|
*ps = s;
|
||
|
|
*pp = p;
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|