| /**************************************************************************** | 
 |  *                                                                          * | 
 |  *                         GNAT COMPILER COMPONENTS                         * | 
 |  *                                                                          * | 
 |  *                            A D A D E C O D E                             * | 
 |  *                                                                          * | 
 |  *                          C Implementation File                           * | 
 |  *                                                                          * | 
 |  *           Copyright (C) 2001-2006, Free Software Foundation, Inc.        * | 
 |  *                                                                          * | 
 |  * GNAT is free software;  you can  redistribute it  and/or modify it under * | 
 |  * terms of the  GNU General Public License as published  by the Free Soft- * | 
 |  * ware  Foundation;  either version 2,  or (at your option) any later ver- * | 
 |  * sion.  GNAT is distributed in the hope that it will be useful, but WITH- * | 
 |  * OUT 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  distributed with GNAT;  see file COPYING.  If not, write * | 
 |  * to  the  Free Software Foundation,  51  Franklin  Street,  Fifth  Floor, * | 
 |  * Boston, MA 02110-1301, USA.                                              * | 
 |  *                                                                          * | 
 |  * As a  special  exception,  if you  link  this file  with other  files to * | 
 |  * produce an executable,  this file does not by itself cause the resulting * | 
 |  * executable to be covered by the GNU General Public License. This except- * | 
 |  * ion does not  however invalidate  any other reasons  why the  executable * | 
 |  * file might be covered by the  GNU Public License.                        * | 
 |  *                                                                          * | 
 |  * GNAT was originally developed  by the GNAT team at  New York University. * | 
 |  * Extensive contributions were provided by Ada Core Technologies Inc.      * | 
 |  *                                                                          * | 
 |  ****************************************************************************/ | 
 |  | 
 | #ifdef IN_GCC | 
 | #include "config.h" | 
 | #include "system.h" | 
 | #else | 
 | #include <stdio.h> | 
 | #include <ctype.h> | 
 | #define ISDIGIT(c) isdigit(c) | 
 | #define PARMS(ARGS) ARGS | 
 | #endif | 
 |  | 
 | #include "adadecode.h" | 
 |  | 
 | static void add_verbose (const char *, char *); | 
 | static int has_prefix (const char *, const char *); | 
 | static int has_suffix (const char *, const char *); | 
 |  | 
 | /* This is a safe version of strcpy that can be used with overlapped | 
 |    pointers. Does nothing if s2 <= s1.  */ | 
 | static void ostrcpy (char *s1, char *s2); | 
 |  | 
 | /* Set to nonzero if we have written any verbose info.  */ | 
 | static int verbose_info; | 
 |  | 
 | /* Add TEXT to end of ADA_NAME, putting a leading " (" or ", ", depending | 
 |    on VERBOSE_INFO.  */ | 
 |  | 
 | static void add_verbose (const char *text, char *ada_name) | 
 | { | 
 |   strcat (ada_name, verbose_info ? ", " : " ("); | 
 |   strcat (ada_name, text); | 
 |  | 
 |   verbose_info = 1; | 
 | } | 
 |  | 
 | /* Returns 1 if NAME starts with PREFIX.  */ | 
 |  | 
 | static int | 
 | has_prefix (const char *name, const char *prefix) | 
 | { | 
 |   return strncmp (name, prefix, strlen (prefix)) == 0; | 
 | } | 
 |  | 
 | /* Returns 1 if NAME ends with SUFFIX.  */ | 
 |  | 
 | static int | 
 | has_suffix (const char *name, const char *suffix) | 
 | { | 
 |   int nlen = strlen (name); | 
 |   int slen = strlen (suffix); | 
 |  | 
 |   return nlen > slen && strncmp (name + nlen - slen, suffix, slen) == 0; | 
 | } | 
 |  | 
 | /* Safe overlapped pointers version of strcpy.  */ | 
 |  | 
 | static void | 
 | ostrcpy (char *s1, char *s2) | 
 | { | 
 |   if (s2 > s1) | 
 |     { | 
 |       while (*s2) *s1++ = *s2++; | 
 |       *s1 = '\0'; | 
 |     } | 
 | } | 
 |  | 
 | /* This function will return the Ada name from the encoded form. | 
 |    The Ada coding is done in exp_dbug.ads and this is the inverse function. | 
 |    see exp_dbug.ads for full encoding rules, a short description is added | 
 |    below. Right now only objects and routines are handled. Ada types are | 
 |    stripped of their encodings. | 
 |  | 
 |    CODED_NAME is the encoded entity name. | 
 |  | 
 |    ADA_NAME is a pointer to a buffer, it will receive the Ada name. A safe | 
 |    size for this buffer is: strlen (coded_name) * 2 + 60. (60 is for the | 
 |    verbose information). | 
 |  | 
 |    VERBOSE is nonzero if more information about the entity is to be | 
 |    added at the end of the Ada name and surrounded by ( and ). | 
 |  | 
 |      Coded name           Ada name                verbose info | 
 |   --------------------------------------------------------------------- | 
 |   _ada_xyz                xyz                     library level | 
 |   x__y__z                 x.y.z | 
 |   x__yTKB                 x.y                     task body | 
 |   x__yB                   x.y                     task body | 
 |   x__yX                   x.y                     body nested | 
 |   x__yXb                  x.y                     body nested | 
 |   xTK__y                  x.y                     in task | 
 |   x__y$2                  x.y                     overloaded | 
 |   x__y__3                 x.y                     overloaded | 
 |   x__Oabs                 "abs" | 
 |   x__Oand                 "and" | 
 |   x__Omod                 "mod" | 
 |   x__Onot                 "not" | 
 |   x__Oor                  "or" | 
 |   x__Orem                 "rem" | 
 |   x__Oxor                 "xor" | 
 |   x__Oeq                  "=" | 
 |   x__One                  "/=" | 
 |   x__Olt                  "<" | 
 |   x__Ole                  "<=" | 
 |   x__Ogt                  ">" | 
 |   x__Oge                  ">=" | 
 |   x__Oadd                 "+" | 
 |   x__Osubtract            "-" | 
 |   x__Oconcat              "&" | 
 |   x__Omultiply            "*" | 
 |   x__Odivide              "/" | 
 |   x__Oexpon               "**"     */ | 
 |  | 
 | void | 
 | __gnat_decode (const char *coded_name, char *ada_name, int verbose) | 
 | { | 
 |   int lib_subprog = 0; | 
 |   int overloaded = 0; | 
 |   int task_body = 0; | 
 |   int in_task = 0; | 
 |   int body_nested = 0; | 
 |  | 
 |   /* Check for library level subprogram.  */ | 
 |   if (has_prefix (coded_name, "_ada_")) | 
 |     { | 
 |       strcpy (ada_name, coded_name + 5); | 
 |       lib_subprog = 1; | 
 |     } | 
 |   else | 
 |     strcpy (ada_name, coded_name); | 
 |  | 
 |   /* Check for the first triple underscore in the name. This indicates | 
 |      that the name represents a type with encodings; in this case, we | 
 |      need to strip the encodings.  */ | 
 |   { | 
 |     char *encodings; | 
 |  | 
 |     if ((encodings = (char *) strstr (ada_name, "___")) != NULL) | 
 |       { | 
 | 	*encodings = '\0'; | 
 |       } | 
 |   } | 
 |  | 
 |   /* Check for task body.  */ | 
 |   if (has_suffix (ada_name, "TKB")) | 
 |     { | 
 |       ada_name[strlen (ada_name) - 3] = '\0'; | 
 |       task_body = 1; | 
 |     } | 
 |  | 
 |   if (has_suffix (ada_name, "B")) | 
 |     { | 
 |       ada_name[strlen (ada_name) - 1] = '\0'; | 
 |       task_body = 1; | 
 |     } | 
 |  | 
 |   /* Check for body-nested entity: X[bn] */ | 
 |   if (has_suffix (ada_name, "X")) | 
 |     { | 
 |       ada_name[strlen (ada_name) - 1] = '\0'; | 
 |       body_nested = 1; | 
 |     } | 
 |  | 
 |   if (has_suffix (ada_name, "Xb")) | 
 |     { | 
 |       ada_name[strlen (ada_name) - 2] = '\0'; | 
 |       body_nested = 1; | 
 |     } | 
 |  | 
 |   if (has_suffix (ada_name, "Xn")) | 
 |     { | 
 |       ada_name[strlen (ada_name) - 2] = '\0'; | 
 |       body_nested = 1; | 
 |     } | 
 |  | 
 |   /* Change instance of TK__ (object declared inside a task) to __.  */ | 
 |   { | 
 |     char *tktoken; | 
 |  | 
 |     while ((tktoken = (char *) strstr (ada_name, "TK__")) != NULL) | 
 |       { | 
 | 	ostrcpy (tktoken, tktoken + 2); | 
 | 	in_task = 1; | 
 |       } | 
 |   } | 
 |  | 
 |   /* Check for overloading: name terminated by $nn or __nn.  */ | 
 |   { | 
 |     int len = strlen (ada_name); | 
 |     int n_digits = 0; | 
 |  | 
 |     if (len > 1) | 
 |       while (ISDIGIT ((int) ada_name[(int) len - 1 - n_digits])) | 
 | 	n_digits++; | 
 |  | 
 |     /* Check if we have $ or __ before digits.  */ | 
 |     if (ada_name[len - 1 - n_digits] == '$') | 
 |       { | 
 | 	ada_name[len - 1 - n_digits] = '\0'; | 
 | 	overloaded = 1; | 
 |       } | 
 |     else if (ada_name[len - 1 - n_digits] == '_' | 
 | 	     && ada_name[len - 1 - n_digits - 1] == '_') | 
 |       { | 
 | 	ada_name[len - 1 - n_digits - 1] = '\0'; | 
 | 	overloaded = 1; | 
 |       } | 
 |   } | 
 |  | 
 |   /* Change all "__" to ".". */ | 
 |   { | 
 |     int len = strlen (ada_name); | 
 |     int k = 0; | 
 |  | 
 |     while (k < len) | 
 |       { | 
 | 	if (ada_name[k] == '_' && ada_name[k+1] == '_') | 
 | 	  { | 
 | 	    ada_name[k] = '.'; | 
 | 	    ostrcpy (ada_name + k + 1, ada_name + k + 2); | 
 | 	    len = len - 1; | 
 | 	  } | 
 | 	k++; | 
 |       } | 
 |   } | 
 |  | 
 |   /* Checks for operator name.  */ | 
 |   { | 
 |     const char *trans_table[][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 = 0; | 
 |  | 
 |     while (1) | 
 |       { | 
 | 	char *optoken; | 
 |  | 
 | 	if ((optoken = (char *) strstr (ada_name, trans_table[k][0])) != NULL) | 
 | 	  { | 
 | 	    int codedlen = strlen (trans_table[k][0]); | 
 | 	    int oplen = strlen (trans_table[k][1]); | 
 |  | 
 | 	    if (codedlen > oplen) | 
 | 	      /* We shrink the space.  */ | 
 | 	      ostrcpy (optoken, optoken + codedlen - oplen); | 
 | 	    else if (oplen > codedlen) | 
 | 	      { | 
 | 		/* We need more space.  */ | 
 | 		int len = strlen (ada_name); | 
 | 		int space = oplen - codedlen; | 
 | 		int num_to_move = &ada_name[len] - optoken; | 
 | 		int t; | 
 |  | 
 | 		for (t = 0; t < num_to_move; t++) | 
 | 		  ada_name[len + space - t - 1] = ada_name[len - t - 1]; | 
 | 	      } | 
 |  | 
 | 	    /* Write symbol in the space.  */ | 
 | 	    strncpy (optoken, trans_table[k][1], oplen); | 
 | 	  } | 
 | 	else | 
 | 	  k++; | 
 |  | 
 | 	/* Check for table's ending.  */ | 
 | 	if (trans_table[k][0] == NULL) | 
 | 	  break; | 
 |       } | 
 |   } | 
 |  | 
 |   /* If verbose mode is on, we add some information to the Ada name.  */ | 
 |   if (verbose) | 
 |     { | 
 |       if (overloaded) | 
 | 	add_verbose ("overloaded", ada_name); | 
 |  | 
 |       if (lib_subprog) | 
 | 	add_verbose ("library level", ada_name); | 
 |  | 
 |       if (body_nested) | 
 | 	add_verbose ("body nested", ada_name); | 
 |  | 
 |       if (in_task) | 
 | 	add_verbose ("in task", ada_name); | 
 |  | 
 |       if (task_body) | 
 | 	add_verbose ("task body", ada_name); | 
 |  | 
 |       if (verbose_info == 1) | 
 | 	strcat (ada_name, ")"); | 
 |     } | 
 | } | 
 |  | 
 | char * | 
 | ada_demangle (const char *coded_name) | 
 | { | 
 |   char ada_name[2048]; | 
 |  | 
 |   __gnat_decode (coded_name, ada_name, 0); | 
 |   return xstrdup (ada_name); | 
 | } | 
 |  | 
 | void | 
 | get_encoding (const char *coded_name, char *encoding) | 
 | { | 
 |   char * dest_index = encoding; | 
 |   const char *p; | 
 |   int found = 0; | 
 |   int count = 0; | 
 |  | 
 |   /* The heuristics is the following: we assume that the first triple | 
 |      underscore in an encoded name indicates the beginning of the | 
 |      first encoding, and that subsequent triple underscores indicate | 
 |      the next encodings. We assume that the encodings are always at the | 
 |      end of encoded names.  */ | 
 |  | 
 |   for (p = coded_name; *p != '\0'; p++) | 
 |     { | 
 |       if (*p != '_') | 
 | 	count = 0; | 
 |       else | 
 | 	if (++count == 3) | 
 | 	  { | 
 | 	    count = 0; | 
 |  | 
 | 	    if (found) | 
 | 	      { | 
 | 		dest_index = dest_index - 2; | 
 | 		*dest_index++ = ':'; | 
 | 	      } | 
 |  | 
 | 	    p++; | 
 | 	    found = 1; | 
 | 	  } | 
 |  | 
 |       if (found) | 
 | 	*dest_index++ = *p; | 
 |     } | 
 |  | 
 |   *dest_index = '\0'; | 
 | } |