more mangler
diff --git a/src/libmach/mangle.c b/src/libmach/mangle.c
index e903025..e2d827c 100644
--- a/src/libmach/mangle.c
+++ b/src/libmach/mangle.c
@@ -43,14 +43,8 @@
 			nparen--;
 			break;
 		default:
-			if(nparen == 0 && nangle == 0){
-				if(*r == ':' && *(r+1) == ':'){
-					*w++ = '$';
-					r++;
-				}
-				else
-					*w++ = *r;
-			}
+			if(nparen == 0 && nangle == 0)
+				*w++ = *r;
 			break;
 		}
 	}
diff --git a/src/libmach/manglegcc2.c b/src/libmach/manglegcc2.c
index 59f4d46..1fae4eb 100644
--- a/src/libmach/manglegcc2.c
+++ b/src/libmach/manglegcc2.c
@@ -7,6 +7,7 @@
  *
  * Not implemented:
  *	unicode mangling
+ *	rename operator functions
  */
 /*
 RULES TO ADD:
@@ -178,7 +179,9 @@
 		if(name == constructor || name == destructor){
 			*p = 0;
 			t = strrchr(buf, ':');
-			if(t == nil)
+			if(t)
+				t++;
+			else
 				t = buf;
 		}
 		strcpy(p, "::");
@@ -190,6 +193,8 @@
 			name = t;
 		}
 	}
+	if(p >= buf+2 && memcmp(p-2, "::", 2) == 0 && *(p-3) == ')')
+		p -= 2;
 	memmove(p, name, namelen);
 	p += namelen;
 	
@@ -444,6 +449,8 @@
 		break;
 
 	case 'H':	/* template specialization */
+		if(memcmp(s-2, "__", 2) != 0)
+			fprint(2, "wow: %s\n", s-2);
 		t = s;
 		s++;
 		if(!gccnumber(&s, &n, 0))
@@ -474,14 +481,44 @@
 			return 0;
 		}
 		s++;
-		p1 = p;
-		/* name */
-		if(!gccname(&s, &p))
-			return 0;
-		/* XXX 
-__adjust_heap__H3ZPt4pair2Zt12basic_string3ZcZt11char_traits1ZcZt9allocator1ZcZt12basic_string3ZcZt11char_traits1ZcZt9allocator1ZcZiZt4pair2Zt12basic_string3ZcZt11char_traits1ZcZt9allocator1ZcZt12basic_string3ZcZt11char_traits1ZcZt9allocator1Zc_X01X11X11X21_v
-		*/
-		/* XXX swap p0, p1, p - maybe defer to main */
+
+		/*
+		 * Can't seem to tell difference between a qualifying name
+		 * and arguments.  Not sure which is which.  It appears that if
+		 * you get a name, use it, otherwise look for types.
+		 * The G type qualifier appears to have no effect other than
+		 * turning an ambiguous name into a definite type.
+		 *
+		 *	SetFlag__H1Zb_P15FlagSettingMode_v
+		 *	=>	void SetFlag<bool>(FlagSettingMode *)
+		 *	SetFlag__H1Zb_15FlagSettingMode_v
+		 *	=>	void FlagSettingMode::SetFlag<bool>()
+		 *	SetFlag__H1Zb_G15FlagSettingMode_v
+		 *	=>	void SetFlag<bool>(FlagSettingMode)
+		 */
+		if(strchr("ACFGPRSUVX", *s)){
+			/* args */
+			t = s;
+			p1 = p;
+			*p++ = '(';
+			while(*s != '_'){
+				if(*s == 0 || !gccname(&s, &p)){
+					werrstr("bad H args: %s", t);
+					return 0;
+				}
+			}
+			*p++ = ')';
+			s++;
+		}else{
+			p1 = p;
+			/* name */
+			if(!gccname(&s, &p))
+				return 0;
+		}
+		/*
+		 * Need to do some rearrangement of <> () and names here.
+		 * Doesn't matter since we strip out the <> and () anyway.
+		 */
 		break;
 
 	case 'M':	/* M1S: pointer to member */
diff --git a/src/libmach/sym.c b/src/libmach/sym.c
index c3d0519..a5b057d 100644
--- a/src/libmach/sym.c
+++ b/src/libmach/sym.c
@@ -187,6 +187,40 @@
 	return nil;
 }
 
+Symbol*
+flookupsymx(Fhdr *fhdr, char *name)
+{
+	Symbol **a, *t;
+	uint n, m;
+	int i;
+
+	a = fhdr->byxname;
+	n = fhdr->nsym;
+	if(a == nil)
+		return nil;
+
+	while(n > 0){
+		m = n/2;
+		t = a[m];
+		i = strcmp(name, t->xname);
+		if(i < 0)
+			n = m;
+		else if(i > 0){
+			n -= m+1;
+			a += m+1;
+		}else{
+			/* found! */
+			m += a - fhdr->byxname;
+			a = fhdr->byxname;
+			assert(strcmp(name, a[m]->xname) == 0);
+			while(m > 0 && strcmp(name, a[m-1]->xname) == 0)
+				m--;
+			return a[m];
+		}
+	}
+	return nil;
+}
+
 int
 lookupsym(char *fn, char *var, Symbol *s)
 {
@@ -199,10 +233,12 @@
 		return -1;
 	t = nil;
 	for(p=fhdrlist; p; p=p->next)
-		if((t=flookupsym(p, nam)) != nil){
+		if((t=flookupsym(p, nam)) != nil
+		|| (t=flookupsymx(p, nam)) != nil){
 			relocsym(&s1, t, p->base);
 			break;
 		}
+
 	if(t == nil)
 		goto err;
 	if(fn && var)
@@ -423,6 +459,27 @@
 
 /* name, location, class */
 static int
+byxnamecmp(const void *va, const void *vb)
+{
+	int i;
+	Symbol *a, *b;
+
+	a = *(Symbol**)va;
+	b = *(Symbol**)vb;
+	i = strcmp(a->xname, b->xname);
+	if(i != 0)
+		return i;
+	i = strcmp(a->name, b->name);
+	if(i != 0)
+		return i;
+	i = loccmp(&a->loc, &b->loc);
+	if(i != 0)
+		return i;
+	return a->class - b->class;
+}
+
+/* name, location, class */
+static int
 bynamecmp(const void *va, const void *vb)
 {
 	int i;
@@ -466,12 +523,21 @@
 
 	hdr->byname = malloc(hdr->nsym*sizeof(hdr->byname[0]));
 	if(hdr->byname == nil){
-		fprint(2, "could not allocate table to sort by location\n");
+		fprint(2, "could not allocate table to sort by name\n");
 	}else{
 		for(i=0; i<hdr->nsym; i++)
 			hdr->byname[i] = &hdr->sym[i];
 		qsort(hdr->byname, hdr->nsym, sizeof(hdr->byname[0]), bynamecmp);
 	}
+	
+	hdr->byxname = malloc(hdr->nsym*sizeof(hdr->byxname[0]));
+	if(hdr->byxname == nil){
+		fprint(2, "could not allocate table to sort by xname\n");
+	}else{
+		for(i=0; i<hdr->nsym; i++)
+			hdr->byxname[i] = &hdr->sym[i];
+		qsort(hdr->byxname, hdr->nsym, sizeof(hdr->byxname[0]), byxnamecmp);
+	}
 	return 0;
 }
 
@@ -506,10 +572,11 @@
 	sym->fhdr = fp;
 	t = demangle(sym->name, buf, 1);
 	if(t != sym->name){
-		sym->name = strdup(t);
-		if(sym->name == nil)
+		t = strdup(t);
+		if(t == nil)
 			return nil;
 	}
+	sym->xname = t;
 	s = &fp->sym[fp->nsym++];
 	*s = *sym;
 	return s;