1 /****************************************************************************
2  *                                                                          *
3  *                         GNAT COMPILER COMPONENTS                         *
4  *                                                                          *
5  *                            A D A D E C O D E                             *
6  *                                                                          *
7  *                          C Implementation File                           *
8  *                                                                          *
9  *           Copyright (C) 2001-2012, Free Software Foundation, Inc.        *
10  *                                                                          *
11  * GNAT is free software;  you can  redistribute it  and/or modify it under *
12  * terms of the  GNU General Public License as published  by the Free Soft- *
13  * ware  Foundation;  either version 3,  or (at your option) any later ver- *
14  * sion.  GNAT is distributed in the hope that it will be useful, but WITH- *
15  * OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY *
16  * or FITNESS FOR A PARTICULAR PURPOSE.                                     *
17  *                                                                          *
18  * As a special exception under Section 7 of GPL version 3, you are granted *
19  * additional permissions described in the GCC Runtime Library Exception,   *
20  * version 3.1, as published by the Free Software Foundation.               *
21  *                                                                          *
22  * You should have received a copy of the GNU General Public License and    *
23  * a copy of the GCC Runtime Library Exception along with this program;     *
24  * see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    *
25  * <http://www.gnu.org/licenses/>.                                          *
26  *                                                                          *
27  * GNAT was originally developed  by the GNAT team at  New York University. *
28  * Extensive contributions were provided by Ada Core Technologies Inc.      *
29  *                                                                          *
30  ****************************************************************************/
31 
32 
33 #if defined(IN_RTS)
34 #include "tconfig.h"
35 #include "tsystem.h"
36 #elif defined(IN_GCC)
37 #include "config.h"
38 #include "system.h"
39 #endif
40 
41 #include <string.h>
42 #include <stdio.h>
43 #include <ctype.h>
44 
45 #include "adaint.h"  /* for a macro version of xstrdup.  */
46 
47 #ifndef ISDIGIT
48 #define ISDIGIT(c) isdigit(c)
49 #endif
50 
51 #ifndef PARMS
52 #define PARMS(ARGS) ARGS
53 #endif
54 
55 #include "adadecode.h"
56 
57 static void add_verbose (const char *, char *);
58 static int has_prefix (const char *, const char *);
59 static int has_suffix (const char *, const char *);
60 
61 /* This is a safe version of strcpy that can be used with overlapped
62    pointers. Does nothing if s2 <= s1.  */
63 static void ostrcpy (char *s1, char *s2);
64 
65 /* Set to nonzero if we have written any verbose info.  */
66 static int verbose_info;
67 
68 /* Add TEXT to end of ADA_NAME, putting a leading " (" or ", ", depending
69    on VERBOSE_INFO.  */
70 
add_verbose(const char * text,char * ada_name)71 static void add_verbose (const char *text, char *ada_name)
72 {
73   strcat (ada_name, verbose_info ? ", " : " (");
74   strcat (ada_name, text);
75 
76   verbose_info = 1;
77 }
78 
79 /* Returns 1 if NAME starts with PREFIX.  */
80 
81 static int
has_prefix(const char * name,const char * prefix)82 has_prefix (const char *name, const char *prefix)
83 {
84   return strncmp (name, prefix, strlen (prefix)) == 0;
85 }
86 
87 /* Returns 1 if NAME ends with SUFFIX.  */
88 
89 static int
has_suffix(const char * name,const char * suffix)90 has_suffix (const char *name, const char *suffix)
91 {
92   int nlen = strlen (name);
93   int slen = strlen (suffix);
94 
95   return nlen > slen && strncmp (name + nlen - slen, suffix, slen) == 0;
96 }
97 
98 /* Safe overlapped pointers version of strcpy.  */
99 
100 static void
ostrcpy(char * s1,char * s2)101 ostrcpy (char *s1, char *s2)
102 {
103   if (s2 > s1)
104     {
105       while (*s2) *s1++ = *s2++;
106       *s1 = '\0';
107     }
108 }
109 
110 /* This function will return the Ada name from the encoded form.
111    The Ada coding is done in exp_dbug.ads and this is the inverse function.
112    see exp_dbug.ads for full encoding rules, a short description is added
113    below. Right now only objects and routines are handled. Ada types are
114    stripped of their encodings.
115 
116    CODED_NAME is the encoded entity name.
117 
118    ADA_NAME is a pointer to a buffer, it will receive the Ada name. A safe
119    size for this buffer is: strlen (coded_name) * 2 + 60. (60 is for the
120    verbose information).
121 
122    VERBOSE is nonzero if more information about the entity is to be
123    added at the end of the Ada name and surrounded by ( and ).
124 
125      Coded name           Ada name                verbose info
126   ---------------------------------------------------------------------
127   _ada_xyz                xyz                     library level
128   x__y__z                 x.y.z
129   x__yTKB                 x.y                     task body
130   x__yB                   x.y                     task body
131   x__yX                   x.y                     body nested
132   x__yXb                  x.y                     body nested
133   xTK__y                  x.y                     in task
134   x__y$2                  x.y                     overloaded
135   x__y__3                 x.y                     overloaded
136   x__Oabs                 "abs"
137   x__Oand                 "and"
138   x__Omod                 "mod"
139   x__Onot                 "not"
140   x__Oor                  "or"
141   x__Orem                 "rem"
142   x__Oxor                 "xor"
143   x__Oeq                  "="
144   x__One                  "/="
145   x__Olt                  "<"
146   x__Ole                  "<="
147   x__Ogt                  ">"
148   x__Oge                  ">="
149   x__Oadd                 "+"
150   x__Osubtract            "-"
151   x__Oconcat              "&"
152   x__Omultiply            "*"
153   x__Odivide              "/"
154   x__Oexpon               "**"     */
155 
156 void
__gnat_decode(const char * coded_name,char * ada_name,int verbose)157 __gnat_decode (const char *coded_name, char *ada_name, int verbose)
158 {
159   int lib_subprog = 0;
160   int overloaded = 0;
161   int task_body = 0;
162   int in_task = 0;
163   int body_nested = 0;
164 
165   /* Deal with empty input early.  This allows assuming non-null length
166      later on, simplifying coding.  In principle, it should be our callers
167      business not to call here for empty inputs.  It is easy enough to
168      allow it, however, and might allow simplifications upstream so is not
169      a bad thing per se.  We need a guard in any case.  */
170 
171   if (*coded_name == '\0')
172     {
173       *ada_name = '\0';
174       return;
175     }
176 
177   /* Check for library level subprogram.  */
178   else if (has_prefix (coded_name, "_ada_"))
179     {
180       strcpy (ada_name, coded_name + 5);
181       lib_subprog = 1;
182     }
183   else
184     strcpy (ada_name, coded_name);
185 
186   /* Check for the first triple underscore in the name. This indicates
187      that the name represents a type with encodings; in this case, we
188      need to strip the encodings.  */
189   {
190     char *encodings;
191 
192     if ((encodings = (char *) strstr (ada_name, "___")) != NULL)
193       {
194 	*encodings = '\0';
195       }
196   }
197 
198   /* Check for task body.  */
199   if (has_suffix (ada_name, "TKB"))
200     {
201       ada_name[strlen (ada_name) - 3] = '\0';
202       task_body = 1;
203     }
204 
205   if (has_suffix (ada_name, "B"))
206     {
207       ada_name[strlen (ada_name) - 1] = '\0';
208       task_body = 1;
209     }
210 
211   /* Check for body-nested entity: X[bn] */
212   if (has_suffix (ada_name, "X"))
213     {
214       ada_name[strlen (ada_name) - 1] = '\0';
215       body_nested = 1;
216     }
217 
218   if (has_suffix (ada_name, "Xb"))
219     {
220       ada_name[strlen (ada_name) - 2] = '\0';
221       body_nested = 1;
222     }
223 
224   if (has_suffix (ada_name, "Xn"))
225     {
226       ada_name[strlen (ada_name) - 2] = '\0';
227       body_nested = 1;
228     }
229 
230   /* Change instance of TK__ (object declared inside a task) to __.  */
231   {
232     char *tktoken;
233 
234     while ((tktoken = (char *) strstr (ada_name, "TK__")) != NULL)
235       {
236 	ostrcpy (tktoken, tktoken + 2);
237 	in_task = 1;
238       }
239   }
240 
241   /* Check for overloading: name terminated by $nn or __nn.  */
242   {
243     int len = strlen (ada_name);
244     int n_digits = 0;
245 
246     if (len > 1)
247       while (ISDIGIT ((int) ada_name[(int) len - 1 - n_digits]))
248 	n_digits++;
249 
250     /* Check if we have $ or __ before digits.  */
251     if (ada_name[len - 1 - n_digits] == '$')
252       {
253 	ada_name[len - 1 - n_digits] = '\0';
254 	overloaded = 1;
255       }
256     else if (ada_name[len - 1 - n_digits] == '_'
257 	     && ada_name[len - 1 - n_digits - 1] == '_')
258       {
259 	ada_name[len - 1 - n_digits - 1] = '\0';
260 	overloaded = 1;
261       }
262   }
263 
264   /* Check for nested subprogram ending in .nnnn and strip suffix. */
265   {
266     int last = strlen (ada_name) - 1;
267 
268     while (ISDIGIT (ada_name[last]) && last > 0)
269       {
270         last--;
271       }
272 
273     if (ada_name[last] == '.')
274       {
275         ada_name[last] = (char) 0;
276       }
277   }
278 
279   /* Change all "__" to ".". */
280   {
281     int len = strlen (ada_name);
282     int k = 0;
283 
284     while (k < len)
285       {
286 	if (ada_name[k] == '_' && ada_name[k+1] == '_')
287 	  {
288 	    ada_name[k] = '.';
289 	    ostrcpy (ada_name + k + 1, ada_name + k + 2);
290 	    len = len - 1;
291 	  }
292 	k++;
293       }
294   }
295 
296   /* Checks for operator name.  */
297   {
298     const char *trans_table[][2]
299       = {{"Oabs", "\"abs\""},  {"Oand", "\"and\""},    {"Omod", "\"mod\""},
300 	 {"Onot", "\"not\""},  {"Oor", "\"or\""},      {"Orem", "\"rem\""},
301 	 {"Oxor", "\"xor\""},  {"Oeq", "\"=\""},       {"One", "\"/=\""},
302 	 {"Olt", "\"<\""},     {"Ole", "\"<=\""},      {"Ogt", "\">\""},
303 	 {"Oge", "\">=\""},    {"Oadd", "\"+\""},      {"Osubtract", "\"-\""},
304 	 {"Oconcat", "\"&\""}, {"Omultiply", "\"*\""}, {"Odivide", "\"/\""},
305 	 {"Oexpon", "\"**\""}, {NULL, NULL} };
306     int k = 0;
307 
308     while (1)
309       {
310 	char *optoken;
311 
312 	if ((optoken = (char *) strstr (ada_name, trans_table[k][0])) != NULL)
313 	  {
314 	    int codedlen = strlen (trans_table[k][0]);
315 	    int oplen = strlen (trans_table[k][1]);
316 
317 	    if (codedlen > oplen)
318 	      /* We shrink the space.  */
319 	      ostrcpy (optoken, optoken + codedlen - oplen);
320 	    else if (oplen > codedlen)
321 	      {
322 		/* We need more space.  */
323 		int len = strlen (ada_name);
324 		int space = oplen - codedlen;
325 		int num_to_move = &ada_name[len] - optoken;
326 		int t;
327 
328 		for (t = 0; t < num_to_move; t++)
329 		  ada_name[len + space - t - 1] = ada_name[len - t - 1];
330 	      }
331 
332 	    /* Write symbol in the space.  */
333 	    strncpy (optoken, trans_table[k][1], oplen);
334 	  }
335 	else
336 	  k++;
337 
338 	/* Check for table's ending.  */
339 	if (trans_table[k][0] == NULL)
340 	  break;
341       }
342   }
343 
344   /* If verbose mode is on, we add some information to the Ada name.  */
345   if (verbose)
346     {
347       if (overloaded)
348 	add_verbose ("overloaded", ada_name);
349 
350       if (lib_subprog)
351 	add_verbose ("library level", ada_name);
352 
353       if (body_nested)
354 	add_verbose ("body nested", ada_name);
355 
356       if (in_task)
357 	add_verbose ("in task", ada_name);
358 
359       if (task_body)
360 	add_verbose ("task body", ada_name);
361 
362       if (verbose_info == 1)
363 	strcat (ada_name, ")");
364     }
365 }
366 
367 #ifdef __cplusplus
368 extern "C" {
369 #endif
370 
371 #ifdef IN_GCC
372 char *
ada_demangle(const char * coded_name)373 ada_demangle (const char *coded_name)
374 {
375   char ada_name[2048];
376 
377   __gnat_decode (coded_name, ada_name, 0);
378   return xstrdup (ada_name);
379 }
380 #endif
381 
382 void
get_encoding(const char * coded_name,char * encoding)383 get_encoding (const char *coded_name, char *encoding)
384 {
385   char * dest_index = encoding;
386   const char *p;
387   int found = 0;
388   int count = 0;
389 
390   /* The heuristics is the following: we assume that the first triple
391      underscore in an encoded name indicates the beginning of the
392      first encoding, and that subsequent triple underscores indicate
393      the next encodings. We assume that the encodings are always at the
394      end of encoded names.  */
395 
396   for (p = coded_name; *p != '\0'; p++)
397     {
398       if (*p != '_')
399 	count = 0;
400       else
401 	if (++count == 3)
402 	  {
403 	    count = 0;
404 
405 	    if (found)
406 	      {
407 		dest_index = dest_index - 2;
408 		*dest_index++ = ':';
409 	      }
410 
411 	    p++;
412 	    found = 1;
413 	  }
414 
415       if (found)
416 	*dest_index++ = *p;
417     }
418 
419   *dest_index = '\0';
420 }
421 
422 #ifdef __cplusplus
423 }
424 #endif
425