This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Ping [Patch/libiberty]: Rewrite of ada_demangle
- From: Tristan Gingold <gingold at adacore dot com>
- To: gcc-patches <gcc-patches at gcc dot gnu dot org>
- Date: Mon, 4 Jan 2010 12:59:34 +0100
- Subject: Ping [Patch/libiberty]: Rewrite of ada_demangle
- References: <F15337BC-7884-42AF-A54D-18E2943370F6@adacore.com>
Ping, as there was no review for almost one month.
On Dec 9, 2009, at 12:39 PM, Tristan Gingold wrote:
> Hi,
>
> the Ada/GNAT demangler in libiberty is slightly outdated: it didn't handle
> many common encodings.
> In fact it is used only by binutils: both GCC and gdb have their own
> demangler. I plan to reuse the libiberty demangler for gdb and that's the
> reason why ada_demangle is now public.
>
> This patch is a complete rewrite of ada_demangle and also adds many tests
> in the testsuite (maybe it make sense to create a specific file in
> libiberty/testsuite instead of adding GNAT tests in demangle-expected).
>
> Tristan.
>
> include/
> 2009-12-09 Tristan Gingold <gingold@adacore.com>
>
> * demangle.h (ada_demangle): Add prototype.
>
> libiberty/
> 2009-12-09 Tristan Gingold <gingold@adacore.com>
>
> * cplus-dem.c (ada_demangle): Remove prototype.
> (grow_vect): Removed.
> (ada_demangle): Rewritten.
> (cplus_demangle): Fix indentation.
> * testsuite/demangle-expected: Add tests for Ada.
> ---
> include/demangle.h | 3 +
> libiberty/cplus-dem.c | 277 ++++++++++++++++++++-------------
> libiberty/testsuite/demangle-expected | 95 +++++++++++
> 3 files changed, 267 insertions(+), 108 deletions(-)
>
> diff --git a/include/demangle.h b/include/demangle.h
> index 76fab0a..2ab2760 100644
> --- a/include/demangle.h
> +++ b/include/demangle.h
> @@ -160,6 +160,9 @@ java_demangle_v3_callback (const char *mangled,
> extern char*
> java_demangle_v3 (const char *mangled);
>
> +char *
> +ada_demangle (const char *mangled, int options);
> +
> enum gnu_v3_ctor_kinds {
> gnu_v3_complete_object_ctor = 1,
> gnu_v3_base_object_ctor,
> diff --git a/libiberty/cplus-dem.c b/libiberty/cplus-dem.c
> index 6628514..f20a5ef 100644
> --- a/libiberty/cplus-dem.c
> +++ b/libiberty/cplus-dem.c
> @@ -62,8 +62,6 @@ void * realloc ();
>
> #include "libiberty.h"
>
> -static char *ada_demangle (const char *, int);
> -
> #define min(X,Y) (((X) < (Y)) ? (X) : (Y))
>
> /* A value at least one greater than the maximum number of characters
> @@ -478,8 +476,6 @@ demangle_arm_hp_template (struct work_stuff *, const char **, int, string *);
> static void
> recursively_demangle (struct work_stuff *, const char **, string *, int);
>
> -static void grow_vect (char **, size_t *, size_t, int);
> -
> /* Translate count to integer, consuming tokens in the process.
> Conversion terminates on the first non-digit character.
>
> @@ -872,129 +868,194 @@ cplus_demangle (const char *mangled, int options)
> }
>
> if (GNAT_DEMANGLING)
> - return ada_demangle(mangled,options);
> + return ada_demangle (mangled, options);
>
> ret = internal_cplus_demangle (work, mangled);
> squangle_mop_up (work);
> return (ret);
> }
>
> +/* Demangle ada names. The encoding is documented in gcc/ada/exp_dbug.ads. */
>
> -/* Assuming *OLD_VECT points to an array of *SIZE objects of size
> - ELEMENT_SIZE, grow it to contain at least MIN_SIZE objects,
> - updating *OLD_VECT and *SIZE as necessary. */
> -
> -static void
> -grow_vect (char **old_vect, size_t *size, size_t min_size, int element_size)
> -{
> - if (*size < min_size)
> - {
> - *size *= 2;
> - if (*size < min_size)
> - *size = min_size;
> - *old_vect = XRESIZEVAR (char, *old_vect, *size * element_size);
> - }
> -}
> -
> -/* Demangle ada names:
> - 1. Discard final __{DIGIT}+ or ${DIGIT}+
> - 2. Convert other instances of embedded "__" to `.'.
> - 3. Discard leading _ada_.
> - 4. Remove everything after first ___ if it is followed by 'X'.
> - 5. Put symbols that should be suppressed in <...> brackets.
> - The resulting string is valid until the next call of ada_demangle. */
> -
> -static char *
> +char *
> ada_demangle (const char *mangled, int option ATTRIBUTE_UNUSED)
> {
> - int i, j;
> int len0;
> const char* p;
> - char *demangled = NULL;
> - int changed;
> - size_t demangled_size = 0;
> + char *d;
> + char *demangled;
>
> - changed = 0;
> -
> + /* Discard leading _ada_, which is used for library level subprograms. */
> if (strncmp (mangled, "_ada_", 5) == 0)
> - {
> - mangled += 5;
> - changed = 1;
> - }
> -
> - if (mangled[0] == '_' || mangled[0] == '<')
> - goto Suppress;
> + mangled += 5;
> +
> + /* All ada unit names are lower-case. */
> + if (!ISLOWER (mangled[0]))
> + goto unknown;
> +
> + /* Most of the demangling will trivially remove chars. Operator names
> + may add one char but because they are always preceeded by '__' which is
> + replaced by '.', they eventually never expand the size. '___elabs' and
> + '___elabb' add only 2 chars, but they occur only once. */
> + len0 = strlen (mangled) + 2 + 1;
> + demangled = XNEWVEC (char, len0);
>
> - p = strstr (mangled, "___");
> - if (p == NULL)
> - len0 = strlen (mangled);
> - else
> + d = demangled;
> + p = mangled;
> + while (1)
> {
> - if (p[3] == 'X')
> - {
> - len0 = p - mangled;
> - changed = 1;
> - }
> + /* Convert name, which is always lower-case. */
> + if (ISLOWER (*p))
> + {
> + do
> + *d++ = *p++;
> + while (ISLOWER(*p) || ISDIGIT (*p)
> + || (p[0] == '_' && (ISLOWER (p[1]) || ISDIGIT (p[1]))));
> + }
> + else if (p[0] == 'O')
> + {
> + static const char * const operators[][2] =
> + {{"Oabs", "abs"}, {"Oand", "and"}, {"Omod", "mod"},
> + {"Onot", "not"}, {"Oor", "or"}, {"Orem", "rem"},
> + {"Oxor", "xor"}, {"Oeq", "="}, {"One", "/="},
> + {"Olt", "<"}, {"Ole", "<="}, {"Ogt", ">"},
> + {"Oge", ">="}, {"Oadd", "+"}, {"Osubtract", "-"},
> + {"Oconcat", "&"}, {"Omultiply", "*"}, {"Odivide", "/"},
> + {"Oexpon", "**"}, {NULL, NULL}};
> + int k;
> +
> + for (k = 0; operators[k][0]; k++)
> + {
> + int l = strlen (operators[k][0]);
> + if (!strncmp (p, operators[k][0], l))
> + {
> + p += l;
> + l = strlen (operators[k][1]);
> + *d++ = '"';
> + memcpy (d, operators[k][1], l);
> + d += l;
> + *d++ = '"';
> + break;
> + }
> + }
> + /* Operator not found. */
> + if (!operators[k][0])
> + goto unknown;
> + }
> else
> - goto Suppress;
> - }
> -
> - /* Make demangled big enough for possible expansion by operator name. */
> - grow_vect (&demangled,
> - &demangled_size, 2 * len0 + 1,
> - sizeof (char));
> -
> - if (ISDIGIT ((unsigned char) mangled[len0 - 1])) {
> - for (i = len0 - 2; i >= 0 && ISDIGIT ((unsigned char) mangled[i]); i -= 1)
> - ;
> - if (i > 1 && mangled[i] == '_' && mangled[i - 1] == '_')
> - {
> - len0 = i - 1;
> - changed = 1;
> - }
> - else if (mangled[i] == '$')
> - {
> - len0 = i;
> - changed = 1;
> - }
> - }
> -
> - for (i = 0, j = 0; i < len0 && ! ISALPHA ((unsigned char)mangled[i]);
> - i += 1, j += 1)
> - demangled[j] = mangled[i];
> -
> - while (i < len0)
> - {
> - if (i < len0 - 2 && mangled[i] == '_' && mangled[i + 1] == '_')
> - {
> - demangled[j] = '.';
> - changed = 1;
> - i += 2; j += 1;
> - }
> + {
> + /* Not a GNAT encoding. */
> + goto unknown;
> + }
> +
> + if (p[0] == '_')
> + {
> + /* Separator. */
> + if (p[1] == '_')
> + {
> + /* Standard separator. Handled first. */
> + p += 2;
> + if (ISDIGIT (*p))
> + {
> + /* Overloading. */
> + do
> + p++;
> + while (ISDIGIT (*p) || (p[0] == '_' && ISDIGIT (p[1])));
> + }
> + else if (*p == '_' && !strcmp (p + 1, "elabb"))
> + {
> + memcpy (d, "'Elab_Body", 10);
> + d += 10;
> + break;
> + }
> + else if (*p == '_' && !strcmp (p + 1, "elabs"))
> + {
> + memcpy (d, "'Elab_Spec", 10);
> + d += 10;
> + break;
> + }
> + else
> + {
> + *d++ = '.';
> + continue;
> + }
> + }
> + else if (p[1] == 'B' || p[1] == 'E')
> + {
> + /* Entry Body or barrier Evaluation. */
> + p += 2;
> + while (ISDIGIT (*p))
> + p++;
> + if (p[0] == 's' && p[1] == 0)
> + break;
> + else
> + goto unknown;
> + }
> + else
> + goto unknown;
> + }
> +
> + if (p[0] == 'T' && p[1] == 'K')
> + {
> + if (p[2] == 'B' && p[3] == 0)
> + {
> + /* Subprogram for task body. */
> + break;
> + }
> + else if (p[2] == '_' && p[3] == '_')
> + {
> + /* Inner declarations in a task. */
> + p += 4;
> + *d++ = '.';
> + continue;
> + }
> + else
> + goto unknown;
> + }
> + if ((p[0] == 'P' || p[0] == 'N') && p[1] == 0)
> + {
> + /* Protected type subprogram. */
> + break;
> + }
> + if (p[0] == 'E' && p[1] == 0)
> + {
> + /* Exception name. */
> + goto unknown;
> + }
> + if (*p == 'N' || *p == 'S')
> + {
> + /* Enumerated type name table. */
> + goto unknown;
> + }
> + if (p[0] == 'X')
> + {
> + /* Body nested. */
> + if (p[1] == 'n' || p[1] == 'b')
> + p += 2;
> + else if (p[1] == 0)
> + p++;
> + }
> + if (p[0] == '.' && ISDIGIT (p[1]))
> + {
> + /* Nested subprogram. */
> + p += 2;
> + while (ISDIGIT (*p))
> + p++;
> + }
> + if (*p == 0)
> + {
> + /* End of mangled name. */
> + break;
> + }
> else
> - {
> - demangled[j] = mangled[i];
> - i += 1; j += 1;
> - }
> + goto unknown;
> }
> - demangled[j] = '\000';
> -
> - for (i = 0; demangled[i] != '\0'; i += 1)
> - if (ISUPPER ((unsigned char)demangled[i]) || demangled[i] == ' ')
> - goto Suppress;
> + *d = 0;
> + return demangled;
>
> - if (! changed)
> - {
> - free (demangled);
> - return NULL;
> - }
> - else
> - return demangled;
> -
> - Suppress:
> - grow_vect (&demangled,
> - &demangled_size, strlen (mangled) + 3,
> - sizeof (char));
> + unknown:
> + len0 = strlen (mangled);
> + demangled = XNEWVEC (char, len0 + 3);
>
> if (mangled[0] == '<')
> strcpy (demangled, mangled);
> diff --git a/libiberty/testsuite/demangle-expected b/libiberty/testsuite/demangle-expected
> index 6798154..c201a98 100644
> --- a/libiberty/testsuite/demangle-expected
> +++ b/libiberty/testsuite/demangle-expected
> @@ -3926,3 +3926,98 @@ S<int>::x::{lambda()#3}::operator()() const
> --format=gnu-v3
> _Z1fN1SUt_E
> f(S::{unnamed type#1})
> +#
> +# Ada (GNAT) tests.
> +#
> +# Simple test.
> +--format=gnat
> +yz__qrs
> +yz.qrs
> +# Operator
> +--format=gnat
> +oper__Oadd
> +oper."+"
> +# Overloaded subprogram.
> +--format=gnat
> +yz__qrs__2
> +yz.qrs
> +# Nested subprogram.
> +--format=gnat
> +yz__qrs__tuv.1661
> +yz.qrs.tuv
> +# Nested and overloaded subprograms.
> +--format=gnat
> +yz__qrs__tuv__2_1.1667
> +yz.qrs.tuv
> +--format=gnat
> +yz__qrs__tuv__2_2.1670
> +yz.qrs.tuv
> +--format=gnat
> +yz__qrs__tuv__2_3.1674
> +yz.qrs.tuv
> +# Elaborated flag (not demangled)
> +--format=gnat
> +x_E
> +<x_E>
> +# Nested package
> +--format=gnat
> +x__m1
> +x.m1
> +--format=gnat
> +x__m3
> +x.m3
> +--format=gnat
> +x__y__m2X
> +x.y.m2
> +--format=gnat
> +x__y__z__rXb
> +x.y.z.r
> +# Child package
> +--format=gnat
> +x__y__j
> +x.y.j
> +# Library level
> +--format=gnat
> +_ada_x__m3
> +x.m3
> +# Package body elaborator
> +--format=gnat
> +p___elabb
> +p'Elab_Body
> +# Package spec elaborator
> +--format=gnat
> +p___elabs
> +p'Elab_Spec
> +# Task body
> +--format=gnat
> +p__taskobjTKB
> +p.taskobj
> +# Task subprogram
> +--format=gnat
> +p__taskobjTK__f1.2330
> +p.taskobj.f1
> +# Protected types subprograms
> +--format=gnat
> +prot__lock__getN
> +prot.lock.get
> +--format=gnat
> +prot__lock__getP
> +prot.lock.get
> +--format=gnat
> +prot__lock__get__sub.2590
> +prot.lock.get.sub
> +--format=gnat
> +prot__lock__setN
> +prot.lock.set
> +--format=gnat
> +prot__lock__setP
> +prot.lock.set
> +# Protected type entries
> +--format=gnat
> +prot__lock__update_B7s
> +prot.lock.update
> +--format=gnat
> +prot__lock__update_E6s
> +prot.lock.update
> +
> +
> --
> 1.6.2
>