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,
+ ¤t_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)
next prev parent 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