#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"
static const char *find_last_component (const char *name);
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 char *remove_params (const char *demangled_name);
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);
static const char *
find_last_component (const char *name)
{
const char *p;
int depth;
p = name + strlen (name) - 1;
while (p > name && *p != ')')
p--;
if (p == name)
return NULL;
p--;
depth = 1;
while (p > name && depth > 0)
{
if (*p == '<' || *p == '(')
depth--;
else if (*p == '>' || *p == ')')
depth++;
p--;
}
if (p == name)
return NULL;
while (p > name && *p != ':')
p--;
if (p == name || p == name + 1 || p[-1] != ':')
return NULL;
return p - 1;
}
char *
class_name_from_physname (const char *physname)
{
char *ret = NULL;
const char *end;
int depth = 0;
char *demangled_name = cplus_demangle (physname, DMGL_ANSI | DMGL_PARAMS);
if (demangled_name == NULL)
return NULL;
end = find_last_component (demangled_name);
if (end != NULL)
{
ret = xmalloc (end - demangled_name + 1);
memcpy (ret, demangled_name, end - demangled_name);
ret[end - demangled_name] = '\0';
}
xfree (demangled_name);
return ret;
}
char *
method_name_from_physname (const char *physname)
{
char *ret = NULL;
const char *end;
int depth = 0;
char *demangled_name = cplus_demangle (physname, DMGL_ANSI | DMGL_PARAMS);
if (demangled_name == NULL)
return NULL;
end = find_last_component (demangled_name);
if (end != NULL)
{
char *args;
int len;
end = end + 2;
args = strchr (end, '(');
if (args == NULL)
len = strlen (end + 2);
else
{
args --;
while (*args == ' ')
args --;
len = args - end + 1;
}
ret = xmalloc (len + 1);
memcpy (ret, end, len);
ret[len] = 0;
}
xfree (demangled_name);
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;
}
char *
cp_func_name (const char *full_name)
{
const char *previous_component = full_name;
const char *next_component;
if (!full_name)
return NULL;
for (next_component = (previous_component
+ cp_find_first_component (previous_component));
*next_component == ':';
next_component = (previous_component
+ cp_find_first_component (previous_component)))
{
previous_component = next_component + 2;
}
return remove_params (previous_component);
}
static char *
remove_params (const char *demangled_name)
{
const char *argp;
char *new_name;
int depth;
if (demangled_name == NULL)
return NULL;
argp = strrchr (demangled_name, ')');
if (argp == NULL)
return NULL;
depth = 1;
while (argp-- > demangled_name)
{
if (*argp == ')')
depth ++;
else if (*argp == '(')
{
depth --;
if (depth == 0)
break;
}
}
if (depth != 0)
internal_error (__FILE__, __LINE__,
"bad demangled name %s\n", demangled_name);
while (argp[-1] == ' ' && argp > demangled_name)
argp --;
new_name = xmalloc (argp - demangled_name + 1);
memcpy (new_name, demangled_name, argp - demangled_name);
new_name[argp - demangled_name] = '\0';
return new_name;
}
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)
{
warning ("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);
}