forked from Imagelibrary/binutils-gdb
gdb/
* linespec.c (struct linespec_canonical_name): New. (struct linespec_state): Change canonical_names type to it. (add_sal_to_sals): Change variable canonical_name to canonical. Change xrealloc element size. Initialize the different CANONICAL fields. (canonical_to_fullform): New. (filter_results): Use it. Add variables canonical, fullform and cleanup. (struct decode_line_2_item, decode_line_2_compare_items): New. (decode_line_2): Remove variables iter and item_names, add variables items and items_count. Modify the code for these new variables. gdb/testsuite/ * gdb.linespec/base/one/thefile.cc (twodup): New. (m): Call it. * gdb.linespec/base/two/thefile.cc (dupname): New. (n): Call it. * gdb.linespec/break-ask.exp: New file. * gdb.linespec/lspec.cc (body_elsewhere): New comment marker.
This commit is contained in:
196
gdb/linespec.c
196
gdb/linespec.c
@@ -157,6 +157,21 @@ struct linespec
|
||||
};
|
||||
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. */
|
||||
@@ -186,7 +201,7 @@ struct linespec_state
|
||||
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. */
|
||||
@@ -848,10 +863,12 @@ add_sal_to_sals (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 *));
|
||||
(sals->nelts
|
||||
* sizeof (*self->canonical_names)));
|
||||
canonical = &self->canonical_names[sals->nelts - 1];
|
||||
if (!literal_canonical && sal->symtab)
|
||||
{
|
||||
const char *fullname = symtab_to_fullname (sal->symtab);
|
||||
@@ -861,17 +878,21 @@ add_sal_to_sals (struct linespec_state *self,
|
||||
the time being. */
|
||||
if (symname != NULL && sal->line != 0
|
||||
&& self->language->la_language == language_ada)
|
||||
canonical_name = xstrprintf ("%s:%s:%d", fullname, symname,
|
||||
sal->line);
|
||||
canonical->suffix = xstrprintf ("%s:%d", symname, sal->line);
|
||||
else if (symname != NULL)
|
||||
canonical_name = xstrprintf ("%s:%s", fullname, symname);
|
||||
canonical->suffix = xstrdup (symname);
|
||||
else
|
||||
canonical_name = xstrprintf ("%s:%d", fullname, 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1200,6 +1221,19 @@ find_toplevel_string (const char *haystack, const char *needle)
|
||||
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. */
|
||||
|
||||
@@ -1220,8 +1254,18 @@ filter_results (struct linespec_state *self,
|
||||
|
||||
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)
|
||||
@@ -1247,6 +1291,44 @@ convert_results_to_lsals (struct linespec_state *self,
|
||||
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
|
||||
@@ -1257,58 +1339,80 @@ decode_line_2 (struct linespec_state *self,
|
||||
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), &item_names);
|
||||
make_cleanup (VEC_cleanup (const_char_ptr), &filters);
|
||||
for (i = 0; i < result->nelts; ++i)
|
||||
old_chain = make_cleanup (VEC_cleanup (const_char_ptr), &filters);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
if (select_mode == multiple_symbols_cancel
|
||||
&& VEC_length (const_char_ptr, item_names) > 1)
|
||||
/* 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 && 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)
|
||||
@@ -1343,16 +1447,16 @@ decode_line_2 (struct linespec_state *self,
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
@@ -2326,8 +2430,8 @@ decode_line_full (char **argptr, int flags,
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user