tname mangling, process control - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 7d6f5677c1ce9bdce141dea16364478216d0f4cc
 (DIR) parent 689be541258e9e701a600d6bd2fc3e5241726867
 (HTM) Author: rsc <devnull@localhost>
       Date:   Mon, 28 Nov 2005 00:40:04 +0000
       
       name mangling, process control
       
       Diffstat:
         M src/libmach/Linux.c                 |      30 ++++++++++++++++++++----------
         A src/libmach/mangle.c                |      73 +++++++++++++++++++++++++++++++
         A src/libmach/manglegcc2.c            |     337 +++++++++++++++++++++++++++++++
         A src/libmach/manglegcc3.c            |     339 +++++++++++++++++++++++++++++++
         M src/libmach/mkfile                  |       3 +++
         M src/libmach/sym.c                   |       8 ++++++++
       
       6 files changed, 780 insertions(+), 10 deletions(-)
       ---
 (DIR) diff --git a/src/libmach/Linux.c b/src/libmach/Linux.c
       t@@ -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<nattached; i++)
                        if(attachedpids[i]==pid)
                                return 0;
       t@@ -243,7 +236,7 @@ ptraceregrw(Regs *regs, char *name, ulong *val, int isr)
                        *val = u;
                }else{
                        u = *val;
       -                if(ptrace(PTRACE_POKEUSER, pid, addr, &u) < 0)
       +                if(ptrace(PTRACE_POKEUSER, pid, addr, (void*)u) < 0)
                                goto ptraceerr;
                }
                return 0;
       t@@ -321,7 +314,6 @@ isstopped(int pid)
                36. processor
        */
        
       -
        int
        procnotes(int pid, char ***pnotes)
        {
       t@@ -386,7 +378,19 @@ procnotes(int pid, char ***pnotes)
        int
        ctlproc(int pid, char *msg)
        {
       -        int p, status;
       +        int i, p, status;
       +
       +        if(strcmp(msg, "attached") == 0){
       +                for(i=0; i<nattached; i++)
       +                        if(attachedpids[i]==pid)
       +                                return 0;
       +                if(nattached == nelem(attachedpids)){
       +                        werrstr("attached to too many processes");
       +                        return -1;
       +                }
       +                attachedpids[nattached++] = pid;
       +                return 0;
       +        }
        
                if(strcmp(msg, "hang") == 0){
                        if(pid == getpid())
       t@@ -411,6 +415,11 @@ ctlproc(int pid, char *msg)
                                return -1;
                        goto waitstop;
                }
       +        if(strcmp(msg, "step") == 0){
       +                if(ptrace(PTRACE_SINGLESTEP, pid, 0, 0) < 0)
       +                        return -1;
       +                goto waitstop;
       +        }
                if(strcmp(msg, "waitstop") == 0){
                waitstop:
                        if(isstopped(pid))
       t@@ -424,6 +433,7 @@ ctlproc(int pid, char *msg)
                                        }
                                        return -1;
                                }
       +//fprint(2, "got pid %d status %x\n", pid, status);
                                if(WIFEXITED(status) || WIFSTOPPED(status))
                                        return 0;
                        }
 (DIR) diff --git a/src/libmach/mangle.c b/src/libmach/mangle.c
       t@@ -0,0 +1,73 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include <mach.h>
       +
       +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<nelem(demanglers); i++){
       +                t = demanglers[i](s, buf);
       +                if(t != s)
       +                        break;
       +        }
       +        if(t == s || !strip)
       +                return t;
       +
       +        /* copy name without <> 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<argc; i++){
       +                print("%s\n", demangle(argv[i], 0));
       +                print("\t%s\n", demangle(argv[i], 1));
       +        }
       +        exits(nil);
       +}
       +#endif
 (DIR) diff --git a/src/libmach/manglegcc2.c b/src/libmach/manglegcc2.c
       t@@ -0,0 +1,337 @@
       +/*
       + * 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;
       +}
       +
 (DIR) diff --git a/src/libmach/manglegcc3.c b/src/libmach/manglegcc3.c
       t@@ -0,0 +1,339 @@
       +/*
       + * 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;
       +}
       +
 (DIR) diff --git a/src/libmach/mkfile b/src/libmach/mkfile
       t@@ -32,6 +32,9 @@ OFILES=\
                macho.$O\
                machocorepower.$O\
                machpower.$O\
       +        mangle.$O\
       +        manglegcc2.$O\
       +        manglegcc3.$O\
                map.$O\
                regs.$O\
                stabs.$O\
 (DIR) diff --git a/src/libmach/sym.c b/src/libmach/sym.c
       t@@ -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){
       t@@ -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;