/* 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.
#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. */
{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. */
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;
}
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;
}
}
}
-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)
{
/* 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 = ¤t_event.u.LoadDll;
DWORD dll_name_ptr;
}
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;
/* 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;
}
/* 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;
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));
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;
}
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;
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 (¤t_event, 0, sizeof (current_event));
push_target (&child_ops);
}
static void
-child_detach (char *args ATTRIBUTE_UNUSED, int from_tty)
+child_detach (char *args, int from_tty)
{
int detached = 1;
/* 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));
/* 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.");
}
child_mourn_inferior (void)
{
(void) child_continue (DBG_CONTINUE, -1);
+ i386_cleanup_dregs();
unpush_target (&child_ops);
generic_mourn_inferior ();
}
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)
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;
}
}
static void
-child_close (int x ATTRIBUTE_UNUSED)
+child_close (int x)
{
DEBUG_EVENTS (("gdb: child_close, inferior_ptid=%d\n",
PIDGET (inferior_ptid)));
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. */
}
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;