#include "config.h"
#endif
-#include <ctype.h>
-
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
/* If CP_DEMANGLE_DEBUG is defined, a trace of the grammar evaluation,
and other debugging output, will be generated. */
#ifdef CP_DEMANGLE_DEBUG
-#define DEMANGLE_TRACE(PRODUCTION, DM) \
- fprintf (stderr, " -> %-24s at position %3d\n", \
+#define DEMANGLE_TRACE(PRODUCTION, DM) \
+ fprintf (stderr, " -> %-24s at position %3d\n", \
(PRODUCTION), current_position (DM));
#else
#define DEMANGLE_TRACE(PRODUCTION, DM)
#endif
+/* Don't include <ctype.h>, to prevent additional unresolved symbols
+ from being dragged into the C++ runtime library. */
+#define IS_DIGIT(CHAR) ((CHAR) >= '0' && (CHAR) <= '9')
+#define IS_ALPHA(CHAR) \
+ (((CHAR) >= 'a' && (CHAR) <= 'z') \
+ || ((CHAR) >= 'A' && (CHAR) <= 'Z'))
+
/* If flag_verbose is zero, some simplifications will be made to the
output to make it easier to read and supress details that are
generally not of interest to the average C++ programmer.
struct demangling_def
{
/* The full mangled name being mangled. */
- char *name;
+ const char *name;
/* Pointer into name at the current position. */
- char *next;
+ const char *next;
/* Stack for strings containing demangled result generated so far.
Text is emitted to the topmost (first) string. */
typedef const char *status_t;
/* Special values that can be used as a status_t. */
-#define STATUS_OK NULL
-#define STATUS_ERROR "Error."
-#define STATUS_UNIMPLEMENTED "Unimplemented."
-#define STATUS_INTERNAL_ERROR "Internal error."
+#define STATUS_OK NULL
+#define STATUS_ERROR "Error."
+#define STATUS_UNIMPLEMENTED "Unimplemented."
+#define STATUS_INTERNAL_ERROR "Internal error."
+
+/* This status code indicates a failure in malloc or realloc. */
+static const char* const status_allocation_failed = "Allocation failed.";
+#define STATUS_ALLOCATION_FAILED status_allocation_failed
+
+/* Non-zero if STATUS indicates that no error has occurred. */
+#define STATUS_NO_ERROR(STATUS) ((STATUS) == STATUS_OK)
-static void int_to_dyn_string
+/* Evaluate EXPR, which must produce a status_t. If the status code
+ indicates an error, return from the current function with that
+ status code. */
+#define RETURN_IF_ERROR(EXPR) \
+ do \
+ { \
+ status_t s = EXPR; \
+ if (!STATUS_NO_ERROR (s)) \
+ return s; \
+ } \
+ while (0)
+
+static status_t int_to_dyn_string
PARAMS ((int, dyn_string_t));
static string_list_t string_list_new
PARAMS ((int));
static void string_list_delete
PARAMS ((string_list_t));
-static void result_close_template_list
+static status_t result_close_template_list
PARAMS ((demangling_t));
-static void result_push
+static status_t result_push
PARAMS ((demangling_t));
static string_list_t result_pop
PARAMS ((demangling_t));
static int substitution_start
PARAMS ((demangling_t));
-static void substitution_add
+static status_t substitution_add
PARAMS ((demangling_t, int, int, int));
static dyn_string_t substitution_get
PARAMS ((demangling_t, int, int *));
static template_arg_list_t current_template_arg_list
PARAMS ((demangling_t));
static demangling_t demangling_new
- PARAMS ((char *));
+ PARAMS ((const char *));
static void demangling_delete
PARAMS ((demangling_t));
(dyn_string_buf (DS)[dyn_string_length (DS) - 1])
/* Append a space character (` ') to DS if it does not already end
- with one. */
+ with one. Evaluates to 1 on success, or 0 on allocation failure. */
#define dyn_string_append_space(DS) \
- do \
- { \
- if (dyn_string_length (DS) > 0 \
- && dyn_string_last_char (DS) != ' ') \
- dyn_string_append_char ((DS), ' '); \
- } \
- while (0)
+ ((dyn_string_length (DS) > 0 \
+ && dyn_string_last_char (DS) != ' ') \
+ ? dyn_string_append_char ((DS), ' ') \
+ : 1)
/* Returns the index of the current position in the mangled name. */
#define current_position(DM) ((DM)->next - (DM)->name)
/* Appends a dyn_string_t to the demangled result. */
#define result_append_string(DM, STRING) \
- dyn_string_append (&(DM)->result->string, (STRING))
+ (dyn_string_append (&(DM)->result->string, (STRING)) \
+ ? STATUS_OK : STATUS_ALLOCATION_FAILED)
/* Appends NUL-terminated string CSTR to the demangled result. */
#define result_append(DM, CSTR) \
- dyn_string_append_cstr (&(DM)->result->string, (CSTR))
+ (dyn_string_append_cstr (&(DM)->result->string, (CSTR)) \
+ ? STATUS_OK : STATUS_ALLOCATION_FAILED)
/* Appends character CHAR to the demangled result. */
#define result_append_char(DM, CHAR) \
- dyn_string_append_char (&(DM)->result->string, (CHAR))
+ (dyn_string_append_char (&(DM)->result->string, (CHAR)) \
+ ? STATUS_OK : STATUS_ALLOCATION_FAILED)
/* The length of the current demangled result. */
#define result_length(DM) \
/* Appends a space to the demangled result if the last character is
not a space. */
#define result_append_space(DM) \
- dyn_string_append_space (&(DM)->result->string)
-
-/* Evaluate EXPR, which must produce a status_t. If the status code
- indicates an error, return from the current function with that
- status code. */
-#define RETURN_IF_ERROR(EXPR) \
- do \
- { \
- status_t s = EXPR; \
- if (s != STATUS_OK) \
- return s; \
- } \
- while (0)
+ (dyn_string_append_space (&(DM)->result->string) \
+ ? STATUS_OK : STATUS_ALLOCATION_FAILED)
-/* Appends a base 10 representation of VALUE to DS. */
+/* Appends a base 10 representation of VALUE to DS. STATUS_OK on
+ success. On failure, deletes DS and returns an error code. */
-static void
+static status_t
int_to_dyn_string (value, ds)
int value;
dyn_string_t ds;
/* Handle zero up front. */
if (value == 0)
{
- dyn_string_append_char (ds, '0');
- return;
+ if (!dyn_string_append_char (ds, '0'))
+ return STATUS_ALLOCATION_FAILED;
+ return STATUS_OK;
}
/* For negative numbers, emit a minus sign. */
if (value < 0)
{
- dyn_string_append_char (ds, '-');
+ if (!dyn_string_append_char (ds, '-'))
+ return STATUS_ALLOCATION_FAILED;
value = -value;
}
while (mask > 0)
{
int digit = value / mask;
- dyn_string_append_char (ds, '0' + digit);
+
+ if (!dyn_string_append_char (ds, '0' + digit))
+ return STATUS_ALLOCATION_FAILED;
+
value -= digit * mask;
mask /= 10;
}
+
+ return STATUS_OK;
}
/* Creates a new string list node. The contents of the string are
empty, but the initial buffer allocation is LENGTH. The string
- list node should be deleted with string_list_delete. */
+ list node should be deleted with string_list_delete. Returns NULL
+ if allocation fails. */
static string_list_t
string_list_new (length)
int length;
{
- string_list_t s =
- (string_list_t) xmalloc (sizeof (struct string_list_def));
- dyn_string_init ((dyn_string_t) s, length);
+ string_list_t s = (string_list_t) malloc (sizeof (struct string_list_def));
+ if (s == NULL)
+ return NULL;
+ if (!dyn_string_init ((dyn_string_t) s, length))
+ return NULL;
return s;
}
first, so that the two greater-than characters don't look like a
right shift token. */
-static void
+static status_t
result_close_template_list (dm)
demangling_t dm;
{
dyn_string_t s = &dm->result->string;
+
+ /* Add a space if the last character is already a closing angle
+ bracket, so that a nested template arg list doesn't look like
+ it's closed with a right-shift operator. */
if (dyn_string_last_char (s) == '>')
- dyn_string_append_char (s, ' ');
- dyn_string_append_char (s, '>');
+ {
+ if (!dyn_string_append_char (s, ' '))
+ return STATUS_ALLOCATION_FAILED;
+ }
+
+ /* Add closing angle brackets. */
+ if (!dyn_string_append_char (s, '>'))
+ return STATUS_ALLOCATION_FAILED;
+
+ return STATUS_OK;
}
/* Allocates and pushes a new string onto the demangled results stack
- for DM. Subsequent demangling with DM will emit to the new string. */
+ for DM. Subsequent demangling with DM will emit to the new string.
+ Returns STATUS_OK on success, STATUS_ALLOCATION_FAILED on
+ allocation failure. */
-static void
+static status_t
result_push (dm)
demangling_t dm;
{
string_list_t new_string = string_list_new (0);
+ if (new_string == NULL)
+ /* Allocation failed. */
+ return STATUS_ALLOCATION_FAILED;
+
+ /* Link the new string to the front of the list of result strings. */
new_string->next = (string_list_t) dm->result;
dm->result = new_string;
+ return STATUS_OK;
}
/* Removes and returns the topmost element on the demangled results
otherwise-identical types and other <template-param>s with
different indices. */
-static void
+static status_t
substitution_add (dm, start_position, template_p, template_parm_number)
demangling_t dm;
int start_position;
dyn_string_t substitution = dyn_string_new (0);
int i;
- dyn_string_substring (substitution,
- result, start_position, result_length (dm));
+ if (substitution == NULL)
+ return STATUS_ALLOCATION_FAILED;
+
+ /* Extract the substring of the current demangling result that
+ represents the subsitution candidate. */
+ if (!dyn_string_substring (substitution,
+ result, start_position, result_length (dm)))
+ {
+ dyn_string_delete (substitution);
+ return STATUS_ALLOCATION_FAILED;
+ }
/* Check whether SUBSTITUTION already occurs. */
for (i = 0; i < dm->num_substitutions; ++i)
/* Callers expect this function to take ownership of
SUBSTITUTION, so delete it. */
dyn_string_delete (substitution);
- return;
+ return STATUS_OK;
}
/* If there's no room for the new entry, grow the array. */
if (dm->substitutions_allocated == dm->num_substitutions)
{
+ size_t new_array_size;
dm->substitutions_allocated *= 2;
- dm->substitutions = (struct substitution_def *)
- xrealloc (dm->substitutions,
- sizeof (struct substitution_def)
- * dm->substitutions_allocated);
+ new_array_size =
+ sizeof (struct substitution_def) * dm->substitutions_allocated;
+
+ dm->substitutions = (struct substitution_def *)
+ realloc (dm->substitutions, new_array_size);
+ if (dm->substitutions == NULL)
+ /* Realloc failed. */
+ {
+ dyn_string_delete (substitution);
+ return STATUS_ALLOCATION_FAILED;
+ }
}
/* Add the substitution to the array. */
#ifdef CP_DEMANGLE_DEBUG
substitutions_print (dm, stderr);
#endif
+
+ return STATUS_OK;
}
/* Returns the Nth-most-recent substitution. Sets *TEMPLATE_P to
#endif /* CP_DEMANGLE_DEBUG */
-/* Creates a new template argument list. */
+/* Creates a new template argument list. Returns NULL if allocation
+ fails. */
static template_arg_list_t
template_arg_list_new ()
{
- template_arg_list_t new_list
- = (template_arg_list_t) xmalloc (sizeof (struct template_arg_list_def));
+ template_arg_list_t new_list =
+ (template_arg_list_t) malloc (sizeof (struct template_arg_list_def));
+ if (new_list == NULL)
+ return NULL;
/* Initialize the new list to have no arguments. */
new_list->first_argument = NULL;
new_list->last_argument = NULL;
}
/* Allocates a demangling_t object for demangling mangled NAME. A new
- result must be pushed before the returned object can be used. */
+ result must be pushed before the returned object can be used.
+ Returns NULL if allocation fails. */
static demangling_t
demangling_new (name)
- char *name;
+ const char *name;
{
- demangling_t dm = (demangling_t)
- xmalloc (sizeof (struct demangling_def));
+ demangling_t dm;
+ dm = (demangling_t) malloc (sizeof (struct demangling_def));
+ if (dm == NULL)
+ return NULL;
dm->name = name;
dm->next = name;
dm->result = NULL;
- dm->last_source_name = dyn_string_new (0);
dm->num_substitutions = 0;
dm->substitutions_allocated = 10;
- dm->substitutions = (struct substitution_def *)
- xmalloc (dm->substitutions_allocated * sizeof (struct substitution_def));
dm->template_arg_lists = NULL;
+ dm->last_source_name = dyn_string_new (0);
+ if (dm->last_source_name == NULL)
+ return NULL;
+ dm->substitutions = (struct substitution_def *)
+ malloc (dm->substitutions_allocated * sizeof (struct substitution_def));
+ if (dm->substitutions == NULL)
+ {
+ dyn_string_delete (dm->last_source_name);
+ return NULL;
+ }
return dm;
}
static status_t demangle_discriminator
PARAMS ((demangling_t, int));
static status_t cp_demangle
- PARAMS ((char *, dyn_string_t));
+ PARAMS ((const char *, dyn_string_t));
+static status_t cp_demangle_type
+ PARAMS ((const char*, dyn_string_t));
/* When passed to demangle_bare_function_type, indicates that the
function's return type is not encoded before its parameter types. */
<encoding> ::= <function name> <bare-function-type>
::= <data name>
- ::= <substitution> */
+ ::= <special-name> */
static status_t
demangle_encoding (dm)
demangling_t dm;
{
int template_p;
- int special_std_substitution;
int start_position;
- int start = substitution_start (dm);
template_arg_list_t old_arg_list = current_template_arg_list (dm);
char peek = peek_char (dm);
function, we'll have to insert the return type here. */
start_position = result_length (dm);
- if (peek == 'S')
- {
- RETURN_IF_ERROR (demangle_substitution (dm, &template_p,
- &special_std_substitution));
- if (special_std_substitution)
- {
- /* This was the magic `std::' substitution. */
- result_append (dm, "::");
- RETURN_IF_ERROR (demangle_encoding (dm));
- }
- }
- else if (peek == 'G' || peek == 'T')
+ if (peek == 'G' || peek == 'T')
RETURN_IF_ERROR (demangle_special_name (dm));
else
{
RETURN_IF_ERROR
(demangle_bare_function_type (dm, BFT_NO_RETURN_TYPE));
}
-
- substitution_add (dm, start, template_p, NOT_TEMPLATE_PARM);
}
/* Pop off template argument lists that were built during the
case 'S':
/* The `St' substitution allows a name nested in std:: to appear
- without being enclosed in a nested name.
- <name> ::= St <unqualified-name> # ::std:: */
+ without being enclosed in a nested name. */
if (peek_char_next (dm) == 't')
{
(void) next_char (dm);
(void) next_char (dm);
- result_append (dm, "std::");
+ RETURN_IF_ERROR (result_append (dm, "std::"));
RETURN_IF_ERROR (demangle_unqualified_name (dm));
}
else
/* This was the magic `std::' substitution. We can have
a <nested-name> or one of the unscoped names
following. */
- result_append (dm, "::");
+ RETURN_IF_ERROR (result_append (dm, "::"));
RETURN_IF_ERROR (demangle_name (dm, template_p));
}
}
+ /* Check if a template argument list immediately follows.
+ If so, then we just demangled an <unqualified-template-name>. */
+ if (peek_char (dm) == 'I')
+ {
+ RETURN_IF_ERROR (substitution_add (dm, start, 0,
+ NOT_TEMPLATE_PARM));
+ RETURN_IF_ERROR (demangle_template_args (dm));
+ }
break;
default:
if (peek_char (dm) == 'I')
{
/* Add a substitution for the unqualified template name. */
- substitution_add (dm, start, 0, NOT_TEMPLATE_PARM);
+ RETURN_IF_ERROR (substitution_add (dm, start, 0,
+ NOT_TEMPLATE_PARM));
RETURN_IF_ERROR (demangle_template_args (dm));
*template_p = 1;
peek = peek_char (dm);
if (peek == 'r' || peek == 'V' || peek == 'K')
{
+ status_t status;
+
/* Snarf up and emit CV qualifiers. */
dyn_string_t cv_qualifiers = dyn_string_new (24);
+ if (cv_qualifiers == NULL)
+ return STATUS_ALLOCATION_FAILED;
+
demangle_CV_qualifiers (dm, cv_qualifiers);
- result_append_string (dm, cv_qualifiers);
+ status = result_append_string (dm, cv_qualifiers);
dyn_string_delete (cv_qualifiers);
- result_append_space (dm);
+ RETURN_IF_ERROR (status);
+ RETURN_IF_ERROR (result_append_space (dm));
}
RETURN_IF_ERROR (demangle_prefix (dm, template_p));
peek = peek_char (dm);
- if (isdigit ((unsigned char) peek)
+ if (IS_DIGIT ((unsigned char) peek)
|| (peek >= 'a' && peek <= 'z')
|| peek == 'C' || peek == 'D'
|| peek == 'S')
{
/* We have another level of scope qualification. */
if (nested)
- result_append (dm, "::");
+ RETURN_IF_ERROR (result_append (dm, "::"));
else
nested = 1;
if (*template_p)
return STATUS_INTERNAL_ERROR;
/* The template name is a substitution candidate. */
- substitution_add (dm, start, 0, NOT_TEMPLATE_PARM);
+ RETURN_IF_ERROR (substitution_add (dm, start, 0, NOT_TEMPLATE_PARM));
RETURN_IF_ERROR (demangle_template_args (dm));
*template_p = 1;
}
return "Unexpected character in <compound-name>.";
/* Add a new substitution for the prefix thus far. */
- substitution_add (dm, start, *template_p, NOT_TEMPLATE_PARM);
+ RETURN_IF_ERROR (substitution_add (dm, start, *template_p,
+ NOT_TEMPLATE_PARM));
}
}
DEMANGLE_TRACE ("unqualified-name", dm);
- if (isdigit ((unsigned char) peek))
+ if (IS_DIGIT ((unsigned char) peek))
RETURN_IF_ERROR (demangle_source_name (dm));
else if (peek >= 'a' && peek <= 'z')
{
dm->last_source_name));
/* Emit it. */
- result_append_string (dm, dm->last_source_name);
+ RETURN_IF_ERROR (result_append_string (dm, dm->last_source_name));
return STATUS_OK;
}
DEMANGLE_TRACE ("number", dm);
+ if (number == NULL)
+ return STATUS_ALLOCATION_FAILED;
+
demangle_number_literally (dm, number, base, is_signed);
*value = strtol (dyn_string_buf (number), NULL, base);
dyn_string_delete (number);
advance_char (dm);
/* The normal way to write a negative number is with a minus
sign. */
- dyn_string_append_char (str, '-');
+ if (!dyn_string_append_char (str, '-'))
+ return STATUS_ALLOCATION_FAILED;
}
/* Loop until we hit a non-digit. */
while (1)
{
char peek = peek_char (dm);
- if (isdigit ((unsigned char) peek)
+ if (IS_DIGIT ((unsigned char) peek)
|| (base == 36 && peek >= 'A' && peek <= 'Z'))
- /* Accumulate digits. */
- dyn_string_append_char (str, next_char (dm));
+ {
+ /* Accumulate digits. */
+ if (!dyn_string_append_char (str, next_char (dm)))
+ return STATUS_ALLOCATION_FAILED;
+ }
else
/* Not a digit? All done. */
break;
DEMANGLE_TRACE ("identifier", dm);
dyn_string_clear (identifier);
- dyn_string_resize (identifier, length);
+ if (!dyn_string_resize (identifier, length))
+ return STATUS_ALLOCATION_FAILED;
+
while (length-- > 0)
{
if (end_of_name_p (dm))
return "Unexpected end of name in <identifier>.";
- dyn_string_append_char (identifier, next_char (dm));
+ if (!dyn_string_append_char (identifier, next_char (dm)))
+ return STATUS_ALLOCATION_FAILED;
}
return STATUS_OK;
/* Is this a vendor extended operator? */
if (c0 == 'v' && c1 == 'x')
{
- result_append (dm, "operator");
+ RETURN_IF_ERROR (result_append (dm, "operator"));
RETURN_IF_ERROR (demangle_source_name (dm));
*num_args = 0;
return STATUS_OK;
/* Is this a conversion operator? */
if (c0 == 'c' && c1 == 'v')
{
- result_append (dm, "operator ");
+ RETURN_IF_ERROR (result_append (dm, "operator "));
/* Demangle the converted-to type. */
RETURN_IF_ERROR (demangle_type (dm));
*num_args = 0;
/* Found it. */
{
if (!short_name)
- result_append (dm, "operator");
- result_append (dm, p->name);
+ RETURN_IF_ERROR (result_append (dm, "operator"));
+ RETURN_IF_ERROR (result_append (dm, p->name));
*num_args = p->num_args;
return STATUS_OK;
/* A guard variable name. Consume the G. */
advance_char (dm);
RETURN_IF_ERROR (demangle_char (dm, 'V'));
- result_append (dm, "guard variable for ");
+ RETURN_IF_ERROR (result_append (dm, "guard variable for "));
RETURN_IF_ERROR (demangle_name (dm, &unused));
}
else if (peek == 'T')
{
+ status_t status = STATUS_OK;
+
/* Other C++ implementation miscellania. Consume the T. */
advance_char (dm);
case 'V':
/* Virtual table. */
advance_char (dm);
- result_append (dm, "vtable for ");
+ RETURN_IF_ERROR (result_append (dm, "vtable for "));
RETURN_IF_ERROR (demangle_type (dm));
break;
case 'T':
/* VTT structure. */
advance_char (dm);
- result_append (dm, "VTT for ");
+ RETURN_IF_ERROR (result_append (dm, "VTT for "));
RETURN_IF_ERROR (demangle_type (dm));
break;
case 'I':
/* Typeinfo structure. */
advance_char (dm);
- result_append (dm, "typeinfo for ");
+ RETURN_IF_ERROR (result_append (dm, "typeinfo for "));
RETURN_IF_ERROR (demangle_type (dm));
break;
case 'F':
/* Typeinfo function. Used only in old ABI with new mangling. */
advance_char (dm);
- result_append (dm, "typeinfo fn for ");
+ RETURN_IF_ERROR (result_append (dm, "typeinfo fn for "));
RETURN_IF_ERROR (demangle_type (dm));
break;
case 'S':
/* Character string containing type name, used in typeinfo. */
advance_char (dm);
- result_append (dm, "typeinfo name for ");
+ RETURN_IF_ERROR (result_append (dm, "typeinfo name for "));
RETURN_IF_ERROR (demangle_type (dm));
break;
case 'J':
/* The java Class variable corresponding to a C++ class. */
advance_char (dm);
- result_append (dm, "java Class for ");
+ RETURN_IF_ERROR (result_append (dm, "java Class for "));
RETURN_IF_ERROR (demangle_type (dm));
break;
case 'h':
/* Non-virtual thunk. */
advance_char (dm);
- result_append (dm, "non-virtual thunk");
+ RETURN_IF_ERROR (result_append (dm, "non-virtual thunk"));
/* Demangle and emit the offset. */
number = dyn_string_new (4);
+ if (number == NULL)
+ return STATUS_ALLOCATION_FAILED;
demangle_number_literally (dm, number, 10, 1);
/* Don't display the offset unless in verbose mode. */
if (flag_verbose)
{
- result_append_char (dm, ' ');
- result_append_string (dm, number);
+ status = result_append_char (dm, ' ');
+ if (STATUS_NO_ERROR (status))
+ status = result_append_string (dm, number);
}
dyn_string_delete (number);
+ RETURN_IF_ERROR (status);
/* Demangle the separator. */
RETURN_IF_ERROR (demangle_char (dm, '_'));
/* Demangle and emit the target name and function type. */
- result_append (dm, " to ");
+ RETURN_IF_ERROR (result_append (dm, " to "));
RETURN_IF_ERROR (demangle_encoding (dm));
break;
case 'v':
/* Virtual thunk. */
advance_char (dm);
- result_append (dm, "virtual thunk ");
+ RETURN_IF_ERROR (result_append (dm, "virtual thunk "));
/* Demangle and emit the offset. */
number = dyn_string_new (4);
+ if (number == NULL)
+ return STATUS_ALLOCATION_FAILED;
demangle_number_literally (dm, number, 10, 1);
/* Don't display the offset unless in verbose mode. */
if (flag_verbose)
{
- result_append_string (dm, number);
- result_append_char (dm, ' ');
+ status = result_append_string (dm, number);
+ if (STATUS_NO_ERROR (status))
+ result_append_char (dm, ' ');
}
dyn_string_delete (number);
+ RETURN_IF_ERROR (status);
/* Demangle the separator. */
RETURN_IF_ERROR (demangle_char (dm, '_'));
/* Demangle and emit the vcall offset. */
number = dyn_string_new (4);
+ if (number == NULL)
+ return STATUS_ALLOCATION_FAILED;
demangle_number_literally (dm, number, 10, 1);
/* Don't display the vcall offset unless in verbose mode. */
if (flag_verbose)
{
- result_append_string (dm, number);
- result_append_char (dm, ' ');
+ status = result_append_string (dm, number);
+ if (STATUS_NO_ERROR (status))
+ status = result_append_char (dm, ' ');
}
dyn_string_delete (number);
+ RETURN_IF_ERROR (status);
/* Demangle the separator. */
RETURN_IF_ERROR (demangle_char (dm, '_'));
/* Demangle and emit the target function. */
- result_append (dm, "to ");
+ RETURN_IF_ERROR (result_append (dm, "to "));
RETURN_IF_ERROR (demangle_encoding (dm));
break;
/* TC is a special g++ mangling for a construction vtable. */
if (!flag_strict)
{
+ dyn_string_t derived_type;
+
advance_char (dm);
- result_append (dm, "construction vtable for ");
+ RETURN_IF_ERROR (result_append (dm, "construction vtable for "));
+
+ /* Demangle the derived type off to the side. */
+ RETURN_IF_ERROR (result_push (dm));
RETURN_IF_ERROR (demangle_type (dm));
+ derived_type = (dyn_string_t) result_pop (dm);
+
/* Demangle the offset. */
number = dyn_string_new (4);
+ if (number == NULL)
+ {
+ dyn_string_delete (derived_type);
+ return STATUS_ALLOCATION_FAILED;
+ }
demangle_number_literally (dm, number, 10, 1);
/* Demangle the underscore separator. */
- RETURN_IF_ERROR (demangle_char (dm, '_'));
+ status = demangle_char (dm, '_');
+
/* Demangle the base type. */
- result_append (dm, "-in-");
- RETURN_IF_ERROR (demangle_type (dm));
+ if (STATUS_NO_ERROR (status))
+ status = demangle_type (dm);
+
+ /* Emit the derived type. */
+ if (STATUS_NO_ERROR (status))
+ status = result_append (dm, "-in-");
+ if (STATUS_NO_ERROR (status))
+ status = result_append_string (dm, derived_type);
+ dyn_string_delete (derived_type);
+
/* Don't display the offset unless in verbose mode. */
if (flag_verbose)
{
- result_append_char (dm, ' ');
- result_append_string (dm, number);
+ status = result_append_char (dm, ' ');
+ if (STATUS_NO_ERROR (status))
+ result_append_string (dm, number);
}
dyn_string_delete (number);
+ RETURN_IF_ERROR (status);
break;
}
/* If flag_strict, fall through. */
advance_char (dm);
if (peek_char (dm) < '1' || peek_char (dm) > '4')
return "Unrecognized constructor.";
- result_append_string (dm, dm->last_source_name);
+ RETURN_IF_ERROR (result_append_string (dm, dm->last_source_name));
/* Print the flavor of the constructor if in verbose mode. */
flavor = next_char (dm) - '1';
if (flag_verbose)
{
- result_append (dm, "[");
- result_append (dm, ctor_flavors[flavor]);
- result_append_char (dm, ']');
+ RETURN_IF_ERROR (result_append (dm, "["));
+ RETURN_IF_ERROR (result_append (dm, ctor_flavors[flavor]));
+ RETURN_IF_ERROR (result_append_char (dm, ']'));
}
}
else if (peek == 'D')
advance_char (dm);
if (peek_char (dm) < '0' || peek_char (dm) > '2')
return "Unrecognized destructor.";
- result_append_char (dm, '~');
- result_append_string (dm, dm->last_source_name);
+ RETURN_IF_ERROR (result_append_char (dm, '~'));
+ RETURN_IF_ERROR (result_append_string (dm, dm->last_source_name));
/* Print the flavor of the destructor if in verbose mode. */
flavor = next_char (dm) - '0';
if (flag_verbose)
{
- result_append (dm, " [");
- result_append (dm, dtor_flavors[flavor]);
- result_append_char (dm, ']');
+ RETURN_IF_ERROR (result_append (dm, " ["));
+ RETURN_IF_ERROR (result_append (dm, dtor_flavors[flavor]));
+ RETURN_IF_ERROR (result_append_char (dm, ']'));
}
}
else
DEMANGLE_TRACE ("type*", dm);
+ if (symbols == NULL)
+ return STATUS_ALLOCATION_FAILED;
+
/* Scan forward, collecting pointers and references into symbols,
until we hit something else. Then emit the type. */
while (1)
next = peek_char (dm);
if (next == 'P')
{
- dyn_string_append_char (symbols, '*');
+ if (!dyn_string_append_char (symbols, '*'))
+ return STATUS_ALLOCATION_FAILED;
advance_char (dm);
}
else if (next == 'R')
{
- dyn_string_append_char (symbols, '&');
+ if (!dyn_string_append_char (symbols, '&'))
+ return STATUS_ALLOCATION_FAILED;
advance_char (dm);
}
else if (next == 'M')
advance_char (dm);
/* Capture the type of which this is a pointer-to-member. */
- result_push (dm);
+ RETURN_IF_ERROR (result_push (dm));
RETURN_IF_ERROR (demangle_type (dm));
class_type = (dyn_string_t) result_pop (dm);
/* Build the pointer-to-member notation. It comes before
other pointer and reference qualifiers -- */
- dyn_string_prepend_cstr (symbols, "::*");
- dyn_string_prepend (symbols, class_type);
+ if (!dyn_string_prepend_cstr (symbols, "::*"))
+ return STATUS_ALLOCATION_FAILED;
+ if (!dyn_string_prepend (symbols, class_type))
+ return STATUS_ALLOCATION_FAILED;
dyn_string_delete (class_type);
if (peek_char (dm) == 'F')
/* Demangle the type of the pointed-to member. */
status = demangle_type (dm);
/* Make it pretty. */
- result_append_space (dm);
+ if (STATUS_NO_ERROR (status))
+ status = result_append_space (dm);
/* Add the pointer-to-member syntax, and other pointer and
reference symbols. */
- result_append_string (dm, symbols);
+ if (STATUS_NO_ERROR (status))
+ status = result_append_string (dm, symbols);
/* Clean up. */
dyn_string_delete (symbols);
{
/* Ooh, tricky, a pointer-to-function. */
int position = result_length (dm);
- result_append_char (dm, '(');
- result_append_string (dm, symbols);
- result_append_char (dm, ')');
+ status = result_append_char (dm, '(');
+ if (STATUS_NO_ERROR (status))
+ status = result_append_string (dm, symbols);
+ if (STATUS_NO_ERROR (status))
+ status = result_append_char (dm, ')');
dyn_string_delete (symbols);
+ RETURN_IF_ERROR (status);
RETURN_IF_ERROR (demangle_function_type (dm, position));
return STATUS_OK;
/* No more pointe or reference tokens. Finish up. */
status = demangle_type (dm);
- result_append_string (dm, symbols);
+ if (STATUS_NO_ERROR (status))
+ status = result_append_string (dm, symbols);
dyn_string_delete (symbols);
+ RETURN_IF_ERROR (status);
RETURN_IF_ERROR (status);
return STATUS_OK;
{
int start = substitution_start (dm);
char peek = peek_char (dm);
+ char peek_next;
int template_p = 0;
int special_std_substitution;
int is_builtin_type = 0;
/* A <class-enum-type> can start with a digit (a <source-name>), an
N (a <nested-name>), or a Z (a <local-name>). */
- if (isdigit ((unsigned char) peek) || peek == 'N' || peek == 'Z')
+ if (IS_DIGIT ((unsigned char) peek) || peek == 'N' || peek == 'Z')
RETURN_IF_ERROR (demangle_class_enum_type (dm, &template_p));
else if (peek >= 'a' && peek <= 'z')
{
{
status_t status;
dyn_string_t cv_qualifiers = dyn_string_new (24);
+
+ if (cv_qualifiers == NULL)
+ return STATUS_ALLOCATION_FAILED;
+
demangle_CV_qualifiers (dm, cv_qualifiers);
/* If the qualifiers apply to a pointer or reference, they
if (peek_char (dm) == 'P' || peek_char (dm) == 'R')
{
status = demangle_type (dm);
- result_append_space (dm);
- result_append_string (dm, cv_qualifiers);
+ if (STATUS_NO_ERROR (status))
+ status = result_append_space (dm);
+ if (STATUS_NO_ERROR (status))
+ status = result_append_string (dm, cv_qualifiers);
}
/* Otherwise, the qualifiers come first. */
else
{
- result_append_string (dm, cv_qualifiers);
- result_append_space (dm);
- status = demangle_type (dm);
+ status = result_append_string (dm, cv_qualifiers);
+ if (STATUS_NO_ERROR (status))
+ status = result_append_space (dm);
+ if (STATUS_NO_ERROR (status))
+ status = demangle_type (dm);
}
dyn_string_delete (cv_qualifiers);
break;
case 'S':
- RETURN_IF_ERROR (demangle_substitution (dm, &template_p,
- &special_std_substitution));
- if (special_std_substitution)
- {
- /* This was the magic `std::' substitution. What follows
- must be a class name in that namespace. */
- result_append (dm, "::");
- RETURN_IF_ERROR (demangle_class_enum_type (dm, &template_p));
- }
+ /* First check if this is a special substitution. If it is,
+ this is a <class-enum-type>. Special substitutions have a
+ letter following the `S'; other substitutions have a digit
+ or underscore. */
+ peek_next = peek_char_next (dm);
+ if (IS_DIGIT (peek_next) || peek_next == '_')
+ RETURN_IF_ERROR (demangle_substitution (dm, &template_p,
+ &special_std_substitution));
+ else
+ demangle_class_enum_type (dm, &template_p);
break;
case 'P':
case 'C':
/* A C99 complex type. */
- result_append (dm, "complex ");
+ RETURN_IF_ERROR (result_append (dm, "complex "));
advance_char (dm);
RETURN_IF_ERROR (demangle_type (dm));
break;
case 'G':
/* A C99 imaginary type. */
- result_append (dm, "imaginary ");
+ RETURN_IF_ERROR (result_append (dm, "imaginary "));
advance_char (dm);
RETURN_IF_ERROR (demangle_type (dm));
break;
/* Vendor extended type qualifier. */
advance_char (dm);
RETURN_IF_ERROR (demangle_source_name (dm));
- result_append_char (dm, ' ');
+ RETURN_IF_ERROR (result_append_char (dm, ' '));
RETURN_IF_ERROR (demangle_type (dm));
break;
<template-param>, pass its index since from the point of
substitutions, a <template-param> token is a substitution
candidate distinct from the type that is substituted for it. */
- substitution_add (dm, start, template_p, template_parm);
+ RETURN_IF_ERROR (substitution_add (dm, start, template_p, template_parm));
/* Pop off template argument lists added during mangling of this
type. */
if (type_name == NULL)
return "Unrecognized <builtin-type> code.";
- result_append (dm, type_name);
+ RETURN_IF_ERROR (result_append (dm, type_name));
advance_char (dm);
return STATUS_OK;
}
switch (peek_char (dm))
{
case 'r':
- dyn_string_append_space (qualifiers);
- dyn_string_append_cstr (qualifiers, "restrict");
+ if (!dyn_string_append_space (qualifiers))
+ return STATUS_ALLOCATION_FAILED;
+ if (!dyn_string_append_cstr (qualifiers, "restrict"))
+ return STATUS_ALLOCATION_FAILED;
break;
case 'V':
- dyn_string_append_space (qualifiers);
- dyn_string_append_cstr (qualifiers, "volatile");
+ if (!dyn_string_append_space (qualifiers))
+ return STATUS_ALLOCATION_FAILED;
+ if (!dyn_string_append_cstr (qualifiers, "volatile"))
+ return STATUS_ALLOCATION_FAILED;
break;
case 'K':
- dyn_string_append_space (qualifiers);
- dyn_string_append_cstr (qualifiers, "const");
+ if (!dyn_string_append_space (qualifiers))
+ return STATUS_ALLOCATION_FAILED;
+ if (!dyn_string_append_cstr (qualifiers, "const"))
+ return STATUS_ALLOCATION_FAILED;
break;
default:
{
/* Indicate this function has C linkage if in verbose mode. */
if (flag_verbose)
- result_append (dm, " [extern \"C\"] ");
+ RETURN_IF_ERROR (result_append (dm, " [extern \"C\"] "));
advance_char (dm);
}
RETURN_IF_ERROR (demangle_bare_function_type (dm, function_name_pos));
DEMANGLE_TRACE ("bare-function-type", dm);
- result_append_char (dm, '(');
+ RETURN_IF_ERROR (result_append_char (dm, '('));
while (!end_of_name_p (dm) && peek_char (dm) != 'E')
{
if (sequence == -1)
/* We're decoding the function's return type. */
{
dyn_string_t return_type;
+ status_t status = STATUS_OK;
/* Decode the return type off to the side. */
- result_push (dm);
+ RETURN_IF_ERROR (result_push (dm));
RETURN_IF_ERROR (demangle_type (dm));
return_type = (dyn_string_t) result_pop (dm);
- /* Add a space to the end of the type. */
- dyn_string_append_space (return_type);
+ /* Add a space to the end of the type. Insert the return
+ type where we've been asked to. */
+ if (!dyn_string_append_space (return_type)
+ || !dyn_string_insert (result_string (dm), return_type_pos,
+ return_type))
+ status = STATUS_ALLOCATION_FAILED;
- /* Insert the return type where we've been asked to. */
- dyn_string_insert (result_string (dm), return_type_pos,
- return_type);
dyn_string_delete (return_type);
+ RETURN_IF_ERROR (status);
}
else
{
}
/* Separate parameter types by commas. */
if (sequence > 0)
- result_append (dm, ", ");
+ RETURN_IF_ERROR (result_append (dm, ", "));
/* Demangle the type. */
RETURN_IF_ERROR (demangle_type (dm));
}
++sequence;
}
- result_append_char (dm, ')');
+ RETURN_IF_ERROR (result_append_char (dm, ')'));
return STATUS_OK;
}
demangle_array_type (dm)
demangling_t dm;
{
+ status_t status;
dyn_string_t array_size = dyn_string_new (10);
- RETURN_IF_ERROR (demangle_char (dm, 'A'));
+ if (array_size == NULL)
+ return STATUS_ALLOCATION_FAILED;
+
+ status = demangle_char (dm, 'A');
/* Demangle the array size into array_size. */
- RETURN_IF_ERROR (demangle_number_literally (dm, array_size, 10, 0));
+ if (STATUS_NO_ERROR (status))
+ status = demangle_number_literally (dm, array_size, 10, 0);
/* Demangle the base type of the array. */
- RETURN_IF_ERROR (demangle_char (dm, '_'));
- RETURN_IF_ERROR (demangle_type (dm));
+ if (STATUS_NO_ERROR (status))
+ status = demangle_char (dm, '_');
+ if (STATUS_NO_ERROR (status))
+ status = demangle_type (dm);
/* Emit the array dimension syntax. */
- result_append_char (dm, '[');
- result_append_string (dm, array_size);
- result_append_char (dm, ']');
+ if (STATUS_NO_ERROR (status))
+ status = result_append_char (dm, '[');
+ if (STATUS_NO_ERROR (status))
+ status = result_append_string (dm, array_size);
+ if (STATUS_NO_ERROR (status))
+ status = result_append_char (dm, ']');
dyn_string_delete (array_size);
+ RETURN_IF_ERROR (status);
+
return STATUS_OK;
}
/* parm_number exceeded the number of arguments in the current
template argument list. */
return "Template parameter number out of bounds.";
- result_append_string (dm, (dyn_string_t) arg);
+ RETURN_IF_ERROR (result_append_string (dm, (dyn_string_t) arg));
if (peek_char (dm) == 'I')
RETURN_IF_ERROR (demangle_template_args (dm));
demangling_t dm;
{
int first = 1;
+ dyn_string_t old_last_source_name;
template_arg_list_t arg_list = template_arg_list_new ();
+ if (arg_list == NULL)
+ return STATUS_ALLOCATION_FAILED;
+
/* Preserve the most recently demangled source name. */
- dyn_string_t old_last_source_name = dm->last_source_name;
+ old_last_source_name = dm->last_source_name;
dm->last_source_name = dyn_string_new (0);
DEMANGLE_TRACE ("template-args", dm);
+ if (dm->last_source_name == NULL)
+ return STATUS_ALLOCATION_FAILED;
+
RETURN_IF_ERROR (demangle_char (dm, 'I'));
- result_append_char (dm, '<');
+ RETURN_IF_ERROR (result_append_char (dm, '<'));
do
{
string_list_t arg;
if (first)
first = 0;
else
- result_append (dm, ", ");
+ RETURN_IF_ERROR (result_append (dm, ", "));
/* Capture the template arg. */
- result_push (dm);
+ RETURN_IF_ERROR (result_push (dm));
RETURN_IF_ERROR (demangle_template_arg (dm));
arg = result_pop (dm);
/* Emit it in the demangled name. */
- result_append_string (dm, (dyn_string_t) arg);
+ RETURN_IF_ERROR (result_append_string (dm, (dyn_string_t) arg));
/* Save it for use in expanding <template-param>s. */
template_arg_list_add_arg (arg_list, arg);
}
while (peek_char (dm) != 'E');
/* Append the '>'. */
- result_close_template_list (dm);
+ RETURN_IF_ERROR (result_close_template_list (dm));
/* Consume the 'E'. */
advance_char (dm);
demangle_literal (dm)
demangling_t dm;
{
- dyn_string_t value = dyn_string_new (0);
char peek = peek_char (dm);
+ dyn_string_t value_string;
+ status_t status;
DEMANGLE_TRACE ("literal", dm);
corresponding to false or true, respectively. */
value = peek_char (dm);
if (value == '0')
- result_append (dm, "false");
+ RETURN_IF_ERROR (result_append (dm, "false"));
else if (value == '1')
- result_append (dm, "true");
+ RETURN_IF_ERROR (result_append (dm, "true"));
else
return "Unrecognized bool constant.";
/* Consume the 0 or 1. */
/* Consume the type character. */
advance_char (dm);
+
/* Demangle the number and write it out. */
- RETURN_IF_ERROR (demangle_number_literally (dm, value, 10, 1));
- result_append_string (dm, value);
+ value_string = dyn_string_new (0);
+ status = demangle_number_literally (dm, value_string, 10, 1);
+ if (STATUS_NO_ERROR (status))
+ status = result_append_string (dm, value_string);
/* For long integers, append an l. */
- if (code == 'l')
- result_append_char (dm, code);
+ if (code == 'l' && STATUS_NO_ERROR (status))
+ status = result_append_char (dm, code);
+ dyn_string_delete (value_string);
+
+ RETURN_IF_ERROR (status);
return STATUS_OK;
}
/* ...else code == ' ', so fall through to represent this
literal's type explicitly using cast syntax. */
}
- result_append_char (dm, '(');
+ RETURN_IF_ERROR (result_append_char (dm, '('));
RETURN_IF_ERROR (demangle_type (dm));
- result_append_char (dm, ')');
+ RETURN_IF_ERROR (result_append_char (dm, ')'));
+
+ value_string = dyn_string_new (0);
+ if (value_string == NULL)
+ return STATUS_ALLOCATION_FAILED;
- RETURN_IF_ERROR (demangle_number_literally (dm, value, 10, 1));
- result_append_string (dm, value);
- dyn_string_delete (value);
+ status = demangle_number_literally (dm, value_string, 10, 1);
+ if (STATUS_NO_ERROR (status))
+ status = result_append_string (dm, value_string);
+ dyn_string_delete (value_string);
+ RETURN_IF_ERROR (status);
return STATUS_OK;
}
/* An operator expression. */
{
int num_args;
+ status_t status = STATUS_OK;
dyn_string_t operator_name;
/* We have an operator name. Since we want to output binary
operations in infix notation, capture the operator name
first. */
- result_push (dm);
+ RETURN_IF_ERROR (result_push (dm));
RETURN_IF_ERROR (demangle_operator_name (dm, 1, &num_args));
operator_name = (dyn_string_t) result_pop (dm);
/* If it's binary, do an operand first. */
if (num_args > 1)
{
- result_append_char (dm, '(');
- RETURN_IF_ERROR (demangle_expression (dm));
- result_append_char (dm, ')');
+ status = result_append_char (dm, '(');
+ if (STATUS_NO_ERROR (status))
+ status = demangle_expression (dm);
+ if (STATUS_NO_ERROR (status))
+ status = result_append_char (dm, ')');
}
- /* Now emit the operator, followed by its second (if binary) or
- only (if unary) operand. */
- result_append_string (dm, operator_name);
+ /* Emit the operator. */
+ if (STATUS_NO_ERROR (status))
+ status = result_append_string (dm, operator_name);
dyn_string_delete (operator_name);
- result_append_char (dm, '(');
+ RETURN_IF_ERROR (status);
+
+ /* Emit its second (if binary) or only (if unary) operand. */
+ RETURN_IF_ERROR (result_append_char (dm, '('));
RETURN_IF_ERROR (demangle_expression (dm));
- result_append_char (dm, ')');
+ RETURN_IF_ERROR (result_append_char (dm, ')'));
/* The ternary operator takes a third operand. */
if (num_args == 3)
{
- result_append (dm, ":(");
+ RETURN_IF_ERROR (result_append (dm, ":("));
RETURN_IF_ERROR (demangle_expression (dm));
- result_append_char (dm, ')');
+ RETURN_IF_ERROR (result_append_char (dm, ')'));
}
}
RETURN_IF_ERROR (demangle_char (dm, 's'));
RETURN_IF_ERROR (demangle_char (dm, 'r'));
RETURN_IF_ERROR (demangle_type (dm));
- result_append (dm, "::");
+ RETURN_IF_ERROR (result_append (dm, "::"));
RETURN_IF_ERROR (demangle_encoding (dm));
return STATUS_OK;
}
/* If the following character is 0-9 or a capital letter, interpret
the sequence up to the next underscore as a base-36 substitution
index. */
- else if (isdigit ((unsigned char) peek)
+ else if (IS_DIGIT ((unsigned char) peek)
|| (peek >= 'A' && peek <= 'Z'))
RETURN_IF_ERROR (demangle_number (dm, &seq_id, 36, 0));
else
{
+ const char *new_last_source_name = NULL;
+
switch (peek)
{
case 't':
- result_append (dm, "std");
+ RETURN_IF_ERROR (result_append (dm, "std"));
*special_std_substitution = 1;
break;
case 'a':
- result_append (dm, "std::allocator");
- dyn_string_copy_cstr (dm->last_source_name, "allocator");
+ RETURN_IF_ERROR (result_append (dm, "std::allocator"));
+ new_last_source_name = "allocator";
+ *template_p = 1;
break;
case 'b':
- result_append (dm, "std::basic_string");
- dyn_string_copy_cstr (dm->last_source_name, "basic_string");
+ RETURN_IF_ERROR (result_append (dm, "std::basic_string"));
+ new_last_source_name = "basic_string";
+ *template_p = 1;
break;
case 's':
if (!flag_verbose)
{
- result_append (dm, "std::string");
- dyn_string_copy_cstr (dm->last_source_name, "string");
+ RETURN_IF_ERROR (result_append (dm, "std::string"));
+ new_last_source_name = "string";
}
else
{
- result_append (dm, "std::basic_string<char, std::char_traits<char>, std::allocator<char> >");
- dyn_string_copy_cstr (dm->last_source_name, "basic_string");
+ RETURN_IF_ERROR (result_append (dm, "std::basic_string<char, std::char_traits<char>, std::allocator<char> >"));
+ new_last_source_name = "basic_string";
}
+ *template_p = 0;
break;
case 'i':
if (!flag_verbose)
{
- result_append (dm, "std::istream");
- dyn_string_copy_cstr (dm->last_source_name, "istream");
+ RETURN_IF_ERROR (result_append (dm, "std::istream"));
+ new_last_source_name = "istream";
}
else
{
- result_append (dm, "std::basic_istream<char, std::char_traints<char> >");
- dyn_string_copy_cstr (dm->last_source_name, "basic_istream");
+ RETURN_IF_ERROR (result_append (dm, "std::basic_istream<char, std::char_traints<char> >"));
+ new_last_source_name = "basic_istream";
}
+ *template_p = 0;
break;
case 'o':
if (!flag_verbose)
{
- result_append (dm, "std::ostream");
- dyn_string_copy_cstr (dm->last_source_name, "ostream");
+ RETURN_IF_ERROR (result_append (dm, "std::ostream"));
+ new_last_source_name = "ostream";
}
else
{
- result_append (dm, "std::basic_ostream<char, std::char_traits<char> >");
- dyn_string_copy_cstr (dm->last_source_name, "basic_ostream");
+ RETURN_IF_ERROR (result_append (dm, "std::basic_ostream<char, std::char_traits<char> >"));
+ new_last_source_name = "basic_ostream";
}
+ *template_p = 0;
break;
case 'd':
if (!flag_verbose)
{
- result_append (dm, "std::iostream");
- dyn_string_copy_cstr (dm->last_source_name, "iostream");
+ RETURN_IF_ERROR (result_append (dm, "std::iostream"));
+ new_last_source_name = "iostream";
}
else
{
- result_append (dm, "std::basic_iostream<char, std::char_traits<char> >");
- dyn_string_copy_cstr (dm->last_source_name, "basic_iostream");
+ RETURN_IF_ERROR (result_append (dm, "std::basic_iostream<char, std::char_traits<char> >"));
+ new_last_source_name = "basic_iostream";
}
+ *template_p = 0;
break;
default:
return "Unrecognized <substitution>.";
}
+ /* Consume the character we just processed. */
advance_char (dm);
+
+ if (new_last_source_name != NULL)
+ {
+ if (!dyn_string_copy_cstr (dm->last_source_name,
+ new_last_source_name))
+ return STATUS_ALLOCATION_FAILED;
+ }
+
return STATUS_OK;
}
substitution, `S0_' is the second-most-recent, etc., shift the
numbering by one. */
text = substitution_get (dm, seq_id + 1, template_p);
- if (text == NULL)
+ if (text == NULL)
return "Substitution number out of range.";
/* Emit the substitution text. */
- result_append_string (dm, text);
+ RETURN_IF_ERROR (result_append_string (dm, text));
RETURN_IF_ERROR (demangle_char (dm, '_'));
return STATUS_OK;
RETURN_IF_ERROR (demangle_char (dm, 'Z'));
RETURN_IF_ERROR (demangle_encoding (dm));
RETURN_IF_ERROR (demangle_char (dm, 'E'));
- result_append (dm, "'s ");
+ RETURN_IF_ERROR (result_append (dm, "'s "));
if (peek_char (dm) == 's')
{
/* Local character string literal. */
- result_append (dm, "string literal");
+ RETURN_IF_ERROR (result_append (dm, "string literal"));
/* Consume the s. */
advance_char (dm);
RETURN_IF_ERROR (demangle_discriminator (dm, 0));
else
{
int unused;
- result_append (dm, "local ");
+ RETURN_IF_ERROR (result_append (dm, "local "));
/* Local name for some other entity. Demangle its name. */
RETURN_IF_ERROR (demangle_name (dm, &unused));
RETURN_IF_ERROR (demangle_discriminator (dm, 1));
/* Consume the underscore. */
advance_char (dm);
if (flag_verbose)
- result_append (dm, " [#");
+ RETURN_IF_ERROR (result_append (dm, " [#"));
/* Check if there's a number following the underscore. */
- if (isdigit ((unsigned char) peek_char (dm)))
+ if (IS_DIGIT ((unsigned char) peek_char (dm)))
{
int discriminator;
/* Demangle the number. */
/* Write the discriminator. The mangled number is two
less than the discriminator ordinal, counting from
zero. */
- int_to_dyn_string (discriminator + 2,
- (dyn_string_t) dm->result);
+ RETURN_IF_ERROR (int_to_dyn_string (discriminator + 2,
+ (dyn_string_t) dm->result));
}
else
{
if (flag_verbose)
/* A missing digit correspond to one. */
- result_append_char (dm, '1');
+ RETURN_IF_ERROR (result_append_char (dm, '1'));
}
if (flag_verbose)
- result_append_char (dm, ']');
+ RETURN_IF_ERROR (result_append_char (dm, ']'));
}
else if (!suppress_first)
{
if (flag_verbose)
- result_append (dm, " [#0]");
+ RETURN_IF_ERROR (result_append (dm, " [#0]"));
}
return STATUS_OK;
static status_t
cp_demangle (name, result)
- char *name;
+ const char *name;
dyn_string_t result;
{
status_t status;
if (length > 2 && name[0] == '_' && name[1] == 'Z')
{
demangling_t dm = demangling_new (name);
+ if (dm == NULL)
+ return STATUS_ALLOCATION_FAILED;
- result_push (dm);
- status = demangle_mangled_name (dm);
+ status = result_push (dm);
+ if (status != STATUS_OK)
+ {
+ demangling_delete (dm);
+ return status;
+ }
- if (status == STATUS_OK)
+ status = demangle_mangled_name (dm);
+ if (STATUS_NO_ERROR (status))
{
dyn_string_t demangled = (dyn_string_t) result_pop (dm);
- dyn_string_copy (result, demangled);
+ if (!dyn_string_copy (result, demangled))
+ return STATUS_ALLOCATION_FAILED;
dyn_string_delete (demangled);
}
/* It's evidently not a mangled C++ name. It could be the name
of something with C linkage, though, so just copy NAME into
RESULT. */
- dyn_string_copy_cstr (result, name);
+ if (!dyn_string_copy_cstr (result, name))
+ return STATUS_ALLOCATION_FAILED;
status = STATUS_OK;
}
+ return status;
+}
+
+/* Demangle TYPE_NAME into RESULT, which must be an initialized
+ dyn_string_t. On success, returns STATUS_OK. On failiure, returns
+ an error message, and the contents of RESULT are unchanged. */
+
+static status_t
+cp_demangle_type (type_name, result)
+ const char* type_name;
+ dyn_string_t result;
+{
+ status_t status;
+ demangling_t dm = demangling_new (type_name);
+
+ if (dm == NULL)
+ return STATUS_ALLOCATION_FAILED;
+
+ /* Demangle the type name. The demangled name is stored in dm. */
+ status = result_push (dm);
+ if (status != STATUS_OK)
+ {
+ demangling_delete (dm);
+ return status;
+ }
+
+ status = demangle_type (dm);
+
+ if (STATUS_NO_ERROR (status))
+ {
+ /* The demangling succeeded. Pop the result out of dm and copy
+ it into RESULT. */
+ dyn_string_t demangled = (dyn_string_t) result_pop (dm);
+ if (!dyn_string_copy (result, demangled))
+ return STATUS_ALLOCATION_FAILED;
+ dyn_string_delete (demangled);
+ }
+
+ /* Clean up. */
+ demangling_delete (dm);
+
return status;
}
+
+#ifdef IN_LIBGCC2
+
+extern char *__cxa_demangle PARAMS ((const char *, char *, size_t *, int *));
+
+/* ABI-mandated entry point in the C++ runtime library for performing
+ demangling. MANGLED_NAME is a NUL-terminated character string
+ containing the name to be demangled.
+
+ OUTPUT_BUFFER is a region of memory, allocated with malloc, of
+ *LENGTH bytes, into which the demangled name is stored. If
+ OUTPUT_BUFFER is not long enough, it is expanded using realloc.
+ OUTPUT_BUFFER may instead be NULL; in that case, the demangled name
+ is placed in a region of memory allocated with malloc.
+
+ If LENGTH is non-NULL, the length of the buffer conaining the
+ demangled name, is placed in *LENGTH.
+
+ The return value is a pointer to the start of the NUL-terminated
+ demangled name, or NULL if the demangling fails. The caller is
+ responsible for deallocating this memory using free.
+
+ *STATUS is set to one of the following values:
+ 0: The demangling operation succeeded.
+ -1: A memory allocation failiure occurred.
+ -2: MANGLED_NAME is not a valid name under the C++ ABI mangling rules.
+ -3: One of the arguments is invalid.
+
+ The demagling is performed using the C++ ABI mangling rules, with
+ GNU extensions. */
+
+char *
+__cxa_demangle (mangled_name, output_buffer, length, status)
+ const char *mangled_name;
+ char *output_buffer;
+ size_t *length;
+ int *status;
+{
+ struct dyn_string demangled_name;
+ status_t result;
+
+ if (status == NULL)
+ return NULL;
+
+ if (mangled_name == NULL) {
+ *status = -3;
+ return NULL;
+ }
+
+ /* Did the caller provide a buffer for the demangled name? */
+ if (output_buffer == NULL) {
+ /* No; dyn_string will malloc a buffer for us. */
+ if (!dyn_string_init (&demangled_name, 0))
+ {
+ *status = -1;
+ return NULL;
+ }
+ }
+ else {
+ /* Yes. Check that the length was provided. */
+ if (length == NULL) {
+ *status = -3;
+ return NULL;
+ }
+ /* Install the buffer into a dyn_string. */
+ demangled_name.allocated = *length;
+ demangled_name.length = 0;
+ demangled_name.s = output_buffer;
+ }
+
+ if (mangled_name[0] == '_' && mangled_name[1] == 'Z')
+ /* MANGLED_NAME apprears to be a function or variable name.
+ Demangle it accordingly. */
+ result = cp_demangle (mangled_name, &demangled_name);
+ else
+ /* Try to demangled MANGLED_NAME as the name of a type. */
+ result = cp_demangle_type (mangled_name, &demangled_name);
+
+ if (result == STATUS_OK)
+ /* The demangling succeeded. */
+ {
+ /* If LENGTH isn't NULL, store the allocated buffer length
+ there; the buffer may have been realloced by dyn_string
+ functions. */
+ if (length != NULL)
+ *length = demangled_name.allocated;
+ /* The operation was a success. */
+ *status = 0;
+ return dyn_string_buf (&demangled_name);
+ }
+ else if (result == STATUS_ALLOCATION_FAILED)
+ /* A call to malloc or realloc failed during the demangling
+ operation. */
+ {
+ *status = -1;
+ return NULL;
+ }
+ else
+ /* The demangling failed for another reason, most probably because
+ MANGLED_NAME isn't a valid mangled name. */
+ {
+ /* If the buffer containing the demangled name wasn't provided
+ by the caller, free it. */
+ if (output_buffer == NULL)
+ free (dyn_string_buf (&demangled_name));
+ *status = -2;
+ return NULL;
+ }
+}
+
+#else /* !IN_LIBGCC2 */
+
/* Variant entry point for integration with the existing cplus-dem
demangler. Attempts to demangle MANGLED. If the demangling
succeeds, returns a buffer, allocated with malloc, containing the
dyn_string_t demangled = dyn_string_new (0);
/* Attempt the demangling. */
status_t status = cp_demangle ((char *) mangled, demangled);
- if (status == STATUS_OK)
+ if (STATUS_NO_ERROR (status))
/* Demangling succeeded. */
{
/* Grab the demangled result from the dyn_string. It was
allocated with malloc, so we can return it directly. */
char *return_value = dyn_string_release (demangled);
- /* The dyn_string can go away. */
- dyn_string_delete (demangled);
/* Hand back the demangled name. */
return return_value;
}
+ else if (status == STATUS_ALLOCATION_FAILED)
+ {
+ fprintf (stderr, "Memory allocation failed.\n");
+ abort ();
+ }
else
/* Demangling failed. */
{
}
}
+#endif /* IN_LIBGCC2 */
+
#ifdef STANDALONE_DEMANGLER
#include "getopt.h"
/* Non-zero if CHAR is a character than can occur in a mangled name. */
#define is_mangled_char(CHAR) \
- (isalnum ((unsigned char) (CHAR)) || (CHAR) == '_')
+ (IS_ALPHA (CHAR) || IS_DIGIT (CHAR) || (CHAR) == '_')
/* The name of this program, as invoked. */
const char* program_name;
/* If the demangling succeeded, great! Print out the
demangled version. */
- if (status == STATUS_OK)
+ if (STATUS_NO_ERROR (status))
fputs (dyn_string_buf (demangled), stdout);
+ /* Abort on allocation failures. */
+ else if (status == STATUS_ALLOCATION_FAILED)
+ {
+ fprintf (stderr, "Memory allocation failed.\n");
+ abort ();
+ }
/* Otherwise, it might not have been a mangled name. Just
print out the original text. */
else
status = cp_demangle (argv[i], result);
/* If it worked, print the demangled name. */
- if (status == STATUS_OK)
+ if (STATUS_NO_ERROR (status))
printf ("%s\n", dyn_string_buf (result));
+ /* Abort on allocaiton failures. */
+ else if (status == STATUS_ALLOCATION_FAILED)
+ {
+ fprintf (stderr, "Memory allocaiton failed.\n");
+ abort ();
+ }
/* If not, print the error message to stderr instead. */
else
fprintf (stderr, "%s\n", status);