OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [gdb-5.0/] [gdb/] [wince-stub.c] - Blame information for rev 1774

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.