blob: fe0253ee09f315eb447cf4287af9151e5f53d34b [file] [log] [blame]
/****************************************************************************
* *
* GNAT COMPILER COMPONENTS *
* *
* A D A D E C O D E *
* *
* C Implementation File *
* *
* Copyright (C) 2001-2003, 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, 59 Temple Place - Suite 330, Boston, *
* MA 02111-1307, 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. There is no support
for Ada types.
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 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);
}