xref: /openbsd-src/gnu/usr.bin/binutils/gdb/wince-stub.c (revision b725ae7711052a2233e31a66fefb8a752c388d7a)
1*b725ae77Skettenis /* wince-stub.c -- debugging stub for a Windows CE device
2*b725ae77Skettenis 
3*b725ae77Skettenis    Copyright 1999, 2000 Free Software Foundation, Inc.
4*b725ae77Skettenis    Contributed by Cygnus Solutions, A Red Hat Company.
5*b725ae77Skettenis 
6*b725ae77Skettenis    This file is part of GDB.
7*b725ae77Skettenis 
8*b725ae77Skettenis    This program is free software; you can redistribute it and/or modify
9*b725ae77Skettenis    it under the terms of the GNU General Public License as published by
10*b725ae77Skettenis    the Free Software Foundation; either version 2 of the License, or
11*b725ae77Skettenis    (at your option) any later version.
12*b725ae77Skettenis 
13*b725ae77Skettenis    This program is distributed in the hope that it will be useful,
14*b725ae77Skettenis    but WITHOUT ANY WARRANTY; without eve nthe implied warranty of
15*b725ae77Skettenis    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16*b725ae77Skettenis    GNU General Public License for more details.
17*b725ae77Skettenis 
18*b725ae77Skettenis    You should have received a copy of the GNU General Public License
19*b725ae77Skettenis    along with this program; if not, write to the Free Software
20*b725ae77Skettenis    Foundation, Inc., 59 Temple Place - Suite 330,
21*b725ae77Skettenis    Boston, MA 02111-1307, USA.
22*b725ae77Skettenis  */
23*b725ae77Skettenis 
24*b725ae77Skettenis /* by Christopher Faylor (cgf@cygnus.com) */
25*b725ae77Skettenis 
26*b725ae77Skettenis #include <stdarg.h>
27*b725ae77Skettenis #include <windows.h>
28*b725ae77Skettenis #include <winsock.h>
29*b725ae77Skettenis #include "wince-stub.h"
30*b725ae77Skettenis 
31*b725ae77Skettenis #define MALLOC(n) (void *) LocalAlloc (LMEM_MOVEABLE | LMEM_ZEROINIT, (UINT)(n))
32*b725ae77Skettenis #define REALLOC(s, n) (void *) LocalReAlloc ((HLOCAL)(s), (UINT)(n), LMEM_MOVEABLE)
33*b725ae77Skettenis #define FREE(s) LocalFree ((HLOCAL)(s))
34*b725ae77Skettenis 
35*b725ae77Skettenis static int skip_next_id = 0;	/* Don't read next API code from socket */
36*b725ae77Skettenis 
37*b725ae77Skettenis /* v-style interface for handling varying argument list error messages.
38*b725ae77Skettenis    Displays the error message in a dialog box and exits when user clicks
39*b725ae77Skettenis    on OK. */
40*b725ae77Skettenis static void
vstub_error(LPCWSTR fmt,va_list args)41*b725ae77Skettenis vstub_error (LPCWSTR fmt, va_list args)
42*b725ae77Skettenis {
43*b725ae77Skettenis   WCHAR buf[4096];
44*b725ae77Skettenis   wvsprintfW (buf, fmt, args);
45*b725ae77Skettenis 
46*b725ae77Skettenis   MessageBoxW (NULL, buf, L"GDB", MB_ICONERROR);
47*b725ae77Skettenis   WSACleanup ();
48*b725ae77Skettenis   ExitThread (1);
49*b725ae77Skettenis }
50*b725ae77Skettenis 
51*b725ae77Skettenis /* The standard way to display an error message and exit. */
52*b725ae77Skettenis static void
stub_error(LPCWSTR fmt,...)53*b725ae77Skettenis stub_error (LPCWSTR fmt, ...)
54*b725ae77Skettenis {
55*b725ae77Skettenis   va_list args;
56*b725ae77Skettenis   va_start (args, fmt);
57*b725ae77Skettenis   vstub_error (fmt, args);
58*b725ae77Skettenis }
59*b725ae77Skettenis 
60*b725ae77Skettenis /* Allocate a limited pool of memory, reallocating over unused
61*b725ae77Skettenis    buffers.  This assumes that there will never be more than four
62*b725ae77Skettenis    "buffers" required which, so far, is a safe assumption. */
63*b725ae77Skettenis static LPVOID
mempool(unsigned int len)64*b725ae77Skettenis mempool (unsigned int len)
65*b725ae77Skettenis {
66*b725ae77Skettenis   static int outn = -1;
67*b725ae77Skettenis   static LPWSTR outs[4] = {NULL, NULL, NULL, NULL};
68*b725ae77Skettenis 
69*b725ae77Skettenis   if (++outn >= (sizeof (outs) / sizeof (outs[0])))
70*b725ae77Skettenis     outn = 0;
71*b725ae77Skettenis 
72*b725ae77Skettenis   /* Allocate space for the converted string, reusing any previously allocated
73*b725ae77Skettenis      space, if applicable. */
74*b725ae77Skettenis   if (outs[outn])
75*b725ae77Skettenis     FREE (outs[outn]);
76*b725ae77Skettenis   outs[outn] = (LPWSTR) MALLOC (len);
77*b725ae77Skettenis 
78*b725ae77Skettenis   return outs[outn];
79*b725ae77Skettenis }
80*b725ae77Skettenis 
81*b725ae77Skettenis /* Standard "oh well" can't communicate error.  Someday this might attempt
82*b725ae77Skettenis    synchronization. */
83*b725ae77Skettenis static void
attempt_resync(LPCWSTR huh,int s)84*b725ae77Skettenis attempt_resync (LPCWSTR huh, int s)
85*b725ae77Skettenis {
86*b725ae77Skettenis   stub_error (L"lost synchronization with host attempting %s.  Error %d", huh, WSAGetLastError ());
87*b725ae77Skettenis }
88*b725ae77Skettenis 
89*b725ae77Skettenis /* Read arbitrary stuff from a socket. */
90*b725ae77Skettenis static int
sockread(LPCWSTR huh,int s,void * str,size_t n)91*b725ae77Skettenis sockread (LPCWSTR huh, int s, void *str, size_t n)
92*b725ae77Skettenis {
93*b725ae77Skettenis   for (;;)
94*b725ae77Skettenis     {
95*b725ae77Skettenis       if (recv (s, str, n, 0) == (int) n)
96*b725ae77Skettenis 	return n;
97*b725ae77Skettenis       attempt_resync (huh, s);
98*b725ae77Skettenis     }
99*b725ae77Skettenis }
100*b725ae77Skettenis 
101*b725ae77Skettenis /* Write arbitrary stuff to a socket. */
102*b725ae77Skettenis static int
sockwrite(LPCWSTR huh,int s,const void * str,size_t n)103*b725ae77Skettenis sockwrite (LPCWSTR huh, int s, const void *str, size_t n)
104*b725ae77Skettenis {
105*b725ae77Skettenis   for (;;)
106*b725ae77Skettenis     {
107*b725ae77Skettenis       if (send (s, str, n, 0) == (int) n)
108*b725ae77Skettenis 	return n;
109*b725ae77Skettenis       attempt_resync (huh, s);
110*b725ae77Skettenis     }
111*b725ae77Skettenis }
112*b725ae77Skettenis 
113*b725ae77Skettenis /* Get a an ID (possibly) and a DWORD from the host gdb.
114*b725ae77Skettenis    Don't bother with the id if the main loop has already
115*b725ae77Skettenis    read it. */
116*b725ae77Skettenis static DWORD
getdword(LPCWSTR huh,int s,gdb_wince_id what_this)117*b725ae77Skettenis getdword (LPCWSTR huh, int s, gdb_wince_id what_this)
118*b725ae77Skettenis {
119*b725ae77Skettenis   DWORD n;
120*b725ae77Skettenis   gdb_wince_id what;
121*b725ae77Skettenis 
122*b725ae77Skettenis   if (skip_next_id)
123*b725ae77Skettenis     skip_next_id = 0;
124*b725ae77Skettenis   else
125*b725ae77Skettenis     do
126*b725ae77Skettenis       if (sockread (huh, s, &what, sizeof (what)) != sizeof (what))
127*b725ae77Skettenis 	stub_error (L"error getting record type from host - %s.", huh);
128*b725ae77Skettenis     while (what_this != what);
129*b725ae77Skettenis 
130*b725ae77Skettenis   if (sockread (huh, s, &n, sizeof (n)) != sizeof (n))
131*b725ae77Skettenis     stub_error (L"error getting %s from host.", huh);
132*b725ae77Skettenis 
133*b725ae77Skettenis   return n;
134*b725ae77Skettenis }
135*b725ae77Skettenis 
136*b725ae77Skettenis /* Get a an ID (possibly) and a WORD from the host gdb.
137*b725ae77Skettenis    Don't bother with the id if the main loop has already
138*b725ae77Skettenis    read it. */
139*b725ae77Skettenis static WORD
getword(LPCWSTR huh,int s,gdb_wince_id what_this)140*b725ae77Skettenis getword (LPCWSTR huh, int s, gdb_wince_id what_this)
141*b725ae77Skettenis {
142*b725ae77Skettenis   WORD n;
143*b725ae77Skettenis   gdb_wince_id what;
144*b725ae77Skettenis 
145*b725ae77Skettenis   if (skip_next_id)
146*b725ae77Skettenis     skip_next_id = 0;
147*b725ae77Skettenis   else
148*b725ae77Skettenis     do
149*b725ae77Skettenis       if (sockread (huh, s, &what, sizeof (what)) != sizeof (what))
150*b725ae77Skettenis 	stub_error (L"error getting record type from host - %s.", huh);
151*b725ae77Skettenis     while (what_this != what);
152*b725ae77Skettenis 
153*b725ae77Skettenis   if (sockread (huh, s, &n, sizeof (n)) != sizeof (n))
154*b725ae77Skettenis     stub_error (L"error getting %s from host.", huh);
155*b725ae77Skettenis 
156*b725ae77Skettenis   return n;
157*b725ae77Skettenis }
158*b725ae77Skettenis 
159*b725ae77Skettenis /* Handy defines for getting various types of values. */
160*b725ae77Skettenis #define gethandle(huh, s, what) (HANDLE) getdword ((huh), (s), (what))
161*b725ae77Skettenis #define getpvoid(huh, s, what) (LPVOID) getdword ((huh), (s), (what))
162*b725ae77Skettenis #define getlen(huh, s, what) (gdb_wince_len) getword ((huh), (s), (what))
163*b725ae77Skettenis 
164*b725ae77Skettenis /* Get an arbitrary block of memory from the gdb host.  This comes in
165*b725ae77Skettenis    two chunks an id/dword representing the length and the stream of memory
166*b725ae77Skettenis    itself. Returns a pointer, allocated via mempool, to a memory buffer. */
167*b725ae77Skettenis static LPWSTR
getmemory(LPCWSTR huh,int s,gdb_wince_id what,gdb_wince_len * inlen)168*b725ae77Skettenis getmemory (LPCWSTR huh, int s, gdb_wince_id what, gdb_wince_len *inlen)
169*b725ae77Skettenis {
170*b725ae77Skettenis   LPVOID p;
171*b725ae77Skettenis   gdb_wince_len dummy;
172*b725ae77Skettenis 
173*b725ae77Skettenis   if (!inlen)
174*b725ae77Skettenis     inlen = &dummy;
175*b725ae77Skettenis 
176*b725ae77Skettenis   *inlen = getlen (huh, s, what);
177*b725ae77Skettenis 
178*b725ae77Skettenis   p = mempool ((unsigned int) *inlen);	/* FIXME: check for error */
179*b725ae77Skettenis 
180*b725ae77Skettenis   if ((gdb_wince_len) sockread (huh, s, p, *inlen) != *inlen)
181*b725ae77Skettenis     stub_error (L"error getting string from host.");
182*b725ae77Skettenis 
183*b725ae77Skettenis   return p;
184*b725ae77Skettenis }
185*b725ae77Skettenis 
186*b725ae77Skettenis /* Output an id/dword to the host */
187*b725ae77Skettenis static void
putdword(LPCWSTR huh,int s,gdb_wince_id what,DWORD n)188*b725ae77Skettenis putdword (LPCWSTR huh, int s, gdb_wince_id what, DWORD n)
189*b725ae77Skettenis {
190*b725ae77Skettenis   if (sockwrite (huh, s, &what, sizeof (what)) != sizeof (what))
191*b725ae77Skettenis     stub_error (L"error writing record id for %s to host.", huh);
192*b725ae77Skettenis   if (sockwrite (huh, s, &n, sizeof (n)) != sizeof (n))
193*b725ae77Skettenis     stub_error (L"error writing %s to host.", huh);
194*b725ae77Skettenis }
195*b725ae77Skettenis 
196*b725ae77Skettenis /* Output an id/word to the host */
197*b725ae77Skettenis static void
putword(LPCWSTR huh,int s,gdb_wince_id what,WORD n)198*b725ae77Skettenis putword (LPCWSTR huh, int s, gdb_wince_id what, WORD n)
199*b725ae77Skettenis {
200*b725ae77Skettenis   if (sockwrite (huh, s, &what, sizeof (what)) != sizeof (what))
201*b725ae77Skettenis     stub_error (L"error writing record id for %s to host.", huh);
202*b725ae77Skettenis   if (sockwrite (huh, s, &n, sizeof (n)) != sizeof (n))
203*b725ae77Skettenis     stub_error (L"error writing %s to host.", huh);
204*b725ae77Skettenis }
205*b725ae77Skettenis 
206*b725ae77Skettenis /* Convenience define for outputting a "gdb_wince_len" type. */
207*b725ae77Skettenis #define putlen(huh, s, what, n) putword ((huh), (s), (what), (gdb_wince_len) (n))
208*b725ae77Skettenis 
209*b725ae77Skettenis /* Put an arbitrary block of memory to the gdb host.  This comes in
210*b725ae77Skettenis    two chunks an id/dword representing the length and the stream of memory
211*b725ae77Skettenis    itself. */
212*b725ae77Skettenis static void
putmemory(LPCWSTR huh,int s,gdb_wince_id what,const void * mem,gdb_wince_len len)213*b725ae77Skettenis putmemory (LPCWSTR huh, int s, gdb_wince_id what, const void *mem, gdb_wince_len len)
214*b725ae77Skettenis {
215*b725ae77Skettenis   putlen (huh, s, what, len);
216*b725ae77Skettenis   if (((short) len > 0) && (gdb_wince_len) sockwrite (huh, s, mem, len) != len)
217*b725ae77Skettenis     stub_error (L"error writing memory to host.");
218*b725ae77Skettenis }
219*b725ae77Skettenis 
220*b725ae77Skettenis /* Output the result of an operation to the host.  If res != 0, sends a block of
221*b725ae77Skettenis    memory starting at mem of len bytes.  If res == 0, sends -GetLastError () and
222*b725ae77Skettenis    avoids sending the mem. */
223*b725ae77Skettenis static void
putresult(LPCWSTR huh,gdb_wince_result res,int s,gdb_wince_id what,const void * mem,gdb_wince_len len)224*b725ae77Skettenis putresult (LPCWSTR huh, gdb_wince_result res, int s, gdb_wince_id what, const void *mem, gdb_wince_len len)
225*b725ae77Skettenis {
226*b725ae77Skettenis   if (!res)
227*b725ae77Skettenis     len = -(int) GetLastError ();
228*b725ae77Skettenis   putmemory (huh, s, what, mem, len);
229*b725ae77Skettenis }
230*b725ae77Skettenis 
231*b725ae77Skettenis static HANDLE curproc;		/* Currently unused, but nice for debugging */
232*b725ae77Skettenis 
233*b725ae77Skettenis /* Emulate CreateProcess.  Returns &pi if no error. */
234*b725ae77Skettenis static void
create_process(int s)235*b725ae77Skettenis create_process (int s)
236*b725ae77Skettenis {
237*b725ae77Skettenis   LPWSTR exec_file = getmemory (L"CreateProcess exec_file", s, GDB_CREATEPROCESS, NULL);
238*b725ae77Skettenis   LPWSTR args = getmemory (L"CreateProcess args", s, GDB_CREATEPROCESS, NULL);
239*b725ae77Skettenis   DWORD flags = getdword (L"CreateProcess flags", s, GDB_CREATEPROCESS);
240*b725ae77Skettenis   PROCESS_INFORMATION pi;
241*b725ae77Skettenis   gdb_wince_result res;
242*b725ae77Skettenis 
243*b725ae77Skettenis   res = CreateProcessW (exec_file,
244*b725ae77Skettenis 			args,	/* command line */
245*b725ae77Skettenis 			NULL,	/* Security */
246*b725ae77Skettenis 			NULL,	/* thread */
247*b725ae77Skettenis 			FALSE,	/* inherit handles */
248*b725ae77Skettenis 			flags,	/* start flags */
249*b725ae77Skettenis 			NULL,
250*b725ae77Skettenis 			NULL,	/* current directory */
251*b725ae77Skettenis 			NULL,
252*b725ae77Skettenis 			&pi);
253*b725ae77Skettenis   putresult (L"CreateProcess", res, s, GDB_CREATEPROCESS, &pi, sizeof (pi));
254*b725ae77Skettenis   curproc = pi.hProcess;
255*b725ae77Skettenis }
256*b725ae77Skettenis 
257*b725ae77Skettenis /* Emulate TerminateProcess.  Returns return value of TerminateProcess if
258*b725ae77Skettenis    no error.
259*b725ae77Skettenis    *** NOTE:  For some unknown reason, TerminateProcess seems to always return
260*b725ae77Skettenis    an ACCESS_DENIED (on Windows CE???) error.  So, force a TRUE value for now. */
261*b725ae77Skettenis static void
terminate_process(int s)262*b725ae77Skettenis terminate_process (int s)
263*b725ae77Skettenis {
264*b725ae77Skettenis   gdb_wince_result res;
265*b725ae77Skettenis   HANDLE h = gethandle (L"TerminateProcess handle", s, GDB_TERMINATEPROCESS);
266*b725ae77Skettenis 
267*b725ae77Skettenis   res = TerminateProcess (h, 0) || 1;	/* Doesn't seem to work on SH so default to TRUE */
268*b725ae77Skettenis   putresult (L"Terminate process result", res, s, GDB_TERMINATEPROCESS,
269*b725ae77Skettenis 	     &res, sizeof (res));
270*b725ae77Skettenis }
271*b725ae77Skettenis 
272*b725ae77Skettenis static int stepped = 0;
273*b725ae77Skettenis /* Handle single step instruction.  FIXME: unneded? */
274*b725ae77Skettenis static void
flag_single_step(int s)275*b725ae77Skettenis flag_single_step (int s)
276*b725ae77Skettenis {
277*b725ae77Skettenis   stepped = 1;
278*b725ae77Skettenis   skip_next_id = 0;
279*b725ae77Skettenis }
280*b725ae77Skettenis 
281*b725ae77Skettenis struct skipper
282*b725ae77Skettenis {
283*b725ae77Skettenis   wchar_t *s;
284*b725ae77Skettenis   int nskip;
285*b725ae77Skettenis } skippy[] =
286*b725ae77Skettenis {
287*b725ae77Skettenis   {L"Undefined Instruction:", 1},
288*b725ae77Skettenis   {L"Data Abort:", 2},
289*b725ae77Skettenis   {NULL, 0}
290*b725ae77Skettenis };
291*b725ae77Skettenis 
292*b725ae77Skettenis static int
skip_message(DEBUG_EVENT * ev)293*b725ae77Skettenis skip_message (DEBUG_EVENT *ev)
294*b725ae77Skettenis {
295*b725ae77Skettenis   char s[80];
296*b725ae77Skettenis   DWORD nread;
297*b725ae77Skettenis   struct skipper *skp;
298*b725ae77Skettenis   int nbytes = ev->u.DebugString.nDebugStringLength;
299*b725ae77Skettenis 
300*b725ae77Skettenis   if (nbytes > sizeof(s))
301*b725ae77Skettenis     nbytes = sizeof(s);
302*b725ae77Skettenis 
303*b725ae77Skettenis   memset (s, 0, sizeof (s));
304*b725ae77Skettenis   if (!ReadProcessMemory (curproc, ev->u.DebugString.lpDebugStringData,
305*b725ae77Skettenis 			  s, nbytes, &nread))
306*b725ae77Skettenis     return 0;
307*b725ae77Skettenis 
308*b725ae77Skettenis   for (skp = skippy; skp->s != NULL; skp++)
309*b725ae77Skettenis     if (wcsncmp ((wchar_t *) s, skp->s, wcslen (skp->s)) == 0)
310*b725ae77Skettenis       return skp->nskip;
311*b725ae77Skettenis 
312*b725ae77Skettenis   return 0;
313*b725ae77Skettenis }
314*b725ae77Skettenis 
315*b725ae77Skettenis /* Emulate WaitForDebugEvent.  Returns the debug event on success. */
316*b725ae77Skettenis static void
wait_for_debug_event(int s)317*b725ae77Skettenis wait_for_debug_event (int s)
318*b725ae77Skettenis {
319*b725ae77Skettenis   DWORD ms = getdword (L"WaitForDebugEvent ms", s, GDB_WAITFORDEBUGEVENT);
320*b725ae77Skettenis   gdb_wince_result res;
321*b725ae77Skettenis   DEBUG_EVENT ev;
322*b725ae77Skettenis   static int skip_next = 0;
323*b725ae77Skettenis 
324*b725ae77Skettenis   for (;;)
325*b725ae77Skettenis     {
326*b725ae77Skettenis       res = WaitForDebugEvent (&ev, ms);
327*b725ae77Skettenis 
328*b725ae77Skettenis       if (ev.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT)
329*b725ae77Skettenis 	{
330*b725ae77Skettenis 	  if (skip_next)
331*b725ae77Skettenis 	    {
332*b725ae77Skettenis 	      skip_next--;
333*b725ae77Skettenis 	      goto ignore;
334*b725ae77Skettenis 	    }
335*b725ae77Skettenis 	  if (skip_next = skip_message (&ev))
336*b725ae77Skettenis 	    goto ignore;
337*b725ae77Skettenis 	}
338*b725ae77Skettenis 
339*b725ae77Skettenis       putresult (L"WaitForDebugEvent event", res, s, GDB_WAITFORDEBUGEVENT,
340*b725ae77Skettenis 		 &ev, sizeof (ev));
341*b725ae77Skettenis       break;
342*b725ae77Skettenis 
343*b725ae77Skettenis     ignore:
344*b725ae77Skettenis       ContinueDebugEvent (ev.dwProcessId, ev.dwThreadId, DBG_CONTINUE);
345*b725ae77Skettenis     }
346*b725ae77Skettenis 
347*b725ae77Skettenis   return;
348*b725ae77Skettenis }
349*b725ae77Skettenis 
350*b725ae77Skettenis /* Emulate GetThreadContext.  Returns CONTEXT structure on success. */
351*b725ae77Skettenis static void
get_thread_context(int s)352*b725ae77Skettenis get_thread_context (int s)
353*b725ae77Skettenis {
354*b725ae77Skettenis   CONTEXT c;
355*b725ae77Skettenis   HANDLE h = gethandle (L"GetThreadContext handle", s, GDB_GETTHREADCONTEXT);
356*b725ae77Skettenis   gdb_wince_result res;
357*b725ae77Skettenis 
358*b725ae77Skettenis   memset (&c, 0, sizeof (c));
359*b725ae77Skettenis   c.ContextFlags = getdword (L"GetThreadContext flags", s, GDB_GETTHREADCONTEXT);
360*b725ae77Skettenis 
361*b725ae77Skettenis   res = (gdb_wince_result) GetThreadContext (h, &c);
362*b725ae77Skettenis   putresult (L"GetThreadContext data", res, s, GDB_GETTHREADCONTEXT,
363*b725ae77Skettenis 	     &c, sizeof (c));
364*b725ae77Skettenis }
365*b725ae77Skettenis 
366*b725ae77Skettenis /* Emulate GetThreadContext.  Returns success of SetThreadContext. */
367*b725ae77Skettenis static void
set_thread_context(int s)368*b725ae77Skettenis set_thread_context (int s)
369*b725ae77Skettenis {
370*b725ae77Skettenis   gdb_wince_result res;
371*b725ae77Skettenis   HANDLE h = gethandle (L"SetThreadContext handle", s, GDB_SETTHREADCONTEXT);
372*b725ae77Skettenis   LPCONTEXT pc = (LPCONTEXT) getmemory (L"SetThreadContext context", s,
373*b725ae77Skettenis 					GDB_SETTHREADCONTEXT, NULL);
374*b725ae77Skettenis 
375*b725ae77Skettenis   res = SetThreadContext (h, pc);
376*b725ae77Skettenis   putresult (L"SetThreadContext result", res, s, GDB_SETTHREADCONTEXT,
377*b725ae77Skettenis 	     &res, sizeof (res));
378*b725ae77Skettenis }
379*b725ae77Skettenis 
380*b725ae77Skettenis /* Emulate ReadProcessMemory.  Returns memory read on success. */
381*b725ae77Skettenis static void
read_process_memory(int s)382*b725ae77Skettenis read_process_memory (int s)
383*b725ae77Skettenis {
384*b725ae77Skettenis   HANDLE h = gethandle (L"ReadProcessMemory handle", s, GDB_READPROCESSMEMORY);
385*b725ae77Skettenis   LPVOID p = getpvoid (L"ReadProcessMemory base", s, GDB_READPROCESSMEMORY);
386*b725ae77Skettenis   gdb_wince_len len = getlen (L"ReadProcessMemory size", s, GDB_READPROCESSMEMORY);
387*b725ae77Skettenis   LPVOID buf = mempool ((unsigned int) len);
388*b725ae77Skettenis   DWORD outlen;
389*b725ae77Skettenis   gdb_wince_result res;
390*b725ae77Skettenis 
391*b725ae77Skettenis   outlen = 0;
392*b725ae77Skettenis   res = (gdb_wince_result) ReadProcessMemory (h, p, buf, len, &outlen);
393*b725ae77Skettenis   putresult (L"ReadProcessMemory data", res, s, GDB_READPROCESSMEMORY,
394*b725ae77Skettenis 	     buf, (gdb_wince_len) outlen);
395*b725ae77Skettenis }
396*b725ae77Skettenis 
397*b725ae77Skettenis /* Emulate WriteProcessMemory.  Returns WriteProcessMemory success. */
398*b725ae77Skettenis static void
write_process_memory(int s)399*b725ae77Skettenis write_process_memory (int s)
400*b725ae77Skettenis {
401*b725ae77Skettenis   HANDLE h = gethandle (L"WriteProcessMemory handle", s, GDB_WRITEPROCESSMEMORY);
402*b725ae77Skettenis   LPVOID p = getpvoid (L"WriteProcessMemory base", s, GDB_WRITEPROCESSMEMORY);
403*b725ae77Skettenis   gdb_wince_len len;
404*b725ae77Skettenis   LPVOID buf = getmemory (L"WriteProcessMemory buf", s, GDB_WRITEPROCESSMEMORY, &len);
405*b725ae77Skettenis   DWORD outlen;
406*b725ae77Skettenis   gdb_wince_result res;
407*b725ae77Skettenis 
408*b725ae77Skettenis   outlen = 0;
409*b725ae77Skettenis   res = WriteProcessMemory (h, p, buf, (DWORD) len, &outlen);
410*b725ae77Skettenis   putresult (L"WriteProcessMemory data", res, s, GDB_WRITEPROCESSMEMORY,
411*b725ae77Skettenis 	     (gdb_wince_len *) & outlen, sizeof (gdb_wince_len));
412*b725ae77Skettenis }
413*b725ae77Skettenis 
414*b725ae77Skettenis /* Return non-zero to gdb host if given thread is alive. */
415*b725ae77Skettenis static void
thread_alive(int s)416*b725ae77Skettenis thread_alive (int s)
417*b725ae77Skettenis {
418*b725ae77Skettenis   HANDLE h = gethandle (L"ThreadAlive handle", s, GDB_THREADALIVE);
419*b725ae77Skettenis   gdb_wince_result res;
420*b725ae77Skettenis 
421*b725ae77Skettenis   res = WaitForSingleObject (h, 0) == WAIT_OBJECT_0 ? 1 : 0;
422*b725ae77Skettenis   putresult (L"WriteProcessMemory data", res, s, GDB_THREADALIVE,
423*b725ae77Skettenis 	     &res, sizeof (res));
424*b725ae77Skettenis }
425*b725ae77Skettenis 
426*b725ae77Skettenis /* Emulate SuspendThread.  Returns value returned from SuspendThread. */
427*b725ae77Skettenis static void
suspend_thread(int s)428*b725ae77Skettenis suspend_thread (int s)
429*b725ae77Skettenis {
430*b725ae77Skettenis   DWORD res;
431*b725ae77Skettenis   HANDLE h = gethandle (L"SuspendThread handle", s, GDB_SUSPENDTHREAD);
432*b725ae77Skettenis   res = SuspendThread (h);
433*b725ae77Skettenis   putdword (L"SuspendThread result", s, GDB_SUSPENDTHREAD, res);
434*b725ae77Skettenis }
435*b725ae77Skettenis 
436*b725ae77Skettenis /* Emulate ResumeThread.  Returns value returned from ResumeThread. */
437*b725ae77Skettenis static void
resume_thread(int s)438*b725ae77Skettenis resume_thread (int s)
439*b725ae77Skettenis {
440*b725ae77Skettenis   DWORD res;
441*b725ae77Skettenis   HANDLE h = gethandle (L"ResumeThread handle", s, GDB_RESUMETHREAD);
442*b725ae77Skettenis   res = ResumeThread (h);
443*b725ae77Skettenis   putdword (L"ResumeThread result", s, GDB_RESUMETHREAD, res);
444*b725ae77Skettenis }
445*b725ae77Skettenis 
446*b725ae77Skettenis /* Emulate ContinueDebugEvent.  Returns ContinueDebugEvent success. */
447*b725ae77Skettenis static void
continue_debug_event(int s)448*b725ae77Skettenis continue_debug_event (int s)
449*b725ae77Skettenis {
450*b725ae77Skettenis   gdb_wince_result res;
451*b725ae77Skettenis   DWORD pid = getdword (L"ContinueDebugEvent pid", s, GDB_CONTINUEDEBUGEVENT);
452*b725ae77Skettenis   DWORD tid = getdword (L"ContinueDebugEvent tid", s, GDB_CONTINUEDEBUGEVENT);
453*b725ae77Skettenis   DWORD status = getdword (L"ContinueDebugEvent status", s, GDB_CONTINUEDEBUGEVENT);
454*b725ae77Skettenis   res = (gdb_wince_result) ContinueDebugEvent (pid, tid, status);
455*b725ae77Skettenis   putresult (L"ContinueDebugEvent result", res, s, GDB_CONTINUEDEBUGEVENT, &res, sizeof (res));
456*b725ae77Skettenis }
457*b725ae77Skettenis 
458*b725ae77Skettenis /* Emulate CloseHandle.  Returns CloseHandle success. */
459*b725ae77Skettenis static void
close_handle(int s)460*b725ae77Skettenis close_handle (int s)
461*b725ae77Skettenis {
462*b725ae77Skettenis   gdb_wince_result res;
463*b725ae77Skettenis   HANDLE h = gethandle (L"CloseHandle handle", s, GDB_CLOSEHANDLE);
464*b725ae77Skettenis   res = (gdb_wince_result) CloseHandle (h);
465*b725ae77Skettenis   putresult (L"CloseHandle result", res, s, GDB_CLOSEHANDLE, &res, sizeof (res));
466*b725ae77Skettenis }
467*b725ae77Skettenis 
468*b725ae77Skettenis /* Main loop for reading requests from gdb host on the socket. */
469*b725ae77Skettenis static void
dispatch(int s)470*b725ae77Skettenis dispatch (int s)
471*b725ae77Skettenis {
472*b725ae77Skettenis   gdb_wince_id id;
473*b725ae77Skettenis 
474*b725ae77Skettenis   /* Continue reading from socket until receive a GDB_STOPSUB. */
475*b725ae77Skettenis   while (sockread (L"Dispatch", s, &id, sizeof (id)) > 0)
476*b725ae77Skettenis     {
477*b725ae77Skettenis       skip_next_id = 1;
478*b725ae77Skettenis       switch (id)
479*b725ae77Skettenis 	{
480*b725ae77Skettenis 	case GDB_CREATEPROCESS:
481*b725ae77Skettenis 	  create_process (s);
482*b725ae77Skettenis 	  break;
483*b725ae77Skettenis 	case GDB_TERMINATEPROCESS:
484*b725ae77Skettenis 	  terminate_process (s);
485*b725ae77Skettenis 	  break;
486*b725ae77Skettenis 	case GDB_WAITFORDEBUGEVENT:
487*b725ae77Skettenis 	  wait_for_debug_event (s);
488*b725ae77Skettenis 	  break;
489*b725ae77Skettenis 	case GDB_GETTHREADCONTEXT:
490*b725ae77Skettenis 	  get_thread_context (s);
491*b725ae77Skettenis 	  break;
492*b725ae77Skettenis 	case GDB_SETTHREADCONTEXT:
493*b725ae77Skettenis 	  set_thread_context (s);
494*b725ae77Skettenis 	  break;
495*b725ae77Skettenis 	case GDB_READPROCESSMEMORY:
496*b725ae77Skettenis 	  read_process_memory (s);
497*b725ae77Skettenis 	  break;
498*b725ae77Skettenis 	case GDB_WRITEPROCESSMEMORY:
499*b725ae77Skettenis 	  write_process_memory (s);
500*b725ae77Skettenis 	  break;
501*b725ae77Skettenis 	case GDB_THREADALIVE:
502*b725ae77Skettenis 	  thread_alive (s);
503*b725ae77Skettenis 	  break;
504*b725ae77Skettenis 	case GDB_SUSPENDTHREAD:
505*b725ae77Skettenis 	  suspend_thread (s);
506*b725ae77Skettenis 	  break;
507*b725ae77Skettenis 	case GDB_RESUMETHREAD:
508*b725ae77Skettenis 	  resume_thread (s);
509*b725ae77Skettenis 	  break;
510*b725ae77Skettenis 	case GDB_CONTINUEDEBUGEVENT:
511*b725ae77Skettenis 	  continue_debug_event (s);
512*b725ae77Skettenis 	  break;
513*b725ae77Skettenis 	case GDB_CLOSEHANDLE:
514*b725ae77Skettenis 	  close_handle (s);
515*b725ae77Skettenis 	  break;
516*b725ae77Skettenis 	case GDB_STOPSTUB:
517*b725ae77Skettenis 	  terminate_process (s);
518*b725ae77Skettenis 	  return;
519*b725ae77Skettenis 	case GDB_SINGLESTEP:
520*b725ae77Skettenis 	  flag_single_step (s);
521*b725ae77Skettenis 	  break;
522*b725ae77Skettenis 	default:
523*b725ae77Skettenis 	  {
524*b725ae77Skettenis 	    WCHAR buf[80];
525*b725ae77Skettenis 	    wsprintfW (buf, L"Invalid command id received: %d", id);
526*b725ae77Skettenis 	    MessageBoxW (NULL, buf, L"GDB", MB_ICONERROR);
527*b725ae77Skettenis 	    skip_next_id = 0;
528*b725ae77Skettenis 	  }
529*b725ae77Skettenis 	}
530*b725ae77Skettenis     }
531*b725ae77Skettenis }
532*b725ae77Skettenis 
533*b725ae77Skettenis /* The Windows Main entry point */
534*b725ae77Skettenis int WINAPI
WinMain(HINSTANCE hi,HINSTANCE hp,LPWSTR cmd,int show)535*b725ae77Skettenis WinMain (HINSTANCE hi, HINSTANCE hp, LPWSTR cmd, int show)
536*b725ae77Skettenis {
537*b725ae77Skettenis   struct hostent *h;
538*b725ae77Skettenis   int s;
539*b725ae77Skettenis   struct WSAData wd;
540*b725ae77Skettenis   struct sockaddr_in sin;
541*b725ae77Skettenis   int tmp;
542*b725ae77Skettenis   LPWSTR whost;
543*b725ae77Skettenis   char host[80];
544*b725ae77Skettenis 
545*b725ae77Skettenis   whost = wcschr (cmd, L' ');	/* Look for argument. */
546*b725ae77Skettenis 
547*b725ae77Skettenis   /* If no host is specified, just use default */
548*b725ae77Skettenis   if (whost)
549*b725ae77Skettenis     {
550*b725ae77Skettenis       /* Eat any spaces. */
551*b725ae77Skettenis       while (*whost == L' ' || *whost == L'\t')
552*b725ae77Skettenis 	whost++;
553*b725ae77Skettenis 
554*b725ae77Skettenis       wcstombs (host, whost, 80);	/* Convert from UNICODE to ascii */
555*b725ae77Skettenis     }
556*b725ae77Skettenis 
557*b725ae77Skettenis   /* Winsock initialization. */
558*b725ae77Skettenis   if (WSAStartup (MAKEWORD (1, 1), &wd))
559*b725ae77Skettenis     stub_error (L"Couldn't initialize WINSOCK.");
560*b725ae77Skettenis 
561*b725ae77Skettenis   /* If whost was specified, first try it.  If it was not specified or the
562*b725ae77Skettenis      host lookup failed, try the Windows CE magic ppp_peer lookup.  ppp_peer
563*b725ae77Skettenis      is supposed to be the Windows host sitting on the other end of the
564*b725ae77Skettenis      serial cable. */
565*b725ae77Skettenis   if (whost && *whost && (h = gethostbyname (host)) != NULL)
566*b725ae77Skettenis     /* nothing to do */ ;
567*b725ae77Skettenis   else if ((h = gethostbyname ("ppp_peer")) == NULL)
568*b725ae77Skettenis     stub_error (L"Couldn't get IP address of host system.  Error %d", WSAGetLastError ());
569*b725ae77Skettenis 
570*b725ae77Skettenis   /* Get a socket. */
571*b725ae77Skettenis   if ((s = socket (AF_INET, SOCK_STREAM, 0)) < 0)
572*b725ae77Skettenis     stub_error (L"Couldn't connect to host system. Error %d", WSAGetLastError ());
573*b725ae77Skettenis 
574*b725ae77Skettenis   /* Allow rapid reuse of the port. */
575*b725ae77Skettenis   tmp = 1;
576*b725ae77Skettenis   setsockopt (s, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp, sizeof (tmp));
577*b725ae77Skettenis 
578*b725ae77Skettenis   /* Set up the information for connecting to the host gdb process. */
579*b725ae77Skettenis   memset (&sin, 0, sizeof (sin));
580*b725ae77Skettenis   sin.sin_family = h->h_addrtype;
581*b725ae77Skettenis   memcpy (&sin.sin_addr, h->h_addr, h->h_length);
582*b725ae77Skettenis   sin.sin_port = htons (7000);	/* FIXME: This should be configurable */
583*b725ae77Skettenis 
584*b725ae77Skettenis   /* Connect to host */
585*b725ae77Skettenis   if (connect (s, (struct sockaddr *) &sin, sizeof (sin)) < 0)
586*b725ae77Skettenis     stub_error (L"Couldn't connect to host gdb.");
587*b725ae77Skettenis 
588*b725ae77Skettenis   /* Read from socket until told to exit. */
589*b725ae77Skettenis   dispatch (s);
590*b725ae77Skettenis   WSACleanup ();
591*b725ae77Skettenis   return 0;
592*b725ae77Skettenis }
593