This is the mail archive of the
gdb-patches@sourceware.cygnus.com
mailing list for the GDB project.
Add support for WinCE toolchains
- To: gdb-patches at sourceware dot cygnus dot com
- Subject: Add support for WinCE toolchains
- From: Nick Clifton <nickc at cygnus dot com>
- Date: Tue, 22 Feb 2000 15:39:54 -0800
Hi Guys,
May I have permission to apply the following patch please ? It adds
support for toolchains which are targeted at Microsoft's WinCE
execution environment. For the moment this means the sh-pe, mips-pe
and arm-wince-pe toolchains.
Cheers
Nick
2000-02-22 Nick Clifton <nickc@cygnus.com> Chris Faylor <cgf@cygnus.com>
* configure.tgt: Add support for sh-pe and arm-wince-pe
targets.
* sh-tdep.c: Use SH3 register names by default for sh-pe
targets.
* wince-stub.c: New File: Stub debugging functions for a
WinCE device.
* wince-stub.h: New File: Header file for wince-stub.c
* wince.c: New File: Target vector operations for controlling
WinCE child processes.
* config/arm/arm-wince-pe.mt: New file: Makefile fragment for
arm-wince-pe targets.
* config/arm/tm-arm.h: Add WinCE support.
* config/mips/tm-mips.h: Add WinCE support.
* config/sh/tm-sh.h: Add WinCE support.
Index: configure.tgt
===================================================================
RCS file: /cvs/src//src/gdb/configure.tgt,v
retrieving revision 1.3
diff -p -r1.3 configure.tgt
*** configure.tgt 2000/02/22 01:17:29 1.3
--- configure.tgt 2000/02/22 23:31:31
*************** alpha*-*-linux*) gdb_target=alpha-linux
*** 51,56 ****
--- 51,57 ----
arc-*-*) gdb_target=arc ;;
+ arm*-wince-pe) gdb_target=arm-wince-pe ;;
arm*-*-linux*) gdb_target=linux ;;
arm*-*-* | thumb*-*-* | strongarm*-*-*)
gdb_target=embed
*************** rs6000-*-lynxos*) gdb_target=rs6000lynx
*** 245,250 ****
--- 246,252 ----
rs6000-*-aix4*) gdb_target=aix4 ;;
rs6000-*-*) gdb_target=rs6000 ;;
+ sh*-*-pe) gdb_target=sh-pe ;;
sh-*-*) gdb_target=sh ;;
sparc-*-aout*) gdb_target=sparc-em ;;
Index: sh-tdep.c
===================================================================
RCS file: /cvs/src//src/gdb/sh-tdep.c,v
retrieving revision 1.2
diff -p -r1.2 sh-tdep.c
*** sh-tdep.c 2000/02/14 18:43:48 1.2
--- sh-tdep.c 2000/02/22 23:31:31
*************** static char *sh3e_reg_names[] = {
*** 90,96 ****
--- 90,100 ----
+ #ifdef _WIN32_WCE
+ char **sh_register_names = sh3_reg_names;
+ #else
char **sh_register_names = sh_generic_reg_names;
+ #endif
struct
{
Index: wince-stub.c
===================================================================
RCS file: wince-stub.c
diff -N wince-stub.c
*** /dev/null Tue May 5 13:32:27 1998
--- wince-stub.c Tue Feb 22 15:31:31 2000
***************
*** 0 ****
--- 1,534 ----
+ /* wince-stub.c -- debugging stub for a Windows CE device
+
+ Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+ Contributed by Cygnus Support.
+
+ 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 eve nthe 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. */
+
+ /* by Christopher Faylor (cgf@cygnus.com) */
+
+ #include <stdarg.h>
+ #include <windows.h>
+ #include <winsock.h>
+ #include "wince-stub.h"
+
+ #define MALLOC(n) (void *) LocalAlloc (LMEM_MOVEABLE, (UINT)(n))
+ #define REALLOC(s, n) (void *) LocalReAlloc ((HLOCAL)(s), (UINT)(n), LMEM_MOVEABLE)
+
+ static int skip_next_id = 0; /* Don't read next API code from socket. */
+
+ /* v-style interface for handling varying argyment list error messages.
+ Displays the error message in a dialog box and exits when user clicks
+ on OK. */
+ static void
+ vstub_error (LPCWSTR fmt, va_list args)
+ {
+ WCHAR buf[4096];
+ wvsprintfW (buf, fmt, args);
+
+ MessageBoxW (NULL, buf, L"GDB", MB_ICONERROR);
+ WSACleanup ();
+ ExitThread (1);
+ }
+
+ /* The standard way to display an error message and exit. */
+ static void
+ stub_error (LPCWSTR fmt, ...)
+ {
+ va_list args;
+ va_start (args, fmt);
+ vstub_error (fmt, args);
+ }
+
+ /* Standard "oh well" can't communicate error. Someday this might attempt
+ synchronization. */
+ static void
+ attempt_resync (LPCWSTR huh, int s)
+ {
+ stub_error (L"lost synchronization with host attempting %s. Error %d", huh, WSAGetLastError ());
+ }
+
+ /* Read arbitrary stuff from a socket. */
+ static int
+ sockread (LPCWSTR huh, int s, void *str, size_t n)
+ {
+ for (;;)
+ {
+ if (recv (s, str, n, 0) == (int) n)
+ return n;
+ attempt_resync (huh, s);
+ }
+ }
+
+ /* Write arbitrary stuff to a socket. */
+ static int
+ sockwrite (LPCWSTR huh, int s, const void *str, size_t n)
+ {
+ for (;;)
+ {
+ if (send (s, str, n, 0) == (int) n)
+ return n;
+ attempt_resync (huh, s);
+ }
+ }
+
+ /* 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. */
+ static DWORD
+ getdword (LPCWSTR huh, int s, gdb_wince_id what_this)
+ {
+ DWORD n;
+ gdb_wince_id what;
+
+ if (skip_next_id)
+ skip_next_id = 0;
+ else
+ do
+ if (sockread (huh, s, &what, sizeof (what)) != sizeof (what))
+ stub_error (L"error getting record type from host - %s.", huh);
+ while (what_this != what);
+
+ if (sockread (huh, s, &n, sizeof (n)) != sizeof (n))
+ stub_error (L"error getting %s from host.", huh);
+
+ return n;
+ }
+
+ /* Get a an ID (possibly) and a WORD from the host gdb.
+ Don't bother with the id if the main loop has already
+ read it. */
+ static WORD
+ getword (LPCWSTR huh, int s, gdb_wince_id what_this)
+ {
+ WORD n;
+ gdb_wince_id what;
+
+ if (skip_next_id)
+ skip_next_id = 0;
+ else
+ do
+ if (sockread (huh, s, &what, sizeof (what)) != sizeof (what))
+ stub_error (L"error getting record type from host - %s.", huh);
+ while (what_this != what);
+
+ if (sockread (huh, s, &n, sizeof (n)) != sizeof (n))
+ stub_error (L"error getting %s from host.", huh);
+
+ return n;
+ }
+
+ /* Handy defines for getting various types of values. */
+ #define gethandle(huh, s, what) (HANDLE) getdword ((huh), (s), (what))
+ #define getpvoid(huh, s, what) (LPVOID) getdword ((huh), (s), (what))
+ #define getlen(huh, s, what) (gdb_wince_len) getword ((huh), (s), (what))
+
+ /* Get an arbitrary block of memory from the gdb host. This comes in
+ two chunks an id/dword representing the length and the stream of memory
+ itself. Returns a pointer, allocated via mempool, to a memory buffer. */
+ static LPWSTR
+ getmemory (LPCWSTR huh, int s, gdb_wince_id what, gdb_wince_len *inlen)
+ {
+ LPVOID p;
+ gdb_wince_len dummy;
+
+ if (!inlen)
+ inlen = &dummy;
+
+ *inlen = getlen (huh, s, what);
+
+ p = mempool (*inlen); /* FIXME: check for error */
+
+ if ((gdb_wince_len) sockread (huh, s, p, *inlen) != *inlen)
+ stub_error (L"error getting string from host.");
+
+ return p;
+ }
+
+ /* Output an id/dword to the host */
+ static void
+ putdword (LPCWSTR huh, int s, gdb_wince_id what, DWORD n)
+ {
+ if (sockwrite (huh, s, &what, sizeof (what)) != sizeof (what))
+ stub_error (L"error writing record id for %s to host.", huh);
+ if (sockwrite (huh, s, &n, sizeof (n)) != sizeof (n))
+ stub_error (L"error writing %s to host.", huh);
+ }
+
+ /* Output an id/word to the host */
+ static void
+ putword (LPCWSTR huh, int s, gdb_wince_id what, WORD n)
+ {
+ if (sockwrite (huh, s, &what, sizeof (what)) != sizeof (what))
+ stub_error (L"error writing record id for %s to host.", huh);
+ if (sockwrite (huh, s, &n, sizeof (n)) != sizeof (n))
+ stub_error (L"error writing %s to host.", huh);
+ }
+
+ /* Convenience define for outputting a "gdb_wince_len" type. */
+ #define putlen(huh, s, what, n) putword ((huh), (s), (what), (gdb_wince_len) (n))
+
+ /* Put an arbitrary block of memory to the gdb host. This comes in
+ two chunks an id/dword representing the length and the stream of memory
+ itself. */
+ static void
+ putmemory (LPCWSTR huh, int s, gdb_wince_id what, const void *mem, gdb_wince_len len)
+ {
+ putlen (huh, s, what, len);
+ if (((short) len > 0) && (gdb_wince_len) sockwrite (huh, s, mem, len) != len)
+ stub_error (L"error writing memory to host.");
+ }
+
+ /* Output the result of an operation to the host. If res != 0, sends a block of
+ memory starting at mem of len bytes. If res == 0, sends -GetLastError () and
+ avoids sending the mem. */
+ static void
+ putresult (LPCWSTR huh, gdb_wince_result res, int s, gdb_wince_id what, const void *mem, gdb_wince_len len)
+ {
+ if (!res)
+ len = -(int) GetLastError ();
+ putmemory (huh, s, what, mem, len);
+ }
+
+ static HANDLE curproc; /* Currently unused, but nice for debugging */
+
+ /* Emulate CreateProcess. Returns &pi if no error. */
+ static void
+ create_process (int s)
+ {
+ LPWSTR exec_file = getmemory (L"CreateProcess exec_file", s, GDB_CREATEPROCESS, NULL);
+ LPWSTR args = getmemory (L"CreateProcess args", s, GDB_CREATEPROCESS, NULL);
+ DWORD flags = getdword (L"CreateProcess flags", s, GDB_CREATEPROCESS);
+ PROCESS_INFORMATION pi;
+ gdb_wince_result res;
+
+ res = CreateProcessW (exec_file,
+ args, /* command line */
+ NULL, /* Security */
+ NULL, /* thread */
+ FALSE, /* inherit handles */
+ flags, /* start flags */
+ NULL,
+ NULL, /* current directory */
+ NULL,
+ &pi);
+ putresult (L"CreateProcess", res, s, GDB_CREATEPROCESS, &pi, sizeof (pi));
+ curproc = pi.hProcess;
+ }
+
+ /* Emulate TerminateProcess. Returns return value of TerminateProcess if
+ no error.
+ *** NOTE: For some unknown reason, TerminateProcess seems to always return
+ an ACCESS_DENIED (on Windows CE???) error. So, force a TRUE value for now. */
+ static void
+ terminate_process (int s)
+ {
+ gdb_wince_result res;
+ HANDLE h = gethandle (L"TerminateProcess handle", s, GDB_TERMINATEPROCESS);
+
+ res = TerminateProcess (h, 0) || 1; /* Doesn't seem to work on SH so default to TRUE */
+ putresult (L"Terminate process result", res, s, GDB_TERMINATEPROCESS,
+ &res, sizeof (res));
+ }
+
+ /* Emulate WaitForDebugEvent. Returns the debug event on success. */
+ static void
+ wait_for_debug_event (int s)
+ {
+ DWORD ms = getdword (L"WaitForDebugEvent ms", s, GDB_WAITFORDEBUGEVENT);
+ gdb_wince_result res;
+ DEBUG_EVENT ev;
+
+ res = WaitForDebugEvent (&ev, ms);
+ putresult (L"WaitForDebugEvent event", res, s, GDB_WAITFORDEBUGEVENT,
+ &ev, sizeof (ev));
+ }
+
+ /* Emulate GetThreadContext. Returns CONTEXT structure on success. */
+ static void
+ get_thread_context (int s)
+ {
+ CONTEXT c;
+ HANDLE h = gethandle (L"GetThreadContext handle", s, GDB_GETTHREADCONTEXT);
+ gdb_wince_result res;
+
+ memset (&c, 0, sizeof (c));
+ c.ContextFlags = getdword (L"GetThreadContext handle", s, GDB_GETTHREADCONTEXT);
+
+ res = (gdb_wince_result) GetThreadContext (h, &c);
+ putresult (L"GetThreadContext data", res, s, GDB_GETTHREADCONTEXT,
+ &c, sizeof (c));
+ }
+
+ /* Emulate GetThreadContext. Returns success of SetThreadContext. */
+ static void
+ set_thread_context (int s)
+ {
+ gdb_wince_result res;
+ HANDLE h = gethandle (L"SetThreadContext handle", s, GDB_SETTHREADCONTEXT);
+ LPCONTEXT pc = (LPCONTEXT) getmemory (L"SetThreadContext context", s,
+ GDB_SETTHREADCONTEXT, NULL);
+
+ res = SetThreadContext (h, pc);
+ putresult (L"SetThreadContext result", res, s, GDB_SETTHREADCONTEXT,
+ &res, sizeof (res));
+ }
+
+ /* Emulate ReadProcessMemory. Returns memory read on success. */
+ static void
+ 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);
+ DWORD outlen;
+ gdb_wince_result res;
+
+ outlen = 0;
+ res = (gdb_wince_result) ReadProcessMemory (h, p, buf, len, &outlen);
+ putresult (L"ReadProcessMemory data", res, s, GDB_READPROCESSMEMORY,
+ buf, (gdb_wince_len) outlen);
+ }
+
+ /* Emulate WriteProcessMemory. Returns WriteProcessMemory success. */
+ static void
+ write_process_memory (int s)
+ {
+ HANDLE h = gethandle (L"WriteProcessMemory handle", s, GDB_WRITEPROCESSMEMORY);
+ LPVOID p = getpvoid (L"WriteProcessMemory base", s, GDB_WRITEPROCESSMEMORY);
+ gdb_wince_len len;
+ LPVOID buf = getmemory (L"WriteProcessMemory buf", s, GDB_WRITEPROCESSMEMORY, &len);
+ DWORD outlen;
+ gdb_wince_result res;
+
+ outlen = 0;
+ res = WriteProcessMemory (h, p, buf, (DWORD) len, &outlen);
+ putresult (L"WriteProcessMemory data", res, s, GDB_WRITEPROCESSMEMORY,
+ (gdb_wince_len *) & outlen, sizeof (gdb_wince_len));
+ }
+
+ /* Return non-zero to gdb host if given thread is alive. */
+ static void
+ thread_alive (int s)
+ {
+ HANDLE h = gethandle (L"ThreadAlive handle", s, GDB_THREADALIVE);
+ gdb_wince_result res;
+
+ res = WaitForSingleObject (h, 0) == WAIT_OBJECT_0 ? 1 : 0;
+ putresult (L"WriteProcessMemory data", res, s, GDB_THREADALIVE,
+ &res, sizeof (res));
+ }
+
+ /* Emulate SuspendThread. Returns value returned from SuspendThread. */
+ static void
+ suspend_thread (int s)
+ {
+ DWORD res;
+ HANDLE h = gethandle (L"SuspendThread handle", s, GDB_SUSPENDTHREAD);
+ res = SuspendThread (h);
+ putdword (L"SuspendThread result", s, GDB_SUSPENDTHREAD, res);
+ }
+
+ /* Emulate ResumeThread. Returns value returned from ResumeThread. */
+ static void
+ resume_thread (int s)
+ {
+ DWORD res;
+ HANDLE h = gethandle (L"ResumeThread handle", s, GDB_RESUMETHREAD);
+ res = ResumeThread (h);
+ putdword (L"ResumeThread result", s, GDB_RESUMETHREAD, res);
+ }
+
+ /* Emulate ContinueDebugEvent. Returns ContinueDebugEvent success. */
+ static void
+ continue_debug_event (int s)
+ {
+ gdb_wince_result res;
+ DWORD pid = getdword (L"ContinueDebugEvent pid", s, GDB_CONTINUEDEBUGEVENT);
+ DWORD tid = getdword (L"ContinueDebugEvent tid", s, GDB_CONTINUEDEBUGEVENT);
+ DWORD status = getdword (L"ContinueDebugEvent status", s, GDB_CONTINUEDEBUGEVENT);
+ res = (gdb_wince_result) ContinueDebugEvent (pid, tid, status);
+ putresult (L"ContinueDebugEvent result", res, s, GDB_CONTINUEDEBUGEVENT, &res, sizeof (res));
+ }
+
+ /* Emulate CloseHandle. Returns CloseHandle success. */
+ static void
+ close_handle (int s)
+ {
+ gdb_wince_result res;
+ HANDLE h = gethandle (L"CloseHandle handle", s, GDB_CLOSEHANDLE);
+ res = (gdb_wince_result) CloseHandle (h);
+ 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)
+ {
+ gdb_wince_id id;
+
+ /* Continue reading from socket until receive a GDB_STOPSUB. */
+ while (sockread (L"Dispatch", s, &id, sizeof (id)) > 0)
+ {
+ skip_next_id = 1;
+ switch (id)
+ {
+ case GDB_CREATEPROCESS:
+ create_process (s);
+ break;
+ case GDB_TERMINATEPROCESS:
+ terminate_process (s);
+ break;
+ case GDB_WAITFORDEBUGEVENT:
+ wait_for_debug_event (s);
+ break;
+ case GDB_GETTHREADCONTEXT:
+ get_thread_context (s);
+ break;
+ case GDB_SETTHREADCONTEXT:
+ set_thread_context (s);
+ break;
+ case GDB_READPROCESSMEMORY:
+ read_process_memory (s);
+ break;
+ case GDB_WRITEPROCESSMEMORY:
+ write_process_memory (s);
+ break;
+ case GDB_THREADALIVE:
+ thread_alive (s);
+ break;
+ case GDB_SUSPENDTHREAD:
+ suspend_thread (s);
+ break;
+ case GDB_RESUMETHREAD:
+ resume_thread (s);
+ break;
+ case GDB_CONTINUEDEBUGEVENT:
+ continue_debug_event (s);
+ break;
+ case GDB_CLOSEHANDLE:
+ close_handle (s);
+ break;
+ case GDB_STOPSTUB:
+ terminate_process (s);
+ return;
+ case GDB_SINGLESTEP:
+ single_step (s);
+ return;
+ default:
+ {
+ WCHAR buf[80];
+ wsprintfW (buf, L"Invalid command id received: %d", id);
+ MessageBoxW (NULL, buf, L"GDB", MB_ICONERROR);
+ skip_next_id = 0;
+ }
+ }
+ }
+ }
+
+ /* The Windows Main entry point */
+ int WINAPI
+ WinMain (HINSTANCE hi, HINSTANCE hp, LPWSTR cmd, int show)
+ {
+ struct hostent *h;
+ int s;
+ struct WSAData wd;
+ struct sockaddr_in sin;
+ int tmp;
+ LPWSTR whost;
+ char host[80];
+
+ whost = wcschr (cmd, L' '); /* Look for argument. */
+
+ /* If no host is specified, just use default */
+ if (whost)
+ {
+ /* Eat any spaces. */
+ while (*whost == L' ' || *whost == L'\t')
+ whost++;
+
+ 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.");
+
+ /* If whost was specified, first try it. If it was not specified or the
+ host lookup failed, try the Windows CE magic ppp_peer lookup. ppp_peer
+ is supposed to be the Windows host sitting on the other end of the
+ serial cable. */
+ if (whost && *whost && (h = gethostbyname (host)) != NULL)
+ /* nothing to do */ ;
+ else if ((h = gethostbyname ("ppp_peer")) == NULL)
+ stub_error (L"Couldn't get IP address of host system. Error %d", WSAGetLastError ());
+
+ /* Get a socket. */
+ if ((s = socket (AF_INET, SOCK_STREAM, 0)) < 0)
+ stub_error (L"Couldn't connect to host system. Error %d", WSAGetLastError ());
+
+ /* Allow rapid reuse of the port. */
+ tmp = 1;
+ setsockopt (s, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp, sizeof (tmp));
+
+ /* Set up the information for connecting to the host gdb process. */
+ memset (&sin, 0, sizeof (sin));
+ sin.sin_family = h->h_addrtype;
+ memcpy (&sin.sin_addr, h->h_addr, h->h_length);
+ sin.sin_port = htons (7000); /* FIXME: This should be configurable */
+
+ /* Connect to host */
+ if (connect (s, (struct sockaddr *) &sin, sizeof (sin)) < 0)
+ stub_error (L"Couldn't connect to host gdb.");
+
+ /* Read from socket until told to exit. */
+ dispatch (s);
+ WSACleanup ();
+ return 0;
+ }
Index: wince-stub.h
===================================================================
RCS file: wince-stub.h
diff -N wince-stub.h
*** /dev/null Tue May 5 13:32:27 1998
--- wince-stub.h Tue Feb 22 15:31:31 2000
***************
*** 0 ****
--- 1,48 ----
+ /* wince-stub.h -- Definitions for commnicating with the WinCE stub.
+
+ Copyright 1999 Free Software Foundation, Inc.
+ Contributed by Cygnus Support.
+
+ 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 eve nthe 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.
+ */
+
+ /* by Christopher Faylor (cgf@cygnus.com) */
+
+ enum win_func
+ {
+ GDB_CREATEPROCESS = 42,
+ GDB_TERMINATEPROCESS,
+ GDB_WAITFORDEBUGEVENT,
+ GDB_GETTHREADCONTEXT,
+ GDB_SETTHREADCONTEXT,
+ GDB_READPROCESSMEMORY,
+ GDB_WRITEPROCESSMEMORY,
+ GDB_THREADALIVE,
+ GDB_SUSPENDTHREAD,
+ GDB_RESUMETHREAD,
+ GDB_CONTINUEDEBUGEVENT,
+ GDB_CLOSEHANDLE,
+ GDB_STOPSTUB,
+ GDB_SINGLESTEP,
+ GDB_SETBREAK,
+ GDB_INVALID
+ };
+
+ typedef unsigned char gdb_wince_id;
+ typedef unsigned short gdb_wince_len;
+ typedef short gdb_wince_result;
Index: wince.c
===================================================================
RCS file: wince.c
diff -N wince.c
*** /dev/null Tue May 5 13:32:27 1998
--- wince.c Tue Feb 22 15:31:32 2000
***************
*** 0 ****
--- 1,2035 ----
+ /* Target-vector operations for controlling Windows CE child processes, for GDB.
+ Copyright 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+ Contributed by Cygnus Support.
+
+ 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 eve nthe 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.
+ */
+
+ /* by Christopher Faylor (cgf@cygnus.com) */
+
+ /* We assume we're being built with and will be used for cygwin. */
+
+ #ifdef SHx
+ #undef SH4
+ #define SH4 /* Just to get all of the CONTEXT defines. */
+ #endif
+
+ #include "defs.h"
+ #include "frame.h" /* required by inferior.h */
+ #include "inferior.h"
+ #include "target.h"
+ #include "gdb_wait.h"
+ #include "gdbcore.h"
+ #include "command.h"
+ #include <signal.h>
+ #include <sys/types.h>
+ #include <fcntl.h>
+ #include <stdlib.h>
+
+ #include <windows.h>
+ #include <rapi.h>
+ #include <netdb.h>
+ #include <cygwin/in.h>
+ #include <cygwin/socket.h>
+
+ #include "buildsym.h"
+ #include "symfile.h"
+ #include "objfiles.h"
+ #include "gdb_string.h"
+ #include "gdbthread.h"
+ #include "gdbcmd.h"
+ #include <sys/param.h>
+ #include "wince-stub.h"
+ #include "dcache.h"
+
+ /* The ui's event loop. */
+ extern int (*ui_loop_hook) PARAMS ((int signo));
+
+ /* If we're not using the old Cygwin header file set, define the
+ following which never should have been in the generic Win32 API
+ headers in the first place since they were our own invention... */
+ #ifndef _GNU_H_WINDOWS_H
+ #define FLAG_TRACE_BIT 0x100
+ #ifdef CONTEXT_FLOATING_POINT
+ #define CONTEXT_DEBUGGER0 (CONTEXT_FULL | CONTEXT_FLOATING_POINT)
+ #else
+ #define CONTEXT_DEBUGGER0 (CONTEXT_FULL)
+ #endif
+ #endif
+
+ #ifdef SH4
+ #define CONTEXT_DEBUGGER ((CONTEXT_DEBUGGER0 & ~(CONTEXT_SH4 | CONTEXT_FLOATING_POINT)) | CONTEXT_SH3)
+ #else
+ #define CONTEXT_DEBUGGER CONTEXT_DEBUGGER0
+ #endif
+ /* The string sent by cygwin when it processes a signal.
+ FIXME: This should be in a cygwin include file. */
+ #define CYGWIN_SIGNAL_STRING "cygwin: signal"
+
+ #define CHECK(x) check (x, __FILE__,__LINE__)
+ #define DEBUG_EXEC(x) if (debug_exec) printf x
+ #define DEBUG_EVENTS(x) if (debug_events) printf x
+ #define DEBUG_MEM(x) if (debug_memory) printf x
+ #define DEBUG_EXCEPT(x) if (debug_exceptions) printf x
+
+ static int connection_initialized = 0; /* True if we've initialized a RAPI session. */
+
+ static DCACHE *remote_dcache;
+
+ /* The directory where the stub and executable files are uploaded. */
+ static const char *remote_directory = "\\gdb";
+
+ /* The types automatic upload available. */
+ static enum
+ {
+ UPLOAD_ALWAYS = 0,
+ UPLOAD_NEWER = 1,
+ UPLOAD_NEVER = 2
+ }
+ upload_when = UPLOAD_NEWER;
+
+ /* Valid options for 'set remoteupload'. Note that options
+ must track upload_when enum. */
+ static struct opts
+ {
+ const char *name;
+ int abbrev;
+ }
+ upload_options[3] =
+ {
+ {
+ "always", 1
+ }
+ ,
+ {
+ "newer", 3
+ }
+ ,
+ {
+ "never", 3
+ }
+ };
+
+ static char *remote_upload = NULL; /* Set by set remoteupload */
+ static int remote_add_host = 0;
+
+ /* Forward declaration */
+ extern struct target_ops child_ops;
+
+ static int win32_child_thread_alive PARAMS ((int));
+ void child_kill_inferior PARAMS ((void));
+
+ static int last_sig = 0; /* Set if a signal was received from the
+ debugged process */
+
+ /* Thread information structure used to track information that is
+ not available in gdb's thread structure. */
+ typedef struct thread_info_struct
+ {
+ struct thread_info_struct *next;
+ DWORD id;
+ HANDLE h;
+ char *name;
+ int suspend_count;
+ int stepped; /* True if stepped. */
+ CORE_ADDR step_pc;
+ unsigned long step_instr;
+ unsigned long step_prev;
+ CONTEXT context;
+ }
+ thread_info;
+
+ static thread_info thread_head =
+ {NULL};
+
+ /* The process and thread handles for the above context. */
+
+ static DEBUG_EVENT current_event; /* The current debug event from
+ WaitForDebugEvent */
+ static HANDLE current_process_handle; /* Currently executing process */
+ static thread_info *current_thread; /* Info on currently selected thread */
+ static thread_info *this_thread; /* Info on thread returned by wait_for_debug_event */
+ static DWORD main_thread_id; /* Thread ID of the main thread */
+
+ /* Counts of things. */
+ static int exception_count = 0;
+ static int event_count = 0;
+
+ /* User options. */
+ static int debug_exec = 0; /* show execution */
+ static int debug_events = 0; /* show events from kernel */
+ static int debug_memory = 0; /* show target memory accesses */
+ static int debug_exceptions = 0; /* show target exceptions */
+
+ /* 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. regptr will return zero for this
+ register.
+
+ This is used by the regptr function. */
+ #define context_offset(x) ((int)&(((PCONTEXT)NULL)->x))
+ static const int mappings[NUM_REGS + 1] =
+ {
+ #ifdef __i386__
+ context_offset (Eax),
+ context_offset (Ecx),
+ context_offset (Edx),
+ context_offset (Ebx),
+ context_offset (Esp),
+ context_offset (Ebp),
+ context_offset (Esi),
+ context_offset (Edi),
+ context_offset (Eip),
+ context_offset (EFlags),
+ context_offset (SegCs),
+ context_offset (SegSs),
+ context_offset (SegDs),
+ context_offset (SegEs),
+ context_offset (SegFs),
+ context_offset (SegGs),
+ context_offset (FloatSave.RegisterArea[0 * 10]),
+ context_offset (FloatSave.RegisterArea[1 * 10]),
+ context_offset (FloatSave.RegisterArea[2 * 10]),
+ context_offset (FloatSave.RegisterArea[3 * 10]),
+ context_offset (FloatSave.RegisterArea[4 * 10]),
+ context_offset (FloatSave.RegisterArea[5 * 10]),
+ context_offset (FloatSave.RegisterArea[6 * 10]),
+ context_offset (FloatSave.RegisterArea[7 * 10]),
+ #elif defined(SHx)
+ context_offset (R0),
+ context_offset (R1),
+ context_offset (R2),
+ context_offset (R3),
+ context_offset (R4),
+ context_offset (R5),
+ context_offset (R6),
+ context_offset (R7),
+ context_offset (R8),
+ context_offset (R9),
+ context_offset (R10),
+ context_offset (R11),
+ context_offset (R12),
+ context_offset (R13),
+ context_offset (R14),
+ context_offset (R15),
+ context_offset (Fir),
+ context_offset (PR), /* Procedure Register */
+ context_offset (GBR), /* Global Base Register */
+ context_offset (MACH), /* Accumulate */
+ context_offset (MACL), /* Multiply */
+ context_offset (Psr),
+ context_offset (Fpul),
+ context_offset (Fpscr),
+ context_offset (FRegs[0]),
+ context_offset (FRegs[1]),
+ context_offset (FRegs[2]),
+ context_offset (FRegs[3]),
+ context_offset (FRegs[4]),
+ context_offset (FRegs[5]),
+ context_offset (FRegs[6]),
+ context_offset (FRegs[7]),
+ context_offset (FRegs[8]),
+ context_offset (FRegs[9]),
+ context_offset (FRegs[10]),
+ context_offset (FRegs[11]),
+ context_offset (FRegs[12]),
+ context_offset (FRegs[13]),
+ context_offset (FRegs[14]),
+ context_offset (FRegs[15]),
+ context_offset (xFRegs[0]),
+ context_offset (xFRegs[1]),
+ context_offset (xFRegs[2]),
+ context_offset (xFRegs[3]),
+ context_offset (xFRegs[4]),
+ context_offset (xFRegs[5]),
+ context_offset (xFRegs[6]),
+ context_offset (xFRegs[7]),
+ context_offset (xFRegs[8]),
+ context_offset (xFRegs[9]),
+ context_offset (xFRegs[10]),
+ context_offset (xFRegs[11]),
+ context_offset (xFRegs[12]),
+ context_offset (xFRegs[13]),
+ context_offset (xFRegs[14]),
+ context_offset (xFRegs[15]),
+ #elif defined(MIPS)
+ context_offset (IntZero),
+ context_offset (IntAt),
+ context_offset (IntV0),
+ context_offset (IntV1),
+ context_offset (IntA0),
+ context_offset (IntA1),
+ context_offset (IntA2),
+ context_offset (IntA3),
+ context_offset (IntT0),
+ context_offset (IntT1),
+ context_offset (IntT2),
+ context_offset (IntT3),
+ context_offset (IntT4),
+ context_offset (IntT5),
+ context_offset (IntT6),
+ context_offset (IntT7),
+ context_offset (IntS0),
+ context_offset (IntS1),
+ context_offset (IntS2),
+ context_offset (IntS3),
+ context_offset (IntS4),
+ context_offset (IntS5),
+ context_offset (IntS6),
+ context_offset (IntS7),
+ context_offset (IntT8),
+ context_offset (IntT9),
+ context_offset (IntK0),
+ context_offset (IntK1),
+ context_offset (IntGp),
+ context_offset (IntSp),
+ context_offset (IntS8),
+ context_offset (IntRa),
+ context_offset (Psr),
+ context_offset (IntLo),
+ context_offset (IntHi),
+ -1, /* bad */
+ -1, /* cause */
+ context_offset (Fir),
+ context_offset (FltF0),
+ context_offset (FltF1),
+ context_offset (FltF2),
+ context_offset (FltF3),
+ context_offset (FltF4),
+ context_offset (FltF5),
+ context_offset (FltF6),
+ context_offset (FltF7),
+ context_offset (FltF8),
+ context_offset (FltF9),
+ context_offset (FltF10),
+ context_offset (FltF11),
+ context_offset (FltF12),
+ context_offset (FltF13),
+ context_offset (FltF14),
+ context_offset (FltF15),
+ context_offset (FltF16),
+ context_offset (FltF17),
+ context_offset (FltF18),
+ context_offset (FltF19),
+ context_offset (FltF20),
+ context_offset (FltF21),
+ context_offset (FltF22),
+ context_offset (FltF23),
+ context_offset (FltF24),
+ context_offset (FltF25),
+ context_offset (FltF26),
+ context_offset (FltF27),
+ context_offset (FltF28),
+ context_offset (FltF29),
+ context_offset (FltF30),
+ context_offset (FltF31),
+ context_offset (Fsr),
+ context_offset (Fir),
+ -1, /* fp */
+ #elif defined(ARM)
+ context_offset (R0),
+ context_offset (R1),
+ context_offset (R2),
+ context_offset (R3),
+ context_offset (R4),
+ context_offset (R5),
+ context_offset (R6),
+ context_offset (R7),
+ context_offset (R8),
+ context_offset (R9),
+ context_offset (R10),
+ context_offset (R11),
+ context_offset (R12),
+ context_offset (Sp),
+ context_offset (Lr),
+ context_offset (Pc),
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ context_offset (Psr),
+ #endif
+ -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[] =
+ {
+ {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}};
+
+ /******************** Beginning of stub interface ********************/
+
+ /* Stub interface description:
+
+ The Windows CE stub implements a crude RPC. The hand-held device
+ connects to gdb using port 7000. gdb and the stub then communicate
+ using packets where:
+
+ byte 0: command id (e.g. Create Process)
+
+ byte 1-4: DWORD
+
+ byte 1-2: WORD
+
+ byte 1-2: length
+ byte 3-n: arbitrary memory.
+
+ The interface is deterministic, i.e., if the stub expects a DWORD then
+ the gdb server should send a DWORD.
+ */
+
+ /* Note: In the functions below, the `huh' parameter is a string passed from the
+ function containing a descriptive string concerning the current operation.
+ This is used for error reporting.
+
+ The 'what' parameter is a command id as found in wince-stub.h.
+
+ Hopefully, the rest of the parameters are self-explanatory.
+ */
+
+ static int s; /* communication socket */
+
+ /* v-style interface for handling varying argyment list error messages.
+ Displays the error message in a dialog box and exits when user clicks
+ on OK. */
+ static void
+ vstub_error (LPCSTR fmt, va_list * args)
+ {
+ char buf[4096];
+ vsprintf (buf, fmt, args);
+ s = -1;
+ error ("%s", buf);
+ }
+
+ /* The standard way to display an error message and exit. */
+ static void
+ stub_error (LPCSTR fmt,...)
+ {
+ va_list args;
+ va_start (args, fmt);
+ vstub_error (fmt, args);
+ }
+
+ /* Standard "oh well" can't communicate error. Someday this might attempt
+ synchronization. */
+ static void
+ attempt_resync (LPCSTR huh, int s)
+ {
+ stub_error ("lost synchronization with target attempting %s", huh);
+ }
+
+ /* Read arbitrary stuff from a socket. */
+ static int
+ sockread (LPCSTR huh, int s, void *str, size_t n)
+ {
+ for (;;)
+ {
+ if (recv (s, str, n, 0) == n)
+ return n;
+ attempt_resync (huh, s);
+ }
+ }
+
+ /* Write arbitrary stuff to a socket. */
+ static int
+ sockwrite (LPCSTR huh, const void *str, size_t n)
+ {
+ for (;;)
+ {
+ if (send (s, str, n, 0) == n)
+ return n;
+ attempt_resync (huh, s);
+ }
+ }
+
+ /* Output an id/dword to the host */
+ static void
+ putdword (LPCSTR huh, gdb_wince_id what, DWORD n)
+ {
+ if (sockwrite (huh, &what, sizeof (what)) != sizeof (what))
+ stub_error ("error writing record id to host for %s", huh);
+ if (sockwrite (huh, &n, sizeof (n)) != sizeof (n))
+ stub_error ("error writing %s to host.", huh);
+ }
+
+ /* Output an id/word to the host */
+ static void
+ putword (LPCSTR huh, gdb_wince_id what, WORD n)
+ {
+ if (sockwrite (huh, &what, sizeof (what)) != sizeof (what))
+ stub_error ("error writing record id to host for %s", huh);
+ if (sockwrite (huh, &n, sizeof (n)) != sizeof (n))
+ stub_error ("error writing %s host.", huh);
+ }
+
+ /* Convenience define for outputting a "gdb_wince_len" type. */
+ #define putlen(huh, what, n) putword((huh), (what), (gdb_wince_len) (n))
+
+ /* Put an arbitrary block of memory to the gdb host. This comes in
+ two chunks an id/dword representing the length and the stream of memory
+ itself. */
+ static void
+ putmemory (LPCSTR huh, gdb_wince_id what, const void *mem, gdb_wince_len len)
+ {
+ putlen (huh, what, len);
+ if (((short) len > 0) && sockwrite (huh, mem, len) != len)
+ stub_error ("error writing %s to host.", huh);
+ }
+
+ /* Output the result of an operation to the host. If res != 0, sends a block of
+ memory starting at mem of len bytes. If res == 0, sends -GetLastError () and
+ avoids sending the mem. */
+ static DWORD
+ getdword (LPCSTR huh, gdb_wince_id what_this)
+ {
+ DWORD n;
+ gdb_wince_id what;
+ do
+ if (sockread (huh, s, &what, sizeof (what)) != sizeof (what))
+ stub_error ("error getting record type from host - %s.", huh);
+ while (what_this != what);
+
+ if (sockread (huh, s, &n, sizeof (n)) != sizeof (n))
+ stub_error ("error getting %s from host.", huh);
+
+ return n;
+ }
+
+ /* Get a an ID (possibly) and a WORD from the host gdb.
+ Don't bother with the id if the main loop has already
+ read it. */
+ static WORD
+ getword (LPCSTR huh, gdb_wince_id what_this)
+ {
+ WORD n;
+ gdb_wince_id what;
+ do
+ if (sockread (huh, s, &what, sizeof (what)) != sizeof (what))
+ stub_error ("error getting record type from host - %s.", huh);
+ while (what_this != what);
+
+ if (sockread (huh, s, &n, sizeof (n)) != sizeof (n))
+ stub_error ("error getting %s from host.", huh);
+
+ return n;
+ }
+
+ /* Handy defines for getting/putting various types of values. */
+ #define gethandle(huh, what) (HANDLE) getdword ((huh), (what))
+ #define getpvoid(huh, what) (LPVOID) getdword ((huh), (what))
+ #define getlen(huh, what) (gdb_wince_len) getword ((huh), (what))
+ #define puthandle(huh, what, h) putdword ((huh), (what), (DWORD) (h))
+ #define putpvoid(huh, what, p) putdword ((huh), (what), (DWORD) (p))
+
+ /* Retrieve the result of an operation from the stub. If nbytes < 0) then nbytes
+ is actually an error and nothing else follows. Use SetLastError to remember this.
+ if nbytes > 0, retrieve a block of *nbytes into buf.
+ */
+ int
+ getresult (LPCSTR huh, gdb_wince_id what, LPVOID buf, gdb_wince_len * nbytes)
+ {
+ gdb_wince_len dummy;
+ if (nbytes == NULL)
+ nbytes = &dummy;
+
+ *nbytes = getlen (huh, what);
+
+ if ((short) *nbytes < 0)
+ {
+ SetLastError (-(short) *nbytes);
+ return 0;
+ }
+
+ if ((gdb_wince_len) sockread (huh, s, buf, *nbytes) != *nbytes)
+ stub_error ("couldn't read information from wince stub - %s", huh);
+
+ return 1;
+ }
+
+ /* Convert "narrow" string to "wide". Manipulates a buffer ring of 8
+ buffers which hold the translated string. This is an arbitrary limit
+ but it is approximately double the current needs of this module.
+ */
+ LPWSTR
+ towide (const char *s, gdb_wince_len * out_len)
+ {
+ static int n = -1;
+ static LPWSTR outs[8] =
+ {NULL /*, NULL, etc. */ };
+ gdb_wince_len dummy;
+
+ if (!out_len)
+ out_len = &dummy;
+
+ /* First determine the length required to hold the converted string. */
+ *out_len = sizeof (WCHAR) * MultiByteToWideChar (CP_ACP, 0, s, -1, NULL, 0);
+ if (!*out_len)
+ return NULL; /* The conversion failed */
+
+ if (++n >= (sizeof (outs) / sizeof (outs[0])))
+ n = 0; /* wrap */
+
+ /* Allocate space for the converted string, reusing any previously allocated
+ space, if applicable. Note that if outs[n] is NULL, realloc will act as
+ a malloc (under cygwin, at least).
+ */
+ outs[n] = (LPWSTR) realloc (outs[n], *out_len);
+ memset (outs[n], 0, *out_len);
+ (void) MultiByteToWideChar (CP_ACP, 0, s, -1, outs[n], *out_len);
+ return outs[n];
+ }
+
+ /******************** Emulation routines start here. ********************
+
+ The functions below are modelled after their Win32 counterparts. They are named
+ similarly to Win32 and take exactly the same arguments except where otherwise noted.
+ They communicate with the stub on the hand-held device by sending their arguments
+ over the socket and waiting for results from the socket.
+
+ There is one universal change. In cases where a length is expected to be returned
+ in a DWORD, we use a gdb_wince_len type instead. Currently this is an unsigned short
+ which is smaller than the standard Win32 DWORD. This is done to minimize unnecessary
+ traffic since the connection to Windows CE can be slow. To change this, modify the
+ 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)
+ {
+ gdb_wince_len len;
+ LPWSTR buf;
+
+ buf = towide (exec_file, &len);
+ putmemory ("CreateProcess exec_file", GDB_CREATEPROCESS, buf, len);
+ buf = towide (args, &len);
+ putmemory ("CreateProcess args", GDB_CREATEPROCESS, buf, len);
+ putdword ("CreateProcess flags", GDB_CREATEPROCESS, flags);
+ return getresult ("CreateProcess result", GDB_CREATEPROCESS, pi, NULL);
+ }
+
+ /* Emulate TerminateProcess. Don't bother with the second argument since CE
+ ignores it.
+ */
+ static int
+ terminate_process (HANDLE h)
+ {
+ gdb_wince_result res;
+ if (s < 0)
+ return 1;
+ puthandle ("TerminateProcess handle", GDB_TERMINATEPROCESS, h);
+ return getresult ("TerminateProcess result", GDB_TERMINATEPROCESS, &res, NULL);
+ }
+
+ static int
+ wait_for_debug_event (DEBUG_EVENT * ev, DWORD ms)
+ {
+ if (s < 0)
+ return 1;
+ putdword ("WaitForDebugEvent ms", GDB_WAITFORDEBUGEVENT, ms);
+ return getresult ("WaitForDebugEvent event", GDB_WAITFORDEBUGEVENT, ev, NULL);
+ }
+
+ static int
+ get_thread_context (HANDLE h, CONTEXT * c)
+ {
+ if (s < 0)
+ return 1;
+ puthandle ("GetThreadContext handle", GDB_GETTHREADCONTEXT, h);
+ putdword ("GetThreadContext flags", GDB_GETTHREADCONTEXT, c->ContextFlags);
+ return getresult ("GetThreadContext context", GDB_GETTHREADCONTEXT, c, NULL);
+ }
+
+ static int
+ set_thread_context (HANDLE h, CONTEXT * c)
+ {
+ gdb_wince_result res;
+ if (s < 0)
+ return 1;
+ puthandle ("SetThreadContext handle", GDB_SETTHREADCONTEXT, h);
+ putmemory ("SetThreadContext context", GDB_SETTHREADCONTEXT, c, sizeof (*c));
+ return getresult ("SetThreadContext context", GDB_SETTHREADCONTEXT, &res, NULL);
+ }
+
+ static int
+ read_process_memory (HANDLE h, LPCVOID where, LPVOID buf, gdb_wince_len len, gdb_wince_len * nbytes)
+ {
+ if (s < 0)
+ return 1;
+ puthandle ("ReadProcessMemory handle", GDB_READPROCESSMEMORY, h);
+ putpvoid ("ReadProcessMemory location", GDB_READPROCESSMEMORY, where);
+ putlen ("ReadProcessMemory size", GDB_READPROCESSMEMORY, len);
+
+ return getresult ("ReadProcessMemory buf", GDB_READPROCESSMEMORY, buf, nbytes);
+ }
+
+ static int
+ write_process_memory (HANDLE h, LPCVOID where, LPCVOID buf, gdb_wince_len len, gdb_wince_len * nbytes)
+ {
+ if (s < 0)
+ return 1;
+ puthandle ("WriteProcessMemory handle", GDB_WRITEPROCESSMEMORY, h);
+ putpvoid ("WriteProcessMemory location", GDB_WRITEPROCESSMEMORY, where);
+ putmemory ("WriteProcProcessMemory buf", GDB_WRITEPROCESSMEMORY, buf, len);
+
+ return getresult ("WriteProcessMemory result", GDB_WRITEPROCESSMEMORY, nbytes, NULL);
+ }
+
+ static int
+ remote_read_bytes (CORE_ADDR memaddr, char *myaddr, int len)
+ {
+ gdb_wince_len nbytes;
+ if (!read_process_memory (current_process_handle, (LPCVOID) memaddr,
+ (LPVOID) myaddr, len, &nbytes))
+ return -1;
+ return nbytes;
+ }
+
+ static int
+ remote_write_bytes (CORE_ADDR memaddr, char *myaddr, int len)
+ {
+ gdb_wince_len nbytes;
+ if (!write_process_memory (current_process_handle, (LPCVOID) memaddr,
+ (LPCVOID) myaddr, len, &nbytes))
+ return -1;
+ return nbytes;
+ }
+
+ /* This is not a standard Win32 function. It instructs the stub to return TRUE
+ if the thread referenced by HANDLE h is alive.
+ */
+ static int
+ thread_alive (HANDLE h)
+ {
+ gdb_wince_result res;
+ if (s < 0)
+ return 1;
+ puthandle ("ThreadAlive handle", GDB_THREADALIVE, h);
+ return getresult ("ThreadAlive result", GDB_THREADALIVE, &res, NULL);
+ }
+
+ static int
+ suspend_thread (HANDLE h)
+ {
+ if (s < 0)
+ return 1;
+ puthandle ("SuspendThread handle", GDB_SUSPENDTHREAD, h);
+ return (int) getdword ("SuspendThread result", GDB_SUSPENDTHREAD);
+ }
+
+ static int
+ resume_thread (HANDLE h)
+ {
+ if (s < 0)
+ return 1;
+ puthandle ("ResumeThread handle", GDB_RESUMETHREAD, h);
+ return (int) getdword ("SuspendThread result", GDB_RESUMETHREAD);
+ }
+
+ static int
+ continue_debug_event (DWORD pid, DWORD tid, DWORD status)
+ {
+ gdb_wince_result res;
+ if (s < 0)
+ return 0;
+ putdword ("ContinueDebugEvent pid", GDB_CONTINUEDEBUGEVENT, pid);
+ putdword ("ContinueDebugEvent tid", GDB_CONTINUEDEBUGEVENT, tid);
+ putdword ("ContinueDebugEvent status", GDB_CONTINUEDEBUGEVENT, status);
+ return getresult ("ContinueDebugEvent result", GDB_CONTINUEDEBUGEVENT, &res, NULL);
+ }
+
+ static int
+ close_handle (HANDLE h)
+ {
+ gdb_wince_result res;
+ if (s < 0)
+ return 1;
+ puthandle ("CloseHandle handle", GDB_CLOSEHANDLE, h);
+ return (int) getresult ("CloseHandle result", GDB_CLOSEHANDLE, &res, NULL);
+ }
+
+ /* This is not a standard Win32 interface. This function tells the stub
+ to terminate.
+ */
+ static void
+ stop_stub ()
+ {
+ if (s < 0)
+ return;
+ (void) putdword ("Stopping gdb stub", GDB_STOPSTUB, 0);
+ s = -1;
+ }
+
+ /******************** End of emulation routines. ********************/
+ /******************** End of stub interface ********************/
+
+ /* Find a thread record given a thread id.
+ If get_context then also retrieve the context for this
+ thread. */
+ static thread_info *
+ thread_rec (DWORD id, int get_context)
+ {
+ thread_info *th;
+
+ for (th = &thread_head; (th = th->next) != NULL;)
+ if (th->id == id)
+ {
+ if (!th->suspend_count && get_context)
+ {
+ if (get_context > 0 && th != this_thread)
+ th->suspend_count = suspend_thread (th->h) + 1;
+ else if (get_context < 0)
+ th->suspend_count = -1;
+
+ th->context.ContextFlags = CONTEXT_DEBUGGER;
+ get_thread_context (th->h, &th->context);
+ }
+ return th;
+ }
+
+ return NULL;
+ }
+
+ /* Add a thread to the thread list */
+ static thread_info *
+ child_add_thread (DWORD id, HANDLE h)
+ {
+ thread_info *th;
+
+ if ((th = thread_rec (id, FALSE)))
+ return th;
+
+ th = (thread_info *) xmalloc (sizeof (*th));
+ memset (th, 0, sizeof (*th));
+ th->id = id;
+ th->h = h;
+ th->next = thread_head.next;
+ thread_head.next = th;
+ add_thread (id);
+ return th;
+ }
+
+ /* Clear out any old thread list and reintialize it to a
+ pristine state. */
+ static void
+ child_init_thread_list ()
+ {
+ thread_info *th = &thread_head;
+
+ DEBUG_EVENTS (("gdb: child_init_thread_list\n"));
+ init_thread_list ();
+ while (th->next != NULL)
+ {
+ thread_info *here = th->next;
+ th->next = here->next;
+ (void) close_handle (here->h);
+ free (here);
+ }
+ }
+
+ /* Delete a thread from the list of threads */
+ static void
+ child_delete_thread (DWORD id)
+ {
+ thread_info *th;
+
+ if (info_verbose)
+ printf_unfiltered ("[Deleting %s]\n", target_pid_to_str (id));
+ delete_thread (id);
+
+ for (th = &thread_head;
+ th->next != NULL && th->next->id != id;
+ th = th->next)
+ continue;
+
+ if (th->next != NULL)
+ {
+ thread_info *here = th->next;
+ th->next = here->next;
+ close_handle (here->h);
+ free (here);
+ }
+ }
+
+ static void
+ check (BOOL ok, const char *file, int line)
+ {
+ if (!ok)
+ 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)
+ {
+ if (r >= 0)
+ {
+ supply_register (r, (char *) regptr (¤t_thread->context, r));
+ }
+ else
+ {
+ for (r = 0; r < NUM_REGS; r++)
+ do_child_fetch_inferior_registers (r);
+ }
+ }
+
+ static void
+ child_fetch_inferior_registers (int r)
+ {
+ current_thread = thread_rec (inferior_pid, TRUE);
+ do_child_fetch_inferior_registers (r);
+ }
+
+ static void
+ do_child_store_inferior_registers (int r)
+ {
+ if (r >= 0)
+ read_register_gen (r, ((char *) ¤t_thread->context) + mappings[r]);
+ else
+ {
+ for (r = 0; r < NUM_REGS; r++)
+ do_child_store_inferior_registers (r);
+ }
+ }
+
+ /* Store a new register value into the current thread context */
+ static void
+ child_store_inferior_registers (int r)
+ {
+ current_thread = thread_rec (inferior_pid, TRUE);
+ do_child_store_inferior_registers (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 (PTR dummy)
+ {
+ LOAD_DLL_DEBUG_INFO *event = ¤t_event.u.LoadDll;
+ char dll_buf[MAX_PATH + 1];
+ char *p, *bufp, *imgp, *dll_name, *dll_basename;
+ int len;
+
+ dll_buf[0] = dll_buf[sizeof (dll_buf) - 1] = '\0';
+ if (!event->lpImageName)
+ return 1;
+
+ len = 0;
+ for (bufp = dll_buf, imgp = event->lpImageName;
+ bufp < dll_buf + sizeof (dll_buf);
+ bufp += 16, imgp += 16)
+ {
+ gdb_wince_len nbytes = 0;
+ (void) read_process_memory (current_process_handle,
+ imgp, bufp, 16, &nbytes);
+
+ if (!nbytes && bufp == dll_buf)
+ return 1; /* couldn't read it */
+ for (p = bufp; p < bufp + nbytes; p++)
+ {
+ len++;
+ if (*p == '\0')
+ goto out;
+ if (event->fUnicode)
+ p++;
+ }
+ if (!nbytes)
+ break;
+ }
+
+ out:
+ if (!len)
+ return 1;
+ dll_buf[len] = '\0';
+ dll_name = alloca (len);
+
+ if (!dll_name)
+ return 1;
+
+ if (!event->fUnicode)
+ memcpy (dll_name, dll_buf, len);
+ else
+ WideCharToMultiByte (CP_ACP, 0, (LPCWSTR) dll_buf, len,
+ dll_name, len, 0, 0);
+
+ while ((p = strchr (dll_name, '\\')))
+ *p = '/';
+
+ /* FIXME!! It would be nice to define one symbol which pointed to the
+ front of the dll if we can't find any symbols. */
+
+ if (!(dll_basename = strrchr (dll_name, '/')))
+ dll_basename = dll_name;
+ else
+ dll_basename++;
+
+ /* The symbols in a dll are offset by 0x1000, which is the
+ the offset from 0 of the first byte in an image - because
+ of the file header and the section alignment.
+
+ 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 (§ion_addrs, 0, sizeof (section_addrs));
+ section_addrs.text_addr = (int) event->lpBaseOfDll + 0x1000;
+ symbol_file_add (dll_name, 0, §ion_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. */
+ static void
+ handle_output_debug_string (struct target_waitstatus *ourstatus)
+ {
+ char p[256];
+ char s[255];
+ char *q;
+ gdb_wince_len nbytes_read;
+ gdb_wince_len nbytes = current_event.u.DebugString.nDebugStringLength;
+
+ if (nbytes > 255)
+ nbytes = 255;
+
+ memset (p, 0, sizeof (p));
+ if (!read_process_memory (current_process_handle,
+ current_event.u.DebugString.lpDebugStringData,
+ &p, nbytes, &nbytes_read)
+ || !*p)
+ return;
+
+ memset (s, 0, sizeof (s));
+ WideCharToMultiByte (CP_ACP, 0, (LPCWSTR) p, (int) nbytes_read, s,
+ sizeof (s) - 1, NULL, NULL);
+ q = strchr (s, '\n');
+ if (q != NULL)
+ {
+ *q = '\0';
+ if (*--q = '\r')
+ *q = '\0';
+ }
+
+ warning (s);
+ return;
+ }
+
+ /* Handle target exceptions. */
+ static int
+ handle_exception (struct target_waitstatus *ourstatus)
+ {
+ thread_info *th;
+
+ if (current_event.u.Exception.dwFirstChance)
+ return 0;
+
+ 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:
+ DEBUG_EXCEPT (("gdb: Target exception ACCESS_VIOLATION at 0x%08x\n",
+ (unsigned) current_event.u.Exception.ExceptionRecord.ExceptionAddress));
+ ourstatus->value.sig = TARGET_SIGNAL_SEGV;
+ break;
+ case STATUS_STACK_OVERFLOW:
+ DEBUG_EXCEPT (("gdb: Target exception STACK_OVERFLOW at 0x%08x\n",
+ (unsigned) current_event.u.Exception.ExceptionRecord.ExceptionAddress));
+ ourstatus->value.sig = TARGET_SIGNAL_SEGV;
+ break;
+ case EXCEPTION_BREAKPOINT:
+ DEBUG_EXCEPT (("gdb: Target exception BREAKPOINT at 0x%08x\n",
+ (unsigned) current_event.u.Exception.ExceptionRecord.ExceptionAddress));
+ ourstatus->value.sig = TARGET_SIGNAL_TRAP;
+ break;
+ case DBG_CONTROL_C:
+ DEBUG_EXCEPT (("gdb: Target exception CONTROL_C at 0x%08x\n",
+ (unsigned) current_event.u.Exception.ExceptionRecord.ExceptionAddress));
+ ourstatus->value.sig = TARGET_SIGNAL_INT;
+ /* User typed CTRL-C. Continue with this status */
+ last_sig = SIGINT; /* FIXME - should check pass state */
+ break;
+ case EXCEPTION_SINGLE_STEP:
+ DEBUG_EXCEPT (("gdb: Target exception SINGLE_STEP at 0x%08x\n",
+ (unsigned) current_event.u.Exception.ExceptionRecord.ExceptionAddress));
+ ourstatus->value.sig = TARGET_SIGNAL_TRAP;
+ 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. */
+
+ printf_unfiltered ("gdb: unknown target exception 0x%08x at 0x%08x\n",
+ current_event.u.Exception.ExceptionRecord.ExceptionCode,
+ current_event.u.Exception.ExceptionRecord.ExceptionAddress);
+ ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN;
+ break;
+ }
+ exception_count++;
+ return 1;
+ }
+
+ /* Resume all artificially suspended threads if we are continuing
+ execution */
+ static BOOL
+ child_continue (DWORD continue_status, int id)
+ {
+ int i;
+ thread_info *th;
+ BOOL res;
+
+ DEBUG_EVENTS (("ContinueDebugEvent (cpid=%d, ctid=%d, DBG_CONTINUE);\n",
+ (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId));
+ res = continue_debug_event (current_event.dwProcessId,
+ current_event.dwThreadId,
+ continue_status);
+ if (res)
+ for (th = &thread_head; (th = th->next) != NULL;)
+ if (((id == -1) || (id == th->id)) && th->suspend_count)
+ {
+ for (i = 0; i < th->suspend_count; i++)
+ (void) resume_thread (th->h);
+ th->suspend_count = 0;
+ }
+
+ return res;
+ }
+
+ /* Get the next event from the child. Return 1 if the event requires
+ handling by WFI (or whatever).
+ */
+ static int
+ get_child_debug_event (int pid, struct target_waitstatus *ourstatus, DWORD * event_code, int *retval)
+ {
+ BOOL debug_event;
+ DWORD continue_status;
+ int breakout = 1;
+
+ if (!(debug_event = wait_for_debug_event (¤t_event, 1000)))
+ {
+ breakout = *retval = *event_code = 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)
+ {
+ case CREATE_THREAD_DEBUG_EVENT:
+ DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%x code=%s)\n",
+ (unsigned) current_event.dwProcessId,
+ (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);
+ if (info_verbose)
+ printf_unfiltered ("[New %s]\n",
+ target_pid_to_str (current_event.dwThreadId));
+ break;
+
+ case EXIT_THREAD_DEBUG_EVENT:
+ DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n",
+ (unsigned) current_event.dwProcessId,
+ (unsigned) current_event.dwThreadId,
+ "EXIT_THREAD_DEBUG_EVENT"));
+ child_delete_thread (current_event.dwThreadId);
+ break;
+
+ case CREATE_PROCESS_DEBUG_EVENT:
+ DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n",
+ (unsigned) current_event.dwProcessId,
+ (unsigned) current_event.dwThreadId,
+ "CREATE_PROCESS_DEBUG_EVENT"));
+ current_process_handle = current_event.u.CreateProcessInfo.hProcess;
+
+ main_thread_id = inferior_pid = current_event.dwThreadId;
+ /* Add the main thread */
+ current_thread = child_add_thread (inferior_pid,
+ current_event.u.CreateProcessInfo.hThread);
+ break;
+
+ case EXIT_PROCESS_DEBUG_EVENT:
+ DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n",
+ (unsigned) current_event.dwProcessId,
+ (unsigned) current_event.dwThreadId,
+ "EXIT_PROCESS_DEBUG_EVENT"));
+ ourstatus->kind = TARGET_WAITKIND_EXITED;
+ ourstatus->value.integer = current_event.u.ExitProcess.dwExitCode;
+ close_handle (current_process_handle);
+ *retval = current_event.dwProcessId;
+ goto out;
+
+ case LOAD_DLL_DEBUG_EVENT:
+ DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n",
+ (unsigned) current_event.dwProcessId,
+ (unsigned) current_event.dwThreadId,
+ "LOAD_DLL_DEBUG_EVENT"));
+ catch_errors (handle_load_dll, NULL, (char *) "", RETURN_MASK_ALL);
+ registers_changed (); /* mark all regs invalid */
+ break;
+
+ case UNLOAD_DLL_DEBUG_EVENT:
+ DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n",
+ (unsigned) current_event.dwProcessId,
+ (unsigned) current_event.dwThreadId,
+ "UNLOAD_DLL_DEBUG_EVENT"));
+ break; /* FIXME: don't know what to do here */
+
+ case EXCEPTION_DEBUG_EVENT:
+ DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n",
+ (unsigned) current_event.dwProcessId,
+ (unsigned) current_event.dwThreadId,
+ "EXCEPTION_DEBUG_EVENT"));
+ if (handle_exception (ourstatus))
+ {
+ 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;
+ break;
+
+ case OUTPUT_DEBUG_STRING_EVENT: /* message from the kernel */
+ DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n",
+ (unsigned) current_event.dwProcessId,
+ (unsigned) current_event.dwThreadId,
+ "OUTPUT_DEBUG_STRING_EVENT"));
+ handle_output_debug_string (ourstatus);
+ break;
+ default:
+ printf_unfiltered ("gdb: kernel event for pid=%d tid=%d\n",
+ current_event.dwProcessId,
+ current_event.dwThreadId);
+ printf_unfiltered (" unknown event code %d\n",
+ current_event.dwDebugEventCode);
+ break;
+ }
+
+ breakout = 0;
+ CHECK (child_continue (continue_status, -1));
+
+ out:
+ return breakout;
+ }
+
+ /* Wait for interesting events to occur in the target process. */
+ static int
+ child_wait (int pid, struct target_waitstatus *ourstatus)
+ {
+ DWORD event_code;
+ int retval;
+
+ /* We loop when we get a non-standard exception rather than return
+ with a SPURIOUS because resume can try and step or modify things,
+ which needs a current_thread->h. But some of these exceptions mark
+ the birth or death of threads, which mean that the current thread
+ isn't necessarily what you think it is. */
+
+ while (1)
+ if (get_child_debug_event (pid, ourstatus, &event_code, &retval))
+ return retval;
+ else
+ {
+ int detach = 0;
+
+ if (ui_loop_hook != NULL)
+ detach = ui_loop_hook (0);
+
+ if (detach)
+ child_kill_inferior ();
+ }
+ }
+
+ /* Print status information about what we're accessing. */
+
+ static void
+ child_files_info (ignore)
+ struct target_ops *ignore;
+ {
+ printf_unfiltered ("\tUsing the running image of child %s.\n",
+ target_pid_to_str (inferior_pid));
+ }
+
+ /* ARGSUSED */
+ static void
+ child_open (arg, from_tty)
+ char *arg;
+ int from_tty;
+ {
+ error ("Use the \"run\" command to start a child process.");
+ }
+
+ #define FACTOR (0x19db1ded53ea710LL)
+ #define NSPERSEC 10000000
+
+ /* Convert a Win32 time to "UNIX" format. */
+ long
+ to_time_t (FILETIME * ptr)
+ {
+ /* A file time is the number of 100ns since jan 1 1601
+ stuffed into two long words.
+ A time_t is the number of seconds since jan 1 1970. */
+
+ long rem;
+ long long x = ((long long) ptr->dwHighDateTime << 32) + ((unsigned) ptr->dwLowDateTime);
+ x -= FACTOR; /* number of 100ns between 1601 and 1970 */
+ rem = x % ((long long) NSPERSEC);
+ rem += (NSPERSEC / 2);
+ x /= (long long) NSPERSEC; /* number of 100ns in a second */
+ x += (long long) (rem / NSPERSEC);
+ return x;
+ }
+
+ /* Upload a file to the remote device depending on the user's
+ 'set remoteupload' specification. */
+ char *
+ upload_to_device (const char *to, const char *from)
+ {
+ HANDLE h;
+ 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;
+ struct stat st;
+ int fd;
+
+ /* Look for a path separator and only use trailing part. */
+ while ((p = strpbrk (to, "/\\")) != NULL)
+ to = p + 1;
+
+ if (!*to)
+ error ("no filename found to upload - %s.", in_to);
+
+ len = strlen (dir) + strlen (to) + 2;
+ remotefile = (char *) realloc (remotefile, len);
+ strcpy (remotefile, dir);
+ strcat (remotefile, "\\");
+ strcat (remotefile, to);
+
+ if (upload_when != UPLOAD_NEVER)
+ return remotefile; /* Don't bother uploading. */
+
+ /* Open the source. */
+ if ((fd = openp (getenv ("PATH"), TRUE, (char *) from, O_RDONLY, 0, NULL)) < 0)
+ error ("couldn't open %s", from);
+
+ /* Get the time for later comparison. */
+ if (fstat (fd, &st))
+ st.st_mtime = (time_t) - 1;
+
+ /* Always attempt to create the directory on the remote system. */
+ wstr = towide (dir, NULL);
+ (void) CeCreateDirectory (wstr, NULL);
+
+ /* Attempt to open the remote file, creating it if it doesn't exist. */
+ wstr = towide (remotefile, NULL);
+ h = CeCreateFile (wstr, GENERIC_READ | GENERIC_WRITE, 0, NULL,
+ OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ /* Some kind of problem? */
+ err = CeGetLastError ();
+ if (h == NULL)
+ error ("error creating file to \"%s\". Windows error %d.",
+ remotefile, err);
+
+ /* 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)
+ {
+ DWORD nbytes;
+ char buf[4096];
+ int n;
+
+ /* Upload the file. */
+ while ((n = read (fd, buf, sizeof (buf))) > 0)
+ if (!CeWriteFile (h, buf, (DWORD) n, &nbytes, NULL))
+ error ("error writing to remote device - %d.",
+ CeGetLastError ());
+ }
+
+ close (fd);
+ CeCloseHandle (h);
+
+ return remotefile;
+ }
+
+ /* Initialize the connection to the remote device. */
+ static void
+ wince_initialize ()
+ {
+ int tmp;
+ char args[256];
+ char *hostname;
+ struct sockaddr_in sin;
+ char *stub_file_name;
+ int s0;
+ PROCESS_INFORMATION pi;
+
+ if (!connection_initialized)
+ switch (CeRapiInit ())
+ {
+ case 0:
+ connection_initialized = 1;
+ break;
+ default:
+ CeRapiUninit ();
+ error ("Can't initialize connection to remote device.\n");
+ break;
+ }
+
+ /* Upload the stub to the handheld device. */
+ stub_file_name = upload_to_device ("wince-stub.exe", WINCE_STUB);
+ strcpy (args, stub_file_name);
+
+ if (remote_add_host)
+ {
+ strcat (args, " ");
+ hostname = strchr (args, '\0');
+ if (gethostname (hostname, sizeof (args) - strlen (args)))
+ error ("couldn't get hostname of this system.");
+ sprintf(hostname, "192.168.187.6");
+ }
+
+ /* Get a socket. */
+ if ((s0 = socket (AF_INET, SOCK_STREAM, 0)) < 0)
+ stub_error ("Couldn't connect to host system.");
+
+ /* Allow rapid reuse of the port. */
+ tmp = 1;
+ (void) setsockopt (s0, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp, sizeof (tmp));
+
+
+ /* Set up the information for connecting to the host gdb process. */
+ memset (&sin, 0, sizeof (sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons (7000); /* FIXME: This should be configurable */
+
+ if (bind (s0, (struct sockaddr *) &sin, sizeof (sin)))
+ error ("couldn't bind socket");
+
+ if (listen (s0, 1))
+ error ("Couldn't open socket for listening.\n");
+
+ /* Start up the stub on the remote device. */
+ if (!CeCreateProcess (towide (stub_file_name, NULL), towide (args, NULL),
+ NULL, NULL, 0, 0, NULL, NULL, NULL, &pi))
+ error ("Unable to start remote stub '%s'. Windows CE error %d.",
+ stub_file_name, CeGetLastError ());
+
+ /* Wait for a connection */
+
+ if ((s = accept (s0, NULL, NULL)) < 0)
+ error ("couldn't set up server for connection.");
+
+ close (s0);
+ }
+
+ /* Start an inferior win32 child process and sets inferior_pid to its pid.
+ EXEC_FILE is the file to run.
+ ALLARGS is a string containing the arguments to the program.
+ ENV is the environment vector to pass. Errors reported with error(). */
+ static void
+ child_create_inferior (char *exec_file, char *args, char **env)
+ {
+ PROCESS_INFORMATION pi;
+ struct target_waitstatus dummy;
+ int ret;
+ DWORD flags, event_code;
+ char *exec_and_args;
+
+ if (!exec_file)
+ error ("No executable specified, use `target exec'.\n");
+
+ flags = DEBUG_PROCESS;
+
+ wince_initialize (); /* Make sure we've got a connection. */
+ if (!remote_dcache)
+ remote_dcache = dcache_init (remote_read_bytes, remote_write_bytes);
+ else
+ dcache_flush (remote_dcache);
+
+ exec_file = upload_to_device (exec_file, exec_file);
+
+ while (*args == ' ')
+ args++;
+
+ /* Allocate space for "command<sp>args" */
+ if (*args == '\0')
+ {
+ exec_and_args = alloca (strlen (exec_file) + 1);
+ strcpy (exec_and_args, exec_file);
+ }
+ else
+ {
+ exec_and_args = alloca (strlen (exec_file + strlen (args) + 2));
+ sprintf (exec_and_args, "%s %s", exec_file, args);
+ }
+
+ memset (&pi, 0, sizeof (pi));
+ /* Execute the process */
+ if (!create_process (exec_file, exec_and_args, flags, &pi))
+ error ("Error creating process %s, (error %d)\n", exec_file, GetLastError ());
+
+ exception_count = 0;
+ event_count = 0;
+
+ current_process_handle = pi.hProcess;
+ current_event.dwProcessId = pi.dwProcessId;
+ memset (¤t_event, 0, sizeof (current_event));
+ inferior_pid = current_event.dwThreadId = pi.dwThreadId;
+ push_target (&child_ops);
+ child_init_thread_list ();
+ child_add_thread (pi.dwThreadId, pi.hThread);
+ init_wait_for_inferior ();
+ clear_proceed_status ();
+ 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);
+
+ proceed ((CORE_ADDR) -1, TARGET_SIGNAL_0, 0);
+ }
+
+ /* Chile has gone bye-bye. */
+ static void
+ child_mourn_inferior ()
+ {
+ (void) child_continue (DBG_CONTINUE, -1);
+ unpush_target (&child_ops);
+ stop_stub ();
+ CeRapiUninit ();
+ connection_initialized = 0;
+ generic_mourn_inferior ();
+ }
+
+ /* Move memory from child to/from gdb. */
+ int
+ child_xfer_memory (CORE_ADDR memaddr, char *our, int len,
+ int write, struct target_ops *target)
+ {
+ if (len <= 0)
+ return 0;
+ return dcache_xfer_memory (remote_dcache, memaddr, our, len, write);
+ }
+
+ /* Terminate the process and wait for child to tell us it has completed. */
+ void
+ child_kill_inferior (void)
+ {
+ CHECK (terminate_process (current_process_handle));
+
+ for (;;)
+ {
+ if (!child_continue (DBG_CONTINUE, -1))
+ break;
+ if (!wait_for_debug_event (¤t_event, INFINITE))
+ break;
+ if (current_event.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT)
+ break;
+ }
+
+ CHECK (close_handle (current_process_handle));
+ close_handle (current_thread->h);
+ 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)
+ {
+ thread_info *th;
+ DWORD continue_status = last_sig > 0 && last_sig < NSIG ?
+ DBG_EXCEPTION_NOT_HANDLED : DBG_CONTINUE;
+
+ DEBUG_EXEC (("gdb: child_resume (pid=%d, step=%d, sig=%d);\n",
+ pid, step, sig));
+
+ /* Get context for currently selected thread */
+ th = thread_rec (current_event.dwThreadId, FALSE);
+
+ if (th->context.ContextFlags)
+ {
+ CHECK (set_thread_context (th->h, &th->context));
+ th->context.ContextFlags = 0;
+ }
+
+ dcache_flush (remote_dcache);
+
+ /* Allow continuing with the same signal that interrupted us.
+ Otherwise complain. */
+ if (sig && sig != last_sig)
+ fprintf_unfiltered (gdb_stderr, "Can't send signals to the child. signal %d\n", sig);
+
+ last_sig = 0;
+ child_continue (continue_status, pid);
+ }
+
+ static void
+ child_prepare_to_store ()
+ {
+ /* Do nothing, since we can store individual regs */
+ }
+
+ static int
+ child_can_run ()
+ {
+ return 1;
+ }
+
+ static void
+ child_close ()
+ {
+ DEBUG_EVENTS (("gdb: child_close, inferior_pid=%d\n", inferior_pid));
+ }
+
+ /* Explicitly upload file to remotedir */
+
+ static void
+ child_load (char *file, int from_tty)
+ {
+ upload_to_device (file, file);
+ }
+
+ struct target_ops child_ops;
+
+ static void
+ init_child_ops (void)
+ {
+ memset (&child_ops, 0, sizeof (child_ops));
+ child_ops.to_shortname = (char *) "child";
+ child_ops.to_longname = (char *) "Windows CE process";
+ child_ops.to_doc = (char *) "Windows CE process (started by the \"run\" command).";
+ child_ops.to_open = child_open;
+ child_ops.to_close = child_close;
+ child_ops.to_resume = child_resume;
+ child_ops.to_wait = child_wait;
+ child_ops.to_fetch_registers = child_fetch_inferior_registers;
+ child_ops.to_store_registers = child_store_inferior_registers;
+ child_ops.to_prepare_to_store = child_prepare_to_store;
+ child_ops.to_xfer_memory = child_xfer_memory;
+ child_ops.to_files_info = child_files_info;
+ child_ops.to_insert_breakpoint = memory_insert_breakpoint;
+ child_ops.to_remove_breakpoint = memory_remove_breakpoint;
+ child_ops.to_terminal_init = terminal_init_inferior;
+ child_ops.to_terminal_inferior = terminal_inferior;
+ child_ops.to_terminal_ours_for_output = terminal_ours_for_output;
+ child_ops.to_terminal_ours = terminal_ours;
+ child_ops.to_terminal_info = child_terminal_info;
+ child_ops.to_kill = child_kill_inferior;
+ child_ops.to_load = child_load;
+ child_ops.to_create_inferior = child_create_inferior;
+ child_ops.to_mourn_inferior = child_mourn_inferior;
+ child_ops.to_can_run = child_can_run;
+ child_ops.to_thread_alive = win32_child_thread_alive;
+ child_ops.to_stratum = process_stratum;
+ child_ops.to_has_all_memory = 1;
+ child_ops.to_has_memory = 1;
+ child_ops.to_has_stack = 1;
+ child_ops.to_has_registers = 1;
+ child_ops.to_has_execution = 1;
+ child_ops.to_sections = 0;
+ child_ops.to_sections_end = 0;
+ child_ops.to_magic = OPS_MAGIC;
+ }
+
+
+ /* Handle 'set remoteupload' parameter. */
+
+ #define replace_upload(what) \
+ upload_when = UPLOAD_NEWER; \
+ remote_upload = realloc (remote_upload, strlen (upload_options[upload_when].name)); \
+ strcpy (remote_upload, upload_options[upload_when].name);
+
+ static void
+ set_upload_type (char *ignore, int from_tty)
+ {
+ int i, len;
+ char *bad_option;
+
+ if (!remote_upload || !remote_upload[0])
+ {
+ replace_upload (UPLOAD_NEWER);
+ if (from_tty)
+ printf_unfiltered ("Upload upload_options are: always, newer, never.\n");
+ return;
+ }
+
+ len = strlen (remote_upload);
+ for (i = 0; i < (sizeof (upload_options) / sizeof (upload_options[0])); i++)
+ 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;
+ return;
+ }
+
+ bad_option = remote_upload;
+ replace_upload (UPLOAD_NEWER);
+ error ("Unknown upload type: %s.", bad_option);
+ }
+
+ void
+ _initialize_inftarg ()
+ {
+ struct cmd_list_element *set;
+ init_child_ops ();
+
+ add_show_from_set
+ (add_set_cmd ((char *) "remotedirectory", no_class,
+ var_string_noescape, (char *) &remote_directory,
+ (char *) "Set directory for remote upload.\n",
+ &setlist),
+ &showlist);
+ remote_directory = xstrdup (remote_directory);
+
+ set = add_set_cmd ((char *) "remoteupload", no_class,
+ var_string_noescape, (char *) &remote_upload,
+ (char *) "Set how to upload executables to remote device.\n",
+ &setlist);
+ add_show_from_set (set, &showlist);
+ set->function.cfunc = set_upload_type;
+ set_upload_type (NULL, 0);
+ set_dcache_state (1);
+
+ add_show_from_set
+ (add_set_cmd ((char *) "debugexec", class_support, var_boolean,
+ (char *) &debug_exec,
+ (char *) "Set whether to display execution in child process.",
+ &setlist),
+ &showlist);
+
+ add_show_from_set
+ (add_set_cmd ((char *) "remoteaddhost", class_support, var_boolean,
+ (char *) &remote_add_host,
+ (char *) "Set whether to add this host to remote stub arguments for\n
+ debugging over a network.", &setlist),
+ &showlist);
+
+ add_show_from_set
+ (add_set_cmd ((char *) "debugevents", class_support, var_boolean,
+ (char *) &debug_events,
+ (char *) "Set whether to display kernel events in child process.",
+ &setlist),
+ &showlist);
+
+ add_show_from_set
+ (add_set_cmd ((char *) "debugmemory", class_support, var_boolean,
+ (char *) &debug_memory,
+ (char *) "Set whether to display memory accesses in child process.",
+ &setlist),
+ &showlist);
+
+ add_show_from_set
+ (add_set_cmd ((char *) "debugexceptions", class_support, var_boolean,
+ (char *) &debug_exceptions,
+ (char *) "Set whether to display kernel exceptions in child process.",
+ &setlist),
+ &showlist);
+
+ add_target (&child_ops);
+ }
+
+ /* 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. */
+ static int
+ win32_child_thread_alive (int pid)
+ {
+ return thread_alive (thread_rec (pid, FALSE)->h);
+ }
+
+ /* Convert pid to printable format. */
+ char *
+ cygwin_pid_to_str (int pid)
+ {
+ static char buf[80];
+ if (pid == current_event.dwProcessId)
+ sprintf (buf, "process %d", pid);
+ else
+ sprintf (buf, "thread %d.0x%x", (unsigned) current_event.dwProcessId, pid);
+ return buf;
+ }
Index: config/arm/arm-wince-pe.mt
===================================================================
RCS file: arm-wince-pe.mt
diff -N arm-wince-pe.mt
*** /dev/null Tue May 5 13:32:27 1998
--- arm-wince-pe.mt Tue Feb 22 15:31:32 2000
***************
*** 0 ****
--- 1,5 ----
+ # Target: Acorn RISC machine (ARM) with simulator
+ TDEPFILES= arm-tdep.o wince.o
+ TM_FILE= tm-arm.h
+ MT_CFLAGS=-DARM -U_M_IX86 -U__i386__ -DUNICODE -D_WIN32_WCE -DWINCE_STUB='"${target_alias}-stub.exe"'
+ WIN32LIBS=-lrapi
Index: config/arm/tm-arm.h
===================================================================
RCS file: /cvs/src//src/gdb/config/arm/tm-arm.h,v
retrieving revision 1.1.1.9
diff -p -r1.1.1.9 tm-arm.h
*** tm-arm.h 2000/02/05 07:29:52 1.1.1.9
--- tm-arm.h 2000/02/22 23:31:33
*************** void arm_fix_call_dummy (char *dummy, CO
*** 475,480 ****
--- 475,491 ----
CORE_ADDR arm_get_next_pc (CORE_ADDR pc);
+ /* Windows CE needs to do single stepping by forcing a trap into memory and
+ it is little-endian. */
+
+ #ifdef _WIN32_WCE
+ #define SOFTWARE_SINGLE_STEP_P 1
+ #define SOFTWARE_SINGLE_STEP(sig, bp_p) wince_software_single_step (sig, bp_p)
+ void wince_software_single_step (unsigned int, int);
+ #undef TARGET_BYTE_ORDER_SELECTABLE
+ #define TARGET_BYTE_ORDER LITTLE_ENDIAN
+ #endif
+
/* Macros for setting and testing a bit in a minimal symbol that marks
it as Thumb function. The MSB of the minimal symbol's "info" field
is used for this purpose. This field is already being used to store
Index: config/mips/tm-mips.h
===================================================================
RCS file: /cvs/src//src/gdb/config/mips/tm-mips.h,v
retrieving revision 1.1.1.11
diff -p -r1.1.1.11 tm-mips.h
*** tm-mips.h 1999/12/22 21:45:14 1.1.1.11
--- tm-mips.h 2000/02/22 23:31:34
*************** struct value;
*** 45,50 ****
--- 45,61 ----
#define MIPS_EABI 0
#endif
+ /* Windows CE needs to do single stepping by forcing a trap into memory and
+ it is little-endian. */
+
+ #ifdef _WIN32_WCE
+ #define SOFTWARE_SINGLE_STEP_P 1
+ #define SOFTWARE_SINGLE_STEP(sig, bp_p) wince_software_single_step (sig, bp_p)
+ void wince_software_single_step (unsigned int, int);
+ #undef TARGET_BYTE_ORDER_SELECTABLE
+ #define TARGET_BYTE_ORDER LITTLE_ENDIAN
+ #endif
+
#if !defined (TARGET_MONITOR_PROMPT)
#define TARGET_MONITOR_PROMPT "<IDT>"
#endif
Index: config/sh/tm-sh.h
===================================================================
RCS file: /cvs/src//src/gdb/config/sh/tm-sh.h,v
retrieving revision 1.1.1.8
diff -p -r1.1.1.8 tm-sh.h
*** tm-sh.h 1999/12/14 01:05:42 1.1.1.8
--- tm-sh.h 2000/02/22 23:31:35
*************** extern CORE_ADDR sh_skip_prologue PARAMS
*** 54,59 ****
--- 54,70 ----
#define SAVED_PC_AFTER_CALL(frame) (ADDR_BITS_REMOVE(read_register(PR_REGNUM)))
+ /* Windows CE needs to do single stepping by forcing a trap into memory and
+ it is little-endian. */
+
+ #ifdef _WIN32_WCE
+ #define SOFTWARE_SINGLE_STEP_P 1
+ #define SOFTWARE_SINGLE_STEP(sig, bp_p) wince_software_single_step (sig, bp_p)
+ void wince_software_single_step (unsigned int, int);
+ #undef TARGET_BYTE_ORDER_SELECTABLE
+ #define TARGET_BYTE_ORDER LITTLE_ENDIAN
+ #endif
+
/* Stack grows downward. */
#define INNER_THAN(lhs,rhs) ((lhs) < (rhs))