bug-gdb
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Single stepping remote targets can miss breakpoints


From: Fred Fish
Subject: Single stepping remote targets can miss breakpoints
Date: Sat, 2 Mar 2002 11:33:08 -0700 (MST)

While chasing the cause of a failure in the gdb testsuite, in the
break.exp tests, I've found that there is a significant difference
between how native targets and remote targets handle single stepping.
Since I've not previously done a lot of work with remote targets, I
didn't realize this fundamental difference existed.

It is causing a failure in the part of break.exp that checks that you
can set a breakpoint on the next line, and then when you single step
at the source level, that breakpoint gets hit:

  # Test break at offset +1

  gdb_test "break +1" \
    "Breakpoint.*at.* file .*$srcfile, line 86\\." \
    "breakpoint offset +1"

  # Check to see if breakpoint is hit when stepped onto

  gdb_test "step" \
    ".*Breakpoint \[0-9\]+, main \\(argc=.*, argv=.*, envp=.*\\) at 
.*$srcfile:86.*86\[\t \]+return argc;" \
    "step onto breakpoint"

What happens is that for native targets, gdb actually does single step
at the instruction level, from the current pc (where there is an
active breakpoint) to the destination pc for the next line (where
there is also an active breakpoint).  However since there is an active
breakpoint on the starting pc where it is currently stopped, it
doesn't reinsert breakpoints until it has stepped off that pc via a
single step at the instruction level.  Then it continues to single
step at the instruction level until it reaches the destination pc, at
which point it stops and prints the breakpoint info for that pc:

  (gdb) step
  
  Breakpoint 3, child_resume (ptid={pid = 2135, lwp = 0, tid = 0}, step=1, 
      signal=TARGET_SIGNAL_0) at 
/src/sourceware/gdb/src/gdb/i386-linux-nat.c:882
  882       int pid = PIDGET (ptid);
  4: /x step_range_start = 0x80485bb
  3: /x stop_pc = 0x80485bb
  2: /x step_range_end = 0x80485cd
  1: breakpoints_inserted = 0
  (top-gdb) c
  Continuing.
  
  Breakpoint 3, child_resume (ptid={pid = -1, lwp = 0, tid = 0}, step=1, 
      signal=TARGET_SIGNAL_0) at 
/src/sourceware/gdb/src/gdb/i386-linux-nat.c:882
  882       int pid = PIDGET (ptid);
  4: /x step_range_start = 0x80485bb
  3: /x stop_pc = 0x80485c0
  2: /x step_range_end = 0x80485cd
  1: breakpoints_inserted = 1
  (top-gdb) c
  Continuing.
  
  Breakpoint 3, child_resume (ptid={pid = -1, lwp = 0, tid = 0}, step=1, 
      signal=TARGET_SIGNAL_0) at 
/src/sourceware/gdb/src/gdb/i386-linux-nat.c:882
  882       int pid = PIDGET (ptid);
  4: /x step_range_start = 0x80485bb
  3: /x stop_pc = 0x80485c7
  2: /x step_range_end = 0x80485cd
  1: breakpoints_inserted = 1
  (top-gdb) c
  Continuing.
  
  Breakpoint 3, child_resume (ptid={pid = -1, lwp = 0, tid = 0}, step=1, 
      signal=TARGET_SIGNAL_0) at 
/src/sourceware/gdb/src/gdb/i386-linux-nat.c:882
  882       int pid = PIDGET (ptid);
  4: /x step_range_start = 0x80485bb
  3: /x stop_pc = 0x80485ca
  2: /x step_range_end = 0x80485cd
  1: breakpoints_inserted = 1
  (top-gdb) c
  Continuing.
  
  Breakpoint 8, main (argc=0, argv=0xbfffe9d4, envp=0xbfffe9dc) at 
/src/sourceware/gdb/src/gdb/testsuite/gdb.base/break.c:86
  86          return argc;
  (gdb) quit

Now for the remote case, instead of calling child_resume(), the target
is resumed by calling remote_resume().  The remote_resume() function
implements stepping by creating a packet using the step_range_start
and step_range_end values, and telling the target to resume execution.
Thus the target runs until the end of the stepping range, and then
returns control to gdb.  Since gdb didn't have breakpoints inserted at
the first call to remote_resume(), it doesn't print the active
breakpoint:

  (gdb) step
  
  Breakpoint 3, remote_resume (ptid={pid = 42000, lwp = 0, tid = 0}, step=1, 
      siggnal=TARGET_SIGNAL_0)
      at /src/cygnus/xxxxx/devo/gdb/remote.c:2557
  2557    struct remote_state *rs = get_remote_state ();
  4: /x step_range_start = 0x2f0
  3: /x stop_pc = 0x2f0
  2: /x step_range_end = 0x306
  1: breakpoints_inserted = 0
  (top-gdb) c
  Continuing.
  86        return argc;
  (gdb) quit

I would assume that this different behavior for remote targets is to
avoid having to actually single step them at the instruction level to
implement a source level single step, which obvious would result in
more traffic between the remote target and gdb.

However this leads me to theorize that if you single step from one
line to the next, for remote targets you may miss a breakpoint set in
the middle of the line you are stepping over.  Some testing confirms
that:

  Native case:

  (gdb) x/i $pc
  0x80485bb <main+147>: mov    $0x0,%eax
  (gdb) 
  0x80485c0 <main+152>: cmpl   $0x3039,0x8(%ebp)
  (gdb) 
  0x80485c7 <main+159>: sete   %al
  (gdb) br *0x80485c7
  Breakpoint 9 at 0x80485c7: file 
/src/sourceware/gdb/src/gdb/testsuite/gdb.base/break.c, line 85.
  (gdb) step
  
  Breakpoint 9, 0x080485c7 in main (argc=1, argv=0xbffff254, envp=0xbffff25c) 
at /src/sourceware/gdb/src/gdb/testsuite/gdb.base/break.c:85
  85        argc = (argc == 12345); /* This is silly, but we can step off of it 
*/
  (gdb) step
  
  Breakpoint 8, main (argc=0, argv=0xbffff254, envp=0xbffff25c) at 
/src/sourceware/gdb/src/gdb/testsuite/gdb.base/break.c:86
  86        return argc;
  (gdb) quit

  Remote case:

  (gdb) x/i $pc
  0x2f0 <main+112>:     mov w[r14+0x8],0x0
  (gdb) 
  0x2f6 <main+118>:     cmp w[r14],0x3039
  (gdb) 
  0x2fa <main+122>:     jnes 0x302 <main+130>
  (gdb) br *0x2fa
  Breakpoint 9 at 0x2fa: file 
/src/cygnus/xxxxx/devo/gdb/testsuite/gdb.base/break.c, line 85.
  (gdb) step
  86        return argc;
  (gdb) quit

So although we could probably handle the difference in behaviors
inside gdb by printing the breakpoint at the end of the stepping range
even when breakpoints aren't currently inserted due to single
stepping, that doesn't solve the problem of missing breakpoints inside
a line we are single stepping over.

Any ideas?

Note, please CC me on any replies as I don't subscribe to the bug list.

-Fred



reply via email to

[Prev in Thread] Current Thread [Next in Thread]