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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [gdb/] [wince-stub.c] - Blame information for rev 1771

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

Line No. Rev Author Line
1 578 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 | LMEM_ZEROINIT, (UINT)(n))
32
#define REALLOC(s, n) (void *) LocalReAlloc ((HLOCAL)(s), (UINT)(n), LMEM_MOVEABLE)
33
#define FREE(s) LocalFree ((HLOCAL)(s))
34
 
35
static int skip_next_id = 0;     /* Don't read next API code from socket */
36
 
37
/* v-style interface for handling varying argument list error messages.
38
   Displays the error message in a dialog box and exits when user clicks
39
   on OK. */
40
static void
41
vstub_error (LPCWSTR fmt, va_list args)
42
{
43
  WCHAR buf[4096];
44
  wvsprintfW (buf, fmt, args);
45
 
46
  MessageBoxW (NULL, buf, L"GDB", MB_ICONERROR);
47
  WSACleanup ();
48
  ExitThread (1);
49
}
50
 
51
/* The standard way to display an error message and exit. */
52
static void
53
stub_error (LPCWSTR fmt, ...)
54
{
55
  va_list args;
56
  va_start (args, fmt);
57
  vstub_error (fmt, args);
58
}
59
 
60
/* Allocate a limited pool of memory, reallocating over unused
61
   buffers.  This assumes that there will never be more than four
62
   "buffers" required which, so far, is a safe assumption. */
63
static LPVOID
64
mempool (unsigned int len)
65
{
66
  static int outn = -1;
67
  static LPWSTR outs[4] = {NULL, NULL, NULL, NULL};
68
 
69
  if (++outn >= (sizeof (outs) / sizeof (outs[0])))
70
    outn = 0;
71
 
72
  /* Allocate space for the converted string, reusing any previously allocated
73
     space, if applicable. */
74
  if (outs[outn])
75
    FREE (outs[outn]);
76
  outs[outn] = (LPWSTR) MALLOC (len);
77
 
78
  return outs[outn];
79
}
80
 
81
/* Standard "oh well" can't communicate error.  Someday this might attempt
82
   synchronization. */
83
static void
84
attempt_resync (LPCWSTR huh, int s)
85
{
86
  stub_error (L"lost synchronization with host attempting %s.  Error %d", huh, WSAGetLastError ());
87
}
88
 
89
/* Read arbitrary stuff from a socket. */
90
static int
91
sockread (LPCWSTR huh, int s, void *str, size_t n)
92
{
93
  for (;;)
94
    {
95
      if (recv (s, str, n, 0) == (int) n)
96
        return n;
97
      attempt_resync (huh, s);
98
    }
99
}
100
 
101
/* Write arbitrary stuff to a socket. */
102
static int
103
sockwrite (LPCWSTR huh, int s, const void *str, size_t n)
104
{
105
  for (;;)
106
    {
107
      if (send (s, str, n, 0) == (int) n)
108
        return n;
109
      attempt_resync (huh, s);
110
    }
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 ((unsigned int) *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
static int stepped = 0;
273
/* Handle single step instruction.  FIXME: unneded? */
274
static void
275
flag_single_step (int s)
276
{
277
  stepped = 1;
278
  skip_next_id = 0;
279
}
280
 
281
struct skipper
282
{
283
  wchar_t *s;
284
  int nskip;
285
} skippy[] =
286
{
287
  {L"Undefined Instruction:", 1},
288
  {L"Data Abort:", 2},
289
  {NULL, 0}
290
};
291
 
292
static int
293
skip_message (DEBUG_EVENT *ev)
294
{
295
  char s[80];
296
  DWORD nread;
297
  struct skipper *skp;
298
  int nbytes = ev->u.DebugString.nDebugStringLength;
299
 
300
  if (nbytes > sizeof(s))
301
    nbytes = sizeof(s);
302
 
303
  memset (s, 0, sizeof (s));
304
  if (!ReadProcessMemory (curproc, ev->u.DebugString.lpDebugStringData,
305
                          s, nbytes, &nread))
306
    return 0;
307
 
308
  for (skp = skippy; skp->s != NULL; skp++)
309
    if (wcsncmp ((wchar_t *) s, skp->s, wcslen (skp->s)) == 0)
310
      return skp->nskip;
311
 
312
  return 0;
313
}
314
 
315
/* Emulate WaitForDebugEvent.  Returns the debug event on success. */
316
static void
317
wait_for_debug_event (int s)
318
{
319
  DWORD ms = getdword (L"WaitForDebugEvent ms", s, GDB_WAITFORDEBUGEVENT);
320
  gdb_wince_result res;
321
  DEBUG_EVENT ev;
322
  static int skip_next = 0;
323
 
324
  for (;;)
325
    {
326
      res = WaitForDebugEvent (&ev, ms);
327
 
328
      if (ev.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT)
329
        {
330
          if (skip_next)
331
            {
332
              skip_next--;
333
              goto ignore;
334
            }
335
          if (skip_next = skip_message (&ev))
336
            goto ignore;
337
        }
338
 
339
      putresult (L"WaitForDebugEvent event", res, s, GDB_WAITFORDEBUGEVENT,
340
                 &ev, sizeof (ev));
341
      break;
342
 
343
    ignore:
344
      ContinueDebugEvent (ev.dwProcessId, ev.dwThreadId, DBG_CONTINUE);
345
    }
346
 
347
  return;
348
}
349
 
350
/* Emulate GetThreadContext.  Returns CONTEXT structure on success. */
351
static void
352
get_thread_context (int s)
353
{
354
  CONTEXT c;
355
  HANDLE h = gethandle (L"GetThreadContext handle", s, GDB_GETTHREADCONTEXT);
356
  gdb_wince_result res;
357
 
358
  memset (&c, 0, sizeof (c));
359
  c.ContextFlags = getdword (L"GetThreadContext flags", s, GDB_GETTHREADCONTEXT);
360
 
361
  res = (gdb_wince_result) GetThreadContext (h, &c);
362
  putresult (L"GetThreadContext data", res, s, GDB_GETTHREADCONTEXT,
363
             &c, sizeof (c));
364
}
365
 
366
/* Emulate GetThreadContext.  Returns success of SetThreadContext. */
367
static void
368
set_thread_context (int s)
369
{
370
  gdb_wince_result res;
371
  HANDLE h = gethandle (L"SetThreadContext handle", s, GDB_SETTHREADCONTEXT);
372
  LPCONTEXT pc = (LPCONTEXT) getmemory (L"SetThreadContext context", s,
373
                                        GDB_SETTHREADCONTEXT, NULL);
374
 
375
  res = SetThreadContext (h, pc);
376
  putresult (L"SetThreadContext result", res, s, GDB_SETTHREADCONTEXT,
377
             &res, sizeof (res));
378
}
379
 
380
/* Emulate ReadProcessMemory.  Returns memory read on success. */
381
static void
382
read_process_memory (int s)
383
{
384
  HANDLE h = gethandle (L"ReadProcessMemory handle", s, GDB_READPROCESSMEMORY);
385
  LPVOID p = getpvoid (L"ReadProcessMemory base", s, GDB_READPROCESSMEMORY);
386
  gdb_wince_len len = getlen (L"ReadProcessMemory size", s, GDB_READPROCESSMEMORY);
387
  LPVOID buf = mempool ((unsigned int) len);
388
  DWORD outlen;
389
  gdb_wince_result res;
390
 
391
  outlen = 0;
392
  res = (gdb_wince_result) ReadProcessMemory (h, p, buf, len, &outlen);
393
  putresult (L"ReadProcessMemory data", res, s, GDB_READPROCESSMEMORY,
394
             buf, (gdb_wince_len) outlen);
395
}
396
 
397
/* Emulate WriteProcessMemory.  Returns WriteProcessMemory success. */
398
static void
399
write_process_memory (int s)
400
{
401
  HANDLE h = gethandle (L"WriteProcessMemory handle", s, GDB_WRITEPROCESSMEMORY);
402
  LPVOID p = getpvoid (L"WriteProcessMemory base", s, GDB_WRITEPROCESSMEMORY);
403
  gdb_wince_len len;
404
  LPVOID buf = getmemory (L"WriteProcessMemory buf", s, GDB_WRITEPROCESSMEMORY, &len);
405
  DWORD outlen;
406
  gdb_wince_result res;
407
 
408
  outlen = 0;
409
  res = WriteProcessMemory (h, p, buf, (DWORD) len, &outlen);
410
  putresult (L"WriteProcessMemory data", res, s, GDB_WRITEPROCESSMEMORY,
411
             (gdb_wince_len *) & outlen, sizeof (gdb_wince_len));
412
}
413
 
414
/* Return non-zero to gdb host if given thread is alive. */
415
static void
416
thread_alive (int s)
417
{
418
  HANDLE h = gethandle (L"ThreadAlive handle", s, GDB_THREADALIVE);
419
  gdb_wince_result res;
420
 
421
  res = WaitForSingleObject (h, 0) == WAIT_OBJECT_0 ? 1 : 0;
422
  putresult (L"WriteProcessMemory data", res, s, GDB_THREADALIVE,
423
             &res, sizeof (res));
424
}
425
 
426
/* Emulate SuspendThread.  Returns value returned from SuspendThread. */
427
static void
428
suspend_thread (int s)
429
{
430
  DWORD res;
431
  HANDLE h = gethandle (L"SuspendThread handle", s, GDB_SUSPENDTHREAD);
432
  res = SuspendThread (h);
433
  putdword (L"SuspendThread result", s, GDB_SUSPENDTHREAD, res);
434
}
435
 
436
/* Emulate ResumeThread.  Returns value returned from ResumeThread. */
437
static void
438
resume_thread (int s)
439
{
440
  DWORD res;
441
  HANDLE h = gethandle (L"ResumeThread handle", s, GDB_RESUMETHREAD);
442
  res = ResumeThread (h);
443
  putdword (L"ResumeThread result", s, GDB_RESUMETHREAD, res);
444
}
445
 
446
/* Emulate ContinueDebugEvent.  Returns ContinueDebugEvent success. */
447
static void
448
continue_debug_event (int s)
449
{
450
  gdb_wince_result res;
451
  DWORD pid = getdword (L"ContinueDebugEvent pid", s, GDB_CONTINUEDEBUGEVENT);
452
  DWORD tid = getdword (L"ContinueDebugEvent tid", s, GDB_CONTINUEDEBUGEVENT);
453
  DWORD status = getdword (L"ContinueDebugEvent status", s, GDB_CONTINUEDEBUGEVENT);
454
  res = (gdb_wince_result) ContinueDebugEvent (pid, tid, status);
455
  putresult (L"ContinueDebugEvent result", res, s, GDB_CONTINUEDEBUGEVENT, &res, sizeof (res));
456
}
457
 
458
/* Emulate CloseHandle.  Returns CloseHandle success. */
459
static void
460
close_handle (int s)
461
{
462
  gdb_wince_result res;
463
  HANDLE h = gethandle (L"CloseHandle handle", s, GDB_CLOSEHANDLE);
464
  res = (gdb_wince_result) CloseHandle (h);
465
  putresult (L"CloseHandle result", res, s, GDB_CLOSEHANDLE, &res, sizeof (res));
466
}
467
 
468
/* Main loop for reading requests from gdb host on the socket. */
469
static void
470
dispatch (int s)
471
{
472
  gdb_wince_id id;
473
 
474
  /* Continue reading from socket until receive a GDB_STOPSUB. */
475
  while (sockread (L"Dispatch", s, &id, sizeof (id)) > 0)
476
    {
477
      skip_next_id = 1;
478
      switch (id)
479
        {
480
        case GDB_CREATEPROCESS:
481
          create_process (s);
482
          break;
483
        case GDB_TERMINATEPROCESS:
484
          terminate_process (s);
485
          break;
486
        case GDB_WAITFORDEBUGEVENT:
487
          wait_for_debug_event (s);
488
          break;
489
        case GDB_GETTHREADCONTEXT:
490
          get_thread_context (s);
491
          break;
492
        case GDB_SETTHREADCONTEXT:
493
          set_thread_context (s);
494
          break;
495
        case GDB_READPROCESSMEMORY:
496
          read_process_memory (s);
497
          break;
498
        case GDB_WRITEPROCESSMEMORY:
499
          write_process_memory (s);
500
          break;
501
        case GDB_THREADALIVE:
502
          thread_alive (s);
503
          break;
504
        case GDB_SUSPENDTHREAD:
505
          suspend_thread (s);
506
          break;
507
        case GDB_RESUMETHREAD:
508
          resume_thread (s);
509
          break;
510
        case GDB_CONTINUEDEBUGEVENT:
511
          continue_debug_event (s);
512
          break;
513
        case GDB_CLOSEHANDLE:
514
          close_handle (s);
515
          break;
516
        case GDB_STOPSTUB:
517
          terminate_process (s);
518
          return;
519
        case GDB_SINGLESTEP:
520
          flag_single_step (s);
521
          break;
522
        default:
523
          {
524
            WCHAR buf[80];
525
            wsprintfW (buf, L"Invalid command id received: %d", id);
526
            MessageBoxW (NULL, buf, L"GDB", MB_ICONERROR);
527
            skip_next_id = 0;
528
          }
529
        }
530
    }
531
}
532
 
533
/* The Windows Main entry point */
534
int WINAPI
535
WinMain (HINSTANCE hi, HINSTANCE hp, LPWSTR cmd, int show)
536
{
537
  struct hostent *h;
538
  int s;
539
  struct WSAData wd;
540
  struct sockaddr_in sin;
541
  int tmp;
542
  LPWSTR whost;
543
  char host[80];
544
 
545
  whost = wcschr (cmd, L' ');   /* Look for argument. */
546
 
547
  /* If no host is specified, just use default */
548
  if (whost)
549
    {
550
      /* Eat any spaces. */
551
      while (*whost == L' ' || *whost == L'\t')
552
        whost++;
553
 
554
      wcstombs (host, whost, 80);       /* Convert from UNICODE to ascii */
555
    }
556
 
557
  /* Winsock initialization. */
558
  if (WSAStartup (MAKEWORD (1, 1), &wd))
559
    stub_error (L"Couldn't initialize WINSOCK.");
560
 
561
  /* If whost was specified, first try it.  If it was not specified or the
562
     host lookup failed, try the Windows CE magic ppp_peer lookup.  ppp_peer
563
     is supposed to be the Windows host sitting on the other end of the
564
     serial cable. */
565
  if (whost && *whost && (h = gethostbyname (host)) != NULL)
566
    /* nothing to do */ ;
567
  else if ((h = gethostbyname ("ppp_peer")) == NULL)
568
    stub_error (L"Couldn't get IP address of host system.  Error %d", WSAGetLastError ());
569
 
570
  /* Get a socket. */
571
  if ((s = socket (AF_INET, SOCK_STREAM, 0)) < 0)
572
    stub_error (L"Couldn't connect to host system. Error %d", WSAGetLastError ());
573
 
574
  /* Allow rapid reuse of the port. */
575
  tmp = 1;
576
  setsockopt (s, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp, sizeof (tmp));
577
 
578
  /* Set up the information for connecting to the host gdb process. */
579
  memset (&sin, 0, sizeof (sin));
580
  sin.sin_family = h->h_addrtype;
581
  memcpy (&sin.sin_addr, h->h_addr, h->h_length);
582
  sin.sin_port = htons (7000);  /* FIXME: This should be configurable */
583
 
584
  /* Connect to host */
585
  if (connect (s, (struct sockaddr *) &sin, sizeof (sin)) < 0)
586
    stub_error (L"Couldn't connect to host gdb.");
587
 
588
  /* Read from socket until told to exit. */
589
  dispatch (s);
590
  WSACleanup ();
591
  return 0;
592
}

powered by: WebSVN 2.1.0

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