1 /* Demangler for the D programming language
2    Copyright 2014, 2015, 2016 Free Software Foundation, Inc.
3    Written by Iain Buclaw (ibuclaw@gdcproject.org)
4 
5 This file is part of the libiberty library.
6 Libiberty is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10 
11 In addition to the permissions in the GNU Library General Public
12 License, the Free Software Foundation gives you unlimited permission
13 to link the compiled version of this file into combinations with other
14 programs, and to distribute those combinations without any restriction
15 coming from the use of this file.  (The Library Public License
16 restrictions do apply in other respects; for example, they cover
17 modification of the file, and distribution when not linked into a
18 combined executable.)
19 
20 Libiberty is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23 Library General Public License for more details.
24 
25 You should have received a copy of the GNU Library General Public
26 License along with libiberty; see the file COPYING.LIB.
27 If not, see <http://www.gnu.org/licenses/>.  */
28 
29 /* This file exports one function; dlang_demangle.
30 
31    This file imports strtol for decoding mangled literals.  */
32 
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36 
37 #include "safe-ctype.h"
38 
39 #include <sys/types.h>
40 #include <string.h>
41 #include <stdio.h>
42 
43 #ifdef HAVE_STDLIB_H
44 #include <stdlib.h>
45 #else
46 extern long strtol (const char *nptr, char **endptr, int base);
47 #endif
48 
49 #include <demangle.h>
50 #include "libiberty.h"
51 
52 /* A mini string-handling package */
53 
54 typedef struct string		/* Beware: these aren't required to be */
55 {				/*  '\0' terminated.  */
56   char *b;			/* pointer to start of string */
57   char *p;			/* pointer after last character */
58   char *e;			/* pointer after end of allocated space */
59 } string;
60 
61 static void
string_need(string * s,int n)62 string_need (string *s, int n)
63 {
64   int tem;
65 
66   if (s->b == NULL)
67     {
68       if (n < 32)
69 	{
70 	  n = 32;
71 	}
72       s->p = s->b = XNEWVEC (char, n);
73       s->e = s->b + n;
74     }
75   else if (s->e - s->p < n)
76     {
77       tem = s->p - s->b;
78       n += tem;
79       n *= 2;
80       s->b = XRESIZEVEC (char, s->b, n);
81       s->p = s->b + tem;
82       s->e = s->b + n;
83     }
84 }
85 
86 static void
string_delete(string * s)87 string_delete (string *s)
88 {
89   if (s->b != NULL)
90     {
91       XDELETEVEC (s->b);
92       s->b = s->e = s->p = NULL;
93     }
94 }
95 
96 static void
string_init(string * s)97 string_init (string *s)
98 {
99   s->b = s->p = s->e = NULL;
100 }
101 
102 static int
string_length(string * s)103 string_length (string *s)
104 {
105   if (s->p == s->b)
106     {
107       return 0;
108     }
109   return s->p - s->b;
110 }
111 
112 static void
string_setlength(string * s,int n)113 string_setlength (string *s, int n)
114 {
115   if (n - string_length (s) < 0)
116     {
117       s->p = s->b + n;
118     }
119 }
120 
121 static void
string_append(string * p,const char * s)122 string_append (string *p, const char *s)
123 {
124   int n = strlen (s);
125   string_need (p, n);
126   memcpy (p->p, s, n);
127   p->p += n;
128 }
129 
130 static void
string_appendn(string * p,const char * s,int n)131 string_appendn (string *p, const char *s, int n)
132 {
133   if (n != 0)
134     {
135       string_need (p, n);
136       memcpy (p->p, s, n);
137       p->p += n;
138     }
139 }
140 
141 static void
string_prependn(string * p,const char * s,int n)142 string_prependn (string *p, const char *s, int n)
143 {
144   char *q;
145 
146   if (n != 0)
147     {
148       string_need (p, n);
149       for (q = p->p - 1; q >= p->b; q--)
150 	{
151 	  q[n] = q[0];
152 	}
153       memcpy (p->b, s, n);
154       p->p += n;
155     }
156 }
157 
158 static void
string_prepend(string * p,const char * s)159 string_prepend (string *p, const char *s)
160 {
161   if (s != NULL && *s != '\0')
162     {
163       string_prependn (p, s, strlen (s));
164     }
165 }
166 
167 /* What kinds of symbol we could be parsing.  */
168 enum dlang_symbol_kinds
169 {
170   /* Top-level symbol, needs it's type checked.  */
171   dlang_top_level,
172   /* Function symbol, needs it's type checked.   */
173   dlang_function,
174   /* Strongly typed name, such as for classes, structs and enums.  */
175   dlang_type_name,
176   /* Template identifier.  */
177   dlang_template_ident,
178   /* Template symbol parameter.  */
179   dlang_template_param
180 };
181 
182 /* Prototypes for forward referenced functions */
183 static const char *dlang_function_args (string *, const char *);
184 
185 static const char *dlang_type (string *, const char *);
186 
187 static const char *dlang_value (string *, const char *, const char *, char);
188 
189 static const char *dlang_parse_symbol (string *, const char *,
190 				       enum dlang_symbol_kinds);
191 
192 static const char *dlang_parse_tuple (string *, const char *);
193 
194 static const char *dlang_parse_template (string *, const char *, long);
195 
196 
197 /* Demangle the calling convention from MANGLED and append it to DECL.
198    Return the remaining string on success or NULL on failure.  */
199 static const char *
dlang_call_convention(string * decl,const char * mangled)200 dlang_call_convention (string *decl, const char *mangled)
201 {
202   if (mangled == NULL || *mangled == '\0')
203     return NULL;
204 
205   switch (*mangled)
206     {
207     case 'F': /* (D) */
208       mangled++;
209       break;
210     case 'U': /* (C) */
211       mangled++;
212       string_append (decl, "extern(C) ");
213       break;
214     case 'W': /* (Windows) */
215       mangled++;
216       string_append (decl, "extern(Windows) ");
217       break;
218     case 'V': /* (Pascal) */
219       mangled++;
220       string_append (decl, "extern(Pascal) ");
221       break;
222     case 'R': /* (C++) */
223       mangled++;
224       string_append (decl, "extern(C++) ");
225       break;
226     case 'Y': /* (Objective-C) */
227       mangled++;
228       string_append (decl, "extern(Objective-C) ");
229       break;
230     default:
231       return NULL;
232     }
233 
234   return mangled;
235 }
236 
237 /* Extract the type modifiers from MANGLED and append them to DECL.
238    Returns the remaining signature on success or NULL on failure.  */
239 static const char *
dlang_type_modifiers(string * decl,const char * mangled)240 dlang_type_modifiers (string *decl, const char *mangled)
241 {
242   if (mangled == NULL || *mangled == '\0')
243     return NULL;
244 
245   switch (*mangled)
246     {
247     case 'x': /* const */
248       mangled++;
249       string_append (decl, " const");
250       return mangled;
251     case 'y': /* immutable */
252       mangled++;
253       string_append (decl, " immutable");
254       return mangled;
255     case 'O': /* shared */
256       mangled++;
257       string_append (decl, " shared");
258       return dlang_type_modifiers (decl, mangled);
259     case 'N':
260       mangled++;
261       if (*mangled == 'g') /* wild */
262 	{
263 	  mangled++;
264 	  string_append (decl, " inout");
265 	  return dlang_type_modifiers (decl, mangled);
266 	}
267       else
268 	return NULL;
269 
270     default:
271       return mangled;
272     }
273 }
274 
275 /* Demangle the D function attributes from MANGLED and append it to DECL.
276    Return the remaining string on success or NULL on failure.  */
277 static const char *
dlang_attributes(string * decl,const char * mangled)278 dlang_attributes (string *decl, const char *mangled)
279 {
280   if (mangled == NULL || *mangled == '\0')
281     return NULL;
282 
283   while (*mangled == 'N')
284     {
285       mangled++;
286       switch (*mangled)
287 	{
288 	case 'a': /* pure */
289 	  mangled++;
290 	  string_append (decl, "pure ");
291 	  continue;
292 	case 'b': /* nothrow */
293 	  mangled++;
294 	  string_append (decl, "nothrow ");
295 	  continue;
296 	case 'c': /* ref */
297 	  mangled++;
298 	  string_append (decl, "ref ");
299 	  continue;
300 	case 'd': /* @property */
301 	  mangled++;
302 	  string_append (decl, "@property ");
303 	  continue;
304 	case 'e': /* @trusted */
305 	  mangled++;
306 	  string_append (decl, "@trusted ");
307 	  continue;
308 	case 'f': /* @safe */
309 	  mangled++;
310 	  string_append (decl, "@safe ");
311 	  continue;
312 	case 'g':
313 	case 'h':
314 	case 'k':
315 	  /* inout parameter is represented as 'Ng'.
316 	     vector parameter is represented as 'Nh'.
317 	     return paramenter is represented as 'Nk'.
318 	     If we see this, then we know we're really in the
319 	     parameter list.  Rewind and break.  */
320 	  mangled--;
321 	  break;
322 	case 'i': /* @nogc */
323 	  mangled++;
324 	  string_append (decl, "@nogc ");
325 	  continue;
326 	case 'j': /* return */
327 	  mangled++;
328 	  string_append (decl, "return ");
329 	  continue;
330 
331 	default: /* unknown attribute */
332 	  return NULL;
333 	}
334       break;
335     }
336 
337   return mangled;
338 }
339 
340 /* Demangle the function type from MANGLED and append it to DECL.
341    Return the remaining string on success or NULL on failure.  */
342 static const char *
dlang_function_type(string * decl,const char * mangled)343 dlang_function_type (string *decl, const char *mangled)
344 {
345   string attr, args, type;
346   size_t szattr, szargs, sztype;
347 
348   if (mangled == NULL || *mangled == '\0')
349     return NULL;
350 
351   /* The order of the mangled string is:
352 	CallConvention FuncAttrs Arguments ArgClose Type
353 
354      The demangled string is re-ordered as:
355 	CallConvention Type Arguments FuncAttrs
356    */
357   string_init (&attr);
358   string_init (&args);
359   string_init (&type);
360 
361   /* Function call convention.  */
362   mangled = dlang_call_convention (decl, mangled);
363 
364   /* Function attributes.  */
365   mangled = dlang_attributes (&attr, mangled);
366   szattr = string_length (&attr);
367 
368   /* Function arguments.  */
369   mangled = dlang_function_args (&args, mangled);
370   szargs = string_length (&args);
371 
372   /* Function return type.  */
373   mangled = dlang_type (&type, mangled);
374   sztype = string_length (&type);
375 
376   /* Append to decl in order. */
377   string_appendn (decl, type.b, sztype);
378   string_append (decl, "(");
379   string_appendn (decl, args.b, szargs);
380   string_append (decl, ") ");
381   string_appendn (decl, attr.b, szattr);
382 
383   string_delete (&attr);
384   string_delete (&args);
385   string_delete (&type);
386   return mangled;
387 }
388 
389 /* Demangle the argument list from MANGLED and append it to DECL.
390    Return the remaining string on success or NULL on failure.  */
391 static const char *
dlang_function_args(string * decl,const char * mangled)392 dlang_function_args (string *decl, const char *mangled)
393 {
394   size_t n = 0;
395 
396   while (mangled && *mangled != '\0')
397     {
398       switch (*mangled)
399 	{
400 	case 'X': /* (variadic T t...) style.  */
401 	  mangled++;
402 	  string_append (decl, "...");
403 	  return mangled;
404 	case 'Y': /* (variadic T t, ...) style.  */
405 	  mangled++;
406 	  if (n != 0)
407 	    string_append (decl, ", ");
408 	  string_append (decl, "...");
409 	  return mangled;
410 	case 'Z': /* Normal function.  */
411 	  mangled++;
412 	  return mangled;
413 	}
414 
415       if (n++)
416 	string_append (decl, ", ");
417 
418       if (*mangled == 'M') /* scope(T) */
419 	{
420 	  mangled++;
421 	  string_append (decl, "scope ");
422 	}
423 
424       if (mangled[0] == 'N' && mangled[1] == 'k') /* return(T) */
425 	{
426 	  mangled += 2;
427 	  string_append (decl, "return ");
428 	}
429 
430       switch (*mangled)
431 	{
432 	case 'J': /* out(T) */
433 	  mangled++;
434 	  string_append (decl, "out ");
435 	  break;
436 	case 'K': /* ref(T) */
437 	  mangled++;
438 	  string_append (decl, "ref ");
439 	  break;
440 	case 'L': /* lazy(T) */
441 	  mangled++;
442 	  string_append (decl, "lazy ");
443 	  break;
444 	}
445       mangled = dlang_type (decl, mangled);
446     }
447 
448   return mangled;
449 }
450 
451 /* Demangle the type from MANGLED and append it to DECL.
452    Return the remaining string on success or NULL on failure.  */
453 static const char *
dlang_type(string * decl,const char * mangled)454 dlang_type (string *decl, const char *mangled)
455 {
456   if (mangled == NULL || *mangled == '\0')
457     return NULL;
458 
459   switch (*mangled)
460     {
461     case 'O': /* shared(T) */
462       mangled++;
463       string_append (decl, "shared(");
464       mangled = dlang_type (decl, mangled);
465       string_append (decl, ")");
466       return mangled;
467     case 'x': /* const(T) */
468       mangled++;
469       string_append (decl, "const(");
470       mangled = dlang_type (decl, mangled);
471       string_append (decl, ")");
472       return mangled;
473     case 'y': /* immutable(T) */
474       mangled++;
475       string_append (decl, "immutable(");
476       mangled = dlang_type (decl, mangled);
477       string_append (decl, ")");
478       return mangled;
479     case 'N':
480       mangled++;
481       if (*mangled == 'g') /* wild(T) */
482 	{
483 	  mangled++;
484 	  string_append (decl, "inout(");
485 	  mangled = dlang_type (decl, mangled);
486 	  string_append (decl, ")");
487 	  return mangled;
488 	}
489       else if (*mangled == 'h') /* vector(T) */
490 	{
491 	  mangled++;
492 	  string_append (decl, "__vector(");
493 	  mangled = dlang_type (decl, mangled);
494 	  string_append (decl, ")");
495 	  return mangled;
496 	}
497       else
498 	return NULL;
499     case 'A': /* dynamic array (T[]) */
500       mangled++;
501       mangled = dlang_type (decl, mangled);
502       string_append (decl, "[]");
503       return mangled;
504     case 'G': /* static array (T[N]) */
505     {
506       const char *numptr;
507       size_t num = 0;
508       mangled++;
509 
510       numptr = mangled;
511       while (ISDIGIT (*mangled))
512 	{
513 	  num++;
514 	  mangled++;
515 	}
516       mangled = dlang_type (decl, mangled);
517       string_append (decl, "[");
518       string_appendn (decl, numptr, num);
519       string_append (decl, "]");
520       return mangled;
521     }
522     case 'H': /* associative array (T[T]) */
523     {
524       string type;
525       size_t sztype;
526       mangled++;
527 
528       string_init (&type);
529       mangled = dlang_type (&type, mangled);
530       sztype = string_length (&type);
531 
532       mangled = dlang_type (decl, mangled);
533       string_append (decl, "[");
534       string_appendn (decl, type.b, sztype);
535       string_append (decl, "]");
536 
537       string_delete (&type);
538       return mangled;
539     }
540     case 'P': /* pointer (T*) */
541       mangled++;
542       /* Function pointer types don't include the trailing asterisk.  */
543       switch (*mangled)
544 	{
545 	case 'F': case 'U': case 'W':
546 	case 'V': case 'R': case 'Y':
547 	  mangled = dlang_function_type (decl, mangled);
548 	  string_append (decl, "function");
549 	  return mangled;
550 	}
551       mangled = dlang_type (decl, mangled);
552       string_append (decl, "*");
553       return mangled;
554     case 'I': /* ident T */
555     case 'C': /* class T */
556     case 'S': /* struct T */
557     case 'E': /* enum T */
558     case 'T': /* typedef T */
559       mangled++;
560       return dlang_parse_symbol (decl, mangled, dlang_type_name);
561     case 'D': /* delegate T */
562     {
563       string mods;
564       size_t szmods;
565       mangled++;
566 
567       string_init (&mods);
568       mangled = dlang_type_modifiers (&mods, mangled);
569       szmods = string_length (&mods);
570 
571       mangled = dlang_function_type (decl, mangled);
572       string_append (decl, "delegate");
573       string_appendn (decl, mods.b, szmods);
574 
575       string_delete (&mods);
576       return mangled;
577     }
578     case 'B': /* tuple T */
579       mangled++;
580       return dlang_parse_tuple (decl, mangled);
581 
582     /* Basic types */
583     case 'n':
584       mangled++;
585       string_append (decl, "none");
586       return mangled;
587     case 'v':
588       mangled++;
589       string_append (decl, "void");
590       return mangled;
591     case 'g':
592       mangled++;
593       string_append (decl, "byte");
594       return mangled;
595     case 'h':
596       mangled++;
597       string_append (decl, "ubyte");
598       return mangled;
599     case 's':
600       mangled++;
601       string_append (decl, "short");
602       return mangled;
603     case 't':
604       mangled++;
605       string_append (decl, "ushort");
606       return mangled;
607     case 'i':
608       mangled++;
609       string_append (decl, "int");
610       return mangled;
611     case 'k':
612       mangled++;
613       string_append (decl, "uint");
614       return mangled;
615     case 'l':
616       mangled++;
617       string_append (decl, "long");
618       return mangled;
619     case 'm':
620       mangled++;
621       string_append (decl, "ulong");
622       return mangled;
623     case 'f':
624       mangled++;
625       string_append (decl, "float");
626       return mangled;
627     case 'd':
628       mangled++;
629       string_append (decl, "double");
630       return mangled;
631     case 'e':
632       mangled++;
633       string_append (decl, "real");
634       return mangled;
635 
636     /* Imaginary and Complex types */
637     case 'o':
638       mangled++;
639       string_append (decl, "ifloat");
640       return mangled;
641     case 'p':
642       mangled++;
643       string_append (decl, "idouble");
644       return mangled;
645     case 'j':
646       mangled++;
647       string_append (decl, "ireal");
648       return mangled;
649     case 'q':
650       mangled++;
651       string_append (decl, "cfloat");
652       return mangled;
653     case 'r':
654       mangled++;
655       string_append (decl, "cdouble");
656       return mangled;
657     case 'c':
658       mangled++;
659       string_append (decl, "creal");
660       return mangled;
661 
662     /* Other types */
663     case 'b':
664       mangled++;
665       string_append (decl, "bool");
666       return mangled;
667     case 'a':
668       mangled++;
669       string_append (decl, "char");
670       return mangled;
671     case 'u':
672       mangled++;
673       string_append (decl, "wchar");
674       return mangled;
675     case 'w':
676       mangled++;
677       string_append (decl, "dchar");
678       return mangled;
679     case 'z':
680       mangled++;
681       switch (*mangled)
682 	{
683 	case 'i':
684 	  mangled++;
685 	  string_append (decl, "cent");
686 	  return mangled;
687 	case 'k':
688 	  mangled++;
689 	  string_append (decl, "ucent");
690 	  return mangled;
691 	}
692       return NULL;
693 
694     default: /* unhandled */
695       return NULL;
696     }
697 }
698 
699 /* Extract the identifier from MANGLED and append it to DECL.
700    Return the remaining string on success or NULL on failure.  */
701 static const char *
dlang_identifier(string * decl,const char * mangled,enum dlang_symbol_kinds kind)702 dlang_identifier (string *decl, const char *mangled,
703 		  enum dlang_symbol_kinds kind)
704 {
705   char *endptr;
706   long len;
707 
708   if (mangled == NULL || *mangled == '\0')
709     return NULL;
710 
711   len = strtol (mangled, &endptr, 10);
712 
713   if (endptr == NULL || len <= 0)
714     return NULL;
715 
716   /* In template parameter symbols, the first character of the mangled
717      name can be a digit.  This causes ambiguity issues because the
718      digits of the two numbers are adjacent.  */
719   if (kind == dlang_template_param)
720     {
721       long psize = len;
722       char *pend;
723       int saved = string_length (decl);
724 
725       /* Work backwards until a match is found.  */
726       for (pend = endptr; endptr != NULL; pend--)
727 	{
728 	  mangled = pend;
729 
730 	  /* Reached the beginning of the pointer to the name length,
731 	     try parsing the entire symbol.  */
732 	  if (psize == 0)
733 	    {
734 	      psize = len;
735 	      pend = endptr;
736 	      endptr = NULL;
737 	    }
738 
739 	  /* Check whether template parameter is a function with a valid
740 	     return type or an untyped identifier.  */
741 	  if (ISDIGIT (*mangled))
742 	    mangled = dlang_parse_symbol (decl, mangled, dlang_template_ident);
743 	  else if (strncmp (mangled, "_D", 2) == 0)
744 	    {
745 	      mangled += 2;
746 	      mangled = dlang_parse_symbol (decl, mangled, dlang_function);
747 	    }
748 
749 	  /* Check for name length mismatch.  */
750 	  if (mangled && (mangled - pend) == psize)
751 	    return mangled;
752 
753 	  psize /= 10;
754 	  string_setlength (decl, saved);
755 	}
756 
757       /* No match on any combinations.  */
758       return NULL;
759     }
760   else
761     {
762       if (strlen (endptr) < (size_t) len)
763 	return NULL;
764 
765       mangled = endptr;
766 
767       /* May be a template instance.  */
768       if (len >= 5 && strncmp (mangled, "__T", 3) == 0)
769 	{
770 	  /* Template symbol.  */
771 	  if (ISDIGIT (mangled[3]) && mangled[3] != '0')
772 	    return dlang_parse_template (decl, mangled, len);
773 
774 	  return NULL;
775 	}
776 
777       switch (len)
778 	{
779 	case 6:
780 	  if (strncmp (mangled, "__ctor", len) == 0)
781 	    {
782 	      /* Constructor symbol for a class/struct.  */
783 	      string_append (decl, "this");
784 	      mangled += len;
785 	      return mangled;
786 	    }
787 	  else if (strncmp (mangled, "__dtor", len) == 0)
788 	    {
789 	      /* Destructor symbol for a class/struct.  */
790 	      string_append (decl, "~this");
791 	      mangled += len;
792 	      return mangled;
793 	    }
794 	  else if (strncmp (mangled, "__initZ", len+1) == 0)
795 	    {
796 	      /* The static initialiser for a given symbol.  */
797 	      string_append (decl, "init$");
798 	      mangled += len;
799 	      return mangled;
800 	    }
801 	  else if (strncmp (mangled, "__vtblZ", len+1) == 0)
802 	    {
803 	      /* The vtable symbol for a given class.  */
804 	      string_prepend (decl, "vtable for ");
805 	      string_setlength (decl, string_length (decl) - 1);
806 	      mangled += len;
807 	      return mangled;
808 	    }
809 	  break;
810 
811 	case 7:
812 	  if (strncmp (mangled, "__ClassZ", len+1) == 0)
813 	    {
814 	      /* The classinfo symbol for a given class.  */
815 	      string_prepend (decl, "ClassInfo for ");
816 	      string_setlength (decl, string_length (decl) - 1);
817 	      mangled += len;
818 	      return mangled;
819 	    }
820 	  break;
821 
822 	case 10:
823 	  if (strncmp (mangled, "__postblitMFZ", len+3) == 0)
824 	    {
825 	      /* Postblit symbol for a struct.  */
826 	      string_append (decl, "this(this)");
827 	      mangled += len + 3;
828 	      return mangled;
829 	    }
830 	  break;
831 
832 	case 11:
833 	  if (strncmp (mangled, "__InterfaceZ", len+1) == 0)
834 	    {
835 	      /* The interface symbol for a given class.  */
836 	      string_prepend (decl, "Interface for ");
837 	      string_setlength (decl, string_length (decl) - 1);
838 	      mangled += len;
839 	      return mangled;
840 	    }
841 	  break;
842 
843 	case 12:
844 	  if (strncmp (mangled, "__ModuleInfoZ", len+1) == 0)
845 	    {
846 	      /* The ModuleInfo symbol for a given module.  */
847 	      string_prepend (decl, "ModuleInfo for ");
848 	      string_setlength (decl, string_length (decl) - 1);
849 	      mangled += len;
850 	      return mangled;
851 	    }
852 	  break;
853 	}
854 
855       string_appendn (decl, mangled, len);
856       mangled += len;
857     }
858 
859   return mangled;
860 }
861 
862 /* Extract the integer value from MANGLED and append it to DECL,
863    where TYPE is the type it should be represented as.
864    Return the remaining string on success or NULL on failure.  */
865 static const char *
dlang_parse_integer(string * decl,const char * mangled,char type)866 dlang_parse_integer (string *decl, const char *mangled, char type)
867 {
868   if (type == 'a' || type == 'u' || type == 'w')
869     {
870       /* Parse character value.  */
871       char value[10];
872       int pos = 10;
873       int width = 0;
874       char *endptr;
875       long val = strtol (mangled, &endptr, 10);
876 
877       if (endptr == NULL || val < 0)
878 	return NULL;
879 
880       string_append (decl, "'");
881 
882       if (type == 'a' && val >= 0x20 && val < 0x7F)
883 	{
884 	  /* Represent as a character literal.  */
885 	  char c = (char) val;
886 	  string_appendn (decl, &c, 1);
887 	}
888       else
889 	{
890 	  /* Represent as a hexadecimal value.  */
891 	  switch (type)
892 	    {
893 	    case 'a': /* char */
894 	      string_append (decl, "\\x");
895 	      width = 2;
896 	      break;
897 	    case 'u': /* wchar */
898 	      string_append (decl, "\\u");
899 	      width = 4;
900 	      break;
901 	    case 'w': /* dchar */
902 	      string_append (decl, "\\U");
903 	      width = 8;
904 	      break;
905 	    }
906 
907 	  while (val > 0)
908 	    {
909 	      int digit = val % 16;
910 
911 	      if (digit < 10)
912 		value[--pos] = (char)(digit + '0');
913 	      else
914 		value[--pos] = (char)((digit - 10) + 'a');
915 
916 	      val /= 16;
917 	      width--;
918 	    }
919 
920 	  for (; width > 0; width--)
921 	    value[--pos] = '0';
922 
923 	  string_appendn (decl, &(value[pos]), 10 - pos);
924 	}
925       string_append (decl, "'");
926       mangled = endptr;
927     }
928   else if (type == 'b')
929     {
930       /* Parse boolean value.  */
931       char *endptr;
932       long val = strtol (mangled, &endptr, 10);
933 
934       if (endptr == NULL || val < 0)
935 	return NULL;
936 
937       string_append (decl, val ? "true" : "false");
938       mangled = endptr;
939     }
940   else
941     {
942       /* Parse integer value.  */
943       const char *numptr = mangled;
944       size_t num = 0;
945 
946       while (ISDIGIT (*mangled))
947 	{
948 	  num++;
949 	  mangled++;
950 	}
951       string_appendn (decl, numptr, num);
952 
953       /* Append suffix.  */
954       switch (type)
955 	{
956 	case 'h': /* ubyte */
957 	case 't': /* ushort */
958 	case 'k': /* uint */
959 	  string_append (decl, "u");
960 	  break;
961 	case 'l': /* long */
962 	  string_append (decl, "L");
963 	  break;
964 	case 'm': /* ulong */
965 	  string_append (decl, "uL");
966 	  break;
967 	}
968     }
969 
970   return mangled;
971 }
972 
973 /* Extract the floating-point value from MANGLED and append it to DECL.
974    Return the remaining string on success or NULL on failure.  */
975 static const char *
dlang_parse_real(string * decl,const char * mangled)976 dlang_parse_real (string *decl, const char *mangled)
977 {
978   char buffer[64];
979   int len = 0;
980 
981   /* Handle NAN and +-INF.  */
982   if (strncmp (mangled, "NAN", 3) == 0)
983     {
984       string_append (decl, "NaN");
985       mangled += 3;
986       return mangled;
987     }
988   else if (strncmp (mangled, "INF", 3) == 0)
989     {
990       string_append (decl, "Inf");
991       mangled += 3;
992       return mangled;
993     }
994   else if (strncmp (mangled, "NINF", 4) == 0)
995     {
996       string_append (decl, "-Inf");
997       mangled += 4;
998       return mangled;
999     }
1000 
1001   /* Hexadecimal prefix and leading bit.  */
1002   if (*mangled == 'N')
1003     {
1004       buffer[len++] = '-';
1005       mangled++;
1006     }
1007 
1008   if (!ISXDIGIT (*mangled))
1009     return NULL;
1010 
1011   buffer[len++] = '0';
1012   buffer[len++] = 'x';
1013   buffer[len++] = *mangled;
1014   buffer[len++] = '.';
1015   mangled++;
1016 
1017   /* Significand.  */
1018   while (ISXDIGIT (*mangled))
1019     {
1020       buffer[len++] = *mangled;
1021       mangled++;
1022     }
1023 
1024   /* Exponent.  */
1025   if (*mangled != 'P')
1026     return NULL;
1027 
1028   buffer[len++] = 'p';
1029   mangled++;
1030 
1031   if (*mangled == 'N')
1032     {
1033       buffer[len++] = '-';
1034       mangled++;
1035     }
1036 
1037   while (ISDIGIT (*mangled))
1038     {
1039       buffer[len++] = *mangled;
1040       mangled++;
1041     }
1042 
1043   /* Write out the demangled hexadecimal, rather than trying to
1044      convert the buffer into a floating-point value.  */
1045   buffer[len] = '\0';
1046   len = strlen (buffer);
1047   string_appendn (decl, buffer, len);
1048   return mangled;
1049 }
1050 
1051 /* Convert VAL from an ascii hexdigit to value.  */
1052 static char
ascii2hex(char val)1053 ascii2hex (char val)
1054 {
1055   if (val >= 'a' && val <= 'f')
1056     return (val - 'a' + 10);
1057 
1058   if (val >= 'A' && val <= 'F')
1059     return (val - 'A' + 10);
1060 
1061   if (val >= '0' && val <= '9')
1062     return (val - '0');
1063 
1064   return 0;
1065 }
1066 
1067 /* Extract the string value from MANGLED and append it to DECL.
1068    Return the remaining string on success or NULL on failure.  */
1069 static const char *
dlang_parse_string(string * decl,const char * mangled)1070 dlang_parse_string (string *decl, const char *mangled)
1071 {
1072   char type = *mangled;
1073   char *endptr;
1074   long len;
1075 
1076   mangled++;
1077   len = strtol (mangled, &endptr, 10);
1078 
1079   if (endptr == NULL || len < 0)
1080     return NULL;
1081 
1082   mangled = endptr;
1083   if (*mangled != '_')
1084     return NULL;
1085 
1086   mangled++;
1087   string_append (decl, "\"");
1088   while (len--)
1089     {
1090       if (ISXDIGIT (mangled[0]) && ISXDIGIT (mangled[1]))
1091 	{
1092 	  char a = ascii2hex (mangled[0]);
1093 	  char b = ascii2hex (mangled[1]);
1094 	  char val = (a << 4) | b;
1095 
1096 	  /* Sanitize white and non-printable characters.  */
1097 	  switch (val)
1098 	    {
1099 	    case ' ':
1100 	      string_append (decl, " ");
1101 	      break;
1102 	    case '\t':
1103 	      string_append (decl, "\\t");
1104 	      break;
1105 	    case '\n':
1106 	      string_append (decl, "\\n");
1107 	      break;
1108 	    case '\r':
1109 	      string_append (decl, "\\r");
1110 	      break;
1111 	    case '\f':
1112 	      string_append (decl, "\\f");
1113 	      break;
1114 	    case '\v':
1115 	      string_append (decl, "\\v");
1116 	      break;
1117 
1118 	    default:
1119 	      if (ISPRINT (val))
1120 		string_appendn (decl, &val, 1);
1121 	      else
1122 		{
1123 		  string_append (decl, "\\x");
1124 		  string_appendn (decl, mangled, 2);
1125 		}
1126 	    }
1127 	}
1128       else
1129 	return NULL;
1130 
1131       mangled += 2;
1132     }
1133   string_append (decl, "\"");
1134 
1135   if (type != 'a')
1136     string_appendn (decl, &type, 1);
1137 
1138   return mangled;
1139 }
1140 
1141 /* Extract the static array value from MANGLED and append it to DECL.
1142    Return the remaining string on success or NULL on failure.  */
1143 static const char *
dlang_parse_arrayliteral(string * decl,const char * mangled)1144 dlang_parse_arrayliteral (string *decl, const char *mangled)
1145 {
1146   char *endptr;
1147   long elements = strtol (mangled, &endptr, 10);
1148 
1149   if (endptr == NULL || elements < 0)
1150     return NULL;
1151 
1152   mangled = endptr;
1153   string_append (decl, "[");
1154   while (elements--)
1155     {
1156       mangled = dlang_value (decl, mangled, NULL, '\0');
1157       if (elements != 0)
1158 	string_append (decl, ", ");
1159     }
1160 
1161   string_append (decl, "]");
1162   return mangled;
1163 }
1164 
1165 /* Extract the associative array value from MANGLED and append it to DECL.
1166    Return the remaining string on success or NULL on failure.  */
1167 static const char *
dlang_parse_assocarray(string * decl,const char * mangled)1168 dlang_parse_assocarray (string *decl, const char *mangled)
1169 {
1170   char *endptr;
1171   long elements = strtol (mangled, &endptr, 10);
1172 
1173   if (endptr == NULL || elements < 0)
1174     return NULL;
1175 
1176   mangled = endptr;
1177   string_append (decl, "[");
1178   while (elements--)
1179     {
1180       mangled = dlang_value (decl, mangled, NULL, '\0');
1181       string_append (decl, ":");
1182       mangled = dlang_value (decl, mangled, NULL, '\0');
1183 
1184       if (elements != 0)
1185 	string_append (decl, ", ");
1186     }
1187 
1188   string_append (decl, "]");
1189   return mangled;
1190 }
1191 
1192 /* Extract the struct literal value for NAME from MANGLED and append it to DECL.
1193    Return the remaining string on success or NULL on failure.  */
1194 static const char *
dlang_parse_structlit(string * decl,const char * mangled,const char * name)1195 dlang_parse_structlit (string *decl, const char *mangled, const char *name)
1196 {
1197   char *endptr;
1198   long args = strtol (mangled, &endptr, 10);
1199 
1200   if (endptr == NULL || args < 0)
1201     return NULL;
1202 
1203   mangled = endptr;
1204   if (name != NULL)
1205     string_append (decl, name);
1206 
1207   string_append (decl, "(");
1208   while (args--)
1209     {
1210       mangled = dlang_value (decl, mangled, NULL, '\0');
1211       if (args != 0)
1212 	string_append (decl, ", ");
1213     }
1214 
1215   string_append (decl, ")");
1216   return mangled;
1217 }
1218 
1219 /* Extract the value from MANGLED and append it to DECL.
1220    Return the remaining string on success or NULL on failure.  */
1221 static const char *
dlang_value(string * decl,const char * mangled,const char * name,char type)1222 dlang_value (string *decl, const char *mangled, const char *name, char type)
1223 {
1224   if (mangled == NULL || *mangled == '\0')
1225     return NULL;
1226 
1227   switch (*mangled)
1228     {
1229       /* Null value.  */
1230     case 'n':
1231       mangled++;
1232       string_append (decl, "null");
1233       break;
1234 
1235       /* Integral values.  */
1236     case 'N':
1237       mangled++;
1238       string_append (decl, "-");
1239       mangled = dlang_parse_integer (decl, mangled, type);
1240       break;
1241 
1242     case 'i':
1243       mangled++;
1244       if (*mangled < '0' || *mangled > '9')
1245 	return NULL;
1246       /* Fall through */
1247     case '0': case '1': case '2': case '3': case '4':
1248     case '5': case '6': case '7': case '8': case '9':
1249       mangled = dlang_parse_integer (decl, mangled, type);
1250       break;
1251 
1252       /* Real value.  */
1253     case 'e':
1254       mangled++;
1255       mangled = dlang_parse_real (decl, mangled);
1256       break;
1257 
1258       /* Complex value.  */
1259     case 'c':
1260       mangled++;
1261       mangled = dlang_parse_real (decl, mangled);
1262       string_append (decl, "+");
1263       if (mangled == NULL || *mangled != 'c')
1264 	return NULL;
1265       mangled++;
1266       mangled = dlang_parse_real (decl, mangled);
1267       string_append (decl, "i");
1268       break;
1269 
1270       /* String values.  */
1271     case 'a': /* UTF8 */
1272     case 'w': /* UTF16 */
1273     case 'd': /* UTF32 */
1274       mangled = dlang_parse_string (decl, mangled);
1275       break;
1276 
1277       /* Array values.  */
1278     case 'A':
1279       mangled++;
1280       if (type == 'H')
1281 	mangled = dlang_parse_assocarray (decl, mangled);
1282       else
1283 	mangled = dlang_parse_arrayliteral (decl, mangled);
1284       break;
1285 
1286       /* Struct values.  */
1287     case 'S':
1288       mangled++;
1289       mangled = dlang_parse_structlit (decl, mangled, name);
1290       break;
1291 
1292     default:
1293       return NULL;
1294     }
1295 
1296   return mangled;
1297 }
1298 
1299 /* Extract the type modifiers from MANGLED and return the string
1300    length that it consumes in MANGLED on success or 0 on failure.  */
1301 static int
dlang_type_modifier_p(const char * mangled)1302 dlang_type_modifier_p (const char *mangled)
1303 {
1304   int i;
1305 
1306   switch (*mangled)
1307     {
1308     case 'x': case 'y':
1309       return 1;
1310 
1311     case 'O':
1312       mangled++;
1313       i = dlang_type_modifier_p (mangled);
1314       return i + 1;
1315 
1316     case 'N':
1317       mangled++;
1318       if (*mangled == 'g')
1319 	{
1320 	  mangled++;
1321 	  i = dlang_type_modifier_p (mangled);
1322 	  return i + 2;
1323 	}
1324     }
1325 
1326   return 0;
1327 }
1328 
1329 /* Extract the function calling convention from MANGLED and
1330    return 1 on success or 0 on failure.  */
1331 static int
dlang_call_convention_p(const char * mangled)1332 dlang_call_convention_p (const char *mangled)
1333 {
1334   /* Prefix for functions needing 'this' */
1335   if (*mangled == 'M')
1336     {
1337       mangled++;
1338       /* Also skip over any type modifiers.  */
1339       mangled += dlang_type_modifier_p (mangled);
1340     }
1341 
1342   switch (*mangled)
1343     {
1344     case 'F': case 'U': case 'V':
1345     case 'W': case 'R': case 'Y':
1346       return 1;
1347 
1348     default:
1349       return 0;
1350     }
1351 }
1352 
1353 /* Extract and demangle the symbol in MANGLED and append it to DECL.
1354    Returns the remaining signature on success or NULL on failure.  */
1355 static const char *
dlang_parse_symbol(string * decl,const char * mangled,enum dlang_symbol_kinds kind)1356 dlang_parse_symbol (string *decl, const char *mangled,
1357 		    enum dlang_symbol_kinds kind)
1358 {
1359   int saved;
1360   size_t n = 0;
1361   do
1362     {
1363       if (n++)
1364 	string_append (decl, ".");
1365 
1366       mangled = dlang_identifier (decl, mangled, kind);
1367 
1368       if (mangled && dlang_call_convention_p (mangled))
1369 	{
1370 	  string mods;
1371 	  const char *start = NULL;
1372 	  int checkpoint = 0;
1373 
1374 	  /* Skip over 'this' parameter.  */
1375 	  if (*mangled == 'M')
1376 	    mangled++;
1377 
1378 	  /* We have reached here because we expect an extern(Pascal) function.
1379 	     However this is so rare, that it is more likely a template value
1380 	     parameter.  Since this can't be assumed, first attempt parsing
1381 	     the symbol as a function, and then back out on failure.  */
1382 	  if (*mangled == 'V')
1383 	    {
1384 	      start = mangled;
1385 	      checkpoint = string_length (decl);
1386 	    }
1387 
1388 	  /* Save the type modifiers for appending at the end.  */
1389 	  string_init (&mods);
1390 	  mangled = dlang_type_modifiers (&mods, mangled);
1391 
1392 	  /* Skip over calling convention and attributes in qualified name.  */
1393 	  saved = string_length (decl);
1394 	  mangled = dlang_call_convention (decl, mangled);
1395 	  mangled = dlang_attributes (decl, mangled);
1396 	  string_setlength (decl, saved);
1397 
1398 	  string_append (decl, "(");
1399 	  mangled = dlang_function_args (decl, mangled);
1400 	  string_append (decl, ")");
1401 
1402 	  /* Add any const/immutable/shared modifier. */
1403 	  string_appendn (decl, mods.b, string_length (&mods));
1404 	  string_delete (&mods);
1405 
1406 	  if (mangled == NULL && checkpoint != 0)
1407 	    {
1408 	      mangled = start;
1409 	      string_setlength (decl, checkpoint);
1410 	    }
1411 	}
1412     }
1413   while (mangled && ISDIGIT (*mangled));
1414 
1415   /* Only top-level symbols or function template parameters have
1416      a type that needs checking.  */
1417   if (kind == dlang_top_level || kind == dlang_function)
1418     {
1419       /* Artificial symbols end with 'Z' and have no type.  */
1420       if (mangled && *mangled == 'Z')
1421 	mangled++;
1422       else
1423 	{
1424 	  saved = string_length (decl);
1425 	  mangled = dlang_type (decl, mangled);
1426 	  string_setlength (decl, saved);
1427 	}
1428 
1429       /* Check that the entire symbol was successfully demangled.  */
1430       if (kind == dlang_top_level)
1431 	{
1432 	  if (mangled == NULL || *mangled != '\0')
1433 	    return NULL;
1434 	}
1435     }
1436 
1437   return mangled;
1438 }
1439 
1440 /* Demangle the tuple from MANGLED and append it to DECL.
1441    Return the remaining string on success or NULL on failure.  */
1442 static const char *
dlang_parse_tuple(string * decl,const char * mangled)1443 dlang_parse_tuple (string *decl, const char *mangled)
1444 {
1445   char *endptr;
1446   long elements = strtol (mangled, &endptr, 10);
1447 
1448   if (endptr == NULL || elements < 0)
1449     return NULL;
1450 
1451   mangled = endptr;
1452   string_append (decl, "Tuple!(");
1453 
1454   while (elements--)
1455     {
1456       mangled = dlang_type (decl, mangled);
1457       if (elements != 0)
1458 	string_append (decl, ", ");
1459     }
1460 
1461   string_append (decl, ")");
1462   return mangled;
1463 }
1464 
1465 /* Demangle the argument list from MANGLED and append it to DECL.
1466    Return the remaining string on success or NULL on failure.  */
1467 static const char *
dlang_template_args(string * decl,const char * mangled)1468 dlang_template_args (string *decl, const char *mangled)
1469 {
1470   size_t n = 0;
1471 
1472   while (mangled && *mangled != '\0')
1473     {
1474       switch (*mangled)
1475 	{
1476 	case 'Z': /* End of parameter list.  */
1477 	  mangled++;
1478 	  return mangled;
1479 	}
1480 
1481       if (n++)
1482 	string_append (decl, ", ");
1483 
1484       /* Skip over specialised template prefix.  */
1485       if (*mangled == 'H')
1486 	mangled++;
1487 
1488       switch (*mangled)
1489 	{
1490 	case 'S': /* Symbol parameter.  */
1491 	  mangled++;
1492 	  mangled = dlang_parse_symbol (decl, mangled, dlang_template_param);
1493 	  break;
1494 	case 'T': /* Type parameter.  */
1495 	  mangled++;
1496 	  mangled = dlang_type (decl, mangled);
1497 	  break;
1498 	case 'V': /* Value parameter.  */
1499 	{
1500 	  string name;
1501 	  char type;
1502 
1503 	  /* Peek at the type.  */
1504 	  mangled++;
1505 	  type = *mangled;
1506 
1507 	  /* In the few instances where the type is actually desired in
1508 	     the output, it should precede the value from dlang_value.  */
1509 	  string_init (&name);
1510 	  mangled = dlang_type (&name, mangled);
1511 	  string_need (&name, 1);
1512 	  *(name.p) = '\0';
1513 
1514 	  mangled = dlang_value (decl, mangled, name.b, type);
1515 	  string_delete (&name);
1516 	  break;
1517 	}
1518 
1519 	default:
1520 	  return NULL;
1521 	}
1522     }
1523 
1524   return mangled;
1525 }
1526 
1527 /* Extract and demangle the template symbol in MANGLED, expected to
1528    be made up of LEN characters, and append it to DECL.
1529    Returns the remaining signature on success or NULL on failure.  */
1530 static const char *
dlang_parse_template(string * decl,const char * mangled,long len)1531 dlang_parse_template (string *decl, const char *mangled, long len)
1532 {
1533   const char *start = mangled;
1534 
1535   /* Template instance names have the types and values of its parameters
1536      encoded into it.
1537 
1538 	TemplateInstanceName:
1539 	    Number __T LName TemplateArgs Z
1540 		   ^
1541      The start pointer should be at the above location, and LEN should be
1542      the value of the decoded number.
1543    */
1544   if (strncmp (mangled, "__T", 3) != 0)
1545     return NULL;
1546 
1547   mangled += 3;
1548 
1549   /* Template identifier.  */
1550   mangled = dlang_identifier (decl, mangled, dlang_template_ident);
1551 
1552   /* Template arguments.  */
1553   string_append (decl, "!(");
1554   mangled = dlang_template_args (decl, mangled);
1555   string_append (decl, ")");
1556 
1557   /* Check for template name length mismatch.  */
1558   if (mangled && (mangled - start) != len)
1559     return NULL;
1560 
1561   return mangled;
1562 }
1563 
1564 /* Extract and demangle the symbol in MANGLED.  Returns the demangled
1565    signature on success or NULL on failure.  */
1566 
1567 char *
dlang_demangle(const char * mangled,int option ATTRIBUTE_UNUSED)1568 dlang_demangle (const char *mangled, int option ATTRIBUTE_UNUSED)
1569 {
1570   string decl;
1571   char *demangled = NULL;
1572 
1573   if (mangled == NULL || *mangled == '\0')
1574     return NULL;
1575 
1576   if (strncmp (mangled, "_D", 2) != 0)
1577     return NULL;
1578 
1579   string_init (&decl);
1580 
1581   if (strcmp (mangled, "_Dmain") == 0)
1582     {
1583       string_append (&decl, "D main");
1584     }
1585   else
1586     {
1587       mangled += 2;
1588 
1589       if (dlang_parse_symbol (&decl, mangled, dlang_top_level) == NULL)
1590 	string_delete (&decl);
1591     }
1592 
1593   if (string_length (&decl) > 0)
1594     {
1595       string_need (&decl, 1);
1596       *(decl.p) = '\0';
1597       demangled = decl.b;
1598     }
1599 
1600   return demangled;
1601 }
1602 
1603