1 /* Demangler for the D programming language
2    Copyright 2014 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 and strtod 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 extern double strtod (const char *nptr, char **endptr);
48 #endif
49 
50 #include <demangle.h>
51 #include "libiberty.h"
52 
53 /* A mini string-handling package */
54 
55 typedef struct string		/* Beware: these aren't required to be */
56 {				/*  '\0' terminated.  */
57   char *b;			/* pointer to start of string */
58   char *p;			/* pointer after last character */
59   char *e;			/* pointer after end of allocated space */
60 } string;
61 
62 static void
string_need(string * s,int n)63 string_need (string *s, int n)
64 {
65   int tem;
66 
67   if (s->b == NULL)
68     {
69       if (n < 32)
70 	{
71 	  n = 32;
72 	}
73       s->p = s->b = XNEWVEC (char, n);
74       s->e = s->b + n;
75     }
76   else if (s->e - s->p < n)
77     {
78       tem = s->p - s->b;
79       n += tem;
80       n *= 2;
81       s->b = XRESIZEVEC (char, s->b, n);
82       s->p = s->b + tem;
83       s->e = s->b + n;
84     }
85 }
86 
87 static void
string_delete(string * s)88 string_delete (string *s)
89 {
90   if (s->b != NULL)
91     {
92       XDELETEVEC (s->b);
93       s->b = s->e = s->p = NULL;
94     }
95 }
96 
97 static void
string_init(string * s)98 string_init (string *s)
99 {
100   s->b = s->p = s->e = NULL;
101 }
102 
103 static int
string_length(string * s)104 string_length (string *s)
105 {
106   if (s->p == s->b)
107     {
108       return 0;
109     }
110   return s->p - s->b;
111 }
112 
113 static void
string_setlength(string * s,int n)114 string_setlength (string *s, int n)
115 {
116   if (n - string_length (s) < 0)
117     {
118       s->p = s->b + n;
119     }
120 }
121 
122 static void
string_append(string * p,const char * s)123 string_append (string *p, const char *s)
124 {
125   int n = strlen (s);
126   string_need (p, n);
127   memcpy (p->p, s, n);
128   p->p += n;
129 }
130 
131 static void
string_appendn(string * p,const char * s,int n)132 string_appendn (string *p, const char *s, int n)
133 {
134   if (n != 0)
135     {
136       string_need (p, n);
137       memcpy (p->p, s, n);
138       p->p += n;
139     }
140 }
141 
142 static void
string_prependn(string * p,const char * s,int n)143 string_prependn (string *p, const char *s, int n)
144 {
145   char *q;
146 
147   if (n != 0)
148     {
149       string_need (p, n);
150       for (q = p->p - 1; q >= p->b; q--)
151 	{
152 	  q[n] = q[0];
153 	}
154       memcpy (p->b, s, n);
155       p->p += n;
156     }
157 }
158 
159 static void
string_prepend(string * p,const char * s)160 string_prepend (string *p, const char *s)
161 {
162   if (s != NULL && *s != '\0')
163     {
164       string_prependn (p, s, strlen (s));
165     }
166 }
167 
168 /* Prototypes for forward referenced functions */
169 static const char *dlang_function_args (string *, const char *);
170 
171 static const char *dlang_type (string *, const char *);
172 
173 static const char *dlang_value (string *, const char *, const char *, char);
174 
175 static const char *dlang_parse_symbol (string *, const char *);
176 
177 static const char *dlang_parse_tuple (string *, const char *);
178 
179 static const char *dlang_parse_template (string *, const char *, long);
180 
181 
182 /* Demangle the calling convention from MANGLED and append it to DECL.
183    Return the remaining string on success or NULL on failure.  */
184 static const char *
dlang_call_convention(string * decl,const char * mangled)185 dlang_call_convention (string *decl, const char *mangled)
186 {
187   if (mangled == NULL || *mangled == '\0')
188     return mangled;
189 
190   switch (*mangled)
191     {
192     case 'F': /* (D) */
193       mangled++;
194       break;
195     case 'U': /* (C) */
196       mangled++;
197       string_append (decl, "extern(C) ");
198       break;
199     case 'W': /* (Windows) */
200       mangled++;
201       string_append (decl, "extern(Windows) ");
202       break;
203     case 'V': /* (Pascal) */
204       mangled++;
205       string_append (decl, "extern(Pascal) ");
206       break;
207     case 'R': /* (C++) */
208       mangled++;
209       string_append (decl, "extern(C++) ");
210       break;
211     default:
212       return NULL;
213     }
214 
215   return mangled;
216 }
217 
218 /* Demangle the D function attributes from MANGLED and append it to DECL.
219    Return the remaining string on success or NULL on failure.  */
220 static const char *
dlang_attributes(string * decl,const char * mangled)221 dlang_attributes (string *decl, const char *mangled)
222 {
223   if (mangled == NULL || *mangled == '\0')
224     return mangled;
225 
226   while (*mangled == 'N')
227     {
228       mangled++;
229       switch (*mangled)
230 	{
231 	case 'a': /* pure */
232 	  mangled++;
233 	  string_append (decl, "pure ");
234 	  continue;
235 	case 'b': /* nothrow */
236 	  mangled++;
237 	  string_append (decl, "nothrow ");
238 	  continue;
239 	case 'c': /* ref */
240 	  mangled++;
241 	  string_append (decl, "ref ");
242 	  continue;
243 	case 'd': /* @property */
244 	  mangled++;
245 	  string_append (decl, "@property ");
246 	  continue;
247 	case 'e': /* @trusted */
248 	  mangled++;
249 	  string_append (decl, "@trusted ");
250 	  continue;
251 	case 'f': /* @safe */
252 	  mangled++;
253 	  string_append (decl, "@safe ");
254 	  continue;
255 	case 'g':
256 	case 'h':
257 	  /* inout parameter is represented as 'Ng'.
258 	     vector parameter is represented as 'Nh'.
259 	     If we see this, then we know we're really in the
260 	     parameter list.  Rewind and break.  */
261 	  mangled--;
262 	  break;
263 	case 'i': /* @nogc */
264 	  mangled++;
265 	  string_append (decl, "@nogc ");
266 	  continue;
267 	}
268       break;
269     }
270 
271   return mangled;
272 }
273 
274 /* Demangle the function type from MANGLED and append it to DECL.
275    Return the remaining string on success or NULL on failure.  */
276 static const char *
dlang_function_type(string * decl,const char * mangled)277 dlang_function_type (string *decl, const char *mangled)
278 {
279   string attr, args, type;
280   size_t szattr, szargs, sztype;
281 
282   if (mangled == NULL || *mangled == '\0')
283     return mangled;
284 
285   /* The order of the mangled string is:
286 	CallConvention FuncAttrs Arguments ArgClose Type
287 
288      The demangled string is re-ordered as:
289 	CallConvention Type Arguments FuncAttrs
290    */
291   string_init (&attr);
292   string_init (&args);
293   string_init (&type);
294 
295   /* Function call convention.  */
296   mangled = dlang_call_convention (decl, mangled);
297 
298   /* Function attributes.  */
299   mangled = dlang_attributes (&attr, mangled);
300   szattr = string_length (&attr);
301 
302   /* Function arguments.  */
303   mangled = dlang_function_args (&args, mangled);
304   szargs = string_length (&args);
305 
306   /* Function return type.  */
307   mangled = dlang_type (&type, mangled);
308   sztype = string_length (&type);
309 
310   /* Append to decl in order. */
311   string_appendn (decl, type.b, sztype);
312   string_append (decl, "(");
313   string_appendn (decl, args.b, szargs);
314   string_append (decl, ") ");
315   string_appendn (decl, attr.b, szattr);
316 
317   string_delete (&attr);
318   string_delete (&args);
319   string_delete (&type);
320   return mangled;
321 }
322 
323 /* Demangle the argument list from MANGLED and append it to DECL.
324    Return the remaining string on success or NULL on failure.  */
325 static const char *
dlang_function_args(string * decl,const char * mangled)326 dlang_function_args (string *decl, const char *mangled)
327 {
328   size_t n = 0;
329 
330   while (mangled && *mangled != '\0')
331     {
332       switch (*mangled)
333 	{
334 	case 'X': /* (variadic T t...) style.  */
335 	  mangled++;
336 	  string_append (decl, "...");
337 	  return mangled;
338 	case 'Y': /* (variadic T t, ...) style.  */
339 	  mangled++;
340 	  string_append (decl, ", ...");
341 	  return mangled;
342 	case 'Z': /* Normal function.  */
343 	  mangled++;
344 	  return mangled;
345 	}
346 
347       if (n++)
348 	string_append (decl, ", ");
349 
350       if (*mangled == 'M') /* scope(T) */
351 	{
352 	  mangled++;
353 	  string_append (decl, "scope ");
354 	}
355 
356       switch (*mangled)
357 	{
358 	case 'J': /* out(T) */
359 	  mangled++;
360 	  string_append (decl, "out ");
361 	  break;
362 	case 'K': /* ref(T) */
363 	  mangled++;
364 	  string_append (decl, "ref ");
365 	  break;
366 	case 'L': /* lazy(T) */
367 	  mangled++;
368 	  string_append (decl, "lazy ");
369 	  break;
370 	}
371       mangled = dlang_type (decl, mangled);
372     }
373 
374   return mangled;
375 }
376 
377 /* Demangle the type from MANGLED and append it to DECL.
378    Return the remaining string on success or NULL on failure.  */
379 static const char *
dlang_type(string * decl,const char * mangled)380 dlang_type (string *decl, const char *mangled)
381 {
382   if (mangled == NULL || *mangled == '\0')
383     return mangled;
384 
385   switch (*mangled)
386     {
387     case 'O': /* shared(T) */
388       mangled++;
389       string_append (decl, "shared(");
390       mangled = dlang_type (decl, mangled);
391       string_append (decl, ")");
392       return mangled;
393     case 'x': /* const(T) */
394       mangled++;
395       string_append (decl, "const(");
396       mangled = dlang_type (decl, mangled);
397       string_append (decl, ")");
398       return mangled;
399     case 'y': /* immutable(T) */
400       mangled++;
401       string_append (decl, "immutable(");
402       mangled = dlang_type (decl, mangled);
403       string_append (decl, ")");
404       return mangled;
405     case 'N':
406       mangled++;
407       if (*mangled == 'g') /* wild(T) */
408 	{
409 	  mangled++;
410 	  string_append (decl, "inout(");
411 	  mangled = dlang_type (decl, mangled);
412 	  string_append (decl, ")");
413 	  return mangled;
414 	}
415       else if (*mangled == 'h') /* vector(T) */
416 	{
417 	  mangled++;
418 	  string_append (decl, "__vector(");
419 	  mangled = dlang_type (decl, mangled);
420 	  string_append (decl, ")");
421 	  return mangled;
422 	}
423       else
424 	return NULL;
425     case 'A': /* dynamic array (T[]) */
426       mangled++;
427       mangled = dlang_type (decl, mangled);
428       string_append (decl, "[]");
429       return mangled;
430     case 'G': /* static array (T[N]) */
431     {
432       const char *numptr;
433       size_t num = 0;
434       mangled++;
435 
436       numptr = mangled;
437       while (ISDIGIT (*mangled))
438 	{
439 	  num++;
440 	  mangled++;
441 	}
442       mangled = dlang_type (decl, mangled);
443       string_append (decl, "[");
444       string_appendn (decl, numptr, num);
445       string_append (decl, "]");
446       return mangled;
447     }
448     case 'H': /* associative array (T[T]) */
449     {
450       string type;
451       size_t sztype;
452       mangled++;
453 
454       string_init (&type);
455       mangled = dlang_type (&type, mangled);
456       sztype = string_length (&type);
457 
458       mangled = dlang_type (decl, mangled);
459       string_append (decl, "[");
460       string_appendn (decl, type.b, sztype);
461       string_append (decl, "]");
462 
463       string_delete (&type);
464       return mangled;
465     }
466     case 'P': /* pointer (T*) */
467       mangled++;
468       mangled = dlang_type (decl, mangled);
469       string_append (decl, "*");
470       return mangled;
471     case 'I': /* ident T */
472     case 'C': /* class T */
473     case 'S': /* struct T */
474     case 'E': /* enum T */
475     case 'T': /* typedef T */
476       mangled++;
477       return dlang_parse_symbol (decl, mangled);
478     case 'D': /* delegate T */
479       mangled++;
480       mangled = dlang_function_type (decl, mangled);
481       string_append (decl, "delegate");
482       return mangled;
483     case 'B': /* tuple T */
484       mangled++;
485       return dlang_parse_tuple (decl, mangled);
486 
487     /* Function types */
488     case 'F': case 'U': case 'W':
489     case 'V': case 'R':
490       mangled = dlang_function_type (decl, mangled);
491       string_append (decl, "function");
492       return mangled;
493 
494     /* Basic types */
495     case 'n':
496       mangled++;
497       string_append (decl, "none");
498       return mangled;
499     case 'v':
500       mangled++;
501       string_append (decl, "void");
502       return mangled;
503     case 'g':
504       mangled++;
505       string_append (decl, "byte");
506       return mangled;
507     case 'h':
508       mangled++;
509       string_append (decl, "ubyte");
510       return mangled;
511     case 's':
512       mangled++;
513       string_append (decl, "short");
514       return mangled;
515     case 't':
516       mangled++;
517       string_append (decl, "ushort");
518       return mangled;
519     case 'i':
520       mangled++;
521       string_append (decl, "int");
522       return mangled;
523     case 'k':
524       mangled++;
525       string_append (decl, "uint");
526       return mangled;
527     case 'l':
528       mangled++;
529       string_append (decl, "long");
530       return mangled;
531     case 'm':
532       mangled++;
533       string_append (decl, "ulong");
534       return mangled;
535     case 'f':
536       mangled++;
537       string_append (decl, "float");
538       return mangled;
539     case 'd':
540       mangled++;
541       string_append (decl, "double");
542       return mangled;
543     case 'e':
544       mangled++;
545       string_append (decl, "real");
546       return mangled;
547 
548     /* Imaginary and Complex types */
549     case 'o':
550       mangled++;
551       string_append (decl, "ifloat");
552       return mangled;
553     case 'p':
554       mangled++;
555       string_append (decl, "idouble");
556       return mangled;
557     case 'j':
558       mangled++;
559       string_append (decl, "ireal");
560       return mangled;
561     case 'q':
562       mangled++;
563       string_append (decl, "cfloat");
564       return mangled;
565     case 'r':
566       mangled++;
567       string_append (decl, "cdouble");
568       return mangled;
569     case 'c':
570       mangled++;
571       string_append (decl, "creal");
572       return mangled;
573 
574     /* Other types */
575     case 'b':
576       mangled++;
577       string_append (decl, "bool");
578       return mangled;
579     case 'a':
580       mangled++;
581       string_append (decl, "char");
582       return mangled;
583     case 'u':
584       mangled++;
585       string_append (decl, "wchar");
586       return mangled;
587     case 'w':
588       mangled++;
589       string_append (decl, "dchar");
590       return mangled;
591 
592     default: /* unhandled */
593       return NULL;
594     }
595 }
596 
597 /* Extract the identifier from MANGLED and append it to DECL.
598    Return the remaining string on success or NULL on failure.  */
599 static const char *
dlang_identifier(string * decl,const char * mangled)600 dlang_identifier (string *decl, const char *mangled)
601 {
602   if (mangled == NULL || *mangled == '\0')
603     return mangled;
604 
605   if (ISDIGIT (*mangled))
606     {
607       char *endptr;
608       long i = strtol (mangled, &endptr, 10);
609 
610       if (endptr == NULL || i <= 0 || strlen (endptr) < (size_t) i)
611 	return NULL;
612 
613       mangled = endptr;
614 
615       /* May be a template instance.  */
616       if (i >= 5 && strncmp (mangled, "__T", 3) == 0)
617 	{
618 	  /* Template symbol.  */
619 	  if (ISDIGIT (mangled[3]) && mangled[3] != '0')
620 	    return dlang_parse_template (decl, mangled, i);
621 
622 	  return NULL;
623 	}
624 
625       if (strncmp (mangled, "__ctor", i) == 0)
626 	{
627 	  /* Constructor symbol for a class/struct.  */
628 	  string_append (decl, "this");
629 	  mangled += i;
630 	  return mangled;
631 	}
632       else if (strncmp (mangled, "__dtor", i) == 0)
633 	{
634 	  /* Destructor symbol for a class/struct.  */
635 	  string_append (decl, "~this");
636 	  mangled += i;
637 	  return mangled;
638 	}
639       else if (strncmp (mangled, "__postblit", i) == 0)
640 	{
641 	  /* Postblit symbol for a struct.  */
642 	  string_append (decl, "this(this)");
643 	  mangled += i;
644 	  return mangled;
645 	}
646       else if (strncmp (mangled, "__initZ", i+1) == 0)
647 	{
648 	  /* The static initialiser for a given symbol.  */
649 	  string_append (decl, "init$");
650 	  mangled += i + 1;
651 	  return mangled;
652 	}
653       else if (strncmp (mangled, "__ClassZ", i+1) == 0)
654 	{
655 	  /* The classinfo symbol for a given class.  */
656 	  string_prepend (decl, "ClassInfo for ");
657 	  string_setlength (decl, string_length (decl) - 1);
658 	  mangled += i + 1;
659 	  return mangled;
660 	}
661       else if (strncmp (mangled, "__vtblZ", i+1) == 0)
662 	{
663 	  /* The vtable symbol for a given class.  */
664 	  string_prepend (decl, "vtable for ");
665 	  string_setlength (decl, string_length (decl) - 1);
666 	  mangled += i + 1;
667 	  return mangled;
668 	}
669       else if (strncmp (mangled, "__InterfaceZ", i+1) == 0)
670 	{
671 	  /* The interface symbol for a given class.  */
672 	  string_prepend (decl, "Interface for ");
673 	  string_setlength (decl, string_length (decl) - 1);
674 	  mangled += i + 1;
675 	  return mangled;
676 	}
677       else if (strncmp (mangled, "__ModuleInfoZ", i+1) == 0)
678 	{
679 	  /* The ModuleInfo symbol for a given module.  */
680 	  string_prepend (decl, "ModuleInfo for ");
681 	  string_setlength (decl, string_length (decl) - 1);
682 	  mangled += i + 1;
683 	  return mangled;
684 	}
685 
686       string_appendn (decl, mangled, i);
687       mangled += i;
688     }
689   else
690     return NULL;
691 
692   return mangled;
693 }
694 
695 /* Extract the integer value from MANGLED and append it to DECL,
696    where TYPE is the type it should be represented as.
697    Return the remaining string on success or NULL on failure.  */
698 static const char *
dlang_parse_integer(string * decl,const char * mangled,char type)699 dlang_parse_integer (string *decl, const char *mangled, char type)
700 {
701   if (type == 'a' || type == 'u' || type == 'w')
702     {
703       /* Parse character value.  */
704       char value[10];
705       int pos = 10;
706       int width = 0;
707       char *endptr;
708       long val = strtol (mangled, &endptr, 10);
709 
710       if (endptr == NULL || val < 0)
711 	return NULL;
712 
713       string_append (decl, "'");
714 
715       if (type == 'a' && val >= 0x20 && val < 0x7F)
716 	{
717 	  /* Represent as a character literal.  */
718 	  char c = (char) val;
719 	  string_appendn (decl, &c, 1);
720 	}
721       else
722 	{
723 	  /* Represent as a hexadecimal value.  */
724 	  switch (type)
725 	    {
726 	    case 'a': /* char */
727 	      string_append (decl, "\\x");
728 	      width = 2;
729 	      break;
730 	    case 'u': /* wchar */
731 	      string_append (decl, "\\u");
732 	      width = 4;
733 	      break;
734 	    case 'w': /* dchar */
735 	      string_append (decl, "\\U");
736 	      width = 8;
737 	      break;
738 	    }
739 
740 	  while (val > 0)
741 	    {
742 	      int digit = val % 16;
743 
744 	      if (digit < 10)
745 		value[--pos] = (char)(digit + '0');
746 	      else
747 		value[--pos] = (char)((digit - 10) + 'a');
748 
749 	      val /= 16;
750 	      width--;
751 	    }
752 
753 	  for (; width > 0; width--)
754 	    value[--pos] = '0';
755 
756 	  string_appendn (decl, &(value[pos]), 10 - pos);
757 	}
758       string_append (decl, "'");
759       mangled = endptr;
760     }
761   else if (type == 'b')
762     {
763       /* Parse boolean value.  */
764       char *endptr;
765       long val = strtol (mangled, &endptr, 10);
766 
767       if (endptr == NULL || val < 0)
768 	return NULL;
769 
770       string_append (decl, val ? "true" : "false");
771       mangled = endptr;
772     }
773   else
774     {
775       /* Parse integer value.  */
776       const char *numptr = mangled;
777       size_t num = 0;
778 
779       while (ISDIGIT (*mangled))
780 	{
781 	  num++;
782 	  mangled++;
783 	}
784       string_appendn (decl, numptr, num);
785 
786       /* Append suffix.  */
787       switch (type)
788 	{
789 	case 'h': /* ubyte */
790 	case 't': /* ushort */
791 	case 'k': /* uint */
792 	  string_append (decl, "u");
793 	  break;
794 	case 'l': /* long */
795 	  string_append (decl, "L");
796 	  break;
797 	case 'm': /* ulong */
798 	  string_append (decl, "uL");
799 	  break;
800 	}
801     }
802 
803   return mangled;
804 }
805 
806 /* Extract the floating-point value from MANGLED and append it to DECL.
807    Return the remaining string on success or NULL on failure.  */
808 static const char *
dlang_parse_real(string * decl,const char * mangled)809 dlang_parse_real (string *decl, const char *mangled)
810 {
811   char buffer[64];
812   int len = 0;
813   double value;
814   char *endptr;
815 
816   /* Handle NAN and +-INF.  */
817   if (strncmp (mangled, "NAN", 3) == 0)
818     {
819       string_append (decl, "NaN");
820       mangled += 3;
821       return mangled;
822     }
823   else if (strncmp (mangled, "INF", 3) == 0)
824     {
825       string_append (decl, "Inf");
826       mangled += 3;
827       return mangled;
828     }
829   else if (strncmp (mangled, "NINF", 4) == 0)
830     {
831       string_append (decl, "-Inf");
832       mangled += 4;
833       return mangled;
834     }
835 
836   /* Hexadecimal prefix and leading bit.  */
837   if (*mangled == 'N')
838     {
839       buffer[len++] = '-';
840       mangled++;
841     }
842 
843   if (!ISXDIGIT (*mangled))
844     return NULL;
845 
846   buffer[len++] = '0';
847   buffer[len++] = 'x';
848   buffer[len++] = *mangled;
849   buffer[len++] = '.';
850   mangled++;
851 
852   /* Significand.  */
853   while (ISXDIGIT (*mangled))
854     {
855       buffer[len++] = *mangled;
856       mangled++;
857     }
858 
859   /* Exponent.  */
860   if (*mangled != 'P')
861     return NULL;
862 
863   buffer[len++] = 'p';
864   mangled++;
865 
866   if (*mangled == 'N')
867     {
868       buffer[len++] = '-';
869       mangled++;
870     }
871 
872   while (ISDIGIT (*mangled))
873     {
874       buffer[len++] = *mangled;
875       mangled++;
876     }
877 
878   /* Convert buffer from hexadecimal to floating-point.  */
879   buffer[len] = '\0';
880   value = strtod (buffer, &endptr);
881 
882   if (endptr == NULL || endptr != (buffer + len))
883     return NULL;
884 
885   len = snprintf (buffer, sizeof(buffer), "%#g", value);
886   string_appendn (decl, buffer, len);
887   return mangled;
888 }
889 
890 /* Convert VAL from an ascii hexdigit to value.  */
891 static char
ascii2hex(char val)892 ascii2hex (char val)
893 {
894   if (val >= 'a' && val <= 'f')
895     return (val - 'a' + 10);
896 
897   if (val >= 'A' && val <= 'F')
898     return (val - 'A' + 10);
899 
900   if (val >= '0' && val <= '9')
901     return (val - '0');
902 
903   return 0;
904 }
905 
906 /* Extract the string value from MANGLED and append it to DECL.
907    Return the remaining string on success or NULL on failure.  */
908 static const char *
dlang_parse_string(string * decl,const char * mangled)909 dlang_parse_string (string *decl, const char *mangled)
910 {
911   char type = *mangled;
912   char *endptr;
913   long len;
914 
915   mangled++;
916   len = strtol (mangled, &endptr, 10);
917 
918   if (endptr == NULL || len < 0)
919     return NULL;
920 
921   mangled = endptr;
922   if (*mangled != '_')
923     return NULL;
924 
925   mangled++;
926   string_append (decl, "\"");
927   while (len--)
928     {
929       if (ISXDIGIT (mangled[0]) && ISXDIGIT (mangled[1]))
930 	{
931 	  char a = ascii2hex (mangled[0]);
932 	  char b = ascii2hex (mangled[1]);
933 	  char val = (a << 4) | b;
934 	  string_appendn (decl, &val, 1);
935 	}
936       else
937 	return NULL;
938 
939       mangled += 2;
940     }
941   string_append (decl, "\"");
942 
943   if (type != 'a')
944     string_appendn (decl, &type, 1);
945 
946   return mangled;
947 }
948 
949 /* Extract the static array value from MANGLED and append it to DECL.
950    Return the remaining string on success or NULL on failure.  */
951 static const char *
dlang_parse_arrayliteral(string * decl,const char * mangled)952 dlang_parse_arrayliteral (string *decl, const char *mangled)
953 {
954   char *endptr;
955   long elements = strtol (mangled, &endptr, 10);
956 
957   if (endptr == NULL || elements < 0)
958     return NULL;
959 
960   mangled = endptr;
961   string_append (decl, "[");
962   while (elements--)
963     {
964       mangled = dlang_value (decl, mangled, NULL, '\0');
965       if (elements != 0)
966 	string_append (decl, ", ");
967     }
968 
969   string_append (decl, "]");
970   return mangled;
971 }
972 
973 /* Extract the associative array 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_assocarray(string * decl,const char * mangled)976 dlang_parse_assocarray (string *decl, const char *mangled)
977 {
978   char *endptr;
979   long elements = strtol (mangled, &endptr, 10);
980 
981   if (endptr == NULL || elements < 0)
982     return NULL;
983 
984   mangled = endptr;
985   string_append (decl, "[");
986   while (elements--)
987     {
988       mangled = dlang_value (decl, mangled, NULL, '\0');
989       string_append (decl, ":");
990       mangled = dlang_value (decl, mangled, NULL, '\0');
991 
992       if (elements != 0)
993 	string_append (decl, ", ");
994     }
995 
996   string_append (decl, "]");
997   return mangled;
998 }
999 
1000 /* Extract the struct literal value for NAME from MANGLED and append it to DECL.
1001    Return the remaining string on success or NULL on failure.  */
1002 static const char *
dlang_parse_structlit(string * decl,const char * mangled,const char * name)1003 dlang_parse_structlit (string *decl, const char *mangled, const char *name)
1004 {
1005   char *endptr;
1006   long args = strtol (mangled, &endptr, 10);
1007 
1008   if (endptr == NULL || args < 0)
1009     return NULL;
1010 
1011   mangled = endptr;
1012   if (name != NULL)
1013     string_append (decl, name);
1014 
1015   string_append (decl, "(");
1016   while (args--)
1017     {
1018       mangled = dlang_value (decl, mangled, NULL, '\0');
1019       if (args != 0)
1020 	string_append (decl, ", ");
1021     }
1022 
1023   string_append (decl, ")");
1024   return mangled;
1025 }
1026 
1027 /* Extract the value from MANGLED and append it to DECL.
1028    Return the remaining string on success or NULL on failure.  */
1029 static const char *
dlang_value(string * decl,const char * mangled,const char * name,char type)1030 dlang_value (string *decl, const char *mangled, const char *name, char type)
1031 {
1032   if (mangled == NULL || *mangled == '\0')
1033     return mangled;
1034 
1035   switch (*mangled)
1036     {
1037       /* Null value.  */
1038     case 'n':
1039       mangled++;
1040       string_append (decl, "null");
1041       break;
1042 
1043       /* Integral values.  */
1044     case 'N':
1045       mangled++;
1046       string_append (decl, "-");
1047       mangled = dlang_parse_integer (decl, mangled, type);
1048       break;
1049 
1050     case 'i':
1051       mangled++;
1052       if (*mangled < '0' || *mangled > '9')
1053 	return NULL;
1054       /* Fall through */
1055     case '0': case '1': case '2': case '3': case '4':
1056     case '5': case '6': case '7': case '8': case '9':
1057       mangled = dlang_parse_integer (decl, mangled, type);
1058       break;
1059 
1060       /* Real value.  */
1061     case 'e':
1062       mangled++;
1063       mangled = dlang_parse_real (decl, mangled);
1064       break;
1065 
1066       /* Complex value.  */
1067     case 'c':
1068       mangled++;
1069       mangled = dlang_parse_real (decl, mangled);
1070       string_append (decl, "+");
1071       if (mangled == NULL || *mangled != 'c')
1072 	return NULL;
1073       mangled++;
1074       mangled = dlang_parse_real (decl, mangled);
1075       string_append (decl, "i");
1076       break;
1077 
1078       /* String values.  */
1079     case 'a': /* UTF8 */
1080     case 'w': /* UTF16 */
1081     case 'd': /* UTF32 */
1082       mangled = dlang_parse_string (decl, mangled);
1083       break;
1084 
1085       /* Array values.  */
1086     case 'A':
1087       mangled++;
1088       if (type == 'H')
1089 	mangled = dlang_parse_assocarray (decl, mangled);
1090       else
1091 	mangled = dlang_parse_arrayliteral (decl, mangled);
1092       break;
1093 
1094       /* Struct values.  */
1095     case 'S':
1096       mangled++;
1097       mangled = dlang_parse_structlit (decl, mangled, name);
1098       break;
1099 
1100     default:
1101       return NULL;
1102     }
1103 
1104   return mangled;
1105 }
1106 
1107 static int
dlang_call_convention_p(const char * mangled)1108 dlang_call_convention_p (const char *mangled)
1109 {
1110   size_t i;
1111 
1112   switch (*mangled)
1113     {
1114     case 'F': case 'U': case 'V':
1115     case 'W': case 'R':
1116       return 1;
1117 
1118     case 'M': /* Prefix for functions needing 'this' */
1119       i = 1;
1120       if (mangled[i] == 'x')
1121 	i++;
1122 
1123       switch (mangled[i])
1124 	{
1125 	case 'F': case 'U': case 'V':
1126 	case 'W': case 'R':
1127 	  return 1;
1128 	}
1129 
1130     default:
1131       return 0;
1132     }
1133 }
1134 
1135 /* Extract and demangle the symbol in MANGLED and append it to DECL.
1136    Returns the remaining signature on success or NULL on failure.  */
1137 static const char *
dlang_parse_symbol(string * decl,const char * mangled)1138 dlang_parse_symbol (string *decl, const char *mangled)
1139 {
1140   size_t n = 0;
1141   do
1142     {
1143       if (n++)
1144 	string_append (decl, ".");
1145 
1146       mangled = dlang_identifier (decl, mangled);
1147 
1148       if (mangled && dlang_call_convention_p (mangled))
1149 	{
1150 	  int saved;
1151 
1152 	  /* Skip over 'this' parameter.  */
1153 	  if (*mangled == 'M')
1154 	    mangled += (mangled[1] == 'x') ? 2 : 1;
1155 
1156 	  /* Skip over calling convention and attributes in qualified name.  */
1157 	  saved = string_length (decl);
1158 	  mangled = dlang_call_convention (decl, mangled);
1159 	  mangled = dlang_attributes (decl, mangled);
1160 	  string_setlength (decl, saved);
1161 
1162 	  string_append (decl, "(");
1163 	  mangled = dlang_function_args (decl, mangled);
1164 	  string_append (decl, ")");
1165 
1166 	  /* Demangle the function return type as a kind of sanity test.  */
1167 	  if (mangled && !ISDIGIT (*mangled))
1168 	    {
1169 	      saved = string_length (decl);
1170 	      mangled = dlang_type (decl, mangled);
1171 	      string_setlength (decl, saved);
1172 	    }
1173 	}
1174     }
1175   while (mangled && ISDIGIT (*mangled));
1176 
1177   return mangled;
1178 }
1179 
1180 /* Demangle the tuple from MANGLED and append it to DECL.
1181    Return the remaining string on success or NULL on failure.  */
1182 static const char *
dlang_parse_tuple(string * decl,const char * mangled)1183 dlang_parse_tuple (string *decl, const char *mangled)
1184 {
1185   char *endptr;
1186   long elements = strtol (mangled, &endptr, 10);
1187 
1188   if (endptr == NULL || elements < 0)
1189     return NULL;
1190 
1191   mangled = endptr;
1192   string_append (decl, "Tuple!(");
1193 
1194   while (elements--)
1195     {
1196       mangled = dlang_type (decl, mangled);
1197       if (elements != 0)
1198 	string_append (decl, ", ");
1199     }
1200 
1201   string_append (decl, ")");
1202   return mangled;
1203 }
1204 
1205 /* Demangle the argument list from MANGLED and append it to DECL.
1206    Return the remaining string on success or NULL on failure.  */
1207 static const char *
dlang_template_args(string * decl,const char * mangled)1208 dlang_template_args (string *decl, const char *mangled)
1209 {
1210   size_t n = 0;
1211 
1212   while (mangled && *mangled != '\0')
1213     {
1214       switch (*mangled)
1215 	{
1216 	case 'Z': /* End of parameter list.  */
1217 	  mangled++;
1218 	  return mangled;
1219 	}
1220 
1221       if (n++)
1222 	string_append (decl, ", ");
1223 
1224       switch (*mangled)
1225 	{
1226 	case 'S': /* Symbol parameter.  */
1227 	  mangled++;
1228 	  mangled = dlang_parse_symbol (decl, mangled);
1229 	  break;
1230 	case 'T': /* Type parameter.  */
1231 	  mangled++;
1232 	  mangled = dlang_type (decl, mangled);
1233 	  break;
1234 	case 'V': /* Value parameter.  */
1235 	{
1236 	  string name;
1237 	  char type;
1238 
1239 	  /* Peek at the type.  */
1240 	  mangled++;
1241 	  type = *mangled;
1242 
1243 	  /* In the few instances where the type is actually desired in
1244 	     the output, it should precede the value from dlang_value.  */
1245 	  string_init (&name);
1246 	  mangled = dlang_type (&name, mangled);
1247 	  string_need (&name, 1);
1248 	  *(name.p) = '\0';
1249 
1250 	  mangled = dlang_value (decl, mangled, name.b, type);
1251 	  string_delete (&name);
1252 	  break;
1253 	}
1254 
1255 	default:
1256 	  return NULL;
1257 	}
1258     }
1259 
1260   return mangled;
1261 }
1262 
1263 /* Extract and demangle the template symbol in MANGLED, expected to
1264    be made up of LEN characters, and append it to DECL.
1265    Returns the remaining signature on success or NULL on failure.  */
1266 static const char *
dlang_parse_template(string * decl,const char * mangled,long len)1267 dlang_parse_template (string *decl, const char *mangled, long len)
1268 {
1269   const char *start = mangled;
1270 
1271   /* Template instance names have the types and values of its parameters
1272      encoded into it.
1273 
1274 	TemplateInstanceName:
1275 	    Number __T LName TemplateArgs Z
1276 		   ^
1277      The start pointer should be at the above location, and LEN should be
1278      the value of the decoded number.
1279    */
1280   if (strncmp (mangled, "__T", 3) != 0)
1281     return NULL;
1282 
1283   mangled += 3;
1284 
1285   /* Template identifier.  */
1286   mangled = dlang_identifier (decl, mangled);
1287 
1288   /* Template arguments.  */
1289   string_append (decl, "!(");
1290   mangled = dlang_template_args (decl, mangled);
1291   string_append (decl, ")");
1292 
1293   /* Check for template name length mismatch.  */
1294   if (mangled && (mangled - start) != len)
1295     return NULL;
1296 
1297   return mangled;
1298 }
1299 
1300 /* Extract and demangle the symbol in MANGLED.  Returns the demangled
1301    signature on success or NULL on failure.  */
1302 
1303 char *
dlang_demangle(const char * mangled,int option ATTRIBUTE_UNUSED)1304 dlang_demangle (const char *mangled, int option ATTRIBUTE_UNUSED)
1305 {
1306   string decl;
1307   char *demangled = NULL;
1308 
1309   if (mangled == NULL || *mangled == '\0')
1310     return NULL;
1311 
1312   if (strncmp (mangled, "_D", 2) != 0)
1313     return NULL;
1314 
1315   string_init (&decl);
1316 
1317   if (strcmp (mangled, "_Dmain") == 0)
1318     {
1319       string_append (&decl, "D main");
1320     }
1321   else
1322     {
1323       mangled += 2;
1324 
1325       if (dlang_parse_symbol (&decl, mangled) == NULL)
1326 	string_delete (&decl);
1327     }
1328 
1329   if (string_length (&decl) > 0)
1330     {
1331       string_need (&decl, 1);
1332       *(decl.p) = '\0';
1333       demangled = decl.b;
1334     }
1335 
1336   return demangled;
1337 }
1338 
1339