1 /* Demangler for the D programming language
2 Copyright 2014 Free Software Foundation, Inc.
3 Written by Iain Buclaw (ibuclaw@gdcproject.org)
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.
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
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.
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/>. */
29 /* This file exports one function; dlang_demangle.
31 This file imports strtol and strtold for decoding mangled literals. */
37 #include "safe-ctype.h"
39 #include <sys/types.h>
46 extern long strtol (const char *nptr
, char **endptr
, int base
);
47 extern long double strtold (const char *nptr
, char **endptr
);
51 #include "libiberty.h"
53 /* A mini string-handling package */
55 typedef struct string
/* Beware: these aren't required to be */
56 { /* '\0' terminated. */
57 char *b
; /* pointer to start of string */
58 char *p
; /* pointer after last character */
59 char *e
; /* pointer after end of allocated space */
63 string_need (string
*s
, int n
)
73 s
->p
= s
->b
= XNEWVEC (char, n
);
76 else if (s
->e
- s
->p
< n
)
81 s
->b
= XRESIZEVEC (char, s
->b
, n
);
88 string_delete (string
*s
)
93 s
->b
= s
->e
= s
->p
= NULL
;
98 string_init (string
*s
)
100 s
->b
= s
->p
= s
->e
= NULL
;
104 string_length (string
*s
)
114 string_setlength (string
*s
, int n
)
116 if (n
- string_length (s
) < 0)
123 string_append (string
*p
, const char *s
)
132 string_appendn (string
*p
, const char *s
, int n
)
143 string_prependn (string
*p
, const char *s
, int n
)
150 for (q
= p
->p
- 1; q
>= p
->b
; q
--)
160 string_prepend (string
*p
, const char *s
)
162 if (s
!= NULL
&& *s
!= '\0')
164 string_prependn (p
, s
, strlen (s
));
168 /* Prototypes for forward referenced functions */
169 static const char *dlang_function_args (string
*, const char *);
171 static const char *dlang_type (string
*, const char *);
173 static const char *dlang_value (string
*, const char *, const char *, char);
175 static const char *dlang_parse_symbol (string
*, const char *);
177 static const char *dlang_parse_tuple (string
*, const char *);
179 static const char *dlang_parse_template (string
*, const char *, long);
182 /* Demangle the calling convention from MANGLED and append it to DECL.
183 Return the remaining string on success or NULL on failure. */
185 dlang_call_convention (string
*decl
, const char *mangled
)
187 if (mangled
== NULL
|| *mangled
== '\0')
197 string_append (decl
, "extern(C) ");
199 case 'W': /* (Windows) */
201 string_append (decl
, "extern(Windows) ");
203 case 'V': /* (Pascal) */
205 string_append (decl
, "extern(Pascal) ");
207 case 'R': /* (C++) */
209 string_append (decl
, "extern(C++) ");
218 /* Demangle the D function attributes from MANGLED and append it to DECL.
219 Return the remaining string on success or NULL on failure. */
221 dlang_attributes (string
*decl
, const char *mangled
)
223 if (mangled
== NULL
|| *mangled
== '\0')
226 while (*mangled
== 'N')
233 string_append (decl
, "pure ");
235 case 'b': /* nothrow */
237 string_append (decl
, "nothrow ");
241 string_append (decl
, "ref ");
243 case 'd': /* @property */
245 string_append (decl
, "@property ");
247 case 'e': /* @trusted */
249 string_append (decl
, "@trusted ");
251 case 'f': /* @safe */
253 string_append (decl
, "@safe ");
257 /* inout parameter is represented as 'Ng'.
258 vector parameter is represented as 'Nh'.
259 If we see this, then we know we're really in the
260 parameter list. Rewind and break. */
263 case 'i': /* @nogc */
265 string_append (decl
, "@nogc ");
274 /* Demangle the function type from MANGLED and append it to DECL.
275 Return the remaining string on success or NULL on failure. */
277 dlang_function_type (string
*decl
, const char *mangled
)
279 string attr
, args
, type
;
280 size_t szattr
, szargs
, sztype
;
282 if (mangled
== NULL
|| *mangled
== '\0')
285 /* The order of the mangled string is:
286 CallConvention FuncAttrs Arguments ArgClose Type
288 The demangled string is re-ordered as:
289 CallConvention Type Arguments FuncAttrs
295 /* Function call convention. */
296 mangled
= dlang_call_convention (decl
, mangled
);
298 /* Function attributes. */
299 mangled
= dlang_attributes (&attr
, mangled
);
300 szattr
= string_length (&attr
);
302 /* Function arguments. */
303 mangled
= dlang_function_args (&args
, mangled
);
304 szargs
= string_length (&args
);
306 /* Function return type. */
307 mangled
= dlang_type (&type
, mangled
);
308 sztype
= string_length (&type
);
310 /* Append to decl in order. */
311 string_appendn (decl
, type
.b
, sztype
);
312 string_append (decl
, "(");
313 string_appendn (decl
, args
.b
, szargs
);
314 string_append (decl
, ") ");
315 string_appendn (decl
, attr
.b
, szattr
);
317 string_delete (&attr
);
318 string_delete (&args
);
319 string_delete (&type
);
323 /* Demangle the argument list from MANGLED and append it to DECL.
324 Return the remaining string on success or NULL on failure. */
326 dlang_function_args (string
*decl
, const char *mangled
)
330 while (mangled
&& *mangled
!= '\0')
334 case 'X': /* (variadic T t...) style. */
336 string_append (decl
, "...");
338 case 'Y': /* (variadic T t, ...) style. */
340 string_append (decl
, ", ...");
342 case 'Z': /* Normal function. */
348 string_append (decl
, ", ");
350 if (*mangled
== 'M') /* scope(T) */
353 string_append (decl
, "scope ");
358 case 'J': /* out(T) */
360 string_append (decl
, "out ");
362 case 'K': /* ref(T) */
364 string_append (decl
, "ref ");
366 case 'L': /* lazy(T) */
368 string_append (decl
, "lazy ");
371 mangled
= dlang_type (decl
, mangled
);
377 /* Demangle the type from MANGLED and append it to DECL.
378 Return the remaining string on success or NULL on failure. */
380 dlang_type (string
*decl
, const char *mangled
)
382 if (mangled
== NULL
|| *mangled
== '\0')
387 case 'O': /* shared(T) */
389 string_append (decl
, "shared(");
390 mangled
= dlang_type (decl
, mangled
);
391 string_append (decl
, ")");
393 case 'x': /* const(T) */
395 string_append (decl
, "const(");
396 mangled
= dlang_type (decl
, mangled
);
397 string_append (decl
, ")");
399 case 'y': /* immutable(T) */
401 string_append (decl
, "immutable(");
402 mangled
= dlang_type (decl
, mangled
);
403 string_append (decl
, ")");
407 if (*mangled
== 'g') /* wild(T) */
410 string_append (decl
, "inout(");
411 mangled
= dlang_type (decl
, mangled
);
412 string_append (decl
, ")");
415 else if (*mangled
== 'h') /* vector(T) */
418 string_append (decl
, "__vector(");
419 mangled
= dlang_type (decl
, mangled
);
420 string_append (decl
, ")");
425 case 'A': /* dynamic array (T[]) */
427 mangled
= dlang_type (decl
, mangled
);
428 string_append (decl
, "[]");
430 case 'G': /* static array (T[N]) */
437 while (ISDIGIT (*mangled
))
442 mangled
= dlang_type (decl
, mangled
);
443 string_append (decl
, "[");
444 string_appendn (decl
, numptr
, num
);
445 string_append (decl
, "]");
448 case 'H': /* associative array (T[T]) */
455 mangled
= dlang_type (&type
, mangled
);
456 sztype
= string_length (&type
);
458 mangled
= dlang_type (decl
, mangled
);
459 string_append (decl
, "[");
460 string_appendn (decl
, type
.b
, sztype
);
461 string_append (decl
, "]");
463 string_delete (&type
);
466 case 'P': /* pointer (T*) */
468 mangled
= dlang_type (decl
, mangled
);
469 string_append (decl
, "*");
471 case 'I': /* ident T */
472 case 'C': /* class T */
473 case 'S': /* struct T */
474 case 'E': /* enum T */
475 case 'T': /* typedef T */
477 return dlang_parse_symbol (decl
, mangled
);
478 case 'D': /* delegate T */
480 mangled
= dlang_function_type (decl
, mangled
);
481 string_append (decl
, "delegate");
483 case 'B': /* tuple T */
485 return dlang_parse_tuple (decl
, mangled
);
488 case 'F': case 'U': case 'W':
490 mangled
= dlang_function_type (decl
, mangled
);
491 string_append (decl
, "function");
497 string_append (decl
, "none");
501 string_append (decl
, "void");
505 string_append (decl
, "byte");
509 string_append (decl
, "ubyte");
513 string_append (decl
, "short");
517 string_append (decl
, "ushort");
521 string_append (decl
, "int");
525 string_append (decl
, "uint");
529 string_append (decl
, "long");
533 string_append (decl
, "ulong");
537 string_append (decl
, "float");
541 string_append (decl
, "double");
545 string_append (decl
, "real");
548 /* Imaginary and Complex types */
551 string_append (decl
, "ifloat");
555 string_append (decl
, "idouble");
559 string_append (decl
, "ireal");
563 string_append (decl
, "cfloat");
567 string_append (decl
, "cdouble");
571 string_append (decl
, "creal");
577 string_append (decl
, "bool");
581 string_append (decl
, "char");
585 string_append (decl
, "wchar");
589 string_append (decl
, "dchar");
592 default: /* unhandled */
597 /* Extract the identifier from MANGLED and append it to DECL.
598 Return the remaining string on success or NULL on failure. */
600 dlang_identifier (string
*decl
, const char *mangled
)
602 if (mangled
== NULL
|| *mangled
== '\0')
605 if (ISDIGIT (*mangled
))
608 long i
= strtol (mangled
, &endptr
, 10);
610 if (endptr
== NULL
|| i
<= 0 || strlen (endptr
) < (size_t) i
)
615 /* May be a template instance. */
616 if (i
>= 5 && strncmp (mangled
, "__T", 3) == 0)
618 /* Template symbol. */
619 if (ISDIGIT (mangled
[3]) && mangled
[3] != '0')
620 return dlang_parse_template (decl
, mangled
, i
);
625 if (strncmp (mangled
, "__ctor", i
) == 0)
627 /* Constructor symbol for a class/struct. */
628 string_append (decl
, "this");
632 else if (strncmp (mangled
, "__dtor", i
) == 0)
634 /* Destructor symbol for a class/struct. */
635 string_append (decl
, "~this");
639 else if (strncmp (mangled
, "__postblit", i
) == 0)
641 /* Postblit symbol for a struct. */
642 string_append (decl
, "this(this)");
646 else if (strncmp (mangled
, "__initZ", i
+1) == 0)
648 /* The static initialiser for a given symbol. */
649 string_append (decl
, "init$");
653 else if (strncmp (mangled
, "__ClassZ", i
+1) == 0)
655 /* The classinfo symbol for a given class. */
656 string_prepend (decl
, "ClassInfo for ");
657 string_setlength (decl
, string_length (decl
) - 1);
661 else if (strncmp (mangled
, "__vtblZ", i
+1) == 0)
663 /* The vtable symbol for a given class. */
664 string_prepend (decl
, "vtable for ");
665 string_setlength (decl
, string_length (decl
) - 1);
669 else if (strncmp (mangled
, "__InterfaceZ", i
+1) == 0)
671 /* The interface symbol for a given class. */
672 string_prepend (decl
, "Interface for ");
673 string_setlength (decl
, string_length (decl
) - 1);
677 else if (strncmp (mangled
, "__ModuleInfoZ", i
+1) == 0)
679 /* The ModuleInfo symbol for a given module. */
680 string_prepend (decl
, "ModuleInfo for ");
681 string_setlength (decl
, string_length (decl
) - 1);
686 string_appendn (decl
, mangled
, i
);
695 /* Extract the integer value from MANGLED and append it to DECL,
696 where TYPE is the type it should be represented as.
697 Return the remaining string on success or NULL on failure. */
699 dlang_parse_integer (string
*decl
, const char *mangled
, char type
)
701 if (type
== 'a' || type
== 'u' || type
== 'w')
703 /* Parse character value. */
708 long val
= strtol (mangled
, &endptr
, 10);
710 if (endptr
== NULL
|| val
< 0)
713 string_append (decl
, "'");
715 if (type
== 'a' && val
>= 0x20 && val
< 0x7F)
717 /* Represent as a character literal. */
719 string_appendn (decl
, &c
, 1);
723 /* Represent as a hexadecimal value. */
727 string_append (decl
, "\\x");
730 case 'u': /* wchar */
731 string_append (decl
, "\\u");
734 case 'w': /* dchar */
735 string_append (decl
, "\\U");
742 int digit
= val
% 16;
745 value
[--pos
] = (char)(digit
+ '0');
747 value
[--pos
] = (char)((digit
- 10) + 'a');
753 for (; width
> 0; width
--)
756 string_appendn (decl
, &(value
[pos
]), 10 - pos
);
758 string_append (decl
, "'");
761 else if (type
== 'b')
763 /* Parse boolean value. */
765 long val
= strtol (mangled
, &endptr
, 10);
767 if (endptr
== NULL
|| val
< 0)
770 string_append (decl
, val
? "true" : "false");
775 /* Parse integer value. */
776 const char *numptr
= mangled
;
779 while (ISDIGIT (*mangled
))
784 string_appendn (decl
, numptr
, num
);
789 case 'h': /* ubyte */
790 case 't': /* ushort */
792 string_append (decl
, "u");
795 string_append (decl
, "L");
797 case 'm': /* ulong */
798 string_append (decl
, "uL");
806 /* Extract the floating-point value from MANGLED and append it to DECL.
807 Return the remaining string on success or NULL on failure. */
809 dlang_parse_real (string
*decl
, const char *mangled
)
816 /* Handle NAN and +-INF. */
817 if (strncmp (mangled
, "NAN", 3) == 0)
819 string_append (decl
, "NaN");
823 else if (strncmp (mangled
, "INF", 3) == 0)
825 string_append (decl
, "Inf");
829 else if (strncmp (mangled
, "NINF", 4) == 0)
831 string_append (decl
, "-Inf");
836 /* Hexadecimal prefix and leading bit. */
843 if (!ISXDIGIT (*mangled
))
848 buffer
[len
++] = *mangled
;
853 while (ISXDIGIT (*mangled
))
855 buffer
[len
++] = *mangled
;
872 while (ISDIGIT (*mangled
))
874 buffer
[len
++] = *mangled
;
878 /* Convert buffer from hexadecimal to floating-point. */
880 value
= strtold (buffer
, &endptr
);
882 if (endptr
== NULL
|| endptr
!= (buffer
+ len
))
885 len
= snprintf (buffer
, sizeof(buffer
), "%#Lg", value
);
886 string_appendn (decl
, buffer
, len
);
890 /* Convert VAL from an ascii hexdigit to value. */
894 if (val
>= 'a' && val
<= 'f')
895 return (val
- 'a' + 10);
897 if (val
>= 'A' && val
<= 'F')
898 return (val
- 'A' + 10);
900 if (val
>= '0' && val
<= '9')
906 /* Extract the string value from MANGLED and append it to DECL.
907 Return the remaining string on success or NULL on failure. */
909 dlang_parse_string (string
*decl
, const char *mangled
)
911 char type
= *mangled
;
916 len
= strtol (mangled
, &endptr
, 10);
918 if (endptr
== NULL
|| len
< 0)
926 string_append (decl
, "\"");
929 if (ISXDIGIT (mangled
[0]) && ISXDIGIT (mangled
[1]))
931 char a
= ascii2hex (mangled
[0]);
932 char b
= ascii2hex (mangled
[1]);
933 char val
= (a
<< 4) | b
;
934 string_appendn (decl
, &val
, 1);
941 string_append (decl
, "\"");
944 string_appendn (decl
, &type
, 1);
949 /* Extract the static array value from MANGLED and append it to DECL.
950 Return the remaining string on success or NULL on failure. */
952 dlang_parse_arrayliteral (string
*decl
, const char *mangled
)
955 long elements
= strtol (mangled
, &endptr
, 10);
957 if (endptr
== NULL
|| elements
< 0)
961 string_append (decl
, "[");
964 mangled
= dlang_value (decl
, mangled
, NULL
, '\0');
966 string_append (decl
, ", ");
969 string_append (decl
, "]");
973 /* Extract the associative array value from MANGLED and append it to DECL.
974 Return the remaining string on success or NULL on failure. */
976 dlang_parse_assocarray (string
*decl
, const char *mangled
)
979 long elements
= strtol (mangled
, &endptr
, 10);
981 if (endptr
== NULL
|| elements
< 0)
985 string_append (decl
, "[");
988 mangled
= dlang_value (decl
, mangled
, NULL
, '\0');
989 string_append (decl
, ":");
990 mangled
= dlang_value (decl
, mangled
, NULL
, '\0');
993 string_append (decl
, ", ");
996 string_append (decl
, "]");
1000 /* Extract the struct literal value for NAME from MANGLED and append it to DECL.
1001 Return the remaining string on success or NULL on failure. */
1003 dlang_parse_structlit (string
*decl
, const char *mangled
, const char *name
)
1006 long args
= strtol (mangled
, &endptr
, 10);
1008 if (endptr
== NULL
|| args
< 0)
1013 string_append (decl
, name
);
1015 string_append (decl
, "(");
1018 mangled
= dlang_value (decl
, mangled
, NULL
, '\0');
1020 string_append (decl
, ", ");
1023 string_append (decl
, ")");
1027 /* Extract the value from MANGLED and append it to DECL.
1028 Return the remaining string on success or NULL on failure. */
1030 dlang_value (string
*decl
, const char *mangled
, const char *name
, char type
)
1032 if (mangled
== NULL
|| *mangled
== '\0')
1040 string_append (decl
, "null");
1043 /* Integral values. */
1046 string_append (decl
, "-");
1047 mangled
= dlang_parse_integer (decl
, mangled
, type
);
1052 if (*mangled
< '0' || *mangled
> '9')
1055 case '0': case '1': case '2': case '3': case '4':
1056 case '5': case '6': case '7': case '8': case '9':
1057 mangled
= dlang_parse_integer (decl
, mangled
, type
);
1063 mangled
= dlang_parse_real (decl
, mangled
);
1066 /* Complex value. */
1069 mangled
= dlang_parse_real (decl
, mangled
);
1070 string_append (decl
, "+");
1071 if (mangled
== NULL
|| *mangled
!= 'c')
1074 mangled
= dlang_parse_real (decl
, mangled
);
1075 string_append (decl
, "i");
1078 /* String values. */
1079 case 'a': /* UTF8 */
1080 case 'w': /* UTF16 */
1081 case 'd': /* UTF32 */
1082 mangled
= dlang_parse_string (decl
, mangled
);
1089 mangled
= dlang_parse_assocarray (decl
, mangled
);
1091 mangled
= dlang_parse_arrayliteral (decl
, mangled
);
1094 /* Struct values. */
1097 mangled
= dlang_parse_structlit (decl
, mangled
, name
);
1108 dlang_call_convention_p (const char *mangled
)
1114 case 'F': case 'U': case 'V':
1118 case 'M': /* Prefix for functions needing 'this' */
1120 if (mangled
[i
] == 'x')
1125 case 'F': case 'U': case 'V':
1135 /* Extract and demangle the symbol in MANGLED and append it to DECL.
1136 Returns the remaining signature on success or NULL on failure. */
1138 dlang_parse_symbol (string
*decl
, const char *mangled
)
1144 string_append (decl
, ".");
1146 mangled
= dlang_identifier (decl
, mangled
);
1148 if (mangled
&& dlang_call_convention_p (mangled
))
1152 /* Skip over 'this' parameter. */
1153 if (*mangled
== 'M')
1154 mangled
+= (mangled
[1] == 'x') ? 2 : 1;
1156 /* Skip over calling convention and attributes in qualified name. */
1157 saved
= string_length (decl
);
1158 mangled
= dlang_call_convention (decl
, mangled
);
1159 mangled
= dlang_attributes (decl
, mangled
);
1160 string_setlength (decl
, saved
);
1162 string_append (decl
, "(");
1163 mangled
= dlang_function_args (decl
, mangled
);
1164 string_append (decl
, ")");
1166 /* Demangle the function return type as a kind of sanity test. */
1167 if (mangled
&& !ISDIGIT (*mangled
))
1169 saved
= string_length (decl
);
1170 mangled
= dlang_type (decl
, mangled
);
1171 string_setlength (decl
, saved
);
1175 while (mangled
&& ISDIGIT (*mangled
));
1180 /* Demangle the tuple from MANGLED and append it to DECL.
1181 Return the remaining string on success or NULL on failure. */
1183 dlang_parse_tuple (string
*decl
, const char *mangled
)
1186 long elements
= strtol (mangled
, &endptr
, 10);
1188 if (endptr
== NULL
|| elements
< 0)
1192 string_append (decl
, "Tuple!(");
1196 mangled
= dlang_type (decl
, mangled
);
1198 string_append (decl
, ", ");
1201 string_append (decl
, ")");
1205 /* Demangle the argument list from MANGLED and append it to DECL.
1206 Return the remaining string on success or NULL on failure. */
1208 dlang_template_args (string
*decl
, const char *mangled
)
1212 while (mangled
&& *mangled
!= '\0')
1216 case 'Z': /* End of parameter list. */
1222 string_append (decl
, ", ");
1226 case 'S': /* Symbol parameter. */
1228 mangled
= dlang_parse_symbol (decl
, mangled
);
1230 case 'T': /* Type parameter. */
1232 mangled
= dlang_type (decl
, mangled
);
1234 case 'V': /* Value parameter. */
1239 /* Peek at the type. */
1243 /* In the few instances where the type is actually desired in
1244 the output, it should precede the value from dlang_value. */
1245 string_init (&name
);
1246 mangled
= dlang_type (&name
, mangled
);
1247 string_need (&name
, 1);
1250 mangled
= dlang_value (decl
, mangled
, name
.b
, type
);
1251 string_delete (&name
);
1263 /* Extract and demangle the template symbol in MANGLED, expected to
1264 be made up of LEN characters, and append it to DECL.
1265 Returns the remaining signature on success or NULL on failure. */
1267 dlang_parse_template (string
*decl
, const char *mangled
, long len
)
1269 const char *start
= mangled
;
1271 /* Template instance names have the types and values of its parameters
1274 TemplateInstanceName:
1275 Number __T LName TemplateArgs Z
1277 The start pointer should be at the above location, and LEN should be
1278 the value of the decoded number.
1280 if (strncmp (mangled
, "__T", 3) != 0)
1285 /* Template identifier. */
1286 mangled
= dlang_identifier (decl
, mangled
);
1288 /* Template arguments. */
1289 string_append (decl
, "!(");
1290 mangled
= dlang_template_args (decl
, mangled
);
1291 string_append (decl
, ")");
1293 /* Check for template name length mismatch. */
1294 if (mangled
&& (mangled
- start
) != len
)
1300 /* Extract and demangle the symbol in MANGLED. Returns the demangled
1301 signature on success or NULL on failure. */
1304 dlang_demangle (const char *mangled
, int option ATTRIBUTE_UNUSED
)
1307 char *demangled
= NULL
;
1309 if (mangled
== NULL
|| *mangled
== '\0')
1312 if (strncmp (mangled
, "_D", 2) != 0)
1315 string_init (&decl
);
1317 if (strcmp (mangled
, "_Dmain") == 0)
1319 string_append (&decl
, "D main");
1325 if (dlang_parse_symbol (&decl
, mangled
) == NULL
)
1326 string_delete (&decl
);
1329 if (string_length (&decl
) > 0)
1331 string_need (&decl
, 1);