This is the mail archive of the gdb-prs@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]

gdb/2500: Read watchpoints do not behave correctly


>Number:         2500
>Category:       gdb
>Synopsis:       Read watchpoints do not behave correctly
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    unassigned
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Tue Aug 12 15:58:01 UTC 2008
>Closed-Date:
>Last-Modified:
>Originator:     jeremy.bennett@embecosm.com
>Release:        unknown-1.0
>Organization:
>Environment:
Fedora 9 with GDB 6.8. Examples using both native intel and remote OpenCores 1000 targets
>Description:
Read watchpoint logic appears to be broken. This appears to be related to Bug 1600.

See the How-to-Repeat section for three demonstration runs. In the first (native Intel), a phantom read watchpoint for variable a is triggered by the statement:

  b = 1;

In the second example (simulated remote OpenRISC 1000), read watchpoints are set on two global integers, a and b. The first triggers on the statement

  i = a;

The second fails to trigger on the following statement

  i = b;

The third example (simulated remote OpenRISC 1000) has the same code and watchpoints, but this time the read watchpoint on b is only set after the read watchpoint on a has triggered.

The problem appears to be the logic for determining if a watchpoint reported by hardware should trigger. In the second example the hardware triggers the second watchpoint correctly, but GDB decides (in bpstat_top_status) that the watchpoint should not be reported.

Although it is experimental, the OpenRISC 1000 is a useful testbench, since its hardware distinguishes explicitly between read and write watchpoint accesses.
>How-To-Repeat:
The test code is:

int  a;
int  b;

main()
{
  int  i;

  a = 0;
  b = 1;

  i = a;
  i = b;

}

The following is a transcript of the GDB session under native Intel target:

GNU gdb Fedora (6.8-17.fc9)
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...
(gdb) rwatch a
Hardware read watchpoint 1: a
(gdb) rwatch b
Hardware read watchpoint 2: b
(gdb) run
Starting program: /home/jeremy/svntrunk/GNU/gdb-6.8/progs_or32/a.out 
Hardware read watchpoint 1: a

Value = 0
main () at rwatch.c:9
9         b = 1;
(gdb) c
Continuing.
Hardware read watchpoint 1: a

Value = 0
0x080483be in main () at rwatch.c:11
11        i = a;
(gdb) c
Continuing.
Hardware read watchpoint 2: b

Value = 1
0x080483c6 in main () at rwatch.c:12
12        i = b;
(gdb) c
Continuing.

Program exited with code 01.
(gdb) 

The first breakpoint should not occur.

The same program was run using the experimental OpenRISC 1000 port of GDB 6.8.

The following script shows what happens when both watchpoints are requested prior to running (the line numbers are slight different due to extra include headers and comments):

(gdb) rwatch a
Hardware read watchpoint 1: a
(gdb) rwatch b
Hardware read watchpoint 2: b
(gdb) r
Starting program: /home/jeremy/svntrunk/GNU/gdb-6.8/progs_or32/rwatch 
[Switching to process -1]
Hardware read watchpoint 1: a

Value = 0
0x0000125c in main () at rwatch.c:41
41        i = a;
(gdb) c
Continuing.

Program exited normally.
(gdb) 

The second watchpoint, which should occur at i = b; is not triggered.

However if the second watchpoint is requested after the first one has triggered, all behaves correctly:

(gdb) rwatch a
Hardware read watchpoint 1: a
(gdb) run
Starting program: /home/jeremy/svntrunk/GNU/gdb-6.8/progs_or32/rwatch 
[Switching to process -1]
Hardware read watchpoint 1: a

Value = 0
0x0000125c in main () at rwatch.c:41
41        i = a;
(gdb) rwatch b
Hardware read watchpoint 2: b
(gdb) c
Continuing.
Hardware read watchpoint 2: b

Value = 1
0x0000127c in main () at rwatch.c:42
42        i = b;
(gdb) c
Continuing.

Program exited normally.
(gdb) 


>Fix:
The logic in bpstat_top_status calls watchpoint_check() to determine if the value being watched has changed. Read watchpoints should not fire if the value has changed (a read should not change the value). Write watchpoints should not fire if the value has NOT changed.

The logic seems broken, because the comparison is to the value of the watch expression at the time the watchpoint was set. For a read watchpoint, the value may subsequently have been changed, so that when the read watchpoint is triggered the value is shown as different, even though it is not the watched instruction that caused the change. This is why the watchpoint on b does not trigger in example 2, but does in example 3 (it is set AFTER b has been changed).

There are a number of strategies that could be used to fix this. The simplest is to trust the hardware. If it says a read watchpoint has been triggered, then it has been triggered. So the test for no-change can just be dropped.

I am not confident the test for write watchpoints remains correct however. It should be a check of the value before this instruction and the value after. This means recording the value when the watchpoint triggers, and comparing to the value after the watchpoint has been cleared and the code single stepped through the instruction.
>Release-Note:
>Audit-Trail:
>Unformatted:


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