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