source: rtems-tools/rtemstoolkit/libiberty/d-demangle.c @ 78bbe4c

5
Last change on this file since 78bbe4c was 78bbe4c, checked in by Chris Johns <chrisj@…>, on 08/16/17 at 08:09:59

linkers/exe-info Support ARM static constructors.

Note, ARM destructors are registered at runtime and currently not
easly found.

Update libiberty to get a newer demangler.

Closes #3102.

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