This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFA] Fix frame-issue with watchpoints...


Hello,

A coworker of mine noticed an issue with watchpoints. To reproduce,
he provided the following Ada program (on x86-linux for instance):

     1  procedure Watch is
     2
     3     procedure Foo (X : access Integer) is
     4     begin
     5        delay 1.0;
     6     end Foo;
     7
     8     X : aliased Integer := 1;
     9
    10  begin
    11     Foo (X'Access);
    12     X := 2;  -- BREAK
    13  end Watch;

This program needs to be compiled using the usual trivial command:

        % gnatmake -g watch

This will produce a small program that can be debugged as follow:

        % gdb watch
        (gdb) b foo.adb:5
        (gdb) b foo.adb:12
        (gdb) run

At this point, the debugger will stop inside procedure Foo, where
we insert a watchpoint on X, before continuing to the next breakpoint
on line 12:

        (gdb) watch x
        Hardware watchpoint 3: x
        (gdb) cont
        Continuing.
        No frame is currently executing in block watch.foo.

Here is what happens:

The first thing we do is notice that we just stopped at a location
where we have a breakpoint, so we do a single-step, which worked out
just fine, and then do the real continue. Just before resuming the
execution of the inferior, we try to re-insert the breakpoints, and
that means we re-evaluate all breakpoint locations, and this is where
things start to break...

The watchpoint location evaluation eventually leads us to
value_of_variable, and in particular the error message we see:

        else if (symbol_read_needs_frame (var))
          {
            frame = block_innermost_frame (b);
            if (!frame)
              {   
                if (BLOCK_FUNCTION (b)
                    && SYMBOL_PRINT_NAME (BLOCK_FUNCTION (b)))
                  error (_("No frame is currently executing in block %s."),

What happens is that block_innermost_frame(b) returned NULL, and
the reason is fairly simple:

        frame = NULL;
        while (1)
          {
            frame = get_prev_frame (frame);

There is a note from Andrew besides the part of get_prev_frame that
says:

  if (this_frame == NULL)
    {
      /* NOTE: cagney/2002-11-09: There was a code segment here that
         would error out when CURRENT_FRAME was NULL.  The comment
         that went with it made the claim ...

         ``This screws value_of_variable, which just wants a nice
         clean NULL return from block_innermost_frame if there are no
         frames.  I don't think I've ever seen this message happen
         otherwise.  And returning NULL here is a perfectly legitimate
         thing to do.''

         Per the above, this code shouldn't even be called with a NULL
         THIS_FRAME.  */
      frame_debug_got_null_frame (gdb_stdlog, this_frame, "this_frame NULL");
      return current_frame;
    }

The issue in our case is that "current_frame" is NULL too, probably
because we never needed it before in our case (just finished off
single-stepping out of the breakpoint and immediately getting ready
to resume) and therefore never set it to a proper value.

One way to bandaid this, probably along the lines that Andrew was
trying to do (try to recover from a situation that should not happen),
is to replace "current_frame" by get_current_frame().
However, I'm thinking that the real culprit is block_innermost_frame
which called this function with a NULL frame, which it's not supposed
to do. So I rewrote the loop to start from the outermost frame instead
of a NULL frame, and then work its way up the frame stack...

This fixes the problem without introducing any regression.

In addition to this patch, I think we should investigate the option
of removing the check above and replace it with an assertion that
THIS_FRAME is not null. Or maybe if we are afraid of breaking something,
then at least change "current_frame" along the lines of what I suggested,
and print an unconditional warning. Let's make it visible.

2006-10-05  Joel Brobecker  <brobecker@adacore.com>

        * blockframe.c (block_innermost_frame): Rewrite frame search logic.

Tested on x86-linux, no regression. A new testcase to be submitted soon.
OK to apply?

Thanks,
-- 
Joel

Attachment: blockframe.c.diff
Description: Text document


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]