+2007-05-10 Pedro Alves <pedro_alves@portugalmail.pt>
+
+ * win32-low.c (debug_registers_changed,
+ debug_registers_used, CONTEXT_EXTENDED_REGISTERS,
+ CONTEXT_FLOATING_POINT, CONTEXT_DEBUG_REGISTERS,
+ CONTEXT_DEBUGGER, CONTEXT_DEBUGGER_DR): Delete.
+ (thread_rec): Get context using the low target.
+ (child_add_thread): Call thread_added on the low target,
+ which does the same thing.
+ (regptr): Delete.
+ (do_initial_child_stuff): Remove debug registers references.
+ Set context using the low target. Resume threads after
+ setting the contexts.
+ (child_continue): Remove dead variable. Remove debug
+ registers references.
+ (child_fetch_inferior_registers): Go through the low target.
+ (do_child_store_inferior_registers): Remove.
+ (child_store_inferior_registers): Go through the low target.
+ (win32_resume): Remove debug registers references.
+ Set context using the low target.
+ (handle_exception): Change return type to void. Don't record
+ context here. Set status to TARGET_WAITKIND_SPURIOUS on a
+ first chance exception.
+ (get_child_debug_event): Change return type to void. Remove
+ goto loop. Always return after waiting for debug event.
+ (win32_wait): Convert to switch statement. Handle spurious
+ events.
+
+ * win32-i386-low.c (debug_registers_changed,
+ debug_registers_used): New.
+ (initial_stuff): Rename to ...
+ (i386_initial_stuff): ... this. Clear debug registers
+ state variables.
+ (store_debug_registers): Delete.
+ (i386_get_thread_context): New.
+ (load_debug_registers): Delete.
+ (i386_set_thread_context): New.
+ (i386_thread_added): New.
+ (single_step): Rename to ...
+ (i386_single_step): ... this.
+ (do_fetch_inferior_registers): Rename to ...
+ (i386_fetch_inferior_register): ... this.
+ (i386_store_inferior_register): New.
+ (the_low_target): Adapt to new interface.
+
+ * win32-arm-low.c (CONTEXT_FLOATING_POINT): Define.
+ (arm_get_thread_context): New.
+ (arm_set_thread_context): New.
+ (regptr): New.
+ (do_fetch_inferior_registers): Rename to ...
+ (arm_fetch_inferior_register): ... this.
+ (arm_store_inferior_register): New.
+ (arm_wince_breakpoint): Reimplement as unsigned long.
+ (arm_wince_breakpoint_len): Define.
+ (the_low_target): Adapt to new interface.
+
+ * win32-low.h (target_ops): Remove regmap, store_debug_registers and
+ load_debug_registers. Add get_thread_context, set_thread_context,
+ thread_added and store_inferior_register. Rename
+ fetch_inferior_registers to fetch_inferior_register.
+ (regptr): Remove declaration.
+
2007-05-10 Pedro Alves <pedro_alves@portugalmail.pt>
* linux-low.c (linux_detach): Change return type to int. Return 0.
#include "server.h"
#include "win32-low.h"
-/* Fetch register(s) from gdbserver regcache data. */
+#ifndef CONTEXT_FLOATING_POINT
+#define CONTEXT_FLOATING_POINT 0
+#endif
+
static void
-do_fetch_inferior_registers (win32_thread_info *th, int r)
+arm_get_thread_context (win32_thread_info *th, DEBUG_EVENT* current_event)
{
- char *context_offset = regptr (&th->context, r);
- supply_register (r, context_offset);
+ th->context.ContextFlags = \
+ CONTEXT_FULL | \
+ CONTEXT_FLOATING_POINT;
+
+ GetThreadContext (th->h, &th->context);
+}
+
+static void
+arm_set_thread_context (win32_thread_info *th, DEBUG_EVENT* current_event)
+{
+ SetThreadContext (th->h, &th->context);
}
#define context_offset(x) ((int)&(((CONTEXT *)NULL)->x))
};
#undef context_offset
-static const unsigned char arm_wince_le_breakpoint[] =
- { 0x10, 0x00, 0x00, 0xe6 };
+/* Return a pointer into a CONTEXT field indexed by gdb register number.
+ Return a pointer to an dummy register holding zero if there is no
+ corresponding CONTEXT field for the given register number. */
+static char *
+regptr (CONTEXT* c, int r)
+{
+ if (mappings[r] < 0)
+ {
+ static ULONG zero;
+ /* Always force value to zero, in case the user tried to write
+ to this register before. */
+ zero = 0;
+ return (char *) &zero;
+ }
+ else
+ return (char *) c + mappings[r];
+}
+
+/* Fetch register from gdbserver regcache data. */
+static void
+arm_fetch_inferior_register (win32_thread_info *th, int r)
+{
+ char *context_offset = regptr (&th->context, r);
+ supply_register (r, context_offset);
+}
+
+/* Store a new register value into the thread context of TH. */
+static void
+arm_store_inferior_register (win32_thread_info *th, int r)
+{
+ collect_register (r, regptr (&th->context, r));
+}
+
+/* Correct in either endianness. We do not support Thumb yet. */
+static const unsigned long arm_wince_breakpoint = 0xe6000001;
+#define arm_wince_breakpoint_len 4
struct win32_target_ops the_low_target = {
- mappings,
sizeof (mappings) / sizeof (mappings[0]),
NULL, /* initial_stuff */
- NULL, /* store_debug_registers */
- NULL, /* load_debug_registers */
- do_fetch_inferior_registers,
+ arm_get_thread_context,
+ arm_set_thread_context,
+ NULL, /* thread_added */
+ arm_fetch_inferior_register,
+ arm_store_inferior_register,
NULL, /* single_step */
- arm_wince_le_breakpoint,
- sizeof (arm_wince_le_breakpoint) / sizeof (arm_wince_le_breakpoint[0]),
+ (const unsigned char *) &arm_wince_breakpoint,
+ arm_wince_breakpoint_len,
"arm" /* arch_string */
};
static unsigned dr[8];
+static int debug_registers_changed = 0;
+static int debug_registers_used = 0;
+
static void
-initial_stuff (void)
+i386_initial_stuff (void)
{
memset (&dr, 0, sizeof (dr));
+ debug_registers_changed = 0;
+ debug_registers_used = 0;
}
static void
-store_debug_registers (win32_thread_info *th)
+i386_get_thread_context (win32_thread_info *th, DEBUG_EVENT* current_event)
{
- 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;
+ th->context.ContextFlags = \
+ CONTEXT_FULL | \
+ CONTEXT_FLOATING_POINT | \
+ CONTEXT_EXTENDED_REGISTERS | \
+ CONTEXT_DEBUG_REGISTERS;
+
+ GetThreadContext (th->h, &th->context);
+
+ debug_registers_changed = 0;
+
+ if (th->tid == current_event->dwThreadId)
+ {
+ /* Copy dr values from the current 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;
+ }
}
static void
-load_debug_registers (win32_thread_info *th)
+i386_set_thread_context (win32_thread_info *th, DEBUG_EVENT* current_event)
{
- 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];
+ 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];
+ }
+
+ SetThreadContext (th->h, &th->context);
}
-/* Fetch register(s) from gdbserver regcache data. */
static void
-do_fetch_inferior_registers (win32_thread_info *th, int r)
+i386_thread_added (win32_thread_info *th)
{
- char *context_offset = regptr (&th->context, r);
-
- long l;
- if (r == FCS_REGNUM)
+ /* Set the debug registers for the new thread if they are used. */
+ if (debug_registers_used)
{
- l = *((long *) context_offset) & 0xffff;
- supply_register (r, (char *) &l);
+ th->context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
+ 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];
+
+ SetThreadContext (th->h, &th->context);
+ th->context.ContextFlags = 0;
}
- else if (r == FOP_REGNUM)
- {
- l = (*((long *) context_offset) >> 16) & ((1 << 11) - 1);
- supply_register (r, (char *) &l);
- }
- else
- supply_register (r, context_offset);
}
static void
-single_step (win32_thread_info *th)
+i386_single_step (win32_thread_info *th)
{
th->context.EFlags |= FLAG_TRACE_BIT;
}
};
#undef context_offset
+/* Fetch register from gdbserver regcache data. */
+static void
+i386_fetch_inferior_register (win32_thread_info *th, int r)
+{
+ char *context_offset = (char *) &th->context + mappings[r];
+
+ long l;
+ if (r == FCS_REGNUM)
+ {
+ l = *((long *) context_offset) & 0xffff;
+ supply_register (r, (char *) &l);
+ }
+ else if (r == FOP_REGNUM)
+ {
+ l = (*((long *) context_offset) >> 16) & ((1 << 11) - 1);
+ supply_register (r, (char *) &l);
+ }
+ else
+ supply_register (r, context_offset);
+}
+
+/* Store a new register value into the thread context of TH. */
+static void
+i386_store_inferior_register (win32_thread_info *th, int r)
+{
+ char *context_offset = (char *) &th->context + mappings[r];
+ collect_register (r, context_offset);
+}
+
struct win32_target_ops the_low_target = {
- mappings,
sizeof (mappings) / sizeof (mappings[0]),
- initial_stuff,
- store_debug_registers,
- load_debug_registers,
- do_fetch_inferior_registers,
- single_step,
- (const char*)NULL, /* breakpoint */
+ i386_initial_stuff,
+ i386_get_thread_context,
+ i386_set_thread_context,
+ i386_thread_added,
+ i386_fetch_inferior_register,
+ i386_store_inferior_register,
+ i386_single_step,
+ NULL, /* breakpoint */
0, /* breakpoint_len */
"i386" /* arch_string */
};
/* The current debug event from WaitForDebugEvent. */
static DEBUG_EVENT current_event;
-static int debug_registers_changed = 0;
-static int debug_registers_used = 0;
-
#define NUM_REGS (the_low_target.num_regs)
typedef BOOL WINAPI (*winapi_DebugActiveProcessStop) (DWORD dwProcessId);
typedef BOOL WINAPI (*winapi_DebugSetProcessKillOnExit) (BOOL KillOnExit);
-#ifndef CONTEXT_EXTENDED_REGISTERS
-#define CONTEXT_EXTENDED_REGISTERS 0
-#endif
-
-#ifndef CONTEXT_FLOATING_POINT
-#define CONTEXT_FLOATING_POINT 0
-#endif
-
-#ifndef CONTEXT_DEBUG_REGISTERS
-#define CONTEXT_DEBUG_REGISTERS 0
-#endif
-
-#define CONTEXT_DEBUGGER (CONTEXT_FULL | CONTEXT_FLOATING_POINT)
-#define CONTEXT_DEBUGGER_DR CONTEXT_DEBUGGER | CONTEXT_DEBUG_REGISTERS \
- | CONTEXT_EXTENDED_REGISTERS
-
static DWORD main_thread_id = 0;
+static void win32_resume (struct thread_resume *resume_info);
+
/* Get the thread ID from the current selected inferior (the current
thread). */
static DWORD
th = inferior_target_data (thread);
if (!th->suspend_count && get_context)
{
- if (get_context > 0 && id != current_event.dwThreadId)
+ if (id != current_event.dwThreadId)
th->suspend_count = SuspendThread (th->h) + 1;
- else if (get_context < 0)
- th->suspend_count = -1;
-
- th->context.ContextFlags = CONTEXT_DEBUGGER_DR;
- GetThreadContext (th->h, &th->context);
-
- if (id == current_event.dwThreadId)
- {
- /* Copy dr values from that thread. */
- if (the_low_target.store_debug_registers != NULL)
- (*the_low_target.store_debug_registers) (th);
- }
+ (*the_low_target.get_thread_context) (th, ¤t_event);
}
return th;
find_inferior_id (&all_threads, tid),
new_register_cache ());
- /* Set the debug registers for the new thread if they are used. */
- if (debug_registers_used
- && the_low_target.load_debug_registers != NULL)
- {
- /* Only change the value of the debug registers. */
- th->context.ContextFlags = CONTEXT_DEBUGGER_DR;
-
- GetThreadContext (th->h, &th->context);
-
- (*the_low_target.load_debug_registers) (th);
-
- SetThreadContext (th->h, &th->context);
- th->context.ContextFlags = 0;
- }
+ if (the_low_target.thread_added != NULL)
+ (*the_low_target.thread_added) (th);
return th;
}
/* The program has exec'ed a new executable file. The new file's
pathname is pointed to by value.execd_pathname. */
-
TARGET_WAITKIND_EXECD,
/* Nothing happened, but we stopped anyway. This perhaps should be handled
value;
};
-/* Return a pointer into a CONTEXT field indexed by gdb register number.
- Return a pointer to an dummy register holding zero if there is no
- corresponding CONTEXT field for the given register number. */
-char *
-regptr (CONTEXT* c, int r)
-{
- if (the_low_target.regmap[r] < 0)
- {
- static ULONG zero;
- /* Always force value to zero, in case the user tried to write
- to this register before. */
- zero = 0;
- return (char *) &zero;
- }
- else
- return (char *) c + the_low_target.regmap[r];
-}
-
-
/* Clear out any old thread list and reinitialize it to a pristine
state. */
static void
{
last_sig = TARGET_SIGNAL_0;
- debug_registers_changed = 0;
- debug_registers_used = 0;
-
memset (¤t_event, 0, sizeof (current_event));
child_init_thread_list ();
if ((thread_id == -1 || thread_id == th->tid)
&& th->suspend_count)
{
- for (i = 0; i < th->suspend_count; i++)
- (void) ResumeThread (th->h);
- th->suspend_count = 0;
- if (debug_registers_changed)
+ if (th->context.ContextFlags)
{
- /* Only change the value of the debug registers. */
- th->context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
-
- if (the_low_target.load_debug_registers != NULL)
- the_low_target.load_debug_registers (th);
-
- SetThreadContext (th->h, &th->context);
+ (*the_low_target.set_thread_context) (th, ¤t_event);
th->context.ContextFlags = 0;
}
+
+ for (i = 0; i < th->suspend_count; i++)
+ (void) ResumeThread (th->h);
+ th->suspend_count = 0;
}
return 0;
res = ContinueDebugEvent (current_event.dwProcessId,
current_event.dwThreadId, continue_status);
- continue_status = 0;
if (res)
find_inferior (&all_threads, continue_one_thread, &thread_id);
- debug_registers_changed = 0;
return res;
}
child_fetch_inferior_registers (NUM_REGS);
else
for (regno = 0; regno < r; regno++)
- (*the_low_target.fetch_inferior_registers) (th, regno);
-}
-
-/* Get register from gdbserver regcache data. */
-static void
-do_child_store_inferior_registers (win32_thread_info *th, int r)
-{
- collect_register (r, regptr (&th->context, r));
+ (*the_low_target.fetch_inferior_register) (th, regno);
}
/* Store a new register value into the current thread context. We don't
child_store_inferior_registers (NUM_REGS);
else
for (regno = 0; regno < r; regno++)
- do_child_store_inferior_registers (th, regno);
+ (*the_low_target.store_inferior_register) (th, regno);
}
/* Map the Windows error number in ERROR to a locale-dependent error
{
if (th->context.ContextFlags)
{
- if (debug_registers_changed)
- if (the_low_target.load_debug_registers != NULL)
- (*the_low_target.load_debug_registers) (th);
-
/* Move register values from the inferior into the thread
context structure. */
regcache_invalidate ();
error ("Single stepping is not supported "
"in this configuration.\n");
}
- SetThreadContext (th->h, &th->context);
+
+ (*the_low_target.set_thread_context) (th, ¤t_event);
th->context.ContextFlags = 0;
}
}
child_continue (continue_status, tid);
}
-static int
+static void
handle_exception (struct target_waitstatus *ourstatus)
{
- win32_thread_info *th;
DWORD code = current_event.u.Exception.ExceptionRecord.ExceptionCode;
ourstatus->kind = TARGET_WAITKIND_STOPPED;
- /* Record the context of the current thread. */
- th = thread_rec (current_event.dwThreadId, -1);
-
switch (code)
{
case EXCEPTION_ACCESS_VIOLATION:
break;
default:
if (current_event.u.Exception.dwFirstChance)
- return 0;
+ {
+ ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
+ return;
+ }
OUTMSG2 (("gdbserver: unknown target exception 0x%08lx at 0x%08lx",
current_event.u.Exception.ExceptionRecord.ExceptionCode,
(DWORD) current_event.u.Exception.ExceptionRecord.
}
OUTMSG2 (("\n"));
last_sig = ourstatus->value.sig;
- return 1;
}
-/* Get the next event from the child. Return 1 if the event requires
- handling. */
-static int
+/* Get the next event from the child. */
+static void
get_child_debug_event (struct target_waitstatus *ourstatus)
{
BOOL debug_event;
- DWORD continue_status, event_code;
- win32_thread_info *th = NULL;
- static win32_thread_info dummy_thread_info;
- int retval = 0;
-
-in:
last_sig = TARGET_SIGNAL_0;
ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
if (!(debug_event = WaitForDebugEvent (¤t_event, 1000)))
- goto out;
+ return;
current_inferior =
(struct thread_info *) find_inferior_id (&all_threads,
current_event.dwThreadId);
- continue_status = DBG_CONTINUE;
- event_code = current_event.dwDebugEventCode;
-
- switch (event_code)
+ switch (current_event.dwDebugEventCode)
{
case CREATE_THREAD_DEBUG_EVENT:
OUTMSG2 (("gdbserver: kernel event CREATE_THREAD_DEBUG_EVENT "
(unsigned) current_event.dwThreadId));
/* Record the existence of this thread. */
- th = child_add_thread (current_event.dwThreadId,
+ child_add_thread (current_event.dwThreadId,
current_event.u.CreateThread.hThread);
-
- retval = current_event.dwThreadId;
break;
case EXIT_THREAD_DEBUG_EVENT:
(unsigned) current_event.dwProcessId,
(unsigned) current_event.dwThreadId));
child_delete_thread (current_event.dwThreadId);
- th = &dummy_thread_info;
break;
case CREATE_PROCESS_DEBUG_EVENT:
ourstatus->value.execd_pathname = "Main executable";
/* Add the main thread. */
- th =
- child_add_thread (main_thread_id,
- current_event.u.CreateProcessInfo.hThread);
+ child_add_thread (main_thread_id,
+ current_event.u.CreateProcessInfo.hThread);
- retval = ourstatus->value.related_pid = current_event.dwThreadId;
+ ourstatus->value.related_pid = current_event.dwThreadId;
#ifdef _WIN32_WCE
/* Windows CE doesn't set the initial breakpoint automatically
like the desktop versions of Windows do. We add it explicitly
ourstatus->value.integer = current_event.u.ExitProcess.dwExitCode;
CloseHandle (current_process_handle);
current_process_handle = NULL;
- retval = main_thread_id;
break;
case LOAD_DLL_DEBUG_EVENT:
ourstatus->kind = TARGET_WAITKIND_LOADED;
ourstatus->value.integer = 0;
- retval = main_thread_id;
break;
case UNLOAD_DLL_DEBUG_EVENT:
"for pid=%d tid=%x\n",
(unsigned) current_event.dwProcessId,
(unsigned) current_event.dwThreadId));
- retval = handle_exception (ourstatus);
+ handle_exception (ourstatus);
break;
case OUTPUT_DEBUG_STRING_EVENT:
current_inferior =
(struct thread_info *) find_inferior_id (&all_threads,
current_event.dwThreadId);
-
- if (!retval || (event_code != EXCEPTION_DEBUG_EVENT && event_code != EXIT_PROCESS_DEBUG_EVENT))
- {
- child_continue (continue_status, -1);
- goto in;
- }
-
- if (th == NULL)
- thread_rec (current_event.dwThreadId, TRUE);
-
-out:
- return retval;
}
/* Wait for the inferior process to change state.
{
get_child_debug_event (&our_status);
- if (our_status.kind == TARGET_WAITKIND_EXITED)
+ switch (our_status.kind)
{
+ case TARGET_WAITKIND_EXITED:
OUTMSG2 (("Child exited with retcode = %x\n",
our_status.value.integer));
child_fetch_inferior_registers (-1);
return our_status.value.integer;
- }
- else if (our_status.kind == TARGET_WAITKIND_STOPPED)
- {
+ case TARGET_WAITKIND_STOPPED:
OUTMSG2 (("Child Stopped with signal = %d \n",
our_status.value.sig));
child_fetch_inferior_registers (-1);
return our_status.value.sig;
+ default:
+ OUTMSG (("Ignoring unknown internal event, %d\n", our_status.kind));
+ /* fall-through */
+ case TARGET_WAITKIND_SPURIOUS:
+ case TARGET_WAITKIND_LOADED:
+ case TARGET_WAITKIND_EXECD:
+ /* do nothing, just continue */
+ child_continue (DBG_CONTINUE, -1);
+ break;
}
- else
- OUTMSG (("Ignoring unknown internal event, %d\n", our_status.kind));
-
- {
- struct thread_resume resume;
- resume.thread = -1;
- resume.step = 0;
- resume.sig = 0;
- resume.leave_stopped = 0;
- win32_resume (&resume);
- }
}
}
struct win32_target_ops
{
- /* An array of offset mappings into a Win32 Context structure.
- This is a one-to-one mapping which is indexed by gdb's register
- numbers. It retrieves an offset into the context structure where
- the 4 byte register is located.
- An offset value of -1 indicates that Win32 does not provide this
- register in it's CONTEXT structure. In this case regptr will return
- a pointer into a dummy register. */
- const int *regmap;
-
- /* The number of elements of regmap. */
+ /* The number of target registers. */
int num_regs;
+ /* Perform initializations on startup. */
void (*initial_stuff) (void);
- void (*store_debug_registers) (win32_thread_info *);
- void (*load_debug_registers) (win32_thread_info *);
+ /* Fetch the context from the inferior. */
+ void (*get_thread_context) (win32_thread_info *th, DEBUG_EVENT *current_event);
- /* Fetch register(s) from gdbserver regcache data. */
- void (*fetch_inferior_registers) (win32_thread_info *th, int r);
+ /* Flush the context back to the inferior. */
+ void (*set_thread_context) (win32_thread_info *th, DEBUG_EVENT *current_event);
+
+ /* Called when a thread was added. */
+ void (*thread_added) (win32_thread_info *th);
+
+ /* Fetch register from gdbserver regcache data. */
+ void (*fetch_inferior_register) (win32_thread_info *th, int r);
+
+ /* Store a new register value into the thread context of TH. */
+ void (*store_inferior_register) (win32_thread_info *th, int r);
void (*single_step) (win32_thread_info *th);
extern struct win32_target_ops the_low_target;
-/* in win32-low.c */
-
-/* Return a pointer into a CONTEXT field indexed by gdb register number.
- Return a pointer to an dummy register holding zero if there is no
- corresponding CONTEXT field for the given register number. */
-extern char * regptr (CONTEXT* c, int r);
-
/* Map the Windows error number in ERROR to a locale-dependent error
message string and return a pointer to it. Typically, the values
for ERROR come from GetLastError.