* solib-svr4.c (svr4_truncate_ptr): New function.
[deliverable/binutils-gdb.git] / gdb / win32-nat.c
index a8d11708ed4251cb04e55678db237b844d8d1231..fe1c01cf1c4d765068f163b80fb15fddcadfc11a 100644 (file)
@@ -1,6 +1,8 @@
 /* Target-vector operations for controlling win32 child processes, for GDB.
-   Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001
-   Free Software Foundation, Inc.
+
+   Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 Free
+   Software Foundation, Inc.
+
    Contributed by Cygnus Solutions, A Red Hat Company.
 
    This file is part of GDB.
@@ -69,11 +71,15 @@ enum
 #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 +220,15 @@ static const struct xlate_exception
   {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 +249,16 @@ thread_rec (DWORD id, int get_context)
 
            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 +282,22 @@ child_add_thread (DWORD id, HANDLE h)
   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;
 }
 
@@ -302,13 +343,6 @@ child_delete_thread (DWORD id)
     }
 }
 
-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)
 {
@@ -571,7 +605,7 @@ register_loaded_dll (const char *name, DWORD load_addr)
 /* Wait for child to do something.  Return pid of child, or -1 in case
    of error; store status through argument pointer OURSTATUS.  */
 static int
-handle_load_dll (void *dummy ATTRIBUTE_UNUSED)
+handle_load_dll (void *dummy)
 {
   LOAD_DLL_DEBUG_INFO *event = &current_event.u.LoadDll;
   DWORD dll_name_ptr;
@@ -652,7 +686,7 @@ handle_load_dll (void *dummy ATTRIBUTE_UNUSED)
 }
 
 static int
-handle_unload_dll (void *dummy ATTRIBUTE_UNUSED)
+handle_unload_dll (void *dummy)
 {
   DWORD lpBaseOfDll = (DWORD) current_event.u.UnloadDll.lpBaseOfDll + 0x1000;
   struct so_stuff *so;
@@ -676,7 +710,7 @@ handle_unload_dll (void *dummy ATTRIBUTE_UNUSED)
 
 /* Return name of last loaded DLL. */
 char *
-child_solib_loaded_library_pathname (int pid ATTRIBUTE_UNUSED)
+child_solib_loaded_library_pathname (int pid)
 {
   return !solib_end || !solib_end->name[0] ? NULL : solib_end->name;
 }
@@ -742,7 +776,7 @@ dll_symbol_command (char *args, int from_tty)
 
 /* List currently loaded DLLs. */
 void
-info_dll_command (char *ignore ATTRIBUTE_UNUSED, int from_tty ATTRIBUTE_UNUSED)
+info_dll_command (char *ignore, int from_tty)
 {
   struct so_stuff *so = &solib_start;
 
@@ -833,6 +867,12 @@ handle_exception (struct target_waitstatus *ourstatus)
       ourstatus->value.sig = TARGET_SIGNAL_INT;
       last_sig = SIGINT;       /* FIXME - should check pass state */
       break;
+    case DBG_CONTROL_BREAK:
+      DEBUG_EXCEPT (("gdb: Target exception CONTROL_BREAK at 0x%08lx\n",
+       (DWORD) current_event.u.Exception.ExceptionRecord.ExceptionAddress));
+      ourstatus->value.sig = TARGET_SIGNAL_INT;
+      last_sig = SIGINT;       /* FIXME - should check pass state */
+      break;
     case EXCEPTION_SINGLE_STEP:
       DEBUG_EXCEPT (("gdb: Target exception SINGLE_STEP at 0x%08lx\n",
        (DWORD) current_event.u.Exception.ExceptionRecord.ExceptionAddress));
@@ -876,11 +916,27 @@ child_continue (DWORD continue_status, int id)
     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;
 }
 
@@ -888,7 +944,7 @@ child_continue (DWORD continue_status, int id)
    handling by WFI (or whatever).
  */
 static int
-get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourstatus)
+get_child_debug_event (int pid, struct target_waitstatus *ourstatus)
 {
   BOOL debug_event;
   DWORD continue_status, event_code;
@@ -1060,10 +1116,15 @@ static void
 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 < sizeof (dr) / sizeof (dr[0]); i++)
+    dr[i] = 0;
   current_event.dwProcessId = pid;
   memset (&current_event, 0, sizeof (current_event));
   push_target (&child_ops);
@@ -1158,7 +1219,7 @@ child_attach (char *args, int from_tty)
 }
 
 static void
-child_detach (char *args ATTRIBUTE_UNUSED, int from_tty)
+child_detach (char *args, int from_tty)
 {
   int detached = 1;
 
@@ -1190,7 +1251,7 @@ child_detach (char *args ATTRIBUTE_UNUSED, int from_tty)
 /* Print status information about what we're accessing.  */
 
 static void
-child_files_info (struct target_ops *ignore ATTRIBUTE_UNUSED)
+child_files_info (struct target_ops *ignore)
 {
   printf_unfiltered ("\tUsing the running image of %s %s.\n",
       attach_flag ? "attached" : "child", target_pid_to_str (inferior_ptid));
@@ -1198,7 +1259,7 @@ child_files_info (struct target_ops *ignore ATTRIBUTE_UNUSED)
 
 /* ARGSUSED */
 static void
-child_open (char *arg ATTRIBUTE_UNUSED, int from_tty ATTRIBUTE_UNUSED)
+child_open (char *arg, int from_tty)
 {
   error ("Use the \"run\" command to start a Unix child process.");
 }
@@ -1343,6 +1404,7 @@ static void
 child_mourn_inferior (void)
 {
   (void) child_continue (DBG_CONTINUE, -1);
+  i386_cleanup_dregs();
   unpush_target (&child_ops);
   generic_mourn_inferior ();
 }
@@ -1360,8 +1422,8 @@ child_stop (void)
 
 int
 child_xfer_memory (CORE_ADDR memaddr, char *our, int len,
-                  int write, struct mem_attrib *mem ATTRIBUTE_UNUSED,
-                  struct target_ops *target ATTRIBUTE_UNUSED)
+                  int write, struct mem_attrib *mem,
+                  struct target_ops *target)
 {
   DWORD done;
   if (write)
@@ -1430,6 +1492,16 @@ child_resume (ptid_t ptid, int step, enum target_signal sig)
 
       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;
        }
@@ -1454,7 +1526,7 @@ child_can_run (void)
 }
 
 static void
-child_close (int x ATTRIBUTE_UNUSED)
+child_close (int x)
 {
   DEBUG_EVENTS (("gdb: child_close, inferior_ptid=%d\n",
                PIDGET (inferior_ptid)));
@@ -1563,6 +1635,43 @@ _initialize_inftarg (void)
   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
    it means that the pid has died.  Otherwise it is assumed to be alive. */
@@ -1758,7 +1867,8 @@ out:
 }
 
 void
-child_solib_add (char *filename ATTRIBUTE_UNUSED, int from_tty, struct target_ops *target, int readsyms)
+child_solib_add (char *filename, int from_tty, struct target_ops *target,
+                int readsyms)
 {
   if (!readsyms)
     return;
This page took 0.028317 seconds and 4 git commands to generate.