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