* wince-stub.c (FREE): New macro.
authorChristopher Faylor <me+cygwin@cgf.cx>
Fri, 21 Apr 2000 03:04:35 +0000 (03:04 +0000)
committerChristopher Faylor <me+cygwin@cgf.cx>
Fri, 21 Apr 2000 03:04:35 +0000 (03:04 +0000)
(mempool): Just free any buffer prior to reuse.  Don't bother with realloc.
(flag_single_step): New function.
(skip_message): Detect "helpful" Windows CE messages and skip sending them to
the host.
(wait_for_debug_event): Use skip_message to avoid sending debug messages to the
host.
(dispatch): Prelimary implementation of single step detection.
* wince.c: Rework SH single stepping code to be more consistent with other
wince targets.
(handle_output_debug_string): Allow first chance exceptions to come through
since they seem to be all that we get on some versions of Windows CE.
(check_for_step): New function, conditionally compiled based on target.
(regptr): Delete obsolete function.
(handle_exception): Detect illegal instructions.
(get_child_debug_event): Return success only if event code matches target.
(child_create_inferior): Reflect change to get_child_debug_event arguments.

gdb/ChangeLog
gdb/config/sh/tm-wince.h
gdb/wince-stub.c
gdb/wince.c

index efb8921a22e1f60987f3f18dea90d0efe472c146..0f1f773541df23f2439754886bd0370b8179d48b 100644 (file)
@@ -1,3 +1,27 @@
+2000-04-20  Christopher Faylor  <cgf@cygnus.com>
+
+       * wince-stub.c (FREE): New macro.
+       (mempool): Just free any buffer prior to reuse.  Don't bother with
+       realloc.
+       (flag_single_step): New function.
+       (skip_message): Detect "helpful" Windows CE messages and skip sending
+       them to the host.
+       (wait_for_debug_event): Use skip_message to avoid sending debug
+       messages to the host.
+       (dispatch): Prelimary implementation of single step detection.
+       * wince.c: Rework SH single stepping code to be more consistent with
+       other wince targets.
+       (handle_output_debug_string): Allow first chance exceptions to come
+       through since they seem to be all that we get on some versions of
+       Windows CE.
+       (check_for_step): New function, conditionally compiled based on target.
+       (regptr): Delete obsolete function.
+       (handle_exception): Detect illegal instructions.
+       (get_child_debug_event): Return success only if event code matches
+       target.
+       (child_create_inferior): Reflect change to get_child_debug_event
+       arguments.
+
 2000-04-20  Christopher Faylor  <cgf@cygnus.com>
 
        * win32-nat.c (thread_rec): Be more defensive about suspending already
index 16816141d357cd377eafd4b4f7defb2a312584cc..88e2a6fefc6c6e7067fb46c2612ef567b8714a11 100644 (file)
@@ -1,5 +1,5 @@
 /* Target-specific definition for Window CE
-   Copyright 2000 Free Software Foundation, Inc.
+   Copyright (C) 2000 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
index d20223c1690ae11577ba7b981b096d0325c05914..ce872d8137e32957c1b5d428b5c80c1d6e5706cb 100644 (file)
 #include <winsock.h>
 #include "wince-stub.h"
 
-#define MALLOC(n) (void *) LocalAlloc (LMEM_MOVEABLE, (UINT)(n))
+#define MALLOC(n) (void *) LocalAlloc (LMEM_MOVEABLE | LMEM_ZEROINIT, (UINT)(n))
 #define REALLOC(s, n) (void *) LocalReAlloc ((HLOCAL)(s), (UINT)(n), LMEM_MOVEABLE)
+#define FREE(s) LocalFree ((HLOCAL)(s))
 
 static int skip_next_id = 0;   /* Don't read next API code from socket */
 
-/* v-style interface for handling varying argyment list error messages.
+/* v-style interface for handling varying argument list error messages.
    Displays the error message in a dialog box and exits when user clicks
    on OK. */
 static void
@@ -56,6 +57,27 @@ stub_error (LPCWSTR fmt, ...)
   vstub_error (fmt, args);
 }
 
+/* Allocate a limited pool of memory, reallocating over unused
+   buffers.  This assumes that there will never be more than four
+   "buffers" required which, so far, is a safe assumption. */
+static LPVOID
+mempool (unsigned int len)
+{
+  static int outn = -1;
+  static LPWSTR outs[4] = {NULL, NULL, NULL, NULL};
+
+  if (++outn >= (sizeof (outs) / sizeof (outs[0])))
+    outn = 0;
+
+  /* Allocate space for the converted string, reusing any previously allocated
+     space, if applicable. */
+  if (outs[outn])
+    FREE (outs[outn]);
+  outs[outn] = (LPWSTR) MALLOC (len);
+
+  return outs[outn];
+}
+
 /* Standard "oh well" can't communicate error.  Someday this might attempt
    synchronization. */
 static void
@@ -88,28 +110,6 @@ sockwrite (LPCWSTR huh, int s, const void *str, size_t n)
     }
 }
 
-/* Allocate a limited pool of memory, reallocating over unused
-   buffers.  This assumes that there will never be more than four
-   "buffers" required which, so far, is a safe assumption. */
-static LPVOID
-mempool (gdb_wince_len len)
-{
-  static int n = -1;
-  static LPWSTR outs[4] = {NULL /*, NULL, etc. */};
-
-  if (++n >= (sizeof (outs) / sizeof (outs[0])))
-    n = 0;
-
-  /* Allocate space for the converted string, reusing any previously allocated
-     space, if applicable. */
-  if (outs[n])
-    outs[n] = (LPWSTR) REALLOC (outs[n], len);
-  else
-    outs[n] = (LPWSTR) MALLOC (len);
-
-  return outs[n];
-}
-
 /* Get a an ID (possibly) and a DWORD from the host gdb.
    Don't bother with the id if the main loop has already
    read it. */
@@ -175,7 +175,7 @@ getmemory (LPCWSTR huh, int s, gdb_wince_id what, gdb_wince_len *inlen)
 
   *inlen = getlen (huh, s, what);
 
-  p = mempool (*inlen);                /* FIXME: check for error */
+  p = mempool ((unsigned int) *inlen); /* FIXME: check for error */
 
   if ((gdb_wince_len) sockread (huh, s, p, *inlen) != *inlen)
     stub_error (L"error getting string from host.");
@@ -269,6 +269,49 @@ terminate_process (int s)
             &res, sizeof (res));
 }
 
+static int stepped = 0;
+/* Handle single step instruction.  FIXME: unneded? */
+static void
+flag_single_step (int s)
+{
+  stepped = 1;
+  skip_next_id = 0;
+}
+
+struct skipper
+{
+  wchar_t *s;
+  int nskip;
+} skippy[] =
+{
+  {L"Undefined Instruction:", 1},
+  {L"Data Abort:", 2},
+  {NULL, 0}
+};
+
+static int
+skip_message (DEBUG_EVENT *ev)
+{
+  char s[80];
+  DWORD nread;
+  struct skipper *skp;
+  int nbytes = ev->u.DebugString.nDebugStringLength;
+
+  if (nbytes > sizeof(s))
+    nbytes = sizeof(s);
+
+  memset (s, 0, sizeof (s));
+  if (!ReadProcessMemory (curproc, ev->u.DebugString.lpDebugStringData,
+                         s, nbytes, &nread))
+    return 0;
+
+  for (skp = skippy; skp->s != NULL; skp++)
+    if (wcsncmp ((wchar_t *) s, skp->s, wcslen (skp->s)) == 0)
+      return skp->nskip;
+
+  return 0;
+}
+
 /* Emulate WaitForDebugEvent.  Returns the debug event on success. */
 static void
 wait_for_debug_event (int s)
@@ -276,10 +319,32 @@ wait_for_debug_event (int s)
   DWORD ms = getdword (L"WaitForDebugEvent ms", s, GDB_WAITFORDEBUGEVENT);
   gdb_wince_result res;
   DEBUG_EVENT ev;
+  static int skip_next = 0;
+
+  for (;;)
+    {
+      res = WaitForDebugEvent (&ev, ms);
+
+      if (ev.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT)
+       {
+         if (skip_next)
+           {
+             skip_next--;
+             goto ignore;
+           }
+         if (skip_next = skip_message (&ev))
+           goto ignore;
+       }
+
+      putresult (L"WaitForDebugEvent event", res, s, GDB_WAITFORDEBUGEVENT,
+                &ev, sizeof (ev));
+      break;
+
+    ignore:
+      ContinueDebugEvent (ev.dwProcessId, ev.dwThreadId, DBG_CONTINUE);
+    }
 
-  res = WaitForDebugEvent (&ev, ms);
-  putresult (L"WaitForDebugEvent event", res, s, GDB_WAITFORDEBUGEVENT,
-            &ev, sizeof (ev));
+  return;
 }
 
 /* Emulate GetThreadContext.  Returns CONTEXT structure on success. */
@@ -291,7 +356,7 @@ get_thread_context (int s)
   gdb_wince_result res;
 
   memset (&c, 0, sizeof (c));
-  c.ContextFlags = getdword (L"GetThreadContext handle", s, GDB_GETTHREADCONTEXT);
+  c.ContextFlags = getdword (L"GetThreadContext flags", s, GDB_GETTHREADCONTEXT);
 
   res = (gdb_wince_result) GetThreadContext (h, &c);
   putresult (L"GetThreadContext data", res, s, GDB_GETTHREADCONTEXT,
@@ -319,7 +384,7 @@ read_process_memory (int s)
   HANDLE h = gethandle (L"ReadProcessMemory handle", s, GDB_READPROCESSMEMORY);
   LPVOID p = getpvoid (L"ReadProcessMemory base", s, GDB_READPROCESSMEMORY);
   gdb_wince_len len = getlen (L"ReadProcessMemory size", s, GDB_READPROCESSMEMORY);
-  LPVOID buf = mempool ((gdb_wince_len) len);
+  LPVOID buf = mempool ((unsigned int) len);
   DWORD outlen;
   gdb_wince_result res;
 
@@ -400,12 +465,6 @@ close_handle (int s)
   putresult (L"CloseHandle result", res, s, GDB_CLOSEHANDLE, &res, sizeof (res));
 }
 
-/* Handle single step instruction */
-static void
-single_step (int s)
-{
-}
-
 /* Main loop for reading requests from gdb host on the socket. */
 static void
 dispatch (int s)
@@ -458,8 +517,8 @@ dispatch (int s)
          terminate_process (s);
          return;
        case GDB_SINGLESTEP:
-         single_step (s);
-         return;
+         flag_single_step (s);
+         break;
        default:
          {
            WCHAR buf[80];
@@ -495,8 +554,6 @@ WinMain (HINSTANCE hi, HINSTANCE hp, LPWSTR cmd, int show)
       wcstombs (host, whost, 80);      /* Convert from UNICODE to ascii */
     }
 
-  MessageBoxW (NULL, whost, L"GDB", MB_ICONERROR);
-
   /* Winsock initialization. */
   if (WSAStartup (MAKEWORD (1, 1), &wd))
     stub_error (L"Couldn't initialize WINSOCK.");
index 77780d4dbc006159f51b4b16897dd2afa79d5c2e..27d3de222bfbf2c426383e4372946432e02d956d 100644 (file)
@@ -55,6 +55,7 @@
 #include <sys/param.h>
 #include "wince-stub.h"
 #include "dcache.h"
+#include <time.h>
 
 /* The ui's event loop. */
 extern int (*ui_loop_hook) PARAMS ((int signo));
@@ -147,7 +148,6 @@ typedef struct thread_info_struct
     int suspend_count;
     int stepped;               /* True if stepped. */
     CORE_ADDR step_pc;
-    unsigned long step_instr;
     unsigned long step_prev;
     CONTEXT context;
   }
@@ -155,6 +155,7 @@ thread_info;
 
 static thread_info thread_head =
 {NULL};
+static thread_info * thread_rec (DWORD id, int get_context);
 
 /* The process and thread handles for the above context. */
 
@@ -374,24 +375,21 @@ static const int mappings[NUM_REGS + 1] =
   -1
 };
 
-/* This vector maps the target's idea of an exception (extracted
-   from the DEBUG_EVENT structure) to GDB's idea. */
-
-struct xlate_exception
-  {
-    int them;
-    enum target_signal us;
-  };
-
-static const struct xlate_exception
-  xlate[] =
+/* Return a pointer into a CONTEXT field indexed by gdb register number.
+   Return a pointer to an address pointing to zero if there is no
+   corresponding CONTEXT field for the given register number.
+ */
+static ULONG *
+regptr (LPCONTEXT c, int r)
 {
-  {EXCEPTION_ACCESS_VIOLATION, TARGET_SIGNAL_SEGV},
-  {STATUS_STACK_OVERFLOW, TARGET_SIGNAL_SEGV},
-  {EXCEPTION_BREAKPOINT, TARGET_SIGNAL_TRAP},
-  {DBG_CONTROL_C, TARGET_SIGNAL_INT},
-  {EXCEPTION_SINGLE_STEP, TARGET_SIGNAL_TRAP},
-  {-1, -1}};
+  static ULONG zero = 0;
+  ULONG *p;
+  if (mappings[r] < 0)
+    p = &zero;
+  else
+    p = (ULONG *) (((char *) c) + mappings[r]);
+  return p;
+}
 
 /******************** Beginning of stub interface ********************/
 
@@ -629,6 +627,7 @@ towide (const char *s, gdb_wince_len * out_len)
   typedef in wince-stub.h and change the putlen/getlen macros in this file and in
   the stub.
 */
+
 static int
 create_process (LPSTR exec_file, LPSTR args, DWORD flags, PROCESS_INFORMATION * pi)
 {
@@ -798,6 +797,227 @@ stop_stub ()
 /******************** End of emulation routines. ********************/
 /******************** End of stub interface ********************/
 
+#define check_for_step(a, x) (x)
+
+#ifdef MIPS
+static void
+undoSStep (thread_info * th)
+{
+  if (th->stepped)
+    {
+      memory_remove_breakpoint (th->step_pc, (void *) &th->step_prev);
+      th->stepped = 0;
+    }
+}
+
+void
+wince_software_single_step (unsigned int ignore, int insert_breakpoints_p)
+{
+  unsigned long pc;
+  thread_info *th = current_thread;    /* Info on currently selected thread */
+  CORE_ADDR mips_next_pc (CORE_ADDR pc);
+
+  if (!insert_breakpoints_p)
+    {
+      undoSStep (th);
+      return;
+    }
+
+  th->stepped = 1;
+  pc = read_register (PC_REGNUM);
+  th->step_pc = mips_next_pc (pc);
+  th->step_prev = 0;
+  memory_insert_breakpoint (th->step_pc, (void *) &th->step_prev);
+  return;
+}
+#elif SHx
+/* Hitachi SH architecture instruction encoding masks */
+
+#define COND_BR_MASK   0xff00
+#define UCOND_DBR_MASK 0xe000
+#define UCOND_RBR_MASK 0xf0df
+#define TRAPA_MASK     0xff00
+
+#define COND_DISP      0x00ff
+#define UCOND_DISP     0x0fff
+#define UCOND_REG      0x0f00
+
+/* Hitachi SH instruction opcodes */
+
+#define BF_INSTR       0x8b00
+#define BT_INSTR       0x8900
+#define BRA_INSTR      0xa000
+#define BSR_INSTR      0xb000
+#define JMP_INSTR      0x402b
+#define JSR_INSTR      0x400b
+#define RTS_INSTR      0x000b
+#define RTE_INSTR      0x002b
+#define TRAPA_INSTR    0xc300
+#define SSTEP_INSTR    0xc3ff
+
+
+#define T_BIT_MASK     0x0001
+
+static CORE_ADDR
+sh_get_next_pc (CONTEXT *c)
+{
+  short *instrMem;
+  int displacement;
+  int reg;
+  unsigned short opcode;
+
+  instrMem = (short *) c->Fir;
+
+  opcode = read_memory_integer ((CORE_ADDR) c->Fir, sizeof (opcode));
+
+  if ((opcode & COND_BR_MASK) == BT_INSTR)
+    {
+      if (c->Psr & T_BIT_MASK)
+       {
+         displacement = (opcode & COND_DISP) << 1;
+         if (displacement & 0x80)
+           displacement |= 0xffffff00;
+         /*
+            * Remember PC points to second instr.
+            * after PC of branch ... so add 4
+          */
+         instrMem = (short *) (c->Fir + displacement + 4);
+       }
+      else
+       instrMem += 1;
+    }
+  else if ((opcode & COND_BR_MASK) == BF_INSTR)
+    {
+      if (c->Psr & T_BIT_MASK)
+       instrMem += 1;
+      else
+       {
+         displacement = (opcode & COND_DISP) << 1;
+         if (displacement & 0x80)
+           displacement |= 0xffffff00;
+         /*
+            * Remember PC points to second instr.
+            * after PC of branch ... so add 4
+          */
+         instrMem = (short *) (c->Fir + displacement + 4);
+       }
+    }
+  else if ((opcode & UCOND_DBR_MASK) == BRA_INSTR)
+    {
+      displacement = (opcode & UCOND_DISP) << 1;
+      if (displacement & 0x0800)
+       displacement |= 0xfffff000;
+
+      /*
+        * Remember PC points to second instr.
+        * after PC of branch ... so add 4
+       */
+      instrMem = (short *) (c->Fir + displacement + 4);
+    }
+  else if ((opcode & UCOND_RBR_MASK) == JSR_INSTR)
+    {
+      reg = (char) ((opcode & UCOND_REG) >> 8);
+
+      instrMem = (short *) *regptr (c, reg);
+    }
+  else if (opcode == RTS_INSTR)
+    instrMem = (short *) c->PR;
+  else if (opcode == RTE_INSTR)
+    instrMem = (short *) *regptr (c, 15);
+  else if ((opcode & TRAPA_MASK) == TRAPA_INSTR)
+    instrMem = (short *) ((opcode & ~TRAPA_MASK) << 2);
+  else
+    instrMem += 1;
+
+  return (CORE_ADDR) instrMem;
+}
+/* Single step (in a painstaking fashion) by inspecting the current
+   instruction and setting a breakpoint on the "next" instruction
+   which would be executed.  This code hails from sh-stub.c.
+ */
+static void
+undoSStep (thread_info * th)
+{
+  if (th->stepped)
+    {
+      memory_remove_breakpoint (th->step_pc, (void *) &th->step_prev);
+      th->stepped = 0;
+    }
+  return;
+}
+
+/* Single step (in a painstaking fashion) by inspecting the current
+   instruction and setting a breakpoint on the "next" instruction
+   which would be executed.  This code hails from sh-stub.c.
+ */
+void
+wince_software_single_step (unsigned int ignore, int insert_breakpoints_p)
+{
+  thread_info *th = current_thread;    /* Info on currently selected thread */
+
+  if (!insert_breakpoints_p)
+    {
+      undoSStep (th);
+      return;
+    }
+
+  th->stepped = 1;
+  th->step_pc = sh_get_next_pc (&th->context);
+  th->step_prev = 0;
+  memory_insert_breakpoint (th->step_pc, (void *) &th->step_prev);
+  return;
+}
+#elif defined (ARM)
+#undef check_for_step
+
+static enum target_signal
+check_for_step (DEBUG_EVENT *ev, enum target_signal x)
+{
+  thread_info *th = thread_rec (ev->dwThreadId, 1);
+
+  if (th->stepped &&
+      th->step_pc == (CORE_ADDR) ev->u.Exception.ExceptionRecord.ExceptionAddress)
+    return TARGET_SIGNAL_TRAP;
+  else
+    return x;
+}
+
+/* Single step (in a painstaking fashion) by inspecting the current
+   instruction and setting a breakpoint on the "next" instruction
+   which would be executed.  This code hails from sh-stub.c.
+ */
+static void
+undoSStep (thread_info * th)
+{
+  if (th->stepped)
+    {
+      memory_remove_breakpoint (th->step_pc, (void *) &th->step_prev);
+      th->stepped = 0;
+    }
+}
+
+void
+wince_software_single_step (unsigned int ignore, int insert_breakpoints_p)
+{
+  unsigned long pc;
+  thread_info *th = current_thread;    /* Info on currently selected thread */
+  CORE_ADDR mips_next_pc (CORE_ADDR pc);
+
+  if (!insert_breakpoints_p)
+    {
+      undoSStep (th);
+      return;
+    }
+
+  th->stepped = 1;
+  pc = read_register (PC_REGNUM);
+  th->step_pc = arm_get_next_pc (pc);
+  th->step_prev = 0;
+  memory_insert_breakpoint (th->step_pc, (void *) &th->step_prev);
+  return;
+}
+#endif
+
 /* Find a thread record given a thread id.
    If get_context then also retrieve the context for this
    thread. */
@@ -893,22 +1113,6 @@ check (BOOL ok, const char *file, int line)
     printf_filtered ("error return %s:%d was %d\n", file, line, GetLastError ());
 }
 
-/* Return a pointer into a CONTEXT field indexed by gdb register number.
-   Return a pointer to an address pointing to zero if there is no
-   corresponding CONTEXT field for the given register number.
- */
-static ULONG *
-regptr (LPCONTEXT c, int r)
-{
-  static ULONG zero = 0;
-  ULONG *p;
-  if (mappings[r] < 0)
-    p = &zero;
-  else
-    p = (ULONG *) (((char *) c) + mappings[r]);
-  return p;
-}
-
 static void
 do_child_fetch_inferior_registers (int r)
 {
@@ -991,7 +1195,9 @@ handle_load_dll (PTR dummy)
 out:
   if (!len)
     return 1;
+#if 0
   dll_buf[len] = '\0';
+#endif
   dll_name = alloca (len);
 
   if (!dll_name)
@@ -1021,22 +1227,12 @@ out:
      FIXME: Is this the real reason that we need the 0x1000 ? */
 
   printf_unfiltered ("%x:%s", event->lpBaseOfDll, dll_name);
-#if 0                          /* FIXME:  Need to use RAPI stuff to read the file someday. */
-  {
-    struct section_addr_info section_addrs;
-    memset (&section_addrs, 0, sizeof (section_addrs));
-    section_addrs.text_addr = (int) event->lpBaseOfDll + 0x1000;
-    symbol_file_add (dll_name, 0, &section_addrs, 0, OBJF_SHARED);
-  }
-#endif
   printf_unfiltered ("\n");
 
   return 1;
 }
 
-/* Handle DEBUG_STRING output from child process.
-   Cygwin prepends its messages with a "cygwin:".  Interpret this as
-   a Cygwin signal.  Otherwise just print the string as a warning. */
+/* Handle DEBUG_STRING output from child process. */
 static void
 handle_output_debug_string (struct target_waitstatus *ourstatus)
 {
@@ -1068,6 +1264,7 @@ handle_output_debug_string (struct target_waitstatus *ourstatus)
     }
 
   warning (s);
+
   return;
 }
 
@@ -1075,16 +1272,13 @@ handle_output_debug_string (struct target_waitstatus *ourstatus)
 static int
 handle_exception (struct target_waitstatus *ourstatus)
 {
-  thread_info *th;
-
+#if 0
   if (current_event.u.Exception.dwFirstChance)
     return 0;
+#endif
 
   ourstatus->kind = TARGET_WAITKIND_STOPPED;
 
-  /* Record the context of the current thread */
-  th = thread_rec (current_event.dwThreadId, -1);
-
   switch (current_event.u.Exception.ExceptionRecord.ExceptionCode)
     {
     case EXCEPTION_ACCESS_VIOLATION:
@@ -1114,10 +1308,15 @@ handle_exception (struct target_waitstatus *ourstatus)
                     (unsigned) current_event.u.Exception.ExceptionRecord.ExceptionAddress));
       ourstatus->value.sig = TARGET_SIGNAL_TRAP;
       break;
+    case EXCEPTION_ILLEGAL_INSTRUCTION:
+      DEBUG_EXCEPT (("gdb: Target exception SINGLE_ILL at 0x%08x\n",
+              current_event.u.Exception.ExceptionRecord.ExceptionAddress));
+      ourstatus->value.sig = check_for_step (&current_event, TARGET_SIGNAL_ILL);
+      break;
     default:
       /* This may be a structured exception handling exception.  In
-         that case, we want to let the program try to handle it, and
-         only break if we see the exception a second time.  */
+        that case, we want to let the program try to handle it, and
+        only break if we see the exception a second time.  */
 
       printf_unfiltered ("gdb: unknown target exception 0x%08x at 0x%08x\n",
                    current_event.u.Exception.ExceptionRecord.ExceptionCode,
@@ -1159,23 +1358,29 @@ child_continue (DWORD continue_status, int id)
    handling by WFI (or whatever).
  */
 static int
-get_child_debug_event (int pid, struct target_waitstatus *ourstatus, DWORD * event_code, int *retval)
+get_child_debug_event (int pid, struct target_waitstatus *ourstatus,
+                      DWORD target_event_code, int *retval)
 {
+  int breakout = 0;
   BOOL debug_event;
-  DWORD continue_status;
-  int breakout = 1;
+  DWORD continue_status, event_code;
+  thread_info *th = NULL;
+  static thread_info dummy_thread_info;
 
   if (!(debug_event = wait_for_debug_event (&current_event, 1000)))
     {
-      breakout = *retval = *event_code = 0;
+      *retval = 0;
       goto out;
     }
 
-  this_thread = thread_rec (current_event.dwThreadId, FALSE);
   event_count++;
   continue_status = DBG_CONTINUE;
   *retval = 0;
-  switch (*event_code = current_event.dwDebugEventCode)
+
+  event_code = current_event.dwDebugEventCode;
+  breakout = event_code == target_event_code;
+
+  switch (event_code)
     {
     case CREATE_THREAD_DEBUG_EVENT:
       DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%x code=%s)\n",
@@ -1183,8 +1388,8 @@ get_child_debug_event (int pid, struct target_waitstatus *ourstatus, DWORD * eve
                     (unsigned) current_event.dwThreadId,
                     "CREATE_THREAD_DEBUG_EVENT"));
       /* Record the existence of this thread */
-      child_add_thread (current_event.dwThreadId,
-                       current_event.u.CreateThread.hThread);
+      th = child_add_thread (current_event.dwThreadId,
+                            current_event.u.CreateThread.hThread);
       if (info_verbose)
        printf_unfiltered ("[New %s]\n",
                           target_pid_to_str (current_event.dwThreadId));
@@ -1196,6 +1401,7 @@ get_child_debug_event (int pid, struct target_waitstatus *ourstatus, DWORD * eve
                     (unsigned) current_event.dwThreadId,
                     "EXIT_THREAD_DEBUG_EVENT"));
       child_delete_thread (current_event.dwThreadId);
+      th = &dummy_thread_info;
       break;
 
     case CREATE_PROCESS_DEBUG_EVENT:
@@ -1207,8 +1413,8 @@ get_child_debug_event (int pid, struct target_waitstatus *ourstatus, DWORD * eve
 
       main_thread_id = inferior_pid = current_event.dwThreadId;
       /* Add the main thread */
-      current_thread = child_add_thread (inferior_pid,
-                                current_event.u.CreateProcessInfo.hThread);
+      th = child_add_thread (inferior_pid,
+                            current_event.u.CreateProcessInfo.hThread);
       break;
 
     case EXIT_PROCESS_DEBUG_EVENT:
@@ -1220,7 +1426,8 @@ get_child_debug_event (int pid, struct target_waitstatus *ourstatus, DWORD * eve
       ourstatus->value.integer = current_event.u.ExitProcess.dwExitCode;
       close_handle (current_process_handle);
       *retval = current_event.dwProcessId;
-      goto out;
+      breakout = 1;
+      break;
 
     case LOAD_DLL_DEBUG_EVENT:
       DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n",
@@ -1244,14 +1451,12 @@ get_child_debug_event (int pid, struct target_waitstatus *ourstatus, DWORD * eve
                     (unsigned) current_event.dwThreadId,
                     "EXCEPTION_DEBUG_EVENT"));
       if (handle_exception (ourstatus))
+       *retval = current_event.dwThreadId;
+      else
        {
-         char buf[32];
-         *retval = current_event.dwThreadId;
-         remote_read_bytes (read_pc (), buf, sizeof (buf));
-         dcache_xfer_memory (remote_dcache, read_pc (), buf, sizeof (buf), 0);
-         goto out;
+         continue_status = DBG_EXCEPTION_NOT_HANDLED;
+         breakout = 0;
        }
-      continue_status = DBG_EXCEPTION_NOT_HANDLED;
       break;
 
     case OUTPUT_DEBUG_STRING_EVENT:    /* message from the kernel */
@@ -1259,7 +1464,7 @@ get_child_debug_event (int pid, struct target_waitstatus *ourstatus, DWORD * eve
                     (unsigned) current_event.dwProcessId,
                     (unsigned) current_event.dwThreadId,
                     "OUTPUT_DEBUG_STRING_EVENT"));
-      handle_output_debug_string (ourstatus);
+      handle_output_debug_string ( ourstatus);
       break;
     default:
       printf_unfiltered ("gdb: kernel event for pid=%d tid=%d\n",
@@ -1270,8 +1475,10 @@ get_child_debug_event (int pid, struct target_waitstatus *ourstatus, DWORD * eve
       break;
     }
 
-  breakout = 0;
-  CHECK (child_continue (continue_status, -1));
+  if (breakout)
+    this_thread = current_thread = th ?: thread_rec (current_event.dwThreadId, TRUE);
+  else
+    CHECK (child_continue (continue_status, -1));
 
 out:
   return breakout;
@@ -1291,7 +1498,7 @@ child_wait (int pid, struct target_waitstatus *ourstatus)
      isn't necessarily what you think it is. */
 
   while (1)
-    if (get_child_debug_event (pid, ourstatus, &event_code, &retval))
+    if (get_child_debug_event (pid, ourstatus, EXCEPTION_DEBUG_EVENT, &retval))
       return retval;
     else
       {
@@ -1351,14 +1558,15 @@ char *
 upload_to_device (const char *to, const char *from)
 {
   HANDLE h;
-  const char *dir = remote_directory ? : "\\gdb";
+  const char *dir = remote_directory ?: "\\gdb";
   int len;
   static char *remotefile = NULL;
   LPWSTR wstr;
   char *p;
   DWORD err;
   const char *in_to = to;
-  FILETIME ctime, atime, wtime;
+  FILETIME crtime, actime, wrtime;
+  time_t utime;
   struct stat st;
   int fd;
 
@@ -1397,15 +1605,25 @@ upload_to_device (const char *to, const char *from)
 
   /* Some kind of problem? */
   err = CeGetLastError ();
-  if (h == NULL)
-    error ("error creating file to \"%s\".  Windows error %d.",
+  if (h == NULL || h == INVALID_HANDLE_VALUE)
+    error ("error opening file \"%s\".  Windows error %d.",
           remotefile, err);
 
+  CeGetFileTime (h, &crtime, &actime, &wrtime);
+  utime = to_time_t (&wrtime);
+#if 0
+  if (utime < st.st_mtime)
+    {
+      char buf[80];
+      strcpy (buf, ctime(&utime));
+      printf ("%s < %s\n", buf, ctime(&st.st_mtime));
+    }
+#endif
   /* See if we need to upload the file. */
   if (upload_when == UPLOAD_ALWAYS ||
       err != ERROR_ALREADY_EXISTS ||
-      !CeGetFileTime (h, &ctime, &atime, &wtime) ||
-      to_time_t (&wtime) < st.st_mtime)
+      !CeGetFileTime (h, &crtime, &actime, &wrtime) ||
+      to_time_t (&wrtime) < st.st_mtime)
     {
       DWORD nbytes;
       char buf[4096];
@@ -1419,7 +1637,8 @@ upload_to_device (const char *to, const char *from)
     }
 
   close (fd);
-  CeCloseHandle (h);
+  if (!CeCloseHandle (h))
+    error ("error closing remote file - %d.", CeGetLastError ());
 
   return remotefile;
 }
@@ -1555,11 +1774,10 @@ child_create_inferior (char *exec_file, char *args, char **env)
   target_terminal_init ();
   target_terminal_inferior ();
 
-
   /* Run until process and threads are loaded */
-  do
-    get_child_debug_event (inferior_pid, &dummy, &event_code, &ret);
-  while (event_code != CREATE_PROCESS_DEBUG_EVENT);
+  while (!get_child_debug_event (inferior_pid, &dummy,
+                                CREATE_PROCESS_DEBUG_EVENT, &ret))
+    continue;
 
   proceed ((CORE_ADDR) -1, TARGET_SIGNAL_0, 0);
 }
@@ -1607,213 +1825,6 @@ child_kill_inferior (void)
   target_mourn_inferior ();    /* or just child_mourn_inferior? */
 }
 
-#ifdef MIPS
-static void
-undoSStep (thread_info * th)
-{
-  if (th->stepped)
-    {
-      memory_remove_breakpoint (th->step_pc, (void *) &th->step_prev);
-      th->stepped = 0;
-    }
-}
-
-void
-wince_software_single_step (unsigned int ignore, int insert_breakpoints_p)
-{
-  unsigned long pc;
-  thread_info *th = current_thread;    /* Info on currently selected thread */
-  CORE_ADDR mips_next_pc (CORE_ADDR pc);
-
-  if (!insert_breakpoints_p)
-    {
-      undoSStep (th);
-      return;
-    }
-
-  th->stepped = 1;
-  pc = read_register (PC_REGNUM);
-  th->step_pc = mips_next_pc (pc);
-  th->step_prev = 0;
-  memory_insert_breakpoint (th->step_pc, (void *) &th->step_prev);
-}
-#elif SHx
-/* Hitachi SH architecture instruction encoding masks */
-
-#define COND_BR_MASK   0xff00
-#define UCOND_DBR_MASK 0xe000
-#define UCOND_RBR_MASK 0xf0df
-#define TRAPA_MASK     0xff00
-
-#define COND_DISP      0x00ff
-#define UCOND_DISP     0x0fff
-#define UCOND_REG      0x0f00
-
-/* Hitachi SH instruction opcodes */
-
-#define BF_INSTR       0x8b00
-#define BT_INSTR       0x8900
-#define BRA_INSTR      0xa000
-#define BSR_INSTR      0xb000
-#define JMP_INSTR      0x402b
-#define JSR_INSTR      0x400b
-#define RTS_INSTR      0x000b
-#define RTE_INSTR      0x002b
-#define TRAPA_INSTR    0xc300
-#define SSTEP_INSTR    0xc3ff
-
-
-#define T_BIT_MASK     0x0001
-
-/* Undo the effect of a previous doSStep.  If we single stepped,
-   restore the old instruction. */
-
-static void
-undoSStep (thread_info * th)
-{
-  if (th->stepped)
-    {
-      gdb_wince_len done;
-      write_process_memory (current_process_handle, (LPVOID) th->step_pc,
-                         (LPVOID) & th->step_instr, sizeof (short), &done);
-      if (done != sizeof (short))
-         error ("error unsetting single step.");
-      th->stepped = 0;
-    }
-}
-
-/* Single step (in a painstaking fashion) by inspecting the current
-   instruction and setting a breakpoint on the "next" instruction
-   which would be executed.  This code hails from sh-stub.c.
- */
-void
-wince_software_single_step (unsigned int ignore, int insert_breakpoints_p)
-{
-  thread_info *th = current_thread;    /* Info on currently selected thread */
-
-  if (!insert_breakpoints_p)
-    undoSStep (th);
-  else
-    {
-      short *instrMem;
-      int displacement;
-      int reg;
-      unsigned short opcode;
-      gdb_wince_len done;
-      LPCONTEXT c = &th->context;
-
-      instrMem = (short *) c->Fir;
-
-      read_process_memory (current_process_handle, (LPCVOID) c->Fir, &opcode,
-                          sizeof (opcode), &done);
-      if (done != sizeof (opcode))
-       error ("couldn't retrieve opcode");
-      th->stepped = 1;
-
-      if ((opcode & COND_BR_MASK) == BT_INSTR)
-       {
-         if (c->Psr & T_BIT_MASK)
-           {
-             displacement = (opcode & COND_DISP) << 1;
-             if (displacement & 0x80)
-               displacement |= 0xffffff00;
-             /*
-                * Remember PC points to second instr.
-                * after PC of branch ... so add 4
-              */
-             instrMem = (short *) (c->Fir + displacement + 4);
-           }
-         else
-           instrMem += 1;
-       }
-      else if ((opcode & COND_BR_MASK) == BF_INSTR)
-       {
-         if (c->Psr & T_BIT_MASK)
-           instrMem += 1;
-         else
-           {
-             displacement = (opcode & COND_DISP) << 1;
-             if (displacement & 0x80)
-               displacement |= 0xffffff00;
-             /*
-                * Remember PC points to second instr.
-                * after PC of branch ... so add 4
-              */
-             instrMem = (short *) (c->Fir + displacement + 4);
-           }
-       }
-      else if ((opcode & UCOND_DBR_MASK) == BRA_INSTR)
-       {
-         displacement = (opcode & UCOND_DISP) << 1;
-         if (displacement & 0x0800)
-           displacement |= 0xfffff000;
-
-         /*
-            * Remember PC points to second instr.
-            * after PC of branch ... so add 4
-          */
-         instrMem = (short *) (c->Fir + displacement + 4);
-       }
-      else if ((opcode & UCOND_RBR_MASK) == JSR_INSTR)
-       {
-         reg = (char) ((opcode & UCOND_REG) >> 8);
-
-         instrMem = (short *) *regptr (c, reg);
-       }
-      else if (opcode == RTS_INSTR)
-       instrMem = (short *) c->PR;
-      else if (opcode == RTE_INSTR)
-       instrMem = (short *) *regptr (c, 15);
-      else if ((opcode & TRAPA_MASK) == TRAPA_INSTR)
-       instrMem = (short *) ((opcode & ~TRAPA_MASK) << 2);
-      else
-       instrMem += 1;
-
-      th->step_pc = (CORE_ADDR) instrMem;
-
-      read_process_memory (current_process_handle, (LPVOID) instrMem,
-                          (LPVOID) & th->step_instr, sizeof (short), &done);
-      opcode = SSTEP_INSTR;
-      write_process_memory (current_process_handle, (LPVOID) instrMem,
-                           (LPVOID) & opcode, sizeof (short), &done);
-    }
-}
-#elif defined (ARM)
-/* Single step (in a painstaking fashion) by inspecting the current
-   instruction and setting a breakpoint on the "next" instruction
-   which would be executed.  This code hails from sh-stub.c.
- */
-static void
-undoSStep (thread_info * th)
-{
-  if (th->stepped)
-    {
-      memory_remove_breakpoint (th->step_pc, (void *) &th->step_prev);
-      th->stepped = 0;
-    }
-}
-
-void
-wince_software_single_step (unsigned int ignore, int insert_breakpoints_p)
-{
-  unsigned long pc;
-  thread_info *th = current_thread;    /* Info on currently selected thread */
-  CORE_ADDR mips_next_pc (CORE_ADDR pc);
-
-  if (!insert_breakpoints_p)
-    {
-      undoSStep (th);
-      return;
-    }
-
-  th->stepped = 1;
-  pc = read_register (PC_REGNUM);
-  th->step_pc = arm_get_next_pc (pc);
-  th->step_prev = 0;
-  memory_insert_breakpoint (th->step_pc, (void *) &th->step_prev);
-}
-#endif
-
 /* Resume the child after an exception. */
 void
 child_resume (int pid, int step, enum target_signal sig)
@@ -1917,8 +1928,8 @@ init_child_ops (void)
 /* Handle 'set remoteupload' parameter. */
 
 #define replace_upload(what) \
-      upload_when = UPLOAD_NEWER; \
-      remote_upload = realloc (remote_upload, strlen (upload_options[upload_when].name)); \
+      upload_when = what; \
+      remote_upload = realloc (remote_upload, strlen (upload_options[upload_when].name) + 1); \
       strcpy (remote_upload, upload_options[upload_when].name);
 
 static void
@@ -1940,8 +1951,7 @@ set_upload_type (char *ignore, int from_tty)
     if (len >= upload_options[i].abbrev &&
        strncasecmp (remote_upload, upload_options[i].name, len) == 0)
       {
-       remote_upload = (char *) upload_options[i].name;
-       upload_when = i;
+       replace_upload (i);
        return;
       }