1130803Smarcel/* Target-vector operations for controlling Windows CE child processes, for GDB.
2130803Smarcel   Copyright 1999, 2000, 2001 Free Software Foundation, Inc.
3130803Smarcel   Contributed by Cygnus Solutions, A Red Hat Company.
4130803Smarcel
5130803Smarcel   This file is part of GDB.
6130803Smarcel
7130803Smarcel   This program is free software; you can redistribute it and/or modify
8130803Smarcel   it under the terms of the GNU General Public License as published by
9130803Smarcel   the Free Software Foundation; either version 2 of the License, or
10130803Smarcel   (at your option) any later version.
11130803Smarcel
12130803Smarcel   This program is distributed in the hope that it will be useful,
13130803Smarcel   but WITHOUT ANY WARRANTY; without even the implied warranty of
14130803Smarcel   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15130803Smarcel   GNU General Public License for more details.
16130803Smarcel
17130803Smarcel   You should have received a copy of the GNU General Public License
18130803Smarcel   along with this program; if not, write to the Free Software
19130803Smarcel   Foundation, Inc., 59 Temple Place - Suite 330,
20130803Smarcel   Boston, MA 02111-1307, USA.
21130803Smarcel */
22130803Smarcel
23130803Smarcel/* by Christopher Faylor (cgf@cygnus.com) */
24130803Smarcel
25130803Smarcel/* We assume we're being built with and will be used for cygwin.  */
26130803Smarcel
27130803Smarcel#ifdef SHx
28130803Smarcel#undef SH4
29130803Smarcel#define SH4			/* Just to get all of the CONTEXT defines. */
30130803Smarcel#endif
31130803Smarcel
32130803Smarcel#include "defs.h"
33130803Smarcel#include "frame.h"		/* required by inferior.h */
34130803Smarcel#include "inferior.h"
35130803Smarcel#include "target.h"
36130803Smarcel#include "gdbcore.h"
37130803Smarcel#include "command.h"
38130803Smarcel#include <signal.h>
39130803Smarcel#include <sys/types.h>
40130803Smarcel#include <fcntl.h>
41130803Smarcel#include <stdlib.h>
42130803Smarcel
43130803Smarcel#include <windows.h>
44130803Smarcel#include <rapi.h>
45130803Smarcel#include <netdb.h>
46130803Smarcel#include <cygwin/in.h>
47130803Smarcel#include <cygwin/socket.h>
48130803Smarcel
49130803Smarcel#include "buildsym.h"
50130803Smarcel#include "symfile.h"
51130803Smarcel#include "objfiles.h"
52130803Smarcel#include "gdb_string.h"
53130803Smarcel#include "gdbthread.h"
54130803Smarcel#include "gdbcmd.h"
55130803Smarcel#include <sys/param.h>
56130803Smarcel#include "wince-stub.h"
57130803Smarcel#include <time.h>
58130803Smarcel#include "regcache.h"
59130803Smarcel#ifdef MIPS
60130803Smarcel#include "mips-tdep.h"
61130803Smarcel#endif
62130803Smarcel
63130803Smarcel/* The ui's event loop. */
64130803Smarcelextern int (*ui_loop_hook) (int signo);
65130803Smarcel
66130803Smarcel/* If we're not using the old Cygwin header file set, define the
67130803Smarcel   following which never should have been in the generic Win32 API
68130803Smarcel   headers in the first place since they were our own invention... */
69130803Smarcel#ifndef _GNU_H_WINDOWS_H
70130803Smarcel#define FLAG_TRACE_BIT 0x100
71130803Smarcel#ifdef CONTEXT_FLOATING_POINT
72130803Smarcel#define CONTEXT_DEBUGGER0 (CONTEXT_FULL | CONTEXT_FLOATING_POINT)
73130803Smarcel#else
74130803Smarcel#define CONTEXT_DEBUGGER0 (CONTEXT_FULL)
75130803Smarcel#endif
76130803Smarcel#endif
77130803Smarcel
78130803Smarcel#ifdef SH4
79130803Smarcel#define CONTEXT_DEBUGGER ((CONTEXT_DEBUGGER0 & ~(CONTEXT_SH4 | CONTEXT_FLOATING_POINT)) | CONTEXT_SH3)
80130803Smarcel#else
81130803Smarcel#define CONTEXT_DEBUGGER CONTEXT_DEBUGGER0
82130803Smarcel#endif
83130803Smarcel/* The string sent by cygwin when it processes a signal.
84130803Smarcel   FIXME: This should be in a cygwin include file. */
85130803Smarcel#define CYGWIN_SIGNAL_STRING "cygwin: signal"
86130803Smarcel
87130803Smarcel#define CHECK(x)	check (x, __FILE__,__LINE__)
88130803Smarcel#define DEBUG_EXEC(x)	if (debug_exec)		printf x
89130803Smarcel#define DEBUG_EVENTS(x)	if (debug_events)	printf x
90130803Smarcel#define DEBUG_MEM(x)	if (debug_memory)	printf x
91130803Smarcel#define DEBUG_EXCEPT(x)	if (debug_exceptions)	printf x
92130803Smarcel
93130803Smarcelstatic int connection_initialized = 0;	/* True if we've initialized a RAPI session. */
94130803Smarcel
95130803Smarcel/* The directory where the stub and executable files are uploaded. */
96130803Smarcelstatic const char *remote_directory = "\\gdb";
97130803Smarcel
98130803Smarcel/* The types automatic upload available. */
99130803Smarcelstatic enum
100130803Smarcel  {
101130803Smarcel    UPLOAD_ALWAYS = 0,
102130803Smarcel    UPLOAD_NEWER = 1,
103130803Smarcel    UPLOAD_NEVER = 2
104130803Smarcel  }
105130803Smarcelupload_when = UPLOAD_NEWER;
106130803Smarcel
107130803Smarcel/* Valid options for 'set remoteupload'.  Note that options
108130803Smarcel   must track upload_when enum. */
109130803Smarcelstatic struct opts
110130803Smarcel  {
111130803Smarcel    const char *name;
112130803Smarcel    int abbrev;
113130803Smarcel  }
114130803Smarcelupload_options[3] =
115130803Smarcel{
116130803Smarcel  {
117130803Smarcel    "always", 1
118130803Smarcel  }
119130803Smarcel  ,
120130803Smarcel  {
121130803Smarcel    "newer", 3
122130803Smarcel  }
123130803Smarcel  ,
124130803Smarcel  {
125130803Smarcel    "never", 3
126130803Smarcel  }
127130803Smarcel};
128130803Smarcel
129130803Smarcelstatic char *remote_upload = NULL;	/* Set by set remoteupload */
130130803Smarcelstatic int remote_add_host = 0;
131130803Smarcel
132130803Smarcel/* Forward declaration */
133130803Smarcelextern struct target_ops child_ops;
134130803Smarcel
135130803Smarcelstatic int win32_child_thread_alive (ptid_t);
136130803Smarcelvoid child_kill_inferior (void);
137130803Smarcel
138130803Smarcelstatic int last_sig = 0;	/* Set if a signal was received from the
139130803Smarcel				   debugged process */
140130803Smarcel
141130803Smarcel/* Thread information structure used to track information that is
142130803Smarcel   not available in gdb's thread structure. */
143130803Smarceltypedef struct thread_info_struct
144130803Smarcel  {
145130803Smarcel    struct thread_info_struct *next;
146130803Smarcel    DWORD id;
147130803Smarcel    HANDLE h;
148130803Smarcel    char *name;
149130803Smarcel    int suspend_count;
150130803Smarcel    int stepped;		/* True if stepped. */
151130803Smarcel    CORE_ADDR step_pc;
152130803Smarcel    unsigned long step_prev;
153130803Smarcel    CONTEXT context;
154130803Smarcel  }
155130803Smarcelthread_info;
156130803Smarcel
157130803Smarcelstatic thread_info thread_head =
158130803Smarcel{NULL};
159130803Smarcelstatic thread_info * thread_rec (DWORD id, int get_context);
160130803Smarcel
161130803Smarcel/* The process and thread handles for the above context. */
162130803Smarcel
163130803Smarcelstatic DEBUG_EVENT current_event;	/* The current debug event from
164130803Smarcel					   WaitForDebugEvent */
165130803Smarcelstatic HANDLE current_process_handle;	/* Currently executing process */
166130803Smarcelstatic thread_info *current_thread;	/* Info on currently selected thread */
167130803Smarcelstatic thread_info *this_thread;	/* Info on thread returned by wait_for_debug_event */
168130803Smarcelstatic DWORD main_thread_id;	/* Thread ID of the main thread */
169130803Smarcel
170130803Smarcel/* Counts of things. */
171130803Smarcelstatic int exception_count = 0;
172130803Smarcelstatic int event_count = 0;
173130803Smarcel
174130803Smarcel/* User options. */
175130803Smarcelstatic int debug_exec = 0;	/* show execution */
176130803Smarcelstatic int debug_events = 0;	/* show events from kernel */
177130803Smarcelstatic int debug_memory = 0;	/* show target memory accesses */
178130803Smarcelstatic int debug_exceptions = 0;	/* show target exceptions */
179130803Smarcel
180130803Smarcel/* An array of offset mappings into a Win32 Context structure.
181130803Smarcel   This is a one-to-one mapping which is indexed by gdb's register
182130803Smarcel   numbers.  It retrieves an offset into the context structure where
183130803Smarcel   the 4 byte register is located.
184130803Smarcel   An offset value of -1 indicates that Win32 does not provide this
185130803Smarcel   register in it's CONTEXT structure.  regptr will return zero for this
186130803Smarcel   register.
187130803Smarcel
188130803Smarcel   This is used by the regptr function. */
189130803Smarcel#define context_offset(x) ((int)&(((PCONTEXT)NULL)->x))
190130803Smarcelstatic const int mappings[NUM_REGS + 1] =
191130803Smarcel{
192130803Smarcel#ifdef __i386__
193130803Smarcel  context_offset (Eax),
194130803Smarcel  context_offset (Ecx),
195130803Smarcel  context_offset (Edx),
196130803Smarcel  context_offset (Ebx),
197130803Smarcel  context_offset (Esp),
198130803Smarcel  context_offset (Ebp),
199130803Smarcel  context_offset (Esi),
200130803Smarcel  context_offset (Edi),
201130803Smarcel  context_offset (Eip),
202130803Smarcel  context_offset (EFlags),
203130803Smarcel  context_offset (SegCs),
204130803Smarcel  context_offset (SegSs),
205130803Smarcel  context_offset (SegDs),
206130803Smarcel  context_offset (SegEs),
207130803Smarcel  context_offset (SegFs),
208130803Smarcel  context_offset (SegGs),
209130803Smarcel  context_offset (FloatSave.RegisterArea[0 * 10]),
210130803Smarcel  context_offset (FloatSave.RegisterArea[1 * 10]),
211130803Smarcel  context_offset (FloatSave.RegisterArea[2 * 10]),
212130803Smarcel  context_offset (FloatSave.RegisterArea[3 * 10]),
213130803Smarcel  context_offset (FloatSave.RegisterArea[4 * 10]),
214130803Smarcel  context_offset (FloatSave.RegisterArea[5 * 10]),
215130803Smarcel  context_offset (FloatSave.RegisterArea[6 * 10]),
216130803Smarcel  context_offset (FloatSave.RegisterArea[7 * 10]),
217130803Smarcel#elif defined(SHx)
218130803Smarcel  context_offset (R0),
219130803Smarcel  context_offset (R1),
220130803Smarcel  context_offset (R2),
221130803Smarcel  context_offset (R3),
222130803Smarcel  context_offset (R4),
223130803Smarcel  context_offset (R5),
224130803Smarcel  context_offset (R6),
225130803Smarcel  context_offset (R7),
226130803Smarcel  context_offset (R8),
227130803Smarcel  context_offset (R9),
228130803Smarcel  context_offset (R10),
229130803Smarcel  context_offset (R11),
230130803Smarcel  context_offset (R12),
231130803Smarcel  context_offset (R13),
232130803Smarcel  context_offset (R14),
233130803Smarcel  context_offset (R15),
234130803Smarcel  context_offset (Fir),
235130803Smarcel  context_offset (PR),		/* Procedure Register */
236130803Smarcel  context_offset (GBR),		/* Global Base Register */
237130803Smarcel  context_offset (MACH),	/* Accumulate */
238130803Smarcel  context_offset (MACL),	/* Multiply */
239130803Smarcel  context_offset (Psr),
240130803Smarcel  context_offset (Fpul),
241130803Smarcel  context_offset (Fpscr),
242130803Smarcel  context_offset (FRegs[0]),
243130803Smarcel  context_offset (FRegs[1]),
244130803Smarcel  context_offset (FRegs[2]),
245130803Smarcel  context_offset (FRegs[3]),
246130803Smarcel  context_offset (FRegs[4]),
247130803Smarcel  context_offset (FRegs[5]),
248130803Smarcel  context_offset (FRegs[6]),
249130803Smarcel  context_offset (FRegs[7]),
250130803Smarcel  context_offset (FRegs[8]),
251130803Smarcel  context_offset (FRegs[9]),
252130803Smarcel  context_offset (FRegs[10]),
253130803Smarcel  context_offset (FRegs[11]),
254130803Smarcel  context_offset (FRegs[12]),
255130803Smarcel  context_offset (FRegs[13]),
256130803Smarcel  context_offset (FRegs[14]),
257130803Smarcel  context_offset (FRegs[15]),
258130803Smarcel  context_offset (xFRegs[0]),
259130803Smarcel  context_offset (xFRegs[1]),
260130803Smarcel  context_offset (xFRegs[2]),
261130803Smarcel  context_offset (xFRegs[3]),
262130803Smarcel  context_offset (xFRegs[4]),
263130803Smarcel  context_offset (xFRegs[5]),
264130803Smarcel  context_offset (xFRegs[6]),
265130803Smarcel  context_offset (xFRegs[7]),
266130803Smarcel  context_offset (xFRegs[8]),
267130803Smarcel  context_offset (xFRegs[9]),
268130803Smarcel  context_offset (xFRegs[10]),
269130803Smarcel  context_offset (xFRegs[11]),
270130803Smarcel  context_offset (xFRegs[12]),
271130803Smarcel  context_offset (xFRegs[13]),
272130803Smarcel  context_offset (xFRegs[14]),
273130803Smarcel  context_offset (xFRegs[15]),
274130803Smarcel#elif defined(MIPS)
275130803Smarcel  context_offset (IntZero),
276130803Smarcel  context_offset (IntAt),
277130803Smarcel  context_offset (IntV0),
278130803Smarcel  context_offset (IntV1),
279130803Smarcel  context_offset (IntA0),
280130803Smarcel  context_offset (IntA1),
281130803Smarcel  context_offset (IntA2),
282130803Smarcel  context_offset (IntA3),
283130803Smarcel  context_offset (IntT0),
284130803Smarcel  context_offset (IntT1),
285130803Smarcel  context_offset (IntT2),
286130803Smarcel  context_offset (IntT3),
287130803Smarcel  context_offset (IntT4),
288130803Smarcel  context_offset (IntT5),
289130803Smarcel  context_offset (IntT6),
290130803Smarcel  context_offset (IntT7),
291130803Smarcel  context_offset (IntS0),
292130803Smarcel  context_offset (IntS1),
293130803Smarcel  context_offset (IntS2),
294130803Smarcel  context_offset (IntS3),
295130803Smarcel  context_offset (IntS4),
296130803Smarcel  context_offset (IntS5),
297130803Smarcel  context_offset (IntS6),
298130803Smarcel  context_offset (IntS7),
299130803Smarcel  context_offset (IntT8),
300130803Smarcel  context_offset (IntT9),
301130803Smarcel  context_offset (IntK0),
302130803Smarcel  context_offset (IntK1),
303130803Smarcel  context_offset (IntGp),
304130803Smarcel  context_offset (IntSp),
305130803Smarcel  context_offset (IntS8),
306130803Smarcel  context_offset (IntRa),
307130803Smarcel  context_offset (Psr),
308130803Smarcel  context_offset (IntLo),
309130803Smarcel  context_offset (IntHi),
310130803Smarcel  -1,				/* bad */
311130803Smarcel  -1,				/* cause */
312130803Smarcel  context_offset (Fir),
313130803Smarcel  context_offset (FltF0),
314130803Smarcel  context_offset (FltF1),
315130803Smarcel  context_offset (FltF2),
316130803Smarcel  context_offset (FltF3),
317130803Smarcel  context_offset (FltF4),
318130803Smarcel  context_offset (FltF5),
319130803Smarcel  context_offset (FltF6),
320130803Smarcel  context_offset (FltF7),
321130803Smarcel  context_offset (FltF8),
322130803Smarcel  context_offset (FltF9),
323130803Smarcel  context_offset (FltF10),
324130803Smarcel  context_offset (FltF11),
325130803Smarcel  context_offset (FltF12),
326130803Smarcel  context_offset (FltF13),
327130803Smarcel  context_offset (FltF14),
328130803Smarcel  context_offset (FltF15),
329130803Smarcel  context_offset (FltF16),
330130803Smarcel  context_offset (FltF17),
331130803Smarcel  context_offset (FltF18),
332130803Smarcel  context_offset (FltF19),
333130803Smarcel  context_offset (FltF20),
334130803Smarcel  context_offset (FltF21),
335130803Smarcel  context_offset (FltF22),
336130803Smarcel  context_offset (FltF23),
337130803Smarcel  context_offset (FltF24),
338130803Smarcel  context_offset (FltF25),
339130803Smarcel  context_offset (FltF26),
340130803Smarcel  context_offset (FltF27),
341130803Smarcel  context_offset (FltF28),
342130803Smarcel  context_offset (FltF29),
343130803Smarcel  context_offset (FltF30),
344130803Smarcel  context_offset (FltF31),
345130803Smarcel  context_offset (Fsr),
346130803Smarcel  context_offset (Fir),
347130803Smarcel  -1,				/* fp */
348130803Smarcel#elif defined(ARM)
349130803Smarcel  context_offset (R0),
350130803Smarcel  context_offset (R1),
351130803Smarcel  context_offset (R2),
352130803Smarcel  context_offset (R3),
353130803Smarcel  context_offset (R4),
354130803Smarcel  context_offset (R5),
355130803Smarcel  context_offset (R6),
356130803Smarcel  context_offset (R7),
357130803Smarcel  context_offset (R8),
358130803Smarcel  context_offset (R9),
359130803Smarcel  context_offset (R10),
360130803Smarcel  context_offset (R11),
361130803Smarcel  context_offset (R12),
362130803Smarcel  context_offset (Sp),
363130803Smarcel  context_offset (Lr),
364130803Smarcel  context_offset (Pc),
365130803Smarcel  -1,
366130803Smarcel  -1,
367130803Smarcel  -1,
368130803Smarcel  -1,
369130803Smarcel  -1,
370130803Smarcel  -1,
371130803Smarcel  -1,
372130803Smarcel  -1,
373130803Smarcel  -1,
374130803Smarcel  context_offset (Psr),
375130803Smarcel#endif
376130803Smarcel  -1
377130803Smarcel};
378130803Smarcel
379130803Smarcel/* Return a pointer into a CONTEXT field indexed by gdb register number.
380130803Smarcel   Return a pointer to an address pointing to zero if there is no
381130803Smarcel   corresponding CONTEXT field for the given register number.
382130803Smarcel */
383130803Smarcelstatic ULONG *
384130803Smarcelregptr (LPCONTEXT c, int r)
385130803Smarcel{
386130803Smarcel  static ULONG zero = 0;
387130803Smarcel  ULONG *p;
388130803Smarcel  if (mappings[r] < 0)
389130803Smarcel    p = &zero;
390130803Smarcel  else
391130803Smarcel    p = (ULONG *) (((char *) c) + mappings[r]);
392130803Smarcel  return p;
393130803Smarcel}
394130803Smarcel
395130803Smarcel/******************** Beginning of stub interface ********************/
396130803Smarcel
397130803Smarcel/* Stub interface description:
398130803Smarcel
399130803Smarcel   The Windows CE stub implements a crude RPC.  The hand-held device
400130803Smarcel   connects to gdb using port 7000.  gdb and the stub then communicate
401130803Smarcel   using packets where:
402130803Smarcel
403130803Smarcel   byte 0:              command id (e.g. Create Process)
404130803Smarcel
405130803Smarcel   byte 1-4:    DWORD
406130803Smarcel
407130803Smarcel   byte 1-2:    WORD
408130803Smarcel
409130803Smarcel   byte 1-2:    length
410130803Smarcel   byte 3-n:    arbitrary memory.
411130803Smarcel
412130803Smarcel   The interface is deterministic, i.e., if the stub expects a DWORD then
413130803Smarcel   the gdb server should send a DWORD.
414130803Smarcel */
415130803Smarcel
416130803Smarcel/* Note:  In the functions below, the `huh' parameter is a string passed from the
417130803Smarcel   function containing a descriptive string concerning the current operation.
418130803Smarcel   This is used for error reporting.
419130803Smarcel
420130803Smarcel   The 'what' parameter is a command id as found in wince-stub.h.
421130803Smarcel
422130803Smarcel   Hopefully, the rest of the parameters are self-explanatory.
423130803Smarcel */
424130803Smarcel
425130803Smarcelstatic int s;			/* communication socket */
426130803Smarcel
427130803Smarcel/* v-style interface for handling varying argyment list error messages.
428130803Smarcel   Displays the error message in a dialog box and exits when user clicks
429130803Smarcel   on OK. */
430130803Smarcelstatic void
431130803Smarcelvstub_error (LPCSTR fmt, va_list * args)
432130803Smarcel{
433130803Smarcel  char buf[4096];
434130803Smarcel  vsprintf (buf, fmt, args);
435130803Smarcel  s = -1;
436130803Smarcel  error ("%s", buf);
437130803Smarcel}
438130803Smarcel
439130803Smarcel/* The standard way to display an error message and exit. */
440130803Smarcelstatic void
441130803Smarcelstub_error (LPCSTR fmt,...)
442130803Smarcel{
443130803Smarcel  va_list args;
444130803Smarcel  va_start (args, fmt);
445130803Smarcel  vstub_error (fmt, args);
446130803Smarcel}
447130803Smarcel
448130803Smarcel/* Standard "oh well" can't communicate error.  Someday this might attempt
449130803Smarcel   synchronization. */
450130803Smarcelstatic void
451130803Smarcelattempt_resync (LPCSTR huh, int s)
452130803Smarcel{
453130803Smarcel  stub_error ("lost synchronization with target attempting %s", huh);
454130803Smarcel}
455130803Smarcel
456130803Smarcel/* Read arbitrary stuff from a socket. */
457130803Smarcelstatic int
458130803Smarcelsockread (LPCSTR huh, int s, void *str, size_t n)
459130803Smarcel{
460130803Smarcel  for (;;)
461130803Smarcel    {
462130803Smarcel      if (recv (s, str, n, 0) == n)
463130803Smarcel	return n;
464130803Smarcel      attempt_resync (huh, s);
465130803Smarcel    }
466130803Smarcel}
467130803Smarcel
468130803Smarcel/* Write arbitrary stuff to a socket. */
469130803Smarcelstatic int
470130803Smarcelsockwrite (LPCSTR huh, const void *str, size_t n)
471130803Smarcel{
472130803Smarcel  for (;;)
473130803Smarcel    {
474130803Smarcel      if (send (s, str, n, 0) == n)
475130803Smarcel	return n;
476130803Smarcel      attempt_resync (huh, s);
477130803Smarcel    }
478130803Smarcel}
479130803Smarcel
480130803Smarcel/* Output an id/dword to the host */
481130803Smarcelstatic void
482130803Smarcelputdword (LPCSTR huh, gdb_wince_id what, DWORD n)
483130803Smarcel{
484130803Smarcel  if (sockwrite (huh, &what, sizeof (what)) != sizeof (what))
485130803Smarcel    stub_error ("error writing record id to host for %s", huh);
486130803Smarcel  if (sockwrite (huh, &n, sizeof (n)) != sizeof (n))
487130803Smarcel    stub_error ("error writing %s to host.", huh);
488130803Smarcel}
489130803Smarcel
490130803Smarcel/* Output an id/word to the host */
491130803Smarcelstatic void
492130803Smarcelputword (LPCSTR huh, gdb_wince_id what, WORD n)
493130803Smarcel{
494130803Smarcel  if (sockwrite (huh, &what, sizeof (what)) != sizeof (what))
495130803Smarcel    stub_error ("error writing record id to host for %s", huh);
496130803Smarcel  if (sockwrite (huh, &n, sizeof (n)) != sizeof (n))
497130803Smarcel    stub_error ("error writing %s host.", huh);
498130803Smarcel}
499130803Smarcel
500130803Smarcel/* Convenience define for outputting a "gdb_wince_len" type. */
501130803Smarcel#define putlen(huh, what, n) putword((huh), (what), (gdb_wince_len) (n))
502130803Smarcel
503130803Smarcel/* Put an arbitrary block of memory to the gdb host.  This comes in
504130803Smarcel   two chunks an id/dword representing the length and the stream of memory
505130803Smarcel   itself. */
506130803Smarcelstatic void
507130803Smarcelputmemory (LPCSTR huh, gdb_wince_id what, const void *mem, gdb_wince_len len)
508130803Smarcel{
509130803Smarcel  putlen (huh, what, len);
510130803Smarcel  if (((short) len > 0) && sockwrite (huh, mem, len) != len)
511130803Smarcel    stub_error ("error writing %s to host.", huh);
512130803Smarcel}
513130803Smarcel
514130803Smarcel/* Output the result of an operation to the host.  If res != 0, sends a block of
515130803Smarcel   memory starting at mem of len bytes.  If res == 0, sends -GetLastError () and
516130803Smarcel   avoids sending the mem. */
517130803Smarcelstatic DWORD
518130803Smarcelgetdword (LPCSTR huh, gdb_wince_id what_this)
519130803Smarcel{
520130803Smarcel  DWORD n;
521130803Smarcel  gdb_wince_id what;
522130803Smarcel  do
523130803Smarcel    if (sockread (huh, s, &what, sizeof (what)) != sizeof (what))
524130803Smarcel      stub_error ("error getting record type from host - %s.", huh);
525130803Smarcel  while (what_this != what);
526130803Smarcel
527130803Smarcel  if (sockread (huh, s, &n, sizeof (n)) != sizeof (n))
528130803Smarcel    stub_error ("error getting %s from host.", huh);
529130803Smarcel
530130803Smarcel  return n;
531130803Smarcel}
532130803Smarcel
533130803Smarcel/* Get a an ID (possibly) and a WORD from the host gdb.
534130803Smarcel   Don't bother with the id if the main loop has already
535130803Smarcel   read it. */
536130803Smarcelstatic WORD
537130803Smarcelgetword (LPCSTR huh, gdb_wince_id what_this)
538130803Smarcel{
539130803Smarcel  WORD n;
540130803Smarcel  gdb_wince_id what;
541130803Smarcel  do
542130803Smarcel    if (sockread (huh, s, &what, sizeof (what)) != sizeof (what))
543130803Smarcel      stub_error ("error getting record type from host - %s.", huh);
544130803Smarcel  while (what_this != what);
545130803Smarcel
546130803Smarcel  if (sockread (huh, s, &n, sizeof (n)) != sizeof (n))
547130803Smarcel    stub_error ("error getting %s from host.", huh);
548130803Smarcel
549130803Smarcel  return n;
550130803Smarcel}
551130803Smarcel
552130803Smarcel/* Handy defines for getting/putting various types of values. */
553130803Smarcel#define gethandle(huh, what) (HANDLE) getdword ((huh), (what))
554130803Smarcel#define getpvoid(huh, what) (LPVOID) getdword ((huh), (what))
555130803Smarcel#define getlen(huh, what) (gdb_wince_len) getword ((huh), (what))
556130803Smarcel#define puthandle(huh, what, h) putdword ((huh), (what), (DWORD) (h))
557130803Smarcel#define putpvoid(huh, what, p) putdword ((huh), (what), (DWORD) (p))
558130803Smarcel
559130803Smarcel/* Retrieve the result of an operation from the stub.  If nbytes < 0) then nbytes
560130803Smarcel   is actually an error and nothing else follows.  Use SetLastError to remember this.
561130803Smarcel   if nbytes > 0, retrieve a block of *nbytes into buf.
562130803Smarcel */
563130803Smarcelint
564130803Smarcelgetresult (LPCSTR huh, gdb_wince_id what, LPVOID buf, gdb_wince_len * nbytes)
565130803Smarcel{
566130803Smarcel  gdb_wince_len dummy;
567130803Smarcel  if (nbytes == NULL)
568130803Smarcel    nbytes = &dummy;
569130803Smarcel
570130803Smarcel  *nbytes = getlen (huh, what);
571130803Smarcel
572130803Smarcel  if ((short) *nbytes < 0)
573130803Smarcel    {
574130803Smarcel      SetLastError (-(short) *nbytes);
575130803Smarcel      return 0;
576130803Smarcel    }
577130803Smarcel
578130803Smarcel  if ((gdb_wince_len) sockread (huh, s, buf, *nbytes) != *nbytes)
579130803Smarcel    stub_error ("couldn't read information from wince stub - %s", huh);
580130803Smarcel
581130803Smarcel  return 1;
582130803Smarcel}
583130803Smarcel
584130803Smarcel/* Convert "narrow" string to "wide".  Manipulates a buffer ring of 8
585130803Smarcel   buffers which hold the translated string.  This is an arbitrary limit
586130803Smarcel   but it is approximately double the current needs of this module.
587130803Smarcel */
588130803SmarcelLPWSTR
589130803Smarceltowide (const char *s, gdb_wince_len * out_len)
590130803Smarcel{
591130803Smarcel  static int n = -1;
592130803Smarcel  static LPWSTR outs[8] =
593130803Smarcel  {NULL /*, NULL, etc. */ };
594130803Smarcel  gdb_wince_len dummy;
595130803Smarcel
596130803Smarcel  if (!out_len)
597130803Smarcel    out_len = &dummy;
598130803Smarcel
599130803Smarcel  /* First determine the length required to hold the converted string. */
600130803Smarcel  *out_len = sizeof (WCHAR) * MultiByteToWideChar (CP_ACP, 0, s, -1, NULL, 0);
601130803Smarcel  if (!*out_len)
602130803Smarcel    return NULL;		/* The conversion failed */
603130803Smarcel
604130803Smarcel  if (++n >= (sizeof (outs) / sizeof (outs[0])))
605130803Smarcel    n = 0;			/* wrap */
606130803Smarcel
607130803Smarcel  /* Allocate space for the converted string, reusing any previously allocated
608130803Smarcel     space, if applicable. Note that if outs[n] is NULL, xrealloc will act as
609130803Smarcel     a malloc (under cygwin, at least).
610130803Smarcel   */
611130803Smarcel  outs[n] = (LPWSTR) xrealloc (outs[n], *out_len);
612130803Smarcel  memset (outs[n], 0, *out_len);
613130803Smarcel  (void) MultiByteToWideChar (CP_ACP, 0, s, -1, outs[n], *out_len);
614130803Smarcel  return outs[n];
615130803Smarcel}
616130803Smarcel
617130803Smarcel/******************** Emulation routines start here. ********************
618130803Smarcel
619130803Smarcel  The functions below are modelled after their Win32 counterparts.  They are named
620130803Smarcel  similarly to Win32 and take exactly the same arguments except where otherwise noted.
621130803Smarcel  They communicate with the stub on the hand-held device by sending their arguments
622130803Smarcel  over the socket and waiting for results from the socket.
623130803Smarcel
624130803Smarcel  There is one universal change.  In cases where a length is expected to be returned
625130803Smarcel  in a DWORD, we use a gdb_wince_len type instead.  Currently this is an unsigned short
626130803Smarcel  which is smaller than the standard Win32 DWORD.  This is done to minimize unnecessary
627130803Smarcel  traffic since the connection to Windows CE can be slow.  To change this, modify the
628130803Smarcel  typedef in wince-stub.h and change the putlen/getlen macros in this file and in
629130803Smarcel  the stub.
630130803Smarcel*/
631130803Smarcel
632130803Smarcelstatic int
633130803Smarcelcreate_process (LPSTR exec_file, LPSTR args, DWORD flags, PROCESS_INFORMATION * pi)
634130803Smarcel{
635130803Smarcel  gdb_wince_len len;
636130803Smarcel  LPWSTR buf;
637130803Smarcel
638130803Smarcel  buf = towide (exec_file, &len);
639130803Smarcel  putmemory ("CreateProcess exec_file", GDB_CREATEPROCESS, buf, len);
640130803Smarcel  buf = towide (args, &len);
641130803Smarcel  putmemory ("CreateProcess args", GDB_CREATEPROCESS, buf, len);
642130803Smarcel  putdword ("CreateProcess flags", GDB_CREATEPROCESS, flags);
643130803Smarcel  return getresult ("CreateProcess result", GDB_CREATEPROCESS, pi, NULL);
644130803Smarcel}
645130803Smarcel
646130803Smarcel/* Emulate TerminateProcess.  Don't bother with the second argument since CE
647130803Smarcel   ignores it.
648130803Smarcel */
649130803Smarcelstatic int
650130803Smarcelterminate_process (HANDLE h)
651130803Smarcel{
652130803Smarcel  gdb_wince_result res;
653130803Smarcel  if (s < 0)
654130803Smarcel    return 1;
655130803Smarcel  puthandle ("TerminateProcess handle", GDB_TERMINATEPROCESS, h);
656130803Smarcel  return getresult ("TerminateProcess result", GDB_TERMINATEPROCESS, &res, NULL);
657130803Smarcel}
658130803Smarcel
659130803Smarcelstatic int
660130803Smarcelwait_for_debug_event (DEBUG_EVENT * ev, DWORD ms)
661130803Smarcel{
662130803Smarcel  if (s < 0)
663130803Smarcel    return 1;
664130803Smarcel  putdword ("WaitForDebugEvent ms", GDB_WAITFORDEBUGEVENT, ms);
665130803Smarcel  return getresult ("WaitForDebugEvent event", GDB_WAITFORDEBUGEVENT, ev, NULL);
666130803Smarcel}
667130803Smarcel
668130803Smarcelstatic int
669130803Smarcelget_thread_context (HANDLE h, CONTEXT * c)
670130803Smarcel{
671130803Smarcel  if (s < 0)
672130803Smarcel    return 1;
673130803Smarcel  puthandle ("GetThreadContext handle", GDB_GETTHREADCONTEXT, h);
674130803Smarcel  putdword ("GetThreadContext flags", GDB_GETTHREADCONTEXT, c->ContextFlags);
675130803Smarcel  return getresult ("GetThreadContext context", GDB_GETTHREADCONTEXT, c, NULL);
676130803Smarcel}
677130803Smarcel
678130803Smarcelstatic int
679130803Smarcelset_thread_context (HANDLE h, CONTEXT * c)
680130803Smarcel{
681130803Smarcel  gdb_wince_result res;
682130803Smarcel  if (s < 0)
683130803Smarcel    return 1;
684130803Smarcel  puthandle ("SetThreadContext handle", GDB_SETTHREADCONTEXT, h);
685130803Smarcel  putmemory ("SetThreadContext context", GDB_SETTHREADCONTEXT, c, sizeof (*c));
686130803Smarcel  return getresult ("SetThreadContext context", GDB_SETTHREADCONTEXT, &res, NULL);
687130803Smarcel}
688130803Smarcel
689130803Smarcelstatic int
690130803Smarcelread_process_memory (HANDLE h, LPCVOID where, LPVOID buf, gdb_wince_len len, gdb_wince_len * nbytes)
691130803Smarcel{
692130803Smarcel  if (s < 0)
693130803Smarcel    return 1;
694130803Smarcel  puthandle ("ReadProcessMemory handle", GDB_READPROCESSMEMORY, h);
695130803Smarcel  putpvoid ("ReadProcessMemory location", GDB_READPROCESSMEMORY, where);
696130803Smarcel  putlen ("ReadProcessMemory size", GDB_READPROCESSMEMORY, len);
697130803Smarcel
698130803Smarcel  return getresult ("ReadProcessMemory buf", GDB_READPROCESSMEMORY, buf, nbytes);
699130803Smarcel}
700130803Smarcel
701130803Smarcelstatic int
702130803Smarcelwrite_process_memory (HANDLE h, LPCVOID where, LPCVOID buf, gdb_wince_len len, gdb_wince_len * nbytes)
703130803Smarcel{
704130803Smarcel  if (s < 0)
705130803Smarcel    return 1;
706130803Smarcel  puthandle ("WriteProcessMemory handle", GDB_WRITEPROCESSMEMORY, h);
707130803Smarcel  putpvoid ("WriteProcessMemory location", GDB_WRITEPROCESSMEMORY, where);
708130803Smarcel  putmemory ("WriteProcProcessMemory buf", GDB_WRITEPROCESSMEMORY, buf, len);
709130803Smarcel
710130803Smarcel  return getresult ("WriteProcessMemory result", GDB_WRITEPROCESSMEMORY, nbytes, NULL);
711130803Smarcel}
712130803Smarcel
713130803Smarcelstatic int
714130803Smarcelremote_read_bytes (CORE_ADDR memaddr, char *myaddr, int len)
715130803Smarcel{
716130803Smarcel  gdb_wince_len nbytes;
717130803Smarcel  if (!read_process_memory (current_process_handle, (LPCVOID) memaddr,
718130803Smarcel			    (LPVOID) myaddr, len, &nbytes))
719130803Smarcel    return -1;
720130803Smarcel  return nbytes;
721130803Smarcel}
722130803Smarcel
723130803Smarcelstatic int
724130803Smarcelremote_write_bytes (CORE_ADDR memaddr, char *myaddr, int len)
725130803Smarcel{
726130803Smarcel  gdb_wince_len nbytes;
727130803Smarcel  if (!write_process_memory (current_process_handle, (LPCVOID) memaddr,
728130803Smarcel			     (LPCVOID) myaddr, len, &nbytes))
729130803Smarcel    return -1;
730130803Smarcel  return nbytes;
731130803Smarcel}
732130803Smarcel
733130803Smarcel/* This is not a standard Win32 function.  It instructs the stub to return TRUE
734130803Smarcel   if the thread referenced by HANDLE h is alive.
735130803Smarcel */
736130803Smarcelstatic int
737130803Smarcelthread_alive (HANDLE h)
738130803Smarcel{
739130803Smarcel  gdb_wince_result res;
740130803Smarcel  if (s < 0)
741130803Smarcel    return 1;
742130803Smarcel  puthandle ("ThreadAlive handle", GDB_THREADALIVE, h);
743130803Smarcel  return getresult ("ThreadAlive result", GDB_THREADALIVE, &res, NULL);
744130803Smarcel}
745130803Smarcel
746130803Smarcelstatic int
747130803Smarcelsuspend_thread (HANDLE h)
748130803Smarcel{
749130803Smarcel  if (s < 0)
750130803Smarcel    return 1;
751130803Smarcel  puthandle ("SuspendThread handle", GDB_SUSPENDTHREAD, h);
752130803Smarcel  return (int) getdword ("SuspendThread result", GDB_SUSPENDTHREAD);
753130803Smarcel}
754130803Smarcel
755130803Smarcelstatic int
756130803Smarcelresume_thread (HANDLE h)
757130803Smarcel{
758130803Smarcel  if (s < 0)
759130803Smarcel    return 1;
760130803Smarcel  puthandle ("ResumeThread handle", GDB_RESUMETHREAD, h);
761130803Smarcel  return (int) getdword ("SuspendThread result", GDB_RESUMETHREAD);
762130803Smarcel}
763130803Smarcel
764130803Smarcelstatic int
765130803Smarcelcontinue_debug_event (DWORD pid, DWORD tid, DWORD status)
766130803Smarcel{
767130803Smarcel  gdb_wince_result res;
768130803Smarcel  if (s < 0)
769130803Smarcel    return 0;
770130803Smarcel  putdword ("ContinueDebugEvent pid", GDB_CONTINUEDEBUGEVENT, pid);
771130803Smarcel  putdword ("ContinueDebugEvent tid", GDB_CONTINUEDEBUGEVENT, tid);
772130803Smarcel  putdword ("ContinueDebugEvent status", GDB_CONTINUEDEBUGEVENT, status);
773130803Smarcel  return getresult ("ContinueDebugEvent result", GDB_CONTINUEDEBUGEVENT, &res, NULL);
774130803Smarcel}
775130803Smarcel
776130803Smarcelstatic int
777130803Smarcelclose_handle (HANDLE h)
778130803Smarcel{
779130803Smarcel  gdb_wince_result res;
780130803Smarcel  if (s < 0)
781130803Smarcel    return 1;
782130803Smarcel  puthandle ("CloseHandle handle", GDB_CLOSEHANDLE, h);
783130803Smarcel  return (int) getresult ("CloseHandle result", GDB_CLOSEHANDLE, &res, NULL);
784130803Smarcel}
785130803Smarcel
786130803Smarcel/* This is not a standard Win32 interface.  This function tells the stub
787130803Smarcel   to terminate.
788130803Smarcel */
789130803Smarcelstatic void
790130803Smarcelstop_stub (void)
791130803Smarcel{
792130803Smarcel  if (s < 0)
793130803Smarcel    return;
794130803Smarcel  (void) putdword ("Stopping gdb stub", GDB_STOPSTUB, 0);
795130803Smarcel  s = -1;
796130803Smarcel}
797130803Smarcel
798130803Smarcel/******************** End of emulation routines. ********************/
799130803Smarcel/******************** End of stub interface ********************/
800130803Smarcel
801130803Smarcel#define check_for_step(a, x) (x)
802130803Smarcel
803130803Smarcel#ifdef MIPS
804130803Smarcelstatic void
805130803SmarcelundoSStep (thread_info * th)
806130803Smarcel{
807130803Smarcel  if (th->stepped)
808130803Smarcel    {
809130803Smarcel      memory_remove_breakpoint (th->step_pc, (void *) &th->step_prev);
810130803Smarcel      th->stepped = 0;
811130803Smarcel    }
812130803Smarcel}
813130803Smarcel
814130803Smarcelvoid
815130803Smarcelwince_software_single_step (enum target_signal ignore,
816130803Smarcel			    int insert_breakpoints_p)
817130803Smarcel{
818130803Smarcel  unsigned long pc;
819130803Smarcel  thread_info *th = current_thread;	/* Info on currently selected thread */
820130803Smarcel  CORE_ADDR mips_next_pc (CORE_ADDR pc);
821130803Smarcel
822130803Smarcel  if (!insert_breakpoints_p)
823130803Smarcel    {
824130803Smarcel      undoSStep (th);
825130803Smarcel      return;
826130803Smarcel    }
827130803Smarcel
828130803Smarcel  th->stepped = 1;
829130803Smarcel  pc = read_register (PC_REGNUM);
830130803Smarcel  th->step_pc = mips_next_pc (pc);
831130803Smarcel  th->step_prev = 0;
832130803Smarcel  memory_insert_breakpoint (th->step_pc, (void *) &th->step_prev);
833130803Smarcel  return;
834130803Smarcel}
835130803Smarcel#elif SHx
836130803Smarcel/* Renesas SH architecture instruction encoding masks */
837130803Smarcel
838130803Smarcel#define COND_BR_MASK   0xff00
839130803Smarcel#define UCOND_DBR_MASK 0xe000
840130803Smarcel#define UCOND_RBR_MASK 0xf0df
841130803Smarcel#define TRAPA_MASK     0xff00
842130803Smarcel
843130803Smarcel#define COND_DISP      0x00ff
844130803Smarcel#define UCOND_DISP     0x0fff
845130803Smarcel#define UCOND_REG      0x0f00
846130803Smarcel
847130803Smarcel/* Renesas SH instruction opcodes */
848130803Smarcel
849130803Smarcel#define BF_INSTR       0x8b00
850130803Smarcel#define BT_INSTR       0x8900
851130803Smarcel#define BRA_INSTR      0xa000
852130803Smarcel#define BSR_INSTR      0xb000
853130803Smarcel#define JMP_INSTR      0x402b
854130803Smarcel#define JSR_INSTR      0x400b
855130803Smarcel#define RTS_INSTR      0x000b
856130803Smarcel#define RTE_INSTR      0x002b
857130803Smarcel#define TRAPA_INSTR    0xc300
858130803Smarcel#define SSTEP_INSTR    0xc3ff
859130803Smarcel
860130803Smarcel
861130803Smarcel#define T_BIT_MASK     0x0001
862130803Smarcel
863130803Smarcelstatic CORE_ADDR
864130803Smarcelsh_get_next_pc (CONTEXT *c)
865130803Smarcel{
866130803Smarcel  short *instrMem;
867130803Smarcel  int displacement;
868130803Smarcel  int reg;
869130803Smarcel  unsigned short opcode;
870130803Smarcel
871130803Smarcel  instrMem = (short *) c->Fir;
872130803Smarcel
873130803Smarcel  opcode = read_memory_integer ((CORE_ADDR) c->Fir, sizeof (opcode));
874130803Smarcel
875130803Smarcel  if ((opcode & COND_BR_MASK) == BT_INSTR)
876130803Smarcel    {
877130803Smarcel      if (c->Psr & T_BIT_MASK)
878130803Smarcel	{
879130803Smarcel	  displacement = (opcode & COND_DISP) << 1;
880130803Smarcel	  if (displacement & 0x80)
881130803Smarcel	    displacement |= 0xffffff00;
882130803Smarcel	  /*
883130803Smarcel	     * Remember PC points to second instr.
884130803Smarcel	     * after PC of branch ... so add 4
885130803Smarcel	   */
886130803Smarcel	  instrMem = (short *) (c->Fir + displacement + 4);
887130803Smarcel	}
888130803Smarcel      else
889130803Smarcel	instrMem += 1;
890130803Smarcel    }
891130803Smarcel  else if ((opcode & COND_BR_MASK) == BF_INSTR)
892130803Smarcel    {
893130803Smarcel      if (c->Psr & T_BIT_MASK)
894130803Smarcel	instrMem += 1;
895130803Smarcel      else
896130803Smarcel	{
897130803Smarcel	  displacement = (opcode & COND_DISP) << 1;
898130803Smarcel	  if (displacement & 0x80)
899130803Smarcel	    displacement |= 0xffffff00;
900130803Smarcel	  /*
901130803Smarcel	     * Remember PC points to second instr.
902130803Smarcel	     * after PC of branch ... so add 4
903130803Smarcel	   */
904130803Smarcel	  instrMem = (short *) (c->Fir + displacement + 4);
905130803Smarcel	}
906130803Smarcel    }
907130803Smarcel  else if ((opcode & UCOND_DBR_MASK) == BRA_INSTR)
908130803Smarcel    {
909130803Smarcel      displacement = (opcode & UCOND_DISP) << 1;
910130803Smarcel      if (displacement & 0x0800)
911130803Smarcel	displacement |= 0xfffff000;
912130803Smarcel
913130803Smarcel      /*
914130803Smarcel	 * Remember PC points to second instr.
915130803Smarcel	 * after PC of branch ... so add 4
916130803Smarcel       */
917130803Smarcel      instrMem = (short *) (c->Fir + displacement + 4);
918130803Smarcel    }
919130803Smarcel  else if ((opcode & UCOND_RBR_MASK) == JSR_INSTR)
920130803Smarcel    {
921130803Smarcel      reg = (char) ((opcode & UCOND_REG) >> 8);
922130803Smarcel
923130803Smarcel      instrMem = (short *) *regptr (c, reg);
924130803Smarcel    }
925130803Smarcel  else if (opcode == RTS_INSTR)
926130803Smarcel    instrMem = (short *) c->PR;
927130803Smarcel  else if (opcode == RTE_INSTR)
928130803Smarcel    instrMem = (short *) *regptr (c, 15);
929130803Smarcel  else if ((opcode & TRAPA_MASK) == TRAPA_INSTR)
930130803Smarcel    instrMem = (short *) ((opcode & ~TRAPA_MASK) << 2);
931130803Smarcel  else
932130803Smarcel    instrMem += 1;
933130803Smarcel
934130803Smarcel  return (CORE_ADDR) instrMem;
935130803Smarcel}
936130803Smarcel/* Single step (in a painstaking fashion) by inspecting the current
937130803Smarcel   instruction and setting a breakpoint on the "next" instruction
938130803Smarcel   which would be executed.  This code hails from sh-stub.c.
939130803Smarcel */
940130803Smarcelstatic void
941130803SmarcelundoSStep (thread_info * th)
942130803Smarcel{
943130803Smarcel  if (th->stepped)
944130803Smarcel    {
945130803Smarcel      memory_remove_breakpoint (th->step_pc, (void *) &th->step_prev);
946130803Smarcel      th->stepped = 0;
947130803Smarcel    }
948130803Smarcel  return;
949130803Smarcel}
950130803Smarcel
951130803Smarcel/* Single step (in a painstaking fashion) by inspecting the current
952130803Smarcel   instruction and setting a breakpoint on the "next" instruction
953130803Smarcel   which would be executed.  This code hails from sh-stub.c.
954130803Smarcel */
955130803Smarcelvoid
956130803Smarcelwince_software_single_step (enum target_signal ignore,
957130803Smarcel			    int insert_breakpoints_p)
958130803Smarcel{
959130803Smarcel  thread_info *th = current_thread;	/* Info on currently selected thread */
960130803Smarcel
961130803Smarcel  if (!insert_breakpoints_p)
962130803Smarcel    {
963130803Smarcel      undoSStep (th);
964130803Smarcel      return;
965130803Smarcel    }
966130803Smarcel
967130803Smarcel  th->stepped = 1;
968130803Smarcel  th->step_pc = sh_get_next_pc (&th->context);
969130803Smarcel  th->step_prev = 0;
970130803Smarcel  memory_insert_breakpoint (th->step_pc, (void *) &th->step_prev);
971130803Smarcel  return;
972130803Smarcel}
973130803Smarcel#elif defined (ARM)
974130803Smarcel#undef check_for_step
975130803Smarcel
976130803Smarcelstatic enum target_signal
977130803Smarcelcheck_for_step (DEBUG_EVENT *ev, enum target_signal x)
978130803Smarcel{
979130803Smarcel  thread_info *th = thread_rec (ev->dwThreadId, 1);
980130803Smarcel
981130803Smarcel  if (th->stepped &&
982130803Smarcel      th->step_pc == (CORE_ADDR) ev->u.Exception.ExceptionRecord.ExceptionAddress)
983130803Smarcel    return TARGET_SIGNAL_TRAP;
984130803Smarcel  else
985130803Smarcel    return x;
986130803Smarcel}
987130803Smarcel
988130803Smarcel/* Single step (in a painstaking fashion) by inspecting the current
989130803Smarcel   instruction and setting a breakpoint on the "next" instruction
990130803Smarcel   which would be executed.  This code hails from sh-stub.c.
991130803Smarcel */
992130803Smarcelstatic void
993130803SmarcelundoSStep (thread_info * th)
994130803Smarcel{
995130803Smarcel  if (th->stepped)
996130803Smarcel    {
997130803Smarcel      memory_remove_breakpoint (th->step_pc, (void *) &th->step_prev);
998130803Smarcel      th->stepped = 0;
999130803Smarcel    }
1000130803Smarcel}
1001130803Smarcel
1002130803Smarcelvoid
1003130803Smarcelwince_software_single_step (enum target_signal ignore,
1004130803Smarcel			    int insert_breakpoints_p)
1005130803Smarcel{
1006130803Smarcel  unsigned long pc;
1007130803Smarcel  thread_info *th = current_thread;	/* Info on currently selected thread */
1008130803Smarcel  CORE_ADDR mips_next_pc (CORE_ADDR pc);
1009130803Smarcel
1010130803Smarcel  if (!insert_breakpoints_p)
1011130803Smarcel    {
1012130803Smarcel      undoSStep (th);
1013130803Smarcel      return;
1014130803Smarcel    }
1015130803Smarcel
1016130803Smarcel  th->stepped = 1;
1017130803Smarcel  pc = read_register (PC_REGNUM);
1018130803Smarcel  th->step_pc = arm_get_next_pc (pc);
1019130803Smarcel  th->step_prev = 0;
1020130803Smarcel  memory_insert_breakpoint (th->step_pc, (void *) &th->step_prev);
1021130803Smarcel  return;
1022130803Smarcel}
1023130803Smarcel#endif
1024130803Smarcel
1025130803Smarcel/* Find a thread record given a thread id.
1026130803Smarcel   If get_context then also retrieve the context for this
1027130803Smarcel   thread. */
1028130803Smarcelstatic thread_info *
1029130803Smarcelthread_rec (DWORD id, int get_context)
1030130803Smarcel{
1031130803Smarcel  thread_info *th;
1032130803Smarcel
1033130803Smarcel  for (th = &thread_head; (th = th->next) != NULL;)
1034130803Smarcel    if (th->id == id)
1035130803Smarcel      {
1036130803Smarcel	if (!th->suspend_count && get_context)
1037130803Smarcel	  {
1038130803Smarcel	    if (get_context > 0 && th != this_thread)
1039130803Smarcel	      th->suspend_count = suspend_thread (th->h) + 1;
1040130803Smarcel	    else if (get_context < 0)
1041130803Smarcel	      th->suspend_count = -1;
1042130803Smarcel
1043130803Smarcel	    th->context.ContextFlags = CONTEXT_DEBUGGER;
1044130803Smarcel	    get_thread_context (th->h, &th->context);
1045130803Smarcel	  }
1046130803Smarcel	return th;
1047130803Smarcel      }
1048130803Smarcel
1049130803Smarcel  return NULL;
1050130803Smarcel}
1051130803Smarcel
1052130803Smarcel/* Add a thread to the thread list */
1053130803Smarcelstatic thread_info *
1054130803Smarcelchild_add_thread (DWORD id, HANDLE h)
1055130803Smarcel{
1056130803Smarcel  thread_info *th;
1057130803Smarcel
1058130803Smarcel  if ((th = thread_rec (id, FALSE)))
1059130803Smarcel    return th;
1060130803Smarcel
1061130803Smarcel  th = (thread_info *) xmalloc (sizeof (*th));
1062130803Smarcel  memset (th, 0, sizeof (*th));
1063130803Smarcel  th->id = id;
1064130803Smarcel  th->h = h;
1065130803Smarcel  th->next = thread_head.next;
1066130803Smarcel  thread_head.next = th;
1067130803Smarcel  add_thread (id);
1068130803Smarcel  return th;
1069130803Smarcel}
1070130803Smarcel
1071130803Smarcel/* Clear out any old thread list and reintialize it to a
1072130803Smarcel   pristine state. */
1073130803Smarcelstatic void
1074130803Smarcelchild_init_thread_list (void)
1075130803Smarcel{
1076130803Smarcel  thread_info *th = &thread_head;
1077130803Smarcel
1078130803Smarcel  DEBUG_EVENTS (("gdb: child_init_thread_list\n"));
1079130803Smarcel  init_thread_list ();
1080130803Smarcel  while (th->next != NULL)
1081130803Smarcel    {
1082130803Smarcel      thread_info *here = th->next;
1083130803Smarcel      th->next = here->next;
1084130803Smarcel      (void) close_handle (here->h);
1085130803Smarcel      xfree (here);
1086130803Smarcel    }
1087130803Smarcel}
1088130803Smarcel
1089130803Smarcel/* Delete a thread from the list of threads */
1090130803Smarcelstatic void
1091130803Smarcelchild_delete_thread (DWORD id)
1092130803Smarcel{
1093130803Smarcel  thread_info *th;
1094130803Smarcel
1095130803Smarcel  if (info_verbose)
1096130803Smarcel    printf_unfiltered ("[Deleting %s]\n", target_pid_to_str (id));
1097130803Smarcel  delete_thread (id);
1098130803Smarcel
1099130803Smarcel  for (th = &thread_head;
1100130803Smarcel       th->next != NULL && th->next->id != id;
1101130803Smarcel       th = th->next)
1102130803Smarcel    continue;
1103130803Smarcel
1104130803Smarcel  if (th->next != NULL)
1105130803Smarcel    {
1106130803Smarcel      thread_info *here = th->next;
1107130803Smarcel      th->next = here->next;
1108130803Smarcel      close_handle (here->h);
1109130803Smarcel      xfree (here);
1110130803Smarcel    }
1111130803Smarcel}
1112130803Smarcel
1113130803Smarcelstatic void
1114130803Smarcelcheck (BOOL ok, const char *file, int line)
1115130803Smarcel{
1116130803Smarcel  if (!ok)
1117130803Smarcel    printf_filtered ("error return %s:%d was %d\n", file, line, GetLastError ());
1118130803Smarcel}
1119130803Smarcel
1120130803Smarcelstatic void
1121130803Smarceldo_child_fetch_inferior_registers (int r)
1122130803Smarcel{
1123130803Smarcel  if (r >= 0)
1124130803Smarcel    {
1125130803Smarcel      supply_register (r, (char *) regptr (&current_thread->context, r));
1126130803Smarcel    }
1127130803Smarcel  else
1128130803Smarcel    {
1129130803Smarcel      for (r = 0; r < NUM_REGS; r++)
1130130803Smarcel	do_child_fetch_inferior_registers (r);
1131130803Smarcel    }
1132130803Smarcel}
1133130803Smarcel
1134130803Smarcelstatic void
1135130803Smarcelchild_fetch_inferior_registers (int r)
1136130803Smarcel{
1137130803Smarcel  current_thread = thread_rec (PIDGET (inferior_ptid), TRUE);
1138130803Smarcel  do_child_fetch_inferior_registers (r);
1139130803Smarcel}
1140130803Smarcel
1141130803Smarcelstatic void
1142130803Smarceldo_child_store_inferior_registers (int r)
1143130803Smarcel{
1144130803Smarcel  if (r >= 0)
1145130803Smarcel    deprecated_read_register_gen (r, ((char *) &current_thread->context) + mappings[r]);
1146130803Smarcel  else
1147130803Smarcel    {
1148130803Smarcel      for (r = 0; r < NUM_REGS; r++)
1149130803Smarcel	do_child_store_inferior_registers (r);
1150130803Smarcel    }
1151130803Smarcel}
1152130803Smarcel
1153130803Smarcel/* Store a new register value into the current thread context */
1154130803Smarcelstatic void
1155130803Smarcelchild_store_inferior_registers (int r)
1156130803Smarcel{
1157130803Smarcel  current_thread = thread_rec (PIDGET (inferior_ptid), TRUE);
1158130803Smarcel  do_child_store_inferior_registers (r);
1159130803Smarcel}
1160130803Smarcel
1161130803Smarcel/* Wait for child to do something.  Return pid of child, or -1 in case
1162130803Smarcel   of error; store status through argument pointer OURSTATUS.  */
1163130803Smarcel
1164130803Smarcelstatic int
1165130803Smarcelhandle_load_dll (void *dummy)
1166130803Smarcel{
1167130803Smarcel  LOAD_DLL_DEBUG_INFO *event = &current_event.u.LoadDll;
1168130803Smarcel  char dll_buf[MAX_PATH + 1];
1169130803Smarcel  char *p, *bufp, *imgp, *dll_name, *dll_basename;
1170130803Smarcel  int len;
1171130803Smarcel
1172130803Smarcel  dll_buf[0] = dll_buf[sizeof (dll_buf) - 1] = '\0';
1173130803Smarcel  if (!event->lpImageName)
1174130803Smarcel    return 1;
1175130803Smarcel
1176130803Smarcel  len = 0;
1177130803Smarcel  for (bufp = dll_buf, imgp = event->lpImageName;
1178130803Smarcel       bufp < dll_buf + sizeof (dll_buf);
1179130803Smarcel       bufp += 16, imgp += 16)
1180130803Smarcel    {
1181130803Smarcel      gdb_wince_len nbytes = 0;
1182130803Smarcel      (void) read_process_memory (current_process_handle,
1183130803Smarcel				  imgp, bufp, 16, &nbytes);
1184130803Smarcel
1185130803Smarcel      if (!nbytes && bufp == dll_buf)
1186130803Smarcel	return 1;		/* couldn't read it */
1187130803Smarcel      for (p = bufp; p < bufp + nbytes; p++)
1188130803Smarcel	{
1189130803Smarcel	  len++;
1190130803Smarcel	  if (*p == '\0')
1191130803Smarcel	    goto out;
1192130803Smarcel	  if (event->fUnicode)
1193130803Smarcel	    p++;
1194130803Smarcel	}
1195130803Smarcel      if (!nbytes)
1196130803Smarcel	break;
1197130803Smarcel    }
1198130803Smarcel
1199130803Smarcelout:
1200130803Smarcel  if (!len)
1201130803Smarcel    return 1;
1202130803Smarcel#if 0
1203130803Smarcel  dll_buf[len] = '\0';
1204130803Smarcel#endif
1205130803Smarcel  dll_name = alloca (len);
1206130803Smarcel
1207130803Smarcel  if (!dll_name)
1208130803Smarcel    return 1;
1209130803Smarcel
1210130803Smarcel  if (!event->fUnicode)
1211130803Smarcel    memcpy (dll_name, dll_buf, len);
1212130803Smarcel  else
1213130803Smarcel    WideCharToMultiByte (CP_ACP, 0, (LPCWSTR) dll_buf, len,
1214130803Smarcel			 dll_name, len, 0, 0);
1215130803Smarcel
1216130803Smarcel  while ((p = strchr (dll_name, '\\')))
1217130803Smarcel    *p = '/';
1218130803Smarcel
1219130803Smarcel  /* FIXME!! It would be nice to define one symbol which pointed to the
1220130803Smarcel     front of the dll if we can't find any symbols. */
1221130803Smarcel
1222130803Smarcel  if (!(dll_basename = strrchr (dll_name, '/')))
1223130803Smarcel    dll_basename = dll_name;
1224130803Smarcel  else
1225130803Smarcel    dll_basename++;
1226130803Smarcel
1227130803Smarcel  /* The symbols in a dll are offset by 0x1000, which is the
1228130803Smarcel     the offset from 0 of the first byte in an image - because
1229130803Smarcel     of the file header and the section alignment.
1230130803Smarcel
1231130803Smarcel     FIXME: Is this the real reason that we need the 0x1000 ? */
1232130803Smarcel
1233130803Smarcel  printf_unfiltered ("%x:%s", event->lpBaseOfDll, dll_name);
1234130803Smarcel  printf_unfiltered ("\n");
1235130803Smarcel
1236130803Smarcel  return 1;
1237130803Smarcel}
1238130803Smarcel
1239130803Smarcel/* Handle DEBUG_STRING output from child process. */
1240130803Smarcelstatic void
1241130803Smarcelhandle_output_debug_string (struct target_waitstatus *ourstatus)
1242130803Smarcel{
1243130803Smarcel  char p[256];
1244130803Smarcel  char s[255];
1245130803Smarcel  char *q;
1246130803Smarcel  gdb_wince_len nbytes_read;
1247130803Smarcel  gdb_wince_len nbytes = current_event.u.DebugString.nDebugStringLength;
1248130803Smarcel
1249130803Smarcel  if (nbytes > 255)
1250130803Smarcel    nbytes = 255;
1251130803Smarcel
1252130803Smarcel  memset (p, 0, sizeof (p));
1253130803Smarcel  if (!read_process_memory (current_process_handle,
1254130803Smarcel			    current_event.u.DebugString.lpDebugStringData,
1255130803Smarcel			    &p, nbytes, &nbytes_read)
1256130803Smarcel      || !*p)
1257130803Smarcel    return;
1258130803Smarcel
1259130803Smarcel  memset (s, 0, sizeof (s));
1260130803Smarcel  WideCharToMultiByte (CP_ACP, 0, (LPCWSTR) p, (int) nbytes_read, s,
1261130803Smarcel		       sizeof (s) - 1, NULL, NULL);
1262130803Smarcel  q = strchr (s, '\n');
1263130803Smarcel  if (q != NULL)
1264130803Smarcel    {
1265130803Smarcel      *q = '\0';
1266130803Smarcel      if (*--q = '\r')
1267130803Smarcel	*q = '\0';
1268130803Smarcel    }
1269130803Smarcel
1270130803Smarcel  warning (s);
1271130803Smarcel
1272130803Smarcel  return;
1273130803Smarcel}
1274130803Smarcel
1275130803Smarcel/* Handle target exceptions. */
1276130803Smarcelstatic int
1277130803Smarcelhandle_exception (struct target_waitstatus *ourstatus)
1278130803Smarcel{
1279130803Smarcel#if 0
1280130803Smarcel  if (current_event.u.Exception.dwFirstChance)
1281130803Smarcel    return 0;
1282130803Smarcel#endif
1283130803Smarcel
1284130803Smarcel  ourstatus->kind = TARGET_WAITKIND_STOPPED;
1285130803Smarcel
1286130803Smarcel  switch (current_event.u.Exception.ExceptionRecord.ExceptionCode)
1287130803Smarcel    {
1288130803Smarcel    case EXCEPTION_ACCESS_VIOLATION:
1289130803Smarcel      DEBUG_EXCEPT (("gdb: Target exception ACCESS_VIOLATION at 0x%08x\n",
1290130803Smarcel		     (unsigned) current_event.u.Exception.ExceptionRecord.ExceptionAddress));
1291130803Smarcel      ourstatus->value.sig = TARGET_SIGNAL_SEGV;
1292130803Smarcel      break;
1293130803Smarcel    case STATUS_STACK_OVERFLOW:
1294130803Smarcel      DEBUG_EXCEPT (("gdb: Target exception STACK_OVERFLOW at 0x%08x\n",
1295130803Smarcel		     (unsigned) current_event.u.Exception.ExceptionRecord.ExceptionAddress));
1296130803Smarcel      ourstatus->value.sig = TARGET_SIGNAL_SEGV;
1297130803Smarcel      break;
1298130803Smarcel    case EXCEPTION_BREAKPOINT:
1299130803Smarcel      DEBUG_EXCEPT (("gdb: Target exception BREAKPOINT at 0x%08x\n",
1300130803Smarcel		     (unsigned) current_event.u.Exception.ExceptionRecord.ExceptionAddress));
1301130803Smarcel      ourstatus->value.sig = TARGET_SIGNAL_TRAP;
1302130803Smarcel      break;
1303130803Smarcel    case DBG_CONTROL_C:
1304130803Smarcel      DEBUG_EXCEPT (("gdb: Target exception CONTROL_C at 0x%08x\n",
1305130803Smarcel		     (unsigned) current_event.u.Exception.ExceptionRecord.ExceptionAddress));
1306130803Smarcel      ourstatus->value.sig = TARGET_SIGNAL_INT;
1307130803Smarcel      /* User typed CTRL-C.  Continue with this status */
1308130803Smarcel      last_sig = SIGINT;	/* FIXME - should check pass state */
1309130803Smarcel      break;
1310130803Smarcel    case EXCEPTION_SINGLE_STEP:
1311130803Smarcel      DEBUG_EXCEPT (("gdb: Target exception SINGLE_STEP at 0x%08x\n",
1312130803Smarcel		     (unsigned) current_event.u.Exception.ExceptionRecord.ExceptionAddress));
1313130803Smarcel      ourstatus->value.sig = TARGET_SIGNAL_TRAP;
1314130803Smarcel      break;
1315130803Smarcel    case EXCEPTION_ILLEGAL_INSTRUCTION:
1316130803Smarcel      DEBUG_EXCEPT (("gdb: Target exception SINGLE_ILL at 0x%08x\n",
1317130803Smarcel	       current_event.u.Exception.ExceptionRecord.ExceptionAddress));
1318130803Smarcel      ourstatus->value.sig = check_for_step (&current_event, TARGET_SIGNAL_ILL);
1319130803Smarcel      break;
1320130803Smarcel    default:
1321130803Smarcel      /* This may be a structured exception handling exception.  In
1322130803Smarcel	 that case, we want to let the program try to handle it, and
1323130803Smarcel	 only break if we see the exception a second time.  */
1324130803Smarcel
1325130803Smarcel      printf_unfiltered ("gdb: unknown target exception 0x%08x at 0x%08x\n",
1326130803Smarcel		    current_event.u.Exception.ExceptionRecord.ExceptionCode,
1327130803Smarcel		current_event.u.Exception.ExceptionRecord.ExceptionAddress);
1328130803Smarcel      ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN;
1329130803Smarcel      break;
1330130803Smarcel    }
1331130803Smarcel  exception_count++;
1332130803Smarcel  return 1;
1333130803Smarcel}
1334130803Smarcel
1335130803Smarcel/* Resume all artificially suspended threads if we are continuing
1336130803Smarcel   execution */
1337130803Smarcelstatic BOOL
1338130803Smarcelchild_continue (DWORD continue_status, int id)
1339130803Smarcel{
1340130803Smarcel  int i;
1341130803Smarcel  thread_info *th;
1342130803Smarcel  BOOL res;
1343130803Smarcel
1344130803Smarcel  DEBUG_EVENTS (("ContinueDebugEvent (cpid=%d, ctid=%d, DBG_CONTINUE);\n",
1345130803Smarcel		 (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId));
1346130803Smarcel  res = continue_debug_event (current_event.dwProcessId,
1347130803Smarcel			      current_event.dwThreadId,
1348130803Smarcel			      continue_status);
1349130803Smarcel  if (res)
1350130803Smarcel    for (th = &thread_head; (th = th->next) != NULL;)
1351130803Smarcel      if (((id == -1) || (id == th->id)) && th->suspend_count)
1352130803Smarcel	{
1353130803Smarcel	  for (i = 0; i < th->suspend_count; i++)
1354130803Smarcel	    (void) resume_thread (th->h);
1355130803Smarcel	  th->suspend_count = 0;
1356130803Smarcel	}
1357130803Smarcel
1358130803Smarcel  return res;
1359130803Smarcel}
1360130803Smarcel
1361130803Smarcel/* Get the next event from the child.  Return 1 if the event requires
1362130803Smarcel   handling by WFI (or whatever).
1363130803Smarcel */
1364130803Smarcelstatic int
1365130803Smarcelget_child_debug_event (int pid, struct target_waitstatus *ourstatus,
1366130803Smarcel		       DWORD target_event_code, int *retval)
1367130803Smarcel{
1368130803Smarcel  int breakout = 0;
1369130803Smarcel  BOOL debug_event;
1370130803Smarcel  DWORD continue_status, event_code;
1371130803Smarcel  thread_info *th = NULL;
1372130803Smarcel  static thread_info dummy_thread_info;
1373130803Smarcel
1374130803Smarcel  if (!(debug_event = wait_for_debug_event (&current_event, 1000)))
1375130803Smarcel    {
1376130803Smarcel      *retval = 0;
1377130803Smarcel      goto out;
1378130803Smarcel    }
1379130803Smarcel
1380130803Smarcel  event_count++;
1381130803Smarcel  continue_status = DBG_CONTINUE;
1382130803Smarcel  *retval = 0;
1383130803Smarcel
1384130803Smarcel  event_code = current_event.dwDebugEventCode;
1385130803Smarcel  breakout = event_code == target_event_code;
1386130803Smarcel
1387130803Smarcel  switch (event_code)
1388130803Smarcel    {
1389130803Smarcel    case CREATE_THREAD_DEBUG_EVENT:
1390130803Smarcel      DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%x code=%s)\n",
1391130803Smarcel		     (unsigned) current_event.dwProcessId,
1392130803Smarcel		     (unsigned) current_event.dwThreadId,
1393130803Smarcel		     "CREATE_THREAD_DEBUG_EVENT"));
1394130803Smarcel      /* Record the existence of this thread */
1395130803Smarcel      th = child_add_thread (current_event.dwThreadId,
1396130803Smarcel			     current_event.u.CreateThread.hThread);
1397130803Smarcel      if (info_verbose)
1398130803Smarcel	printf_unfiltered ("[New %s]\n",
1399130803Smarcel			   target_pid_to_str (current_event.dwThreadId));
1400130803Smarcel      break;
1401130803Smarcel
1402130803Smarcel    case EXIT_THREAD_DEBUG_EVENT:
1403130803Smarcel      DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n",
1404130803Smarcel		     (unsigned) current_event.dwProcessId,
1405130803Smarcel		     (unsigned) current_event.dwThreadId,
1406130803Smarcel		     "EXIT_THREAD_DEBUG_EVENT"));
1407130803Smarcel      child_delete_thread (current_event.dwThreadId);
1408130803Smarcel      th = &dummy_thread_info;
1409130803Smarcel      break;
1410130803Smarcel
1411130803Smarcel    case CREATE_PROCESS_DEBUG_EVENT:
1412130803Smarcel      DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n",
1413130803Smarcel		     (unsigned) current_event.dwProcessId,
1414130803Smarcel		     (unsigned) current_event.dwThreadId,
1415130803Smarcel		     "CREATE_PROCESS_DEBUG_EVENT"));
1416130803Smarcel      current_process_handle = current_event.u.CreateProcessInfo.hProcess;
1417130803Smarcel
1418130803Smarcel      main_thread_id = current_event.dwThreadId;
1419130803Smarcel      inferior_ptid = pid_to_ptid (main_thread_id);
1420130803Smarcel      /* Add the main thread */
1421130803Smarcel      th = child_add_thread (PIDGET (inferior_ptid),
1422130803Smarcel			     current_event.u.CreateProcessInfo.hThread);
1423130803Smarcel      break;
1424130803Smarcel
1425130803Smarcel    case EXIT_PROCESS_DEBUG_EVENT:
1426130803Smarcel      DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n",
1427130803Smarcel		     (unsigned) current_event.dwProcessId,
1428130803Smarcel		     (unsigned) current_event.dwThreadId,
1429130803Smarcel		     "EXIT_PROCESS_DEBUG_EVENT"));
1430130803Smarcel      ourstatus->kind = TARGET_WAITKIND_EXITED;
1431130803Smarcel      ourstatus->value.integer = current_event.u.ExitProcess.dwExitCode;
1432130803Smarcel      close_handle (current_process_handle);
1433130803Smarcel      *retval = current_event.dwProcessId;
1434130803Smarcel      breakout = 1;
1435130803Smarcel      break;
1436130803Smarcel
1437130803Smarcel    case LOAD_DLL_DEBUG_EVENT:
1438130803Smarcel      DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n",
1439130803Smarcel		     (unsigned) current_event.dwProcessId,
1440130803Smarcel		     (unsigned) current_event.dwThreadId,
1441130803Smarcel		     "LOAD_DLL_DEBUG_EVENT"));
1442130803Smarcel      catch_errors (handle_load_dll, NULL, (char *) "", RETURN_MASK_ALL);
1443130803Smarcel      registers_changed ();	/* mark all regs invalid */
1444130803Smarcel      break;
1445130803Smarcel
1446130803Smarcel    case UNLOAD_DLL_DEBUG_EVENT:
1447130803Smarcel      DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n",
1448130803Smarcel		     (unsigned) current_event.dwProcessId,
1449130803Smarcel		     (unsigned) current_event.dwThreadId,
1450130803Smarcel		     "UNLOAD_DLL_DEBUG_EVENT"));
1451130803Smarcel      break;			/* FIXME: don't know what to do here */
1452130803Smarcel
1453130803Smarcel    case EXCEPTION_DEBUG_EVENT:
1454130803Smarcel      DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n",
1455130803Smarcel		     (unsigned) current_event.dwProcessId,
1456130803Smarcel		     (unsigned) current_event.dwThreadId,
1457130803Smarcel		     "EXCEPTION_DEBUG_EVENT"));
1458130803Smarcel      if (handle_exception (ourstatus))
1459130803Smarcel	*retval = current_event.dwThreadId;
1460130803Smarcel      else
1461130803Smarcel	{
1462130803Smarcel	  continue_status = DBG_EXCEPTION_NOT_HANDLED;
1463130803Smarcel	  breakout = 0;
1464130803Smarcel	}
1465130803Smarcel      break;
1466130803Smarcel
1467130803Smarcel    case OUTPUT_DEBUG_STRING_EVENT:	/* message from the kernel */
1468130803Smarcel      DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n",
1469130803Smarcel		     (unsigned) current_event.dwProcessId,
1470130803Smarcel		     (unsigned) current_event.dwThreadId,
1471130803Smarcel		     "OUTPUT_DEBUG_STRING_EVENT"));
1472130803Smarcel      handle_output_debug_string ( ourstatus);
1473130803Smarcel      break;
1474130803Smarcel    default:
1475130803Smarcel      printf_unfiltered ("gdb: kernel event for pid=%d tid=%d\n",
1476130803Smarcel			 current_event.dwProcessId,
1477130803Smarcel			 current_event.dwThreadId);
1478130803Smarcel      printf_unfiltered ("                 unknown event code %d\n",
1479130803Smarcel			 current_event.dwDebugEventCode);
1480130803Smarcel      break;
1481130803Smarcel    }
1482130803Smarcel
1483130803Smarcel  if (breakout)
1484130803Smarcel    this_thread = current_thread = th ?: thread_rec (current_event.dwThreadId, TRUE);
1485130803Smarcel  else
1486130803Smarcel    CHECK (child_continue (continue_status, -1));
1487130803Smarcel
1488130803Smarcelout:
1489130803Smarcel  return breakout;
1490130803Smarcel}
1491130803Smarcel
1492130803Smarcel/* Wait for interesting events to occur in the target process. */
1493130803Smarcelstatic ptid_t
1494130803Smarcelchild_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
1495130803Smarcel{
1496130803Smarcel  DWORD event_code;
1497130803Smarcel  int retval;
1498130803Smarcel  int pid = PIDGET (ptid);
1499130803Smarcel
1500130803Smarcel  /* We loop when we get a non-standard exception rather than return
1501130803Smarcel     with a SPURIOUS because resume can try and step or modify things,
1502130803Smarcel     which needs a current_thread->h.  But some of these exceptions mark
1503130803Smarcel     the birth or death of threads, which mean that the current thread
1504130803Smarcel     isn't necessarily what you think it is. */
1505130803Smarcel
1506130803Smarcel  while (1)
1507130803Smarcel    if (get_child_debug_event (pid, ourstatus, EXCEPTION_DEBUG_EVENT, &retval))
1508130803Smarcel      return pid_to_ptid (retval);
1509130803Smarcel    else
1510130803Smarcel      {
1511130803Smarcel	int detach = 0;
1512130803Smarcel
1513130803Smarcel	if (ui_loop_hook != NULL)
1514130803Smarcel	  detach = ui_loop_hook (0);
1515130803Smarcel
1516130803Smarcel	if (detach)
1517130803Smarcel	  child_kill_inferior ();
1518130803Smarcel      }
1519130803Smarcel}
1520130803Smarcel
1521130803Smarcel/* Print status information about what we're accessing.  */
1522130803Smarcel
1523130803Smarcelstatic void
1524130803Smarcelchild_files_info (struct target_ops *ignore)
1525130803Smarcel{
1526130803Smarcel  printf_unfiltered ("\tUsing the running image of child %s.\n",
1527130803Smarcel		     target_pid_to_str (inferior_ptid));
1528130803Smarcel}
1529130803Smarcel
1530130803Smarcelstatic void
1531130803Smarcelchild_open (char *arg, int from_tty)
1532130803Smarcel{
1533130803Smarcel  error ("Use the \"run\" command to start a child process.");
1534130803Smarcel}
1535130803Smarcel
1536130803Smarcel#define FACTOR (0x19db1ded53ea710LL)
1537130803Smarcel#define NSPERSEC 10000000
1538130803Smarcel
1539130803Smarcel/* Convert a Win32 time to "UNIX" format. */
1540130803Smarcellong
1541130803Smarcelto_time_t (FILETIME * ptr)
1542130803Smarcel{
1543130803Smarcel  /* A file time is the number of 100ns since jan 1 1601
1544130803Smarcel     stuffed into two long words.
1545130803Smarcel     A time_t is the number of seconds since jan 1 1970.  */
1546130803Smarcel
1547130803Smarcel  long rem;
1548130803Smarcel  long long x = ((long long) ptr->dwHighDateTime << 32) + ((unsigned) ptr->dwLowDateTime);
1549130803Smarcel  x -= FACTOR;			/* number of 100ns between 1601 and 1970 */
1550130803Smarcel  rem = x % ((long long) NSPERSEC);
1551130803Smarcel  rem += (NSPERSEC / 2);
1552130803Smarcel  x /= (long long) NSPERSEC;	/* number of 100ns in a second */
1553130803Smarcel  x += (long long) (rem / NSPERSEC);
1554130803Smarcel  return x;
1555130803Smarcel}
1556130803Smarcel
1557130803Smarcel/* Upload a file to the remote device depending on the user's
1558130803Smarcel   'set remoteupload' specification. */
1559130803Smarcelchar *
1560130803Smarcelupload_to_device (const char *to, const char *from)
1561130803Smarcel{
1562130803Smarcel  HANDLE h;
1563130803Smarcel  const char *dir = remote_directory ?: "\\gdb";
1564130803Smarcel  int len;
1565130803Smarcel  static char *remotefile = NULL;
1566130803Smarcel  LPWSTR wstr;
1567130803Smarcel  char *p;
1568130803Smarcel  DWORD err;
1569130803Smarcel  const char *in_to = to;
1570130803Smarcel  FILETIME crtime, actime, wrtime;
1571130803Smarcel  time_t utime;
1572130803Smarcel  struct stat st;
1573130803Smarcel  int fd;
1574130803Smarcel
1575130803Smarcel  /* Look for a path separator and only use trailing part. */
1576130803Smarcel  while ((p = strpbrk (to, "/\\")) != NULL)
1577130803Smarcel    to = p + 1;
1578130803Smarcel
1579130803Smarcel  if (!*to)
1580130803Smarcel    error ("no filename found to upload - %s.", in_to);
1581130803Smarcel
1582130803Smarcel  len = strlen (dir) + strlen (to) + 2;
1583130803Smarcel  remotefile = (char *) xrealloc (remotefile, len);
1584130803Smarcel  strcpy (remotefile, dir);
1585130803Smarcel  strcat (remotefile, "\\");
1586130803Smarcel  strcat (remotefile, to);
1587130803Smarcel
1588130803Smarcel  if (upload_when == UPLOAD_NEVER)
1589130803Smarcel    return remotefile;		/* Don't bother uploading. */
1590130803Smarcel
1591130803Smarcel  /* Open the source. */
1592130803Smarcel  if ((fd = openp (getenv ("PATH"), TRUE, (char *) from, O_RDONLY, 0, NULL)) < 0)
1593130803Smarcel    error ("couldn't open %s", from);
1594130803Smarcel
1595130803Smarcel  /* Get the time for later comparison. */
1596130803Smarcel  if (fstat (fd, &st))
1597130803Smarcel    st.st_mtime = (time_t) - 1;
1598130803Smarcel
1599130803Smarcel  /* Always attempt to create the directory on the remote system. */
1600130803Smarcel  wstr = towide (dir, NULL);
1601130803Smarcel  (void) CeCreateDirectory (wstr, NULL);
1602130803Smarcel
1603130803Smarcel  /* Attempt to open the remote file, creating it if it doesn't exist. */
1604130803Smarcel  wstr = towide (remotefile, NULL);
1605130803Smarcel  h = CeCreateFile (wstr, GENERIC_READ | GENERIC_WRITE, 0, NULL,
1606130803Smarcel		    OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1607130803Smarcel
1608130803Smarcel  /* Some kind of problem? */
1609130803Smarcel  err = CeGetLastError ();
1610130803Smarcel  if (h == NULL || h == INVALID_HANDLE_VALUE)
1611130803Smarcel    error ("error opening file \"%s\".  Windows error %d.",
1612130803Smarcel	   remotefile, err);
1613130803Smarcel
1614130803Smarcel  CeGetFileTime (h, &crtime, &actime, &wrtime);
1615130803Smarcel  utime = to_time_t (&wrtime);
1616130803Smarcel#if 0
1617130803Smarcel  if (utime < st.st_mtime)
1618130803Smarcel    {
1619130803Smarcel      char buf[80];
1620130803Smarcel      strcpy (buf, ctime(&utime));
1621130803Smarcel      printf ("%s < %s\n", buf, ctime(&st.st_mtime));
1622130803Smarcel    }
1623130803Smarcel#endif
1624130803Smarcel  /* See if we need to upload the file. */
1625130803Smarcel  if (upload_when == UPLOAD_ALWAYS ||
1626130803Smarcel      err != ERROR_ALREADY_EXISTS ||
1627130803Smarcel      !CeGetFileTime (h, &crtime, &actime, &wrtime) ||
1628130803Smarcel      to_time_t (&wrtime) < st.st_mtime)
1629130803Smarcel    {
1630130803Smarcel      DWORD nbytes;
1631130803Smarcel      char buf[4096];
1632130803Smarcel      int n;
1633130803Smarcel
1634130803Smarcel      /* Upload the file. */
1635130803Smarcel      while ((n = read (fd, buf, sizeof (buf))) > 0)
1636130803Smarcel	if (!CeWriteFile (h, buf, (DWORD) n, &nbytes, NULL))
1637130803Smarcel	  error ("error writing to remote device - %d.",
1638130803Smarcel		 CeGetLastError ());
1639130803Smarcel    }
1640130803Smarcel
1641130803Smarcel  close (fd);
1642130803Smarcel  if (!CeCloseHandle (h))
1643130803Smarcel    error ("error closing remote file - %d.", CeGetLastError ());
1644130803Smarcel
1645130803Smarcel  return remotefile;
1646130803Smarcel}
1647130803Smarcel
1648130803Smarcel/* Initialize the connection to the remote device. */
1649130803Smarcelstatic void
1650130803Smarcelwince_initialize (void)
1651130803Smarcel{
1652130803Smarcel  int tmp;
1653130803Smarcel  char args[256];
1654130803Smarcel  char *hostname;
1655130803Smarcel  struct sockaddr_in sin;
1656130803Smarcel  char *stub_file_name;
1657130803Smarcel  int s0;
1658130803Smarcel  PROCESS_INFORMATION pi;
1659130803Smarcel
1660130803Smarcel  if (!connection_initialized)
1661130803Smarcel    switch (CeRapiInit ())
1662130803Smarcel      {
1663130803Smarcel      case 0:
1664130803Smarcel	connection_initialized = 1;
1665130803Smarcel	break;
1666130803Smarcel      default:
1667130803Smarcel	CeRapiUninit ();
1668130803Smarcel	error ("Can't initialize connection to remote device.\n");
1669130803Smarcel	break;
1670130803Smarcel      }
1671130803Smarcel
1672130803Smarcel  /* Upload the stub to the handheld device. */
1673130803Smarcel  stub_file_name = upload_to_device ("wince-stub.exe", WINCE_STUB);
1674130803Smarcel  strcpy (args, stub_file_name);
1675130803Smarcel
1676130803Smarcel  if (remote_add_host)
1677130803Smarcel    {
1678130803Smarcel      strcat (args, " ");
1679130803Smarcel      hostname = strchr (args, '\0');
1680130803Smarcel      if (gethostname (hostname, sizeof (args) - strlen (args)))
1681130803Smarcel	error ("couldn't get hostname of this system.");
1682130803Smarcel    }
1683130803Smarcel
1684130803Smarcel  /* Get a socket. */
1685130803Smarcel  if ((s0 = socket (AF_INET, SOCK_STREAM, 0)) < 0)
1686130803Smarcel    stub_error ("Couldn't connect to host system.");
1687130803Smarcel
1688130803Smarcel  /* Allow rapid reuse of the port. */
1689130803Smarcel  tmp = 1;
1690130803Smarcel  (void) setsockopt (s0, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp, sizeof (tmp));
1691130803Smarcel
1692130803Smarcel
1693130803Smarcel  /* Set up the information for connecting to the host gdb process. */
1694130803Smarcel  memset (&sin, 0, sizeof (sin));
1695130803Smarcel  sin.sin_family = AF_INET;
1696130803Smarcel  sin.sin_port = htons (7000);	/* FIXME: This should be configurable */
1697130803Smarcel
1698130803Smarcel  if (bind (s0, (struct sockaddr *) &sin, sizeof (sin)))
1699130803Smarcel    error ("couldn't bind socket");
1700130803Smarcel
1701130803Smarcel  if (listen (s0, 1))
1702130803Smarcel    error ("Couldn't open socket for listening.\n");
1703130803Smarcel
1704130803Smarcel  /* Start up the stub on the remote device. */
1705130803Smarcel  if (!CeCreateProcess (towide (stub_file_name, NULL), towide (args, NULL),
1706130803Smarcel			NULL, NULL, 0, 0, NULL, NULL, NULL, &pi))
1707130803Smarcel    error ("Unable to start remote stub '%s'.  Windows CE error %d.",
1708130803Smarcel	   stub_file_name, CeGetLastError ());
1709130803Smarcel
1710130803Smarcel  /* Wait for a connection */
1711130803Smarcel
1712130803Smarcel  if ((s = accept (s0, NULL, NULL)) < 0)
1713130803Smarcel    error ("couldn't set up server for connection.");
1714130803Smarcel
1715130803Smarcel  close (s0);
1716130803Smarcel}
1717130803Smarcel
1718130803Smarcel/* Start an inferior win32 child process and sets inferior_ptid to its pid.
1719130803Smarcel   EXEC_FILE is the file to run.
1720130803Smarcel   ALLARGS is a string containing the arguments to the program.
1721130803Smarcel   ENV is the environment vector to pass.  Errors reported with error().  */
1722130803Smarcelstatic void
1723130803Smarcelchild_create_inferior (char *exec_file, char *args, char **env)
1724130803Smarcel{
1725130803Smarcel  PROCESS_INFORMATION pi;
1726130803Smarcel  struct target_waitstatus dummy;
1727130803Smarcel  int ret;
1728130803Smarcel  DWORD flags, event_code;
1729130803Smarcel  char *exec_and_args;
1730130803Smarcel
1731130803Smarcel  if (!exec_file)
1732130803Smarcel    error ("No executable specified, use `target exec'.\n");
1733130803Smarcel
1734130803Smarcel  flags = DEBUG_PROCESS;
1735130803Smarcel
1736130803Smarcel  wince_initialize ();		/* Make sure we've got a connection. */
1737130803Smarcel
1738130803Smarcel  exec_file = upload_to_device (exec_file, exec_file);
1739130803Smarcel
1740130803Smarcel  while (*args == ' ')
1741130803Smarcel    args++;
1742130803Smarcel
1743130803Smarcel  /* Allocate space for "command<sp>args" */
1744130803Smarcel  if (*args == '\0')
1745130803Smarcel    {
1746130803Smarcel      exec_and_args = alloca (strlen (exec_file) + 1);
1747130803Smarcel      strcpy (exec_and_args, exec_file);
1748130803Smarcel    }
1749130803Smarcel  else
1750130803Smarcel    {
1751130803Smarcel      exec_and_args = alloca (strlen (exec_file + strlen (args) + 2));
1752130803Smarcel      sprintf (exec_and_args, "%s %s", exec_file, args);
1753130803Smarcel    }
1754130803Smarcel
1755130803Smarcel  memset (&pi, 0, sizeof (pi));
1756130803Smarcel  /* Execute the process */
1757130803Smarcel  if (!create_process (exec_file, exec_and_args, flags, &pi))
1758130803Smarcel    error ("Error creating process %s, (error %d)\n", exec_file, GetLastError ());
1759130803Smarcel
1760130803Smarcel  exception_count = 0;
1761130803Smarcel  event_count = 0;
1762130803Smarcel
1763130803Smarcel  current_process_handle = pi.hProcess;
1764130803Smarcel  current_event.dwProcessId = pi.dwProcessId;
1765130803Smarcel  memset (&current_event, 0, sizeof (current_event));
1766130803Smarcel  current_event.dwThreadId = pi.dwThreadId;
1767130803Smarcel  inferior_ptid = pid_to_ptid (current_event.dwThreadId);
1768130803Smarcel  push_target (&child_ops);
1769130803Smarcel  child_init_thread_list ();
1770130803Smarcel  child_add_thread (pi.dwThreadId, pi.hThread);
1771130803Smarcel  init_wait_for_inferior ();
1772130803Smarcel  clear_proceed_status ();
1773130803Smarcel  target_terminal_init ();
1774130803Smarcel  target_terminal_inferior ();
1775130803Smarcel
1776130803Smarcel  /* Run until process and threads are loaded */
1777130803Smarcel  while (!get_child_debug_event (PIDGET (inferior_ptid), &dummy,
1778130803Smarcel				 CREATE_PROCESS_DEBUG_EVENT, &ret))
1779130803Smarcel    continue;
1780130803Smarcel
1781130803Smarcel  proceed ((CORE_ADDR) -1, TARGET_SIGNAL_0, 0);
1782130803Smarcel}
1783130803Smarcel
1784130803Smarcel/* Chile has gone bye-bye. */
1785130803Smarcelstatic void
1786130803Smarcelchild_mourn_inferior (void)
1787130803Smarcel{
1788130803Smarcel  (void) child_continue (DBG_CONTINUE, -1);
1789130803Smarcel  unpush_target (&child_ops);
1790130803Smarcel  stop_stub ();
1791130803Smarcel  CeRapiUninit ();
1792130803Smarcel  connection_initialized = 0;
1793130803Smarcel  generic_mourn_inferior ();
1794130803Smarcel}
1795130803Smarcel
1796130803Smarcel/* Move memory from child to/from gdb. */
1797130803Smarcelint
1798130803Smarcelchild_xfer_memory (CORE_ADDR memaddr, char *our, int len, int write,
1799130803Smarcel		   struct mem_attrib *attrib,
1800130803Smarcel		   struct target_ops *target)
1801130803Smarcel{
1802130803Smarcel  if (len <= 0)
1803130803Smarcel    return 0;
1804130803Smarcel
1805130803Smarcel  if (write)
1806130803Smarcel    res = remote_write_bytes (memaddr, our, len);
1807130803Smarcel  else
1808130803Smarcel    res = remote_read_bytes (memaddr, our, len);
1809130803Smarcel
1810130803Smarcel  return res;
1811130803Smarcel}
1812130803Smarcel
1813130803Smarcel/* Terminate the process and wait for child to tell us it has completed. */
1814130803Smarcelvoid
1815130803Smarcelchild_kill_inferior (void)
1816130803Smarcel{
1817130803Smarcel  CHECK (terminate_process (current_process_handle));
1818130803Smarcel
1819130803Smarcel  for (;;)
1820130803Smarcel    {
1821130803Smarcel      if (!child_continue (DBG_CONTINUE, -1))
1822130803Smarcel	break;
1823130803Smarcel      if (!wait_for_debug_event (&current_event, INFINITE))
1824130803Smarcel	break;
1825130803Smarcel      if (current_event.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT)
1826130803Smarcel	break;
1827130803Smarcel    }
1828130803Smarcel
1829130803Smarcel  CHECK (close_handle (current_process_handle));
1830130803Smarcel  close_handle (current_thread->h);
1831130803Smarcel  target_mourn_inferior ();	/* or just child_mourn_inferior? */
1832130803Smarcel}
1833130803Smarcel
1834130803Smarcel/* Resume the child after an exception. */
1835130803Smarcelvoid
1836130803Smarcelchild_resume (ptid_t ptid, int step, enum target_signal sig)
1837130803Smarcel{
1838130803Smarcel  thread_info *th;
1839130803Smarcel  DWORD continue_status = last_sig > 0 && last_sig < NSIG ?
1840130803Smarcel  DBG_EXCEPTION_NOT_HANDLED : DBG_CONTINUE;
1841130803Smarcel  int pid = PIDGET (ptid);
1842130803Smarcel
1843130803Smarcel  DEBUG_EXEC (("gdb: child_resume (pid=%d, step=%d, sig=%d);\n",
1844130803Smarcel	       pid, step, sig));
1845130803Smarcel
1846130803Smarcel  /* Get context for currently selected thread */
1847130803Smarcel  th = thread_rec (current_event.dwThreadId, FALSE);
1848130803Smarcel
1849130803Smarcel  if (th->context.ContextFlags)
1850130803Smarcel    {
1851130803Smarcel      CHECK (set_thread_context (th->h, &th->context));
1852130803Smarcel      th->context.ContextFlags = 0;
1853130803Smarcel    }
1854130803Smarcel
1855130803Smarcel  /* Allow continuing with the same signal that interrupted us.
1856130803Smarcel     Otherwise complain. */
1857130803Smarcel  if (sig && sig != last_sig)
1858130803Smarcel    fprintf_unfiltered (gdb_stderr, "Can't send signals to the child.  signal %d\n", sig);
1859130803Smarcel
1860130803Smarcel  last_sig = 0;
1861130803Smarcel  child_continue (continue_status, pid);
1862130803Smarcel}
1863130803Smarcel
1864130803Smarcelstatic void
1865130803Smarcelchild_prepare_to_store (void)
1866130803Smarcel{
1867130803Smarcel  /* Do nothing, since we can store individual regs */
1868130803Smarcel}
1869130803Smarcel
1870130803Smarcelstatic int
1871130803Smarcelchild_can_run (void)
1872130803Smarcel{
1873130803Smarcel  return 1;
1874130803Smarcel}
1875130803Smarcel
1876130803Smarcelstatic void
1877130803Smarcelchild_close (void)
1878130803Smarcel{
1879130803Smarcel  DEBUG_EVENTS (("gdb: child_close, inferior_ptid=%d\n",
1880130803Smarcel                PIDGET (inferior_ptid)));
1881130803Smarcel}
1882130803Smarcel
1883130803Smarcel/* Explicitly upload file to remotedir */
1884130803Smarcel
1885130803Smarcelstatic void
1886130803Smarcelchild_load (char *file, int from_tty)
1887130803Smarcel{
1888130803Smarcel  upload_to_device (file, file);
1889130803Smarcel}
1890130803Smarcel
1891130803Smarcelstruct target_ops child_ops;
1892130803Smarcel
1893130803Smarcelstatic void
1894130803Smarcelinit_child_ops (void)
1895130803Smarcel{
1896130803Smarcel  memset (&child_ops, 0, sizeof (child_ops));
1897130803Smarcel  child_ops.to_shortname = (char *) "child";
1898130803Smarcel  child_ops.to_longname = (char *) "Windows CE process";
1899130803Smarcel  child_ops.to_doc = (char *) "Windows CE process (started by the \"run\" command).";
1900130803Smarcel  child_ops.to_open = child_open;
1901130803Smarcel  child_ops.to_close = child_close;
1902130803Smarcel  child_ops.to_resume = child_resume;
1903130803Smarcel  child_ops.to_wait = child_wait;
1904130803Smarcel  child_ops.to_fetch_registers = child_fetch_inferior_registers;
1905130803Smarcel  child_ops.to_store_registers = child_store_inferior_registers;
1906130803Smarcel  child_ops.to_prepare_to_store = child_prepare_to_store;
1907130803Smarcel  child_ops.to_xfer_memory = child_xfer_memory;
1908130803Smarcel  child_ops.to_files_info = child_files_info;
1909130803Smarcel  child_ops.to_insert_breakpoint = memory_insert_breakpoint;
1910130803Smarcel  child_ops.to_remove_breakpoint = memory_remove_breakpoint;
1911130803Smarcel  child_ops.to_terminal_init = terminal_init_inferior;
1912130803Smarcel  child_ops.to_terminal_inferior = terminal_inferior;
1913130803Smarcel  child_ops.to_terminal_ours_for_output = terminal_ours_for_output;
1914130803Smarcel  child_ops.to_terminal_ours = terminal_ours;
1915130803Smarcel  child_ops.to_terminal_save_ours = terminal_save_ours;
1916130803Smarcel  child_ops.to_terminal_info = child_terminal_info;
1917130803Smarcel  child_ops.to_kill = child_kill_inferior;
1918130803Smarcel  child_ops.to_load = child_load;
1919130803Smarcel  child_ops.to_create_inferior = child_create_inferior;
1920130803Smarcel  child_ops.to_mourn_inferior = child_mourn_inferior;
1921130803Smarcel  child_ops.to_can_run = child_can_run;
1922130803Smarcel  child_ops.to_thread_alive = win32_child_thread_alive;
1923130803Smarcel  child_ops.to_stratum = process_stratum;
1924130803Smarcel  child_ops.to_has_all_memory = 1;
1925130803Smarcel  child_ops.to_has_memory = 1;
1926130803Smarcel  child_ops.to_has_stack = 1;
1927130803Smarcel  child_ops.to_has_registers = 1;
1928130803Smarcel  child_ops.to_has_execution = 1;
1929130803Smarcel  child_ops.to_magic = OPS_MAGIC;
1930130803Smarcel}
1931130803Smarcel
1932130803Smarcel
1933130803Smarcel/* Handle 'set remoteupload' parameter. */
1934130803Smarcel
1935130803Smarcel#define replace_upload(what) \
1936130803Smarcel      upload_when = what; \
1937130803Smarcel      remote_upload = xrealloc (remote_upload, strlen (upload_options[upload_when].name) + 1); \
1938130803Smarcel      strcpy (remote_upload, upload_options[upload_when].name);
1939130803Smarcel
1940130803Smarcelstatic void
1941130803Smarcelset_upload_type (char *ignore, int from_tty)
1942130803Smarcel{
1943130803Smarcel  int i, len;
1944130803Smarcel  char *bad_option;
1945130803Smarcel
1946130803Smarcel  if (!remote_upload || !remote_upload[0])
1947130803Smarcel    {
1948130803Smarcel      replace_upload (UPLOAD_NEWER);
1949130803Smarcel      if (from_tty)
1950130803Smarcel	printf_unfiltered ("Upload upload_options are: always, newer, never.\n");
1951130803Smarcel      return;
1952130803Smarcel    }
1953130803Smarcel
1954130803Smarcel  len = strlen (remote_upload);
1955130803Smarcel  for (i = 0; i < (sizeof (upload_options) / sizeof (upload_options[0])); i++)
1956130803Smarcel    if (len >= upload_options[i].abbrev &&
1957130803Smarcel	strncasecmp (remote_upload, upload_options[i].name, len) == 0)
1958130803Smarcel      {
1959130803Smarcel	replace_upload (i);
1960130803Smarcel	return;
1961130803Smarcel      }
1962130803Smarcel
1963130803Smarcel  bad_option = remote_upload;
1964130803Smarcel  replace_upload (UPLOAD_NEWER);
1965130803Smarcel  error ("Unknown upload type: %s.", bad_option);
1966130803Smarcel}
1967130803Smarcel
1968130803Smarcelvoid
1969130803Smarcel_initialize_wince (void)
1970130803Smarcel{
1971130803Smarcel  struct cmd_list_element *set;
1972130803Smarcel  init_child_ops ();
1973130803Smarcel
1974130803Smarcel  add_show_from_set
1975130803Smarcel    (add_set_cmd ((char *) "remotedirectory", no_class,
1976130803Smarcel		  var_string_noescape, (char *) &remote_directory,
1977130803Smarcel		  (char *) "Set directory for remote upload.\n",
1978130803Smarcel		  &setlist),
1979130803Smarcel     &showlist);
1980130803Smarcel  remote_directory = xstrdup (remote_directory);
1981130803Smarcel
1982130803Smarcel  set = add_set_cmd ((char *) "remoteupload", no_class,
1983130803Smarcel		     var_string_noescape, (char *) &remote_upload,
1984130803Smarcel	       (char *) "Set how to upload executables to remote device.\n",
1985130803Smarcel		     &setlist);
1986130803Smarcel  add_show_from_set (set, &showlist);
1987130803Smarcel  set_cmd_cfunc (set, set_upload_type);
1988130803Smarcel  set_upload_type (NULL, 0);
1989130803Smarcel
1990130803Smarcel  add_show_from_set
1991130803Smarcel    (add_set_cmd ((char *) "debugexec", class_support, var_boolean,
1992130803Smarcel		  (char *) &debug_exec,
1993130803Smarcel	      (char *) "Set whether to display execution in child process.",
1994130803Smarcel		  &setlist),
1995130803Smarcel     &showlist);
1996130803Smarcel
1997130803Smarcel  add_show_from_set
1998130803Smarcel    (add_set_cmd ((char *) "remoteaddhost", class_support, var_boolean,
1999130803Smarcel		  (char *) &remote_add_host,
2000130803Smarcel		  (char *) "\
2001130803SmarcelSet whether to add this host to remote stub arguments for\n\
2002130803Smarceldebugging over a network.", &setlist),
2003130803Smarcel     &showlist);
2004130803Smarcel
2005130803Smarcel  add_show_from_set
2006130803Smarcel    (add_set_cmd ((char *) "debugevents", class_support, var_boolean,
2007130803Smarcel		  (char *) &debug_events,
2008130803Smarcel	  (char *) "Set whether to display kernel events in child process.",
2009130803Smarcel		  &setlist),
2010130803Smarcel     &showlist);
2011130803Smarcel
2012130803Smarcel  add_show_from_set
2013130803Smarcel    (add_set_cmd ((char *) "debugmemory", class_support, var_boolean,
2014130803Smarcel		  (char *) &debug_memory,
2015130803Smarcel	(char *) "Set whether to display memory accesses in child process.",
2016130803Smarcel		  &setlist),
2017130803Smarcel     &showlist);
2018130803Smarcel
2019130803Smarcel  add_show_from_set
2020130803Smarcel    (add_set_cmd ((char *) "debugexceptions", class_support, var_boolean,
2021130803Smarcel		  (char *) &debug_exceptions,
2022130803Smarcel      (char *) "Set whether to display kernel exceptions in child process.",
2023130803Smarcel		  &setlist),
2024130803Smarcel     &showlist);
2025130803Smarcel
2026130803Smarcel  add_target (&child_ops);
2027130803Smarcel}
2028130803Smarcel
2029130803Smarcel/* Determine if the thread referenced by "pid" is alive
2030130803Smarcel   by "polling" it.  If WaitForSingleObject returns WAIT_OBJECT_0
2031130803Smarcel   it means that the pid has died.  Otherwise it is assumed to be alive. */
2032130803Smarcelstatic int
2033130803Smarcelwin32_child_thread_alive (ptid_t ptid)
2034130803Smarcel{
2035130803Smarcel  int pid = PIDGET (ptid);
2036130803Smarcel  return thread_alive (thread_rec (pid, FALSE)->h);
2037130803Smarcel}
2038130803Smarcel
2039130803Smarcel/* Convert pid to printable format. */
2040130803Smarcelchar *
2041130803Smarcelcygwin_pid_to_str (int pid)
2042130803Smarcel{
2043130803Smarcel  static char buf[80];
2044130803Smarcel  if (pid == current_event.dwProcessId)
2045130803Smarcel    sprintf (buf, "process %d", pid);
2046130803Smarcel  else
2047130803Smarcel    sprintf (buf, "thread %d.0x%x", (unsigned) current_event.dwProcessId, pid);
2048130803Smarcel  return buf;
2049130803Smarcel}
2050