This is the mail archive of the gdb-patches@sources.redhat.com 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 2] Debug register support in win32-nat.c


   This is a follow up of my first
proposal for win32 debug register support
(which enables hardware watchpoints,
I never tested the hardware breakpoints, as they don't have
much advantages over normal breakpoints on i386 processors).

   This second patch does solve one remaining problem,
that was related to the fact that a thead created after a watchpoint was 
enabled didn't get the address watched from beginning of the thread.

  This makes this win32 watchpoints enabled for all threads
(which seems to be different from the linux case, where watchpoints seem to be
thread specific).

   The unwanted output that is generated at each DLL loading
is still not solved, but this is also the case for each dynamic library loading under
i386 linux.

2002-01-08  Pierre Muller  <muller@ics.u-strasbg.fr>

	* win32-nat.c (CONTEXT_DEBUG_DR macro): Add use of CONTEXT_DEBUG_REGISTERS.
	(dr variable): New static array containing a local copy of debug registers.
	(debug_registers_changed): Non zero whenever the debug registers where changed and
	need to be written to inferior.
	(debug_registers_used): Non zero if any debug register was set, used new new threads are created.
	(cygwin_set_dr, cygwin_set_dr7, cygwin_get_dr6): New functions used by i386-nat code.
	(thread_rec): Set dr array if id is the thread of current_event .
	(child_continue, child_resume): Change the debug registers for all threads 
	if debug_registers_changed.
	(child_add_thread): Change the debug registers if debug_registers_used.
	* config/i386/cygwin.mh: Add use of i386-nat.o file.
	Link nm.h to new nm-cygwin.h file.
	+ config/i386/nm-cygwin.h: New file.

Index: win32-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/win32-nat.c,v
retrieving revision 1.42
diff -u -r1.42 win32-nat.c
--- win32-nat.c	2002/01/08 08:26:42	1.42
+++ win32-nat.c	2002/01/08 09:12:33
@@ -69,11 +69,15 @@
 #include <psapi.h>
 
 #ifdef HAVE_SSE_REGS
-#define CONTEXT_DEBUGGER_DR CONTEXT_DEBUGGER | CONTEXT_EXTENDED_REGISTERS
+#define CONTEXT_DEBUGGER_DR CONTEXT_DEBUGGER | CONTEXT_DEBUG_REGISTERS \
+	| CONTEXT_EXTENDED_REGISTERS
 #else
-#define CONTEXT_DEBUGGER_DR CONTEXT_DEBUGGER
+#define CONTEXT_DEBUGGER_DR CONTEXT_DEBUGGER | CONTEXT_DEBUG_REGISTERS
 #endif
 
+static unsigned dr[8];
+static int debug_registers_changed = 0;
+static int debug_registers_used = 0;
 
 /* The string sent by cygwin when it processes a signal.
    FIXME: This should be in a cygwin include file. */
@@ -214,6 +218,14 @@
   {EXCEPTION_SINGLE_STEP, TARGET_SIGNAL_TRAP},
   {-1, -1}};
 
+static void
+check (BOOL ok, const char *file, int line)
+{
+  if (!ok)
+    printf_filtered ("error return %s:%d was %lu\n", file, line, GetLastError ());
+}
+
+
 /* Find a thread record given a thread id.
    If get_context then also retrieve the context for this
    thread. */
@@ -234,6 +246,16 @@
 
 	    th->context.ContextFlags = CONTEXT_DEBUGGER_DR;
 	    GetThreadContext (th->h, &th->context);
+	    if (id == current_event.dwThreadId)
+	      {
+		/* Copy dr values from that thread.  */
+		dr[0] = th->context.Dr0;
+		dr[1] = th->context.Dr1;
+		dr[2] = th->context.Dr2;
+		dr[3] = th->context.Dr3;
+		dr[6] = th->context.Dr6;
+		dr[7] = th->context.Dr7;
+	      }
 	  }
 	return th;
       }
@@ -257,6 +279,22 @@
   th->next = thread_head.next;
   thread_head.next = th;
   add_thread (pid_to_ptid (id));
+  /* Set the debug registers for the new thread in they are used.  */ 
+  if (debug_registers_used)
+    {
+      /* Only change the value of the debug registers.  */
+      th->context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
+      CHECK (GetThreadContext (th->h, &th->context));
+      th->context.Dr0 = dr[0];
+      th->context.Dr1 = dr[1];
+      th->context.Dr2 = dr[2];
+      th->context.Dr3 = dr[3];
+      /* th->context.Dr6 = dr[6];
+      FIXME: should we set dr6 also ?? */
+      th->context.Dr7 = dr[7];
+      CHECK (SetThreadContext (th->h, &th->context));
+      th->context.ContextFlags = 0;
+    }
   return th;
 }
 
@@ -303,13 +341,6 @@
 }
 
 static void
-check (BOOL ok, const char *file, int line)
-{
-  if (!ok)
-    printf_filtered ("error return %s:%d was %lu\n", file, line, GetLastError ());
-}
-
-static void
 do_child_fetch_inferior_registers (int r)
 {
   char *context_offset = ((char *) &current_thread->context) + mappings[r];
@@ -876,11 +907,27 @@
     for (th = &thread_head; (th = th->next) != NULL;)
       if (((id == -1) || (id == (int) th->id)) && th->suspend_count)
 	{
+
 	  for (i = 0; i < th->suspend_count; i++)
 	    (void) ResumeThread (th->h);
 	  th->suspend_count = 0;
+	  if (debug_registers_changed)
+	    {
+	      /* Only change the value of the debug reisters */
+	      th->context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
+	      th->context.Dr0 = dr[0];
+	      th->context.Dr1 = dr[1];
+	      th->context.Dr2 = dr[2];
+	      th->context.Dr3 = dr[3];
+	      /* th->context.Dr6 = dr[6];
+	         FIXME: should we set dr6 also ?? */
+	      th->context.Dr7 = dr[7];
+	      CHECK (SetThreadContext (th->h, &th->context));
+	      th->context.ContextFlags = 0;
+	    }
 	}
 
+  debug_registers_changed = 0;
   return res;
 }
 
@@ -1060,10 +1107,15 @@
 do_initial_child_stuff (DWORD pid)
 {
   extern int stop_after_trap;
+  int i;
 
   last_sig = 0;
   event_count = 0;
   exception_count = 0;
+  debug_registers_changed = 0;
+  debug_registers_used = 0;  
+  for (i = 0; i <= 7; i++)
+    dr[i] = 0;
   current_event.dwProcessId = pid;
   memset (&current_event, 0, sizeof (current_event));
   push_target (&child_ops);
@@ -1343,6 +1395,7 @@
 child_mourn_inferior (void)
 {
   (void) child_continue (DBG_CONTINUE, -1);
+  i386_cleanup_dregs();
   unpush_target (&child_ops);
   generic_mourn_inferior ();
 }
@@ -1430,6 +1483,16 @@
 
       if (th->context.ContextFlags)
 	{
+     if (debug_registers_changed)
+       {
+          th->context.Dr0 = dr[0];
+          th->context.Dr1 = dr[1];
+          th->context.Dr2 = dr[2];
+          th->context.Dr3 = dr[3];
+          /* th->context.Dr6 = dr[6];
+           FIXME: should we set dr6 also ?? */
+          th->context.Dr7 = dr[7];
+       }
 	  CHECK (SetThreadContext (th->h, &th->context));
 	  th->context.ContextFlags = 0;
 	}
@@ -1562,6 +1625,43 @@
 
   add_target (&child_ops);
 }
+
+/* Hardware watchpoint support, adapted from go32-nat.c code.  */
+
+/* Pass the address ADDR to the inferior in the I'th debug register.
+   Here we just store the address in dr array, the registers will be
+   actually set up when child_continue is called.  */
+void
+cygwin_set_dr (int i, CORE_ADDR addr)
+{
+  if (i < 0 || i > 3)
+    internal_error (__FILE__, __LINE__,
+		    "Invalid register %d in cygwin_set_dr.\n", i);
+  dr[i] = (unsigned) addr;
+  debug_registers_changed = 1;
+  debug_registers_used = 1;
+}
+
+/* Pass the value VAL to the inferior in the DR7 debug control
+   register.  Here we just store the address in D_REGS, the watchpoint
+   will be actually set up in child_wait.  */
+void
+cygwin_set_dr7 (unsigned val)
+{
+  dr[7] = val;
+  debug_registers_changed = 1;
+  debug_registers_used = 1;
+}
+
+/* Get the value of the DR6 debug status register from the inferior.
+   Here we just return the value stored in dr[6]
+   by the last call to thread_rec for current_event.dwThreadId id.  */
+unsigned
+cygwin_get_dr6 (void)
+{
+  return dr[6];
+}
+
 
 /* Determine if the thread referenced by "pid" is alive
    by "polling" it.  If WaitForSingleObject returns WAIT_OBJECT_0
Index: config/i386/cygwin.mh
===================================================================
RCS file: /cvs/src/src/gdb/config/i386/cygwin.mh,v
retrieving revision 1.4
diff -u -r1.4 cygwin.mh
--- cygwin.mh	2000/08/27 04:21:35	1.4
+++ cygwin.mh	2002/01/08 09:12:33
@@ -1,6 +1,6 @@
 MH_CFLAGS=
 XM_FILE=xm-cygwin.h
 XDEPFILES=
-NATDEPFILES= win32-nat.o corelow.o
-NAT_FILE=../none/nm-none.h
+NATDEPFILES= i386-nat.o win32-nat.o corelow.o
+NAT_FILE=nm-cygwin.h
 XM_CLIBS=
Index: config/i386/nm-cygwin.h
===================================================================
RCS file: nm-cygwin.h
diff -N nm-cygwin.h
--- /dev/null	Tue May  5 13:32:27 1998
+++ nm-cygwin.h	Tue Jan  8 01:12:33 2002
@@ -0,0 +1,38 @@
+/* Native definitions for Intel x86 running CYGWIN.
+   Copyright (C) 2001 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#define NO_PTRACE_H
+
+#define I386_USE_GENERIC_WATCHPOINTS
+
+#include "i386/nm-i386.h"
+
+/* Support for hardware-assisted breakpoints and watchpoints.  */
+
+#define I386_DR_LOW_SET_CONTROL(VAL)	cygwin_set_dr7 (VAL)
+extern void cygwin_set_dr7 (unsigned);
+
+#define I386_DR_LOW_SET_ADDR(N,ADDR)	cygwin_set_dr (N,ADDR)
+extern void cygwin_set_dr (int, CORE_ADDR);
+
+#define I386_DR_LOW_RESET_ADDR(N)
+
+#define I386_DR_LOW_GET_STATUS()	cygwin_get_dr6 ()
+extern unsigned cygwin_get_dr6 (void);


Pierre Muller
Institut Charles Sadron
6,rue Boussingault
F 67083 STRASBOURG CEDEX (France)
mailto:muller@ics.u-strasbg.fr
Phone : (33)-3-88-41-40-07  Fax : (33)-3-88-41-40-99

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