Re: GDB 7.4 branching status? (2011-11-23)

Tom Tromey
2011-11-23T18:47:36Z

>>>>> "Joel" == Joel Brobecker <brobecker@adacore.com> writes:

Joel> - We're still waiting for Tom's awesome work on ambiguous linespec.
Joel> I think he's more or less ready to go, once he's re-based and
Joel> re-posted his patches (with a couple of improvements made for
Joel> the Ada support)

I was composing a note this morning about the issues we were
discussing. I think I will just write it here instead of gdb@.

Joel and Jerome found a couple of bugs in the existing patches.

First, there was an Ada-specific bug that I can't readily describe. I
solved this by adding a new language method, implemented only by Ada,
that basically exposes a form of ada_lookup_symbol_list to linespec. I
will send this separately, today, for review.

Second, it turns out that FILE:LINE linespecs are trickier than they may
first appear. Specifically, the problems arise due to their "inexact
match" semantics" -- if LINE is not seen in a symtab, gdb will pick the
next executable line from the symtab.

This yields a few problems. A simple one is if you have multiple
instances of a symtab where some functions are instantiated in one use
and some in another use -- say, a C++ header with template functions in
it. Then if you "break header.h:LINE", with the current patches you can
wind up with breakpoints in functions that do not actually cover LINE.

This brings up the idea of trying to see "is LINE covered by the
resulting function?". But, this is tough with gdb's current line
tables. For example, the simplest approach of checking the starting
line of the function (let's call this "heuristic 1") fails for this sort
of case:

void function () {
#include "body.h"
}

I think maybe it would be possible to do this by replaying the line
number program, but I am not totally sure.

I implemented another heuristic ("heuristic 2") instead: if the function
is defined in a different symtab, assume it is ok; otherwise, if it is
defined in the same symtab, require that the function's first line be <=
than the requested line.

This heuristic works ok-ish, but there is a specific Ada case that still
fails.

Joel then suggested another heuristic ("heuristic 3"):

Me neither. Our ideas revolved around the idea of marking a SAL as
questionable if it is the first line in the symtab, and its line
number is strictly greater than the requested line number. If we
find other SALs that are not questionable, then discard the questionable
ones.
[...]
If SAL is questionable (using the definition above), and another
symtab contains a function whose line range inclues our target line,
then the SAL should be discarded. This should take care of our
original example involving the generic, and should take care of
the inlining case above as well (this assume that the compiler would
mark the first line of the function to be on line 10, not 11 as my
example suggests).

I am not sure how to implement "and another symtab contains a function
whose line range includes our target line". I am not certain but it
seems to beg the question: if we could determine whether a function
contains a given line, then we could just apply this directly to the
location we just found.

If you are interested in trying to come up with a heuristic, consider
this scenario as well: two files named "file.c". In one file, line 53
is a comment in the middle of a function. In another file, line 53 is
executable. In this case, "break file.c:53" should still set 2
breakpoints.

Another idea I had ("heuristic 4"):

One maybe simpler idea I came up with today is to consider an exact
match in a given symtab, as determined by dirname+filename, to override
all inexact matches.

This would let the file.c:53 case work. But, I think it would reject
the Ada test case we have been struggling with: pack.o has a line 10, so
it would prohibit us from finding the false match in m.o.

The use of the symtab's dirname+filename as the discriminant is there to
let us handle the multiple-files-same-name case.

Joel thinks that this would probably not work:

This is the initial idea that we had. But that might break down in
the case of inlining that I mentioned, no?

10 procedure Foo is
11 begin
12 Do_Something;

In the case of the inlined instance, I would suspect that there would
be no code for line 10 and 11 since no prologue would be necessary.
Someone inserting a breakpoint on line 10 would get the non-inlined
instance, but would miss the inlined one.

A couple of observations.

First, I think having too many locations is better than having too few.
With too many, at least the user can disable some. With too few,
whoops, gdb isn't doing as asked.

Second, at least initially the heuristic only has to perform as well as
what gdb already does. It is pretty easy to construct cases where
"break file:line" sets a breakpoint in the wrong function entirely.
From the latest version of the test case I have here, using cvs head
gdb:

$ nl -ba lspec.h
[...]
11 int f1(void)
12 {
13 return 1; /* f1 breakpoint */
14 }
[...]
20 int f2(void)
21 {
22 return 1; /* f2 breakpoint */
23 }
[...]

(gdb) b lspec.h:13
Breakpoint 1 at 0x400554: file ../../../archer/gdb/testsuite/gdb.linespec/base/two/../../lspec.h, line 13.
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x0000000000400554 in f2()
at ../../../archer/gdb/testsuite/gdb.linespec/base/two/../../lspec.h:13

Oops, it broke in f2, even though f1 actually exists in the program:

(gdb) b f1
Breakpoint 2 at 0x400528: file ../../../archer/gdb/testsuite/gdb.linespec/base/one/../../lspec.h, line 13.

Note the line numbers.

To sum up, this is the last known problem facing this patch series. I
would like to resolve it, but I am not sure exactly how, so I am looking
for input.

Tom