Commit Diff


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<nattached; i++)
 		if(attachedpids[i]==pid)
 			return 0;
@@ -243,7 +236,7 @@ ptraceregrw(Regs *regs, char *name, ulong *val, int is
 		*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;
 		}
blob - /dev/null
blob + e9030252edcd69b7e9ea693b917146343452c4a4 (mode 644)
--- /dev/null
+++ 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
blob - a6d6507e2ca4c6e73e26ebecbd6141558485793e
blob + d66f3f35a5dfa836e77b1c41c7c5c3ab3c9965ba
--- src/libmach/mkfile
+++ 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\
blob - /dev/null
blob + 035ffd357654a05f02561f5264eeb7915ff25373 (mode 644)
--- /dev/null
+++ 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;
+}
+
blob - /dev/null
blob + eca26eb1b9af3aee17c5d10acfc2e45294649cac (mode 644)
--- /dev/null
+++ 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;
+}
+
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;