commit 7d6f5677c1ce9bdce141dea16364478216d0f4cc from: rsc date: Mon Nov 28 00:40:04 2005 UTC name mangling, process control commit - 689be541258e9e701a600d6bd2fc3e5241726867 commit + 7d6f5677c1ce9bdce141dea16364478216d0f4cc blob - 530150d842175c5c99155a0b7e0956b6888acbe6 blob + bef03ba1bf916a87bf4747c98754fb541557ac3e --- src/libmach/Linux.c +++ src/libmach/Linux.c @@ -47,13 +47,6 @@ ptraceattach(int pid) { int i; - /* - if(nattached==1 && attachedpids[0] == pid) - goto already; - if(nattached) - detachproc(attachedpids[0]); - */ - for(i=0; i +#include +#include +#include + +static char *(*demanglers[])(char*, char*) = +{ + demanglegcc2, + demanglegcc3, +}; + +char* +demangle(char *s, char *buf, int strip) +{ + char *t; + char *r, *w; + int i, nangle, nparen; + + for(i=0; i and () - not right, but convenient */ + /* convert :: to $ - not right, but convenient (should fix acid) */ + nangle = 0; + nparen = 0; + for(r=w=buf; *r; r++){ + switch(*r){ + case '<': + nangle++; + break; + case '>': + nangle--; + break; + case '(': + nparen++; + break; + case ')': + nparen--; + break; + default: + if(nparen == 0 && nangle == 0){ + if(*r == ':' && *(r+1) == ':'){ + *w++ = '$'; + r++; + } + else + *w++ = *r; + } + break; + } + } + *w = 0; + return buf; +} + +#ifdef TEST +void +main(int argc, char **argv) +{ + int i; + + for(i=1; i +#include +#include +#include + +#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 +#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; +} + blob - 4730fdc19773ffa887e62e39b600894352ccec1b blob + c3d05191311a6bf1897a87bd3da31c9a984ac0dd --- src/libmach/sym.c +++ src/libmach/sym.c @@ -491,6 +491,8 @@ symclose(Fhdr *hdr) Symbol* _addsym(Fhdr *fp, Symbol *sym) { + char *t; + static char buf[65536]; Symbol *s; if(fp->nsym%128 == 0){ @@ -502,6 +504,12 @@ _addsym(Fhdr *fp, Symbol *sym) if(machdebug) fprint(2, "sym %s %c %L\n", sym->name, sym->type, sym->loc); sym->fhdr = fp; + t = demangle(sym->name, buf, 1); + if(t != sym->name){ + sym->name = strdup(t); + if(sym->name == nil) + return nil; + } s = &fp->sym[fp->nsym++]; *s = *sym; return s;