/* Parser for linespec for the GNU debugger, GDB.
- Copyright (C) 1986-2005, 2007-2012 Free Software Foundation, Inc.
+ Copyright (C) 1986-2013 Free Software Foundation, Inc.
This file is part of GDB.
};
typedef struct linespec *linespec_p;
+/* A canonical linespec represented as a symtab-related string.
+
+ Each entry represents the "SYMTAB:SUFFIX" linespec string.
+ SYMTAB can be converted for example by symtab_to_fullname or
+ symtab_to_filename_for_display as needed. */
+
+struct linespec_canonical_name
+{
+ /* Remaining text part of the linespec string. */
+ char *suffix;
+
+ /* If NULL then SUFFIX is the whole linespec string. */
+ struct symtab *symtab;
+};
+
/* An instance of this is used to keep all state while linespec
operates. This instance is passed around as a 'this' pointer to
the various implementation methods. */
struct linespec_result *canonical;
/* Canonical strings that mirror the symtabs_and_lines result. */
- char **canonical_names;
+ struct linespec_canonical_name *canonical_names;
/* This is a set of address_entry objects which is used to prevent
duplicate symbols from being entered into the result. */
/* Prototypes for local functions. */
+static void iterate_over_file_blocks (struct symtab *symtab,
+ const char *name, domain_enum domain,
+ symbol_found_callback_ftype *callback,
+ void *data);
+
static void initialize_defaults (struct symtab **default_symtab,
int *default_line);
-static CORE_ADDR linespec_expression_to_pc (char **exp_ptr);
+static CORE_ADDR linespec_expression_to_pc (const char **exp_ptr);
static struct symtabs_and_lines decode_objc (struct linespec_state *self,
linespec_p ls,
VEC (symbolp) **label_funcs_ret,
const char *name);
-void find_linespec_symbols (struct linespec_state *self,
- VEC (symtab_p) *file_symtabs,
- const char *name,
- VEC (symbolp) **symbols,
- VEC (minsym_and_objfile_d) **minsyms);
+static void find_linespec_symbols (struct linespec_state *self,
+ VEC (symtab_p) *file_symtabs,
+ const char *name,
+ VEC (symbolp) **symbols,
+ VEC (minsym_and_objfile_d) **minsyms);
static struct line_offset
linespec_parse_variable (struct linespec_state *self,
if (self->canonical)
{
- char *canonical_name = NULL;
+ struct linespec_canonical_name *canonical;
self->canonical_names = xrealloc (self->canonical_names,
- sals->nelts * sizeof (char *));
- if (!literal_canonical && sal->symtab && sal->symtab->filename)
+ (sals->nelts
+ * sizeof (*self->canonical_names)));
+ canonical = &self->canonical_names[sals->nelts - 1];
+ if (!literal_canonical && sal->symtab)
{
- char *filename = sal->symtab->filename;
+ const char *fullname = symtab_to_fullname (sal->symtab);
/* Note that the filter doesn't have to be a valid linespec
input. We only apply the ":LINE" treatment to Ada for
the time being. */
if (symname != NULL && sal->line != 0
&& self->language->la_language == language_ada)
- canonical_name = xstrprintf ("%s:%s:%d", filename, symname,
- sal->line);
+ canonical->suffix = xstrprintf ("%s:%d", symname, sal->line);
else if (symname != NULL)
- canonical_name = xstrprintf ("%s:%s", filename, symname);
+ canonical->suffix = xstrdup (symname);
else
- canonical_name = xstrprintf ("%s:%d", filename, sal->line);
+ canonical->suffix = xstrprintf ("%d", sal->line);
+ canonical->symtab = sal->symtab;
+ }
+ else
+ {
+ if (symname != NULL)
+ canonical->suffix = xstrdup (symname);
+ else
+ canonical->suffix = NULL;
+ canonical->symtab = NULL;
}
- else if (symname != NULL)
- canonical_name = xstrdup (symname);
-
- self->canonical_names[sals->nelts - 1] = canonical_name;
}
}
ALL_OBJFILE_PRIMARY_SYMTABS (objfile, symtab)
{
- struct block *block;
-
- block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK);
- state->language->la_iterate_over_symbols (block, name, domain,
- callback, data);
+ iterate_over_file_blocks (symtab, name, domain, callback, data);
if (include_inline)
{
struct symbol_and_data_callback cad = { callback, data };
+ struct block *block;
int i;
for (i = FIRST_LOCAL_BLOCK;
}
}
-/* Returns the block to be used for symbol searches for the given SYMTAB,
- which may be NULL. */
+/* Returns the block to be used for symbol searches from
+ the current location. */
static struct block *
-get_search_block (struct symtab *symtab)
+get_current_search_block (void)
{
struct block *block;
+ enum language save_language;
- if (symtab != NULL)
- block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK);
- else
- {
- enum language save_language;
-
- /* get_selected_block can change the current language when there is
- no selected frame yet. */
- save_language = current_language->la_language;
- block = get_selected_block (0);
- set_language (save_language);
- }
+ /* get_selected_block can change the current language when there is
+ no selected frame yet. */
+ save_language = current_language->la_language;
+ block = get_selected_block (0);
+ set_language (save_language);
return block;
}
+/* Iterate over static and global blocks. */
+
+static void
+iterate_over_file_blocks (struct symtab *symtab,
+ const char *name, domain_enum domain,
+ symbol_found_callback_ftype *callback, void *data)
+{
+ struct block *block;
+
+ for (block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK);
+ block != NULL;
+ block = BLOCK_SUPERBLOCK (block))
+ LA_ITERATE_OVER_SYMBOLS (block, name, domain, callback, data);
+}
+
/* A helper for find_method. This finds all methods in type T which
match NAME. It adds matching symbol names to RESULT_NAMES, and
adds T's direct superclasses to SUPERCLASSES. */
return NULL;
}
+/* Convert CANONICAL to its string representation using
+ symtab_to_fullname for SYMTAB. The caller must xfree the result. */
+
+static char *
+canonical_to_fullform (const struct linespec_canonical_name *canonical)
+{
+ if (canonical->symtab == NULL)
+ return xstrdup (canonical->suffix);
+ else
+ return xstrprintf ("%s:%s", symtab_to_fullname (canonical->symtab),
+ canonical->suffix);
+}
+
/* Given FILTERS, a list of canonical names, filter the sals in RESULT
and store the result in SELF->CANONICAL. */
for (j = 0; j < result->nelts; ++j)
{
- if (strcmp (name, self->canonical_names[j]) == 0)
+ const struct linespec_canonical_name *canonical;
+ char *fullform;
+ struct cleanup *cleanup;
+
+ canonical = &self->canonical_names[j];
+ fullform = canonical_to_fullform (canonical);
+ cleanup = make_cleanup (xfree, fullform);
+
+ if (strcmp (name, fullform) == 0)
add_sal_to_sals_basic (&lsal.sals, &result->sals[j]);
+
+ do_cleanups (cleanup);
}
if (lsal.sals.nelts > 0)
VEC_safe_push (linespec_sals, self->canonical->sals, &lsal);
}
+/* A structure that contains two string representations of a struct
+ linespec_canonical_name:
+ - one where the the symtab's fullname is used;
+ - one where the filename followed the "set filename-display"
+ setting. */
+
+struct decode_line_2_item
+{
+ /* The form using symtab_to_fullname.
+ It must be xfree'ed after use. */
+ char *fullform;
+
+ /* The form using symtab_to_filename_for_display.
+ It must be xfree'ed after use. */
+ char *displayform;
+
+ /* Field is initialized to zero and it is set to one if the user
+ requested breakpoint for this entry. */
+ unsigned int selected : 1;
+};
+
+/* Helper for qsort to sort decode_line_2_item entries by DISPLAYFORM and
+ secondarily by FULLFORM. */
+
+static int
+decode_line_2_compare_items (const void *ap, const void *bp)
+{
+ const struct decode_line_2_item *a = ap;
+ const struct decode_line_2_item *b = bp;
+ int retval;
+
+ retval = strcmp (a->displayform, b->displayform);
+ if (retval != 0)
+ return retval;
+
+ return strcmp (a->fullform, b->fullform);
+}
+
/* Handle multiple results in RESULT depending on SELECT_MODE. This
will either return normally, throw an exception on multiple
results, or present a menu to the user. On return, the SALS vector
struct symtabs_and_lines *result,
const char *select_mode)
{
- const char *iter;
char *args, *prompt;
int i;
struct cleanup *old_chain;
- VEC (const_char_ptr) *item_names = NULL, *filters = NULL;
+ VEC (const_char_ptr) *filters = NULL;
struct get_number_or_range_state state;
+ struct decode_line_2_item *items;
+ int items_count;
gdb_assert (select_mode != multiple_symbols_all);
gdb_assert (self->canonical != NULL);
+ gdb_assert (result->nelts >= 1);
+
+ old_chain = make_cleanup (VEC_cleanup (const_char_ptr), &filters);
- old_chain = make_cleanup (VEC_cleanup (const_char_ptr), &item_names);
- make_cleanup (VEC_cleanup (const_char_ptr), &filters);
- for (i = 0; i < result->nelts; ++i)
+ /* Prepare ITEMS array. */
+ items_count = result->nelts;
+ items = xmalloc (sizeof (*items) * items_count);
+ make_cleanup (xfree, items);
+ for (i = 0; i < items_count; ++i)
{
- int j, found = 0;
- const char *iter;
+ const struct linespec_canonical_name *canonical;
+ struct decode_line_2_item *item;
- gdb_assert (self->canonical_names[i] != NULL);
- for (j = 0; VEC_iterate (const_char_ptr, item_names, j, iter); ++j)
+ canonical = &self->canonical_names[i];
+ gdb_assert (canonical->suffix != NULL);
+ item = &items[i];
+
+ item->fullform = canonical_to_fullform (canonical);
+ make_cleanup (xfree, item->fullform);
+
+ if (canonical->symtab == NULL)
+ item->displayform = canonical->suffix;
+ else
{
- if (strcmp (iter, self->canonical_names[i]) == 0)
- {
- found = 1;
- break;
- }
+ const char *fn_for_display;
+
+ fn_for_display = symtab_to_filename_for_display (canonical->symtab);
+ item->displayform = xstrprintf ("%s:%s", fn_for_display,
+ canonical->suffix);
+ make_cleanup (xfree, item->displayform);
}
- if (!found)
- VEC_safe_push (const_char_ptr, item_names, self->canonical_names[i]);
+ item->selected = 0;
+ }
+
+ /* Sort the list of method names. */
+ qsort (items, items_count, sizeof (*items), decode_line_2_compare_items);
+
+ /* Remove entries with the same FULLFORM. */
+ if (items_count >= 2)
+ {
+ struct decode_line_2_item *dst, *src;
+
+ dst = items;
+ for (src = &items[1]; src < &items[items_count]; src++)
+ if (strcmp (src->fullform, dst->fullform) != 0)
+ *++dst = *src;
+ items_count = dst + 1 - items;
}
- if (select_mode == multiple_symbols_cancel
- && VEC_length (const_char_ptr, item_names) > 1)
+ if (select_mode == multiple_symbols_cancel && items_count > 1)
error (_("canceled because the command is ambiguous\n"
"See set/show multiple-symbol."));
- if (select_mode == multiple_symbols_all
- || VEC_length (const_char_ptr, item_names) == 1)
+ if (select_mode == multiple_symbols_all || items_count == 1)
{
do_cleanups (old_chain);
convert_results_to_lsals (self, result);
return;
}
- /* Sort the list of method names alphabetically. */
- qsort (VEC_address (const_char_ptr, item_names),
- VEC_length (const_char_ptr, item_names),
- sizeof (const_char_ptr), compare_strings);
-
printf_unfiltered (_("[0] cancel\n[1] all\n"));
- for (i = 0; VEC_iterate (const_char_ptr, item_names, i, iter); ++i)
- printf_unfiltered ("[%d] %s\n", i + 2, iter);
+ for (i = 0; i < items_count; i++)
+ printf_unfiltered ("[%d] %s\n", i + 2, items[i].displayform);
prompt = getenv ("PS2");
if (prompt == NULL)
}
num -= 2;
- if (num >= VEC_length (const_char_ptr, item_names))
+ if (num >= items_count)
printf_unfiltered (_("No choice number %d.\n"), num);
else
{
- const char *elt = VEC_index (const_char_ptr, item_names, num);
+ struct decode_line_2_item *item = &items[num];
- if (elt != NULL)
+ if (!item->selected)
{
- VEC_safe_push (const_char_ptr, filters, elt);
- VEC_replace (const_char_ptr, item_names, num, NULL);
+ VEC_safe_push (const_char_ptr, filters, item->fullform);
+ item->selected = 1;
}
else
{
printf_unfiltered (_("duplicate request for %d ignored.\n"),
- num);
+ num + 2);
}
}
}
if (VEC_length (symtab_p, ls->file_symtabs) == 1
&& VEC_index (symtab_p, ls->file_symtabs, 0) == NULL)
{
+ const char *fullname;
+
set_current_program_space (self->program_space);
/* Make sure we have at least a default source line. */
set_default_source_symtab_and_line ();
initialize_defaults (&self->default_symtab, &self->default_line);
+ fullname = symtab_to_fullname (self->default_symtab);
VEC_pop (symtab_p, ls->file_symtabs);
VEC_free (symtab_p, ls->file_symtabs);
- ls->file_symtabs
- = collect_symtabs_from_filename (self->default_symtab->filename);
+ ls->file_symtabs = collect_symtabs_from_filename (fullname);
use_default = 1;
}
/* Make sure we have a filename for canonicalization. */
if (ls->source_filename == NULL)
- ls->source_filename = xstrdup (state->default_symtab->filename);
+ {
+ const char *fullname = symtab_to_fullname (state->default_symtab);
+
+ ls->source_filename = xstrdup (fullname);
+ }
}
else
{
/* It must be either LSTOKEN_STRING or LSTOKEN_NUMBER. */
if (token.type == LSTOKEN_STRING && *LS_TOKEN_STOKEN (token).ptr == '*')
{
- char *expr, *copy;
+ char *expr;
+ const char *copy;
/* User specified an expression, *EXPR. */
copy = expr = copy_token_string (token);
make_cleanup (xfree, state->canonical_names);
for (i = 0; i < result.nelts; ++i)
{
- gdb_assert (state->canonical_names[i] != NULL);
- make_cleanup (xfree, state->canonical_names[i]);
+ gdb_assert (state->canonical_names[i].suffix != NULL);
+ make_cleanup (xfree, state->canonical_names[i].suffix);
}
}
advancing EXP_PTR past any parsed text. */
static CORE_ADDR
-linespec_expression_to_pc (char **exp_ptr)
+linespec_expression_to_pc (const char **exp_ptr)
{
if (current_program_space->executing_startup)
/* The error message doesn't really matter, because this case
}
else
{
- struct block *search_block;
-
/* Program spaces that are executing startup should have
been filtered out earlier. */
gdb_assert (!SYMTAB_PSPACE (elt)->executing_startup);
set_current_program_space (SYMTAB_PSPACE (elt));
- search_block = get_search_block (elt);
- LA_ITERATE_OVER_SYMBOLS (search_block, class_name, STRUCT_DOMAIN,
- collect_one_symbol, &collector);
- LA_ITERATE_OVER_SYMBOLS (search_block, class_name, VAR_DOMAIN,
- collect_one_symbol, &collector);
+ iterate_over_file_blocks (elt, class_name, STRUCT_DOMAIN,
+ collect_one_symbol, &collector);
+ iterate_over_file_blocks (elt, class_name, VAR_DOMAIN,
+ collect_one_symbol, &collector);
}
}
/* Find all symbols named NAME in FILE_SYMTABS, returning debug symbols
in SYMBOLS and minimal symbols in MINSYMS. */
-void
+static void
find_linespec_symbols (struct linespec_state *state,
VEC (symtab_p) *file_symtabs,
const char *name,
VEC (symbolp) **symbols,
VEC (minsym_and_objfile_d) **minsyms)
{
- char *klass, *method, *canon;
- const char *lookup_name, *last, *p, *scope_op;
struct cleanup *cleanup;
- VEC (symbolp) *classes;
+ char *canon;
+ const char *lookup_name;
volatile struct gdb_exception except;
cleanup = demangle_for_lookup (name, state->language->la_language,
cleanup = make_cleanup (xfree, canon);
}
- /* See if we can find a scope operator and break this symbol
- name into namespaces${SCOPE_OPERATOR}class_name and method_name. */
- scope_op = "::";
- p = find_toplevel_string (lookup_name, scope_op);
- if (p == NULL)
- {
- /* No C++ scope operator. Try Java. */
- scope_op = ".";
- p = find_toplevel_string (lookup_name, scope_op);
- }
+ /* It's important to not call expand_symtabs_matching unnecessarily
+ as it can really slow things down (by unnecessarily expanding
+ potentially 1000s of symtabs, which when debugging some apps can
+ cost 100s of seconds). Avoid this to some extent by *first* calling
+ find_function_symbols, and only if that doesn't find anything
+ *then* call find_method. This handles two important cases:
+ 1) break (anonymous namespace)::foo
+ 2) break class::method where method is in class (and not a baseclass) */
- last = NULL;
- while (p != NULL)
- {
- last = p;
- p = find_toplevel_string (p + strlen (scope_op), scope_op);
- }
+ find_function_symbols (state, file_symtabs, lookup_name,
+ symbols, minsyms);
- /* If no scope operator was found, lookup the name as a symbol. */
- if (last == NULL)
+ /* If we were unable to locate a symbol of the same name, try dividing
+ the name into class and method names and searching the class and its
+ baseclasses. */
+ if (VEC_empty (symbolp, *symbols)
+ && VEC_empty (minsym_and_objfile_d, *minsyms))
{
- find_function_symbols (state, file_symtabs, lookup_name,
- symbols, minsyms);
- do_cleanups (cleanup);
- return;
- }
-
- /* NAME points to the class name.
- LAST points to the method name. */
- klass = xmalloc ((last - lookup_name + 1) * sizeof (char));
- make_cleanup (xfree, klass);
- strncpy (klass, lookup_name, last - lookup_name);
- klass[last - lookup_name] = '\0';
+ char *klass, *method;
+ const char *last, *p, *scope_op;
+ VEC (symbolp) *classes;
- /* Skip past the scope operator. */
- last += strlen (scope_op);
- method = xmalloc ((strlen (last) + 1) * sizeof (char));
- make_cleanup (xfree, method);
- strcpy (method, last);
+ /* See if we can find a scope operator and break this symbol
+ name into namespaces${SCOPE_OPERATOR}class_name and method_name. */
+ scope_op = "::";
+ p = find_toplevel_string (lookup_name, scope_op);
+ if (p == NULL)
+ {
+ /* No C++ scope operator. Try Java. */
+ scope_op = ".";
+ p = find_toplevel_string (lookup_name, scope_op);
+ }
- /* Find a list of classes named KLASS. */
- classes = lookup_prefix_sym (state, file_symtabs, klass);
- make_cleanup (VEC_cleanup (symbolp), &classes);
- if (!VEC_empty (symbolp, classes))
- {
- /* Now locate a list of suitable methods named METHOD. */
- TRY_CATCH (except, RETURN_MASK_ERROR)
+ last = NULL;
+ while (p != NULL)
{
- find_method (state, file_symtabs, klass, method, classes,
- symbols, minsyms);
+ last = p;
+ p = find_toplevel_string (p + strlen (scope_op), scope_op);
}
- /* If successful, we're done. If NOT_FOUND_ERROR
- was not thrown, rethrow the exception that we did get.
- Otherwise, fall back to looking up the entire name as a symbol.
- This can happen with namespace::function. */
- if (except.reason >= 0)
+ /* If no scope operator was found, there is nothing more we can do;
+ we already attempted to lookup the entire name as a symbol
+ and failed. */
+ if (last == NULL)
{
do_cleanups (cleanup);
return;
}
- else if (except.error != NOT_FOUND_ERROR)
- throw_exception (except);
+
+ /* LOOKUP_NAME points to the class name.
+ LAST points to the method name. */
+ klass = xmalloc ((last - lookup_name + 1) * sizeof (char));
+ make_cleanup (xfree, klass);
+ strncpy (klass, lookup_name, last - lookup_name);
+ klass[last - lookup_name] = '\0';
+
+ /* Skip past the scope operator. */
+ last += strlen (scope_op);
+ method = xmalloc ((strlen (last) + 1) * sizeof (char));
+ make_cleanup (xfree, method);
+ strcpy (method, last);
+
+ /* Find a list of classes named KLASS. */
+ classes = lookup_prefix_sym (state, file_symtabs, klass);
+ make_cleanup (VEC_cleanup (symbolp), &classes);
+
+ if (!VEC_empty (symbolp, classes))
+ {
+ /* Now locate a list of suitable methods named METHOD. */
+ TRY_CATCH (except, RETURN_MASK_ERROR)
+ {
+ find_method (state, file_symtabs, klass, method, classes,
+ symbols, minsyms);
+ }
+
+ /* If successful, we're done. If NOT_FOUND_ERROR
+ was not thrown, rethrow the exception that we did get. */
+ if (except.reason < 0 && except.error != NOT_FOUND_ERROR)
+ throw_exception (except);
+ }
}
- /* We couldn't find a class, so we check the entire name as a symbol
- instead. */
- find_function_symbols (state, file_symtabs, lookup_name, symbols, minsyms);
- do_cleanups (cleanup);
+ do_cleanups (cleanup);
}
/* Return all labels named NAME in FUNCTION_SYMBOLS. Return the
if (function_symbols == NULL)
{
set_current_program_space (self->program_space);
- block = get_search_block (NULL);
+ block = get_current_search_block ();
for (;
block && !BLOCK_FUNCTION (block);
sal = find_pc_sect_line (SYMBOL_VALUE_ADDRESS (msymbol),
(struct obj_section *) 0, 0);
- sal.section = SYMBOL_OBJ_SECTION (msymbol);
+ sal.section = SYMBOL_OBJ_SECTION (objfile, msymbol);
/* The minimal symbol might point to a function descriptor;
resolve it to the actual code address instead. */
been filtered out earlier. */
gdb_assert (!SYMTAB_PSPACE (elt)->executing_startup);
set_current_program_space (SYMTAB_PSPACE (elt));
- LA_ITERATE_OVER_SYMBOLS (get_search_block (elt), name,
- VAR_DOMAIN, collect_symbols,
- info);
+ iterate_over_file_blocks (elt, name, VAR_DOMAIN,
+ collect_symbols, info);
}
}
}