#include "defs.h"
#include <ctype.h>
#include "cp-support.h"
#include "gdb_string.h"
#include "demangle.h"
#include "gdb_assert.h"
#include "gdbcmd.h"
#include "dictionary.h"
#include "objfiles.h"
#include "frame.h"
#include "symtab.h"
#include "block.h"
#include "complaints.h"
#include "gdbtypes.h"
#define d_left(dc) (dc)->u.s_binary.left
#define d_right(dc) (dc)->u.s_binary.right
static unsigned int cp_find_first_component_aux (const char *name,
int permissive);
static void demangled_name_complaint (const char *name);
static int sym_return_val_size;
static int sym_return_val_index;
static struct symbol **sym_return_val;
static void overload_list_add_symbol (struct symbol *sym,
const char *oload_name);
static void make_symbol_overload_list_using (const char *func_name,
const char *namespace);
static void make_symbol_overload_list_qualified (const char *func_name);
static void read_in_psymtabs (const char *oload_name);
struct cmd_list_element *maint_cplus_cmd_list = NULL;
static void maint_cplus_command (char *arg, int from_tty);
static void first_component_command (char *arg, int from_tty);
char *
cp_canonicalize_string (const char *string)
{
void *storage;
struct demangle_component *ret_comp;
char *ret;
int len = strlen (string);
len = len + len / 8;
ret_comp = cp_demangled_name_to_comp (string, &storage, NULL);
if (ret_comp == NULL)
return NULL;
ret = cp_comp_to_string (ret_comp, len);
xfree (storage);
return ret;
}
static struct demangle_component *
mangled_name_to_comp (const char *mangled_name, int options,
void **memory, char **demangled_p)
{
struct demangle_component *ret;
char *demangled_name;
if (mangled_name[0] == '_' && mangled_name[1] == 'Z')
{
ret = cplus_demangle_v3_components (mangled_name, options, memory);
if (ret)
{
*demangled_p = NULL;
return ret;
}
}
demangled_name = cplus_demangle (mangled_name, options);
if (demangled_name == NULL)
return NULL;
ret = cp_demangled_name_to_comp (demangled_name, memory, NULL);
if (ret == NULL)
{
free (demangled_name);
return NULL;
}
*demangled_p = demangled_name;
return ret;
}
char *
cp_class_name_from_physname (const char *physname)
{
void *storage;
char *demangled_name = NULL, *ret;
struct demangle_component *ret_comp, *prev_comp, *cur_comp;
int done;
ret_comp = mangled_name_to_comp (physname, DMGL_ANSI, &storage,
&demangled_name);
if (ret_comp == NULL)
return NULL;
done = 0;
while (!done)
switch (ret_comp->type)
{
case DEMANGLE_COMPONENT_CONST:
case DEMANGLE_COMPONENT_RESTRICT:
case DEMANGLE_COMPONENT_VOLATILE:
case DEMANGLE_COMPONENT_CONST_THIS:
case DEMANGLE_COMPONENT_RESTRICT_THIS:
case DEMANGLE_COMPONENT_VOLATILE_THIS:
case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
ret_comp = d_left (ret_comp);
break;
default:
done = 1;
break;
}
if (ret_comp->type == DEMANGLE_COMPONENT_TYPED_NAME)
ret_comp = d_left (ret_comp);
if (ret_comp->type == DEMANGLE_COMPONENT_TEMPLATE)
ret_comp = d_left (ret_comp);
done = 0;
prev_comp = NULL;
cur_comp = ret_comp;
while (!done)
switch (cur_comp->type)
{
case DEMANGLE_COMPONENT_QUAL_NAME:
case DEMANGLE_COMPONENT_LOCAL_NAME:
prev_comp = cur_comp;
cur_comp = d_right (cur_comp);
break;
case DEMANGLE_COMPONENT_TEMPLATE:
case DEMANGLE_COMPONENT_NAME:
case DEMANGLE_COMPONENT_CTOR:
case DEMANGLE_COMPONENT_DTOR:
case DEMANGLE_COMPONENT_OPERATOR:
case DEMANGLE_COMPONENT_EXTENDED_OPERATOR:
done = 1;
break;
default:
done = 1;
cur_comp = NULL;
break;
}
ret = NULL;
if (cur_comp != NULL && prev_comp != NULL)
{
*prev_comp = *d_left (prev_comp);
ret = cp_comp_to_string (ret_comp, 10);
}
xfree (storage);
if (demangled_name)
xfree (demangled_name);
return ret;
}
static struct demangle_component *
unqualified_name_from_comp (struct demangle_component *comp)
{
struct demangle_component *ret_comp = comp, *last_template;
int done;
done = 0;
last_template = NULL;
while (!done)
switch (ret_comp->type)
{
case DEMANGLE_COMPONENT_QUAL_NAME:
case DEMANGLE_COMPONENT_LOCAL_NAME:
ret_comp = d_right (ret_comp);
break;
case DEMANGLE_COMPONENT_TYPED_NAME:
ret_comp = d_left (ret_comp);
break;
case DEMANGLE_COMPONENT_TEMPLATE:
gdb_assert (last_template == NULL);
last_template = ret_comp;
ret_comp = d_left (ret_comp);
break;
case DEMANGLE_COMPONENT_CONST:
case DEMANGLE_COMPONENT_RESTRICT:
case DEMANGLE_COMPONENT_VOLATILE:
case DEMANGLE_COMPONENT_CONST_THIS:
case DEMANGLE_COMPONENT_RESTRICT_THIS:
case DEMANGLE_COMPONENT_VOLATILE_THIS:
case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
ret_comp = d_left (ret_comp);
break;
case DEMANGLE_COMPONENT_NAME:
case DEMANGLE_COMPONENT_CTOR:
case DEMANGLE_COMPONENT_DTOR:
case DEMANGLE_COMPONENT_OPERATOR:
case DEMANGLE_COMPONENT_EXTENDED_OPERATOR:
done = 1;
break;
default:
return NULL;
break;
}
if (last_template)
{
d_left (last_template) = ret_comp;
return last_template;
}
return ret_comp;
}
char *
method_name_from_physname (const char *physname)
{
void *storage;
char *demangled_name = NULL, *ret;
struct demangle_component *ret_comp;
ret_comp = mangled_name_to_comp (physname, DMGL_ANSI, &storage,
&demangled_name);
if (ret_comp == NULL)
return NULL;
ret_comp = unqualified_name_from_comp (ret_comp);
ret = NULL;
if (ret_comp != NULL)
ret = cp_comp_to_string (ret_comp, 10);
xfree (storage);
if (demangled_name)
xfree (demangled_name);
return ret;
}
char *
cp_func_name (const char *full_name)
{
void *storage;
char *ret;
struct demangle_component *ret_comp;
if (!full_name)
return NULL;
ret_comp = cp_demangled_name_to_comp (full_name, &storage, NULL);
if (!ret_comp)
return NULL;
ret_comp = unqualified_name_from_comp (ret_comp);
ret = NULL;
if (ret_comp != NULL)
ret = cp_comp_to_string (ret_comp, 10);
xfree (storage);
return ret;
}
static char *
remove_params (const char *demangled_name)
{
int done = 0;
struct demangle_component *ret_comp;
void *storage;
char *ret = NULL;
if (demangled_name == NULL)
return NULL;
ret_comp = cp_demangled_name_to_comp (demangled_name, &storage, NULL);
if (ret_comp == NULL)
return NULL;
while (!done)
switch (ret_comp->type)
{
case DEMANGLE_COMPONENT_CONST:
case DEMANGLE_COMPONENT_RESTRICT:
case DEMANGLE_COMPONENT_VOLATILE:
case DEMANGLE_COMPONENT_CONST_THIS:
case DEMANGLE_COMPONENT_RESTRICT_THIS:
case DEMANGLE_COMPONENT_VOLATILE_THIS:
case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
ret_comp = d_left (ret_comp);
break;
default:
done = 1;
break;
}
if (ret_comp->type == DEMANGLE_COMPONENT_TYPED_NAME)
ret = cp_comp_to_string (d_left (ret_comp), 10);
xfree (storage);
return ret;
}
unsigned int
cp_find_first_component (const char *name)
{
return cp_find_first_component_aux (name, 0);
}
#define LENGTH_OF_OPERATOR 8
static unsigned int
cp_find_first_component_aux (const char *name, int permissive)
{
unsigned int index = 0;
int operator_possible = 1;
for (;; ++index)
{
switch (name[index])
{
case '<':
index += 1;
for (index += cp_find_first_component_aux (name + index, 1);
name[index] != '>';
index += cp_find_first_component_aux (name + index, 1))
{
if (name[index] != ':')
{
demangled_name_complaint (name);
return strlen (name);
}
index += 2;
}
operator_possible = 1;
break;
case '(':
index += 1;
for (index += cp_find_first_component_aux (name + index, 1);
name[index] != ')';
index += cp_find_first_component_aux (name + index, 1))
{
if (name[index] != ':')
{
demangled_name_complaint (name);
return strlen (name);
}
index += 2;
}
operator_possible = 1;
break;
case '>':
case ')':
if (permissive)
return index;
else
{
demangled_name_complaint (name);
return strlen (name);
}
case '\0':
case ':':
return index;
case 'o':
if (operator_possible
&& strncmp (name + index, "operator", LENGTH_OF_OPERATOR) == 0)
{
index += LENGTH_OF_OPERATOR;
while (isspace(name[index]))
++index;
switch (name[index])
{
case '<':
if (name[index + 1] == '<')
index += 1;
else
index += 0;
break;
case '>':
case '-':
if (name[index + 1] == '>')
index += 1;
else
index += 0;
break;
case '(':
index += 1;
break;
default:
index += 0;
break;
}
}
operator_possible = 0;
break;
case ' ':
case ',':
case '.':
case '&':
case '*':
operator_possible = 1;
break;
default:
operator_possible = 0;
break;
}
}
}
static void
demangled_name_complaint (const char *name)
{
complaint (&symfile_complaints,
"unexpected demangled name '%s'", name);
}
unsigned int
cp_entire_prefix_len (const char *name)
{
unsigned int current_len = cp_find_first_component (name);
unsigned int previous_len = 0;
while (name[current_len] != '\0')
{
gdb_assert (name[current_len] == ':');
previous_len = current_len;
current_len += 2;
current_len += cp_find_first_component (name + current_len);
}
return previous_len;
}
static void
overload_list_add_symbol (struct symbol *sym, const char *oload_name)
{
int newsize;
int i;
char *sym_name;
if (SYMBOL_TYPE (sym) == NULL)
return;
for (i = 0; i < sym_return_val_index; ++i)
if (strcmp (SYMBOL_LINKAGE_NAME (sym),
SYMBOL_LINKAGE_NAME (sym_return_val[i])) == 0)
return;
sym_name = remove_params (SYMBOL_NATURAL_NAME (sym));
if (!sym_name)
return;
if (strcmp (sym_name, oload_name) != 0)
{
xfree (sym_name);
return;
}
xfree (sym_name);
if (sym_return_val_index + 3 > sym_return_val_size)
{
newsize = (sym_return_val_size *= 2) * sizeof (struct symbol *);
sym_return_val = (struct symbol **) xrealloc ((char *) sym_return_val, newsize);
}
sym_return_val[sym_return_val_index++] = sym;
sym_return_val[sym_return_val_index] = NULL;
}
struct symbol **
make_symbol_overload_list (const char *func_name,
const char *namespace)
{
struct cleanup *old_cleanups;
sym_return_val_size = 100;
sym_return_val_index = 0;
sym_return_val = xmalloc ((sym_return_val_size + 1) *
sizeof (struct symbol *));
sym_return_val[0] = NULL;
old_cleanups = make_cleanup (xfree, sym_return_val);
make_symbol_overload_list_using (func_name, namespace);
discard_cleanups (old_cleanups);
return sym_return_val;
}
static void
make_symbol_overload_list_using (const char *func_name,
const char *namespace)
{
const struct using_direct *current;
for (current = block_using (get_selected_block (0));
current != NULL;
current = current->next)
{
if (strcmp (namespace, current->outer) == 0)
{
make_symbol_overload_list_using (func_name,
current->inner);
}
}
if (namespace[0] == '\0')
{
make_symbol_overload_list_qualified (func_name);
}
else
{
char *concatenated_name
= alloca (strlen (namespace) + 2 + strlen (func_name) + 1);
strcpy (concatenated_name, namespace);
strcat (concatenated_name, "::");
strcat (concatenated_name, func_name);
make_symbol_overload_list_qualified (concatenated_name);
}
}
static void
make_symbol_overload_list_qualified (const char *func_name)
{
struct symbol *sym;
struct symtab *s;
struct objfile *objfile;
const struct block *b, *surrounding_static_block = 0;
struct dict_iterator iter;
const struct dictionary *dict;
read_in_psymtabs (func_name);
for (b = get_selected_block (0); b != NULL; b = BLOCK_SUPERBLOCK (b))
{
dict = BLOCK_DICT (b);
for (sym = dict_iter_name_first (dict, func_name, &iter);
sym;
sym = dict_iter_name_next (func_name, &iter))
{
overload_list_add_symbol (sym, func_name);
}
}
surrounding_static_block = block_static_block (get_selected_block (0));
ALL_SYMTABS (objfile, s)
{
QUIT;
b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), GLOBAL_BLOCK);
dict = BLOCK_DICT (b);
for (sym = dict_iter_name_first (dict, func_name, &iter);
sym;
sym = dict_iter_name_next (func_name, &iter))
{
overload_list_add_symbol (sym, func_name);
}
}
ALL_SYMTABS (objfile, s)
{
QUIT;
b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK);
if (b == surrounding_static_block)
continue;
dict = BLOCK_DICT (b);
for (sym = dict_iter_name_first (dict, func_name, &iter);
sym;
sym = dict_iter_name_next (func_name, &iter))
{
overload_list_add_symbol (sym, func_name);
}
}
}
static void
read_in_psymtabs (const char *func_name)
{
struct partial_symtab *ps;
struct objfile *objfile;
ALL_PSYMTABS (objfile, ps)
{
if (ps->readin)
continue;
if ((lookup_partial_symbol (ps, func_name, NULL, 1, VAR_DOMAIN)
!= NULL)
|| (lookup_partial_symbol (ps, func_name, NULL, 0, VAR_DOMAIN)
!= NULL))
psymtab_to_symtab (ps);
}
}
struct type *
cp_lookup_rtti_type (const char *name, struct block *block)
{
struct symbol * rtti_sym;
struct type * rtti_type;
rtti_sym = lookup_symbol (name, block, STRUCT_DOMAIN, NULL, NULL);
if (rtti_sym == NULL)
{
complaint (&symfile_complaints, _("RTTI symbol not found for class '%s'"),
name);
return NULL;
}
if (SYMBOL_CLASS (rtti_sym) != LOC_TYPEDEF)
{
warning (_("RTTI symbol for class '%s' is not a type"), name);
return NULL;
}
rtti_type = SYMBOL_TYPE (rtti_sym);
switch (TYPE_CODE (rtti_type))
{
case TYPE_CODE_CLASS:
break;
case TYPE_CODE_NAMESPACE:
warning (_("RTTI symbol for class '%s' is a namespace"), name);
return NULL;
default:
warning (_("RTTI symbol for class '%s' has bad type"), name);
return NULL;
}
return rtti_type;
}
static void
maint_cplus_command (char *arg, int from_tty)
{
printf_unfiltered (_("\"maintenance cplus\" must be followed by the name of a command.\n"));
help_list (maint_cplus_cmd_list, "maintenance cplus ", -1, gdb_stdout);
}
static void
first_component_command (char *arg, int from_tty)
{
int len = cp_find_first_component (arg);
char *prefix = alloca (len + 1);
memcpy (prefix, arg, len);
prefix[len] = '\0';
printf_unfiltered ("%s\n", prefix);
}
extern initialize_file_ftype _initialize_cp_support;
void
_initialize_cp_support (void)
{
add_prefix_cmd ("cplus", class_maintenance, maint_cplus_command,
_("C++ maintenance commands."), &maint_cplus_cmd_list,
"maintenance cplus ", 0, &maintenancelist);
add_alias_cmd ("cp", "cplus", class_maintenance, 1, &maintenancelist);
add_cmd ("first_component", class_maintenance, first_component_command,
_("Print the first class/namespace component of NAME."),
&maint_cplus_cmd_list);
}