• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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