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]

threads/2388: Cannot disable watchpoints when debugging multithreaded program under cygwin


>Number:         2388
>Category:       threads
>Synopsis:       Cannot disable watchpoints when debugging multithreaded program under cygwin
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    unassigned
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Tue Dec 18 15:18:01 UTC 2007
>Closed-Date:
>Last-Modified:
>Originator:     Michael Luber
>Release:        GNU gdb 6.7.50.20071217, GNU gdb 6.7.1, GNU gdb 6.5.50.20060706-cvs (cygwin-special)
>Organization:
>Environment:
CYGWIN_NT-5.1 with Windows XP SP2,
gcc-Version 3.4.4 (cygming special, gdc 0.12, using dmd 0.125)
GDB configured with "i686-pc-cygwin"
>Description:
When you disable or delete a watchpoint, and issue a "thread info" before continuing, the watchpoint will still  be in effect.
Instead of a "thread info", you can also switch to another thead and back (because "thread info" does nothing else then switching through all threads).

This really is a problem, as IDEs like Eclipse/CDT keep issuing "thread info" commands to update their GUI.

I had a look at the GDB code, and I think there are two problems here:

1. In the file "\gdb\win32-nat.c" there is a global array "static unsigned dr[8]" that represents the current state of the debug registers. If you disable a watchpoint, this will be correctly entered in dr[7] (debug control register), and when you continue afterwards, the function "win32_resume()" copies the debug registers into the context of the current thread and passes that info to Windows with SetThreadContext().
However, if you issue a thread change before you continue (by using the command "thread 2" for instance), the function switch_to_thread() is called, which overwrites the debug registers with the values that are stored in the new thread's context, overwriting the change that disabled the watchpoint. So the information that the watchpoint should be disabled is lost.

2. If the original thread is set up again, its debug registers are not restored, because the flag "reload_context" in the context structure (struct thread_info_struct) is not set. I don't know why. It has something to do with the suspend_count in the "struct win32_thread_info".

I just made a quick-and-dirty patch, to see if this is really the problem: I add code to the function switch_to_thread() so that it always saves the array dr[] to the current thread context, then does the thread switch as before, and then restores the debug registers from the new thread's context into the array dr[].
With this change, the problem does not occur anymore. Of course, this is not a bugfix, and that's why i don't suggest it.
>How-To-Repeat:
1. write a C program "watch.c" with this content:
-------------------------------------
int i;
int main() {
	i = 2;
	i = 3;
	return 0;
}
-------------------------------------

2. compile it: gcc -g watch.c -o watch.exe

3. debug it: 
   - gdb watch.exe
   - break main
   - watch i
   - run
   - delete 2
   - continue
   ===> program terminates as expected
4. debug it again: 
   - gdb watch.exe
   - break main
   - watch i
   - run
   - delete 2
   - info threads
   - continue
   ===> program halts in line 4, reporting a SIGTRAP signal
>Fix:

>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]