Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Joel Brobecker <brobecker@adacore.com>
To: gdb-patches@sourceware.org
Subject: Re: [RFC/RFA] handle function homonyms in breakpoint expressions
Date: Wed, 02 Jan 2008 10:50:00 -0000	[thread overview]
Message-ID: <20080102104506.GC15903@adacore.com> (raw)
In-Reply-To: <20080101194709.GB3758@adacore.com>

[-- Attachment #1: Type: text/plain, Size: 2288 bytes --]

> The idea is to short-circuit the end of decode_line_1 and call the
> Ada-specific part instead, like so:
> 
>    else if (current_language->la_language == language_ada)
>      {
>        return ada_finish_decode_line_1 (argptr, file_symtab, funfirstline,
>                                         canonical, not_found_ptr);
>      }

Actually, I forgot one small piece.  Inside linespec.c:locate_first_half,
we need to do handle the parsing a little bit differently for Ada.
This is because we re-write the breakpoint location expression in
a canonical form that is unambiguous. For that, we use the form
FILE:FUN_NAME:LINE_NO. As a result, the parsing needs to be adjusted
for Ada. We do this by adding the following code in locate_first_half:

  if (current_language->la_language == language_ada)
    p = ada_start_decode_line_1 (*argptr, *is_quote_enclosed);
  else for (; *p; p++)
    [do the normal expression splitting]

Without the above, we managed to insert the breakpoint, but once
we run the program, the breakpoint re-evaluations fail and, causing
these breakpoints to be unexpectedly disabled.

The new patch is identical to the previous one, with the addition of
ada_start_decode_line_1, and a call to that function in linespec.c.

New ChangeLog:

2008-01-02  Joel Brobecker  <brobecker@adacore.com>
        
        * ada-lang.c (get_selections): Set prompt explicitly when calling
        command_line_input, or it will print the GDB prompt.
        (can_use_symbol_on_breakpoint, discard_non_breakpoint_matches)
        (ada_finish_decode_line_1, find_sal_from_funcs_and_line)
        (find_line_in_linetable, nearest_line_number_in_linetable)
        (find_next_line_in_linetable, is_plausible_func_for_line)
        (read_all_symtabs, ada_sals_for_line, extended_canonical_line_spec)
        (adjust_pc_past_prologue, ada_start_decode_line_1): New functions.
        * ada-lang.h (ada_start_decode_line_1): Update profile.
        (ada_finish_decode_line_1): Likewise.
        * linespec.c: #include ada-lang.h.
        (decode_line_1): Add call to ada_finish_decode_line_1.
        (locate_first_half): Add call to ada_start_decode_line_1.
        * Makefile.in (linespec.o): Update dependencies.
    
Tested on x86-linux. No regression.
Thoughts?

Thanks,
-- 
Joel

[-- Attachment #2: overload.diff --]
[-- Type: text/plain, Size: 30838 bytes --]

Index: ada-lang.c
===================================================================
--- ada-lang.c	(revision 36)
+++ ada-lang.c	(revision 37)
@@ -219,6 +219,21 @@ static int is_name_suffix (const char *)
 
 static int wild_match (const char *, int, const char *);
 
+static char *extended_canonical_line_spec (struct symtab_and_line,
+                                           const char *);
+static struct symtabs_and_lines
+  find_sal_from_funcs_and_line (const char *, int,
+                                struct ada_symbol_info *, int);
+
+static int find_line_in_linetable (struct linetable *, int,
+                                   struct ada_symbol_info *, int, int *);
+
+static int find_next_line_in_linetable (struct linetable *, int, int, int);
+
+static void read_all_symtabs (const char *);
+
+static int is_plausible_func_for_line (struct symbol *, int);
+
 static struct value *ada_coerce_ref (struct value *);
 
 static LONGEST pos_atr (struct value *);
@@ -244,6 +259,8 @@ static struct value *ada_to_fixed_value_
 
 static struct value *ada_to_fixed_value (struct value *);
 
+static void adjust_pc_past_prologue (CORE_ADDR *);
+
 static int ada_resolve_function (struct ada_symbol_info *, int,
                                  struct value **, int, const char *,
                                  struct type *);
@@ -3459,18 +3476,14 @@ get_selections (int *choices, int n_choi
                 int is_all_choice, char *annotation_suffix)
 {
   char *args;
-  const char *prompt;
+  char *prompt;
   int n_chosen;
   int first_choice = is_all_choice ? 2 : 1;
 
   prompt = getenv ("PS2");
   if (prompt == NULL)
-    prompt = ">";
-
-  printf_unfiltered (("%s "), prompt);
-  gdb_flush (gdb_stdout);
-
-  args = command_line_input ((char *) NULL, 0, annotation_suffix);
+    prompt = "> ";
+  args = command_line_input (prompt, 0, annotation_suffix);
 
   if (args == NULL)
     error_no_arg (_("one or more choice numbers"));
@@ -5714,6 +5727,797 @@ ada_make_symbol_completion_list (char *t
   return (result.array);
 }
 
+                                /* Breakpoint-related */
+
+/* Return non-zero if INFO refers to a symbol that can be used
+   to insert a breakpoint.  */
+
+static int
+can_use_symbol_on_breakpoint (struct ada_symbol_info info)
+{
+  /* We can break on symbols that represent code blocks such as
+     functions for instance.  */
+
+  if (SYMBOL_CLASS (info.sym) == LOC_BLOCK)
+    return 1;
+
+  /* brobecker/2005-11-11: There are probably many other classes
+     of symbols that can be excluded in this function.  But it is
+     preferable for this function to ere on the cautious side, to
+     make sure we do not remove a choice that's legitimate.  It is
+     better to present the user with more choice, even if some
+     of them do not make sense, rather than deprive him of some
+     of the legitimate option.  */
+
+  /* If a line number is associated to it, then it probably means
+     that we can use this symbol as a breakpoint location.  */
+
+  if (SYMBOL_LINE (info.sym) != 0)
+    return 1;
+
+  /* All other symbols are not suitable for use in a breakpoint
+     location expression.  */
+
+  return 0;
+}
+
+/* Remove from SYMS any symbol that cannot be used to insert a breakpoint.
+   Return the new number of symbols in SYMS.  */
+
+static int
+discard_non_breakpoint_matches (struct ada_symbol_info *syms, int nsyms)
+{
+  int i = 0;
+
+  while (i < nsyms)
+    {
+      if (!can_use_symbol_on_breakpoint (syms[i]))
+        {
+          int j;
+
+          for (j = i; j < nsyms - 1; j++)
+            syms[j] = syms[j+1];
+          nsyms--;
+        }
+      i++;
+    }
+
+  return nsyms;
+}
+
+/* Assuming that LINE is pointing at the beginning of an argument to
+   'break', return a pointer to the delimiter for the initial segment
+   of that name.  This is the first ':', ' ', or end of LINE.
+   
+   If IS_QUOTE_ENCLOSED is non-zero, then spaces are not considered
+   as an argument delimiter.  */
+
+char *
+ada_start_decode_line_1 (char *line, int is_quote_enclosed)
+{
+  char *p = line;
+
+#ifdef __MINGW32__
+  /* On windows hosts, filenames may start with a drive letter.
+     Do not confuse the colon following the drive letter with
+     the actual colon that separates the filename from the rest
+     of the breakpoint location expression.  
+
+     There is a slight ambiguity because, in Ada, the breakpoint
+     location can use the filename:function:line syntax, and the
+     first colon in a Windows filename could be mistaken for the
+     filename to function separator.  But filenames with only
+     one character and no extension are really odd and rare, so
+     we should probably never guess wrong if we consider that
+     a single character followed by a colon is a drive letter.  */
+  if (p[0] != '\0' && p[1] != '\0' && isalpha (p[0]) && p[1] == ':')
+    p = p + 2;
+#endif
+  
+  for (; *p != '\000'; p++)
+    if (*p == ':' || (!is_quote_enclosed && *p == ' '))
+      break;
+
+  return p;
+}
+
+/* *SPEC points to a function and line number spec (as in a break
+   command), following any initial file name specification.
+
+   Return all symbol table/line specfications (sals) consistent with the
+   information in *SPEC and FILE_TABLE in the following sense:
+     + FILE_TABLE is null, or the sal refers to a line in the file
+       named by FILE_TABLE.
+     + If *SPEC points to an argument with a trailing ':LINENUM',
+       then the sal refers to that line (or one following it as closely as
+       possible).
+     + If *SPEC does not start with '*', the sal is in a function with
+       that name.
+
+   Returns with 0 elements if no matching non-minimal symbols found.
+
+   If *SPEC begins with a function name of the form <NAME>, then NAME
+   is taken as a literal name; otherwise the function name is subject
+   to the usual encoding.
+
+   *SPEC is updated to point after the function/line number specification.
+
+   FUNFIRSTLINE is non-zero if we desire the first line of real code
+   in each function.
+
+   If CANONICAL is non-NULL, and if any of the sals require a
+   'canonical line spec', then *CANONICAL is set to point to an array
+   of strings, corresponding to and equal in length to the returned
+   list of sals, such that (*CANONICAL)[i] is non-null and contains a
+   canonical line spec for the ith returned sal, if needed.  If no
+   canonical line specs are required and CANONICAL is non-null,
+   *CANONICAL is set to NULL.
+
+   A 'canonical line spec' is simply a name (in the format of the
+   breakpoint command) that uniquely identifies a breakpoint position,
+   with no further contextual information or user selection.  It is
+   needed whenever the file name, function name, and line number
+   information supplied is insufficient for this unique
+   identification.  Currently overloaded functions, the name '*',
+   or static functions without a filename yield a canonical line spec.
+   The array and the line spec strings are allocated on the heap; it
+   is the caller's responsibility to free them.  */
+
+struct symtabs_and_lines
+ada_finish_decode_line_1 (char **spec, struct symtab *file_table,
+                          int funfirstline, char ***canonical,
+                          int *not_found_ptr)
+{
+  struct ada_symbol_info *symbols;
+  const struct block *block;
+  int n_matches, i, line_num;
+  struct symtabs_and_lines selected;
+  struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
+  char *name;
+  int is_quoted;
+
+  int len;
+  char *lower_name;
+  char *unquoted_name;
+
+  if (file_table == NULL)
+    block = block_static_block (get_selected_block (0));
+  else
+    block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (file_table), STATIC_BLOCK);
+
+  if (canonical != NULL)
+    *canonical = (char **) NULL;
+
+  is_quoted = (**spec && strchr (get_gdb_completer_quote_characters (),
+                                 **spec) != NULL);
+
+  name = *spec;
+  if (**spec == '*')
+    *spec += 1;
+  else
+    {
+      if (is_quoted)
+        *spec = skip_quoted (*spec);
+      while (**spec != '\000'
+             && !strchr (ada_completer_word_break_characters, **spec))
+        *spec += 1;
+    }
+  len = *spec - name;
+
+  line_num = -1;
+  if (file_table != NULL && (*spec)[0] == ':' && isdigit ((*spec)[1]))
+    {
+      line_num = strtol (*spec + 1, spec, 10);
+      while (**spec == ' ' || **spec == '\t')
+        *spec += 1;
+    }
+
+  if (name[0] == '*')
+    {
+      if (line_num == -1)
+        error (_("Wild-card function with no line number or file name."));
+
+      return ada_sals_for_line (file_table->filename, line_num,
+                                funfirstline, canonical, 0);
+    }
+
+  if (name[0] == '\'')
+    {
+      name += 1;
+      len -= 2;
+    }
+
+  if (name[0] == '<')
+    {
+      unquoted_name = (char *) alloca (len - 1);
+      memcpy (unquoted_name, name + 1, len - 2);
+      unquoted_name[len - 2] = '\000';
+      lower_name = NULL;
+    }
+  else
+    {
+      unquoted_name = (char *) alloca (len + 1);
+      memcpy (unquoted_name, name, len);
+      unquoted_name[len] = '\000';
+      lower_name = (char *) alloca (len + 1);
+      for (i = 0; i < len; i += 1)
+        lower_name[i] = tolower (name[i]);
+      lower_name[len] = '\000';
+    }
+
+  n_matches = 0;
+  if (lower_name != NULL)
+    n_matches = ada_lookup_symbol_list (ada_encode (lower_name), block,
+                                        VAR_DOMAIN, &symbols);
+  if (n_matches == 0)
+    n_matches = ada_lookup_symbol_list (unquoted_name, block,
+                                        VAR_DOMAIN, &symbols);
+  if (n_matches == 0 && line_num >= 0)
+    error (_("No line number information found for %s."), unquoted_name);
+  else if (n_matches == 0)
+    {
+      struct symtab_and_line val;
+      struct minimal_symbol *msymbol;
+
+      init_sal (&val);
+
+      msymbol = NULL;
+      if (lower_name != NULL)
+        msymbol = ada_lookup_simple_minsym (ada_encode (lower_name));
+      if (msymbol == NULL)
+        msymbol = ada_lookup_simple_minsym (unquoted_name);
+      if (msymbol != NULL)
+        {
+          val.pc = SYMBOL_VALUE_ADDRESS (msymbol);
+          val.section = SYMBOL_BFD_SECTION (msymbol);
+          if (funfirstline)
+            {
+              val.pc = gdbarch_convert_from_func_ptr_addr (current_gdbarch,
+							   val.pc,
+							   &current_target);
+              gdbarch_skip_prologue (current_gdbarch, val.pc);
+            }
+          selected.sals = (struct symtab_and_line *)
+            xmalloc (sizeof (struct symtab_and_line));
+          selected.sals[0] = val;
+          selected.nelts = 1;
+          return selected;
+        }
+
+      if (!have_full_symbols ()
+          && !have_partial_symbols () && !have_minimal_symbols ())
+        error (_("No symbol table is loaded.  Use the \"file\" command."));
+      if (not_found_ptr)
+	*not_found_ptr = 1;
+      throw_error (NOT_FOUND_ERROR, _("Function \"%s\" not defined."), 
+                   unquoted_name);
+      return selected;          /* for lint */
+    }
+
+  if (line_num >= 0)
+    {
+      struct symtabs_and_lines best_sal =
+        find_sal_from_funcs_and_line (file_table->filename, line_num,
+                                      symbols, n_matches);
+      if (funfirstline)
+        adjust_pc_past_prologue (&best_sal.sals[0].pc);
+      return best_sal;
+    }
+  else
+    {
+      n_matches = discard_non_breakpoint_matches (symbols, n_matches);
+      selected.nelts = user_select_syms (symbols, n_matches, n_matches);
+    }
+
+  selected.sals = (struct symtab_and_line *)
+    xmalloc (sizeof (struct symtab_and_line) * selected.nelts);
+  memset (selected.sals, 0, selected.nelts * sizeof (selected.sals[i]));
+  make_cleanup (xfree, selected.sals);
+
+  i = 0;
+  while (i < selected.nelts)
+    {
+      if (SYMBOL_CLASS (symbols[i].sym) == LOC_BLOCK)
+        selected.sals[i]
+          = find_function_start_sal (symbols[i].sym, funfirstline);
+      else if (SYMBOL_LINE (symbols[i].sym) != 0)
+        {
+          selected.sals[i].symtab =
+            symbols[i].symtab
+            ? symbols[i].symtab : symtab_for_sym (symbols[i].sym);
+          selected.sals[i].line = SYMBOL_LINE (symbols[i].sym);
+        }
+      else if (line_num >= 0)
+        {
+          /* Ignore this choice */
+          symbols[i] = symbols[selected.nelts - 1];
+          selected.nelts -= 1;
+          continue;
+        }
+      else
+        error (_("Line number not known for symbol \"%s\""), unquoted_name);
+      i += 1;
+    }
+
+  if (canonical != NULL && (line_num >= 0 || n_matches > 1))
+    {
+      *canonical = (char **) xmalloc (sizeof (char *) * selected.nelts);
+      for (i = 0; i < selected.nelts; i += 1)
+        (*canonical)[i] =
+          extended_canonical_line_spec (selected.sals[i],
+                                        SYMBOL_PRINT_NAME (symbols[i].sym));
+    }
+
+  discard_cleanups (old_chain);
+  return selected;
+}
+
+/* The (single) sal corresponding to line LINE_NUM in a symbol table
+   with file name FILENAME that occurs in one of the functions listed
+   in the symbol fields of SYMBOLS[0 .. NSYMS-1].  */
+
+static struct symtabs_and_lines
+find_sal_from_funcs_and_line (const char *filename, int line_num,
+                              struct ada_symbol_info *symbols, int nsyms)
+{
+  struct symtabs_and_lines sals;
+  int best_index, best;
+  struct linetable *best_linetable;
+  struct objfile *objfile;
+  struct symtab *s;
+  struct symtab *best_symtab;
+
+  read_all_symtabs (filename);
+
+  best_index = 0;
+  best_linetable = NULL;
+  best_symtab = NULL;
+  best = 0;
+  ALL_SYMTABS (objfile, s)
+  {
+    struct linetable *l;
+    int ind, exact;
+
+    QUIT;
+
+    if (strcmp (filename, s->filename) != 0)
+      continue;
+    l = LINETABLE (s);
+    ind = find_line_in_linetable (l, line_num, symbols, nsyms, &exact);
+    if (ind >= 0)
+      {
+        if (exact)
+          {
+            best_index = ind;
+            best_linetable = l;
+            best_symtab = s;
+            goto done;
+          }
+        if (best == 0 || l->item[ind].line < best)
+          {
+            best = l->item[ind].line;
+            best_index = ind;
+            best_linetable = l;
+            best_symtab = s;
+          }
+      }
+  }
+
+  if (best == 0)
+    error (_("Line number not found in designated function."));
+
+done:
+
+  sals.nelts = 1;
+  sals.sals = (struct symtab_and_line *) xmalloc (sizeof (sals.sals[0]));
+
+  init_sal (&sals.sals[0]);
+
+  sals.sals[0].line = best_linetable->item[best_index].line;
+  sals.sals[0].pc = best_linetable->item[best_index].pc;
+  sals.sals[0].symtab = best_symtab;
+
+  return sals;
+}
+
+/* Return the index in LINETABLE of the best match for LINE_NUM whose
+   pc falls within one of the functions denoted by the symbol fields
+   of SYMBOLS[0..NSYMS-1].  Set *EXACTP to 1 if the match is exact, 
+   and 0 otherwise.  */
+
+static int
+find_line_in_linetable (struct linetable *linetable, int line_num,
+                        struct ada_symbol_info *symbols, int nsyms,
+                        int *exactp)
+{
+  int i, len, best_index, best;
+
+  if (line_num <= 0 || linetable == NULL)
+    return -1;
+
+  len = linetable->nitems;
+  for (i = 0, best_index = -1, best = 0; i < len; i += 1)
+    {
+      int k;
+      struct linetable_entry *item = &(linetable->item[i]);
+
+      for (k = 0; k < nsyms; k += 1)
+        {
+          if (symbols[k].sym != NULL
+              && SYMBOL_CLASS (symbols[k].sym) == LOC_BLOCK
+              && item->pc >= BLOCK_START (SYMBOL_BLOCK_VALUE (symbols[k].sym))
+              && item->pc < BLOCK_END (SYMBOL_BLOCK_VALUE (symbols[k].sym)))
+            goto candidate;
+        }
+      continue;
+
+    candidate:
+
+      if (item->line == line_num)
+        {
+          *exactp = 1;
+          return i;
+        }
+
+      if (item->line > line_num && (best == 0 || item->line < best))
+        {
+          best = item->line;
+          best_index = i;
+        }
+    }
+
+  *exactp = 0;
+  return best_index;
+}
+
+/* Find the smallest k >= LINE_NUM such that k is a line number in
+   LINETABLE, and k falls strictly within a named function that begins at
+   or before LINE_NUM.  Return -1 if there is no such k.  */
+
+static int
+nearest_line_number_in_linetable (struct linetable *linetable, int line_num)
+{
+  int i, len, best;
+
+  if (line_num <= 0 || linetable == NULL || linetable->nitems == 0)
+    return -1;
+  len = linetable->nitems;
+
+  i = 0;
+  best = INT_MAX;
+  while (i < len)
+    {
+      struct linetable_entry *item = &(linetable->item[i]);
+
+      if (item->line >= line_num && item->line < best)
+        {
+          char *func_name;
+          CORE_ADDR start, end;
+
+          func_name = NULL;
+          find_pc_partial_function (item->pc, &func_name, &start, &end);
+
+          if (func_name != NULL && item->pc < end)
+            {
+              if (item->line == line_num)
+                return line_num;
+              else
+                {
+                  struct symbol *sym =
+                    standard_lookup (func_name, NULL, VAR_DOMAIN);
+                  if (is_plausible_func_for_line (sym, line_num))
+                    best = item->line;
+                  else
+                    {
+                      do
+                        i += 1;
+                      while (i < len && linetable->item[i].pc < end);
+                      continue;
+                    }
+                }
+            }
+        }
+
+      i += 1;
+    }
+
+  return (best == INT_MAX) ? -1 : best;
+}
+
+
+/* Return the next higher index, k, into LINETABLE such that k > IND,
+   entry k in LINETABLE has a line number equal to LINE_NUM, k
+   corresponds to a PC that is in a function different from that
+   corresponding to IND, and falls strictly within a named function
+   that begins at a line at or preceding STARTING_LINE.
+   Return -1 if there is no such k.
+   IND == -1 corresponds to no function.  */
+
+static int
+find_next_line_in_linetable (struct linetable *linetable, int line_num,
+                             int starting_line, int ind)
+{
+  int i, len;
+
+  if (line_num <= 0 || linetable == NULL || ind >= linetable->nitems)
+    return -1;
+  len = linetable->nitems;
+
+  if (ind >= 0)
+    {
+      CORE_ADDR start, end;
+
+      if (find_pc_partial_function (linetable->item[ind].pc,
+                                    (char **) NULL, &start, &end))
+        {
+          while (ind < len && linetable->item[ind].pc < end)
+            ind += 1;
+        }
+      else
+        ind += 1;
+    }
+  else
+    ind = 0;
+
+  i = ind;
+  while (i < len)
+    {
+      struct linetable_entry *item = &(linetable->item[i]);
+
+      if (item->line >= line_num)
+        {
+          char *func_name;
+          CORE_ADDR start, end;
+
+          func_name = NULL;
+          find_pc_partial_function (item->pc, &func_name, &start, &end);
+
+          if (func_name != NULL && item->pc < end)
+            {
+              if (item->line == line_num)
+                {
+                  struct symbol *sym =
+                    standard_lookup (func_name, NULL, VAR_DOMAIN);
+                  if (is_plausible_func_for_line (sym, starting_line))
+                    return i;
+                  else
+                    {
+                      while ((i + 1) < len && linetable->item[i + 1].pc < end)
+                        i += 1;
+                    }
+                }
+            }
+        }
+      i += 1;
+    }
+
+  return -1;
+}
+
+/* True iff function symbol SYM starts somewhere at or before line #
+   LINE_NUM.  */
+
+static int
+is_plausible_func_for_line (struct symbol *sym, int line_num)
+{
+  struct symtab_and_line start_sal;
+
+  if (sym == NULL)
+    return 0;
+
+  start_sal = find_function_start_sal (sym, 0);
+
+  return (start_sal.line != 0 && line_num >= start_sal.line);
+}
+
+/* Read in all symbol tables corresponding to partial symbol tables
+   with file name FILENAME.  */
+
+static void
+read_all_symtabs (const char *filename)
+{
+  struct partial_symtab *ps;
+  struct objfile *objfile;
+
+  ALL_PSYMTABS (objfile, ps)
+  {
+    QUIT;
+
+    if (strcmp (filename, ps->filename) == 0)
+      PSYMTAB_TO_SYMTAB (ps);
+  }
+}
+
+/* All sals corresponding to line LINE_NUM in a symbol table from file
+   FILENAME, as filtered by the user.  Filter out any lines that
+   reside in functions with "suppressed" names (not corresponding to
+   explicit Ada functions), if there is at least one in a function
+   with a non-suppressed name.  If CANONICAL is not null, set
+   it to a corresponding array of canonical line specs.
+   If ONE_LOCATION_ONLY is set and several matches are found for
+   the given location, then automatically select the first match found
+   instead of asking the user which instance should be returned.  */
+
+struct symtabs_and_lines
+ada_sals_for_line (const char *filename, int line_num,
+                   int funfirstline, char ***canonical, int one_location_only)
+{
+  struct symtabs_and_lines result;
+  struct objfile *objfile;
+  struct symtab *s;
+  struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
+  size_t len;
+
+  read_all_symtabs (filename);
+
+  result.sals =
+    (struct symtab_and_line *) xmalloc (4 * sizeof (result.sals[0]));
+  result.nelts = 0;
+  len = 4;
+  make_cleanup (free_current_contents, &result.sals);
+
+  ALL_SYMTABS (objfile, s)
+  {
+    int ind, target_line_num;
+
+    QUIT;
+
+    if (strcmp (s->filename, filename) != 0)
+      continue;
+
+    target_line_num =
+      nearest_line_number_in_linetable (LINETABLE (s), line_num);
+    if (target_line_num == -1)
+      continue;
+
+    ind = -1;
+    while (1)
+      {
+        ind =
+          find_next_line_in_linetable (LINETABLE (s),
+                                       target_line_num, line_num, ind);
+
+        if (ind < 0)
+          break;
+
+        GROW_VECT (result.sals, len, result.nelts + 1);
+        init_sal (&result.sals[result.nelts]);
+        result.sals[result.nelts].line = line_num;
+        result.sals[result.nelts].pc = LINETABLE (s)->item[ind].pc;
+        result.sals[result.nelts].symtab = s;
+
+        if (funfirstline)
+          adjust_pc_past_prologue (&result.sals[result.nelts].pc);
+
+        result.nelts += 1;
+      }
+  }
+
+  if (canonical != NULL || result.nelts > 1)
+    {
+      int k, j, n;
+      char **func_names = (char **) alloca (result.nelts * sizeof (char *));
+      int first_choice = (result.nelts > 1) ? 2 : 1;
+      int *choices = (int *) alloca (result.nelts * sizeof (int));
+
+      for (k = 0; k < result.nelts; k += 1)
+        {
+          find_pc_partial_function (result.sals[k].pc, &func_names[k],
+                                    (CORE_ADDR *) NULL, (CORE_ADDR *) NULL);
+          if (func_names[k] == NULL)
+            error (_("Could not find function for one or more breakpoints."));
+        }
+
+      /* Remove suppressed names, unless all are suppressed.  */
+      for (j = 0; j < result.nelts; j += 1)
+        if (!is_suppressed_name (func_names[j]))
+          {
+            /* At least one name is unsuppressed, so remove all
+               suppressed names.  */
+            for (k = n = 0; k < result.nelts; k += 1)
+              if (!is_suppressed_name (func_names[k]))
+                {
+                  func_names[n] = func_names[k];
+                  result.sals[n] = result.sals[k];
+                  n += 1;
+                }
+            result.nelts = n;
+            break;
+          }
+
+      if (result.nelts > 1)
+        {
+          if (one_location_only)
+            {
+              /* Automatically select the first of all possible choices.  */
+              n = 1;
+              choices[0] = 0;
+            }
+          else
+            {
+              printf_unfiltered ("[0] cancel\n");
+              if (result.nelts > 1)
+                printf_unfiltered ("[1] all\n");
+              for (k = 0; k < result.nelts; k += 1)
+                printf_unfiltered ("[%d] %s\n", k + first_choice,
+                                   ada_decode (func_names[k]));
+
+              n = get_selections (choices, result.nelts, result.nelts,
+                                  result.nelts > 1, "instance-choice");
+            }
+
+          for (k = 0; k < n; k += 1)
+            {
+              result.sals[k] = result.sals[choices[k]];
+              func_names[k] = func_names[choices[k]];
+            }
+          result.nelts = n;
+        }
+
+      if (canonical != NULL && result.nelts == 0)
+        *canonical = NULL;
+      else if (canonical != NULL)
+        {
+          *canonical = (char **) xmalloc (result.nelts * sizeof (char **));
+          make_cleanup (xfree, *canonical);
+          for (k = 0; k < result.nelts; k += 1)
+            {
+              (*canonical)[k] =
+                extended_canonical_line_spec (result.sals[k], func_names[k]);
+              if ((*canonical)[k] == NULL)
+                error (_("Could not locate one or more breakpoints."));
+              make_cleanup (xfree, (*canonical)[k]);
+            }
+        }
+    }
+
+  if (result.nelts == 0)
+    {
+      do_cleanups (old_chain);
+      result.sals = NULL;
+    }
+  else
+    discard_cleanups (old_chain);
+  return result;
+}
+
+
+/* A canonical line specification of the form FILE:NAME:LINENUM for
+   symbol table and line data SAL.  NULL if insufficient
+   information.  The caller is responsible for releasing any space
+   allocated.
+   
+   The cannonical form return is enclosed inside double-quotes in order
+   to protect us against spaces embedded inside the file path name.  */
+
+static char *
+extended_canonical_line_spec (struct symtab_and_line sal, const char *name)
+{
+  if (sal.symtab == NULL || sal.symtab->filename == NULL || sal.line <= 0)
+    return NULL;
+
+  
+  return (xstrprintf ("\"%s:'%s':%d\"", sal.symtab->filename, name, sal.line));
+}
+
+/* If the PC is pointing inside a function prologue, then re-adjust it
+   past this prologue.  */
+
+static void
+adjust_pc_past_prologue (CORE_ADDR *pc)
+{
+  struct symbol *func_sym = find_pc_function (*pc);
+
+  if (func_sym)
+    {
+      const struct symtab_and_line sal =
+        find_function_start_sal (func_sym, 1);
+
+      if (*pc <= sal.pc)
+        *pc = sal.pc;
+    }
+}
+
                                 /* Field Access */
 
 /* Return non-zero if TYPE is a pointer to the GNAT dispatch table used
Index: ada-lang.h
===================================================================
--- ada-lang.h	(revision 36)
+++ ada-lang.h	(revision 37)
@@ -333,11 +333,12 @@ extern int user_select_syms (struct ada_
 
 extern int get_selections (int *, int, int, int, char *);
 
-extern char *ada_start_decode_line_1 (char *);
+extern char *ada_start_decode_line_1 (char *, int);
 
 extern struct symtabs_and_lines ada_finish_decode_line_1 (char **,
                                                           struct symtab *,
-                                                          int, char ***);
+                                                          int, char ***,
+                                                          int *);
 
 extern struct symtabs_and_lines ada_sals_for_line (const char*, int,
 						   int, char***, int);
Index: ChangeLog.GNAT
===================================================================
--- ChangeLog.GNAT	(revision 36)
+++ ChangeLog.GNAT	(revision 37)
@@ -1,8 +1,27 @@
 2008-01-01  Joel Brobecker  <brobecker@adacore.com>
  
+	Redo and complete the previous patch.
+
+	* ada-lang.c (get_selections): Set prompt explicitly when calling
+	command_line_input, or it will print the GDB prompt.
+	(can_use_symbol_on_breakpoint, discard_non_breakpoint_matches)
+	(ada_finish_decode_line_1, find_sal_from_funcs_and_line)
+	(find_line_in_linetable, nearest_line_number_in_linetable)
+	(find_next_line_in_linetable, is_plausible_func_for_line)
+	(read_all_symtabs, ada_sals_for_line, extended_canonical_line_spec)
+	(adjust_pc_past_prologue, ada_start_decode_line_1): New functions.
+	* ada-lang.h (ada_start_decode_line_1): Update profile.
+	(ada_finish_decode_line_1): Likewise.
+	* linespec.c: #include ada-lang.h.
+	(decode_line_1): Add call to ada_finish_decode_line_1.
+	(locate_first_half): Add call to ada_start_decode_line_1.
+	* Makefile.in (linespec.o): Update dependencies.
+
+2008-01-01  Joel Brobecker  <brobecker@adacore.com>
+ 
 	*** REVERTED ***  *** REVERTED ***  *** REVERTED ***
-	*** MISSING THE ada_start_decode_line_1 part ***
-	*** WILL REDO THE PATCH - SEE ABOVE ***
+	*** MISSING THE ada_start_decode_line_1 PART ***
+	*** DO NOT SUBMIT - WILL REDO THE PATCH - SEE ABOVE ***
 
 	* ada-lang.c (get_selections): Set prompt explicitly when calling
 	command_line_input, or it will print the GDB prompt.
Index: linespec.c
===================================================================
--- linespec.c	(revision 36)
+++ linespec.c	(revision 37)
@@ -36,6 +36,7 @@
 #include "linespec.h"
 #include "exceptions.h"
 #include "language.h"
+#include "ada-lang.h"
 
 /* We share this one with symtab.c, but it is not exported widely. */
 
@@ -821,6 +822,11 @@ decode_line_1 (char **argptr, int funfir
       /* allow word separators in method names for Obj-C */
       p = skip_quoted_chars (*argptr, NULL, "");
     }
+  else if (current_language->la_language == language_ada)
+    {
+      return ada_finish_decode_line_1 (argptr, file_symtab, funfirstline,
+                                       canonical, not_found_ptr);
+    }
   else if (paren_pointer != NULL)
     {
       p = paren_pointer + 1;
@@ -1014,7 +1020,9 @@ locate_first_half (char **argptr, int *i
     }
   else
     *is_quote_enclosed = 0;
-  for (; *p; p++)
+  if (current_language->la_language == language_ada)
+    p = ada_start_decode_line_1 (*argptr, *is_quote_enclosed);
+  else for (; *p; p++)
     {
       if (p[0] == '<')
 	{
Index: Makefile.in
===================================================================
--- Makefile.in	(revision 36)
+++ Makefile.in	(revision 37)
@@ -2331,7 +2331,8 @@ libunwind-frame.o: libunwind-frame.c $(d
 linespec.o: linespec.c $(defs_h) $(symtab_h) $(frame_h) $(command_h) \
 	$(symfile_h) $(objfiles_h) $(source_h) $(demangle_h) $(value_h) \
 	$(completer_h) $(cp_abi_h) $(parser_defs_h) $(block_h) \
-	$(objc_lang_h) $(linespec_h) $(exceptions_h) $(language_h)
+	$(objc_lang_h) $(linespec_h) $(exceptions_h) $(language_h) \
+	$(ada_lang_h)
 linux-fork.o: linux-fork.c $(defs_h) $(inferior_h) $(regcache_h) $(gdbcmd_h) \
 	$(infcall_h) $(gdb_assert_h) $(gdb_string_h) $(linux_fork_h) \
 	$(linux_nat_h) $(gdb_wait_h) $(gdb_dirent_h)

  reply	other threads:[~2008-01-02 10:50 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-01-01 19:47 Joel Brobecker
2008-01-02 10:50 ` Joel Brobecker [this message]
2008-01-29 18:09   ` Daniel Jacobowitz
2008-01-29 17:40 ` Daniel Jacobowitz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20080102104506.GC15903@adacore.com \
    --to=brobecker@adacore.com \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox