This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Ping [Patch/libiberty]: Rewrite of ada_demangle


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
> 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]