the "ambiguous linespec" series
[deliverable/binutils-gdb.git] / gdb / linespec.c
index 68859a8457dcb6d6708b553b9ec1712d7e3ea8f1..e6e863d65931846c92d4b288a7075250cd0be984 100644 (file)
 #include "mi/mi-cmds.h"
 #include "target.h"
 #include "arch-utils.h"
+#include <ctype.h>
+#include "cli/cli-utils.h"
+#include "filenames.h"
+#include "ada-lang.h"
 
-/* We share this one with symtab.c, but it is not exported widely.  */
+typedef struct symtab *symtab_p;
+DEF_VEC_P (symtab_p);
 
-extern char *operator_chars (char *, char **);
+typedef struct symbol *symbolp;
+DEF_VEC_P (symbolp);
+
+typedef struct type *typep;
+DEF_VEC_P (typep);
+
+/* An address entry is used to ensure that any given location is only
+   added to the result a single time.  It holds an address and the
+   program space from which the address came.  */
+
+struct address_entry
+{
+  struct program_space *pspace;
+  CORE_ADDR addr;
+};
+
+/* 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_state
+{
+  /* The program space as seen when the module was entered.  */
+  struct program_space *program_space;
+
+  /* The default symtab to use, if no other symtab is specified.  */
+  struct symtab *default_symtab;
+
+  /* The default line to use.  */
+  int default_line;
+
+  /* If the linespec started with "FILE:", this holds all the matching
+     symtabs.  Otherwise, it will hold a single NULL entry, meaning
+     that the default symtab should be used.  */
+  VEC (symtab_p) *file_symtabs;
+
+  /* If the linespec started with "FILE:", this holds an xmalloc'd
+     copy of "FILE".  */
+  char *user_filename;
+
+  /* If the linespec is "FUNCTION:LABEL", this holds an xmalloc'd copy
+     of "FUNCTION".  */
+  char *user_function;
+
+  /* The 'funfirstline' value that was passed in to decode_line_1 or
+     decode_line_full.  */
+  int funfirstline;
+
+  /* Nonzero if we are running in 'list' mode; see decode_line_list.  */
+  int list_mode;
+
+  /* The 'canonical' value passed to decode_line_full, or NULL.  */
+  struct linespec_result *canonical;
+
+  /* Canonical strings that mirror the symtabs_and_lines result.  */
+  char **canonical_names;
+
+  /* This is a set of address_entry objects which is used to prevent
+     duplicate symbols from being entered into the result.  */
+  htab_t addr_set;
+};
+
+/* This is a helper object that is used when collecting symbols into a
+   result.  */
+
+struct collect_info
+{
+  /* The linespec object in use.  */
+  struct linespec_state *state;
+
+  /* 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.  */
 
 static void initialize_defaults (struct symtab **default_symtab,
                                 int *default_line);
 
-static struct symtabs_and_lines decode_indirect (char **argptr);
+static struct symtabs_and_lines decode_indirect (struct linespec_state *self,
+                                                char **argptr);
 
 static char *locate_first_half (char **argptr, int *is_quote_enclosed);
 
-static struct symtabs_and_lines decode_objc (char **argptr,
-                                            int funfirstline,
-                                            struct symtab *file_symtab,
-                                            char ***canonical,
-                                            char *saved_arg);
+static struct symtabs_and_lines decode_objc (struct linespec_state *self,
+                                            char **argptr);
 
-static struct symtabs_and_lines decode_compound (char **argptr,
-                                                int funfirstline,
-                                                char ***canonical,
+static struct symtabs_and_lines decode_compound (struct linespec_state *self,
+                                                char **argptr,
                                                 char *saved_arg,
-                                                char *p,
-                                                int *not_found_ptr);
+                                                char *p);
 
-static struct symbol *lookup_prefix_sym (char **argptr, char *p);
+static VEC (symbolp) *lookup_prefix_sym (char **argptr, char *p,
+                                        VEC (symtab_p) *,
+                                        char **);
 
-static struct symtabs_and_lines find_method (int funfirstline,
-                                            char ***canonical,
+static struct symtabs_and_lines find_method (struct linespec_state *self,
                                             char *saved_arg,
                                             char *copy,
-                                            struct type *t,
-                                            struct symbol *sym_class,
-                                            int *not_found_ptr);
+                                            const char *class_name,
+                                            VEC (symbolp) *sym_classes);
 
 static void cplusplus_error (const char *name, const char *fmt, ...)
      ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (2, 3);
 
-static int total_number_of_methods (struct type *type);
+static char *find_toplevel_char (char *s, char c);
+
+static int is_objc_method_format (const char *s);
 
-static int find_methods (struct type *, char *,
-                        enum language, struct symbol **);
+static VEC (symtab_p) *symtabs_from_filename (char **argptr,
+                                             char *p, int is_quote_enclosed,
+                                             char **user_filename);
 
-static int add_matching_methods (int method_counter, struct type *t,
-                                enum language language,
-                                struct symbol **sym_arr);
+static VEC (symbolp) *find_function_symbols (char **argptr, char *p,
+                                            int is_quote_enclosed,
+                                            char **user_function);
 
-static int add_constructors (int method_counter, struct type *t,
-                            enum language language,
-                            struct symbol **sym_arr);
+static struct symtabs_and_lines decode_all_digits (struct linespec_state *self,
+                                                  char **argptr,
+                                                  char *q);
 
-static void build_canonical_line_spec (struct symtab_and_line *,
-                                      char *, char ***);
+static struct symtabs_and_lines decode_dollar (struct linespec_state *self,
+                                              char *copy);
 
-static char *find_toplevel_char (char *s, char c);
+static int decode_label (struct linespec_state *self,
+                        VEC (symbolp) *function_symbols,
+                        char *copy,
+                        struct symtabs_and_lines *result);
 
-static int is_objc_method_format (const char *s);
+static struct symtabs_and_lines decode_variable (struct linespec_state *self,
+                                                char *copy);
 
-static struct symtabs_and_lines decode_line_2 (struct symbol *[],
-                                              int, int, char ***);
+static int symbol_to_sal (struct symtab_and_line *result,
+                         int funfirstline, struct symbol *sym);
 
-static struct symtab *symtab_from_filename (char **argptr,
-                                           char *p, int is_quote_enclosed,
-                                           int *not_found_ptr);
+static void add_matching_symbols_to_info (const char *name,
+                                         struct collect_info *info,
+                                         struct program_space *pspace);
 
-static struct
-symtabs_and_lines decode_all_digits (char **argptr,
-                                    struct symtab *default_symtab,
-                                    int default_line,
-                                    char ***canonical,
-                                    struct symtab *file_symtab,
-                                    char *q);
+static void add_all_symbol_names_from_pspace (struct collect_info *info,
+                                             struct program_space *pspace,
+                                             VEC (const_char_ptr) *names);
 
-static struct symtabs_and_lines decode_dollar (char *copy,
-                                              int funfirstline,
-                                              struct symtab *default_symtab,
-                                              char ***canonical,
-                                              struct symtab *file_symtab);
+/* Helper functions.  */
 
-static int decode_label (char *copy, char ***canonical,
-                        struct symtabs_and_lines *result);
+/* Add SAL to SALS.  */
+
+static void
+add_sal_to_sals_basic (struct symtabs_and_lines *sals,
+                      struct symtab_and_line *sal)
+{
+  ++sals->nelts;
+  sals->sals = xrealloc (sals->sals, sals->nelts * sizeof (sals->sals[0]));
+  sals->sals[sals->nelts - 1] = *sal;
+}
 
-static struct symtabs_and_lines decode_variable (char *copy,
-                                                int funfirstline,
-                                                char ***canonical,
-                                                struct symtab *file_symtab,
-                                                int *not_found_ptr);
+/* Add SAL to SALS, and also update SELF->CANONICAL_NAMES to reflect
+   the new sal, if needed.  If not NULL, SYMNAME is the name of the
+   symbol to use when constructing the new canonical name.  */
 
-static struct
-symtabs_and_lines symbol_found (int funfirstline,
-                               char ***canonical,
-                               char *copy,
-                               struct symbol *sym,
-                               struct symtab *file_symtab);
+static void
+add_sal_to_sals (struct linespec_state *self,
+                struct symtabs_and_lines *sals,
+                struct symtab_and_line *sal,
+                const char *symname)
+{
+  add_sal_to_sals_basic (sals, sal);
 
-static struct
-symtabs_and_lines minsym_found (int funfirstline,
-                               struct minimal_symbol *msymbol);
+  if (self->canonical)
+    {
+      char *canonical_name = NULL;
 
-/* Helper functions.  */
+      self->canonical_names = xrealloc (self->canonical_names,
+                                       sals->nelts * sizeof (char *));
+      if (sal->symtab && sal->symtab->filename)
+       {
+         char *filename = sal->symtab->filename;
+
+         /* 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
+             && current_language->la_language == language_ada)
+           canonical_name = xstrprintf ("%s:%s:%d", filename, symname,
+                                        sal->line);
+         else if (symname != NULL)
+           canonical_name = xstrprintf ("%s:%s", filename, symname);
+         else
+           canonical_name = xstrprintf ("%s:%d", filename, sal->line);
+       }
+
+      self->canonical_names[sals->nelts - 1] = canonical_name;
+    }
+}
+
+/* A hash function for address_entry.  */
+
+static hashval_t
+hash_address_entry (const void *p)
+{
+  const struct address_entry *aep = p;
+
+  return iterative_hash_object (*aep, 0);
+}
+
+/* An equality function for address_entry.  */
+
+static int
+eq_address_entry (const void *a, const void *b)
+{
+  const struct address_entry *aea = a;
+  const struct address_entry *aeb = b;
+
+  return aea->pspace == aeb->pspace && aea->addr == aeb->addr;
+}
+
+/* Check whether the address, represented by PSPACE and ADDR, is
+   already in the set.  If so, return 0.  Otherwise, add it and return
+   1.  */
+
+static int
+maybe_add_address (htab_t set, struct program_space *pspace, CORE_ADDR addr)
+{
+  struct address_entry e, *p;
+  void **slot;
+
+  e.pspace = pspace;
+  e.addr = addr;
+  slot = htab_find_slot (set, &e, INSERT);
+  if (*slot)
+    return 0;
+
+  p = XNEW (struct address_entry);
+  memcpy (p, &e, sizeof (struct address_entry));
+  *slot = p;
+
+  return 1;
+}
 
 /* Issue a helpful hint on using the command completion feature on
    single quoted demangled C++ symbols as part of the completion
@@ -177,49 +324,110 @@ cplusplus_error (const char *name, const char *fmt, ...)
   throw_error (NOT_FOUND_ERROR, "%s", message);
 }
 
-/* Return the number of methods described for TYPE, including the
-   methods from types it derives from.  This can't be done in the symbol
-   reader because the type of the baseclass might still be stubbed
-   when the definition of the derived class is parsed.  */
+/* A helper for iterate_over_all_matching_symtabs that is passed as a
+   callback to the expand_symtabs_matching method.  */
 
 static int
-total_number_of_methods (struct type *type)
+iterate_name_matcher (const struct language_defn *language,
+                     const char *name, void *d)
 {
-  int n;
-  int count;
+  const char **dname = d;
 
-  CHECK_TYPEDEF (type);
-  if (! HAVE_CPLUS_STRUCT (type))
-    return 0;
-  count = TYPE_NFN_FIELDS_TOTAL (type);
+  if (language->la_symbol_name_compare (name, *dname) == 0)
+    return 1;
+  return 0;
+}
+
+/* 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.  */
+
+static void
+iterate_over_all_matching_symtabs (const char *name,
+                                  const domain_enum domain,
+                                  int (*callback) (struct symbol *, void *),
+                                  void *data,
+                                  struct program_space *search_pspace)
+{
+  struct objfile *objfile;
+  struct program_space *pspace;
 
-  for (n = 0; n < TYPE_N_BASECLASSES (type); n++)
-    count += total_number_of_methods (TYPE_BASECLASS (type, n));
+  ALL_PSPACES (pspace)
+  {
+    if (search_pspace != NULL && search_pspace != pspace)
+      continue;
+    if (pspace->executing_startup)
+      continue;
+
+    set_current_program_space (pspace);
+
+    ALL_OBJFILES (objfile)
+    {
+      struct symtab *symtab;
+
+      if (objfile->sf)
+       objfile->sf->qf->expand_symtabs_matching (objfile, NULL,
+                                                 iterate_name_matcher,
+                                                 ALL_DOMAIN,
+                                                 &name);
+
+      ALL_OBJFILE_SYMTABS (objfile, symtab)
+       {
+         if (symtab->primary)
+           {
+             struct block *block;
 
-  return count;
+             block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK);
+             LA_ITERATE_OVER_SYMBOLS (block, name, domain, callback, data);
+           }
+       }
+    }
+  }
 }
 
-/* Recursive helper function for decode_line_1.
-   Look for methods named NAME in type T.
-   Return number of matches.
-   Put matches in SYM_ARR, which should have been allocated with
-   a size of total_number_of_methods (T) * sizeof (struct symbol *).
-   Note that this function is g++ specific.  */
+/* Returns the block to be used for symbol searches for the given SYMTAB,
+   which may be NULL.  */
 
-static int
-find_methods (struct type *t, char *name, enum language language,
-             struct symbol **sym_arr)
+static struct block *
+get_search_block (struct symtab *symtab)
+{
+  struct block *block;
+
+  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);
+    }
+
+  return block;
+}
+
+/* A helper for find_method.  This finds all methods in type T which
+   match NAME.  It adds resulting symbol names to RESULT_NAMES, and
+   adds T's direct superclasses to SUPERCLASSES.  */
+
+static void
+find_methods (struct type *t, const char *name,
+             VEC (const_char_ptr) **result_names,
+             VEC (typep) **superclasses)
 {
   int i1 = 0;
   int ibase;
   char *class_name = type_name_no_tag (t);
+  char *canon;
 
   /* 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
      the class, then the loop can't do any good.  */
-  if (class_name
-      && (lookup_symbol_in_language (class_name, (struct block *) NULL,
-                        STRUCT_DOMAIN, language, (int *) NULL)))
+  if (class_name)
     {
       int method_counter;
       int name_len = strlen (name);
@@ -247,179 +455,32 @@ find_methods (struct type *t, char *name, enum language language,
                method_name = dem_opname;
            }
 
-         if (strcmp_iw (name, method_name) == 0)
-           /* Find all the overloaded methods with that name.  */
-           i1 += add_matching_methods (method_counter, t, language,
-                                       sym_arr + i1);
-         else if (strncmp (class_name, name, name_len) == 0
-                  && (class_name[name_len] == '\0'
-                      || class_name[name_len] == '<'))
-           i1 += add_constructors (method_counter, t, language,
-                                   sym_arr + i1);
-       }
-    }
-
-  /* Only search baseclasses if there is no match yet, since names in
-     derived classes override those in baseclasses.
-
-     FIXME: The above is not true; it is only true of member functions
-     if they have the same number of arguments (??? - section 13.1 of the
-     ARM says the function members are not in the same scope but doesn't
-     really spell out the rules in a way I understand.  In any case, if
-     the number of arguments differ this is a case in which we can overload
-     rather than hiding without any problem, and gcc 2.4.5 does overload
-     rather than hiding in this case).  */
-
-  if (i1 == 0)
-    for (ibase = 0; ibase < TYPE_N_BASECLASSES (t); ibase++)
-      i1 += find_methods (TYPE_BASECLASS (t, ibase), name,
-                         language, sym_arr + i1);
-
-  return i1;
-}
-
-/* Add the symbols associated to methods of the class whose type is T
-   and whose name matches the method indexed by METHOD_COUNTER in the
-   array SYM_ARR.  Return the number of methods added.  */
-
-static int
-add_matching_methods (int method_counter, struct type *t,
-                     enum language language, struct symbol **sym_arr)
-{
-  int field_counter;
-  int i1 = 0;
-
-  for (field_counter = TYPE_FN_FIELDLIST_LENGTH (t, method_counter) - 1;
-       field_counter >= 0;
-       --field_counter)
-    {
-      struct fn_field *f;
-      char *phys_name;
-
-      f = TYPE_FN_FIELDLIST1 (t, method_counter);
+         if (strcmp_iw (method_name, name) == 0)
+           {
+             int field_counter;
 
-      if (TYPE_FN_FIELD_STUB (f, field_counter))
-       {
-         char *tmp_name;
-
-         tmp_name = gdb_mangle_name (t,
-                                     method_counter,
-                                     field_counter);
-         phys_name = alloca (strlen (tmp_name) + 1);
-         strcpy (phys_name, tmp_name);
-         xfree (tmp_name);
-       }
-      else
-       phys_name = TYPE_FN_FIELD_PHYSNAME (f, field_counter);
-
-      sym_arr[i1] = lookup_symbol_in_language (phys_name,
-                                  NULL, VAR_DOMAIN,
-                                  language,
-                                  (int *) NULL);
-      if (sym_arr[i1])
-       i1++;
-      else
-       {
-         /* This error message gets printed, but the method
-            still seems to be found.
-            fputs_filtered("(Cannot find method ", gdb_stdout);
-            fprintf_symbol_filtered (gdb_stdout, phys_name,
-                                     language_cplus,
-                                     DMGL_PARAMS | DMGL_ANSI);
-            fputs_filtered(" - possibly inlined.)\n", gdb_stdout);
-         */
+             for (field_counter = (TYPE_FN_FIELDLIST_LENGTH (t, method_counter)
+                                   - 1);
+                  field_counter >= 0;
+                  --field_counter)
+               {
+                 struct fn_field *f;
+                 const char *phys_name;
+
+                 f = TYPE_FN_FIELDLIST1 (t, method_counter);
+                 if (TYPE_FN_FIELD_STUB (f, field_counter))
+                   continue;
+                 phys_name = TYPE_FN_FIELD_PHYSNAME (f, field_counter);
+                 VEC_safe_push (const_char_ptr, *result_names, phys_name);
+               }
+           }
        }
     }
 
-  return i1;
-}
-
-/* Add the symbols associated to constructors of the class whose type
-   is CLASS_TYPE and which are indexed by by METHOD_COUNTER to the
-   array SYM_ARR.  Return the number of methods added.  */
-
-static int
-add_constructors (int method_counter, struct type *t,
-                 enum language language, struct symbol **sym_arr)
-{
-  int field_counter;
-  int i1 = 0;
-
-  /* For GCC 3.x and stabs, constructors and destructors
-     have names like __base_ctor and __complete_dtor.
-     Check the physname for now if we're looking for a
-     constructor.  */
-  for (field_counter
-        = TYPE_FN_FIELDLIST_LENGTH (t, method_counter) - 1;
-       field_counter >= 0;
-       --field_counter)
-    {
-      struct fn_field *f;
-      char *phys_name;
-
-      f = TYPE_FN_FIELDLIST1 (t, method_counter);
-
-      /* GCC 3.x will never produce stabs stub methods, so
-        we don't need to handle this case.  */
-      if (TYPE_FN_FIELD_STUB (f, field_counter))
-       continue;
-      phys_name = TYPE_FN_FIELD_PHYSNAME (f, field_counter);
-      if (! is_constructor_name (phys_name))
-       continue;
-
-      /* If this method is actually defined, include it in the
-        list.  */
-      sym_arr[i1] = lookup_symbol_in_language (phys_name,
-                                  NULL, VAR_DOMAIN,
-                                  language,
-                                  (int *) NULL);
-      if (sym_arr[i1])
-       i1++;
-    }
-
-  return i1;
-}
-
-/* Helper function for decode_line_1.
-   Build a canonical line spec in CANONICAL if it is non-NULL and if
-   the SAL has a symtab.
-   If SYMNAME is non-NULL the canonical line spec is `filename:symname'.
-   If SYMNAME is NULL the line number from SAL is used and the canonical
-   line spec is `filename:linenum'.  */
-
-static void
-build_canonical_line_spec (struct symtab_and_line *sal, char *symname,
-                          char ***canonical)
-{
-  char **canonical_arr;
-  char *canonical_name;
-  char *filename;
-  struct symtab *s = sal->symtab;
-
-  if (s == (struct symtab *) NULL
-      || s->filename == (char *) NULL
-      || canonical == (char ***) NULL)
-    return;
-
-  canonical_arr = (char **) xmalloc (sizeof (char *));
-  *canonical = canonical_arr;
-
-  filename = s->filename;
-  if (symname != NULL)
-    {
-      canonical_name = xmalloc (strlen (filename) + strlen (symname) + 2);
-      sprintf (canonical_name, "%s:%s", filename, symname);
-    }
-  else
-    {
-      canonical_name = xmalloc (strlen (filename) + 30);
-      sprintf (canonical_name, "%s:%d", filename, sal->line);
-    }
-  canonical_arr[0] = canonical_name;
+  for (ibase = 0; ibase < TYPE_N_BASECLASSES (t); ibase++)
+    VEC_safe_push (typep, *superclasses, TYPE_BASECLASS (t, ibase));
 }
 
-
-
 /* Find an instance of the character C in the string S that is outside
    of all parenthesis pairs, single-quoted strings, and double-quoted
    strings.  Also, ignore the char within a template name, like a ','
@@ -475,147 +536,154 @@ is_objc_method_format (const char *s)
   return 0;
 }
 
-/* Given a list of NELTS symbols in SYM_ARR, return a list of lines to
-   operate on (ask user if necessary).
-   If CANONICAL is non-NULL return a corresponding array of mangled names
-   as canonical line specs there.  */
+/* Given FILTERS, a list of canonical names, filter the sals in RESULT
+   and store the result in SELF->CANONICAL.  */
 
-static struct symtabs_and_lines
-decode_line_2 (struct symbol *sym_arr[], int nelts, int funfirstline,
-              char ***canonical)
+static void
+filter_results (struct linespec_state *self,
+               struct symtabs_and_lines *result,
+               VEC (const_char_ptr) *filters)
+{
+  int i;
+  const char *name;
+
+  for (i = 0; VEC_iterate (const_char_ptr, filters, i, name); ++i)
+    {
+      struct linespec_sals lsal;
+      int j;
+
+      memset (&lsal, 0, sizeof (lsal));
+
+      for (j = 0; j < result->nelts; ++j)
+       {
+         if (strcmp (name, self->canonical_names[j]) == 0)
+           add_sal_to_sals_basic (&lsal.sals, &result->sals[j]);
+       }
+
+      if (lsal.sals.nelts > 0)
+       {
+         lsal.canonical = xstrdup (name);
+         VEC_safe_push (linespec_sals, self->canonical->sals, &lsal);
+       }
+    }
+
+  self->canonical->pre_expanded = 0;
+}
+
+/* Store RESULT into SELF->CANONICAL.  */
+
+static void
+convert_results_to_lsals (struct linespec_state *self,
+                         struct symtabs_and_lines *result)
+{
+  struct linespec_sals lsal;
+
+  lsal.canonical = NULL;
+  lsal.sals = *result;
+  VEC_safe_push (linespec_sals, self->canonical->sals, &lsal);
+}
+
+/* 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
+   in SELF->CANONICAL is set up properly.  */
+
+static void
+decode_line_2 (struct linespec_state *self,
+              struct symtabs_and_lines *result,
+              const char *select_mode)
 {
-  struct symtabs_and_lines values, return_values;
-  char *args, *arg1;
+  const char *iter;
+  char *args, *prompt;
   int i;
-  char *prompt;
-  char *symname;
   struct cleanup *old_chain;
-  char **canonical_arr = (char **) NULL;
-  const char *select_mode = multiple_symbols_select_mode ();
+  VEC (const_char_ptr) *item_names = NULL, *filters = NULL;
+  struct get_number_or_range_state state;
 
-  if (select_mode == multiple_symbols_cancel)
-    error (_("canceled because the command is ambiguous\n"
-            "See set/show multiple-symbol."));
-  
-  values.sals = (struct symtab_and_line *)
-    alloca (nelts * sizeof (struct symtab_and_line));
-  return_values.sals = (struct symtab_and_line *)
-    xmalloc (nelts * sizeof (struct symtab_and_line));
-  old_chain = make_cleanup (xfree, return_values.sals);
+  gdb_assert (select_mode != multiple_symbols_all);
+  gdb_assert (self->canonical != NULL);
 
-  if (canonical)
+  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)
     {
-      canonical_arr = (char **) xmalloc (nelts * sizeof (char *));
-      make_cleanup (xfree, canonical_arr);
-      memset (canonical_arr, 0, nelts * sizeof (char *));
-      *canonical = canonical_arr;
+      int j, found = 0;
+      const char *iter;
+
+      gdb_assert (self->canonical_names[i] != NULL);
+      for (j = 0; VEC_iterate (const_char_ptr, item_names, j, iter); ++j)
+       {
+         if (strcmp (iter, self->canonical_names[i]) == 0)
+           {
+             found = 1;
+             break;
+           }
+       }
+
+      if (!found)
+       VEC_safe_push (const_char_ptr, item_names, self->canonical_names[i]);
     }
 
-  i = 0;
-  while (i < nelts)
+  if (select_mode == multiple_symbols_cancel
+      && VEC_length (const_char_ptr, item_names) > 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)
     {
-      init_sal (&return_values.sals[i]);       /* Initialize to zeroes.  */
-      init_sal (&values.sals[i]);
-      if (sym_arr[i] && SYMBOL_CLASS (sym_arr[i]) == LOC_BLOCK)
-       values.sals[i] = find_function_start_sal (sym_arr[i], funfirstline);
-      i++;
+      do_cleanups (old_chain);
+      convert_results_to_lsals (self, result);
+      return;
     }
 
-  /* If select_mode is "all", then do not print the multiple-choice
-     menu and act as if the user had chosen choice "1" (all).  */
-  if (select_mode == multiple_symbols_all
-      || ui_out_is_mi_like_p (interp_ui_out (top_level_interpreter ())))
-    args = "1";
-  else
+  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);
+
+  prompt = getenv ("PS2");
+  if (prompt == NULL)
     {
-      i = 0;
-      printf_unfiltered (_("[0] cancel\n[1] all\n"));
-      while (i < nelts)
-        {
-          if (sym_arr[i] && SYMBOL_CLASS (sym_arr[i]) == LOC_BLOCK)
-            {
-              if (values.sals[i].symtab)
-                printf_unfiltered ("[%d] %s at %s:%d\n",
-                                   (i + 2),
-                                   SYMBOL_PRINT_NAME (sym_arr[i]),
-                                   values.sals[i].symtab->filename,
-                                   values.sals[i].line);
-              else
-                printf_unfiltered (_("[%d] %s at ?FILE:%d [No symtab? "
-                                    "Probably broken debug info...]\n"),
-                                   (i + 2),
-                                   SYMBOL_PRINT_NAME (sym_arr[i]),
-                                   values.sals[i].line);
-
-            }
-          else
-            printf_unfiltered (_("?HERE\n"));
-          i++;
-        }
-
-      prompt = getenv ("PS2");
-      if (prompt == NULL)
-        {
-          prompt = "> ";
-        }
-      args = command_line_input (prompt, 0, "overload-choice");
+      prompt = "> ";
     }
+  args = command_line_input (prompt, 0, "overload-choice");
 
   if (args == 0 || *args == 0)
     error_no_arg (_("one or more choice numbers"));
 
-  i = 0;
-  while (*args)
+  init_number_or_range (&state, args);
+  while (!state.finished)
     {
       int num;
 
-      arg1 = args;
-      while (*arg1 >= '0' && *arg1 <= '9')
-       arg1++;
-      if (*arg1 && *arg1 != ' ' && *arg1 != '\t')
-       error (_("Arguments must be choice numbers."));
-
-      num = atoi (args);
+      num = get_number_or_range (&state);
 
       if (num == 0)
        error (_("canceled"));
       else if (num == 1)
        {
-         if (canonical_arr)
-           {
-             for (i = 0; i < nelts; i++)
-               {
-                 if (canonical_arr[i] == NULL)
-                   {
-                     symname = SYMBOL_LINKAGE_NAME (sym_arr[i]);
-                     canonical_arr[i] = xstrdup (symname);
-                   }
-               }
-           }
-         memcpy (return_values.sals, values.sals,
-                 (nelts * sizeof (struct symtab_and_line)));
-         return_values.nelts = nelts;
-         discard_cleanups (old_chain);
-         return return_values;
+         /* We intentionally make this result in a single breakpoint,
+            contrary to what older versions of gdb did.  The
+            rationale is that this lets a user get the
+            multiple_symbols_all behavior even with the 'ask'
+            setting; and he can get separate breakpoints by entering
+            "2-57" at the query.  */
+         do_cleanups (old_chain);
+         convert_results_to_lsals (self, result);
+         return;
        }
 
-      if (num >= nelts + 2)
-       {
-         printf_unfiltered (_("No choice number %d.\n"), num);
-       }
+      num -= 2;
+      if (num >= VEC_length (const_char_ptr, item_names))
+       printf_unfiltered (_("No choice number %d.\n"), num);
       else
        {
-         num -= 2;
-         if (values.sals[num].pc)
+         const char *elt = VEC_index (const_char_ptr, item_names, num);
+
+         if (elt != NULL)
            {
-             if (canonical_arr)
-               {
-                 symname = SYMBOL_LINKAGE_NAME (sym_arr[num]);
-                 make_cleanup (xfree, symname);
-                 canonical_arr[i] = xstrdup (symname);
-               }
-             return_values.sals[i++] = values.sals[num];
-             values.sals[num].pc = 0;
+             VEC_safe_push (const_char_ptr, filters, elt);
+             VEC_replace (const_char_ptr, item_names, num, NULL);
            }
          else
            {
@@ -623,14 +691,18 @@ decode_line_2 (struct symbol *sym_arr[], int nelts, int funfirstline,
                                 num);
            }
        }
-
-      args = arg1;
-      while (*args == ' ' || *args == '\t')
-       args++;
     }
-  return_values.nelts = i;
-  discard_cleanups (old_chain);
-  return return_values;
+
+  filter_results (self, result, filters);
+  do_cleanups (old_chain);
+}
+
+/* Valid delimiters for linespec keywords "if", "thread" or "task".  */
+
+static int
+is_linespec_boundary (char c)
+{
+  return c == ' ' || c == '\t' || c == '\0' || c == ',';
 }
 
 /* A helper function for decode_line_1 and friends which skips P
@@ -663,6 +735,58 @@ find_method_overload_end (char *p)
 
   return p;
 }
+
+/* Keep important information used when looking up a name.  This includes
+   template parameters, overload information, and important keywords, including
+   the possible Java trailing type.  */
+
+static char *
+keep_name_info (char *p, int on_boundary)
+{
+  const char *quotes = get_gdb_completer_quote_characters ();
+  char *saved_p = p;
+  int nest = 0;
+
+  while (*p)
+    {
+      if (strchr (quotes, *p))
+       break;
+
+      if (*p == ',' && !nest)
+       break;
+
+      if (on_boundary && !nest)
+       {
+         const char *const words[] = { "if", "thread", "task" };
+         int wordi;
+
+         for (wordi = 0; wordi < ARRAY_SIZE (words); wordi++)
+           if (strncmp (p, words[wordi], strlen (words[wordi])) == 0
+               && is_linespec_boundary (p[strlen (words[wordi])]))
+             break;
+         if (wordi < ARRAY_SIZE (words))
+           break;
+       }
+
+      if (*p == '(' || *p == '<' || *p == '[')
+       nest++;
+      else if ((*p == ')' || *p == '>' || *p == ']') && nest > 0)
+       nest--;
+
+      p++;
+
+      /* The ',' check could fail on "operator ,".  */
+      p += cp_validate_operator (p);
+
+      on_boundary = is_linespec_boundary (p[-1]);
+    }
+
+  while (p > saved_p && is_linespec_boundary (p[-1]))
+    p--;
+
+  return p;
+}
+
 \f
 /* The parser of linespec itself.  */
 
@@ -702,12 +826,7 @@ find_method_overload_end (char *p)
 
    Note that it is possible to return zero for the symtab
    if no file is validly specified.  Callers must check that.
-   Also, the line number returned may be invalid.  
-   If NOT_FOUND_PTR is not null, store a boolean true/false value at
-   the location, based on whether or not failure occurs due to an
-   unknown function or file.  In the case where failure does occur due
-   to an unknown function or file, do not issue an error message.  */
+   Also, the line number returned may be invalid.  */
 
 /* We allow single quotes in various places.  This is a hideous
    kludge, which exists because the completer can't yet deal with the
@@ -715,44 +834,56 @@ find_method_overload_end (char *p)
    can use as appropriate instead of make_symbol_completion_list.  */
 
 struct symtabs_and_lines
-decode_line_1 (char **argptr, int funfirstline, struct symtab *default_symtab,
-              int default_line, char ***canonical, int *not_found_ptr)
+decode_line_internal (struct linespec_state *self, char **argptr)
 {
   char *p;
   char *q;
-  /* If a file name is specified, this is its symtab.  */
-  struct symtab *file_symtab = NULL;
 
   char *copy;
   /* This says whether or not something in *ARGPTR is quoted with
      completer_quotes (i.e. with single quotes).  */
   int is_quoted;
-  /* Is *ARGPTR is enclosed in double quotes?  */
+  /* Is *ARGPTR enclosed in double quotes?  */
   int is_quote_enclosed;
   int is_objc_method = 0;
   char *saved_arg = *argptr;
   /* If IS_QUOTED, the end of the quoted bit.  */
   char *end_quote = NULL;
+  /* Is *ARGPTR enclosed in single quotes?  */
+  int is_squote_enclosed = 0;
   /* The "first half" of the linespec.  */
   char *first_half;
 
-  if (not_found_ptr)
-    *not_found_ptr = 0;
+  /* If we are parsing `function:label', this holds the symbols
+     matching the function name.  */
+  VEC (symbolp) *function_symbols = NULL;
+  /* If FUNCTION_SYMBOLS is not NULL, then this is the exception that
+     was thrown when trying to parse a filename.  */
+  volatile struct gdb_exception file_exception;
+
+  struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
 
   /* Defaults have defaults.  */
 
-  initialize_defaults (&default_symtab, &default_line);
+  initialize_defaults (&self->default_symtab, &self->default_line);
   
   /* See if arg is *PC.  */
 
   if (**argptr == '*')
-    return decode_indirect (argptr);
+    {
+      do_cleanups (cleanup);
+      return decode_indirect (self, argptr);
+    }
 
   is_quoted = (strchr (get_gdb_completer_quote_characters (),
                       **argptr) != NULL);
 
   if (is_quoted)
-    end_quote = skip_quoted (*argptr);
+    {
+      end_quote = skip_quoted (*argptr);
+      if (*end_quote == '\0')
+       is_squote_enclosed = 1;
+    }
 
   /* Check to see if it's a multipart linespec (with colons or
      periods).  */
@@ -765,6 +896,33 @@ decode_line_1 (char **argptr, int funfirstline, struct symtab *default_symtab,
 
   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)
+    {
+      self->file_symtabs = symtabs_from_filename (argptr, p, is_quote_enclosed,
+                                                 &self->user_filename);
+    }
+
+  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);
+    }
+
+  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))
@@ -775,10 +933,12 @@ decode_line_1 (char **argptr, int funfirstline, struct symtab *default_symtab,
   {
     struct symtabs_and_lines values;
 
-    values = decode_objc (argptr, funfirstline, NULL,
-                         canonical, saved_arg);
+    values = decode_objc (self, argptr);
     if (values.sals != NULL)
-      return values;
+      {
+       do_cleanups (cleanup);
+       return values;
+      }
   }
 
   /* Does it look like there actually were two parts?  */
@@ -795,34 +955,67 @@ decode_line_1 (char **argptr, int funfirstline, struct symtab *default_symtab,
       if (p[0] == '.' || p[1] == ':')
        {
          struct symtabs_and_lines values;
+         volatile struct gdb_exception ex;
+         char *saved_argptr = *argptr;
 
          if (is_quote_enclosed)
            ++saved_arg;
-         values = decode_compound (argptr, funfirstline, canonical,
-                                   saved_arg, p, not_found_ptr);
-         if (is_quoted && **argptr == '\'')
+
+         /* 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;
-         return values;
-       }
 
-      /* No, the first part is a filename; set file_symtab to be that file's
-        symtab.  Also, move argptr past the filename.  */
+         if (ex.reason >= 0)
+           {
+             do_cleanups (cleanup);
+             return values;
+           }
 
-      file_symtab = symtab_from_filename (argptr, p, is_quote_enclosed,
-                                         not_found_ptr);
+         if (ex.error != NOT_FOUND_ERROR)
+           throw_exception (ex);
 
-      /* Check for single quotes on the non-filename part.  */
-      if (!is_quoted)
+         *argptr = saved_argptr;
+       }
+      else
        {
-         is_quoted = (**argptr
-                      && strchr (get_gdb_completer_quote_characters (),
-                                 **argptr) != NULL);
-         if (is_quoted)
-           end_quote = skip_quoted (*argptr);
+         /* If there was an exception looking up a specified filename earlier,
+            then check whether we were really given `function:label'.   */
+         if (file_exception.reason < 0)
+           {
+             function_symbols = find_function_symbols (argptr, p,
+                                                       is_quote_enclosed,
+                                                       &self->user_function);
+
+             /* If we did not find a function, re-throw the original
+                exception.  */
+             if (!function_symbols)
+               throw_exception (file_exception);
+
+             make_cleanup (VEC_cleanup (symbolp), &function_symbols);
+           }
+
+         /* Check for single quotes on the non-filename part.  */
+         if (!is_quoted)
+           {
+             is_quoted = (**argptr
+                          && strchr (get_gdb_completer_quote_characters (),
+                                     **argptr) != NULL);
+             if (is_quoted)
+               end_quote = skip_quoted (*argptr);
+           }
        }
     }
 
-  /* file_symtab is specified file's symtab, or 0 if no file specified.
+  /* self->file_symtabs holds the  specified file symtabs, or 0 if no file
+     specified.
+     If we are parsing `function:symbol', then FUNCTION_SYMBOLS holds the
+     functions before the `:'.
      arg no longer contains the file name.  */
 
   /* If the filename was quoted, we must re-check the quotation.  */
@@ -844,10 +1037,16 @@ decode_line_1 (char **argptr, int funfirstline, struct symtab *default_symtab,
   while (*q >= '0' && *q <= '9')
     q++;
 
-  if (q != *argptr && (*q == 0 || *q == ' ' || *q == '\t' || *q == ','))
-    /* We found a token consisting of all digits -- at least one digit.  */
-    return decode_all_digits (argptr, default_symtab, default_line,
-                             canonical, file_symtab, q);
+  if (q != *argptr && (*q == 0 || *q == ' ' || *q == '\t' || *q == ',')
+      && function_symbols == NULL)
+    {
+      struct symtabs_and_lines values;
+
+      /* We found a token consisting of all digits -- at least one digit.  */
+      values = decode_all_digits (self, argptr, q);
+      do_cleanups (cleanup);
+      return values;
+    }
 
   /* Arg token is not digits => try it as a variable name
      Find the next token (everything up to end or next whitespace).  */
@@ -855,7 +1054,7 @@ decode_line_1 (char **argptr, int funfirstline, struct symtab *default_symtab,
   if (**argptr == '$')         /* May be a convenience variable.  */
     /* One or two $ chars possible.  */
     p = skip_quoted (*argptr + (((*argptr)[1] == '$') ? 2 : 1));
-  else if (is_quoted)
+  else if (is_quoted || is_squote_enclosed)
     {
       p = end_quote;
       if (p[-1] != '\'')
@@ -871,17 +1070,8 @@ decode_line_1 (char **argptr, int funfirstline, struct symtab *default_symtab,
       p = skip_quoted (*argptr);
     }
 
-  /* Keep any template parameters.  */
-  if (*p == '<')
-    p = find_template_name_end (p);
-
-  /* Keep method overload information.  */
-  if (*p == '(')
-    p = find_method_overload_end (p);
-
-  /* Make sure we keep important kewords like "const".  */
-  if (strncmp (p, " const", 6) == 0)
-    p += 6;
+  /* Keep any important naming information.  */
+  p = keep_name_info (p, p == saved_arg || is_linespec_boundary (p[-1]));
 
   copy = (char *) alloca (p - *argptr + 1);
   memcpy (copy, *argptr, p - *argptr);
@@ -894,61 +1084,183 @@ decode_line_1 (char **argptr, int funfirstline, struct symtab *default_symtab,
       copy[p - *argptr - 1] = '\0';
       copy++;
     }
-  else if (is_quoted)
+  else if (is_quoted || is_squote_enclosed)
     copy[p - *argptr - 1] = '\0';
-  while (*p == ' ' || *p == '\t')
-    p++;
-  *argptr = p;
+  
+  *argptr = skip_spaces (p);
 
   /* If it starts with $: may be a legitimate variable or routine name
      (e.g. HP-UX millicode routines such as $$dyncall), or it may
      be history value, or it may be a convenience variable.  */
 
-  if (*copy == '$')
-    return decode_dollar (copy, funfirstline, default_symtab,
-                         canonical, file_symtab);
+  if (*copy == '$' && function_symbols == NULL)
+    {
+      struct symtabs_and_lines values;
+
+      values = decode_dollar (self, copy);
+      do_cleanups (cleanup);
+      return values;
+    }
 
   /* Try the token as a label, but only if no file was specified,
      because we can only really find labels in the current scope.  */
 
-  if (!file_symtab)
+  if (VEC_length (symtab_p, self->file_symtabs) == 1
+      && VEC_index (symtab_p, self->file_symtabs, 0) == NULL)
     {
       struct symtabs_and_lines label_result;
-      if (decode_label (copy, canonical, &label_result))
-       return label_result;
+      if (decode_label (self, function_symbols, copy, &label_result))
+       {
+         do_cleanups (cleanup);
+         return label_result;
+       }
     }
 
+  if (function_symbols)
+    throw_exception (file_exception);
+
   /* Look up that token as a variable.
      If file specified, use that file's per-file block to start with.  */
 
-  return decode_variable (copy, funfirstline, canonical,
-                         file_symtab, not_found_ptr);
+  {
+    struct symtabs_and_lines values;
+
+    values = decode_variable (self, copy);
+    do_cleanups (cleanup);
+    return values;
+  }
 }
 
-\f
+/* A constructor for linespec_state.  */
+
+static void
+linespec_state_constructor (struct linespec_state *self,
+                           int flags,
+                           struct symtab *default_symtab,
+                           int default_line,
+                           struct linespec_result *canonical)
+{
+  memset (self, 0, sizeof (*self));
+  self->funfirstline = (flags & DECODE_LINE_FUNFIRSTLINE) ? 1 : 0;
+  self->list_mode = (flags & DECODE_LINE_LIST_MODE) ? 1 : 0;
+  self->default_symtab = default_symtab;
+  self->default_line = default_line;
+  self->canonical = canonical;
+  self->program_space = current_program_space;
+  self->addr_set = htab_create_alloc (10, hash_address_entry, eq_address_entry,
+                                     xfree, xcalloc, xfree);
+}
+
+/* A destructor for linespec_state.  */
+
+static void
+linespec_state_destructor (void *arg)
+{
+  struct linespec_state *self = arg;
+
+  xfree (self->user_filename);
+  xfree (self->user_function);
+  VEC_free (symtab_p, self->file_symtabs);
+  htab_delete (self->addr_set);
+}
+
+/* See linespec.h.  */
+
+void
+decode_line_full (char **argptr, int flags,
+                 struct symtab *default_symtab,
+                 int default_line, struct linespec_result *canonical,
+                 const char *select_mode,
+                 const char *filter)
+{
+  struct symtabs_and_lines result;
+  struct linespec_state state;
+  struct cleanup *cleanups;
+  char *arg_start = *argptr;
+  VEC (const_char_ptr) *filters = NULL;
+
+  gdb_assert (canonical != NULL);
+  /* The filter only makes sense for 'all'.  */
+  gdb_assert (filter == NULL || select_mode == multiple_symbols_all);
+  gdb_assert (select_mode == NULL
+             || select_mode == multiple_symbols_all
+             || select_mode == multiple_symbols_ask
+             || select_mode == multiple_symbols_cancel);
+  gdb_assert ((flags & DECODE_LINE_LIST_MODE) == 0);
+
+  linespec_state_constructor (&state, flags,
+                             default_symtab, default_line, canonical);
+  cleanups = make_cleanup (linespec_state_destructor, &state);
+  save_current_program_space ();
+
+  result = decode_line_internal (&state, argptr);
+
+  gdb_assert (result.nelts == 1 || canonical->pre_expanded);
+  gdb_assert (canonical->addr_string != NULL);
+  canonical->pre_expanded = 1;
+
+  /* Fill in the missing canonical names.  */
+  if (result.nelts > 0)
+    {
+      int i;
+
+      if (state.canonical_names == NULL)
+       state.canonical_names = xcalloc (result.nelts, sizeof (char *));
+      make_cleanup (xfree, state.canonical_names);
+      for (i = 0; i < result.nelts; ++i)
+       {
+         if (state.canonical_names[i] == NULL)
+           state.canonical_names[i] = savestring (arg_start,
+                                                  *argptr - arg_start);
+         make_cleanup (xfree, state.canonical_names[i]);
+       }
+    }
+
+  if (select_mode == NULL)
+    {
+      if (ui_out_is_mi_like_p (interp_ui_out (top_level_interpreter ())))
+       select_mode = multiple_symbols_all;
+      else
+       select_mode = multiple_symbols_select_mode ();
+    }
+
+  if (select_mode == multiple_symbols_all)
+    {
+      if (filter != NULL)
+       {
+         make_cleanup (VEC_cleanup (const_char_ptr), &filters);
+         VEC_safe_push (const_char_ptr, filters, filter);
+         filter_results (&state, &result, filters);
+       }
+      else
+       convert_results_to_lsals (&state, &result);
+    }
+  else
+    decode_line_2 (&state, &result, select_mode);
+
+  do_cleanups (cleanups);
+}
+
+struct symtabs_and_lines
+decode_line_1 (char **argptr, int flags,
+              struct symtab *default_symtab,
+              int default_line)
+{
+  struct symtabs_and_lines result;
+  struct linespec_state state;
+  struct cleanup *cleanups;
+
+  linespec_state_constructor (&state, flags,
+                             default_symtab, default_line, NULL);
+  cleanups = make_cleanup (linespec_state_destructor, &state);
+  save_current_program_space ();
+
+  result = decode_line_internal (&state, argptr);
+  do_cleanups (cleanups);
+  return result;
+}
 
-/* Now, more helper functions for decode_line_1.  Some conventions
-   that these functions follow:
-
-   Decode_line_1 typically passes along some of its arguments or local
-   variables to the subfunctions.  It passes the variables by
-   reference if they are modified by the subfunction, and by value
-   otherwise.
-
-   Some of the functions have side effects that don't arise from
-   variables that are passed by reference.  In particular, if a
-   function is passed ARGPTR as an argument, it modifies what ARGPTR
-   points to; typically, it advances *ARGPTR past whatever substring
-   it has just looked at.  (If it doesn't modify *ARGPTR, then the
-   function gets passed *ARGPTR instead, which is then called ARG.)
-   Also, functions that return a struct symtabs_and_lines may modify
-   CANONICAL, as in the description of decode_line_1.
-
-   If a function returns a struct symtabs_and_lines, then that struct
-   will immediately make its way up the call chain to be returned by
-   decode_line_1.  In particular, all of the functions decode_XXX
-   calculate the appropriate struct symtabs_and_lines, under the
-   assumption that their argument is of the form XXX.  */
+\f
 
 /* First, some functions to initialize stuff at the beggining of the
    function.  */
@@ -974,11 +1286,18 @@ initialize_defaults (struct symtab **default_symtab, int *default_line)
 /* Decode arg of the form *PC.  */
 
 static struct symtabs_and_lines
-decode_indirect (char **argptr)
+decode_indirect (struct linespec_state *self, char **argptr)
 {
   struct symtabs_and_lines values;
   CORE_ADDR pc;
+  char *initial = *argptr;
   
+  if (current_program_space->executing_startup)
+    /* The error message doesn't really matter, because this case
+       should only hit during breakpoint reset.  */
+    throw_error (NOT_FOUND_ERROR, _("cannot evaluate expressions while "
+                                   "program space is in startup"));
+
   (*argptr)++;
   pc = value_as_address (parse_to_comma_and_eval (argptr));
 
@@ -991,6 +1310,9 @@ decode_indirect (char **argptr)
   values.sals[0].section = find_pc_overlay (pc);
   values.sals[0].explicit_pc = 1;
 
+  if (self->canonical)
+    self->canonical->addr_string = savestring (initial, *argptr - initial);
+
   return values;
 }
 
@@ -1047,6 +1369,16 @@ locate_first_half (char **argptr, int *is_quote_enclosed)
          ++p;
        }
     }
+
+
+  /* Check for a drive letter in the filename.  This is done on all hosts
+     to capture cross-compilation environments.  On Unixen, directory
+     separators are illegal in filenames, so if the user enters "e:/foo.c",
+     he is referring to a directory named "e:" and a source file named
+     "foo.c", and we still want to keep these two pieces together.  */
+  if (isalpha (p[0]) && p[1] == ':' && IS_DIR_SEPARATOR (p[2]))
+    p += 3;
+
   for (; *p; p++)
     {
       if (p[0] == '<')
@@ -1057,6 +1389,10 @@ locate_first_half (char **argptr, int *is_quote_enclosed)
            error (_("malformed template specification in command"));
          p = temp_end;
        }
+
+      if (p[0] == '(')
+       p = find_method_overload_end (p);
+
       /* Check for a colon and a plus or minus and a [ (which
          indicates an Objective-C method).  */
       if (is_objc_method_format (p))
@@ -1064,13 +1400,11 @@ locate_first_half (char **argptr, int *is_quote_enclosed)
          break;
        }
       /* Check for the end of the first half of the linespec.  End of
-         line, a tab, a double colon or the last single colon, or a
-         space.  But if enclosed in double quotes we do not break on
-         enclosed spaces.  */
+         line, a tab, a colon or a space.  But if enclosed in double
+        quotes we do not break on enclosed spaces.  */
       if (!*p
          || p[0] == '\t'
-         || ((p[0] == ':')
-             && ((p[1] == ':') || (strchr (p + 1, ':') == NULL)))
+         || (p[0] == ':')
          || ((p[0] == ' ') && !*is_quote_enclosed))
        break;
       if (p[0] == '.' && strchr (p, ':') == NULL)
@@ -1086,8 +1420,7 @@ locate_first_half (char **argptr, int *is_quote_enclosed)
          break;
        }
     }
-  while (p[0] == ' ' || p[0] == '\t')
-    p++;
+  p = skip_spaces (p);
 
   /* If the closing double quote was left at the end, remove it.  */
   if (*is_quote_enclosed)
@@ -1115,106 +1448,52 @@ locate_first_half (char **argptr, int *is_quote_enclosed)
    than one method that could represent the selector, then use some of
    the existing C++ code to let the user choose one.  */
 
-struct symtabs_and_lines
-decode_objc (char **argptr, int funfirstline, struct symtab *file_symtab,
-            char ***canonical, char *saved_arg)
+static struct symtabs_and_lines
+decode_objc (struct linespec_state *self, char **argptr)
 {
-  struct symtabs_and_lines values;
-  struct symbol **sym_arr = NULL;
-  struct symbol *sym = NULL;
-  struct block *block = NULL;
-  unsigned i1 = 0;
-  unsigned i2 = 0;
-
-  values.sals = NULL;
-  values.nelts = 0;
-
-  if (file_symtab != NULL)
-    block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (file_symtab), STATIC_BLOCK);
-  else
+  struct collect_info info;
+  VEC (const_char_ptr) *symbol_names = NULL;
+  char *new_argptr;
+  struct cleanup *cleanup = make_cleanup (VEC_cleanup (const_char_ptr),
+                                         &symbol_names);
+
+  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))
     {
-      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);
+      do_cleanups (cleanup);
+      return info.result;
     }
 
-  find_imps (file_symtab, block, *argptr, NULL, &i1, &i2); 
-    
-  if (i1 > 0)
+  add_all_symbol_names_from_pspace (&info, NULL, symbol_names);
+
+  if (info.result.nelts > 0)
     {
-      sym_arr = (struct symbol **)
-       alloca ((i1 + 1) * sizeof (struct symbol *));
-      sym_arr[i1] = NULL;
+      char *saved_arg;
 
-      *argptr = find_imps (file_symtab, block, *argptr, sym_arr, &i1, &i2);
-    }
+      saved_arg = alloca (new_argptr - *argptr + 1);
+      memcpy (saved_arg, *argptr, new_argptr - *argptr);
+      saved_arg[new_argptr - *argptr] = '\0';
 
-  /* i1 now represents the TOTAL number of matches found.
-     i2 represents how many HIGH-LEVEL (struct symbol) matches,
-     which will come first in the sym_arr array.  Any low-level
-     (minimal_symbol) matches will follow those.  */
-      
-  if (i1 == 1)
-    {
-      if (i2 > 0)
+      if (self->canonical)
        {
-         /* Already a struct symbol.  */
-         sym = sym_arr[0];
-       }
-      else
-       {
-         sym = find_pc_function (SYMBOL_VALUE_ADDRESS (sym_arr[0]));
-         if ((sym != NULL) && strcmp (SYMBOL_LINKAGE_NAME (sym_arr[0]),
-                                      SYMBOL_LINKAGE_NAME (sym)) != 0)
-           {
-             warning (_("debugging symbol \"%s\" does "
-                        "not match selector; ignoring"),
-                      SYMBOL_LINKAGE_NAME (sym));
-             sym = NULL;
-           }
-       }
-             
-      values.sals = (struct symtab_and_line *)
-       xmalloc (sizeof (struct symtab_and_line));
-      values.nelts = 1;
-             
-      if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK)
-       {
-         /* Canonicalize this, so it remains resolved for dylib loads.  */
-         values.sals[0] = find_function_start_sal (sym, funfirstline);
-         build_canonical_line_spec (values.sals,
-                                    SYMBOL_NATURAL_NAME (sym), canonical);
-       }
-      else
-       {
-         /* The only match was a non-debuggable symbol, which might point
-            to a function descriptor; resolve it to the actual code address
-            instead.  */
-         struct minimal_symbol *msymbol = (struct minimal_symbol *)sym_arr[0];
-         struct objfile *objfile = msymbol_objfile (msymbol);
-         struct gdbarch *gdbarch = get_objfile_arch (objfile);
-         CORE_ADDR pc = SYMBOL_VALUE_ADDRESS (msymbol);
-
-         pc = gdbarch_convert_from_func_ptr_addr (gdbarch, pc,
-                                                  &current_target);
-
-         init_sal (&values.sals[0]);
-         values.sals[0].pc = pc;
+         self->canonical->pre_expanded = 1;
+         if (self->user_filename)
+           self->canonical->addr_string
+             = xstrprintf ("%s:%s", self->user_filename, saved_arg);
+         else
+           self->canonical->addr_string = xstrdup (saved_arg);
        }
-      return values;
     }
 
-  if (i1 > 1)
-    {
-      /* More than one match.  The user must choose one or more.  */
-      return decode_line_2 (sym_arr, i2, funfirstline, canonical);
-    }
+  *argptr = new_argptr;
 
-  return values;
+  do_cleanups (cleanup);
+  return info.result;
 }
 
 /* This handles C++ and Java compound data structures.  P should point
@@ -1223,8 +1502,8 @@ decode_objc (char **argptr, int funfirstline, struct symtab *file_symtab,
    pointing to "AAA::inA::fun" and P pointing to "::inA::fun".  */
 
 static struct symtabs_and_lines
-decode_compound (char **argptr, int funfirstline, char ***canonical,
-                char *saved_arg, char *p, int *not_found_ptr)
+decode_compound (struct linespec_state *self,
+                char **argptr, char *the_real_saved_arg, char *p)
 {
   struct symtabs_and_lines values;
   char *p2;
@@ -1232,9 +1511,25 @@ decode_compound (char **argptr, int funfirstline, char ***canonical,
   char *temp_end;
   struct symbol *sym;
   char *copy;
-  struct symbol *sym_class;
-  struct type *t;
-  char *saved_java_argptr = NULL;
+  VEC (symbolp) *sym_classes;
+  char *saved_arg, *class_name;
+  struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
+
+  /* If the user specified any completer quote characters in the input,
+     strip them.  They are superfluous.  */
+  saved_arg = alloca (strlen (the_real_saved_arg) + 1);
+  {
+    char *dst = saved_arg;
+    char *src = the_real_saved_arg;
+    char *quotes = get_gdb_completer_quote_characters ();
+    while (*src != '\0')
+      {
+       if (strchr (quotes, *src) == NULL)
+         *dst++ = *src;
+       ++src;
+      }
+    *dst = '\0';
+  }
 
   /* First check for "global" namespace specification, of the form
      "::foo".  If found, skip over the colons and jump to normal
@@ -1251,8 +1546,9 @@ decode_compound (char **argptr, int funfirstline, char ***canonical,
         find_method.
 
      2) AAA::inA isn't the name of a class.  In that case, either the
-        user made a typo or AAA::inA is the name of a namespace.
-        Either way, we just look up AAA::inA::fun with lookup_symbol.
+        user made a typo, AAA::inA is the name of a namespace, or it is
+        the name of a minimal symbol.
+       In this case we just delegate to decode_variable.
 
      Thus, our first task is to find everything before the last set of
      double-colons and figure out if it's the name of a class.  So we
@@ -1273,6 +1569,8 @@ decode_compound (char **argptr, int funfirstline, char ***canonical,
 
   while (1)
     {
+      static char *break_characters = " \t(";
+
       /* Move pointer up to next possible class/namespace token.  */
 
       p = p2 + 1;      /* Restart with old value +1.  */
@@ -1283,8 +1581,9 @@ decode_compound (char **argptr, int funfirstline, char ***canonical,
       /* PASS2: p2->"::fun", p->":fun" */
 
       /* Move pointer ahead to next double-colon.  */
-      while (*p && (p[0] != ' ') && (p[0] != '\t') && (p[0] != '\'')
-            && (*p != '('))
+      while (*p
+            && strchr (break_characters, *p) == NULL
+            && strchr (get_gdb_completer_quote_characters (), *p) == NULL)
        {
          if (current_language->la_language == language_cplus)
            p += cp_validate_operator (p);
@@ -1308,9 +1607,19 @@ decode_compound (char **argptr, int funfirstline, char ***canonical,
          else if ((p[0] == ':') && (p[1] == ':'))
            break;      /* Found double-colon.  */
          else
-           /* PASS2: We'll keep getting here, until p->"", at which point
-              we exit this loop.  */
-           p++;
+           {
+             /* PASS2: We'll keep getting here, until P points to one of the
+                break characters, at which point we exit this loop.  */
+             if (*p)
+               {
+                 if (p[1] == '('
+                     && strncmp (&p[1], CP_ANONYMOUS_NAMESPACE_STR,
+                                 CP_ANONYMOUS_NAMESPACE_LEN) == 0)
+                   p += CP_ANONYMOUS_NAMESPACE_LEN;
+                 else if (strchr (break_characters, *p) == NULL)
+                   ++p;
+               }
+           }
        }
 
       if (*p != ':')
@@ -1319,7 +1628,7 @@ decode_compound (char **argptr, int funfirstline, char ***canonical,
                           unsuccessfully all the components of the
                           string, and p->""(PASS2).  */
 
-      /* We get here if p points to ' ', '\t', '\'', "::" or ""(i.e
+      /* We get here if p points to one of the break characters or "" (i.e.,
         string ended).  */
       /* Save restart for next time around.  */
       p2 = p;
@@ -1339,15 +1648,14 @@ decode_compound (char **argptr, int funfirstline, char ***canonical,
   /* Before the call, argptr->"AAA::inA::fun",
      p->"", p2->"::fun".  After the call: argptr->"fun", p, p2
      unchanged.  */
-  sym_class = lookup_prefix_sym (argptr, p2);
-
-  /* If sym_class has been found, and if "AAA::inA" is a class, then
-     we're in case 1 above.  So we look up "fun" as a method of that
-     class.  */
-  if (sym_class &&
-      (t = check_typedef (SYMBOL_TYPE (sym_class)),
-       (TYPE_CODE (t) == TYPE_CODE_STRUCT
-       || TYPE_CODE (t) == TYPE_CODE_UNION)))
+  sym_classes = lookup_prefix_sym (argptr, p2, self->file_symtabs,
+                                  &class_name);
+  make_cleanup (VEC_cleanup (symbolp), &sym_classes);
+  make_cleanup (xfree, class_name);
+
+  /* If a class has been found, then we're in case 1 above.  So we
+     look up "fun" as a method of those classes.  */
+  if (!VEC_empty (symbolp, sym_classes))
     {
       /* Arg token is not digits => try it as a function name.
         Find the next token (everything up to end or next
@@ -1379,42 +1687,8 @@ decode_compound (char **argptr, int funfirstline, char ***canonical,
              p += cp_validate_operator (p - 8) - 8;
            }
 
-         /* Keep any template parameters.  */
-         if (*p == '<')
-           p = find_template_name_end (p);
-
-         /* Keep method overload information.  */
-         a = strchr (p, '(');
-         if (a != NULL)
-           p = find_method_overload_end (a);
-
-         /* Make sure we keep important kewords like "const".  */
-         if (strncmp (p, " const", 6) == 0)
-           p += 6;
-
-         /* Java may append typenames,  so assume that if there is
-            anything else left in *argptr, it must be a typename.  */
-         if (*p && current_language->la_language == language_java)
-           {
-             struct type *type;
-
-             p2 = p;
-             while (*p2)
-               ++p2;
-             copy = (char *) alloca (p2 - p + 1);
-             memcpy (copy, p, p2 - p);
-             copy[p2 - p] = '\0';
-             type = lookup_typename (current_language, get_current_arch (),
-                                     copy, NULL, 1);
-             if (type != NULL)
-               {
-                 /* Save the location of this just in case this
-                    method/type combination isn't actually defined.
-                    It will be checked later.  */
-                 saved_java_argptr = p;
-                 p = p2;
-               }
-           }
+         /* Keep any important naming information.  */
+         p = keep_name_info (p, 1);
        }
 
       /* Allocate our own copy of the substring between argptr and
@@ -1431,9 +1705,7 @@ decode_compound (char **argptr, int funfirstline, char ***canonical,
       /* At this point copy->"fun", p->"".  */
 
       /* No line number may be specified.  */
-      while (*p == ' ' || *p == '\t')
-       p++;
-      *argptr = p;
+      *argptr = skip_spaces (p);
       /* At this point arptr->"".  */
 
       /* Look for copy as a method of sym_class.  */
@@ -1443,230 +1715,412 @@ decode_compound (char **argptr, int funfirstline, char ***canonical,
         here, we return.  If not, and we are at the and of the string,
         we'll lookup the whole string in the symbol tables.  */
 
-      values = find_method (funfirstline, canonical, saved_arg,
-                           copy, t, sym_class, not_found_ptr);
-      if (saved_java_argptr != NULL && values.nelts == 1)
-       {
-         /* The user specified a specific return type for a java method.
-            Double-check that it really is the one the user specified.
-            [This is a necessary evil because strcmp_iw_ordered stops
-            comparisons too prematurely.]  */
-         sym = find_pc_sect_function (values.sals[0].pc,
-                                      values.sals[0].section);
-         /* We just found a SAL, we had better be able to go backwards!  */
-         gdb_assert (sym != NULL);
-         if (strcmp_iw (SYMBOL_LINKAGE_NAME (sym), saved_arg) != 0)
-           {
-             xfree (values.sals);
-             error (_("the class `%s' does not have "
-                      "any method instance named %s"),
-                    SYMBOL_PRINT_NAME (sym_class), copy);
-           }
-       }
+      values = find_method (self, saved_arg, copy, class_name, sym_classes);
+
+      do_cleanups (cleanup);
       return values;
     } /* End if symbol found.  */
 
 
   /* We couldn't find a class, so we're in case 2 above.  We check the
-     entire name as a symbol instead.  */
-
-  copy = (char *) alloca (p - saved_arg2 + 1);
-  memcpy (copy, saved_arg2, p - saved_arg2);
-  /* Note: if is_quoted should be true, we snuff out quote here
-     anyway.  */
-  copy[p - saved_arg2] = '\000';
-  /* Set argptr to skip over the name.  */
-  *argptr = (*p == '\'') ? p + 1 : p;
-
-  /* Look up entire name.  */
-  sym = lookup_symbol (copy, 0, VAR_DOMAIN, 0);
-  if (sym)
-    return symbol_found (funfirstline, canonical, copy, sym, NULL);
-
-  /* Couldn't find any interpretation as classes/namespaces, so give
-     up.  The quotes are important if copy is empty.  */
-  if (not_found_ptr)
-    *not_found_ptr = 1;
-  cplusplus_error (saved_arg,
-                  "Can't find member of namespace, "
-                  "class, struct, or union named \"%s\"\n",
-                  copy);
+     entire name as a symbol instead.  The simplest way to do this is
+     to just throw an exception and let our caller fall through to
+     decode_variable.  */
+
+  throw_error (NOT_FOUND_ERROR, _("see caller, this text doesn't matter"));
 }
 
-/* Next come some helper functions for decode_compound.  */
+/* An instance of this type is used when collecting prefix symbols for
+   decode_compound.  */
+
+struct decode_compound_collector
+{
+  /* The result vector.  */
+  VEC (symbolp) *symbols;
+
+  /* A hash table of all symbols we found.  We use this to avoid
+     adding any symbol more than once.  */
+  htab_t unique_syms;
+};
+
+/* A callback for iterate_over_symbols that is used by
+   lookup_prefix_sym to collect type symbols.  */
+
+static int
+collect_one_symbol (struct symbol *sym, void *d)
+{
+  struct decode_compound_collector *collector = d;
+  void **slot;
+  struct type *t;
+
+  if (SYMBOL_CLASS (sym) != LOC_TYPEDEF)
+    return 1;
+
+  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;
+
+  slot = htab_find_slot (collector->unique_syms, sym, INSERT);
+  if (!*slot)
+    {
+      *slot = sym;
+      VEC_safe_push (symbolp, collector->symbols, sym);
+    }
+
+  return 1;
+}
 
 /* Return the symbol corresponding to the substring of *ARGPTR ending
    at P, allowing whitespace.  Also, advance *ARGPTR past the symbol
    name in question, the compound object separator ("::" or "."), and
    whitespace.  Note that *ARGPTR is changed whether or not the
-   lookup_symbol call finds anything (i.e we return NULL).  As an
+   this call finds anything (i.e we return NULL).  As an
    example, say ARGPTR is "AAA::inA::fun" and P is "::inA::fun".  */
 
-static struct symbol *
-lookup_prefix_sym (char **argptr, char *p)
+static VEC (symbolp) *
+lookup_prefix_sym (char **argptr, char *p, VEC (symtab_p) *file_symtabs,
+                  char **class_name)
 {
   char *p1;
   char *copy;
-  struct symbol *sym;
+  int ix;
+  struct symtab *elt;
+  struct decode_compound_collector collector;
+  struct cleanup *outer;
+  struct cleanup *cleanup;
+  struct block *search_block;
 
   /* Extract the class name.  */
   p1 = p;
   while (p != *argptr && p[-1] == ' ')
     --p;
-  copy = (char *) alloca (p - *argptr + 1);
+  copy = (char *) xmalloc (p - *argptr + 1);
   memcpy (copy, *argptr, p - *argptr);
   copy[p - *argptr] = 0;
+  *class_name = copy;
+  outer = make_cleanup (xfree, copy);
 
   /* Discard the class name from the argptr.  */
   p = p1 + (p1[0] == ':' ? 2 : 1);
-  while (*p == ' ' || *p == '\t')
-    p++;
+  p = skip_spaces (p);
   *argptr = p;
 
   /* At this point p1->"::inA::fun", p->"inA::fun" copy->"AAA",
      argptr->"inA::fun".  */
 
-  sym = lookup_symbol (copy, 0, STRUCT_DOMAIN, 0);
-  if (sym == NULL)
-    {
-      /* Typedefs are in VAR_DOMAIN so the above symbol lookup will
-        fail when the user attempts to lookup a method of a class
-        via a typedef'd name (NOT via the class's name, which is already
-        handled in symbol_matches_domain).  So try the lookup again
-        using VAR_DOMAIN (where typedefs live) and double-check that we
-        found a struct/class type.  */
-      struct symbol *s = lookup_symbol (copy, 0, VAR_DOMAIN, 0);
+  collector.symbols = NULL;
+  make_cleanup (VEC_cleanup (symbolp), &collector.symbols);
 
-      if (s != NULL)
-       {
-         struct type *t = SYMBOL_TYPE (s);
+  collector.unique_syms = htab_create_alloc (1, htab_hash_pointer,
+                                            htab_eq_pointer, NULL,
+                                            xcalloc, xfree);
+  cleanup = make_cleanup_htab_delete (collector.unique_syms);
 
-         CHECK_TYPEDEF (t);
-         if (TYPE_CODE (t) == TYPE_CODE_STRUCT)
-           return s;
+  for (ix = 0; VEC_iterate (symtab_p, file_symtabs, ix, elt); ++ix)
+    {
+      if (elt == NULL)
+       {
+         iterate_over_all_matching_symtabs (copy, STRUCT_DOMAIN,
+                                            collect_one_symbol, &collector,
+                                            NULL);
+         iterate_over_all_matching_symtabs (copy, VAR_DOMAIN,
+                                            collect_one_symbol, &collector,
+                                            NULL);
+       }
+      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, copy, STRUCT_DOMAIN,
+                                  collect_one_symbol, &collector);
+         LA_ITERATE_OVER_SYMBOLS (search_block, copy, VAR_DOMAIN,
+                                  collect_one_symbol, &collector);
        }
     }
 
-  return sym;
+  do_cleanups (cleanup);
+  discard_cleanups (outer);
+  return collector.symbols;
 }
 
-/* This finds the method COPY in the class whose type is T and whose
-   symbol is SYM_CLASS.  */
+/* A qsort comparison function for symbols.  The resulting order does
+   not actually matter; we just need to be able to sort them so that
+   symbols with the same program space end up next to each other.  */
 
-static struct symtabs_and_lines
-find_method (int funfirstline, char ***canonical, char *saved_arg,
-            char *copy, struct type *t, struct symbol *sym_class,
-            int *not_found_ptr)
+static int
+compare_symbols (const void *a, const void *b)
 {
-  struct symtabs_and_lines values;
-  struct symbol *sym = NULL;
-  int i1;      /*  Counter for the symbol array.  */
-  struct symbol **sym_arr =  alloca (total_number_of_methods (t)
-                                    * sizeof (struct symbol *));
+  struct symbol * const *sa = a;
+  struct symbol * const *sb = b;
+  uintptr_t uia, uib;
 
-  /* Find all methods with a matching name, and put them in
-     sym_arr.  */
+  uia = (uintptr_t) SYMTAB_PSPACE (SYMBOL_SYMTAB (*sa));
+  uib = (uintptr_t) SYMTAB_PSPACE (SYMBOL_SYMTAB (*sb));
 
-  i1 = find_methods (t, copy, SYMBOL_LANGUAGE (sym_class), sym_arr);
+  if (uia < uib)
+    return -1;
+  if (uia > uib)
+    return 1;
+
+  uia = (uintptr_t) *sa;
+  uib = (uintptr_t) *sb;
+
+  if (uia < uib)
+    return -1;
+  if (uia > uib)
+    return 1;
+
+  return 0;
+}
+
+/* Look for all the matching instances of each symbol in NAMES.  Only
+   instances from PSPACE are considered; other program spaces are
+   handled by our caller.  If PSPACE is NULL, then all program spaces
+   are considered.  Results are stored into INFO.  */
+
+static void
+add_all_symbol_names_from_pspace (struct collect_info *info,
+                                 struct program_space *pspace,
+                                 VEC (const_char_ptr) *names)
+{
+  int ix;
+  const char *iter;
+
+  for (ix = 0; VEC_iterate (const_char_ptr, names, ix, iter); ++ix)
+    add_matching_symbols_to_info (iter, info, pspace);
+}
+
+static void
+find_superclass_methods (VEC (typep) *superclasses,
+                        const char *name,
+                        VEC (const_char_ptr) **result_names)
+{
+  int old_len = VEC_length (const_char_ptr, *result_names);
+  VEC (typep) *iter_classes;
+  struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
 
-  if (i1 == 1)
+  iter_classes = superclasses;
+  while (1)
     {
-      /* There is exactly one field with that name.  */
-      sym = sym_arr[0];
+      VEC (typep) *new_supers = NULL;
+      int ix;
+      struct type *t;
 
-      if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK)
-       {
-         values.sals = (struct symtab_and_line *)
-           xmalloc (sizeof (struct symtab_and_line));
-         values.nelts = 1;
-         values.sals[0] = find_function_start_sal (sym,
-                                                   funfirstline);
-       }
-      else
+      make_cleanup (VEC_cleanup (typep), &new_supers);
+      for (ix = 0; VEC_iterate (typep, iter_classes, ix, t); ++ix)
+       find_methods (t, name, result_names, &new_supers);
+
+      if (VEC_length (const_char_ptr, *result_names) != old_len
+         || VEC_empty (typep, new_supers))
+       break;
+
+      iter_classes = new_supers;
+    }
+
+  do_cleanups (cleanup);
+}
+
+/* This finds the method COPY in the class whose type is given by one
+   of the symbols in SYM_CLASSES.  */
+
+static struct symtabs_and_lines
+find_method (struct linespec_state *self, char *saved_arg,
+            char *copy, const char *class_name, VEC (symbolp) *sym_classes)
+{
+  char *canon;
+  struct symbol *sym;
+  struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
+  int ix;
+  int last_result_len;
+  VEC (typep) *superclass_vec;
+  VEC (const_char_ptr) *result_names;
+  struct collect_info info;
+  char *name_iter;
+
+  /* NAME is typed by the user: it needs to be canonicalized before
+     searching the symbol tables.  */
+  canon = cp_canonicalize_string_no_typedefs (copy);
+  if (canon != NULL)
+    {
+      copy = canon;
+      make_cleanup (xfree, copy);
+    }
+
+  /* Sort symbols so that symbols with the same program space are next
+     to each other.  */
+  qsort (VEC_address (symbolp, sym_classes),
+        VEC_length (symbolp, sym_classes),
+        sizeof (symbolp),
+        compare_symbols);
+
+  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
+     given program space, then we consider inherited methods; this is
+     not ideal (ideal would be to respect C++ hiding rules), but it
+     seems good enough and is what GDB has historically done.  We only
+     need to collect the names because later we find all symbols with
+     those names.  This loop is written in a somewhat funny way
+     because we collect data across the program space before deciding
+     what to do.  */
+  superclass_vec = NULL;
+  make_cleanup (VEC_cleanup (typep), &superclass_vec);
+  result_names = NULL;
+  make_cleanup (VEC_cleanup (const_char_ptr), &result_names);
+  last_result_len = 0;
+  for (ix = 0; VEC_iterate (symbolp, sym_classes, ix, sym); ++ix)
+    {
+      struct type *t;
+      struct program_space *pspace;
+
+      /* Program spaces that are executing startup should have
+        been filtered out earlier.  */
+      gdb_assert (!SYMTAB_PSPACE (SYMBOL_SYMTAB (sym))->executing_startup);
+      pspace = SYMTAB_PSPACE (SYMBOL_SYMTAB (sym));
+      set_current_program_space (pspace);
+      t = check_typedef (SYMBOL_TYPE (sym));
+      find_methods (t, copy, &result_names, &superclass_vec);
+
+      /* Handle all items from a single program space at once; and be
+        sure not to miss the last batch.  */
+      if (ix == VEC_length (symbolp, sym_classes) - 1
+         || (pspace
+             != SYMTAB_PSPACE (SYMBOL_SYMTAB (VEC_index (symbolp, sym_classes,
+                                                         ix + 1)))))
        {
-         values.sals = NULL;
-         values.nelts = 0;
+         /* If we did not find a direct implementation anywhere in
+            this program space, consider superclasses.  */
+         if (VEC_length (const_char_ptr, result_names) == last_result_len)
+           find_superclass_methods (superclass_vec, copy, &result_names);
+
+         /* We have a list of candidate symbol names, so now we
+            iterate over the symbol tables looking for all
+            matches in this pspace.  */
+         add_all_symbol_names_from_pspace (&info, pspace, result_names);
+
+         VEC_truncate (typep, superclass_vec, 0);
+         last_result_len = VEC_length (const_char_ptr, result_names);
        }
-      return values;
     }
-  if (i1 > 0)
+
+  if (info.result.nelts > 0)
     {
-      /* If we were given a specific overload instance, use that
-        (or error if no matches were found).  Otherwise ask the user
-        which one to use.  */
-      if (strchr (saved_arg, '(') != NULL)
+      if (self->canonical)
        {
-         int i;
-         char *name = saved_arg;
-         char *canon = cp_canonicalize_string (name);
-         struct cleanup *cleanup;
-
-         if (canon != NULL)
-           {
-             name = canon;
-             cleanup = make_cleanup (xfree, canon);
-           }
+         self->canonical->pre_expanded = 1;
+         if (self->user_filename)
+           self->canonical->addr_string
+             = xstrprintf ("%s:%s", self->user_filename, saved_arg);
          else
-           cleanup = make_cleanup (null_cleanup, NULL);
-
-         for (i = 0; i < i1; ++i)
-           {
-             if (strcmp_iw (name, SYMBOL_LINKAGE_NAME (sym_arr[i])) == 0)
-               {
-                 values.sals = (struct symtab_and_line *)
-                   xmalloc (sizeof (struct symtab_and_line));
-                 values.nelts = 1;
-                 values.sals[0] = find_function_start_sal (sym_arr[i],
-                                                           funfirstline);
-                 do_cleanups (cleanup);
-                 return values;
-               }
-           }
-
-         error (_("the class `%s' does not have "
-                  "any method instance named %s"),
-                SYMBOL_PRINT_NAME (sym_class), copy);
+           self->canonical->addr_string = xstrdup (saved_arg);
        }
 
-      return decode_line_2 (sym_arr, i1, funfirstline, canonical);
+      do_cleanups (cleanup);
+
+      return info.result;
     }
+
+  if (copy[0] == '~')
+    cplusplus_error (saved_arg,
+                    "the class `%s' does not have destructor defined\n",
+                    class_name);
   else
+    cplusplus_error (saved_arg,
+                    "the class %s does not have any method named %s\n",
+                    class_name, copy);
+}
+
+\f
+
+/* This object is used when collecting all matching symtabs.  */
+
+struct symtab_collector
+{
+  /* The result vector of symtabs.  */
+  VEC (symtab_p) *symtabs;
+
+  /* This is used to ensure the symtabs are unique.  */
+  htab_t symtab_table;
+};
+
+/* Callback for iterate_over_symtabs.  */
+
+static int
+add_symtabs_to_list (struct symtab *symtab, void *d)
+{
+  struct symtab_collector *data = d;
+  void **slot;
+
+  slot = htab_find_slot (data->symtab_table, symtab, INSERT);
+  if (!*slot)
     {
-      if (not_found_ptr)
-        *not_found_ptr = 1;
-      if (copy[0] == '~')
-       cplusplus_error (saved_arg,
-                        "the class `%s' does not have destructor defined\n",
-                        SYMBOL_PRINT_NAME (sym_class));
-      else
-       cplusplus_error (saved_arg,
-                        "the class %s does not have any method named %s\n",
-                        SYMBOL_PRINT_NAME (sym_class), copy);
+      *slot = symtab;
+      VEC_safe_push (symtab_p, data->symtabs, symtab);
     }
+
+  return 0;
 }
 
-\f
+/* Given a file name, return a VEC of all matching symtabs.  */
+
+static VEC (symtab_p) *
+collect_symtabs_from_filename (const char *file)
+{
+  struct symtab_collector collector;
+  struct cleanup *cleanups;
+  struct program_space *pspace;
 
-/* Return the symtab associated to the filename given by the substring
-   of *ARGPTR ending at P, and advance ARGPTR past that filename.  If
-   NOT_FOUND_PTR is not null and the source file is not found, store
-   boolean true at the location pointed to and do not issue an
-   error message.  */
+  collector.symtabs = NULL;
+  collector.symtab_table = htab_create (1, htab_hash_pointer, htab_eq_pointer,
+                                       NULL);
+  cleanups = make_cleanup_htab_delete (collector.symtab_table);
 
-static struct symtab *
-symtab_from_filename (char **argptr, char *p, int is_quote_enclosed, 
-                     int *not_found_ptr)
+  /* Find that file's data.  */
+  ALL_PSPACES (pspace)
+  {
+    if (pspace->executing_startup)
+      continue;
+
+    set_current_program_space (pspace);
+    iterate_over_symtabs (file, add_symtabs_to_list, &collector);
+  }
+
+  do_cleanups (cleanups);
+  return collector.symtabs;
+}
+
+/* Return all the symtabs associated to the filename given by the
+   substring of *ARGPTR ending at P, and advance ARGPTR past that
+   filename.  */
+
+static VEC (symtab_p) *
+symtabs_from_filename (char **argptr, char *p, int is_quote_enclosed,
+                      char **user_filename)
 {
   char *p1;
   char *copy;
-  struct symtab *file_symtab;
+  struct cleanup *outer;
+  VEC (symtab_p) *result;
   
   p1 = p;
   while (p != *argptr && p[-1] == ' ')
     --p;
   if ((*p == '"') && is_quote_enclosed)
     --p;
-  copy = (char *) alloca (p - *argptr + 1);
+  copy = xmalloc (p - *argptr + 1);
+  outer = make_cleanup (xfree, copy);
   memcpy (copy, *argptr, p - *argptr);
   /* It may have the ending quote right after the file name.  */
   if ((is_quote_enclosed && copy[p - *argptr - 1] == '"')
@@ -1675,12 +2129,10 @@ symtab_from_filename (char **argptr, char *p, int is_quote_enclosed,
   else
     copy[p - *argptr] = 0;
 
-  /* Find that file's data.  */
-  file_symtab = lookup_symtab (copy);
-  if (file_symtab == 0)
+  result = collect_symtabs_from_filename (copy);
+
+  if (VEC_empty (symtab_p, result))
     {
-      if (not_found_ptr)
-       *not_found_ptr = 1;
       if (!have_full_symbols () && !have_partial_symbols ())
        throw_error (NOT_FOUND_ERROR,
                     _("No symbol table is loaded.  "
@@ -1689,28 +2141,156 @@ symtab_from_filename (char **argptr, char *p, int is_quote_enclosed,
     }
 
   /* Discard the file name from the arg.  */
-  p = p1 + 1;
-  while (*p == ' ' || *p == '\t')
-    p++;
-  *argptr = p;
+  if (*p1 == '\0')
+    *argptr = p1;
+  else
+    *argptr = skip_spaces (p1 + 1);
+
+  discard_cleanups (outer);
+  *user_filename = copy;
+  return result;
+}
+
+/* A callback used by iterate_over_all_matching_symtabs that collects
+   symbols for find_function_symbols.  */
+
+static int
+collect_function_symbols (struct symbol *sym, void *arg)
+{
+  VEC (symbolp) **syms = arg;
+
+  if (SYMBOL_CLASS (sym) == LOC_BLOCK)
+    VEC_safe_push (symbolp, *syms, sym);
+
+  return 1;
+}
+
+/* Look up a function symbol in *ARGPTR.  If found, advance *ARGPTR
+   and return the symbol.  If not found, return NULL.  */
+
+static VEC (symbolp) *
+find_function_symbols (char **argptr, char *p, int is_quote_enclosed,
+                      char **user_function)
+{
+  char *p1;
+  char *copy;
+  VEC (symbolp) *result = NULL;
+
+  p1 = p;
+  while (p != *argptr && p[-1] == ' ')
+    --p;
+  if ((*p == '"') && is_quote_enclosed)
+    --p;
+  copy = (char *) xmalloc (p - *argptr + 1);
+  *user_function = copy;
+  memcpy (copy, *argptr, p - *argptr);
+  /* It may have the ending quote right after the file name.  */
+  if ((is_quote_enclosed && copy[p - *argptr - 1] == '"')
+      || copy[p - *argptr - 1] == '\'')
+    copy[p - *argptr - 1] = 0;
+  else
+    copy[p - *argptr] = 0;
 
-  return file_symtab;
+  iterate_over_all_matching_symtabs (copy, VAR_DOMAIN,
+                                    collect_function_symbols, &result, NULL);
+
+  if (VEC_empty (symbolp, result))
+    VEC_free (symbolp, result);
+  else
+    {
+      /* Discard the file name from the arg.  */
+      *argptr = skip_spaces (p1 + 1);
+    }
+
+  return result;
 }
 
 \f
 
+/* A helper for decode_all_digits that handles the 'list_mode' case.  */
+
+static void
+decode_digits_list_mode (struct linespec_state *self,
+                        struct symtabs_and_lines *values,
+                        struct symtab_and_line val)
+{
+  int ix;
+  struct symtab *elt;
+
+  gdb_assert (self->list_mode);
+
+  for (ix = 0; VEC_iterate (symtab_p, self->file_symtabs, ix, elt); ++ix)
+    {
+      /* The logic above should ensure this.  */
+      gdb_assert (elt != NULL);
+
+      set_current_program_space (SYMTAB_PSPACE (elt));
+
+      /* Simplistic search just for the list command.  */
+      val.symtab = find_line_symtab (elt, val.line, NULL, NULL);
+      if (val.symtab == NULL)
+       val.symtab = elt;
+      val.pspace = SYMTAB_PSPACE (elt);
+      val.pc = 0;
+      val.explicit_line = 1;
+
+      add_sal_to_sals (self, values, &val, NULL);
+    }
+}
+
+/* A helper for decode_all_digits that iterates over the symtabs,
+   adding lines to the VEC.  */
+
+static void
+decode_digits_ordinary (struct linespec_state *self,
+                       int line,
+                       struct symtabs_and_lines *sals,
+                       struct linetable_entry **best_entry)
+{
+  int ix;
+  struct symtab *elt;
+
+  for (ix = 0; VEC_iterate (symtab_p, self->file_symtabs, ix, elt); ++ix)
+    {
+      int i;
+      VEC (CORE_ADDR) *pcs;
+      CORE_ADDR pc;
+
+      /* The logic above should ensure this.  */
+      gdb_assert (elt != NULL);
+
+      set_current_program_space (SYMTAB_PSPACE (elt));
+
+      pcs = find_pcs_for_symtab_line (elt, line, best_entry);
+      for (i = 0; VEC_iterate (CORE_ADDR, pcs, i, pc); ++i)
+       {
+         struct symtab_and_line sal;
+
+         init_sal (&sal);
+         sal.pspace = SYMTAB_PSPACE (elt);
+         sal.symtab = elt;
+         sal.line = line;
+         sal.pc = pc;
+         add_sal_to_sals_basic (sals, &sal);
+       }
+
+      VEC_free (CORE_ADDR, pcs);
+    }
+}
+
 /* This decodes a line where the argument is all digits (possibly
    preceded by a sign).  Q should point to the end of those digits;
    the other arguments are as usual.  */
 
 static struct symtabs_and_lines
-decode_all_digits (char **argptr, struct symtab *default_symtab,
-                  int default_line, char ***canonical,
-                  struct symtab *file_symtab, char *q)
-
+decode_all_digits (struct linespec_state *self,
+                  char **argptr,
+                  char *q)
 {
   struct symtabs_and_lines values;
   struct symtab_and_line val;
+  int use_default = 0;
+  char *saved_arg = *argptr;
 
   enum sign
     {
@@ -1718,12 +2298,9 @@ decode_all_digits (char **argptr, struct symtab *default_symtab,
     }
   sign = none;
 
-  /* We might need a canonical line spec if no file was specified.  */
-  int need_canonical = (file_symtab == NULL) ? 1 : 0;
-
   init_sal (&val);
-
-  val.pspace = current_program_space;
+  values.sals = NULL;
+  values.nelts = 0;
 
   /* This is where we need to make sure that we have good defaults.
      We must guarantee that this section of code is never executed
@@ -1731,11 +2308,19 @@ decode_all_digits (char **argptr, struct symtab *default_symtab,
      set_default_source_symtab_and_line uses
      select_source_symtab that calls us with such an argument.  */
 
-  if (file_symtab == 0 && default_symtab == 0)
+  if (VEC_length (symtab_p, self->file_symtabs) == 1
+      && VEC_index (symtab_p, self->file_symtabs, 0) == NULL)
     {
+      set_current_program_space (self->program_space);
+
       /* Make sure we have at least a default source file.  */
       set_default_source_symtab_and_line ();
-      initialize_defaults (&default_symtab, &default_line);
+      initialize_defaults (&self->default_symtab, &self->default_line);
+      VEC_pop (symtab_p, self->file_symtabs);
+      VEC_free (symtab_p, self->file_symtabs);
+      self->file_symtabs
+       = collect_symtabs_from_filename (self->default_symtab->filename);
+      use_default = 1;
     }
 
   if (**argptr == '+')
@@ -1748,14 +2333,14 @@ decode_all_digits (char **argptr, struct symtab *default_symtab,
     case plus:
       if (q == *argptr)
        val.line = 5;
-      if (file_symtab == 0)
-       val.line = default_line + val.line;
+      if (use_default)
+       val.line = self->default_line + val.line;
       break;
     case minus:
       if (q == *argptr)
        val.line = 15;
-      if (file_symtab == 0)
-       val.line = default_line - val.line;
+      if (use_default)
+       val.line = self->default_line - val.line;
       else
        val.line = 1;
       break;
@@ -1763,28 +2348,110 @@ decode_all_digits (char **argptr, struct symtab *default_symtab,
       break;           /* No need to adjust val.line.  */
     }
 
-  while (*q == ' ' || *q == '\t')
-    q++;
-  *argptr = q;
-  if (file_symtab == 0)
-    file_symtab = default_symtab;
-
-  /* It is possible that this source file has more than one symtab, 
-     and that the new line number specification has moved us from the
-     default (in file_symtab) to a new one.  */
-  val.symtab = find_line_symtab (file_symtab, val.line, NULL, NULL);
-  if (val.symtab == 0)
-    val.symtab = file_symtab;
-
-  val.pspace = SYMTAB_PSPACE (val.symtab);
-  val.pc = 0;
-  values.sals = (struct symtab_and_line *)
-    xmalloc (sizeof (struct symtab_and_line));
-  values.sals[0] = val;
-  values.nelts = 1;
-  if (need_canonical)
-    build_canonical_line_spec (values.sals, NULL, canonical);
-  values.sals[0].explicit_line = 1;
+  *argptr = skip_spaces (q);
+
+  if (self->list_mode)
+    decode_digits_list_mode (self, &values, val);
+  else
+    {
+      struct linetable_entry *best_entry = NULL;
+      int *filter;
+      struct block **blocks;
+      struct cleanup *cleanup;
+      struct symtabs_and_lines intermediate_results;
+      int i, j;
+
+      intermediate_results.sals = NULL;
+      intermediate_results.nelts = 0;
+
+      decode_digits_ordinary (self, val.line, &intermediate_results,
+                             &best_entry);
+      if (intermediate_results.nelts == 0 && best_entry != NULL)
+       decode_digits_ordinary (self, best_entry->line, &intermediate_results,
+                               &best_entry);
+
+      cleanup = make_cleanup (xfree, intermediate_results.sals);
+
+      /* For optimized code, compiler can scatter one source line
+        accross disjoint ranges of PC values, even when no duplicate
+        functions or inline functions are involved.  For example,
+        'for (;;)' inside non-template non-inline non-ctor-or-dtor
+        function can result in two PC ranges.  In this case, we don't
+        want to set breakpoint on first PC of each range.  To filter
+        such cases, we use containing blocks -- for each PC found
+        above we see if there are other PCs that are in the same
+        block.  If yes, the other PCs are filtered out.  */
+
+      filter = xmalloc (intermediate_results.nelts * sizeof (int));
+      make_cleanup (xfree, filter);
+      blocks = xmalloc (intermediate_results.nelts * sizeof (struct block *));
+      make_cleanup (xfree, blocks);
+
+      for (i = 0; i < intermediate_results.nelts; ++i)
+       {
+         set_current_program_space (intermediate_results.sals[i].pspace);
+
+         filter[i] = 1;
+         blocks[i] = block_for_pc_sect (intermediate_results.sals[i].pc,
+                                        intermediate_results.sals[i].section);
+       }
+
+      for (i = 0; i < intermediate_results.nelts; ++i)
+       {
+         if (blocks[i] != NULL)
+           for (j = i + 1; j < intermediate_results.nelts; ++j)
+             {
+               if (blocks[j] == blocks[i])
+                 {
+                   filter[j] = 0;
+                   break;
+                 }
+             }
+       }
+
+      for (i = 0; i < intermediate_results.nelts; ++i)
+       if (filter[i])
+         {
+           struct symbol *sym = (blocks[i]
+                                 ? block_containing_function (blocks[i])
+                                 : NULL);
+
+           if (self->funfirstline)
+             skip_prologue_sal (&intermediate_results.sals[i]);
+           /* Make sure the line matches the request, not what was
+              found.  */
+           intermediate_results.sals[i].line = val.line;
+           add_sal_to_sals (self, &values, &intermediate_results.sals[i],
+                            sym ? SYMBOL_NATURAL_NAME (sym) : NULL);
+         }
+
+      do_cleanups (cleanup);
+    }
+
+  if (values.nelts == 0)
+    {
+      if (self->user_filename)
+       throw_error (NOT_FOUND_ERROR, _("No line %d in file \"%s\"."),
+                    val.line, self->user_filename);
+      else
+       throw_error (NOT_FOUND_ERROR, _("No line %d in the current file."),
+                    val.line);
+    }
+
+  if (self->canonical)
+    {
+      char *copy = savestring (saved_arg, q - saved_arg);
+
+      self->canonical->pre_expanded = 1;
+      gdb_assert (self->user_filename || use_default);
+      self->canonical->addr_string
+       = xstrprintf ("%s:%s", (self->user_filename
+                               ? self->user_filename
+                               : self->default_symtab->filename),
+                     copy);
+      xfree (copy);
+    }
+
   return values;
 }
 
@@ -1793,17 +2460,17 @@ decode_all_digits (char **argptr, struct symtab *default_symtab,
 /* Decode a linespec starting with a dollar sign.  */
 
 static struct symtabs_and_lines
-decode_dollar (char *copy, int funfirstline, struct symtab *default_symtab,
-              char ***canonical, struct symtab *file_symtab)
+decode_dollar (struct linespec_state *self, char *copy)
 {
   LONGEST valx;
   int index = 0;
-  int need_canonical = 0;
   struct symtabs_and_lines values;
   struct symtab_and_line val;
   char *p;
   struct symbol *sym;
   struct minimal_symbol *msymbol;
+  int ix;
+  struct symtab *elt;
 
   p = (copy[1] == '$') ? copy + 2 : copy + 1;
   while (*p >= '0' && *p <= '9')
@@ -1825,19 +2492,18 @@ decode_dollar (char *copy, int funfirstline, struct symtab *default_symtab,
       /* Not all digits -- may be user variable/function or a
         convenience variable.  */
 
-      /* Look up entire name as a symbol first.  */
-      sym = lookup_symbol (copy, 0, VAR_DOMAIN, 0);
-      file_symtab = (struct symtab *) NULL;
-      need_canonical = 1;
-      /* Symbol was found --> jump to normal symbol processing.  */
-      if (sym)
-       return symbol_found (funfirstline, canonical, copy, sym, NULL);
+      volatile struct gdb_exception exc;
+
+      TRY_CATCH (exc, RETURN_MASK_ERROR)
+       {
+         values = decode_variable (self, copy);
+       }
 
-      /* If symbol was not found, look in minimal symbol tables.  */
-      msymbol = lookup_minimal_symbol (copy, NULL, NULL);
-      /* Min symbol was found --> jump to minsym processing.  */
-      if (msymbol)
-       return minsym_found (funfirstline, msymbol);
+      if (exc.reason == 0)
+       return values;
+
+      if (exc.error != NOT_FOUND_ERROR)
+       throw_exception (exc);
 
       /* Not a user variable or function -- must be convenience variable.  */
       if (!get_internalvar_integer (lookup_internalvar (copy + 1), &valx))
@@ -1847,18 +2513,37 @@ decode_dollar (char *copy, int funfirstline, struct symtab *default_symtab,
 
   init_sal (&val);
 
-  /* Either history value or convenience value from above, in valx.  */
-  val.symtab = file_symtab ? file_symtab : default_symtab;
-  val.line = valx;
-  val.pc = 0;
-  val.pspace = current_program_space;
+  values.sals = NULL;
+  values.nelts = 0;
 
-  values.sals = (struct symtab_and_line *) xmalloc (sizeof val);
-  values.sals[0] = val;
-  values.nelts = 1;
+  for (ix = 0; VEC_iterate (symtab_p, self->file_symtabs, ix, elt); ++ix)
+    {
+      if (elt == NULL)
+       {
+         elt = self->default_symtab;
+         set_current_program_space (self->program_space);
+       }
+      else
+       set_current_program_space (SYMTAB_PSPACE (elt));
+
+      /* Either history value or convenience value from above, in valx.  */
+      val.symtab = elt;
+      val.line = valx;
+      val.pc = 0;
+      val.pspace = elt ? SYMTAB_PSPACE (elt) : current_program_space;
+
+      add_sal_to_sals (self, &values, &val, NULL);
+    }
 
-  if (need_canonical)
-    build_canonical_line_spec (values.sals, NULL, canonical);
+  if (self->canonical)
+    {
+      self->canonical->pre_expanded = 1;
+      if (self->user_filename)
+       self->canonical->addr_string = xstrprintf ("%s:%s",
+                                                  self->user_filename, copy);
+      else
+       self->canonical->addr_string = xstrdup (copy);
+    }
 
   return values;
 }
@@ -1867,6 +2552,8 @@ decode_dollar (char *copy, int funfirstline, struct symtab *default_symtab,
 
 /* A helper for decode_line_1 that tries to find a label.  The label
    is searched for in the current block.
+   FUNCTION_SYMBOLS is a list of the enclosing functions; or NULL if none
+   specified.
    COPY is the name of the label to find.
    CANONICAL is the same as the "canonical" argument to decode_line_1.
    RESULT is a pointer to a symtabs_and_lines structure which will be
@@ -1874,54 +2561,299 @@ decode_dollar (char *copy, int funfirstline, struct symtab *default_symtab,
    This function returns 1 if a label was found, 0 otherwise.  */
 
 static int
-decode_label (char *copy, char ***canonical, struct symtabs_and_lines *result)
+decode_label (struct linespec_state *self,
+             VEC (symbolp) *function_symbols, char *copy,
+             struct symtabs_and_lines *result)
 {
-  struct symbol *sym;
+  struct symbol *fn_sym;
+  int ix;
+
+  if (function_symbols == NULL)
+    {
+      struct block *block;
+      struct symbol *sym;
+      struct symtab_and_line sal;
+      struct symtabs_and_lines values;
+
+      values.nelts = 0;
+      values.sals = NULL;
 
-  sym = lookup_symbol (copy, get_selected_block (0), LABEL_DOMAIN, 0);
+      set_current_program_space (self->program_space);
+      block = get_search_block (NULL);
 
-  if (sym != NULL)
-    *result = symbol_found (0, canonical, copy, sym, NULL);
+      for (;
+          block && !BLOCK_FUNCTION (block);
+          block = BLOCK_SUPERBLOCK (block))
+       ;
+      if (!block)
+       return 0;
+      fn_sym = BLOCK_FUNCTION (block);
 
-  return sym != NULL;
+      sym = lookup_symbol (copy, block, LABEL_DOMAIN, 0);
+
+      if (sym == NULL)
+       return 0;
+
+      symbol_to_sal (&sal, self->funfirstline, sym);
+      add_sal_to_sals (self, &values, &sal,
+                      SYMBOL_NATURAL_NAME (fn_sym));
+
+      if (self->canonical)
+       {
+         self->canonical->special_display = 1;
+         self->canonical->addr_string
+           = xstrprintf ("%s:%s", SYMBOL_NATURAL_NAME (fn_sym),
+                         copy);
+       }
+
+      *result = values;
+
+      return 1;
+    }
+
+  result->sals = NULL;
+  result->nelts = 0;
+
+  for (ix = 0; VEC_iterate (symbolp, function_symbols, ix, fn_sym); ++ix)
+    {
+      struct block *block;
+      struct symbol *sym;
+
+      set_current_program_space (SYMTAB_PSPACE (SYMBOL_SYMTAB (fn_sym)));
+      block = SYMBOL_BLOCK_VALUE (fn_sym);
+      sym = lookup_symbol (copy, block, LABEL_DOMAIN, 0);
+
+      if (sym != NULL)
+       {
+         struct symtab_and_line sal;
+         char *symname;
+
+         symbol_to_sal (&sal, self->funfirstline, sym);
+         symname = xstrprintf ("%s:%s",
+                               SYMBOL_NATURAL_NAME (fn_sym),
+                               SYMBOL_NATURAL_NAME (sym));
+         add_sal_to_sals (self, result, &sal, symname);
+         xfree (symname);
+       }
+    }
+
+  if (self->canonical && result->nelts > 0)
+    {
+      self->canonical->pre_expanded = 1;
+      self->canonical->special_display = 1;
+
+      gdb_assert (self->user_function);
+      self->canonical->addr_string
+       = xstrprintf ("%s:%s", self->user_function, copy);
+    }
+
+  return result->nelts > 0;
 }
 
-/* Decode a linespec that's a variable.  If FILE_SYMTAB is non-NULL,
-   look in that symtab's static variables first.  If NOT_FOUND_PTR is
-   not NULL and the function cannot be found, store boolean true in
-   the location pointed to and do not issue an error message.  */ 
+/* A callback used to possibly add a symbol to the results.  */
 
-static struct symtabs_and_lines
-decode_variable (char *copy, int funfirstline, char ***canonical,
-                struct symtab *file_symtab, int *not_found_ptr)
+static int
+collect_symbols (struct symbol *sym, void *data)
 {
-  struct symbol *sym;
-  struct minimal_symbol *msymbol;
+  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))
+    add_sal_to_sals (info->state, &info->result, &sal,
+                    SYMBOL_NATURAL_NAME (sym));
+
+  return 1;
+}
+
+/* We've found a minimal symbol MSYMBOL to associate with our
+   linespec; add it to the result symtabs_and_lines.  */
+
+static void
+minsym_found (struct linespec_state *self, struct objfile *objfile,
+             struct minimal_symbol *msymbol,
+             struct symtabs_and_lines *result)
+{
+  struct gdbarch *gdbarch = get_objfile_arch (objfile);
+  CORE_ADDR pc;
+  struct symtab_and_line sal;
+
+  sal = find_pc_sect_line (SYMBOL_VALUE_ADDRESS (msymbol),
+                          (struct obj_section *) 0, 0);
+  sal.section = SYMBOL_OBJ_SECTION (msymbol);
+
+  /* The minimal symbol might point to a function descriptor;
+     resolve it to the actual code address instead.  */
+  pc = gdbarch_convert_from_func_ptr_addr (gdbarch, sal.pc, &current_target);
+  if (pc != sal.pc)
+    sal = find_pc_sect_line (pc, NULL, 0);
+
+  if (self->funfirstline)
+    skip_prologue_sal (&sal);
 
-  sym = lookup_symbol (copy,
-                      (file_symtab
-                       ? BLOCKVECTOR_BLOCK (BLOCKVECTOR (file_symtab),
-                                            STATIC_BLOCK)
-                       : get_selected_block (0)),
-                      VAR_DOMAIN, 0);
+  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.  */
+
+static void
+check_minsym (struct minimal_symbol *minsym, void *d)
+{
+  struct collect_info *info = 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)
+    {
+      /* When FUNFIRSTLINE, only allow text symbols.  */
+    }
+  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);
+}
 
-  if (sym != NULL)
-    return symbol_found (funfirstline, canonical, copy, sym, file_symtab);
+/* Search minimal symbols in all objfiles for NAME.  If SEARCH_PSPACE
+   is not NULL, the search is restricted to just that program
+   space.  */
 
-  msymbol = lookup_minimal_symbol (copy, NULL, NULL);
+static void
+search_minsyms_for_name (struct collect_info *info, const char *name,
+                        struct program_space *search_pspace)
+{
+  struct objfile *objfile;
+  struct program_space *pspace;
 
-  if (msymbol != NULL)
-    return minsym_found (funfirstline, msymbol);
+  ALL_PSPACES (pspace)
+  {
+    if (search_pspace != NULL && search_pspace != pspace)
+      continue;
+    if (pspace->executing_startup)
+      continue;
 
-  if (not_found_ptr)
-    *not_found_ptr = 1;
+    set_current_program_space (pspace);
+
+    ALL_OBJFILES (objfile)
+    {
+      info->objfile = objfile;
+      iterate_over_minimal_symbols (objfile, name, check_minsym, info);
+    }
+  }
+}
+
+/* A helper function to add all symbols matching NAME to INFO.  If
+   PSPACE is not NULL, the search is restricted to just that program
+   space.  */
+
+static void
+add_matching_symbols_to_info (const char *name,
+                             struct collect_info *info,
+                             struct program_space *pspace)
+{
+  int ix;
+  struct symtab *elt;
+
+  for (ix = 0; VEC_iterate (symtab_p, info->state->file_symtabs, ix, elt); ++ix)
+    {
+      struct symbol *sym;
+
+      if (elt == NULL)
+       {
+         iterate_over_all_matching_symtabs (name, VAR_DOMAIN,
+                                            collect_symbols, info,
+                                            pspace);
+         search_minsyms_for_name (info, name, pspace);
+       }
+      else if (pspace == NULL || pspace == SYMTAB_PSPACE (elt))
+       {
+         /* 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));
+         LA_ITERATE_OVER_SYMBOLS (get_search_block (elt), name,
+                                  VAR_DOMAIN, collect_symbols,
+                                  info);
+       }
+    }
+}
+
+/* Decode a linespec that's a variable.  If FILE_SYMTAB is non-NULL,
+   look in that symtab's static variables first.  */ 
+
+static struct symtabs_and_lines
+decode_variable (struct linespec_state *self, char *copy)
+{
+  struct collect_info info;
+  const char *lookup_name;
+  char *canon;
+  struct cleanup *cleanup;
+
+  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);
+  if (current_language->la_language == language_ada)
+    {
+      /* In Ada, the symbol lookups are performed using the encoded
+         name rather than the demangled name.  */
+      lookup_name = ada_name_for_lookup (copy);
+      make_cleanup (xfree, (void *) lookup_name);
+    }
+
+  canon = cp_canonicalize_string_no_typedefs (lookup_name);
+  if (canon != NULL)
+    {
+      make_cleanup (xfree, canon);
+      lookup_name = canon;
+    }
+
+  add_matching_symbols_to_info (lookup_name, &info, NULL);
+
+  if (info.result.nelts > 0)
+    {
+      if (self->canonical)
+       {
+         self->canonical->pre_expanded = 1;
+         if (self->user_filename)
+           self->canonical->addr_string
+             = xstrprintf ("%s:%s", self->user_filename, copy);
+         else
+           self->canonical->addr_string = xstrdup (copy);
+       }
+      return info.result;
+    }
 
   if (!have_full_symbols ()
       && !have_partial_symbols ()
       && !have_minimal_symbols ())
     throw_error (NOT_FOUND_ERROR,
                 _("No symbol table is loaded.  Use the \"file\" command."));
-  throw_error (NOT_FOUND_ERROR, _("Function \"%s\" not defined."), copy);
+  if (self->user_filename)
+    throw_error (NOT_FOUND_ERROR, _("Function \"%s\" not defined in \"%s\"."),
+                copy, self->user_filename);
+  else
+    throw_error (NOT_FOUND_ERROR, _("Function \"%s\" not defined."), copy);
 }
 
 
@@ -1930,93 +2862,82 @@ decode_variable (char *copy, int funfirstline, char ***canonical,
 /* Now come some functions that are called from multiple places within
    decode_line_1.  */
 
-/* We've found a symbol SYM to associate with our linespec; build a
-   corresponding struct symtabs_and_lines.  */
-
-static struct symtabs_and_lines
-symbol_found (int funfirstline, char ***canonical, char *copy,
-             struct symbol *sym, struct symtab *file_symtab)
+static int
+symbol_to_sal (struct symtab_and_line *result,
+              int funfirstline, struct symbol *sym)
 {
-  struct symtabs_and_lines values;
-  
   if (SYMBOL_CLASS (sym) == LOC_BLOCK)
     {
-      /* Arg is the name of a function.  */
-      values.sals = (struct symtab_and_line *)
-       xmalloc (sizeof (struct symtab_and_line));
-      values.sals[0] = find_function_start_sal (sym, funfirstline);
-      values.nelts = 1;
-
-      /* Don't use the SYMBOL_LINE; if used at all it points to
-        the line containing the parameters or thereabouts, not
-        the first line of code.  */
-
-      /* We might need a canonical line spec if it is a static
-        function.  */
-      if (file_symtab == 0)
-       {
-         struct blockvector *bv = BLOCKVECTOR (SYMBOL_SYMTAB (sym));
-         struct block *b = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK);
-
-         if (lookup_block_symbol (b, copy, VAR_DOMAIN) != NULL)
-           build_canonical_line_spec (values.sals, copy, canonical);
-       }
-      return values;
+      *result = find_function_start_sal (sym, funfirstline);
+      return 1;
     }
   else
     {
-      if (funfirstline && SYMBOL_CLASS (sym) != LOC_LABEL)
-       error (_("\"%s\" is not a function"), copy);
+      if (SYMBOL_CLASS (sym) == LOC_LABEL && SYMBOL_VALUE_ADDRESS (sym) != 0)
+       {
+         init_sal (result);
+         result->symtab = SYMBOL_SYMTAB (sym);
+         result->line = SYMBOL_LINE (sym);
+         result->pc = SYMBOL_VALUE_ADDRESS (sym);
+         result->pspace = SYMTAB_PSPACE (SYMBOL_SYMTAB (sym));
+         result->explicit_pc = 1;
+         return 1;
+       }
+      else if (funfirstline)
+       {
+         /* Nothing.  */
+       }
       else if (SYMBOL_LINE (sym) != 0)
        {
          /* We know its line number.  */
-         values.sals = (struct symtab_and_line *)
-           xmalloc (sizeof (struct symtab_and_line));
-         values.nelts = 1;
-         memset (&values.sals[0], 0, sizeof (values.sals[0]));
-         values.sals[0].symtab = SYMBOL_SYMTAB (sym);
-         values.sals[0].line = SYMBOL_LINE (sym);
-         values.sals[0].pspace = SYMTAB_PSPACE (SYMBOL_SYMTAB (sym));
-         return values;
+         init_sal (result);
+         result->symtab = SYMBOL_SYMTAB (sym);
+         result->line = SYMBOL_LINE (sym);
+         result->pspace = SYMTAB_PSPACE (SYMBOL_SYMTAB (sym));
+         return 1;
        }
-      else
-       /* This can happen if it is compiled with a compiler which doesn't
-          put out line numbers for variables.  */
-       /* FIXME: Shouldn't we just set .line and .symtab to zero
-          and return?  For example, "info line foo" could print
-          the address.  */
-       error (_("Line number not known for symbol \"%s\""), copy);
     }
+
+  return 0;
 }
 
-/* We've found a minimal symbol MSYMBOL to associate with our
-   linespec; build a corresponding struct symtabs_and_lines.  */
+/* See the comment in linespec.h.  */
 
-static struct symtabs_and_lines
-minsym_found (int funfirstline, struct minimal_symbol *msymbol)
+void
+init_linespec_result (struct linespec_result *lr)
 {
-  struct objfile *objfile = msymbol_objfile (msymbol);
-  struct gdbarch *gdbarch = get_objfile_arch (objfile);
-  struct symtabs_and_lines values;
-  CORE_ADDR pc;
+  memset (lr, 0, sizeof (*lr));
+}
 
-  values.sals = (struct symtab_and_line *)
-    xmalloc (sizeof (struct symtab_and_line));
-  values.sals[0] = find_pc_sect_line (SYMBOL_VALUE_ADDRESS (msymbol),
-                                     (struct obj_section *) 0, 0);
-  values.sals[0].section = SYMBOL_OBJ_SECTION (msymbol);
+/* See the comment in linespec.h.  */
 
-  /* The minimal symbol might point to a function descriptor;
-     resolve it to the actual code address instead.  */
-  pc = gdbarch_convert_from_func_ptr_addr (gdbarch,
-                                           values.sals[0].pc,
-                                           &current_target);
-  if (pc != values.sals[0].pc)
-    values.sals[0] = find_pc_sect_line (pc, NULL, 0);
+void
+destroy_linespec_result (struct linespec_result *ls)
+{
+  int i;
+  struct linespec_sals *lsal;
 
-  if (funfirstline)
-    skip_prologue_sal (&values.sals[0]);
+  xfree (ls->addr_string);
+  for (i = 0; VEC_iterate (linespec_sals, ls->sals, i, lsal); ++i)
+    {
+      xfree (lsal->canonical);
+      xfree (lsal->sals.sals);
+    }
+  VEC_free (linespec_sals, ls->sals);
+}
 
-  values.nelts = 1;
-  return values;
+/* Cleanup function for a linespec_result.  */
+
+static void
+cleanup_linespec_result (void *a)
+{
+  destroy_linespec_result (a);
+}
+
+/* See the comment in linespec.h.  */
+
+struct cleanup *
+make_cleanup_destroy_linespec_result (struct linespec_result *ls)
+{
+  return make_cleanup (cleanup_linespec_result, ls);
 }
This page took 0.060044 seconds and 4 git commands to generate.