/* Helper routines for C++ support in GDB.
- Copyright (C) 2002-2021 Free Software Foundation, Inc.
+ Copyright (C) 2002-2023 Free Software Foundation, Inc.
Contributed by MontaVista Software.
#include "defs.h"
#include "cp-support.h"
+#include "language.h"
#include "demangle.h"
#include "gdbcmd.h"
#include "dictionary.h"
#include "namespace.h"
#include <signal.h>
#include "gdbsupport/gdb_setjmp.h"
-#include "safe-ctype.h"
+#include "gdbsupport/gdb-safe-ctype.h"
#include "gdbsupport/selftest.h"
#include "gdbsupport/gdb-sigmask.h"
#include <atomic>
#include "event-top.h"
#include "run-on-main-thread.h"
+#include "typeprint.h"
#define d_left(dc) (dc)->u.s_binary.left
#define d_right(dc) (dc)->u.s_binary.right
struct cmd_list_element *maint_cplus_cmd_list = NULL;
-/* A list of typedefs which should not be substituted by replace_typedefs. */
-static const char * const ignore_typedefs[] =
- {
- "std::istream", "std::iostream", "std::ostream", "std::string"
- };
-
static void
replace_typedefs (struct demangle_parse_info *info,
struct demangle_component *ret_comp,
canonicalization_ftype *finder,
void *data);
+static struct demangle_component *
+ gdb_cplus_demangle_v3_components (const char *mangled,
+ int options, void **mem);
+
/* A convenience function to copy STRING into OBSTACK, returning a pointer
to the newly allocated string and saving the number of bytes saved in LEN.
memcpy (name, ret_comp->u.s_name.s, ret_comp->u.s_name.len);
name[ret_comp->u.s_name.len] = '\0';
- /* Ignore any typedefs that should not be substituted. */
- for (int i = 0; i < ARRAY_SIZE (ignore_typedefs); ++i)
- {
- if (strcmp (name, ignore_typedefs[i]) == 0)
- return 0;
- }
-
sym = NULL;
try
if (sym != NULL)
{
- struct type *otype = SYMBOL_TYPE (sym);
+ struct type *otype = sym->type ();
if (finder != NULL)
{
struct type *last = otype;
/* Find the last typedef for the type. */
- while (TYPE_TARGET_TYPE (last) != NULL
- && (TYPE_TARGET_TYPE (last)->code ()
+ while (last->target_type () != NULL
+ && (last->target_type ()->code ()
== TYPE_CODE_TYPEDEF))
- last = TYPE_TARGET_TYPE (last);
+ last = last->target_type ();
/* If there is only one typedef for this anonymous type,
do not substitute it. */
string_file buf;
try
{
- type_print (type, "", &buf, -1);
+ /* Avoid using the current language. If the language is
+ C, and TYPE is a struct/class, the printed type is
+ prefixed with "struct " or "class ", which we don't
+ want when we're expanding a C++ typedef. Print using
+ the type symbol's language to expand a C++ typedef
+ the C++ way even if the current language is C. */
+ const language_defn *lang = language_def (sym->language ());
+ lang->print_type (type, "", &buf, -1, 0, &type_print_raw_options);
}
/* If type_print threw an exception, there is little point
in continuing, so just bow out gracefully. */
if (sym != NULL)
{
- struct type *otype = SYMBOL_TYPE (sym);
+ struct type *otype = sym->type ();
const char *new_name = (*finder) (otype, data);
if (new_name != NULL)
static std::unique_ptr<demangle_parse_info>
mangled_name_to_comp (const char *mangled_name, int options,
- void **memory, char **demangled_p)
+ void **memory,
+ gdb::unique_xmalloc_ptr<char> *demangled_p)
{
- char *demangled_name;
-
/* If it looks like a v3 mangled name, then try to go directly
to trees. */
if (mangled_name[0] == '_' && mangled_name[1] == 'Z')
{
struct demangle_component *ret;
- ret = cplus_demangle_v3_components (mangled_name,
- options, memory);
+ ret = gdb_cplus_demangle_v3_components (mangled_name,
+ options, memory);
if (ret)
{
std::unique_ptr<demangle_parse_info> info (new demangle_parse_info);
/* If it doesn't, or if that failed, then try to demangle the
name. */
- demangled_name = gdb_demangle (mangled_name, options);
+ gdb::unique_xmalloc_ptr<char> demangled_name = gdb_demangle (mangled_name,
+ options);
if (demangled_name == NULL)
return NULL;
/* If we could demangle the name, parse it to build the component
tree. */
std::unique_ptr<demangle_parse_info> info
- = cp_demangled_name_to_comp (demangled_name, NULL);
+ = cp_demangled_name_to_comp (demangled_name.get (), NULL);
if (info == NULL)
- {
- xfree (demangled_name);
- return NULL;
- }
+ return NULL;
- *demangled_p = demangled_name;
+ *demangled_p = std::move (demangled_name);
return info;
}
cp_class_name_from_physname (const char *physname)
{
void *storage = NULL;
- char *demangled_name = NULL;
+ gdb::unique_xmalloc_ptr<char> demangled_name;
gdb::unique_xmalloc_ptr<char> ret;
struct demangle_component *ret_comp, *prev_comp, *cur_comp;
std::unique_ptr<demangle_parse_info> info;
}
xfree (storage);
- xfree (demangled_name);
return ret.release ();
}
method_name_from_physname (const char *physname)
{
void *storage = NULL;
- char *demangled_name = NULL;
+ gdb::unique_xmalloc_ptr<char> demangled_name;
gdb::unique_xmalloc_ptr<char> ret;
struct demangle_component *ret_comp;
std::unique_ptr<demangle_parse_info> info;
ret = cp_comp_to_string (ret_comp, 10);
xfree (storage);
- xfree (demangled_name);
return ret.release ();
}
{
/* If there is no type information, we can't do anything, so
skip. */
- if (SYMBOL_TYPE (sym) == NULL)
+ if (sym->type () == NULL)
return;
/* skip any symbols that we've already considered. */
const struct block *block,
std::vector<symbol *> *overload_list)
{
- struct block_iterator iter;
- struct symbol *sym;
-
lookup_name_info lookup_name (name, symbol_name_match_type::FULL);
- ALL_BLOCK_SYMBOLS_WITH_NAME (block, lookup_name, iter, sym)
+ for (struct symbol *sym : block_iterator_range (block, &lookup_name))
overload_list_add_symbol (sym, name, overload_list);
}
}
/* Look in the static block. */
- block = block_static_block (get_selected_block (0));
- if (block)
- add_symbol_overload_list_block (name, block, overload_list);
-
- /* Look in the global block. */
- block = block_global_block (block);
- if (block)
- add_symbol_overload_list_block (name, block, overload_list);
+ block = get_selected_block (0);
+ block = block == nullptr ? nullptr : block->static_block ();
+ if (block != nullptr)
+ {
+ add_symbol_overload_list_block (name, block, overload_list);
+ /* Look in the global block. */
+ block = block->global_block ();
+ if (block)
+ add_symbol_overload_list_block (name, block, overload_list);
+ }
}
/* Search the namespace of the given type and namespace of and public
const char *type_name;
int i, prefix_len;
- while (type->code () == TYPE_CODE_PTR
- || TYPE_IS_REFERENCE (type)
+ while (type->is_pointer_or_reference ()
|| type->code () == TYPE_CODE_ARRAY
|| type->code () == TYPE_CODE_TYPEDEF)
{
if (type->code () == TYPE_CODE_TYPEDEF)
type = check_typedef (type);
else
- type = TYPE_TARGET_TYPE (type);
+ type = type->target_type ();
}
type_name = type->name ();
for (block = get_selected_block (0);
block != NULL;
- block = BLOCK_SUPERBLOCK (block))
- for (current = block_using (block);
+ block = block->superblock ())
+ for (current = block->get_using ();
current != NULL;
current = current->next)
{
add_symbol_overload_list_qualified (const char *func_name,
std::vector<symbol *> *overload_list)
{
- const struct block *b, *surrounding_static_block = 0;
+ const struct block *surrounding_static_block = 0;
/* Look through the partial symtabs for all symbols which begin by
matching FUNC_NAME. Make sure we read that symbol table in. */
/* Search upwards from currently selected frame (so that we can
complete on local vars. */
- for (b = get_selected_block (0); b != NULL; b = BLOCK_SUPERBLOCK (b))
+ for (const block *b = get_selected_block (0);
+ b != nullptr;
+ b = b->superblock ())
add_symbol_overload_list_block (func_name, b, overload_list);
- surrounding_static_block = block_static_block (get_selected_block (0));
+ surrounding_static_block = get_selected_block (0);
+ surrounding_static_block = (surrounding_static_block == nullptr
+ ? nullptr
+ : surrounding_static_block->static_block ());
/* Go through the symtabs and check the externs and statics for
symbols which match. */
- for (objfile *objfile : current_program_space->objfiles ())
- {
- for (compunit_symtab *cust : objfile->compunits ())
- {
- QUIT;
- b = BLOCKVECTOR_BLOCK (COMPUNIT_BLOCKVECTOR (cust), GLOBAL_BLOCK);
- add_symbol_overload_list_block (func_name, b, overload_list);
- }
- }
-
- for (objfile *objfile : current_program_space->objfiles ())
- {
- for (compunit_symtab *cust : objfile->compunits ())
- {
- QUIT;
- b = BLOCKVECTOR_BLOCK (COMPUNIT_BLOCKVECTOR (cust), STATIC_BLOCK);
- /* Don't do this block twice. */
- if (b == surrounding_static_block)
- continue;
- add_symbol_overload_list_block (func_name, b, overload_list);
- }
- }
+ const block *block = get_selected_block (0);
+ struct objfile *current_objfile = block ? block->objfile () : nullptr;
+
+ gdbarch_iterate_over_objfiles_in_search_order
+ (current_objfile ? current_objfile->arch () : target_gdbarch (),
+ [func_name, surrounding_static_block, &overload_list]
+ (struct objfile *obj)
+ {
+ for (compunit_symtab *cust : obj->compunits ())
+ {
+ QUIT;
+ const struct block *b = cust->blockvector ()->global_block ();
+ add_symbol_overload_list_block (func_name, b, overload_list);
+
+ b = cust->blockvector ()->static_block ();
+ /* Don't do this block twice. */
+ if (b == surrounding_static_block)
+ continue;
+
+ add_symbol_overload_list_block (func_name, b, overload_list);
+ }
+
+ return 0;
+ }, current_objfile);
}
/* Lookup the rtti type for a class name. */
return NULL;
}
- if (SYMBOL_CLASS (rtti_sym) != LOC_TYPEDEF)
+ if (rtti_sym->aclass () != LOC_TYPEDEF)
{
warning (_("RTTI symbol for class '%s' is not a type"), name);
return NULL;
}
- rtti_type = check_typedef (SYMBOL_TYPE (rtti_sym));
+ rtti_type = check_typedef (rtti_sym->type ());
switch (rtti_type->code ())
{
begin_line ();
if (core_dump_allowed)
- fprintf_unfiltered (gdb_stderr,
- _("%s\nAttempting to dump core.\n"),
- long_msg.c_str ());
+ gdb_printf (gdb_stderr,
+ _("%s\nAttempting to dump core.\n"),
+ long_msg.c_str ());
else
warn_cant_dump_core (long_msg.c_str ());
/* A wrapper for bfd_demangle. */
-char *
+gdb::unique_xmalloc_ptr<char>
gdb_demangle (const char *name, int options)
{
- char *result = NULL;
+ gdb::unique_xmalloc_ptr<char> result;
int crash_signal = 0;
#ifdef HAVE_WORKING_FORK
#endif
if (crash_signal == 0)
- result = bfd_demangle (NULL, name, options);
+ result.reset (bfd_demangle (NULL, name, options | DMGL_VERBOSE));
#ifdef HAVE_WORKING_FORK
if (catch_demangler_crashes)
we might be in a background thread. Instead, arrange for
the reporting to happen on the main thread. */
std::string copy = name;
- run_on_main_thread ([=] ()
+ run_on_main_thread ([
+#if __cplusplus >= 201402L
+ =, copy = std::move (copy)
+#else
+ =
+#endif
+ ] ()
{
report_failed_demangle (copy.c_str (), core_dump_allowed,
crash_signal);
/* See cp-support.h. */
+char *
+gdb_cplus_demangle_print (int options,
+ struct demangle_component *tree,
+ int estimated_length,
+ size_t *p_allocated_size)
+{
+ return cplus_demangle_print (options | DMGL_VERBOSE, tree,
+ estimated_length, p_allocated_size);
+}
+
+/* A wrapper for cplus_demangle_v3_components that forces
+ DMGL_VERBOSE. */
+
+static struct demangle_component *
+gdb_cplus_demangle_v3_components (const char *mangled,
+ int options, void **mem)
+{
+ return cplus_demangle_v3_components (mangled, options | DMGL_VERBOSE, mem);
+}
+
+/* See cp-support.h. */
+
unsigned int
cp_search_name_hash (const char *search_name)
{
&& string[5] != ':')
break;
+ /* Ignore template parameter lists. */
+ if (string[0] == '<'
+ && string[1] != '(' && string[1] != '<' && string[1] != '='
+ && string[1] != ' ' && string[1] != '\0')
+ break;
+
hash = SYMBOL_HASH_NEXT (hash, *string);
}
return hash;
completion_match_for_lcd *match_for_lcd
= (comp_match_res != NULL ? &comp_match_res->match_for_lcd : NULL);
+ gdb_assert (match_for_lcd == nullptr || match_for_lcd->empty ());
+
while (true)
{
if (strncmp_iw_with_mode (sname, lookup_name, lookup_name_len,
- mode, language_cplus, match_for_lcd) == 0)
+ mode, language_cplus, match_for_lcd, true) == 0)
{
if (comp_match_res != NULL)
{
return true;
}
+ /* Clear match_for_lcd so the next strncmp_iw_with_mode call starts
+ from scratch. */
+ if (match_for_lcd != nullptr)
+ match_for_lcd->clear ();
+
unsigned int len = cp_find_first_component (sname);
if (sname[len] == '\0')
/* Check that removing parameter info out of NAME produces EXPECTED.
COMPLETION_MODE indicates whether we're testing normal and
completion mode. FILE and LINE are used to provide better test
- location information in case ithe check fails. */
+ location information in case the check fails. */
static void
check_remove_params (const char *file, int line,
memcpy (prefix, arg, len);
prefix[len] = '\0';
- printf_unfiltered ("%s\n", prefix);
+ gdb_printf ("%s\n", prefix);
}
/* Implement "info vtbl". */
cplus_print_vtable (value);
}
+/* See description in cp-support.h. */
+
+const char *
+find_toplevel_char (const char *s, char c)
+{
+ int quoted = 0; /* zero if we're not in quotes;
+ '"' if we're in a double-quoted string;
+ '\'' if we're in a single-quoted string. */
+ int depth = 0; /* Number of unclosed parens we've seen. */
+ const char *scan;
+
+ for (scan = s; *scan; scan++)
+ {
+ if (quoted)
+ {
+ if (*scan == quoted)
+ quoted = 0;
+ else if (*scan == '\\' && *(scan + 1))
+ scan++;
+ }
+ else if (*scan == c && ! quoted && depth == 0)
+ return scan;
+ else if (*scan == '"' || *scan == '\'')
+ quoted = *scan;
+ else if (*scan == '(' || *scan == '<')
+ depth++;
+ else if ((*scan == ')' || *scan == '>') && depth > 0)
+ depth--;
+ else if (*scan == 'o' && !quoted && depth == 0)
+ {
+ /* Handle C++ operator names. */
+ if (strncmp (scan, CP_OPERATOR_STR, CP_OPERATOR_LEN) == 0)
+ {
+ scan += CP_OPERATOR_LEN;
+ if (*scan == c)
+ return scan;
+ while (ISSPACE (*scan))
+ {
+ ++scan;
+ if (*scan == c)
+ return scan;
+ }
+ if (*scan == '\0')
+ break;
+
+ switch (*scan)
+ {
+ /* Skip over one less than the appropriate number of
+ characters: the for loop will skip over the last
+ one. */
+ case '<':
+ if (scan[1] == '<')
+ {
+ scan++;
+ if (*scan == c)
+ return scan;
+ }
+ break;
+ case '>':
+ if (scan[1] == '>')
+ {
+ scan++;
+ if (*scan == c)
+ return scan;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
void _initialize_cp_support ();
void
_initialize_cp_support ()
{
- add_basic_prefix_cmd ("cplus", class_maintenance,
- _("C++ maintenance commands."),
- &maint_cplus_cmd_list,
- "maintenance cplus ",
- 0, &maintenancelist);
- add_alias_cmd ("cp", "cplus",
- class_maintenance, 1,
+ cmd_list_element *maintenance_cplus
+ = add_basic_prefix_cmd ("cplus", class_maintenance,
+ _("C++ maintenance commands."),
+ &maint_cplus_cmd_list,
+ 0, &maintenancelist);
+ add_alias_cmd ("cp", maintenance_cplus, class_maintenance, 1,
&maintenancelist);
add_cmd ("first_component",