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