This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
libiberty: D demangler support
- From: Thomas KÃhne <thomas-dloop at kuehne dot cn>
- To: gcc-patches at gcc dot gnu dot org
- Date: Sun, 30 Apr 2006 06:24:48 +0200
- Subject: libiberty: D demangler support
The attached patch adds symbol demangling support for D[1] to libiberty.
todo: replace the include cludge with a propper MAKE rule
Thomas
[1] http://digitalmars.com/d/ http://home.earthlink.net/~dvdfrdmn/d/
diff -urN ./gcc/libiberty/cp-demangle.c ./gcc-demangle-d/libiberty/cp-demangle.c
--- ./gcc/libiberty/cp-demangle.c 2005-02-13 08:21:41.000000000 +0100
+++ ./gcc-demangle-d/libiberty/cp-demangle.c 2006-04-30 05:25:19.000000000 +0200
@@ -99,6 +99,7 @@
#include "libiberty.h"
#include "demangle.h"
#include "cp-demangle.h"
+#include "d-demangle.h"
/* If IN_GLIBCPP_V3 is defined, some functions are made static. We
also rename them via #define to avoid compiler errors when the
@@ -3909,6 +3910,16 @@
}
else
{
+ if ((mangled[0] == '_') && (mangled[1] == 'D') && IS_DIGIT(mangled[2])
+ && (mangled[2] != '0'))
+ {
+ ret = DD_(demangle_d)(mangled);
+ if (ret)
+ {
+ *palc = strlen(ret);
+ return ret;
+ }
+ }
if ((options & DMGL_TYPES) == 0)
return NULL;
type = 1;
@@ -4457,3 +4468,7 @@
}
#endif /* STANDALONE_DEMANGLER */
+
+/* FIXME include d-demangle.c in build system */
+#include "d-demangle.c"
+
diff -urN ./gcc/libiberty/d-demangle.c ./gcc-demangle-d/libiberty/d-demangle.c
--- ./gcc/libiberty/d-demangle.c 1970-01-01 01:00:00.000000000 +0100
+++ ./gcc-demangle-d/libiberty/d-demangle.c 2006-04-30 05:25:19.000000000 +0200
@@ -0,0 +1,946 @@
+/*
+ * demangle_d - pluggable D de-mangler
+ * Copyright (C) 2006 Thomas Kuehne <thomas@kuehne.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * As a special exception, the copyright holders of this library give you
+ * permission to link this library with independent modules to produce an
+ * executable, regardless of the license terms of these independent modules,
+ * and to copy and distribute the resulting executable under terms of your
+ * choice, provided that you also meet, for each linked independent module,
+ * the terms and conditions of the license of that module. An independent
+ * module is a module which is not derived from or based on this library.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "d-demangle-internal.h"
+
+
+#ifdef D_DEMANGLE_REQUIRE_strndup
+/* Copy n first bytes into a newly allocated buffer. */
+char*
+xstrndup(source, n)
+ const char* source; size_t n;
+{
+ char* dest;
+ dest = xmalloc(n+1);
+ xmemcpy(dest, source, n);
+ dest[n] = 0;
+ return dest;
+}
+#endif
+
+#ifdef D_DEMANGLE_REQUIRE_memmove
+/* Copy n bytes from memory area src to memory area dest. */
+void * xmemmove(dest, src, n)
+ void *dest; const void *src; size_t n;
+{
+ void* tmp;
+ char* a;
+ const char* b;
+
+ a = (char*) dest;
+ b = (const char*) src;
+
+ if (((a < b) && (a + n < b)) || (((b < a) && (b + n < a))))
+ return xmemcpy(dest, src, n);
+ else
+ {
+ tmp = xmalloc(n);
+ xmemcpy(tmp, src, n);
+ xmemcpy(dest, tmp, n);
+ xfree(tmp);
+ return dest;
+ }
+}
+#endif
+
+
+#ifdef D_DEMANGLE_REQUIRE_strtol_10
+/* Convert the beginning of string src to an integer using base 10.
+ If endptr is not NULL, store the address of the first invalid character in
+ *endptr. */
+long int
+xstrtol_10(src, endptr)
+ const char* src; char const ** endptr;
+{
+ long int value;
+ int sign;
+
+ if (src[0] == '-')
+ {
+ sign = -1;
+ src++;
+ }
+ else if(src[0] == '+')
+ {
+ sign = 1;
+ src++;
+ }
+ else
+ sign = 1;
+
+ value = 0;
+
+ while (xisdigit(src[0]))
+ {
+ value = (value * 10) + (src[0] - '0');
+ src++;
+ }
+
+ if (endptr)
+ *endptr = src;
+
+ return sign * value;
+}
+#endif
+
+#ifdef D_DEMANGLE_REQUIRE_malloc
+/* Allocate n bytes and returns a pointer to the allocated memory. */
+void*
+xmalloc(n)
+ size_t n;
+{
+ void* ptr;
+ ptr = malloc(n);
+ if (!ptr)
+ xerror(NULL);
+ return ptr;
+}
+#endif
+
+#ifdef D_DEMANGLE_REQUIRE_realloc
+/* Changes the size of the memory block pointed to by ptr to len bytes. */
+void*
+xrealloc(ptr, len)
+ void* ptr; size_t len;
+{
+ ptr = realloc(ptr, len);
+ if (!ptr)
+ xerror(NULL);
+ return ptr;
+}
+#endif
+
+#ifdef D_DEMANGLE_REQUIRE_error
+/* Print error message and abort. If message is null, print the last
+ encountered system error and abort. */
+void
+xerror(message)
+ const char* message;
+{
+ if (message)
+ xfprintf(stderr, message);
+ else
+ xperror("demangle_d");
+ xabort();
+}
+#endif
+
+/* Create and initialize a new string. */
+string_t
+new_string()
+{
+ string_t str = xmalloc(sizeof(string_t));
+ str->used = 0;
+ str->len = 128;
+ str->str = xmalloc(str->len);
+ str->str[0] = 0;
+ return str;
+}
+
+/* Append len bytes from source string to dest string. */
+void
+append_n(dest, source, len)
+ string_t dest; const char* source; size_t len;
+{
+ size_t new_len;
+ new_len = dest->used + len + 1;
+ if (new_len > dest->len)
+ {
+ dest->len = new_len + (new_len >> 1);
+ dest->str = xrealloc(dest->str, dest->len);
+ }
+ xmemcpy(dest->str + dest->used, source, len);
+ dest->used += len;
+ dest->str[dest->used] = 0;
+}
+
+/* Append source char to dest string. */
+void
+append_c(dest, source)
+ string_t dest; int source;
+{
+ size_t new_len;
+ new_len = dest->used + 2;
+ if (new_len > dest->len)
+ {
+ dest->len = new_len + (new_len >> 1);
+ dest->str = xrealloc(dest->str, dest->len);
+ }
+ dest->str[dest->used++] = (char)source;
+ dest->str[dest->used] = 0;
+}
+
+/* Append NULL-terminated string source to dest. */
+void
+append(dest, source)
+ string_t dest; const char* source;
+{
+ append_n(dest, source, xstrlen(source));
+}
+
+/* Prepend len bytes from source string to dest string. */
+void
+prepend_n(dest, source, len)
+ string_t dest; const char* source; size_t len;
+{
+ size_t new_len;
+ new_len = dest->used + len + 1;
+ if (new_len > dest->len)
+ {
+ dest->len = new_len + (new_len >> 1);
+ dest->str = xrealloc(dest->str, dest->len);
+ }
+
+ if (dest->used)
+ xmemmove(dest->str + len, dest->str, dest->used);
+
+ xmemcpy(dest->str, source, len);
+ dest->used += len;
+ dest->str[dest->used] = 0;
+}
+
+/* Prepend NULL-terminated string source to dest. */
+void
+prepend(dest, source)
+ string_t dest; const char* source;
+{
+ prepend_n(dest, source, xstrlen(source));
+}
+
+/* If not nested, append len bytes from source string to dest else
+ prepend with space. */
+void
+nestpend_n(dest, source, len, is_nested)
+ string_t dest; const char* source; size_t len; int is_nested;
+{
+ if (is_nested)
+ append_n(dest, source, len);
+ else
+ {
+ prepend(dest, " ");
+ prepend_n(dest, source, len);
+ }
+}
+
+/* If not nested, append NULL-terminated source string to dest else
+ prepend with space. */
+void
+nestpend(dest, source, is_nested)
+ string_t dest; const char* source; int is_nested;
+{
+ nestpend_n(dest, source, xstrlen(source), is_nested);
+}
+
+/* Parse until the end of the next type and return the pointer to the first
+ uninterpreted charachter or NULL. Set is_nested if a nested type
+ (e.g. index of AA or template/function parameter) is parsed. */
+const char*
+next_type(dest, source, is_nested)
+ string_t dest; const char* source; int is_nested;
+{
+ if (!source || !source[0])
+ return NULL;
+
+ if ((source[0] == '_') && (source[1] == 'D') && xisdigit(source[2])
+ && (source[2] != '0'))
+ {
+ string_t tmp;
+ tmp = new_string();
+ source = next_type(tmp, source + 2, 0);
+ if (dest->used && (dest->str[dest->used] != '.'))
+ append_c(dest, '.');
+ append_n(dest, tmp->str, tmp->used);
+ xfree(tmp->str);
+ xfree(tmp);
+ return source;
+ }
+
+ switch(source[0])
+ {
+ case 'v':
+ nestpend(dest, "void", is_nested);
+ source += 1;
+ break;
+ case 'b': /* deprecated since DMD-0.148 (2006-02-25) */
+ nestpend(dest, "bit", is_nested);
+ source += 1;
+ break;
+ case 'x':
+ nestpend(dest, "bool", is_nested);
+ source += 1;
+ break;
+ case 'g':
+ nestpend(dest, "byte", is_nested);
+ source += 1;
+ break;
+ case 'h':
+ nestpend(dest, "ubyte", is_nested);
+ source += 1;
+ break;
+ case 's':
+ nestpend(dest, "short", is_nested);
+ source += 1;
+ break;
+ case 't':
+ nestpend(dest, "ushort", is_nested);
+ source += 1;
+ break;
+ case 'i':
+ nestpend(dest, "int", is_nested);
+ source += 1;
+ break;
+ case 'k':
+ nestpend(dest, "uint", is_nested);
+ source += 1;
+ break;
+ case 'l':
+ nestpend(dest, "long", is_nested);
+ source += 1;
+ break;
+ case 'm':
+ nestpend(dest, "ulong", is_nested);
+ source += 1;
+ break;
+ case 'f':
+ nestpend(dest, "float", is_nested);
+ source += 1;
+ break;
+ case 'd':
+ nestpend(dest, "double", is_nested);
+ source += 1;
+ break;
+ case 'e':
+ nestpend(dest, "real", is_nested);
+ source += 1;
+ break;
+ case 'o':
+ nestpend(dest, "ifloat", is_nested);
+ source += 1;
+ break;
+ case 'p':
+ nestpend(dest, "idouble", is_nested);
+ source += 1;
+ break;
+ case 'j':
+ nestpend(dest, "ireal", is_nested);
+ source += 1;
+ break;
+ case 'q':
+ nestpend(dest, "cfloat", is_nested);
+ source += 1;
+ break;
+ case 'r':
+ nestpend(dest, "cdouble", is_nested);
+ source += 1;
+ break;
+ case 'c':
+ nestpend(dest, "creal", is_nested);
+ source += 1;
+ break;
+ case 'a':
+ nestpend(dest, "char", is_nested);
+ source += 1;
+ break;
+ case 'u':
+ nestpend(dest, "wchar", is_nested);
+ source += 1;
+ break;
+ case 'w':
+ nestpend(dest, "dchar", is_nested);
+ source += 1;
+ break;
+
+ case 'A': /* dynamic array */
+ if (!is_nested)
+ prepend(dest, "[] ");
+ source = next_type(dest, source+1, is_nested);
+ if (is_nested)
+ append(dest, "[]");
+ break;
+
+ case 'G': /* static array */
+ {
+ const char* start;
+ const char* end;
+ start = ++source;
+ end = start;
+
+ while (xisdigit(*end))
+ end++;
+
+ if (!is_nested)
+ {
+ prepend(dest, "] ");
+ prepend_n(dest, start, end-start);
+ prepend(dest, "[");
+ }
+ source = next_type(dest, end, is_nested);
+ if (is_nested)
+ {
+ append_c(dest, '[');
+ append_n(dest, start, end-start);
+ append_c(dest, ']');
+ }
+ break;
+ }
+
+ case 'H': /* associative array */
+ {
+ string_t aa;
+ aa = new_string();
+ source = next_type(aa, source+1, 1);
+ prepend(aa, "[");
+ append_c(aa, ']');
+ source = next_type(aa, source, 0);
+ nestpend(dest, aa->str, is_nested);
+ xfree(aa->str);
+ xfree(aa);
+ break;
+ }
+
+ case 'D': /* delegate */
+ {
+ string_t sig;
+ sig = new_string();
+ source = parse_function(sig, source+1, NULL, 0);
+ nestpend_n(dest, sig->str, sig->used, is_nested);
+ xfree(sig->str);
+ xfree(sig);
+ break;
+ }
+
+ case 'P': /* pointer */
+ if ((source[1] == 'F') || (source[1]=='U') || (source[1]=='W')
+ || (source[1]=='V') || (source[1]=='R'))
+ {
+ /* function */
+ string_t sig;
+ sig = new_string();
+ source = parse_function(sig, source+1, "", 0);
+ nestpend_n(dest, sig->str, sig->used, is_nested);
+ xfree(sig->str);
+ xfree(sig);
+ }
+ else
+ {
+ /* 'normal' type */
+ if (!is_nested)
+ prepend(dest, "* ");
+ source = next_type(dest, source+1, is_nested);
+ if (is_nested)
+ append(dest, " *");
+ }
+ break;
+
+ case 'J': /* out */
+ append(dest, "out ");
+ source = next_type(dest, source+1, 1);
+ break;
+
+ case 'K': /* inout */
+ append(dest, "inout ");
+ source = next_type(dest, source+1, 1);
+ break;
+
+ case 'C': /* class */
+ case 'S': /* struct */
+ case 'E': /* enum */
+ case 'T': /* typedef */
+ {
+#ifdef D_DEMANGLE_VERBOSE
+ char tmp;
+ tmp = source[0];
+#endif /* D_DEMANGLE_VERBOSE */
+ if (!is_nested)
+ {
+ string_t sig;
+ sig = new_string();
+ source = next_type(sig, source+1, 0);
+ append_c(sig, ' ');
+#ifdef D_DEMANGLE_VERBOSE
+ switch (tmp)
+ {
+ case 'C':
+ prepend(sig, "class ");
+ break;
+ case 'S':
+ prepend(sig, "struct ");
+ break;
+ case 'E':
+ prepend(sig, "enum ");
+ break;
+ case 'T':
+ prepend(sig, "typedef ");
+ break;
+ }
+#endif /* D_DEMANGLE_VERBOSE */
+ prepend_n(dest, sig->str, sig->used);
+ xfree(sig->str);
+ xfree(sig);
+ }
+ else
+ {
+#ifdef D_DEMANGLE_VERBOSE
+ switch (tmp)
+ {
+ case 'C':
+ append(dest, "class ");
+ break;
+ case 'S':
+ append(dest, "struct ");
+ break;
+ case 'E':
+ append(dest, "enum ");
+ break;
+ case 'T':
+ append(dest, "typedef ");
+ break;
+ }
+#endif /* D_DEMANGLE_VERBOSE */
+ source = next_type(dest, source+1, 1);
+ }
+ break;
+ }
+
+ case '1': /* qualified name */
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ {
+ int first_round;
+ first_round = 1;
+
+ while (source && xisdigit(source[0]) && (source[0] != '0'))
+ {
+ long int len;
+ len = xstrtol_10(source, &source);
+
+ if (!first_round)
+ append_c(dest, '.');
+ else
+ first_round = 0;
+
+ if (len >= 5 && (source[0] == '_') && (source[1] == '_')
+ && (source[2] == 'T') && xisdigit(source[3])
+ && (source[3] != '0'))
+ {
+ /* template */
+ char* template;
+ template = xstrndup(source + 3, len-3);
+ interprete_template(dest, template);
+ xfree(template);
+ }
+ else if((len == 5) && (xstrncmp(source, "_ctor", len) == 0))
+ append(dest, "this");
+ else if((len == 5) && (xstrncmp(source, "_dtor", len) == 0))
+ append(dest, "~this");
+ else if((len == 11)
+ && (xstrncmp(source, "_staticCtorFZv", len + 3) == 0))
+ {
+ prepend(dest, "static void ");
+ append(dest, "this()");
+ source = source + 11 + 3;
+ break;
+ }
+ else if((len == 11)
+ && (xstrncmp(source, "_staticDtorFZv", len + 3) == 0))
+ {
+ prepend(dest, "static void ");
+ append(dest, "~this()");
+ source = source + 11 + 3;
+ break;
+ }
+ else
+ /* plain identifier part */
+ append_n(dest, source, len);
+
+ source += len;
+ }
+ if (!is_nested)
+ source = next_type(dest, source, 0);
+ break;
+ }
+
+ case 'F': /* D function */
+ case 'U': /* C function */
+ case 'W': /* Windows function */
+ case 'V': /* Pascal function */
+ case 'R': /* C++ function */
+ if (!is_nested)
+ {
+ string_t id;
+ id = new_string();
+ append_n(id, dest->str, dest->used);
+ dest->used = 0;
+ dest->str[0] = 0;
+ source = parse_function(dest, source, id->str, 0);
+ xfree(id->str);
+ xfree(id);
+ }
+ else
+ source = parse_function(dest, source, "", 1);
+ break;
+
+ default:
+ append(dest, " @bug@[2]{");
+ append(dest, source);
+ append_c(dest, '}');
+ source = NULL;
+ break;
+ }
+
+ return source;
+}
+
+/* Parse a "real" template parameter and return a pointer to the first not
+ interpreted character. */
+const char*
+parse_real(dest, source)
+ string_t dest; const char* source;
+{
+ /* FIXME architecture dependent */
+ long double f;
+ size_t i;
+ int tmp;
+ char* buffer;
+ unsigned char* c;
+
+ c = (unsigned char*) &f;
+
+ for (i = 0; i < 10; i++)
+ {
+ if (!xisxdigit(source[i * 2]) || !xisxdigit(source[i * 2 + 1]))
+ {
+format_error:
+ append(dest, "0x");
+ append_n(dest, source, 20);
+ return source + 20;
+ }
+ c[i] = (xasci2hex(source[i * 2]) << 4);
+ c[i] |= xasci2hex(source[i * 2 + 1]);
+ }
+
+ buffer = xmalloc(64);
+ tmp = xsnprintf(buffer, 64, "%Lf", f);
+ if (tmp < 1)
+ {
+ xfree(buffer);
+ goto format_error;
+ }
+ append_n(dest, buffer, tmp);
+ xfree(buffer);
+ return source + 20;
+}
+
+/* Parse a function - including arguments and return type - and
+ return a pointer to the first not interpreted character. */
+const char*
+parse_function(dest, source, name, is_nested)
+ string_t dest; const char* source; const char* name;
+ const int is_nested;
+{
+ string_t fn_return;
+ string_t fn_param;
+
+ fn_return = new_string();
+ fn_param = new_string();
+
+ source++;
+
+ /* params */
+ if (source[0] != 'Z')
+ {
+ if (source[0] == 'Y')
+ {
+ append(fn_param, "...");
+ goto var_arg_param;
+ }
+ source = next_type(fn_param, source, 1);
+ while (source && source[0] && source[0]!='Z')
+ {
+ if (source[0] == 'Y')
+ {
+ append(fn_param, ", ...");
+ goto var_arg_param;
+ }
+ else if(source[0] == 'X')
+ {
+ append(fn_param, " ...");
+ goto var_arg_param;
+ }
+ append(fn_param, ", ");
+ source = next_type(fn_param, source, 1);
+ }
+ }
+
+ /* return type */
+ if (source && source[0] == 'Z')
+var_arg_param:
+ source = next_type(fn_return, source + 1, 1);
+
+ /* output */
+ if (name && name[0])
+ if (! is_nested)
+ {
+ prepend(dest, " ");
+ prepend_n(dest, fn_return->str, fn_return->used);
+ append(dest, name);
+ }
+ else
+ {
+ append_n(dest, fn_return->str, fn_return->used);
+ append_c(dest, ' ');
+ append(dest, name);
+ }
+ else if(name)
+ {
+ append_n(dest, fn_return->str, fn_return->used);
+ append(dest, " function");
+ }
+ else
+ {
+ append_n(dest, fn_return->str, fn_return->used);
+ append(dest, " delegate");
+ }
+
+ if (fn_param->used)
+ {
+ append_c(dest, '(');
+ append_n(dest, fn_param->str, fn_param->used);
+ append_c(dest, ')');
+ }
+ else
+ append(dest, "()");
+
+ xfree(fn_return->str);
+ xfree(fn_return);
+ xfree(fn_param->str);
+ xfree(fn_param);
+
+ return source;
+}
+
+/* Interprete the NULL terminated template symbol. */
+void
+interprete_template(dest, raw)
+ string_t dest; const char* raw;
+{
+ const char* tmp;
+ long int dataLen;
+ int first_arg;
+
+ first_arg = 1;
+
+ /* id */
+ while (xisdigit(raw[0]) && (raw[0] != '0'))
+ {
+ long int len;
+ len = xstrtol_10(raw, &raw);
+ append_n(dest, raw, len);
+ raw += len;
+ }
+ append(dest, "!(");
+
+ /* arguments */
+ while (raw && raw[0])
+ {
+ if (raw[0] == 'T')
+ {
+ /* type parameter */
+ raw++;
+ if (!first_arg)
+ append(dest, ", ");
+ else
+ first_arg = 0;
+ raw = next_type(dest, raw, 1);
+ }
+ else if(raw[0] == 'V')
+ {
+ /* value parameter */
+ if (!first_arg)
+ append(dest, ", ");
+ else
+ first_arg = 0;
+ raw = next_type(dest, raw + 1, 1);
+ append_c(dest, ' ');
+ if (xisdigit(raw[0]))
+ {
+ /* positive integer */
+integer_arg:
+ tmp = raw;
+ while (xisdigit(raw[0]))
+ raw++;
+ append_n(dest, tmp, raw-tmp);
+ }
+ else if(raw[0] == 'N')
+ {
+ /* negative integer */
+ raw++;
+ append_c(dest, '-');
+ goto integer_arg;
+ }
+ else if(raw[0] == 'e')
+ /* float */
+ raw = parse_real(dest, raw+1);
+ else if(raw[0] == 'c')
+ {
+ /* complex float */
+ raw = parse_real(dest, raw+1);
+ append(dest, " + ");
+ raw = parse_real(dest, raw);
+ append_c(dest, 'i');
+ }
+ else if(raw[0] == 'n')
+ {
+ append(dest, "null");
+ raw++;
+ }
+ else if((raw[0] == 'a') || (raw[0] == 'w') || (raw[0] == 'd'))
+ {
+ /* character literal */
+ raw++;
+ if (!xisdigit(raw[0]))
+ goto bug;
+ dataLen = xstrtol_10(raw, &raw);
+ if (raw[0] != '_')
+ goto bug;
+ raw++;
+ append_c(dest, '"');
+ while (dataLen--)
+ {
+ if (xisxdigit(raw[0]) && xisxdigit(raw[1]))
+ append_c(dest, (xasci2hex(raw[0]) << 4)
+ + xasci2hex(raw[1]));
+ else
+ append_c(dest, '?');
+ raw += 2;
+ }
+ append_c(dest, '"');
+ }
+ else
+ goto bug;
+ }
+ else if(raw[0] == 'Z')
+ /* end of parameter list */
+ break;
+ else
+ {
+bug:
+ append(dest, " @bug@[1]{");
+ append(dest, raw);
+ append_c(dest, '}');
+ break;
+ }
+ }
+ append_c(dest, ')');
+}
+
+/* Demangle the NULL-terminated D symbol and return the UTF-8 encoded
+ representation or NULL. The caller is responsible to free input and
+ output. */
+char*
+demangle_d(source)
+ const char* source;
+{
+ string_t dest;
+ string_t nested;
+ char* back;
+
+ if ((source[0] != '_') || (source[1] != 'D') || (!xisdigit(source[2]))
+ || (source[2] == '0'))
+ {
+ /* FIXME might be mangled with 'D' but hasn't 'D' linkage
+ * samples:
+ * _aaApply10treewalkerFPS3aaA3aaAZi
+ * _aaKeys9_aaKeys_xFPS3aaA3aaAZv
+ */
+ /* FIXME handle special cases:
+ * _init__D1b11_staticCtorFZv3Al
+ * _Class__D1b11_staticCtorFZv3Ali
+ * _vtbl__D1b11_staticCtorFZv3Ali
+ * _modctor_1b
+ * _assert_1b
+ */
+ return NULL;
+ }
+ else
+ source += 2;
+
+ dest = new_string();
+
+ source = next_type(dest, source, 0);
+
+ while (source && source[0])
+ {
+ /* nested symbols */
+ nested = new_string();
+ append_c(dest, '.');
+ source = next_type(nested, source, 0);
+ append_n(dest, nested->str, nested->used);
+ xfree(nested->str);
+ xfree(nested);
+ }
+
+ back = xstrndup(dest->str, dest->used+1);
+ xfree(dest->str);
+ xfree(dest);
+
+ return back;
+}
+
+
+#ifdef D_DEMANGLE_STANDALONE
+int
+main(int argc, char** argv)
+{
+ int i;
+ if (argc < 2)
+ {
+ xfprintf(stderr,
+ _("pluggable D d-demangler by Thomas Kuehne <thomas@kuehne.cn> (%s)\n"),
+ "$Date: 2006-04-22T22:40:29.553250Z $");
+ xfprintf(stderr, _("%s <mangledSymbol_1> [<mangledSymbol_2> ...]\n"),
+ argc ? argv[0] :"demangle_d");
+ return (EXIT_FAILURE);
+ }
+ for (i = 1; i < argc; i++)
+ {
+ char* demangled = demangle_d(argv[i]);
+ if (1 > xprintf(_("%s\t%s\n"), argv[i], demangled))
+ xperror(NULL);
+ if (demangled)
+ xfree(demangled);
+ }
+ return (EXIT_SUCCESS);
+}
+#endif /* D_DEMANGLE_STANDALONE */
diff -urN ./gcc/libiberty/d-demangle.h ./gcc-demangle-d/libiberty/d-demangle.h
--- ./gcc/libiberty/d-demangle.h 1970-01-01 01:00:00.000000000 +0100
+++ ./gcc-demangle-d/libiberty/d-demangle.h 2006-04-30 05:25:18.000000000 +0200
@@ -0,0 +1,21 @@
+#ifndef D_DEMANGLE_H
+#define D_DEMANGLE_H 1
+
+#define DD_(str) demangle_d_##str
+
+/* demangle a D symbol
+ *
+ * input:
+ * a NULL terminated mangled symbol
+ *
+ * output:
+ * UTF-8 encoded demangled symbol
+ * or NULL if unable to demangle
+ *
+ * memory:
+ * the caller is responsible to
+ * free input and output
+ */
+char* DD_(demangle_d)(const char*);
+
+#endif /* D_DEMANGLE_H */
diff -urN ./gcc/libiberty/d-demangle-internal.h ./gcc-demangle-d/libiberty/d-demangle-internal.h
--- ./gcc/libiberty/d-demangle-internal.h 1970-01-01 01:00:00.000000000 +0100
+++ ./gcc-demangle-d/libiberty/d-demangle-internal.h 2006-04-30 05:25:18.000000000 +0200
@@ -0,0 +1,251 @@
+/*
+ * demangle_d - pluggable D de-mangler
+ * Copyright (C) 2006 Thomas Kuehne <thomas@kuehne.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * As a special exception, the copyright holders of this library give you
+ * permission to link this library with independent modules to produce an
+ * executable, regardless of the license terms of these independent modules,
+ * and to copy and distribute the resulting executable under terms of your
+ * choice, provided that you also meet, for each linked independent module,
+ * the terms and conditions of the license of that module. An independent
+ * module is a module which is not derived from or based on this library.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef D_DEMANGLE_INTERNAL_H
+#define D_DEMANGLE_INTERNAL_H 1
+
+#include "d-demangle.h"
+
+#undef D_DEMANGLE_REQUIRE_ISDIGIT
+#undef D_DEMANGLE_REQUIRE_ISXDIGIT
+#undef D_DEMANGLE_REQUIRE_ASCI2HEX
+
+#ifdef D_DEMANGLE_IN_VALGRIND
+
+/* valgrind - http://www.valgrind.org */
+
+#include <stddef.h> /* size_t */
+
+#define xstrlen VG_(strlen)
+#define xstrncmp VG_(strncmp)
+#define xsnprintf VG_(snprintf)
+#define xisdigit ISDIGIT
+#define D_DEMANGLE_REQUIRE_ISDIGIT 1
+#define xisxdigit ISXDIGIT
+#define D_DEMANGLE_REQUIRE_ISXDIGIT 1
+#define xasci2hex ASCI2HEX
+#define D_DEMANGLE_REQUIRE_ASCI2HEX 1
+
+#else /* not D_DEMANGLE_IN_VALGRIND */
+
+/* "normal" libc */
+
+#include <stddef.h> /* size_t */
+
+#include <string.h>
+#define xstrlen strlen
+#define xstrncmp strncmp
+
+#include <stdlib.h>
+#define xabort abort
+
+#include <stdio.h>
+#define xsnprintf snprintf
+
+#include <ctype.h>
+#define xisdigit isdigit
+#define xisxdigit isxdigit
+
+#define xasci2hex ASCI2HEX
+#define D_DEMANGLE_REQUIRE_ASCI2HEX 1
+
+#endif /* not D_DEMANGLE_IN_VALGRIND */
+
+
+/* helper macros */
+
+#ifdef D_DEMANGLE_REQUIRE_ISDIGIT
+#define ISDIGIT(c) (('0' <= (c)) && ((c) <= '9'))
+#endif
+
+#ifdef D_DEMANGLE_REQUIRE_ISXDIGIT
+#define ISXDIGIT(c) ( \
+ (('0' <= (c)) && ((c) <= '9')) \
+ || (('a' <= (c)) && ((c) <= 'f')) \
+ || (('A' <= (c)) && ((c) <= 'F')) \
+ )
+#endif
+
+#ifdef D_DEMANGLE_REQUIRE_ASCI2HEX
+#define ASCI2HEX(c) \
+ ( \
+ ('a' <= (c) && (c) <= 'f') \
+ ? \
+ ((c) - 'a' + 10) \
+ : \
+ ( \
+ ('A' <= (c) && (c) <= 'F') \
+ ? \
+ ((c) - 'A' + 10) \
+ : \
+ ( \
+ ('0' <= (c) && (c) <= '9') \
+ ? \
+ ((c) - '0') \
+ : \
+ 0 \
+ ) \
+ ) \
+ )
+#endif
+
+#undef D_DEMANGLE_REQUIRE_strndup
+#undef D_DEMANGLE_REQUIRE_strtol_10
+#undef D_DEMANGLE_REQUIRE_malloc
+#undef D_DEMANGLE_REQUIRE_realloc
+#undef D_DEMANGLE_REQUIRE_memmove
+#undef D_DEMANGLE_REQUIRE_error
+
+#ifdef D_DEMANGLE_IN_VALGRIND
+/* gdb - http://www.gnu.org/software/gdb/ */
+
+#define xstrndup DD_(strndup)
+#define D_DEMANGLE_REQUIRE_strndup 1
+#define xstrtol_10 DD_(strtol_10)
+#define D_DEMANGLE_REQUIRE_strtol_10 1
+#define xmalloc VG_(malloc)
+#define xrealloc VG_(realloc)
+#define xmemmove DD_(memmove)
+#define D_DEMANGLE_REQUIRE_memmove 1
+#define xfree VG_(free)
+#define xmemcpy VG_(memcpy)
+
+#else /* not D_DEMANGLE_IN_VALGRIND && not D_DEMANGLE_IN_GDB */
+/* 'normal' libc */
+
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(__USE_GNU) || defined(_GNU_SOURCE)
+#define xstrndup strndup
+#else
+#define xstrndup DD_(strndup)
+#define D_DEMANGLE_REQUIRE_strndup 1
+#endif
+
+#define xstrtol_10 DD_(strtol_10)
+#define D_DEMANGLE_REQUIRE_strtol_10 1
+
+#define xmalloc DD_(malloc)
+#define D_DEMANGLE_REQUIRE_malloc 1
+#define xrealloc DD_(realloc)
+#define D_DEMANGLE_REQUIRE_realloc 1
+#define xmemmove memmove
+#define xfree free
+#define xmemcpy memcpy
+
+#ifdef D_DEMANGLE_STANDALONE
+#define D_DEMANGLE_REQUIRE_error 1
+#define xerror DD_(error)
+#define xprintf printf
+#define xperror perror
+#define xfprintf fprintf
+#endif
+
+#endif /* not D_DEMANGLE_IN_VALGRIND && not D_DEMANGLE_IN_GDB */
+
+#ifdef D_DEMANGLE_REQUIRE_strndup
+char* xstrndup(const char*, size_t);
+#endif
+
+#ifdef D_DEMANGLE_REQUIRE_strtol_10
+long int xstrtol_10(const char*, char const **);
+#endif
+
+#ifdef D_DEMANGLE_REQUIRE_malloc
+void* xmalloc(size_t);
+#define D_DEMANGLE_REQUIRE_error 1
+#endif
+
+#ifdef D_DEMANGLE_REQUIRE_realloc
+void* xrealloc(void*, size_t);
+#define D_DEMANGLE_REQUIRE_error 1
+#endif
+
+#ifdef D_DEMANGLE_REQUIRE_memmove
+void * xmemmove(void*, const void *, size_t );
+#endif
+
+#ifdef D_DEMANGLE_REQUIRE_error
+void xerror(const char*);
+#ifndef xperror
+#define xperror perror
+#endif
+#ifndef xfprintf
+#define xfprintf fprintf
+#endif
+#endif
+
+#define string_t DD_(string_t)
+#define new_string DD_(new_string)
+#define append_n DD_(append_n)
+#define append_c DD_(append_c)
+#define append DD_(append)
+#define prepend_n DD_(prepend_n)
+#define prepend DD_(prepend)
+#define nestpend_n DD_(nestpend_n)
+#define nestpend DD_(nestpend)
+
+typedef struct{
+ size_t used;
+ char* str;
+ size_t len;
+}* string_t;
+
+string_t new_string(void);
+
+void append(string_t, const char *);
+void append_n(string_t, const char *, size_t);
+void append_c(string_t, int);
+
+void prepend(string_t, const char *);
+void prepend_n(string_t, const char *, size_t);
+
+void nestpend_n(string_t, const char *, size_t, int);
+void nestpend(string_t, const char*, int);
+
+
+#define next_type DD_(next_type)
+#define interprete_template DD_(interprete_template)
+#define parse_real DD_(parse_real)
+#define parse_function DD_(parse_function)
+#define demangle_d DD_(demangle_d)
+
+const char* next_type(string_t, const char*, int);
+
+void interprete_template(string_t, const char*);
+
+const char* parse_real(string_t, const char*);
+
+const char* parse_function(string_t, const char*, const char*, int);
+
+#ifndef _
+#define _(str) str
+#endif
+
+#endif /* D_DEMANGLE_INTERNAL_H */