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 (¤t_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 *) ¤t_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 = ¤t_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 (¤t_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 (¤t_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 (¤t_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 (¤t_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