* wince-stub.c (FREE): New macro.

(mempool): Just free any buffer prior to reuse.  Don't bother with realloc.
(flag_single_step): New function.
(skip_message): Detect "helpful" Windows CE messages and skip sending them to
the host.
(wait_for_debug_event): Use skip_message to avoid sending debug messages to the
host.
(dispatch): Prelimary implementation of single step detection.
* wince.c: Rework SH single stepping code to be more consistent with other
wince targets.
(handle_output_debug_string): Allow first chance exceptions to come through
since they seem to be all that we get on some versions of Windows CE.
(check_for_step): New function, conditionally compiled based on target.
(regptr): Delete obsolete function.
(handle_exception): Detect illegal instructions.
(get_child_debug_event): Return success only if event code matches target.
(child_create_inferior): Reflect change to get_child_debug_event arguments.
This commit is contained in:
Christopher Faylor 2000-04-21 03:04:35 +00:00
parent 8a892701f5
commit 61c37cee5d
4 changed files with 427 additions and 336 deletions

View file

@ -1,3 +1,27 @@
2000-04-20 Christopher Faylor <cgf@cygnus.com>
* wince-stub.c (FREE): New macro.
(mempool): Just free any buffer prior to reuse. Don't bother with
realloc.
(flag_single_step): New function.
(skip_message): Detect "helpful" Windows CE messages and skip sending
them to the host.
(wait_for_debug_event): Use skip_message to avoid sending debug
messages to the host.
(dispatch): Prelimary implementation of single step detection.
* wince.c: Rework SH single stepping code to be more consistent with
other wince targets.
(handle_output_debug_string): Allow first chance exceptions to come
through since they seem to be all that we get on some versions of
Windows CE.
(check_for_step): New function, conditionally compiled based on target.
(regptr): Delete obsolete function.
(handle_exception): Detect illegal instructions.
(get_child_debug_event): Return success only if event code matches
target.
(child_create_inferior): Reflect change to get_child_debug_event
arguments.
2000-04-20 Christopher Faylor <cgf@cygnus.com> 2000-04-20 Christopher Faylor <cgf@cygnus.com>
* win32-nat.c (thread_rec): Be more defensive about suspending already * win32-nat.c (thread_rec): Be more defensive about suspending already

View file

@ -1,5 +1,5 @@
/* Target-specific definition for Window CE /* Target-specific definition for Window CE
Copyright 2000 Free Software Foundation, Inc. Copyright (C) 2000 Free Software Foundation, Inc.
This file is part of GDB. This file is part of GDB.

View file

@ -28,12 +28,13 @@
#include <winsock.h> #include <winsock.h>
#include "wince-stub.h" #include "wince-stub.h"
#define MALLOC(n) (void *) LocalAlloc (LMEM_MOVEABLE, (UINT)(n)) #define MALLOC(n) (void *) LocalAlloc (LMEM_MOVEABLE | LMEM_ZEROINIT, (UINT)(n))
#define REALLOC(s, n) (void *) LocalReAlloc ((HLOCAL)(s), (UINT)(n), LMEM_MOVEABLE) #define REALLOC(s, n) (void *) LocalReAlloc ((HLOCAL)(s), (UINT)(n), LMEM_MOVEABLE)
#define FREE(s) LocalFree ((HLOCAL)(s))
static int skip_next_id = 0; /* Don't read next API code from socket */ static int skip_next_id = 0; /* Don't read next API code from socket */
/* v-style interface for handling varying argyment list error messages. /* v-style interface for handling varying argument list error messages.
Displays the error message in a dialog box and exits when user clicks Displays the error message in a dialog box and exits when user clicks
on OK. */ on OK. */
static void static void
@ -56,6 +57,27 @@ stub_error (LPCWSTR fmt, ...)
vstub_error (fmt, args); vstub_error (fmt, args);
} }
/* Allocate a limited pool of memory, reallocating over unused
buffers. This assumes that there will never be more than four
"buffers" required which, so far, is a safe assumption. */
static LPVOID
mempool (unsigned int len)
{
static int outn = -1;
static LPWSTR outs[4] = {NULL, NULL, NULL, NULL};
if (++outn >= (sizeof (outs) / sizeof (outs[0])))
outn = 0;
/* Allocate space for the converted string, reusing any previously allocated
space, if applicable. */
if (outs[outn])
FREE (outs[outn]);
outs[outn] = (LPWSTR) MALLOC (len);
return outs[outn];
}
/* Standard "oh well" can't communicate error. Someday this might attempt /* Standard "oh well" can't communicate error. Someday this might attempt
synchronization. */ synchronization. */
static void static void
@ -88,28 +110,6 @@ sockwrite (LPCWSTR huh, int s, const void *str, size_t n)
} }
} }
/* Allocate a limited pool of memory, reallocating over unused
buffers. This assumes that there will never be more than four
"buffers" required which, so far, is a safe assumption. */
static LPVOID
mempool (gdb_wince_len len)
{
static int n = -1;
static LPWSTR outs[4] = {NULL /*, NULL, etc. */};
if (++n >= (sizeof (outs) / sizeof (outs[0])))
n = 0;
/* Allocate space for the converted string, reusing any previously allocated
space, if applicable. */
if (outs[n])
outs[n] = (LPWSTR) REALLOC (outs[n], len);
else
outs[n] = (LPWSTR) MALLOC (len);
return outs[n];
}
/* Get a an ID (possibly) and a DWORD from the host gdb. /* Get a an ID (possibly) and a DWORD from the host gdb.
Don't bother with the id if the main loop has already Don't bother with the id if the main loop has already
read it. */ read it. */
@ -175,7 +175,7 @@ getmemory (LPCWSTR huh, int s, gdb_wince_id what, gdb_wince_len *inlen)
*inlen = getlen (huh, s, what); *inlen = getlen (huh, s, what);
p = mempool (*inlen); /* FIXME: check for error */ p = mempool ((unsigned int) *inlen); /* FIXME: check for error */
if ((gdb_wince_len) sockread (huh, s, p, *inlen) != *inlen) if ((gdb_wince_len) sockread (huh, s, p, *inlen) != *inlen)
stub_error (L"error getting string from host."); stub_error (L"error getting string from host.");
@ -269,6 +269,49 @@ terminate_process (int s)
&res, sizeof (res)); &res, sizeof (res));
} }
static int stepped = 0;
/* Handle single step instruction. FIXME: unneded? */
static void
flag_single_step (int s)
{
stepped = 1;
skip_next_id = 0;
}
struct skipper
{
wchar_t *s;
int nskip;
} skippy[] =
{
{L"Undefined Instruction:", 1},
{L"Data Abort:", 2},
{NULL, 0}
};
static int
skip_message (DEBUG_EVENT *ev)
{
char s[80];
DWORD nread;
struct skipper *skp;
int nbytes = ev->u.DebugString.nDebugStringLength;
if (nbytes > sizeof(s))
nbytes = sizeof(s);
memset (s, 0, sizeof (s));
if (!ReadProcessMemory (curproc, ev->u.DebugString.lpDebugStringData,
s, nbytes, &nread))
return 0;
for (skp = skippy; skp->s != NULL; skp++)
if (wcsncmp ((wchar_t *) s, skp->s, wcslen (skp->s)) == 0)
return skp->nskip;
return 0;
}
/* Emulate WaitForDebugEvent. Returns the debug event on success. */ /* Emulate WaitForDebugEvent. Returns the debug event on success. */
static void static void
wait_for_debug_event (int s) wait_for_debug_event (int s)
@ -276,10 +319,32 @@ wait_for_debug_event (int s)
DWORD ms = getdword (L"WaitForDebugEvent ms", s, GDB_WAITFORDEBUGEVENT); DWORD ms = getdword (L"WaitForDebugEvent ms", s, GDB_WAITFORDEBUGEVENT);
gdb_wince_result res; gdb_wince_result res;
DEBUG_EVENT ev; DEBUG_EVENT ev;
static int skip_next = 0;
res = WaitForDebugEvent (&ev, ms); for (;;)
putresult (L"WaitForDebugEvent event", res, s, GDB_WAITFORDEBUGEVENT, {
&ev, sizeof (ev)); res = WaitForDebugEvent (&ev, ms);
if (ev.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT)
{
if (skip_next)
{
skip_next--;
goto ignore;
}
if (skip_next = skip_message (&ev))
goto ignore;
}
putresult (L"WaitForDebugEvent event", res, s, GDB_WAITFORDEBUGEVENT,
&ev, sizeof (ev));
break;
ignore:
ContinueDebugEvent (ev.dwProcessId, ev.dwThreadId, DBG_CONTINUE);
}
return;
} }
/* Emulate GetThreadContext. Returns CONTEXT structure on success. */ /* Emulate GetThreadContext. Returns CONTEXT structure on success. */
@ -291,7 +356,7 @@ get_thread_context (int s)
gdb_wince_result res; gdb_wince_result res;
memset (&c, 0, sizeof (c)); memset (&c, 0, sizeof (c));
c.ContextFlags = getdword (L"GetThreadContext handle", s, GDB_GETTHREADCONTEXT); c.ContextFlags = getdword (L"GetThreadContext flags", s, GDB_GETTHREADCONTEXT);
res = (gdb_wince_result) GetThreadContext (h, &c); res = (gdb_wince_result) GetThreadContext (h, &c);
putresult (L"GetThreadContext data", res, s, GDB_GETTHREADCONTEXT, putresult (L"GetThreadContext data", res, s, GDB_GETTHREADCONTEXT,
@ -319,7 +384,7 @@ read_process_memory (int s)
HANDLE h = gethandle (L"ReadProcessMemory handle", s, GDB_READPROCESSMEMORY); HANDLE h = gethandle (L"ReadProcessMemory handle", s, GDB_READPROCESSMEMORY);
LPVOID p = getpvoid (L"ReadProcessMemory base", s, GDB_READPROCESSMEMORY); LPVOID p = getpvoid (L"ReadProcessMemory base", s, GDB_READPROCESSMEMORY);
gdb_wince_len len = getlen (L"ReadProcessMemory size", s, GDB_READPROCESSMEMORY); gdb_wince_len len = getlen (L"ReadProcessMemory size", s, GDB_READPROCESSMEMORY);
LPVOID buf = mempool ((gdb_wince_len) len); LPVOID buf = mempool ((unsigned int) len);
DWORD outlen; DWORD outlen;
gdb_wince_result res; gdb_wince_result res;
@ -400,12 +465,6 @@ close_handle (int s)
putresult (L"CloseHandle result", res, s, GDB_CLOSEHANDLE, &res, sizeof (res)); putresult (L"CloseHandle result", res, s, GDB_CLOSEHANDLE, &res, sizeof (res));
} }
/* Handle single step instruction */
static void
single_step (int s)
{
}
/* Main loop for reading requests from gdb host on the socket. */ /* Main loop for reading requests from gdb host on the socket. */
static void static void
dispatch (int s) dispatch (int s)
@ -458,8 +517,8 @@ dispatch (int s)
terminate_process (s); terminate_process (s);
return; return;
case GDB_SINGLESTEP: case GDB_SINGLESTEP:
single_step (s); flag_single_step (s);
return; break;
default: default:
{ {
WCHAR buf[80]; WCHAR buf[80];
@ -495,8 +554,6 @@ WinMain (HINSTANCE hi, HINSTANCE hp, LPWSTR cmd, int show)
wcstombs (host, whost, 80); /* Convert from UNICODE to ascii */ wcstombs (host, whost, 80); /* Convert from UNICODE to ascii */
} }
MessageBoxW (NULL, whost, L"GDB", MB_ICONERROR);
/* Winsock initialization. */ /* Winsock initialization. */
if (WSAStartup (MAKEWORD (1, 1), &wd)) if (WSAStartup (MAKEWORD (1, 1), &wd))
stub_error (L"Couldn't initialize WINSOCK."); stub_error (L"Couldn't initialize WINSOCK.");

View file

@ -55,6 +55,7 @@
#include <sys/param.h> #include <sys/param.h>
#include "wince-stub.h" #include "wince-stub.h"
#include "dcache.h" #include "dcache.h"
#include <time.h>
/* The ui's event loop. */ /* The ui's event loop. */
extern int (*ui_loop_hook) PARAMS ((int signo)); extern int (*ui_loop_hook) PARAMS ((int signo));
@ -147,7 +148,6 @@ typedef struct thread_info_struct
int suspend_count; int suspend_count;
int stepped; /* True if stepped. */ int stepped; /* True if stepped. */
CORE_ADDR step_pc; CORE_ADDR step_pc;
unsigned long step_instr;
unsigned long step_prev; unsigned long step_prev;
CONTEXT context; CONTEXT context;
} }
@ -155,6 +155,7 @@ thread_info;
static thread_info thread_head = static thread_info thread_head =
{NULL}; {NULL};
static thread_info * thread_rec (DWORD id, int get_context);
/* The process and thread handles for the above context. */ /* The process and thread handles for the above context. */
@ -374,24 +375,21 @@ static const int mappings[NUM_REGS + 1] =
-1 -1
}; };
/* This vector maps the target's idea of an exception (extracted /* Return a pointer into a CONTEXT field indexed by gdb register number.
from the DEBUG_EVENT structure) to GDB's idea. */ Return a pointer to an address pointing to zero if there is no
corresponding CONTEXT field for the given register number.
struct xlate_exception */
{ static ULONG *
int them; regptr (LPCONTEXT c, int r)
enum target_signal us;
};
static const struct xlate_exception
xlate[] =
{ {
{EXCEPTION_ACCESS_VIOLATION, TARGET_SIGNAL_SEGV}, static ULONG zero = 0;
{STATUS_STACK_OVERFLOW, TARGET_SIGNAL_SEGV}, ULONG *p;
{EXCEPTION_BREAKPOINT, TARGET_SIGNAL_TRAP}, if (mappings[r] < 0)
{DBG_CONTROL_C, TARGET_SIGNAL_INT}, p = &zero;
{EXCEPTION_SINGLE_STEP, TARGET_SIGNAL_TRAP}, else
{-1, -1}}; p = (ULONG *) (((char *) c) + mappings[r]);
return p;
}
/******************** Beginning of stub interface ********************/ /******************** Beginning of stub interface ********************/
@ -629,6 +627,7 @@ towide (const char *s, gdb_wince_len * out_len)
typedef in wince-stub.h and change the putlen/getlen macros in this file and in typedef in wince-stub.h and change the putlen/getlen macros in this file and in
the stub. the stub.
*/ */
static int static int
create_process (LPSTR exec_file, LPSTR args, DWORD flags, PROCESS_INFORMATION * pi) create_process (LPSTR exec_file, LPSTR args, DWORD flags, PROCESS_INFORMATION * pi)
{ {
@ -798,6 +797,227 @@ stop_stub ()
/******************** End of emulation routines. ********************/ /******************** End of emulation routines. ********************/
/******************** End of stub interface ********************/ /******************** End of stub interface ********************/
#define check_for_step(a, x) (x)
#ifdef MIPS
static void
undoSStep (thread_info * th)
{
if (th->stepped)
{
memory_remove_breakpoint (th->step_pc, (void *) &th->step_prev);
th->stepped = 0;
}
}
void
wince_software_single_step (unsigned int ignore, int insert_breakpoints_p)
{
unsigned long pc;
thread_info *th = current_thread; /* Info on currently selected thread */
CORE_ADDR mips_next_pc (CORE_ADDR pc);
if (!insert_breakpoints_p)
{
undoSStep (th);
return;
}
th->stepped = 1;
pc = read_register (PC_REGNUM);
th->step_pc = mips_next_pc (pc);
th->step_prev = 0;
memory_insert_breakpoint (th->step_pc, (void *) &th->step_prev);
return;
}
#elif SHx
/* Hitachi SH architecture instruction encoding masks */
#define COND_BR_MASK 0xff00
#define UCOND_DBR_MASK 0xe000
#define UCOND_RBR_MASK 0xf0df
#define TRAPA_MASK 0xff00
#define COND_DISP 0x00ff
#define UCOND_DISP 0x0fff
#define UCOND_REG 0x0f00
/* Hitachi SH instruction opcodes */
#define BF_INSTR 0x8b00
#define BT_INSTR 0x8900
#define BRA_INSTR 0xa000
#define BSR_INSTR 0xb000
#define JMP_INSTR 0x402b
#define JSR_INSTR 0x400b
#define RTS_INSTR 0x000b
#define RTE_INSTR 0x002b
#define TRAPA_INSTR 0xc300
#define SSTEP_INSTR 0xc3ff
#define T_BIT_MASK 0x0001
static CORE_ADDR
sh_get_next_pc (CONTEXT *c)
{
short *instrMem;
int displacement;
int reg;
unsigned short opcode;
instrMem = (short *) c->Fir;
opcode = read_memory_integer ((CORE_ADDR) c->Fir, sizeof (opcode));
if ((opcode & COND_BR_MASK) == BT_INSTR)
{
if (c->Psr & T_BIT_MASK)
{
displacement = (opcode & COND_DISP) << 1;
if (displacement & 0x80)
displacement |= 0xffffff00;
/*
* Remember PC points to second instr.
* after PC of branch ... so add 4
*/
instrMem = (short *) (c->Fir + displacement + 4);
}
else
instrMem += 1;
}
else if ((opcode & COND_BR_MASK) == BF_INSTR)
{
if (c->Psr & T_BIT_MASK)
instrMem += 1;
else
{
displacement = (opcode & COND_DISP) << 1;
if (displacement & 0x80)
displacement |= 0xffffff00;
/*
* Remember PC points to second instr.
* after PC of branch ... so add 4
*/
instrMem = (short *) (c->Fir + displacement + 4);
}
}
else if ((opcode & UCOND_DBR_MASK) == BRA_INSTR)
{
displacement = (opcode & UCOND_DISP) << 1;
if (displacement & 0x0800)
displacement |= 0xfffff000;
/*
* Remember PC points to second instr.
* after PC of branch ... so add 4
*/
instrMem = (short *) (c->Fir + displacement + 4);
}
else if ((opcode & UCOND_RBR_MASK) == JSR_INSTR)
{
reg = (char) ((opcode & UCOND_REG) >> 8);
instrMem = (short *) *regptr (c, reg);
}
else if (opcode == RTS_INSTR)
instrMem = (short *) c->PR;
else if (opcode == RTE_INSTR)
instrMem = (short *) *regptr (c, 15);
else if ((opcode & TRAPA_MASK) == TRAPA_INSTR)
instrMem = (short *) ((opcode & ~TRAPA_MASK) << 2);
else
instrMem += 1;
return (CORE_ADDR) instrMem;
}
/* Single step (in a painstaking fashion) by inspecting the current
instruction and setting a breakpoint on the "next" instruction
which would be executed. This code hails from sh-stub.c.
*/
static void
undoSStep (thread_info * th)
{
if (th->stepped)
{
memory_remove_breakpoint (th->step_pc, (void *) &th->step_prev);
th->stepped = 0;
}
return;
}
/* Single step (in a painstaking fashion) by inspecting the current
instruction and setting a breakpoint on the "next" instruction
which would be executed. This code hails from sh-stub.c.
*/
void
wince_software_single_step (unsigned int ignore, int insert_breakpoints_p)
{
thread_info *th = current_thread; /* Info on currently selected thread */
if (!insert_breakpoints_p)
{
undoSStep (th);
return;
}
th->stepped = 1;
th->step_pc = sh_get_next_pc (&th->context);
th->step_prev = 0;
memory_insert_breakpoint (th->step_pc, (void *) &th->step_prev);
return;
}
#elif defined (ARM)
#undef check_for_step
static enum target_signal
check_for_step (DEBUG_EVENT *ev, enum target_signal x)
{
thread_info *th = thread_rec (ev->dwThreadId, 1);
if (th->stepped &&
th->step_pc == (CORE_ADDR) ev->u.Exception.ExceptionRecord.ExceptionAddress)
return TARGET_SIGNAL_TRAP;
else
return x;
}
/* Single step (in a painstaking fashion) by inspecting the current
instruction and setting a breakpoint on the "next" instruction
which would be executed. This code hails from sh-stub.c.
*/
static void
undoSStep (thread_info * th)
{
if (th->stepped)
{
memory_remove_breakpoint (th->step_pc, (void *) &th->step_prev);
th->stepped = 0;
}
}
void
wince_software_single_step (unsigned int ignore, int insert_breakpoints_p)
{
unsigned long pc;
thread_info *th = current_thread; /* Info on currently selected thread */
CORE_ADDR mips_next_pc (CORE_ADDR pc);
if (!insert_breakpoints_p)
{
undoSStep (th);
return;
}
th->stepped = 1;
pc = read_register (PC_REGNUM);
th->step_pc = arm_get_next_pc (pc);
th->step_prev = 0;
memory_insert_breakpoint (th->step_pc, (void *) &th->step_prev);
return;
}
#endif
/* Find a thread record given a thread id. /* Find a thread record given a thread id.
If get_context then also retrieve the context for this If get_context then also retrieve the context for this
thread. */ thread. */
@ -893,22 +1113,6 @@ check (BOOL ok, const char *file, int line)
printf_filtered ("error return %s:%d was %d\n", file, line, GetLastError ()); printf_filtered ("error return %s:%d was %d\n", file, line, GetLastError ());
} }
/* Return a pointer into a CONTEXT field indexed by gdb register number.
Return a pointer to an address pointing to zero if there is no
corresponding CONTEXT field for the given register number.
*/
static ULONG *
regptr (LPCONTEXT c, int r)
{
static ULONG zero = 0;
ULONG *p;
if (mappings[r] < 0)
p = &zero;
else
p = (ULONG *) (((char *) c) + mappings[r]);
return p;
}
static void static void
do_child_fetch_inferior_registers (int r) do_child_fetch_inferior_registers (int r)
{ {
@ -991,7 +1195,9 @@ handle_load_dll (PTR dummy)
out: out:
if (!len) if (!len)
return 1; return 1;
#if 0
dll_buf[len] = '\0'; dll_buf[len] = '\0';
#endif
dll_name = alloca (len); dll_name = alloca (len);
if (!dll_name) if (!dll_name)
@ -1021,22 +1227,12 @@ out:
FIXME: Is this the real reason that we need the 0x1000 ? */ FIXME: Is this the real reason that we need the 0x1000 ? */
printf_unfiltered ("%x:%s", event->lpBaseOfDll, dll_name); printf_unfiltered ("%x:%s", event->lpBaseOfDll, dll_name);
#if 0 /* FIXME: Need to use RAPI stuff to read the file someday. */
{
struct section_addr_info section_addrs;
memset (&section_addrs, 0, sizeof (section_addrs));
section_addrs.text_addr = (int) event->lpBaseOfDll + 0x1000;
symbol_file_add (dll_name, 0, &section_addrs, 0, OBJF_SHARED);
}
#endif
printf_unfiltered ("\n"); printf_unfiltered ("\n");
return 1; return 1;
} }
/* Handle DEBUG_STRING output from child process. /* Handle DEBUG_STRING output from child process. */
Cygwin prepends its messages with a "cygwin:". Interpret this as
a Cygwin signal. Otherwise just print the string as a warning. */
static void static void
handle_output_debug_string (struct target_waitstatus *ourstatus) handle_output_debug_string (struct target_waitstatus *ourstatus)
{ {
@ -1068,6 +1264,7 @@ handle_output_debug_string (struct target_waitstatus *ourstatus)
} }
warning (s); warning (s);
return; return;
} }
@ -1075,16 +1272,13 @@ handle_output_debug_string (struct target_waitstatus *ourstatus)
static int static int
handle_exception (struct target_waitstatus *ourstatus) handle_exception (struct target_waitstatus *ourstatus)
{ {
thread_info *th; #if 0
if (current_event.u.Exception.dwFirstChance) if (current_event.u.Exception.dwFirstChance)
return 0; return 0;
#endif
ourstatus->kind = TARGET_WAITKIND_STOPPED; ourstatus->kind = TARGET_WAITKIND_STOPPED;
/* Record the context of the current thread */
th = thread_rec (current_event.dwThreadId, -1);
switch (current_event.u.Exception.ExceptionRecord.ExceptionCode) switch (current_event.u.Exception.ExceptionRecord.ExceptionCode)
{ {
case EXCEPTION_ACCESS_VIOLATION: case EXCEPTION_ACCESS_VIOLATION:
@ -1114,10 +1308,15 @@ handle_exception (struct target_waitstatus *ourstatus)
(unsigned) current_event.u.Exception.ExceptionRecord.ExceptionAddress)); (unsigned) current_event.u.Exception.ExceptionRecord.ExceptionAddress));
ourstatus->value.sig = TARGET_SIGNAL_TRAP; ourstatus->value.sig = TARGET_SIGNAL_TRAP;
break; break;
case EXCEPTION_ILLEGAL_INSTRUCTION:
DEBUG_EXCEPT (("gdb: Target exception SINGLE_ILL at 0x%08x\n",
current_event.u.Exception.ExceptionRecord.ExceptionAddress));
ourstatus->value.sig = check_for_step (&current_event, TARGET_SIGNAL_ILL);
break;
default: default:
/* This may be a structured exception handling exception. In /* This may be a structured exception handling exception. In
that case, we want to let the program try to handle it, and that case, we want to let the program try to handle it, and
only break if we see the exception a second time. */ only break if we see the exception a second time. */
printf_unfiltered ("gdb: unknown target exception 0x%08x at 0x%08x\n", printf_unfiltered ("gdb: unknown target exception 0x%08x at 0x%08x\n",
current_event.u.Exception.ExceptionRecord.ExceptionCode, current_event.u.Exception.ExceptionRecord.ExceptionCode,
@ -1159,23 +1358,29 @@ child_continue (DWORD continue_status, int id)
handling by WFI (or whatever). handling by WFI (or whatever).
*/ */
static int static int
get_child_debug_event (int pid, struct target_waitstatus *ourstatus, DWORD * event_code, int *retval) get_child_debug_event (int pid, struct target_waitstatus *ourstatus,
DWORD target_event_code, int *retval)
{ {
int breakout = 0;
BOOL debug_event; BOOL debug_event;
DWORD continue_status; DWORD continue_status, event_code;
int breakout = 1; thread_info *th = NULL;
static thread_info dummy_thread_info;
if (!(debug_event = wait_for_debug_event (&current_event, 1000))) if (!(debug_event = wait_for_debug_event (&current_event, 1000)))
{ {
breakout = *retval = *event_code = 0; *retval = 0;
goto out; goto out;
} }
this_thread = thread_rec (current_event.dwThreadId, FALSE);
event_count++; event_count++;
continue_status = DBG_CONTINUE; continue_status = DBG_CONTINUE;
*retval = 0; *retval = 0;
switch (*event_code = current_event.dwDebugEventCode)
event_code = current_event.dwDebugEventCode;
breakout = event_code == target_event_code;
switch (event_code)
{ {
case CREATE_THREAD_DEBUG_EVENT: case CREATE_THREAD_DEBUG_EVENT:
DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%x code=%s)\n", DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%x code=%s)\n",
@ -1183,8 +1388,8 @@ get_child_debug_event (int pid, struct target_waitstatus *ourstatus, DWORD * eve
(unsigned) current_event.dwThreadId, (unsigned) current_event.dwThreadId,
"CREATE_THREAD_DEBUG_EVENT")); "CREATE_THREAD_DEBUG_EVENT"));
/* Record the existence of this thread */ /* Record the existence of this thread */
child_add_thread (current_event.dwThreadId, th = child_add_thread (current_event.dwThreadId,
current_event.u.CreateThread.hThread); current_event.u.CreateThread.hThread);
if (info_verbose) if (info_verbose)
printf_unfiltered ("[New %s]\n", printf_unfiltered ("[New %s]\n",
target_pid_to_str (current_event.dwThreadId)); target_pid_to_str (current_event.dwThreadId));
@ -1196,6 +1401,7 @@ get_child_debug_event (int pid, struct target_waitstatus *ourstatus, DWORD * eve
(unsigned) current_event.dwThreadId, (unsigned) current_event.dwThreadId,
"EXIT_THREAD_DEBUG_EVENT")); "EXIT_THREAD_DEBUG_EVENT"));
child_delete_thread (current_event.dwThreadId); child_delete_thread (current_event.dwThreadId);
th = &dummy_thread_info;
break; break;
case CREATE_PROCESS_DEBUG_EVENT: case CREATE_PROCESS_DEBUG_EVENT:
@ -1207,8 +1413,8 @@ get_child_debug_event (int pid, struct target_waitstatus *ourstatus, DWORD * eve
main_thread_id = inferior_pid = current_event.dwThreadId; main_thread_id = inferior_pid = current_event.dwThreadId;
/* Add the main thread */ /* Add the main thread */
current_thread = child_add_thread (inferior_pid, th = child_add_thread (inferior_pid,
current_event.u.CreateProcessInfo.hThread); current_event.u.CreateProcessInfo.hThread);
break; break;
case EXIT_PROCESS_DEBUG_EVENT: case EXIT_PROCESS_DEBUG_EVENT:
@ -1220,7 +1426,8 @@ get_child_debug_event (int pid, struct target_waitstatus *ourstatus, DWORD * eve
ourstatus->value.integer = current_event.u.ExitProcess.dwExitCode; ourstatus->value.integer = current_event.u.ExitProcess.dwExitCode;
close_handle (current_process_handle); close_handle (current_process_handle);
*retval = current_event.dwProcessId; *retval = current_event.dwProcessId;
goto out; breakout = 1;
break;
case LOAD_DLL_DEBUG_EVENT: case LOAD_DLL_DEBUG_EVENT:
DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n", DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n",
@ -1244,14 +1451,12 @@ get_child_debug_event (int pid, struct target_waitstatus *ourstatus, DWORD * eve
(unsigned) current_event.dwThreadId, (unsigned) current_event.dwThreadId,
"EXCEPTION_DEBUG_EVENT")); "EXCEPTION_DEBUG_EVENT"));
if (handle_exception (ourstatus)) if (handle_exception (ourstatus))
*retval = current_event.dwThreadId;
else
{ {
char buf[32]; continue_status = DBG_EXCEPTION_NOT_HANDLED;
*retval = current_event.dwThreadId; breakout = 0;
remote_read_bytes (read_pc (), buf, sizeof (buf));
dcache_xfer_memory (remote_dcache, read_pc (), buf, sizeof (buf), 0);
goto out;
} }
continue_status = DBG_EXCEPTION_NOT_HANDLED;
break; break;
case OUTPUT_DEBUG_STRING_EVENT: /* message from the kernel */ case OUTPUT_DEBUG_STRING_EVENT: /* message from the kernel */
@ -1259,7 +1464,7 @@ get_child_debug_event (int pid, struct target_waitstatus *ourstatus, DWORD * eve
(unsigned) current_event.dwProcessId, (unsigned) current_event.dwProcessId,
(unsigned) current_event.dwThreadId, (unsigned) current_event.dwThreadId,
"OUTPUT_DEBUG_STRING_EVENT")); "OUTPUT_DEBUG_STRING_EVENT"));
handle_output_debug_string (ourstatus); handle_output_debug_string ( ourstatus);
break; break;
default: default:
printf_unfiltered ("gdb: kernel event for pid=%d tid=%d\n", printf_unfiltered ("gdb: kernel event for pid=%d tid=%d\n",
@ -1270,8 +1475,10 @@ get_child_debug_event (int pid, struct target_waitstatus *ourstatus, DWORD * eve
break; break;
} }
breakout = 0; if (breakout)
CHECK (child_continue (continue_status, -1)); this_thread = current_thread = th ?: thread_rec (current_event.dwThreadId, TRUE);
else
CHECK (child_continue (continue_status, -1));
out: out:
return breakout; return breakout;
@ -1291,7 +1498,7 @@ child_wait (int pid, struct target_waitstatus *ourstatus)
isn't necessarily what you think it is. */ isn't necessarily what you think it is. */
while (1) while (1)
if (get_child_debug_event (pid, ourstatus, &event_code, &retval)) if (get_child_debug_event (pid, ourstatus, EXCEPTION_DEBUG_EVENT, &retval))
return retval; return retval;
else else
{ {
@ -1351,14 +1558,15 @@ char *
upload_to_device (const char *to, const char *from) upload_to_device (const char *to, const char *from)
{ {
HANDLE h; HANDLE h;
const char *dir = remote_directory ? : "\\gdb"; const char *dir = remote_directory ?: "\\gdb";
int len; int len;
static char *remotefile = NULL; static char *remotefile = NULL;
LPWSTR wstr; LPWSTR wstr;
char *p; char *p;
DWORD err; DWORD err;
const char *in_to = to; const char *in_to = to;
FILETIME ctime, atime, wtime; FILETIME crtime, actime, wrtime;
time_t utime;
struct stat st; struct stat st;
int fd; int fd;
@ -1397,15 +1605,25 @@ upload_to_device (const char *to, const char *from)
/* Some kind of problem? */ /* Some kind of problem? */
err = CeGetLastError (); err = CeGetLastError ();
if (h == NULL) if (h == NULL || h == INVALID_HANDLE_VALUE)
error ("error creating file to \"%s\". Windows error %d.", error ("error opening file \"%s\". Windows error %d.",
remotefile, err); remotefile, err);
CeGetFileTime (h, &crtime, &actime, &wrtime);
utime = to_time_t (&wrtime);
#if 0
if (utime < st.st_mtime)
{
char buf[80];
strcpy (buf, ctime(&utime));
printf ("%s < %s\n", buf, ctime(&st.st_mtime));
}
#endif
/* See if we need to upload the file. */ /* See if we need to upload the file. */
if (upload_when == UPLOAD_ALWAYS || if (upload_when == UPLOAD_ALWAYS ||
err != ERROR_ALREADY_EXISTS || err != ERROR_ALREADY_EXISTS ||
!CeGetFileTime (h, &ctime, &atime, &wtime) || !CeGetFileTime (h, &crtime, &actime, &wrtime) ||
to_time_t (&wtime) < st.st_mtime) to_time_t (&wrtime) < st.st_mtime)
{ {
DWORD nbytes; DWORD nbytes;
char buf[4096]; char buf[4096];
@ -1419,7 +1637,8 @@ upload_to_device (const char *to, const char *from)
} }
close (fd); close (fd);
CeCloseHandle (h); if (!CeCloseHandle (h))
error ("error closing remote file - %d.", CeGetLastError ());
return remotefile; return remotefile;
} }
@ -1555,11 +1774,10 @@ child_create_inferior (char *exec_file, char *args, char **env)
target_terminal_init (); target_terminal_init ();
target_terminal_inferior (); target_terminal_inferior ();
/* Run until process and threads are loaded */ /* Run until process and threads are loaded */
do while (!get_child_debug_event (inferior_pid, &dummy,
get_child_debug_event (inferior_pid, &dummy, &event_code, &ret); CREATE_PROCESS_DEBUG_EVENT, &ret))
while (event_code != CREATE_PROCESS_DEBUG_EVENT); continue;
proceed ((CORE_ADDR) -1, TARGET_SIGNAL_0, 0); proceed ((CORE_ADDR) -1, TARGET_SIGNAL_0, 0);
} }
@ -1607,213 +1825,6 @@ child_kill_inferior (void)
target_mourn_inferior (); /* or just child_mourn_inferior? */ target_mourn_inferior (); /* or just child_mourn_inferior? */
} }
#ifdef MIPS
static void
undoSStep (thread_info * th)
{
if (th->stepped)
{
memory_remove_breakpoint (th->step_pc, (void *) &th->step_prev);
th->stepped = 0;
}
}
void
wince_software_single_step (unsigned int ignore, int insert_breakpoints_p)
{
unsigned long pc;
thread_info *th = current_thread; /* Info on currently selected thread */
CORE_ADDR mips_next_pc (CORE_ADDR pc);
if (!insert_breakpoints_p)
{
undoSStep (th);
return;
}
th->stepped = 1;
pc = read_register (PC_REGNUM);
th->step_pc = mips_next_pc (pc);
th->step_prev = 0;
memory_insert_breakpoint (th->step_pc, (void *) &th->step_prev);
}
#elif SHx
/* Hitachi SH architecture instruction encoding masks */
#define COND_BR_MASK 0xff00
#define UCOND_DBR_MASK 0xe000
#define UCOND_RBR_MASK 0xf0df
#define TRAPA_MASK 0xff00
#define COND_DISP 0x00ff
#define UCOND_DISP 0x0fff
#define UCOND_REG 0x0f00
/* Hitachi SH instruction opcodes */
#define BF_INSTR 0x8b00
#define BT_INSTR 0x8900
#define BRA_INSTR 0xa000
#define BSR_INSTR 0xb000
#define JMP_INSTR 0x402b
#define JSR_INSTR 0x400b
#define RTS_INSTR 0x000b
#define RTE_INSTR 0x002b
#define TRAPA_INSTR 0xc300
#define SSTEP_INSTR 0xc3ff
#define T_BIT_MASK 0x0001
/* Undo the effect of a previous doSStep. If we single stepped,
restore the old instruction. */
static void
undoSStep (thread_info * th)
{
if (th->stepped)
{
gdb_wince_len done;
write_process_memory (current_process_handle, (LPVOID) th->step_pc,
(LPVOID) & th->step_instr, sizeof (short), &done);
if (done != sizeof (short))
error ("error unsetting single step.");
th->stepped = 0;
}
}
/* Single step (in a painstaking fashion) by inspecting the current
instruction and setting a breakpoint on the "next" instruction
which would be executed. This code hails from sh-stub.c.
*/
void
wince_software_single_step (unsigned int ignore, int insert_breakpoints_p)
{
thread_info *th = current_thread; /* Info on currently selected thread */
if (!insert_breakpoints_p)
undoSStep (th);
else
{
short *instrMem;
int displacement;
int reg;
unsigned short opcode;
gdb_wince_len done;
LPCONTEXT c = &th->context;
instrMem = (short *) c->Fir;
read_process_memory (current_process_handle, (LPCVOID) c->Fir, &opcode,
sizeof (opcode), &done);
if (done != sizeof (opcode))
error ("couldn't retrieve opcode");
th->stepped = 1;
if ((opcode & COND_BR_MASK) == BT_INSTR)
{
if (c->Psr & T_BIT_MASK)
{
displacement = (opcode & COND_DISP) << 1;
if (displacement & 0x80)
displacement |= 0xffffff00;
/*
* Remember PC points to second instr.
* after PC of branch ... so add 4
*/
instrMem = (short *) (c->Fir + displacement + 4);
}
else
instrMem += 1;
}
else if ((opcode & COND_BR_MASK) == BF_INSTR)
{
if (c->Psr & T_BIT_MASK)
instrMem += 1;
else
{
displacement = (opcode & COND_DISP) << 1;
if (displacement & 0x80)
displacement |= 0xffffff00;
/*
* Remember PC points to second instr.
* after PC of branch ... so add 4
*/
instrMem = (short *) (c->Fir + displacement + 4);
}
}
else if ((opcode & UCOND_DBR_MASK) == BRA_INSTR)
{
displacement = (opcode & UCOND_DISP) << 1;
if (displacement & 0x0800)
displacement |= 0xfffff000;
/*
* Remember PC points to second instr.
* after PC of branch ... so add 4
*/
instrMem = (short *) (c->Fir + displacement + 4);
}
else if ((opcode & UCOND_RBR_MASK) == JSR_INSTR)
{
reg = (char) ((opcode & UCOND_REG) >> 8);
instrMem = (short *) *regptr (c, reg);
}
else if (opcode == RTS_INSTR)
instrMem = (short *) c->PR;
else if (opcode == RTE_INSTR)
instrMem = (short *) *regptr (c, 15);
else if ((opcode & TRAPA_MASK) == TRAPA_INSTR)
instrMem = (short *) ((opcode & ~TRAPA_MASK) << 2);
else
instrMem += 1;
th->step_pc = (CORE_ADDR) instrMem;
read_process_memory (current_process_handle, (LPVOID) instrMem,
(LPVOID) & th->step_instr, sizeof (short), &done);
opcode = SSTEP_INSTR;
write_process_memory (current_process_handle, (LPVOID) instrMem,
(LPVOID) & opcode, sizeof (short), &done);
}
}
#elif defined (ARM)
/* Single step (in a painstaking fashion) by inspecting the current
instruction and setting a breakpoint on the "next" instruction
which would be executed. This code hails from sh-stub.c.
*/
static void
undoSStep (thread_info * th)
{
if (th->stepped)
{
memory_remove_breakpoint (th->step_pc, (void *) &th->step_prev);
th->stepped = 0;
}
}
void
wince_software_single_step (unsigned int ignore, int insert_breakpoints_p)
{
unsigned long pc;
thread_info *th = current_thread; /* Info on currently selected thread */
CORE_ADDR mips_next_pc (CORE_ADDR pc);
if (!insert_breakpoints_p)
{
undoSStep (th);
return;
}
th->stepped = 1;
pc = read_register (PC_REGNUM);
th->step_pc = arm_get_next_pc (pc);
th->step_prev = 0;
memory_insert_breakpoint (th->step_pc, (void *) &th->step_prev);
}
#endif
/* Resume the child after an exception. */ /* Resume the child after an exception. */
void void
child_resume (int pid, int step, enum target_signal sig) child_resume (int pid, int step, enum target_signal sig)
@ -1917,8 +1928,8 @@ init_child_ops (void)
/* Handle 'set remoteupload' parameter. */ /* Handle 'set remoteupload' parameter. */
#define replace_upload(what) \ #define replace_upload(what) \
upload_when = UPLOAD_NEWER; \ upload_when = what; \
remote_upload = realloc (remote_upload, strlen (upload_options[upload_when].name)); \ remote_upload = realloc (remote_upload, strlen (upload_options[upload_when].name) + 1); \
strcpy (remote_upload, upload_options[upload_when].name); strcpy (remote_upload, upload_options[upload_when].name);
static void static void
@ -1940,8 +1951,7 @@ set_upload_type (char *ignore, int from_tty)
if (len >= upload_options[i].abbrev && if (len >= upload_options[i].abbrev &&
strncasecmp (remote_upload, upload_options[i].name, len) == 0) strncasecmp (remote_upload, upload_options[i].name, len) == 0)
{ {
remote_upload = (char *) upload_options[i].name; replace_upload (i);
upload_when = i;
return; return;
} }