diff --git a/gdb/ChangeLog b/gdb/ChangeLog index f9d269f9f1..f30826fa90 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,16 @@ +2013-03-04 Jan Kratochvil + + * 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. + 2013-03-04 Corinna Vinschen * coff-pe-read.c (read_pe_exported_syms): Don't return without diff --git a/gdb/linespec.c b/gdb/linespec.c index 2e98db734d..01f5e0a814 100644 --- a/gdb/linespec.c +++ b/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); } } diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 54f0e3c3af..05386a5336 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2013-03-04 Jan Kratochvil + + * 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. + 2013-02-28 Yao Qi * gdb.trace/report.exp: Move some code to ... diff --git a/gdb/testsuite/gdb.linespec/base/one/thefile.cc b/gdb/testsuite/gdb.linespec/base/one/thefile.cc index f8712c2af0..0417b7a7a4 100644 --- a/gdb/testsuite/gdb.linespec/base/one/thefile.cc +++ b/gdb/testsuite/gdb.linespec/base/one/thefile.cc @@ -9,9 +9,14 @@ +static int twodup () +{ + return 0; +} + int m(int x) { - return x + 23; /* thefile breakpoint */ + return x + 23 + twodup (); /* thefile breakpoint */ } int NameSpace::overload(int x) diff --git a/gdb/testsuite/gdb.linespec/base/two/thefile.cc b/gdb/testsuite/gdb.linespec/base/two/thefile.cc index f0c04cc04e..88188a5e0d 100644 --- a/gdb/testsuite/gdb.linespec/base/two/thefile.cc +++ b/gdb/testsuite/gdb.linespec/base/two/thefile.cc @@ -9,10 +9,15 @@ static int dupname(int y) label: return y; } +static int twodup () +{ + return 0; +} + int n(int y) { int v = dupname(y) - 23; /* thefile breakpoint */ - return v; /* after dupname */ + return v + twodup (); /* after dupname */ } int NameSpace::overload(double x) diff --git a/gdb/testsuite/gdb.linespec/break-ask.exp b/gdb/testsuite/gdb.linespec/break-ask.exp new file mode 100644 index 0000000000..10945f5965 --- /dev/null +++ b/gdb/testsuite/gdb.linespec/break-ask.exp @@ -0,0 +1,100 @@ +# Copyright 2013 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +standard_testfile lspec.cc + +if {[skip_cplus_tests]} { + unsupported ${testfile}.exp + return +} + +set opts {debug c++} +set objfile1 [standard_output_file ${testfile}one.o] +set objfile2 [standard_output_file ${testfile}two.o] + +if { [file pathtype $objdir] == "relative" } { + untested "objdir $objdir should be absolute" + return +} +set saved_pwd [pwd] +cd $srcdir/${subdir}/base/one +set err1 [gdb_compile "thefile.cc" $objfile1 object $opts] +cd $saved_pwd +cd $srcdir/${subdir}/base/two +set err2 [gdb_compile "thefile.cc" $objfile2 object $opts] +cd $saved_pwd +if { $err1 != "" || $err2 != "" } { + untested "compilation failed" + return -1 +} + +if { [gdb_compile "$srcdir/${subdir}/$srcfile $objfile1 $objfile2" \ + $binfile executable $opts] != "" } { + return -1 +} + +clean_restart ${testfile} + +gdb_test_no_output "set multiple-symbols ask" + +gdb_test_no_output "set filename-display absolute" +set cmd "break twodup" +set test "break twodup absolute" +gdb_test_multiple $cmd $test { + -re "^$cmd\r\n\\\[0\\\] cancel\r\n\\\[1\\\] all\r\n\\\[2\\\] \[^\r\n\]+/base/one/thefile\\.cc:twodup\\\(\\\)\r\n\\\[3\\\] \[^\r\n\]+/base/two/thefile\\.cc:twodup\\\(\\\)\r\n> $" { + pass $test + } +} +gdb_test "0" "canceled" + +gdb_test_no_output "set filename-display relative" + +set cmd "break twodup" +set test "break twodup relative" +gdb_test_multiple $cmd $test { + -re "^$cmd\r\n\\\[0\\\] cancel\r\n\\\[1\\\] all\r\n\\\[2\\\] thefile\\.cc:twodup\\\(\\\)\r\n\\\[3\\\] thefile\\.cc:twodup\\\(\\\)\r\n> $" { + pass $test + } +} +gdb_test "2" "^2\r\nBreakpoint \[0-9\]+ at 0x\[0-9a-f\]+: file thefile\\.cc, line \[0-9a-f\]+\\." + +gdb_breakpoint "body_elsewhere" + +gdb_run_cmd +gdb_test "" "Breakpoint \[0-9\]+, twodup \\(\\) at thefile.cc:\[0-9\]+\r\n.*" "expect breakpoint" + +gdb_test "info source" "\r\nLocated in \[^\r\n\]+/base/one/thefile\\.cc\r\n.*" + +gdb_continue_to_breakpoint "body_elsewhere" ".* body_elsewhere marker .*" + +delete_breakpoints + +set cmd "break twodup" +set test "break twodup relative other" +gdb_test_multiple $cmd $test { + -re "^$cmd\r\n\\\[0\\\] cancel\r\n\\\[1\\\] all\r\n\\\[2\\\] thefile\\.cc:twodup\\\(\\\)\r\n\\\[3\\\] thefile\\.cc:twodup\\\(\\\)\r\n> $" { + pass $test + } +} +gdb_test "3" "^3\r\nBreakpoint \[0-9\]+ at 0x\[0-9a-f\]+: file thefile\\.cc, line \[0-9a-f\]+\\." + +gdb_breakpoint "body_elsewhere" + +gdb_run_cmd +gdb_test "" "Breakpoint \[0-9\]+, twodup \\(\\) at thefile.cc:\[0-9\]+\r\n.*" "expect breakpoint other" + +gdb_test "info source" "\r\nLocated in \[^\r\n\]+/base/two/thefile\\.cc\r\n.*" "info source other" + +gdb_continue_to_breakpoint "body_elsewhere other" ".* body_elsewhere marker .*" diff --git a/gdb/testsuite/gdb.linespec/lspec.cc b/gdb/testsuite/gdb.linespec/lspec.cc index b1092e22d7..bb660fbc79 100644 --- a/gdb/testsuite/gdb.linespec/lspec.cc +++ b/gdb/testsuite/gdb.linespec/lspec.cc @@ -9,7 +9,7 @@ int NameSpace::overload() int body_elsewhere() { - int x = 5; + int x = 5; /* body_elsewhere marker */ #include "body.h" }