1 /*
2 Copyright (c) 2009-2016 mingw-w64 project
3
4 Contributing authors: Kai Tietz, Jonathan Yong
5
6 Permission is hereby granted, free of charge, to any person obtaining a
7 copy of this software and associated documentation files (the "Software"),
8 to deal in the Software without restriction, including without limitation
9 the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 and/or sell copies of the Software, and to permit persons to whom the
11 Software is furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 DEALINGS IN THE SOFTWARE.
23 */
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <malloc.h>
27 #include <string.h>
28 #include <inttypes.h>
29 #include <stdint.h>
30
31 #include "m_token.h"
32 #include "m_ms.h"
33
34 #ifdef __MSVCRT__
35 #define MY_LL "I64"
36 #else
37 #define MY_LL "ll"
38 #endif
39
40 static char *mt_strcat (char *h, const char *add);
41
42
43 libmangle_gc_context_t *
libmangle_generate_gc(void)44 libmangle_generate_gc (void)
45 {
46 libmangle_gc_context_t *h = (libmangle_gc_context_t *) malloc (sizeof (libmangle_gc_context_t));
47 if (h)
48 memset (h, 0, sizeof (libmangle_gc_context_t));
49 return h;
50 }
51
52 static void *
alloc_gc(libmangle_gc_context_t * gc,size_t size)53 alloc_gc (libmangle_gc_context_t *gc, size_t size)
54 {
55 sGcElem *n = (sGcElem *) malloc (size + sizeof (sGcElem));
56 if (!n)
57 {
58 fprintf (stderr, "error: Run out of memory for %" MY_LL "x byte(s)\n",
59 (unsigned long long) size);
60 abort ();
61 }
62 memset (n, 0, size + sizeof (sGcElem));
63 n->length = size;
64 if (gc->head == NULL)
65 gc->head = n;
66 else
67 gc->tail->chain = n;
68 gc->tail = n;
69 return & n->dta[0];
70 }
71
72 void
libmangle_release_gc(libmangle_gc_context_t * gc)73 libmangle_release_gc (libmangle_gc_context_t *gc)
74 {
75 sGcElem *n;
76 if (!gc)
77 return;
78 while ((n = gc->head) != NULL)
79 {
80 gc->head = n->chain;
81 free (n);
82 }
83 gc->tail = NULL;
84 free (gc);
85 }
86
87 static void
free_gc(libmangle_gc_context_t * gc,const void * p)88 free_gc (libmangle_gc_context_t *gc, const void *p)
89 {
90 sGcElem *n, *l = NULL;
91
92 if (!gc || !p)
93 return;
94 n = gc->head;
95 while (n != NULL)
96 {
97 const void *ptr = &n->dta[0];
98 if (ptr == p)
99 {
100 if (!l)
101 gc->head = n->chain;
102 else
103 l->chain = n->chain;
104 if (gc->tail == n)
105 gc->tail = l;
106 free (n);
107 return;
108 }
109 l = n;
110 n = n->chain;
111 }
112 }
113
114 uMToken *
gen_tok(libmangle_gc_context_t * gc,enum eMToken kind,enum eMSToken subkind,size_t addend)115 gen_tok (libmangle_gc_context_t *gc, enum eMToken kind, enum eMSToken subkind, size_t addend)
116 {
117 uMToken *ret;
118 switch (kind)
119 {
120 case eMToken_value:
121 addend += sizeof (sMToken_value);
122 break;
123 case eMToken_name:
124 addend += sizeof (sMToken_name);
125 break;
126 case eMToken_dim:
127 addend += sizeof (sMToken_dim);
128 break;
129 case eMToken_unary:
130 addend += sizeof (sMToken_Unary);
131 break;
132 case eMToken_binary:
133 addend += sizeof (sMToken_binary);
134 break;
135 default:
136 abort ();
137 }
138 addend += (addend + 15) & ~15;
139 ret = (uMToken *) alloc_gc (gc, addend);
140 if (!ret)
141 abort ();
142
143 MTOKEN_KIND (ret) = kind;
144 MTOKEN_SUBKIND (ret) = subkind;
145
146 return ret;
147 }
148
149 static void
dump_tok1(FILE * fp,uMToken * p)150 dump_tok1 (FILE *fp, uMToken *p)
151 {
152 if (!p)
153 return;
154 switch (MTOKEN_KIND (p))
155 {
156 case eMToken_value:
157 fprintf (fp, "'value:%d: ", MTOKEN_SUBKIND (p));
158 if (MTOKEN_VALUE_SIGNED (p))
159 {
160 fprintf(fp, "%"MY_LL "dLL", MTOKEN_VALUE (p));
161 }
162 else
163 {
164 fprintf(fp, "0x%"MY_LL"xULL", MTOKEN_VALUE (p));
165 }
166 fprintf (fp,"'");
167 break;
168 case eMToken_name:
169 fprintf (fp,"'name:%d %s'", MTOKEN_SUBKIND (p), MTOKEN_NAME (p));
170 break;
171 case eMToken_dim:
172 fprintf (fp,"'dim:%d %s", MTOKEN_SUBKIND (p), MTOKEN_DIM_NEGATE (p) ? "-" : "");
173 libmangle_dump_tok (fp, MTOKEN_DIM_VALUE (p));
174 if (MTOKEN_DIM_NTTP (p))
175 {
176 fprintf (fp," ");
177 libmangle_dump_tok (fp, MTOKEN_DIM_NTTP (p));
178 }
179 fprintf (fp,"'");
180 break;
181 case eMToken_unary:
182 fprintf (fp,"'unary:%d ", MTOKEN_SUBKIND (p));
183 libmangle_dump_tok (fp, MTOKEN_UNARY (p));
184 fprintf (fp, "'");
185 break;
186 case eMToken_binary:
187 fprintf (fp,"'binary:%d ", MTOKEN_SUBKIND (p));
188 libmangle_dump_tok (fp, MTOKEN_BINARY_LEFT (p));
189 fprintf (fp," ");
190 libmangle_dump_tok (fp, MTOKEN_BINARY_RIGHT (p));
191 fprintf (fp, "'");
192 break;
193 default:
194 fprintf (fp,"'kind(%d/%d):", MTOKEN_KIND (p), MTOKEN_SUBKIND(p));
195 abort ();
196 }
197 }
198
199 void
libmangle_dump_tok(FILE * fp,uMToken * p)200 libmangle_dump_tok (FILE *fp, uMToken *p)
201 {
202 if (!p)
203 return;
204 fprintf (fp, "'[");
205
206 while (p)
207 {
208 dump_tok1 (fp, p);
209 p = MTOKEN_CHAIN (p);
210 if (p) fprintf (fp,",");
211 }
212 fprintf (fp,"]'");
213 }
214
215 uMToken *
chain_tok(uMToken * l,uMToken * add)216 chain_tok (uMToken *l, uMToken *add)
217 {
218 uMToken *p = l;
219 if (!l)
220 return add;
221 if (!add)
222 return l;
223 while (MTOKEN_CHAIN (p))
224 p = MTOKEN_CHAIN (p);
225 MTOKEN_CHAIN (p) = add;
226
227 return l;
228 }
229
230 uMToken *
gen_value(libmangle_gc_context_t * gc,enum eMSToken skind,uint64_t val,int is_signed,int size)231 gen_value (libmangle_gc_context_t *gc, enum eMSToken skind, uint64_t val, int is_signed, int size)
232 {
233 uMToken *ret = gen_tok (gc, eMToken_value, skind, 0);
234 MTOKEN_VALUE (ret) = val;
235 MTOKEN_VALUE_SIGNED (ret) = is_signed;
236 MTOKEN_VALUE_SIZE (ret) = size;
237
238 return ret;
239 }
240
241 uMToken *
gen_name(libmangle_gc_context_t * gc,enum eMSToken skind,const char * name)242 gen_name (libmangle_gc_context_t *gc, enum eMSToken skind, const char *name)
243 {
244 uMToken *ret;
245
246 if (!name)
247 name = "";
248 ret = gen_tok (gc, eMToken_name, skind, strlen (name) + 1);
249 strcpy (MTOKEN_NAME (ret), name);
250
251 return ret;
252 }
253
254 uMToken *
gen_dim(libmangle_gc_context_t * gc,enum eMSToken skind,uint64_t val,const char * non_tt_param,int fSigned,int fNegate)255 gen_dim (libmangle_gc_context_t *gc, enum eMSToken skind, uint64_t val, const char *non_tt_param, int fSigned, int fNegate)
256 {
257 uMToken *ret = gen_tok (gc, eMToken_dim, skind, 0);
258
259 MTOKEN_DIM_VALUE(ret) = gen_value (gc, eMST_val, val, fSigned, 8);
260 if (non_tt_param)
261 MTOKEN_DIM_NTTP(ret) = gen_name (gc, eMST_nttp, non_tt_param);
262 MTOKEN_DIM_NEGATE(ret) = fNegate;
263 return ret;
264 }
265
266 uMToken *
gen_unary(libmangle_gc_context_t * gc,enum eMSToken skind,uMToken * un)267 gen_unary (libmangle_gc_context_t *gc, enum eMSToken skind, uMToken *un)
268 {
269 uMToken *ret = gen_tok (gc, eMToken_unary, skind, 0);
270 MTOKEN_UNARY (ret) = un;
271 return ret;
272 }
273
274 uMToken *
gen_binary(libmangle_gc_context_t * gc,enum eMSToken skind,uMToken * l,uMToken * r)275 gen_binary (libmangle_gc_context_t *gc, enum eMSToken skind, uMToken *l, uMToken *r)
276 {
277 uMToken *ret = gen_tok (gc, eMToken_binary, skind, 0);
278 MTOKEN_BINARY_LEFT (ret) = l;
279 MTOKEN_BINARY_RIGHT (ret) = r;
280 return ret;
281 }
282
283 static char *
mt_strcat(char * h,const char * add)284 mt_strcat (char *h, const char *add)
285 {
286 char *ret;
287 if (!add || *add == 0)
288 return h;
289 if (!h)
290 ret = strdup (add);
291 else
292 {
293 ret = (char *) malloc (strlen (h) + strlen (add) + 1);
294 if (ret)
295 {
296 strcpy (ret, h);
297 strcat (ret, add);
298 }
299 free (h);
300 }
301 if (!ret)
302 {
303 fprintf (stderr, " *** Run out of memory.\n");
304 abort ();
305 }
306 return ret;
307 }
308
309 static char *
sprint_decl1(char * txt,uMToken * r)310 sprint_decl1 (char *txt, uMToken *r)
311 {
312 while (r != NULL)
313 {
314 switch (MTOKEN_KIND (r))
315 {
316 case eMToken_name:
317 switch (MTOKEN_SUBKIND (r))
318 {
319 default:
320 case eMST_unmangled: case eMST_name:
321 case eMST_vftable: case eMST_vbtable: case eMST_vcall:
322 case eMST_nttp: case eMST_rtti:
323 case eMST_cv: case eMST_type: case eMST_opname:
324 txt = mt_strcat (txt, MTOKEN_NAME (r));
325 break;
326 case eMST_colon:
327 txt = mt_strcat (txt, MTOKEN_NAME (r));
328 txt = mt_strcat (txt, ":");
329 break;
330 }
331 break;
332 case eMToken_value:
333 switch (MTOKEN_SUBKIND (r))
334 {
335 default:
336 break;
337 case eMST_gcarray:
338 txt = mt_strcat (txt, "__gc[");
339 case eMST_val:
340 if (! MTOKEN_VALUE_SIGNED (r))
341 {
342 char s[128];
343 if ((MTOKEN_VALUE (r) >> 32) != 0)
344 sprintf (s, "0x%lx%08lx", (unsigned long) (MTOKEN_VALUE (r) >> 32), (unsigned long) MTOKEN_VALUE (r));
345 else
346 sprintf (s,"0x%lx", (unsigned long) MTOKEN_VALUE (r));
347 strcat (s, "U");
348 txt = mt_strcat (txt, s);
349 }
350 else
351 {
352 char s[128];
353 sprintf (s,"%"MY_LL"d", (long long) MTOKEN_VALUE (r));
354 txt = mt_strcat (txt, s);
355 }
356 if (MTOKEN_VALUE_SIZE (r) == 8)
357 txt = mt_strcat (txt, "LL");
358 else if (MTOKEN_VALUE_SIZE (r) == 4)
359 txt = mt_strcat (txt, "L");
360 if (MTOKEN_SUBKIND (r) == eMST_gcarray)
361 txt = mt_strcat (txt, "]");
362 break;
363 }
364 break;
365 case eMToken_dim:
366 switch (MTOKEN_SUBKIND (r))
367 {
368 default:
369 /* FALL THROUGH */
370 case eMST_dim:
371 if (MTOKEN_DIM_NEGATE (r))
372 txt = mt_strcat (txt, "-");
373 if (MTOKEN_DIM_NTTP (r))
374 txt = sprint_decl1 (txt, MTOKEN_DIM_NTTP (r));
375 if (MTOKEN_DIM_VALUE (r))
376 txt = sprint_decl1 (txt, MTOKEN_DIM_VALUE (r));
377 break;
378 }
379 break;
380 case eMToken_unary:
381 switch (MTOKEN_SUBKIND (r))
382 {
383 case eMST_slashed:
384 txt = mt_strcat (txt, "/");
385 txt = sprint_decl1 (txt, MTOKEN_UNARY (r));
386 txt = mt_strcat (txt, "/");
387 break;
388 case eMST_array:
389 txt = mt_strcat (txt, "[");
390 txt = sprint_decl1 (txt, MTOKEN_UNARY (r));
391 txt = mt_strcat (txt, "]");
392 break;
393 case eMST_ltgt:
394 txt = mt_strcat (txt, "<");
395 txt = sprint_decl1 (txt, MTOKEN_UNARY (r));
396 txt = mt_strcat (txt, ">");
397 break;
398 case eMST_frame:
399 txt = mt_strcat (txt, "{");
400 txt = sprint_decl1 (txt, MTOKEN_UNARY (r));
401 txt = mt_strcat (txt, "}");
402 break;
403 case eMST_rframe:
404 txt = mt_strcat (txt, "(");
405 txt = sprint_decl1 (txt, MTOKEN_UNARY (r));
406 txt = mt_strcat (txt, ")");
407 break;
408 case eMST_lexical_frame:
409 txt = mt_strcat (txt, "'");
410 txt = sprint_decl1 (txt, MTOKEN_UNARY (r));
411 txt = mt_strcat (txt, "'");
412 break;
413 case eMST_throw:
414 txt = mt_strcat (txt, "throw ");
415 txt = sprint_decl1 (txt, MTOKEN_UNARY (r));
416 break;
417 case eMST_destructor:
418 txt = mt_strcat (txt, "~");
419 txt = sprint_decl1 (txt, MTOKEN_UNARY (r));
420 break;
421 case eMST_element: case eMST_template_argument_list:
422 txt = sprint_decl1 (txt, MTOKEN_UNARY (r));
423 if (MTOKEN_CHAIN (r) != NULL)
424 txt = mt_strcat (txt, ",");
425 break;
426 default:
427 case eMST_oper: case eMST_scope:
428 txt = sprint_decl1 (txt, MTOKEN_UNARY (r));
429 break;
430 }
431 break;
432 case eMToken_binary:
433 switch (MTOKEN_SUBKIND (r))
434 {
435 default:
436 case eMST_combine: case eMST_ecsu:
437 case eMST_based:
438 txt = sprint_decl1 (txt, MTOKEN_BINARY_LEFT (r));
439 txt = mt_strcat (txt, " ");
440 txt = sprint_decl1 (txt, MTOKEN_BINARY_RIGHT (r));
441 break;
442 case eMST_coloncolon:
443 txt = sprint_decl1 (txt, MTOKEN_BINARY_LEFT (r));
444 txt = mt_strcat (txt, "::");
445 txt = sprint_decl1 (txt, MTOKEN_BINARY_RIGHT (r));
446 break;
447 case eMST_assign:
448 txt = sprint_decl1 (txt, MTOKEN_BINARY_LEFT (r));
449 txt = mt_strcat (txt, "=");
450 txt = sprint_decl1 (txt, MTOKEN_BINARY_RIGHT (r));
451 break;
452 case eMST_templateparam: case eMST_nonetypetemplateparam:
453 txt = sprint_decl1 (txt, MTOKEN_BINARY_LEFT (r));
454 txt = sprint_decl1 (txt, MTOKEN_BINARY_RIGHT (r));
455 break;
456 case eMST_exp:
457 txt = sprint_decl1 (txt, MTOKEN_BINARY_LEFT (r));
458 txt = mt_strcat (txt, "e");
459 txt = sprint_decl1 (txt, MTOKEN_BINARY_RIGHT (r));
460 break;
461 }
462 break;
463 default:
464 break;
465 }
466 r = MTOKEN_CHAIN (r);
467 }
468 return txt;
469 }
470
471 static void
trim_str(char * str)472 trim_str (char *str)
473 {
474 char *r, *l;
475 l = r = str;
476 while ( *r != '\0')
477 {
478 if ( *r == ' ')
479 {
480 if (r[1]=='(' || r[1]=='[' || r[1]==' ') r++;
481 else
482 if (l!=str && (l[-1]=='*' || l[-1]=='&' || l[-1]==')')) r++;
483 else
484 if (l!=r) *l++ = *r++;
485 else
486 r++, l++;
487 }
488 else if (l!=r) *l++ = *r++;
489 else r++, l++;
490 }
491 *l = '\0';
492 }
493
494 char *
libmangle_sprint_decl(uMToken * r)495 libmangle_sprint_decl (uMToken *r)
496 {
497 char *ret = NULL;
498 if (r)
499 ret = sprint_decl1(NULL, r);
500 trim_str (ret);
501 return ret;
502 }
503
504 void
libmangle_print_decl(FILE * fp,uMToken * r)505 libmangle_print_decl (FILE *fp, uMToken *r)
506 {
507 char *ret = libmangle_sprint_decl (r);
508 if (ret)
509 {
510 fprintf (fp, "%s\n", ret);
511 free (ret);
512 }
513 else
514 {
515 fprintf (fp, "<NULL>\n");
516 }
517 }
518
519 #if defined (TEST)
520
521 static const char *szTest[]= {
522 "??_C@_0BL@CNOONJFP@?$GAplacement?5delete?5closure?8?$AA@",
523 "??_C@_07LFCOJCAC@__int64?$AA@",
524 "?outputString@UnDecorator@@0PADA",
525 "?outputString@UnDecorator@@1PADA",
526 "?outputString@UnDecorator@@2PADA",
527 "?outputString@UnDecorator@@3PADA",
528 "?outputString@UnDecorator@@4PADA",
529 "?outputString@UnDecorator@@5PADA",
530 "?outputString@UnDecorator@@6PADA",
531 "?outputString@UnDecorator@@7PADA",
532 "?outputString@UnDecorator@@8PADA",
533 "?outputString@UnDecorator@@9PADA",
534 "??_5DName@@QAEAAV0@ABV0@@Z",
535 "??_7pDNameNode@@6B@",
536 "??_7exception@@6B@",
537 "??_Ebad_cast@@UAEPAXI@Z",
538 "??_Fbad_cast@@QAEXXZ",
539 "??_Gbad_cast@@UAEPAXI@Z",
540 "??_M@YGXPAXIHP6EX0@Z@Z",
541 "??_R1A@?0A@A@exception@@8",
542 "??_R2exception@@8","??_R3exception@@8",
543 "??_R0?AVexception@@@8","??_R4exception@@6B@",
544 "??0Block@HeapManager@@QAE@XZ",
545 "??0DNameNode@@IAE@XZ",
546 "??0__non_rtti_object@@QAE@ABV0@@Z",
547 "??1bad_typeid@@UAE@XZ",
548 "??2@YAPAXIAAVHeapManager@@H@Z",
549 "??3@YAXPAX@Z",
550 "??4DName@@QAEAAV0@ABV0@@Z",
551 "??4DName@@QAEAAV0@W4DNameStatus@@@Z",
552 "??4DName@@QAEAAV0@D@Z",
553 "??4DName@@QAEAAV0@PBD@Z",
554 "??YReplicator@@QAEAAV0@ABVDName@@@Z",
555 "??H@YA?AVDName@@W4DNameStatus@@ABV0@@Z",
556 "??H@YA?AVDName@@PBDABV0@@Z",
557 "__CallSettingFrame@12",
558 "??3@YAXPAX@Z",
559 "??_Etype_info@@UAEPAXI@Z",
560 "??_Gtype_info@@UAEPAXI@Z",
561 "??1type_info@@UAE@XZ",
562 "??_R1A@?0A@A@type_info@@8",
563 "??_R2type_info@@8",
564 "??_R0?AVtype_info@@@8",
565 "??_R4type_info@@6B@",
566 "??_7type_info@@6B@",
567 "??_Gtype_info@@UAEPAXI@Z",
568 "??8type_info@@QBEHABV0@@Z",
569 /* "@foo@bar@$bctr$q", borland */
570 NULL
571 };
572
main()573 int main()
574 {
575 int i;
576 uMToken *h;
577 char *txt;
578 for (i = 0; szTest[i]!=NULL; i++)
579 {
580 libmangle_gc_context_t *gc = libmangle_generate_gc ();
581 h = libmangle_decode_ms_name (gc, szTest[i]);
582 txt = libmangle_sprint_decl (h);
583 fprintf (stderr, "%s\n", txt);
584 free (txt);
585 libmangle_release_gc (gc);
586 }
587 return 0;
588 }
589 #endif
590