1130803Smarcel/* wince-stub.c -- debugging stub for a Windows CE device
2130803Smarcel
3130803Smarcel   Copyright 1999, 2000 Free Software Foundation, Inc.
4130803Smarcel   Contributed by Cygnus Solutions, A Red Hat Company.
5130803Smarcel
6130803Smarcel   This file is part of GDB.
7130803Smarcel
8130803Smarcel   This program is free software; you can redistribute it and/or modify
9130803Smarcel   it under the terms of the GNU General Public License as published by
10130803Smarcel   the Free Software Foundation; either version 2 of the License, or
11130803Smarcel   (at your option) any later version.
12130803Smarcel
13130803Smarcel   This program is distributed in the hope that it will be useful,
14130803Smarcel   but WITHOUT ANY WARRANTY; without eve nthe implied warranty of
15130803Smarcel   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16130803Smarcel   GNU General Public License for more details.
17130803Smarcel
18130803Smarcel   You should have received a copy of the GNU General Public License
19130803Smarcel   along with this program; if not, write to the Free Software
20130803Smarcel   Foundation, Inc., 59 Temple Place - Suite 330,
21130803Smarcel   Boston, MA 02111-1307, USA.
22130803Smarcel */
23130803Smarcel
24130803Smarcel/* by Christopher Faylor (cgf@cygnus.com) */
25130803Smarcel
26130803Smarcel#include <stdarg.h>
27130803Smarcel#include <windows.h>
28130803Smarcel#include <winsock.h>
29130803Smarcel#include "wince-stub.h"
30130803Smarcel
31130803Smarcel#define MALLOC(n) (void *) LocalAlloc (LMEM_MOVEABLE | LMEM_ZEROINIT, (UINT)(n))
32130803Smarcel#define REALLOC(s, n) (void *) LocalReAlloc ((HLOCAL)(s), (UINT)(n), LMEM_MOVEABLE)
33130803Smarcel#define FREE(s) LocalFree ((HLOCAL)(s))
34130803Smarcel
35130803Smarcelstatic int skip_next_id = 0;	/* Don't read next API code from socket */
36130803Smarcel
37130803Smarcel/* v-style interface for handling varying argument list error messages.
38130803Smarcel   Displays the error message in a dialog box and exits when user clicks
39130803Smarcel   on OK. */
40130803Smarcelstatic void
41130803Smarcelvstub_error (LPCWSTR fmt, va_list args)
42130803Smarcel{
43130803Smarcel  WCHAR buf[4096];
44130803Smarcel  wvsprintfW (buf, fmt, args);
45130803Smarcel
46130803Smarcel  MessageBoxW (NULL, buf, L"GDB", MB_ICONERROR);
47130803Smarcel  WSACleanup ();
48130803Smarcel  ExitThread (1);
49130803Smarcel}
50130803Smarcel
51130803Smarcel/* The standard way to display an error message and exit. */
52130803Smarcelstatic void
53130803Smarcelstub_error (LPCWSTR fmt, ...)
54130803Smarcel{
55130803Smarcel  va_list args;
56130803Smarcel  va_start (args, fmt);
57130803Smarcel  vstub_error (fmt, args);
58130803Smarcel}
59130803Smarcel
60130803Smarcel/* Allocate a limited pool of memory, reallocating over unused
61130803Smarcel   buffers.  This assumes that there will never be more than four
62130803Smarcel   "buffers" required which, so far, is a safe assumption. */
63130803Smarcelstatic LPVOID
64130803Smarcelmempool (unsigned int len)
65130803Smarcel{
66130803Smarcel  static int outn = -1;
67130803Smarcel  static LPWSTR outs[4] = {NULL, NULL, NULL, NULL};
68130803Smarcel
69130803Smarcel  if (++outn >= (sizeof (outs) / sizeof (outs[0])))
70130803Smarcel    outn = 0;
71130803Smarcel
72130803Smarcel  /* Allocate space for the converted string, reusing any previously allocated
73130803Smarcel     space, if applicable. */
74130803Smarcel  if (outs[outn])
75130803Smarcel    FREE (outs[outn]);
76130803Smarcel  outs[outn] = (LPWSTR) MALLOC (len);
77130803Smarcel
78130803Smarcel  return outs[outn];
79130803Smarcel}
80130803Smarcel
81130803Smarcel/* Standard "oh well" can't communicate error.  Someday this might attempt
82130803Smarcel   synchronization. */
83130803Smarcelstatic void
84130803Smarcelattempt_resync (LPCWSTR huh, int s)
85130803Smarcel{
86130803Smarcel  stub_error (L"lost synchronization with host attempting %s.  Error %d", huh, WSAGetLastError ());
87130803Smarcel}
88130803Smarcel
89130803Smarcel/* Read arbitrary stuff from a socket. */
90130803Smarcelstatic int
91130803Smarcelsockread (LPCWSTR huh, int s, void *str, size_t n)
92130803Smarcel{
93130803Smarcel  for (;;)
94130803Smarcel    {
95130803Smarcel      if (recv (s, str, n, 0) == (int) n)
96130803Smarcel	return n;
97130803Smarcel      attempt_resync (huh, s);
98130803Smarcel    }
99130803Smarcel}
100130803Smarcel
101130803Smarcel/* Write arbitrary stuff to a socket. */
102130803Smarcelstatic int
103130803Smarcelsockwrite (LPCWSTR huh, int s, const void *str, size_t n)
104130803Smarcel{
105130803Smarcel  for (;;)
106130803Smarcel    {
107130803Smarcel      if (send (s, str, n, 0) == (int) n)
108130803Smarcel	return n;
109130803Smarcel      attempt_resync (huh, s);
110130803Smarcel    }
111130803Smarcel}
112130803Smarcel
113130803Smarcel/* Get a an ID (possibly) and a DWORD from the host gdb.
114130803Smarcel   Don't bother with the id if the main loop has already
115130803Smarcel   read it. */
116130803Smarcelstatic DWORD
117130803Smarcelgetdword (LPCWSTR huh, int s, gdb_wince_id what_this)
118130803Smarcel{
119130803Smarcel  DWORD n;
120130803Smarcel  gdb_wince_id what;
121130803Smarcel
122130803Smarcel  if (skip_next_id)
123130803Smarcel    skip_next_id = 0;
124130803Smarcel  else
125130803Smarcel    do
126130803Smarcel      if (sockread (huh, s, &what, sizeof (what)) != sizeof (what))
127130803Smarcel	stub_error (L"error getting record type from host - %s.", huh);
128130803Smarcel    while (what_this != what);
129130803Smarcel
130130803Smarcel  if (sockread (huh, s, &n, sizeof (n)) != sizeof (n))
131130803Smarcel    stub_error (L"error getting %s from host.", huh);
132130803Smarcel
133130803Smarcel  return n;
134130803Smarcel}
135130803Smarcel
136130803Smarcel/* Get a an ID (possibly) and a WORD from the host gdb.
137130803Smarcel   Don't bother with the id if the main loop has already
138130803Smarcel   read it. */
139130803Smarcelstatic WORD
140130803Smarcelgetword (LPCWSTR huh, int s, gdb_wince_id what_this)
141130803Smarcel{
142130803Smarcel  WORD n;
143130803Smarcel  gdb_wince_id what;
144130803Smarcel
145130803Smarcel  if (skip_next_id)
146130803Smarcel    skip_next_id = 0;
147130803Smarcel  else
148130803Smarcel    do
149130803Smarcel      if (sockread (huh, s, &what, sizeof (what)) != sizeof (what))
150130803Smarcel	stub_error (L"error getting record type from host - %s.", huh);
151130803Smarcel    while (what_this != what);
152130803Smarcel
153130803Smarcel  if (sockread (huh, s, &n, sizeof (n)) != sizeof (n))
154130803Smarcel    stub_error (L"error getting %s from host.", huh);
155130803Smarcel
156130803Smarcel  return n;
157130803Smarcel}
158130803Smarcel
159130803Smarcel/* Handy defines for getting various types of values. */
160130803Smarcel#define gethandle(huh, s, what) (HANDLE) getdword ((huh), (s), (what))
161130803Smarcel#define getpvoid(huh, s, what) (LPVOID) getdword ((huh), (s), (what))
162130803Smarcel#define getlen(huh, s, what) (gdb_wince_len) getword ((huh), (s), (what))
163130803Smarcel
164130803Smarcel/* Get an arbitrary block of memory from the gdb host.  This comes in
165130803Smarcel   two chunks an id/dword representing the length and the stream of memory
166130803Smarcel   itself. Returns a pointer, allocated via mempool, to a memory buffer. */
167130803Smarcelstatic LPWSTR
168130803Smarcelgetmemory (LPCWSTR huh, int s, gdb_wince_id what, gdb_wince_len *inlen)
169130803Smarcel{
170130803Smarcel  LPVOID p;
171130803Smarcel  gdb_wince_len dummy;
172130803Smarcel
173130803Smarcel  if (!inlen)
174130803Smarcel    inlen = &dummy;
175130803Smarcel
176130803Smarcel  *inlen = getlen (huh, s, what);
177130803Smarcel
178130803Smarcel  p = mempool ((unsigned int) *inlen);	/* FIXME: check for error */
179130803Smarcel
180130803Smarcel  if ((gdb_wince_len) sockread (huh, s, p, *inlen) != *inlen)
181130803Smarcel    stub_error (L"error getting string from host.");
182130803Smarcel
183130803Smarcel  return p;
184130803Smarcel}
185130803Smarcel
186130803Smarcel/* Output an id/dword to the host */
187130803Smarcelstatic void
188130803Smarcelputdword (LPCWSTR huh, int s, gdb_wince_id what, DWORD n)
189130803Smarcel{
190130803Smarcel  if (sockwrite (huh, s, &what, sizeof (what)) != sizeof (what))
191130803Smarcel    stub_error (L"error writing record id for %s to host.", huh);
192130803Smarcel  if (sockwrite (huh, s, &n, sizeof (n)) != sizeof (n))
193130803Smarcel    stub_error (L"error writing %s to host.", huh);
194130803Smarcel}
195130803Smarcel
196130803Smarcel/* Output an id/word to the host */
197130803Smarcelstatic void
198130803Smarcelputword (LPCWSTR huh, int s, gdb_wince_id what, WORD n)
199130803Smarcel{
200130803Smarcel  if (sockwrite (huh, s, &what, sizeof (what)) != sizeof (what))
201130803Smarcel    stub_error (L"error writing record id for %s to host.", huh);
202130803Smarcel  if (sockwrite (huh, s, &n, sizeof (n)) != sizeof (n))
203130803Smarcel    stub_error (L"error writing %s to host.", huh);
204130803Smarcel}
205130803Smarcel
206130803Smarcel/* Convenience define for outputting a "gdb_wince_len" type. */
207130803Smarcel#define putlen(huh, s, what, n) putword ((huh), (s), (what), (gdb_wince_len) (n))
208130803Smarcel
209130803Smarcel/* Put an arbitrary block of memory to the gdb host.  This comes in
210130803Smarcel   two chunks an id/dword representing the length and the stream of memory
211130803Smarcel   itself. */
212130803Smarcelstatic void
213130803Smarcelputmemory (LPCWSTR huh, int s, gdb_wince_id what, const void *mem, gdb_wince_len len)
214130803Smarcel{
215130803Smarcel  putlen (huh, s, what, len);
216130803Smarcel  if (((short) len > 0) && (gdb_wince_len) sockwrite (huh, s, mem, len) != len)
217130803Smarcel    stub_error (L"error writing memory to host.");
218130803Smarcel}
219130803Smarcel
220130803Smarcel/* Output the result of an operation to the host.  If res != 0, sends a block of
221130803Smarcel   memory starting at mem of len bytes.  If res == 0, sends -GetLastError () and
222130803Smarcel   avoids sending the mem. */
223130803Smarcelstatic void
224130803Smarcelputresult (LPCWSTR huh, gdb_wince_result res, int s, gdb_wince_id what, const void *mem, gdb_wince_len len)
225130803Smarcel{
226130803Smarcel  if (!res)
227130803Smarcel    len = -(int) GetLastError ();
228130803Smarcel  putmemory (huh, s, what, mem, len);
229130803Smarcel}
230130803Smarcel
231130803Smarcelstatic HANDLE curproc;		/* Currently unused, but nice for debugging */
232130803Smarcel
233130803Smarcel/* Emulate CreateProcess.  Returns &pi if no error. */
234130803Smarcelstatic void
235130803Smarcelcreate_process (int s)
236130803Smarcel{
237130803Smarcel  LPWSTR exec_file = getmemory (L"CreateProcess exec_file", s, GDB_CREATEPROCESS, NULL);
238130803Smarcel  LPWSTR args = getmemory (L"CreateProcess args", s, GDB_CREATEPROCESS, NULL);
239130803Smarcel  DWORD flags = getdword (L"CreateProcess flags", s, GDB_CREATEPROCESS);
240130803Smarcel  PROCESS_INFORMATION pi;
241130803Smarcel  gdb_wince_result res;
242130803Smarcel
243130803Smarcel  res = CreateProcessW (exec_file,
244130803Smarcel			args,	/* command line */
245130803Smarcel			NULL,	/* Security */
246130803Smarcel			NULL,	/* thread */
247130803Smarcel			FALSE,	/* inherit handles */
248130803Smarcel			flags,	/* start flags */
249130803Smarcel			NULL,
250130803Smarcel			NULL,	/* current directory */
251130803Smarcel			NULL,
252130803Smarcel			&pi);
253130803Smarcel  putresult (L"CreateProcess", res, s, GDB_CREATEPROCESS, &pi, sizeof (pi));
254130803Smarcel  curproc = pi.hProcess;
255130803Smarcel}
256130803Smarcel
257130803Smarcel/* Emulate TerminateProcess.  Returns return value of TerminateProcess if
258130803Smarcel   no error.
259130803Smarcel   *** NOTE:  For some unknown reason, TerminateProcess seems to always return
260130803Smarcel   an ACCESS_DENIED (on Windows CE???) error.  So, force a TRUE value for now. */
261130803Smarcelstatic void
262130803Smarcelterminate_process (int s)
263130803Smarcel{
264130803Smarcel  gdb_wince_result res;
265130803Smarcel  HANDLE h = gethandle (L"TerminateProcess handle", s, GDB_TERMINATEPROCESS);
266130803Smarcel
267130803Smarcel  res = TerminateProcess (h, 0) || 1;	/* Doesn't seem to work on SH so default to TRUE */
268130803Smarcel  putresult (L"Terminate process result", res, s, GDB_TERMINATEPROCESS,
269130803Smarcel	     &res, sizeof (res));
270130803Smarcel}
271130803Smarcel
272130803Smarcelstatic int stepped = 0;
273130803Smarcel/* Handle single step instruction.  FIXME: unneded? */
274130803Smarcelstatic void
275130803Smarcelflag_single_step (int s)
276130803Smarcel{
277130803Smarcel  stepped = 1;
278130803Smarcel  skip_next_id = 0;
279130803Smarcel}
280130803Smarcel
281130803Smarcelstruct skipper
282130803Smarcel{
283130803Smarcel  wchar_t *s;
284130803Smarcel  int nskip;
285130803Smarcel} skippy[] =
286130803Smarcel{
287130803Smarcel  {L"Undefined Instruction:", 1},
288130803Smarcel  {L"Data Abort:", 2},
289130803Smarcel  {NULL, 0}
290130803Smarcel};
291130803Smarcel
292130803Smarcelstatic int
293130803Smarcelskip_message (DEBUG_EVENT *ev)
294130803Smarcel{
295130803Smarcel  char s[80];
296130803Smarcel  DWORD nread;
297130803Smarcel  struct skipper *skp;
298130803Smarcel  int nbytes = ev->u.DebugString.nDebugStringLength;
299130803Smarcel
300130803Smarcel  if (nbytes > sizeof(s))
301130803Smarcel    nbytes = sizeof(s);
302130803Smarcel
303130803Smarcel  memset (s, 0, sizeof (s));
304130803Smarcel  if (!ReadProcessMemory (curproc, ev->u.DebugString.lpDebugStringData,
305130803Smarcel			  s, nbytes, &nread))
306130803Smarcel    return 0;
307130803Smarcel
308130803Smarcel  for (skp = skippy; skp->s != NULL; skp++)
309130803Smarcel    if (wcsncmp ((wchar_t *) s, skp->s, wcslen (skp->s)) == 0)
310130803Smarcel      return skp->nskip;
311130803Smarcel
312130803Smarcel  return 0;
313130803Smarcel}
314130803Smarcel
315130803Smarcel/* Emulate WaitForDebugEvent.  Returns the debug event on success. */
316130803Smarcelstatic void
317130803Smarcelwait_for_debug_event (int s)
318130803Smarcel{
319130803Smarcel  DWORD ms = getdword (L"WaitForDebugEvent ms", s, GDB_WAITFORDEBUGEVENT);
320130803Smarcel  gdb_wince_result res;
321130803Smarcel  DEBUG_EVENT ev;
322130803Smarcel  static int skip_next = 0;
323130803Smarcel
324130803Smarcel  for (;;)
325130803Smarcel    {
326130803Smarcel      res = WaitForDebugEvent (&ev, ms);
327130803Smarcel
328130803Smarcel      if (ev.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT)
329130803Smarcel	{
330130803Smarcel	  if (skip_next)
331130803Smarcel	    {
332130803Smarcel	      skip_next--;
333130803Smarcel	      goto ignore;
334130803Smarcel	    }
335130803Smarcel	  if (skip_next = skip_message (&ev))
336130803Smarcel	    goto ignore;
337130803Smarcel	}
338130803Smarcel
339130803Smarcel      putresult (L"WaitForDebugEvent event", res, s, GDB_WAITFORDEBUGEVENT,
340130803Smarcel		 &ev, sizeof (ev));
341130803Smarcel      break;
342130803Smarcel
343130803Smarcel    ignore:
344130803Smarcel      ContinueDebugEvent (ev.dwProcessId, ev.dwThreadId, DBG_CONTINUE);
345130803Smarcel    }
346130803Smarcel
347130803Smarcel  return;
348130803Smarcel}
349130803Smarcel
350130803Smarcel/* Emulate GetThreadContext.  Returns CONTEXT structure on success. */
351130803Smarcelstatic void
352130803Smarcelget_thread_context (int s)
353130803Smarcel{
354130803Smarcel  CONTEXT c;
355130803Smarcel  HANDLE h = gethandle (L"GetThreadContext handle", s, GDB_GETTHREADCONTEXT);
356130803Smarcel  gdb_wince_result res;
357130803Smarcel
358130803Smarcel  memset (&c, 0, sizeof (c));
359130803Smarcel  c.ContextFlags = getdword (L"GetThreadContext flags", s, GDB_GETTHREADCONTEXT);
360130803Smarcel
361130803Smarcel  res = (gdb_wince_result) GetThreadContext (h, &c);
362130803Smarcel  putresult (L"GetThreadContext data", res, s, GDB_GETTHREADCONTEXT,
363130803Smarcel	     &c, sizeof (c));
364130803Smarcel}
365130803Smarcel
366130803Smarcel/* Emulate GetThreadContext.  Returns success of SetThreadContext. */
367130803Smarcelstatic void
368130803Smarcelset_thread_context (int s)
369130803Smarcel{
370130803Smarcel  gdb_wince_result res;
371130803Smarcel  HANDLE h = gethandle (L"SetThreadContext handle", s, GDB_SETTHREADCONTEXT);
372130803Smarcel  LPCONTEXT pc = (LPCONTEXT) getmemory (L"SetThreadContext context", s,
373130803Smarcel					GDB_SETTHREADCONTEXT, NULL);
374130803Smarcel
375130803Smarcel  res = SetThreadContext (h, pc);
376130803Smarcel  putresult (L"SetThreadContext result", res, s, GDB_SETTHREADCONTEXT,
377130803Smarcel	     &res, sizeof (res));
378130803Smarcel}
379130803Smarcel
380130803Smarcel/* Emulate ReadProcessMemory.  Returns memory read on success. */
381130803Smarcelstatic void
382130803Smarcelread_process_memory (int s)
383130803Smarcel{
384130803Smarcel  HANDLE h = gethandle (L"ReadProcessMemory handle", s, GDB_READPROCESSMEMORY);
385130803Smarcel  LPVOID p = getpvoid (L"ReadProcessMemory base", s, GDB_READPROCESSMEMORY);
386130803Smarcel  gdb_wince_len len = getlen (L"ReadProcessMemory size", s, GDB_READPROCESSMEMORY);
387130803Smarcel  LPVOID buf = mempool ((unsigned int) len);
388130803Smarcel  DWORD outlen;
389130803Smarcel  gdb_wince_result res;
390130803Smarcel
391130803Smarcel  outlen = 0;
392130803Smarcel  res = (gdb_wince_result) ReadProcessMemory (h, p, buf, len, &outlen);
393130803Smarcel  putresult (L"ReadProcessMemory data", res, s, GDB_READPROCESSMEMORY,
394130803Smarcel	     buf, (gdb_wince_len) outlen);
395130803Smarcel}
396130803Smarcel
397130803Smarcel/* Emulate WriteProcessMemory.  Returns WriteProcessMemory success. */
398130803Smarcelstatic void
399130803Smarcelwrite_process_memory (int s)
400130803Smarcel{
401130803Smarcel  HANDLE h = gethandle (L"WriteProcessMemory handle", s, GDB_WRITEPROCESSMEMORY);
402130803Smarcel  LPVOID p = getpvoid (L"WriteProcessMemory base", s, GDB_WRITEPROCESSMEMORY);
403130803Smarcel  gdb_wince_len len;
404130803Smarcel  LPVOID buf = getmemory (L"WriteProcessMemory buf", s, GDB_WRITEPROCESSMEMORY, &len);
405130803Smarcel  DWORD outlen;
406130803Smarcel  gdb_wince_result res;
407130803Smarcel
408130803Smarcel  outlen = 0;
409130803Smarcel  res = WriteProcessMemory (h, p, buf, (DWORD) len, &outlen);
410130803Smarcel  putresult (L"WriteProcessMemory data", res, s, GDB_WRITEPROCESSMEMORY,
411130803Smarcel	     (gdb_wince_len *) & outlen, sizeof (gdb_wince_len));
412130803Smarcel}
413130803Smarcel
414130803Smarcel/* Return non-zero to gdb host if given thread is alive. */
415130803Smarcelstatic void
416130803Smarcelthread_alive (int s)
417130803Smarcel{
418130803Smarcel  HANDLE h = gethandle (L"ThreadAlive handle", s, GDB_THREADALIVE);
419130803Smarcel  gdb_wince_result res;
420130803Smarcel
421130803Smarcel  res = WaitForSingleObject (h, 0) == WAIT_OBJECT_0 ? 1 : 0;
422130803Smarcel  putresult (L"WriteProcessMemory data", res, s, GDB_THREADALIVE,
423130803Smarcel	     &res, sizeof (res));
424130803Smarcel}
425130803Smarcel
426130803Smarcel/* Emulate SuspendThread.  Returns value returned from SuspendThread. */
427130803Smarcelstatic void
428130803Smarcelsuspend_thread (int s)
429130803Smarcel{
430130803Smarcel  DWORD res;
431130803Smarcel  HANDLE h = gethandle (L"SuspendThread handle", s, GDB_SUSPENDTHREAD);
432130803Smarcel  res = SuspendThread (h);
433130803Smarcel  putdword (L"SuspendThread result", s, GDB_SUSPENDTHREAD, res);
434130803Smarcel}
435130803Smarcel
436130803Smarcel/* Emulate ResumeThread.  Returns value returned from ResumeThread. */
437130803Smarcelstatic void
438130803Smarcelresume_thread (int s)
439130803Smarcel{
440130803Smarcel  DWORD res;
441130803Smarcel  HANDLE h = gethandle (L"ResumeThread handle", s, GDB_RESUMETHREAD);
442130803Smarcel  res = ResumeThread (h);
443130803Smarcel  putdword (L"ResumeThread result", s, GDB_RESUMETHREAD, res);
444130803Smarcel}
445130803Smarcel
446130803Smarcel/* Emulate ContinueDebugEvent.  Returns ContinueDebugEvent success. */
447130803Smarcelstatic void
448130803Smarcelcontinue_debug_event (int s)
449130803Smarcel{
450130803Smarcel  gdb_wince_result res;
451130803Smarcel  DWORD pid = getdword (L"ContinueDebugEvent pid", s, GDB_CONTINUEDEBUGEVENT);
452130803Smarcel  DWORD tid = getdword (L"ContinueDebugEvent tid", s, GDB_CONTINUEDEBUGEVENT);
453130803Smarcel  DWORD status = getdword (L"ContinueDebugEvent status", s, GDB_CONTINUEDEBUGEVENT);
454130803Smarcel  res = (gdb_wince_result) ContinueDebugEvent (pid, tid, status);
455130803Smarcel  putresult (L"ContinueDebugEvent result", res, s, GDB_CONTINUEDEBUGEVENT, &res, sizeof (res));
456130803Smarcel}
457130803Smarcel
458130803Smarcel/* Emulate CloseHandle.  Returns CloseHandle success. */
459130803Smarcelstatic void
460130803Smarcelclose_handle (int s)
461130803Smarcel{
462130803Smarcel  gdb_wince_result res;
463130803Smarcel  HANDLE h = gethandle (L"CloseHandle handle", s, GDB_CLOSEHANDLE);
464130803Smarcel  res = (gdb_wince_result) CloseHandle (h);
465130803Smarcel  putresult (L"CloseHandle result", res, s, GDB_CLOSEHANDLE, &res, sizeof (res));
466130803Smarcel}
467130803Smarcel
468130803Smarcel/* Main loop for reading requests from gdb host on the socket. */
469130803Smarcelstatic void
470130803Smarceldispatch (int s)
471130803Smarcel{
472130803Smarcel  gdb_wince_id id;
473130803Smarcel
474130803Smarcel  /* Continue reading from socket until receive a GDB_STOPSUB. */
475130803Smarcel  while (sockread (L"Dispatch", s, &id, sizeof (id)) > 0)
476130803Smarcel    {
477130803Smarcel      skip_next_id = 1;
478130803Smarcel      switch (id)
479130803Smarcel	{
480130803Smarcel	case GDB_CREATEPROCESS:
481130803Smarcel	  create_process (s);
482130803Smarcel	  break;
483130803Smarcel	case GDB_TERMINATEPROCESS:
484130803Smarcel	  terminate_process (s);
485130803Smarcel	  break;
486130803Smarcel	case GDB_WAITFORDEBUGEVENT:
487130803Smarcel	  wait_for_debug_event (s);
488130803Smarcel	  break;
489130803Smarcel	case GDB_GETTHREADCONTEXT:
490130803Smarcel	  get_thread_context (s);
491130803Smarcel	  break;
492130803Smarcel	case GDB_SETTHREADCONTEXT:
493130803Smarcel	  set_thread_context (s);
494130803Smarcel	  break;
495130803Smarcel	case GDB_READPROCESSMEMORY:
496130803Smarcel	  read_process_memory (s);
497130803Smarcel	  break;
498130803Smarcel	case GDB_WRITEPROCESSMEMORY:
499130803Smarcel	  write_process_memory (s);
500130803Smarcel	  break;
501130803Smarcel	case GDB_THREADALIVE:
502130803Smarcel	  thread_alive (s);
503130803Smarcel	  break;
504130803Smarcel	case GDB_SUSPENDTHREAD:
505130803Smarcel	  suspend_thread (s);
506130803Smarcel	  break;
507130803Smarcel	case GDB_RESUMETHREAD:
508130803Smarcel	  resume_thread (s);
509130803Smarcel	  break;
510130803Smarcel	case GDB_CONTINUEDEBUGEVENT:
511130803Smarcel	  continue_debug_event (s);
512130803Smarcel	  break;
513130803Smarcel	case GDB_CLOSEHANDLE:
514130803Smarcel	  close_handle (s);
515130803Smarcel	  break;
516130803Smarcel	case GDB_STOPSTUB:
517130803Smarcel	  terminate_process (s);
518130803Smarcel	  return;
519130803Smarcel	case GDB_SINGLESTEP:
520130803Smarcel	  flag_single_step (s);
521130803Smarcel	  break;
522130803Smarcel	default:
523130803Smarcel	  {
524130803Smarcel	    WCHAR buf[80];
525130803Smarcel	    wsprintfW (buf, L"Invalid command id received: %d", id);
526130803Smarcel	    MessageBoxW (NULL, buf, L"GDB", MB_ICONERROR);
527130803Smarcel	    skip_next_id = 0;
528130803Smarcel	  }
529130803Smarcel	}
530130803Smarcel    }
531130803Smarcel}
532130803Smarcel
533130803Smarcel/* The Windows Main entry point */
534130803Smarcelint WINAPI
535130803SmarcelWinMain (HINSTANCE hi, HINSTANCE hp, LPWSTR cmd, int show)
536130803Smarcel{
537130803Smarcel  struct hostent *h;
538130803Smarcel  int s;
539130803Smarcel  struct WSAData wd;
540130803Smarcel  struct sockaddr_in sin;
541130803Smarcel  int tmp;
542130803Smarcel  LPWSTR whost;
543130803Smarcel  char host[80];
544130803Smarcel
545130803Smarcel  whost = wcschr (cmd, L' ');	/* Look for argument. */
546130803Smarcel
547130803Smarcel  /* If no host is specified, just use default */
548130803Smarcel  if (whost)
549130803Smarcel    {
550130803Smarcel      /* Eat any spaces. */
551130803Smarcel      while (*whost == L' ' || *whost == L'\t')
552130803Smarcel	whost++;
553130803Smarcel
554130803Smarcel      wcstombs (host, whost, 80);	/* Convert from UNICODE to ascii */
555130803Smarcel    }
556130803Smarcel
557130803Smarcel  /* Winsock initialization. */
558130803Smarcel  if (WSAStartup (MAKEWORD (1, 1), &wd))
559130803Smarcel    stub_error (L"Couldn't initialize WINSOCK.");
560130803Smarcel
561130803Smarcel  /* If whost was specified, first try it.  If it was not specified or the
562130803Smarcel     host lookup failed, try the Windows CE magic ppp_peer lookup.  ppp_peer
563130803Smarcel     is supposed to be the Windows host sitting on the other end of the
564130803Smarcel     serial cable. */
565130803Smarcel  if (whost && *whost && (h = gethostbyname (host)) != NULL)
566130803Smarcel    /* nothing to do */ ;
567130803Smarcel  else if ((h = gethostbyname ("ppp_peer")) == NULL)
568130803Smarcel    stub_error (L"Couldn't get IP address of host system.  Error %d", WSAGetLastError ());
569130803Smarcel
570130803Smarcel  /* Get a socket. */
571130803Smarcel  if ((s = socket (AF_INET, SOCK_STREAM, 0)) < 0)
572130803Smarcel    stub_error (L"Couldn't connect to host system. Error %d", WSAGetLastError ());
573130803Smarcel
574130803Smarcel  /* Allow rapid reuse of the port. */
575130803Smarcel  tmp = 1;
576130803Smarcel  setsockopt (s, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp, sizeof (tmp));
577130803Smarcel
578130803Smarcel  /* Set up the information for connecting to the host gdb process. */
579130803Smarcel  memset (&sin, 0, sizeof (sin));
580130803Smarcel  sin.sin_family = h->h_addrtype;
581130803Smarcel  memcpy (&sin.sin_addr, h->h_addr, h->h_length);
582130803Smarcel  sin.sin_port = htons (7000);	/* FIXME: This should be configurable */
583130803Smarcel
584130803Smarcel  /* Connect to host */
585130803Smarcel  if (connect (s, (struct sockaddr *) &sin, sizeof (sin)) < 0)
586130803Smarcel    stub_error (L"Couldn't connect to host gdb.");
587130803Smarcel
588130803Smarcel  /* Read from socket until told to exit. */
589130803Smarcel  dispatch (s);
590130803Smarcel  WSACleanup ();
591130803Smarcel  return 0;
592130803Smarcel}
593