aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libmach/Linux.c30
-rw-r--r--src/libmach/mangle.c73
-rw-r--r--src/libmach/manglegcc2.c337
-rw-r--r--src/libmach/manglegcc3.c339
-rw-r--r--src/libmach/mkfile3
-rw-r--r--src/libmach/sym.c8
6 files changed, 780 insertions, 10 deletions
diff --git a/src/libmach/Linux.c b/src/libmach/Linux.c
index 530150d8..bef03ba1 100644
--- a/src/libmach/Linux.c
+++ b/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<nattached; i++)
if(attachedpids[i]==pid)
return 0;
@@ -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;
@@ -321,7 +314,6 @@ isstopped(int pid)
36. processor
*/
-
int
procnotes(int pid, char ***pnotes)
{
@@ -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())
@@ -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))
@@ -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;
}
diff --git a/src/libmach/mangle.c b/src/libmach/mangle.c
new file mode 100644
index 00000000..e9030252
--- /dev/null
+++ b/src/libmach/mangle.c
@@ -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
diff --git a/src/libmach/manglegcc2.c b/src/libmach/manglegcc2.c
new file mode 100644
index 00000000..035ffd35
--- /dev/null
+++ b/src/libmach/manglegcc2.c
@@ -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;
+}
+
diff --git a/src/libmach/manglegcc3.c b/src/libmach/manglegcc3.c
new file mode 100644
index 00000000..eca26eb1
--- /dev/null
+++ b/src/libmach/manglegcc3.c
@@ -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;
+}
+
diff --git a/src/libmach/mkfile b/src/libmach/mkfile
index a6d6507e..d66f3f35 100644
--- a/src/libmach/mkfile
+++ b/src/libmach/mkfile
@@ -32,6 +32,9 @@ OFILES=\
macho.$O\
machocorepower.$O\
machpower.$O\
+ mangle.$O\
+ manglegcc2.$O\
+ manglegcc3.$O\
map.$O\
regs.$O\
stabs.$O\
diff --git a/src/libmach/sym.c b/src/libmach/sym.c
index 4730fdc1..c3d05191 100644
--- a/src/libmach/sym.c
+++ b/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;