1 /*
2  * gcc3 name demangler.
3  */
4 #include <u.h>
5 #include <libc.h>
6 #include <bio.h>
7 #include <mach.h>
8 
9 typedef struct Chartab Chartab;
10 struct Chartab
11 {
12 	char c;
13 	char *s;
14 };
15 
16 static char*
chartabsearch(Chartab * ct,int c)17 chartabsearch(Chartab *ct, int c)
18 {
19 	for(; ct->c; ct++)
20 		if(ct->c == c)
21 			return ct->s;
22 	return nil;
23 }
24 
25 typedef struct Gccstate Gccstate;
26 struct Gccstate
27 {
28 	char *name[128];
29 	int nname;
30 };
31 static int gccname(char**, char**, Gccstate*);
32 char*
demanglegcc3(char * s,char * buf)33 demanglegcc3(char *s, char *buf)
34 {
35 	char *p, *os;
36 	Gccstate state;
37 
38 	state.nname = 0;
39 	os = s;
40 	/* mangled names always start with _Z */
41 	if(s[0] != '_' || s[1] != 'Z')
42 		return s;
43 	s += 2;
44 
45 	p = buf;
46 	if(!gccname(&s, &p, &state)){
47 		if(strchr(os, '@') == nil)
48 			fprint(2, "demangle: %s\n");
49 		return os;
50 	}
51 	if(*s){
52 		/* the rest of the name is the argument types */
53 		*p++ = '(';
54 		while(*s != 0 && gccname(&s, &p, &state))
55 			*p++ = ',';
56 		if(*(p-1) == ',')
57 			p--;
58 		*p++ = ')';
59 	}
60 	*p = 0;
61 	return buf;
62 }
63 
64 static Chartab stdnames[] =
65 {
66 	'a',	"std::allocator",
67 	'b',	"std::basic_string",
68 	'd',	"std::iostream",
69 	'i',	"std::istream",
70 	'o',	"std::ostream",
71 	's',	"std::string",
72 	0, 0
73 };
74 
75 static Chartab typetab[] =
76 {
77 	'b',	"bool",
78 	'c',	"char",
79 	'd',	"double",
80 	'i',	"int",
81 	'j',	"uint",
82 	'v',	"void",
83 	0, 0
84 };
85 
86 static struct {
87 	char *shrt;
88 	char *actual;
89 	char *lng;
90 } operators[] =
91 {
92 	"aN",	"&=",		"andeq",
93 	"aS",	"=",		"assign",
94 	"aa",	"&&",		"andand",
95 	"ad",	"&",		"and",
96 	"an",	"&",		"and",
97 	"cl",	"()",		"construct",
98 	"cm",	",",		"comma",
99 	"co",	"~",		"twiddle",
100 	"dV",	"/=",		"diveq",
101 	"da",	"delete[]",	"deletearray",
102 	"de",	"*",		"star",
103 	"dl",	"delete",	"delete",
104 	"dv",	"/",		"div",
105 	"eO",	"^=",		"xoreq",
106 	"eo",	"^",		"xor",
107 	"eq",	"==",		"eq",
108 	"ge",	">=",		"geq",
109 	"gt",	">",		"gt",
110 	"ix",	"[]",		"index",
111 	"IS",	"<<=",		"lsheq",
112 	"le",	"<=",		"leq",
113 	"ls",	"<<",		"lsh",
114 	"lt",	"<",		"lt",
115 	"ml",	"-=",		"subeq",
116 	"mL",	"*=",		"muleq",
117 	"mi",	"-",		"sub",
118 	"mI",	"*",		"mul",
119 	"mm",	"--",		"dec",
120 	"na",	"new[]",	"newarray",
121 	"ne",	"!=",		"neq",
122 	"ng",	"-",		"neg",
123 	"nt",	"!",		"not",
124 	"nw",	"new",		"new",
125 	"oR",	"|=",		"oreq",
126 	"oo",	"||",		"oror",
127 	"or",	"|",		"or",
128 	"pL",	"+=",		"addeq",
129 	"pl",	"+",		"add",
130 	"pm",	"->*",		"pointstoderef",
131 	"pp",	"++",		"inc",
132 	"ps",	"+",		"pos",
133 	"pt",	"->",		"pointsto",
134 	"qu",	"?",		"question",
135 	"rM",	"%=",		"modeq",
136 	"rS",	">>=",		"rsheq",
137 	"rm",	"%",		"mod",
138 	"rs",	">>",		"rsh",
139 	"st",	"sizeof",	"sizeoftype",
140 	"sz",	"sizeof",	"sizeofexpr",
141 
142 	0,0,0
143 };
144 
145 /*
146  * Pick apart the next mangled name section.
147  * Names and types are treated as the same.
148  * Let's see how far we can go before that becomes a problem.
149  */
150 static int
gccname(char ** ps,char ** pp,Gccstate * state)151 gccname(char **ps, char **pp, Gccstate *state)
152 {
153 	int i, n;
154 	char *os, *s, *t, *p;
155 	Gccstate nstate;
156 
157 	s = *ps;
158 	os = s;
159 	p = *pp;
160 
161 /*	print("\tgccname: %s\n", s); */
162 
163 	/* overloaded operators */
164 	for(i=0; operators[i].shrt; i++){
165 		if(memcmp(operators[i].shrt, s, 2) == 0){
166 			strcpy(p, "operator$");
167 			strcat(p, operators[i].lng);
168 			p += strlen(p);
169 			s += 2;
170 			goto suffix;
171 		}
172 	}
173 
174 	/* basic types */
175 	if((t = chartabsearch(typetab, *s)) != nil){
176 		s++;
177 		strcpy(p, t);
178 		p += strlen(t);
179 		goto suffix;
180 	}
181 
182 	switch(*s){
183 	default:
184 	bad:
185 		fprint(2, "bad name: %s\n", s);
186 		return 0;
187 
188 	case '1': case '2': case '3': case '4':	/* name length */
189 	case '5': case '6': case '7': case '8': case '9':
190 		n = strtol(s, &s, 10);
191 		memmove(p, s, n);
192 		p += n;
193 		s += n;
194 		break;
195 
196 	case 'C':	/* C1: constructor? */
197 		strtol(s+1, &s, 10);
198 		strcpy(p, "constructor");
199 		p += strlen(p);
200 		break;
201 
202 	case 'D':	/* D1: destructor? */
203 		strtol(s+1, &s, 10);
204 		strcpy(p, "destructor");
205 		p += strlen(p);
206 		break;
207 
208 	case 'K':	/* const */
209 		s++;
210 		strcpy(p, "const ");
211 		p += strlen(p);
212 		if(!gccname(&s, &p, state))
213 			return 0;
214 		break;
215 
216 	case 'L':	/* default value */
217 		t = s;
218 		s++;
219 		if(!gccname(&s, &p, state))
220 			return 0;
221 		if(!isdigit((uchar)*s)){
222 			fprint(2, "bad value: %s\n", t);
223 			return 0;
224 		}
225 		n = strtol(s, &s, 10);
226 		if(*s != 'E'){
227 			fprint(2, "bad value2: %s\n", t);
228 			return 0;
229 		}
230 		sprint(p, "=%d", n);
231 		p += strlen(p);
232 		s++;
233 		break;
234 
235 	case 'N':	/* hierarchical name */
236 		s++;
237 		while(*s != 'E'){
238 			if(!gccname(&s, &p, state)){
239 				fprint(2, "bad name in hierarchy: %s in %s\n", s, os);
240 				return 0;
241 			}
242 			strcpy(p, "::");
243 			p += 2;
244 		}
245 		p -= 2;
246 		s++;
247 		break;
248 
249 	case 'P':	/* pointer to */
250 		s++;
251 		if(!gccname(&s, &p, state))
252 			return 0;
253 		*p++ = '*';
254 		break;
255 
256 	case 'R':	/* reference to */
257 		s++;
258 		if(!gccname(&s, &p, state))
259 			return 0;
260 		*p++ = '&';
261 		break;
262 
263 	case 'S':	/* standard or previously-seen name */
264 		s++;
265 		if('0' <= *s && *s <= '9'){
266 			/* previously seen */
267 			t = s-1;
268 			n = strtol(s, &s, 10);
269 			if(*s != '_'){
270 				fprint(2, "bad S: %s\n", t);
271 				return 0;
272 			}
273 			s++;
274 			sprint(p, "S%d_", n);
275 			p += strlen(p);
276 			break;
277 		}
278 		/* SA_ ??? */
279 		if(*s == 'A' && *(s+1) == '_'){
280 			strcpy(p, "SA_");
281 			p += 3;
282 			s += 2;
283 			break;
284 		}
285 
286 		/* standard name */
287 		if(*s == 't'){
288 			strcpy(p, "std::");
289 			p += 5;
290 			s++;
291 			if(!gccname(&s, &p, state))
292 				return 0;
293 		}else if((t = chartabsearch(stdnames, *s)) != nil){
294 			strcpy(p, t);
295 			p += strlen(p);
296 			s++;
297 		}else{
298 			strcpy(p, "std::");
299 			p += 5;
300 			*p++ = *s++;
301 		}
302 		break;
303 
304 	case 'T':	/* previously-seen type??? T0_ also T_*/
305 		t = s;
306 		for(; *s != '_'; s++){
307 			if(*s == 0){
308 				s = t;
309 				goto bad;
310 			}
311 		}
312 		s++;
313 		memmove(p, t, s-t);
314 		p += s-t;
315 		break;
316 	}
317 
318 suffix:
319 	if(*s == 'I'){
320 		/* template suffix */
321 		nstate.nname = 0;
322 		*p++ = '<';
323 		s++;
324 		while(*s != 'E'){
325 			if(!gccname(&s, &p, &nstate)){
326 				fprint(2, "bad name in template: %s\n", s);
327 				return 0;
328 			}
329 			*p++ = ',';
330 		}
331 		*(p-1) = '>';
332 		s++;
333 	}
334 
335 	*ps = s;
336 	*pp = p;
337 	return 1;
338 }
339