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