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