/* Parser for linespec for the GNU debugger, GDB.
- Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
- 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008,
- 2009, 2010, 2011 Free Software Foundation, Inc.
+ Copyright (C) 1986-2005, 2007-2012 Free Software Foundation, Inc.
This file is part of GDB.
/* The result being accumulated. */
struct symtabs_and_lines result;
-
- /* The current objfile; used only by the minimal symbol code. */
- struct objfile *objfile;
};
/* Prototypes for local functions. */
hash_address_entry (const void *p)
{
const struct address_entry *aep = p;
+ hashval_t hash;
- return iterative_hash_object (*aep, 0);
+ hash = iterative_hash_object (aep->pspace, 0);
+ return iterative_hash_object (aep->addr, hash);
}
/* An equality function for address_entry. */
throw_error (NOT_FOUND_ERROR, "%s", message);
}
+/* A callback function and the additional data to call it with. */
+
+struct symbol_and_data_callback
+{
+ /* The callback to use. */
+ symbol_found_callback_ftype *callback;
+
+ /* Data to be passed to the callback. */
+ void *data;
+};
+
+/* A helper for iterate_over_all_matching_symtabs that is used to
+ restrict calls to another callback to symbols representing inline
+ symbols only. */
+
+static int
+iterate_inline_only (struct symbol *sym, void *d)
+{
+ if (SYMBOL_INLINED (sym))
+ {
+ struct symbol_and_data_callback *cad = d;
+
+ return cad->callback (sym, cad->data);
+ }
+ return 1; /* Continue iterating. */
+}
+
+/* Some data for the expand_symtabs_matching callback. */
+
+struct symbol_matcher_data
+{
+ /* The lookup name against which symbol name should be compared. */
+ const char *lookup_name;
+
+ /* The routine to be used for comparison. */
+ symbol_name_cmp_ftype symbol_name_cmp;
+};
+
/* A helper for iterate_over_all_matching_symtabs that is passed as a
callback to the expand_symtabs_matching method. */
static int
-iterate_name_matcher (const struct language_defn *language,
- const char *name, void *d)
+iterate_name_matcher (const char *name, void *d)
{
- const char **dname = d;
+ const struct symbol_matcher_data *data = d;
- if (language->la_symbol_name_compare (name, *dname) == 0)
- return 1;
- return 0;
+ if (data->symbol_name_cmp (name, data->lookup_name) == 0)
+ return 1; /* Expand this symbol's symbol table. */
+ return 0; /* Skip this symbol. */
}
/* A helper that walks over all matching symtabs in all objfiles and
calls CALLBACK for each symbol matching NAME. If SEARCH_PSPACE is
not NULL, then the search is restricted to just that program
- space. */
+ space. If INCLUDE_INLINE is nonzero then symbols representing
+ inlined instances of functions will be included in the result. */
static void
iterate_over_all_matching_symtabs (const char *name,
const domain_enum domain,
- int (*callback) (struct symbol *, void *),
+ symbol_found_callback_ftype *callback,
void *data,
- struct program_space *search_pspace)
+ struct program_space *search_pspace,
+ int include_inline)
{
struct objfile *objfile;
struct program_space *pspace;
+ struct symbol_matcher_data matcher_data;
+
+ matcher_data.lookup_name = name;
+ matcher_data.symbol_name_cmp =
+ current_language->la_get_symbol_name_cmp != NULL
+ ? current_language->la_get_symbol_name_cmp (name)
+ : strcmp_iw;
ALL_PSPACES (pspace)
{
objfile->sf->qf->expand_symtabs_matching (objfile, NULL,
iterate_name_matcher,
ALL_DOMAIN,
- &name);
+ &matcher_data);
ALL_OBJFILE_SYMTABS (objfile, symtab)
{
block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK);
LA_ITERATE_OVER_SYMBOLS (block, name, domain, callback, data);
+
+ if (include_inline)
+ {
+ struct symbol_and_data_callback cad = { callback, data };
+ int i;
+
+ for (i = FIRST_LOCAL_BLOCK;
+ i < BLOCKVECTOR_NBLOCKS (BLOCKVECTOR (symtab)); i++)
+ {
+ block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), i);
+ LA_ITERATE_OVER_SYMBOLS (block, name, domain,
+ iterate_inline_only, &cad);
+ }
+ }
}
}
}
{
int i1 = 0;
int ibase;
- char *class_name = type_name_no_tag (t);
- char *canon;
+ const char *class_name = type_name_no_tag (t);
/* Ignore this class if it doesn't have a name. This is ugly, but
unless we figure out how to get the physname without the name of
method_counter >= 0;
--method_counter)
{
- char *method_name = TYPE_FN_FIELDLIST_NAME (t, method_counter);
+ const char *method_name = TYPE_FN_FIELDLIST_NAME (t, method_counter);
char dem_opname[64];
if (strncmp (method_name, "__", 2) == 0 ||
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);
lack of single quotes. FIXME: write a linespec_completer which we
can use as appropriate instead of make_symbol_completion_list. */
-struct symtabs_and_lines
+static struct symtabs_and_lines
decode_line_internal (struct linespec_state *self, char **argptr)
{
char *p;
/* Locate the end of the first half of the linespec.
After the call, for instance, if the argptr string is "foo.c:123"
- p will point at "123". If there is only one part, like "foo", p
+ p will point at ":123". If there is only one part, like "foo", p
will point to "". If this is a C++ name, like "A::B::foo", p will
point to "::B::foo". Argptr is not changed by this call. */
first_half = p = locate_first_half (argptr, &is_quote_enclosed);
/* First things first: if ARGPTR starts with a filename, get its
- symtab and strip the filename from ARGPTR. */
- TRY_CATCH (file_exception, RETURN_MASK_ERROR)
+ symtab and strip the filename from ARGPTR.
+ Avoid calling symtab_from_filename if we know can,
+ it can be expensive. We know we can avoid the call if we see a
+ single word (e.g., "break NAME") or if we see a qualified C++
+ name ("break QUAL::NAME"). */
+
+ if (*p != '\0' && !(p[0] == ':' && p[1] == ':'))
{
- self->file_symtabs = symtabs_from_filename (argptr, p, is_quote_enclosed,
- &self->user_filename);
- }
+ TRY_CATCH (file_exception, RETURN_MASK_ERROR)
+ {
+ self->file_symtabs = symtabs_from_filename (argptr, p,
+ is_quote_enclosed,
+ &self->user_filename);
+ }
- if (VEC_empty (symtab_p, self->file_symtabs))
+ if (file_exception.reason >= 0)
+ {
+ /* Check for single quotes on the non-filename part. */
+ is_quoted = (**argptr
+ && strchr (get_gdb_completer_quote_characters (),
+ **argptr) != NULL);
+ if (is_quoted)
+ end_quote = skip_quoted (*argptr);
+
+ /* Locate the next "half" of the linespec. */
+ first_half = p = locate_first_half (argptr, &is_quote_enclosed);
+ }
+
+ if (VEC_empty (symtab_p, self->file_symtabs))
+ {
+ /* A NULL entry means to use GLOBAL_DEFAULT_SYMTAB. */
+ VEC_safe_push (symtab_p, self->file_symtabs, NULL);
+ }
+ }
+ else
{
/* A NULL entry means to use GLOBAL_DEFAULT_SYMTAB. */
VEC_safe_push (symtab_p, self->file_symtabs, NULL);
}
- if (file_exception.reason >= 0)
- {
- /* Check for single quotes on the non-filename part. */
- is_quoted = (**argptr
- && strchr (get_gdb_completer_quote_characters (),
- **argptr) != NULL);
- if (is_quoted)
- end_quote = skip_quoted (*argptr);
-
- /* Locate the next "half" of the linespec. */
- first_half = p = locate_first_half (argptr, &is_quote_enclosed);
- }
-
/* Check if this is an Objective-C method (anything that starts with
a '+' or '-' and a '['). */
if (is_objc_method_format (p))
if (p[0] == '.' || p[1] == ':')
{
- struct symtabs_and_lines values;
- volatile struct gdb_exception ex;
- char *saved_argptr = *argptr;
+ /* We only perform this check for the languages where it might
+ make sense. For instance, Ada does not use this type of
+ syntax, and trying to apply this logic on an Ada linespec
+ may trigger a spurious error (for instance, decode_compound
+ does not like expressions such as `ops."<"', which is a
+ valid function name in Ada). */
+ if (current_language->la_language == language_c
+ || current_language->la_language == language_cplus
+ || current_language->la_language == language_java)
+ {
+ struct symtabs_and_lines values;
+ volatile struct gdb_exception ex;
+ char *saved_argptr = *argptr;
- if (is_quote_enclosed)
- ++saved_arg;
+ if (is_quote_enclosed)
+ ++saved_arg;
- /* Initialize it just to avoid a GCC false warning. */
- memset (&values, 0, sizeof (values));
+ /* Initialize it just to avoid a GCC false warning. */
+ memset (&values, 0, sizeof (values));
- TRY_CATCH (ex, RETURN_MASK_ERROR)
- {
- values = decode_compound (self, argptr, saved_arg, p);
- }
- if ((is_quoted || is_squote_enclosed) && **argptr == '\'')
- *argptr = *argptr + 1;
+ TRY_CATCH (ex, RETURN_MASK_ERROR)
+ {
+ values = decode_compound (self, argptr, saved_arg, p);
+ }
+ if ((is_quoted || is_squote_enclosed) && **argptr == '\'')
+ *argptr = *argptr + 1;
- if (ex.reason >= 0)
- {
- do_cleanups (cleanup);
- return values;
- }
+ if (ex.reason >= 0)
+ {
+ do_cleanups (cleanup);
+ return values;
+ }
- if (ex.error != NOT_FOUND_ERROR)
- throw_exception (ex);
+ if (ex.error != NOT_FOUND_ERROR)
+ throw_exception (ex);
- *argptr = saved_argptr;
+ *argptr = saved_argptr;
+ }
}
else
{
char *p, *p1;
int has_comma;
+ /* Check if the linespec starts with an Ada operator (such as "+",
+ or ">", for instance). */
+ p = *argptr;
+ if (p[0] == '"'
+ && current_language->la_language == language_ada)
+ {
+ const struct ada_opname_map *op;
+
+ for (op = ada_opname_table; op->encoded != NULL; op++)
+ if (strncmp (op->decoded, p, strlen (op->decoded)) == 0)
+ break;
+ if (op->encoded != NULL)
+ {
+ *is_quote_enclosed = 0;
+ return p + strlen (op->decoded);
+ }
+ }
+
/* Maybe we were called with a line range FILENAME:LINENUM,FILENAME:LINENUM
and we must isolate the first half. Outer layers will call again later
for the second half.
info.state = self;
info.result.sals = NULL;
info.result.nelts = 0;
- info.objfile = NULL;
new_argptr = find_imps (*argptr, &symbol_names);
if (VEC_empty (const_char_ptr, symbol_names))
struct type *t;
if (SYMBOL_CLASS (sym) != LOC_TYPEDEF)
- return 1;
+ return 1; /* Continue iterating. */
t = SYMBOL_TYPE (sym);
CHECK_TYPEDEF (t);
if (TYPE_CODE (t) != TYPE_CODE_STRUCT
&& TYPE_CODE (t) != TYPE_CODE_UNION
&& TYPE_CODE (t) != TYPE_CODE_NAMESPACE)
- return 1;
+ return 1; /* Continue iterating. */
slot = htab_find_slot (collector->unique_syms, sym, INSERT);
if (!*slot)
VEC_safe_push (symbolp, collector->symbols, sym);
}
- return 1;
+ return 1; /* Continue iterating. */
}
/* Return the symbol corresponding to the substring of *ARGPTR ending
{
iterate_over_all_matching_symtabs (copy, STRUCT_DOMAIN,
collect_one_symbol, &collector,
- NULL);
+ NULL, 0);
iterate_over_all_matching_symtabs (copy, VAR_DOMAIN,
collect_one_symbol, &collector,
- NULL);
+ NULL, 0);
}
else
{
info.state = self;
info.result.sals = NULL;
info.result.nelts = 0;
- info.objfile = NULL;
/* Iterate over all the types, looking for the names of existing
methods matching COPY. If we cannot find a direct method in a
if (SYMBOL_CLASS (sym) == LOC_BLOCK)
VEC_safe_push (symbolp, *syms, sym);
- return 1;
+ return 1; /* Continue iterating. */
}
/* Look up a function symbol in *ARGPTR. If found, advance *ARGPTR
copy[p - *argptr] = 0;
iterate_over_all_matching_symtabs (copy, VAR_DOMAIN,
- collect_function_symbols, &result, NULL);
+ collect_function_symbols, &result, NULL,
+ 0);
if (VEC_empty (symbolp, result))
VEC_free (symbolp, result);
volatile struct gdb_exception exc;
+ /* Avoid "may be used uninitialized" warning. */
+ values.sals = NULL;
+ values.nelts = 0;
+
TRY_CATCH (exc, RETURN_MASK_ERROR)
{
values = decode_variable (self, copy);
struct collect_info *info = data;
struct symtab_and_line sal;
- if ((SYMBOL_CLASS (sym) == LOC_STATIC
- && !info->state->funfirstline
- && !maybe_add_address (info->state->addr_set,
- SYMTAB_PSPACE (SYMBOL_SYMTAB (sym)),
- SYMBOL_VALUE_ADDRESS (sym)))
- || (SYMBOL_CLASS (sym) == LOC_BLOCK
- && !maybe_add_address (info->state->addr_set,
- SYMTAB_PSPACE (SYMBOL_SYMTAB (sym)),
- BLOCK_START (SYMBOL_BLOCK_VALUE (sym)))))
- {
- /* Nothing. */
- }
- else if (symbol_to_sal (&sal, info->state->funfirstline, sym))
+ if (symbol_to_sal (&sal, info->state->funfirstline, sym)
+ && maybe_add_address (info->state->addr_set,
+ SYMTAB_PSPACE (SYMBOL_SYMTAB (sym)),
+ sal.pc))
add_sal_to_sals (info->state, &info->result, &sal,
SYMBOL_NATURAL_NAME (sym));
- return 1;
+ return 1; /* Continue iterating. */
}
/* We've found a minimal symbol MSYMBOL to associate with our
if (self->funfirstline)
skip_prologue_sal (&sal);
- add_sal_to_sals (self, result, &sal, SYMBOL_NATURAL_NAME (msymbol));
+ if (maybe_add_address (self->addr_set, objfile->pspace, sal.pc))
+ add_sal_to_sals (self, result, &sal, SYMBOL_NATURAL_NAME (msymbol));
}
-/* Callback for iterate_over_minimal_symbols that may add the symbol
- to the result. */
+/* A helper struct which just holds a minimal symbol and the object
+ file from which it came. */
-static void
-check_minsym (struct minimal_symbol *minsym, void *d)
+typedef struct minsym_and_objfile
{
- struct collect_info *info = d;
+ struct minimal_symbol *minsym;
+ struct objfile *objfile;
+} minsym_and_objfile_d;
- if (MSYMBOL_TYPE (minsym) == mst_unknown
- || MSYMBOL_TYPE (minsym) == mst_slot_got_plt
- || MSYMBOL_TYPE (minsym) == mst_solib_trampoline)
- {
- /* Reject some odd ones. */
- }
- else if (info->state->funfirstline
- && MSYMBOL_TYPE (minsym) != mst_text
- && MSYMBOL_TYPE (minsym) != mst_text_gnu_ifunc
- && MSYMBOL_TYPE (minsym) != mst_file_text)
+DEF_VEC_O (minsym_and_objfile_d);
+
+/* A helper struct to pass some data through
+ iterate_over_minimal_symbols. */
+
+struct collect_minsyms
+{
+ /* The objfile we're examining. */
+ struct objfile *objfile;
+
+ /* The funfirstline setting from the initial call. */
+ int funfirstline;
+
+ /* The list_mode setting from the initial call. */
+ int list_mode;
+
+ /* The resulting symbols. */
+ VEC (minsym_and_objfile_d) *msyms;
+};
+
+/* A helper function to classify a minimal_symbol_type according to
+ priority. */
+
+static int
+classify_mtype (enum minimal_symbol_type t)
+{
+ switch (t)
{
- /* When FUNFIRSTLINE, only allow text symbols. */
+ case mst_file_text:
+ case mst_file_data:
+ case mst_file_bss:
+ /* Intermediate priority. */
+ return 1;
+
+ case mst_solib_trampoline:
+ /* Lowest priority. */
+ return 2;
+
+ default:
+ /* Highest priority. */
+ return 0;
}
- else if (maybe_add_address (info->state->addr_set, info->objfile->pspace,
- SYMBOL_VALUE_ADDRESS (minsym)))
- minsym_found (info->state, info->objfile, minsym, &info->result);
+}
+
+/* Callback for qsort that sorts symbols by priority. */
+
+static int
+compare_msyms (const void *a, const void *b)
+{
+ const minsym_and_objfile_d *moa = a;
+ const minsym_and_objfile_d *mob = b;
+ enum minimal_symbol_type ta = MSYMBOL_TYPE (moa->minsym);
+ enum minimal_symbol_type tb = MSYMBOL_TYPE (mob->minsym);
+
+ return classify_mtype (ta) - classify_mtype (tb);
+}
+
+/* Callback for iterate_over_minimal_symbols that adds the symbol to
+ the result. */
+
+static void
+add_minsym (struct minimal_symbol *minsym, void *d)
+{
+ struct collect_minsyms *info = d;
+ minsym_and_objfile_d mo;
+
+ /* Exclude data symbols when looking for breakpoint locations. */
+ if (!info->list_mode)
+ switch (minsym->type)
+ {
+ case mst_slot_got_plt:
+ case mst_data:
+ case mst_bss:
+ case mst_abs:
+ case mst_file_data:
+ case mst_file_bss:
+ {
+ /* Make sure this minsym is not a function descriptor
+ before we decide to discard it. */
+ struct gdbarch *gdbarch = info->objfile->gdbarch;
+ CORE_ADDR addr = gdbarch_convert_from_func_ptr_addr
+ (gdbarch, SYMBOL_VALUE_ADDRESS (minsym),
+ ¤t_target);
+
+ if (addr == SYMBOL_VALUE_ADDRESS (minsym))
+ return;
+ }
+ }
+
+ mo.minsym = minsym;
+ mo.objfile = info->objfile;
+ VEC_safe_push (minsym_and_objfile_d, info->msyms, &mo);
}
/* Search minimal symbols in all objfiles for NAME. If SEARCH_PSPACE
ALL_PSPACES (pspace)
{
+ struct collect_minsyms local;
+ struct cleanup *cleanup;
+
if (search_pspace != NULL && search_pspace != pspace)
continue;
if (pspace->executing_startup)
set_current_program_space (pspace);
+ memset (&local, 0, sizeof (local));
+ local.funfirstline = info->state->funfirstline;
+ local.list_mode = info->state->list_mode;
+
+ cleanup = make_cleanup (VEC_cleanup (minsym_and_objfile_d),
+ &local.msyms);
+
ALL_OBJFILES (objfile)
{
- info->objfile = objfile;
- iterate_over_minimal_symbols (objfile, name, check_minsym, info);
+ local.objfile = objfile;
+ iterate_over_minimal_symbols (objfile, name, add_minsym, &local);
}
+
+ if (!VEC_empty (minsym_and_objfile_d, local.msyms))
+ {
+ int classification;
+ int ix;
+ minsym_and_objfile_d *item;
+
+ qsort (VEC_address (minsym_and_objfile_d, local.msyms),
+ VEC_length (minsym_and_objfile_d, local.msyms),
+ sizeof (minsym_and_objfile_d),
+ compare_msyms);
+
+ /* Now the minsyms are in classification order. So, we walk
+ over them and process just the minsyms with the same
+ classification as the very first minsym in the list. */
+ item = VEC_index (minsym_and_objfile_d, local.msyms, 0);
+ classification = classify_mtype (MSYMBOL_TYPE (item->minsym));
+
+ for (ix = 0;
+ VEC_iterate (minsym_and_objfile_d, local.msyms, ix, item);
+ ++ix)
+ {
+ if (classify_mtype (MSYMBOL_TYPE (item->minsym)) != classification)
+ break;
+
+ minsym_found (info->state, item->objfile, item->minsym,
+ &info->result);
+ }
+ }
+
+ do_cleanups (cleanup);
}
}
{
iterate_over_all_matching_symtabs (name, VAR_DOMAIN,
collect_symbols, info,
- pspace);
+ pspace, 1);
search_minsyms_for_name (info, name, pspace);
}
else if (pspace == NULL || pspace == SYMTAB_PSPACE (elt))
info.state = self;
info.result.sals = NULL;
info.result.nelts = 0;
- info.objfile = NULL;
cleanup = demangle_for_lookup (copy, current_language->la_language,
&lookup_name);