* win32_nat.c (cygwin_load_start): New variable.
(cygwin_load_end): Ditto. (have_saved_context): Ditto. (saved_context): Ditto. (max_dll_name_len): Delete obsolete variable. (do_win32_fetch_inferior_registers): Use context saved from cygwin1.dll if we are in a cygwin signal rather than a windows signal. (solib_symbols_add): Detect and store beginning and end of cygwin DLL if dll being loaded is the cygwin DLL. (register_loaded_dll): Remove calculation of max_dll_name_len. (win32_clear_solib): Ditto. (handle_load_dll): Delete obsolete variable. Remove unneeded call to solib_add. (handle_output_debug_string): Detect and store signal information sent by Cygwin here. (handle_exception): Silently pass on errors in the cygwin DLL. Return -1 on first pass exception. (win32_continue): Remove spurious clearing of continue_status. (get_win32_debug_event): Deal differently first chance exception.
This commit is contained in:
parent
e78254f677
commit
a244bdca25
@ -1,3 +1,25 @@
|
||||
2006-02-19 Christopher Faylor <cgf@timesys.com>
|
||||
|
||||
* win32_nat.c (cygwin_load_start): New variable.
|
||||
(cygwin_load_end): Ditto.
|
||||
(have_saved_context): Ditto.
|
||||
(saved_context): Ditto.
|
||||
(max_dll_name_len): Delete obsolete variable.
|
||||
(do_win32_fetch_inferior_registers): Use context saved from cygwin1.dll
|
||||
if we are in a cygwin signal rather than a windows signal.
|
||||
(solib_symbols_add): Detect and store beginning and end of cygwin DLL
|
||||
if dll being loaded is the cygwin DLL.
|
||||
(register_loaded_dll): Remove calculation of max_dll_name_len.
|
||||
(win32_clear_solib): Ditto.
|
||||
(handle_load_dll): Delete obsolete variable. Remove unneeded call to
|
||||
solib_add.
|
||||
(handle_output_debug_string): Detect and store signal information sent
|
||||
by Cygwin here.
|
||||
(handle_exception): Silently pass on errors in the cygwin DLL. Return
|
||||
-1 on first pass exception.
|
||||
(win32_continue): Remove spurious clearing of continue_status.
|
||||
(get_win32_debug_event): Deal differently first chance exception.
|
||||
|
||||
2006-02-19 Randolph Chung <tausq@debian.org>
|
||||
|
||||
* hppa-tdep.c (hppa_in_solib_call_trampoline): Only use if no
|
||||
|
308
gdb/win32-nat.c
308
gdb/win32-nat.c
@ -44,6 +44,7 @@
|
||||
#include <windows.h>
|
||||
#include <imagehlp.h>
|
||||
#include <sys/cygwin.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "buildsym.h"
|
||||
#include "symfile.h"
|
||||
@ -63,6 +64,13 @@
|
||||
static struct target_ops win32_ops;
|
||||
static struct target_so_ops win32_so_ops;
|
||||
|
||||
/* The starting and ending address of the cygwin1.dll text segment. */
|
||||
static bfd_vma cygwin_load_start;
|
||||
static bfd_vma cygwin_load_end;
|
||||
|
||||
static int have_saved_context; /* True if we've saved context from a cygwin signal. */
|
||||
static CONTEXT saved_context; /* Containes the saved context from a cygwin signal. */
|
||||
|
||||
/* If we're not using the old Cygwin header file set, define the
|
||||
following which never should have been in the generic Win32 API
|
||||
headers in the first place since they were our own invention... */
|
||||
@ -346,16 +354,27 @@ do_win32_fetch_inferior_registers (int r)
|
||||
|
||||
if (current_thread->reload_context)
|
||||
{
|
||||
thread_info *th = current_thread;
|
||||
th->context.ContextFlags = CONTEXT_DEBUGGER_DR;
|
||||
GetThreadContext (th->h, &th->context);
|
||||
/* Copy dr values from that thread. */
|
||||
dr[0] = th->context.Dr0;
|
||||
dr[1] = th->context.Dr1;
|
||||
dr[2] = th->context.Dr2;
|
||||
dr[3] = th->context.Dr3;
|
||||
dr[6] = th->context.Dr6;
|
||||
dr[7] = th->context.Dr7;
|
||||
if (have_saved_context)
|
||||
{
|
||||
/* Lie about where the program actually is stopped since cygwin has informed us that
|
||||
we should consider the signal to have occurred at another location which is stored
|
||||
in "saved_context. */
|
||||
memcpy (¤t_thread->context, &saved_context, __COPY_CONTEXT_SIZE);
|
||||
have_saved_context = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
thread_info *th = current_thread;
|
||||
th->context.ContextFlags = CONTEXT_DEBUGGER_DR;
|
||||
GetThreadContext (th->h, &th->context);
|
||||
/* Copy dr values from that thread. */
|
||||
dr[0] = th->context.Dr0;
|
||||
dr[1] = th->context.Dr1;
|
||||
dr[2] = th->context.Dr2;
|
||||
dr[3] = th->context.Dr3;
|
||||
dr[6] = th->context.Dr6;
|
||||
dr[7] = th->context.Dr7;
|
||||
}
|
||||
current_thread->reload_context = 0;
|
||||
}
|
||||
|
||||
@ -596,12 +615,10 @@ get_relocated_section_addrs (bfd *abfd, CORE_ADDR text_load)
|
||||
{
|
||||
/* Couldn't get the .text section. Weird. */
|
||||
}
|
||||
|
||||
else if (text_load == (text_vma = bfd_get_section_vma (abfd, text_section)))
|
||||
{
|
||||
/* DLL wasn't relocated. */
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
/* Figure out all sections' loaded addresses. The offset here is
|
||||
@ -640,6 +657,7 @@ solib_symbols_add (struct so_list *so, CORE_ADDR load_addr)
|
||||
static struct objfile *result = NULL;
|
||||
char *name = so->so_name;
|
||||
bfd *abfd = NULL;
|
||||
char *p;
|
||||
|
||||
/* The symbols in a dll are offset by 0x1000, which is the
|
||||
the offset from 0 of the first byte in an image - because
|
||||
@ -660,8 +678,6 @@ solib_symbols_add (struct so_list *so, CORE_ADDR load_addr)
|
||||
{
|
||||
if (bfd_check_format (abfd, bfd_object))
|
||||
addrs = get_relocated_section_addrs (abfd, load_addr);
|
||||
|
||||
bfd_close (abfd);
|
||||
}
|
||||
|
||||
if (addrs)
|
||||
@ -683,13 +699,20 @@ solib_symbols_add (struct so_list *so, CORE_ADDR load_addr)
|
||||
do_cleanups (my_cleanups);
|
||||
}
|
||||
|
||||
p = strchr (so->so_name, '\0') - (sizeof ("/cygwin1.dll") - 1);
|
||||
if (p >= so->so_name && strcasecmp (p, "/cygwin1.dll") == 0)
|
||||
{
|
||||
asection *text = bfd_get_section_by_name (abfd, ".text");
|
||||
cygwin_load_start = bfd_section_vma (abfd, text);
|
||||
cygwin_load_end = cygwin_load_start + bfd_section_size (abfd, text);
|
||||
}
|
||||
|
||||
bfd_close (abfd);
|
||||
|
||||
so->symbols_loaded = !!result;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Remember the maximum DLL length for printing in info dll command. */
|
||||
static int max_dll_name_len;
|
||||
|
||||
static char *
|
||||
register_loaded_dll (const char *name, DWORD load_addr, int readsyms)
|
||||
{
|
||||
@ -733,10 +756,9 @@ register_loaded_dll (const char *name, DWORD load_addr, int readsyms)
|
||||
solib_end->next = so;
|
||||
solib_end = so;
|
||||
len = strlen (so->so_name);
|
||||
if (len > max_dll_name_len)
|
||||
max_dll_name_len = len;
|
||||
if (readsyms)
|
||||
solib_symbols_add (so, (CORE_ADDR) load_addr);
|
||||
|
||||
return so->so_name;
|
||||
}
|
||||
|
||||
@ -789,7 +811,6 @@ handle_load_dll (void *dummy)
|
||||
LOAD_DLL_DEBUG_INFO *event = ¤t_event.u.LoadDll;
|
||||
char dll_buf[MAX_PATH + 1];
|
||||
char *dll_name = NULL;
|
||||
char *p;
|
||||
|
||||
dll_buf[0] = dll_buf[sizeof (dll_buf) - 1] = '\0';
|
||||
|
||||
@ -804,7 +825,6 @@ handle_load_dll (void *dummy)
|
||||
return 1;
|
||||
|
||||
register_loaded_dll (dll_name, (DWORD) event->lpBaseOfDll + 0x1000, auto_solib_add);
|
||||
solib_add (NULL, 0, NULL, auto_solib_add);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -860,7 +880,6 @@ win32_clear_solib (void)
|
||||
{
|
||||
solib_start.next = NULL;
|
||||
solib_end = &solib_start;
|
||||
max_dll_name_len = sizeof ("DLL Name") - 1;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -897,31 +916,49 @@ dll_symbol_command (char *args, int from_tty)
|
||||
static int
|
||||
handle_output_debug_string (struct target_waitstatus *ourstatus)
|
||||
{
|
||||
char *s;
|
||||
int gotasig = FALSE;
|
||||
char *s = NULL;
|
||||
int retval = 0;
|
||||
|
||||
if (!target_read_string
|
||||
((CORE_ADDR) current_event.u.DebugString.lpDebugStringData, &s, 1024, 0)
|
||||
|| !s || !*s)
|
||||
return gotasig;
|
||||
|
||||
if (strncmp (s, _CYGWIN_SIGNAL_STRING, sizeof (_CYGWIN_SIGNAL_STRING) - 1) != 0)
|
||||
/* nothing to do */;
|
||||
else if (strncmp (s, _CYGWIN_SIGNAL_STRING, sizeof (_CYGWIN_SIGNAL_STRING) - 1) != 0)
|
||||
{
|
||||
if (strncmp (s, "cYg", 3) != 0)
|
||||
warning (("%s"), s);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Got a cygwin signal marker. A cygwin signal is followed by the signal number
|
||||
itself and then optionally followed by the thread id and address to saved context
|
||||
within the DLL. If these are supplied, then the given thread is assumed to have
|
||||
issued the signal and the context from the thread is assumed to be stored at the
|
||||
given address in the inferior. Tell gdb to treat this like a real signal. */
|
||||
char *p;
|
||||
int sig = strtol (s + sizeof (_CYGWIN_SIGNAL_STRING) - 1, &p, 0);
|
||||
gotasig = target_signal_from_host (sig);
|
||||
int gotasig = target_signal_from_host (sig);
|
||||
ourstatus->value.sig = gotasig;
|
||||
if (gotasig)
|
||||
ourstatus->kind = TARGET_WAITKIND_STOPPED;
|
||||
{
|
||||
LPCVOID x;
|
||||
DWORD n;
|
||||
ourstatus->kind = TARGET_WAITKIND_STOPPED;
|
||||
retval = strtoul (p, &p, 0);
|
||||
if (!retval)
|
||||
retval = main_thread_id;
|
||||
else if ((x = (LPCVOID) strtoul (p, &p, 0))
|
||||
&& ReadProcessMemory (current_process_handle, x,
|
||||
&saved_context, __COPY_CONTEXT_SIZE, &n)
|
||||
&& n == __COPY_CONTEXT_SIZE)
|
||||
have_saved_context = 1;
|
||||
current_event.dwThreadId = retval;
|
||||
}
|
||||
}
|
||||
|
||||
xfree (s);
|
||||
return gotasig;
|
||||
if (s)
|
||||
xfree (s);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1065,11 +1102,17 @@ handle_exception (struct target_waitstatus *ourstatus)
|
||||
DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ACCESS_VIOLATION");
|
||||
ourstatus->value.sig = TARGET_SIGNAL_SEGV;
|
||||
{
|
||||
/* See if the access violation happened within the cygwin DLL itself. Cygwin uses
|
||||
a kind of exception handling to deal with passed-in invalid addresses. gdb
|
||||
should not treat these as real SEGVs since they will be silently handled by
|
||||
cygwin. A real SEGV will (theoretically) be caught by cygwin later in the process
|
||||
and will be sent as a cygwin-specific-signal. So, ignore SEGVs if they show up
|
||||
within the text segment of the DLL itself. */
|
||||
char *fn;
|
||||
if (find_pc_partial_function ((CORE_ADDR) current_event.u.Exception
|
||||
.ExceptionRecord.ExceptionAddress,
|
||||
&fn, NULL, NULL)
|
||||
&& strncmp (fn, "KERNEL32!IsBad", strlen ("KERNEL32!IsBad")) == 0)
|
||||
bfd_vma addr = (bfd_vma) current_event.u.Exception.ExceptionRecord.ExceptionAddress;
|
||||
if ((addr >= cygwin_load_start && addr < cygwin_load_end)
|
||||
|| (find_pc_partial_function (addr, &fn, NULL, NULL)
|
||||
&& strncmp (fn, "KERNEL32!IsBad", strlen ("KERNEL32!IsBad")) == 0))
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
@ -1146,8 +1189,9 @@ handle_exception (struct target_waitstatus *ourstatus)
|
||||
ourstatus->value.sig = TARGET_SIGNAL_ILL;
|
||||
break;
|
||||
default:
|
||||
/* Treat unhandled first chance exceptions specially. */
|
||||
if (current_event.u.Exception.dwFirstChance)
|
||||
return 0;
|
||||
return -1;
|
||||
printf_unfiltered ("gdb: unknown target exception 0x%08lx at 0x%08lx\n",
|
||||
current_event.u.Exception.ExceptionRecord.ExceptionCode,
|
||||
(DWORD) current_event.u.Exception.ExceptionRecord.ExceptionAddress);
|
||||
@ -1175,7 +1219,6 @@ win32_continue (DWORD continue_status, int id)
|
||||
res = ContinueDebugEvent (current_event.dwProcessId,
|
||||
current_event.dwThreadId,
|
||||
continue_status);
|
||||
continue_status = 0;
|
||||
if (res)
|
||||
for (th = &thread_head; (th = th->next) != NULL;)
|
||||
if (((id == -1) || (id == (int) th->id)) && th->suspend_count)
|
||||
@ -1217,6 +1260,87 @@ fake_create_process (void)
|
||||
return main_thread_id;
|
||||
}
|
||||
|
||||
static void
|
||||
win32_resume (ptid_t ptid, int step, enum target_signal sig)
|
||||
{
|
||||
thread_info *th;
|
||||
DWORD continue_status = DBG_CONTINUE;
|
||||
|
||||
int pid = PIDGET (ptid);
|
||||
|
||||
if (sig != TARGET_SIGNAL_0)
|
||||
{
|
||||
if (current_event.dwDebugEventCode != EXCEPTION_DEBUG_EVENT)
|
||||
{
|
||||
DEBUG_EXCEPT(("Cannot continue with signal %d here.\n",sig));
|
||||
}
|
||||
else if (sig == last_sig)
|
||||
continue_status = DBG_EXCEPTION_NOT_HANDLED;
|
||||
else
|
||||
#if 0
|
||||
/* This code does not seem to work, because
|
||||
the kernel does probably not consider changes in the ExceptionRecord
|
||||
structure when passing the exception to the inferior.
|
||||
Note that this seems possible in the exception handler itself. */
|
||||
{
|
||||
int i;
|
||||
for (i = 0; xlate[i].them != -1; i++)
|
||||
if (xlate[i].us == sig)
|
||||
{
|
||||
current_event.u.Exception.ExceptionRecord.ExceptionCode =
|
||||
xlate[i].them;
|
||||
continue_status = DBG_EXCEPTION_NOT_HANDLED;
|
||||
break;
|
||||
}
|
||||
if (continue_status == DBG_CONTINUE)
|
||||
{
|
||||
DEBUG_EXCEPT(("Cannot continue with signal %d.\n",sig));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
DEBUG_EXCEPT(("Can only continue with recieved signal %d.\n",
|
||||
last_sig));
|
||||
}
|
||||
|
||||
last_sig = TARGET_SIGNAL_0;
|
||||
|
||||
DEBUG_EXEC (("gdb: win32_resume (pid=%d, step=%d, sig=%d);\n",
|
||||
pid, step, sig));
|
||||
|
||||
/* Get context for currently selected thread */
|
||||
th = thread_rec (current_event.dwThreadId, FALSE);
|
||||
if (th)
|
||||
{
|
||||
if (step)
|
||||
{
|
||||
/* Single step by setting t bit */
|
||||
win32_fetch_inferior_registers (PS_REGNUM);
|
||||
th->context.EFlags |= FLAG_TRACE_BIT;
|
||||
}
|
||||
|
||||
if (th->context.ContextFlags)
|
||||
{
|
||||
if (debug_registers_changed)
|
||||
{
|
||||
th->context.Dr0 = dr[0];
|
||||
th->context.Dr1 = dr[1];
|
||||
th->context.Dr2 = dr[2];
|
||||
th->context.Dr3 = dr[3];
|
||||
/* th->context.Dr6 = dr[6];
|
||||
FIXME: should we set dr6 also ?? */
|
||||
th->context.Dr7 = dr[7];
|
||||
}
|
||||
CHECK (SetThreadContext (th->h, &th->context));
|
||||
th->context.ContextFlags = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allow continuing with the same signal that interrupted us.
|
||||
Otherwise complain. */
|
||||
|
||||
win32_continue (continue_status, pid);
|
||||
}
|
||||
|
||||
/* Get the next event from the child. Return 1 if the event requires
|
||||
handling by WFI (or whatever).
|
||||
*/
|
||||
@ -1228,6 +1352,7 @@ get_win32_debug_event (int pid, struct target_waitstatus *ourstatus)
|
||||
thread_info *th;
|
||||
static thread_info dummy_thread_info;
|
||||
int retval = 0;
|
||||
ptid_t ptid = {-1};
|
||||
|
||||
last_sig = TARGET_SIGNAL_0;
|
||||
|
||||
@ -1240,6 +1365,7 @@ get_win32_debug_event (int pid, struct target_waitstatus *ourstatus)
|
||||
event_code = current_event.dwDebugEventCode;
|
||||
ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
|
||||
th = NULL;
|
||||
have_saved_context = 0;
|
||||
|
||||
switch (event_code)
|
||||
{
|
||||
@ -1353,10 +1479,19 @@ get_win32_debug_event (int pid, struct target_waitstatus *ourstatus)
|
||||
"EXCEPTION_DEBUG_EVENT"));
|
||||
if (saw_create != 1)
|
||||
break;
|
||||
if (handle_exception (ourstatus))
|
||||
retval = current_event.dwThreadId;
|
||||
else
|
||||
continue_status = DBG_EXCEPTION_NOT_HANDLED;
|
||||
switch (handle_exception (ourstatus))
|
||||
{
|
||||
case 0:
|
||||
continue_status = DBG_EXCEPTION_NOT_HANDLED;
|
||||
break;
|
||||
case 1:
|
||||
retval = current_event.dwThreadId;
|
||||
break;
|
||||
case -1:
|
||||
last_sig = 1;
|
||||
continue_status = -1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case OUTPUT_DEBUG_STRING_EVENT: /* message from the kernel */
|
||||
@ -1366,8 +1501,7 @@ get_win32_debug_event (int pid, struct target_waitstatus *ourstatus)
|
||||
"OUTPUT_DEBUG_STRING_EVENT"));
|
||||
if (saw_create != 1)
|
||||
break;
|
||||
if (handle_output_debug_string (ourstatus))
|
||||
retval = main_thread_id;
|
||||
retval = handle_output_debug_string (ourstatus);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -1382,7 +1516,12 @@ get_win32_debug_event (int pid, struct target_waitstatus *ourstatus)
|
||||
}
|
||||
|
||||
if (!retval || saw_create != 1)
|
||||
CHECK (win32_continue (continue_status, -1));
|
||||
{
|
||||
if (continue_status == -1)
|
||||
win32_resume (ptid, 0, 1);
|
||||
else
|
||||
CHECK (win32_continue (continue_status, -1));
|
||||
}
|
||||
else
|
||||
{
|
||||
inferior_ptid = pid_to_ptid (retval);
|
||||
@ -1981,87 +2120,6 @@ win32_kill_inferior (void)
|
||||
target_mourn_inferior (); /* or just win32_mourn_inferior? */
|
||||
}
|
||||
|
||||
static void
|
||||
win32_resume (ptid_t ptid, int step, enum target_signal sig)
|
||||
{
|
||||
thread_info *th;
|
||||
DWORD continue_status = DBG_CONTINUE;
|
||||
|
||||
int pid = PIDGET (ptid);
|
||||
|
||||
if (sig != TARGET_SIGNAL_0)
|
||||
{
|
||||
if (current_event.dwDebugEventCode != EXCEPTION_DEBUG_EVENT)
|
||||
{
|
||||
DEBUG_EXCEPT(("Cannot continue with signal %d here.\n",sig));
|
||||
}
|
||||
else if (sig == last_sig)
|
||||
continue_status = DBG_EXCEPTION_NOT_HANDLED;
|
||||
else
|
||||
#if 0
|
||||
/* This code does not seem to work, because
|
||||
the kernel does probably not consider changes in the ExceptionRecord
|
||||
structure when passing the exception to the inferior.
|
||||
Note that this seems possible in the exception handler itself. */
|
||||
{
|
||||
int i;
|
||||
for (i = 0; xlate[i].them != -1; i++)
|
||||
if (xlate[i].us == sig)
|
||||
{
|
||||
current_event.u.Exception.ExceptionRecord.ExceptionCode =
|
||||
xlate[i].them;
|
||||
continue_status = DBG_EXCEPTION_NOT_HANDLED;
|
||||
break;
|
||||
}
|
||||
if (continue_status == DBG_CONTINUE)
|
||||
{
|
||||
DEBUG_EXCEPT(("Cannot continue with signal %d.\n",sig));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
DEBUG_EXCEPT(("Can only continue with recieved signal %d.\n",
|
||||
last_sig));
|
||||
}
|
||||
|
||||
last_sig = TARGET_SIGNAL_0;
|
||||
|
||||
DEBUG_EXEC (("gdb: win32_resume (pid=%d, step=%d, sig=%d);\n",
|
||||
pid, step, sig));
|
||||
|
||||
/* Get context for currently selected thread */
|
||||
th = thread_rec (current_event.dwThreadId, FALSE);
|
||||
if (th)
|
||||
{
|
||||
if (step)
|
||||
{
|
||||
/* Single step by setting t bit */
|
||||
win32_fetch_inferior_registers (PS_REGNUM);
|
||||
th->context.EFlags |= FLAG_TRACE_BIT;
|
||||
}
|
||||
|
||||
if (th->context.ContextFlags)
|
||||
{
|
||||
if (debug_registers_changed)
|
||||
{
|
||||
th->context.Dr0 = dr[0];
|
||||
th->context.Dr1 = dr[1];
|
||||
th->context.Dr2 = dr[2];
|
||||
th->context.Dr3 = dr[3];
|
||||
/* th->context.Dr6 = dr[6];
|
||||
FIXME: should we set dr6 also ?? */
|
||||
th->context.Dr7 = dr[7];
|
||||
}
|
||||
CHECK (SetThreadContext (th->h, &th->context));
|
||||
th->context.ContextFlags = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allow continuing with the same signal that interrupted us.
|
||||
Otherwise complain. */
|
||||
|
||||
win32_continue (continue_status, pid);
|
||||
}
|
||||
|
||||
static void
|
||||
win32_prepare_to_store (void)
|
||||
{
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include <windows.h>
|
||||
#include <imagehlp.h>
|
||||
#include <sys/cygwin.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "buildsym.h"
|
||||
#include "symfile.h"
|
||||
@ -63,6 +64,13 @@
|
||||
static struct target_ops win32_ops;
|
||||
static struct target_so_ops win32_so_ops;
|
||||
|
||||
/* The starting and ending address of the cygwin1.dll text segment. */
|
||||
static bfd_vma cygwin_load_start;
|
||||
static bfd_vma cygwin_load_end;
|
||||
|
||||
static int have_saved_context; /* True if we've saved context from a cygwin signal. */
|
||||
static CONTEXT saved_context; /* Containes the saved context from a cygwin signal. */
|
||||
|
||||
/* If we're not using the old Cygwin header file set, define the
|
||||
following which never should have been in the generic Win32 API
|
||||
headers in the first place since they were our own invention... */
|
||||
@ -346,16 +354,27 @@ do_win32_fetch_inferior_registers (int r)
|
||||
|
||||
if (current_thread->reload_context)
|
||||
{
|
||||
thread_info *th = current_thread;
|
||||
th->context.ContextFlags = CONTEXT_DEBUGGER_DR;
|
||||
GetThreadContext (th->h, &th->context);
|
||||
/* Copy dr values from that thread. */
|
||||
dr[0] = th->context.Dr0;
|
||||
dr[1] = th->context.Dr1;
|
||||
dr[2] = th->context.Dr2;
|
||||
dr[3] = th->context.Dr3;
|
||||
dr[6] = th->context.Dr6;
|
||||
dr[7] = th->context.Dr7;
|
||||
if (have_saved_context)
|
||||
{
|
||||
/* Lie about where the program actually is stopped since cygwin has informed us that
|
||||
we should consider the signal to have occurred at another location which is stored
|
||||
in "saved_context. */
|
||||
memcpy (¤t_thread->context, &saved_context, __COPY_CONTEXT_SIZE);
|
||||
have_saved_context = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
thread_info *th = current_thread;
|
||||
th->context.ContextFlags = CONTEXT_DEBUGGER_DR;
|
||||
GetThreadContext (th->h, &th->context);
|
||||
/* Copy dr values from that thread. */
|
||||
dr[0] = th->context.Dr0;
|
||||
dr[1] = th->context.Dr1;
|
||||
dr[2] = th->context.Dr2;
|
||||
dr[3] = th->context.Dr3;
|
||||
dr[6] = th->context.Dr6;
|
||||
dr[7] = th->context.Dr7;
|
||||
}
|
||||
current_thread->reload_context = 0;
|
||||
}
|
||||
|
||||
@ -596,12 +615,10 @@ get_relocated_section_addrs (bfd *abfd, CORE_ADDR text_load)
|
||||
{
|
||||
/* Couldn't get the .text section. Weird. */
|
||||
}
|
||||
|
||||
else if (text_load == (text_vma = bfd_get_section_vma (abfd, text_section)))
|
||||
{
|
||||
/* DLL wasn't relocated. */
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
/* Figure out all sections' loaded addresses. The offset here is
|
||||
@ -640,6 +657,7 @@ solib_symbols_add (struct so_list *so, CORE_ADDR load_addr)
|
||||
static struct objfile *result = NULL;
|
||||
char *name = so->so_name;
|
||||
bfd *abfd = NULL;
|
||||
char *p;
|
||||
|
||||
/* The symbols in a dll are offset by 0x1000, which is the
|
||||
the offset from 0 of the first byte in an image - because
|
||||
@ -660,8 +678,6 @@ solib_symbols_add (struct so_list *so, CORE_ADDR load_addr)
|
||||
{
|
||||
if (bfd_check_format (abfd, bfd_object))
|
||||
addrs = get_relocated_section_addrs (abfd, load_addr);
|
||||
|
||||
bfd_close (abfd);
|
||||
}
|
||||
|
||||
if (addrs)
|
||||
@ -683,13 +699,20 @@ solib_symbols_add (struct so_list *so, CORE_ADDR load_addr)
|
||||
do_cleanups (my_cleanups);
|
||||
}
|
||||
|
||||
p = strchr (so->so_name, '\0') - (sizeof ("/cygwin1.dll") - 1);
|
||||
if (p >= so->so_name && strcasecmp (p, "/cygwin1.dll") == 0)
|
||||
{
|
||||
asection *text = bfd_get_section_by_name (abfd, ".text");
|
||||
cygwin_load_start = bfd_section_vma (abfd, text);
|
||||
cygwin_load_end = cygwin_load_start + bfd_section_size (abfd, text);
|
||||
}
|
||||
|
||||
bfd_close (abfd);
|
||||
|
||||
so->symbols_loaded = !!result;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Remember the maximum DLL length for printing in info dll command. */
|
||||
static int max_dll_name_len;
|
||||
|
||||
static char *
|
||||
register_loaded_dll (const char *name, DWORD load_addr, int readsyms)
|
||||
{
|
||||
@ -733,10 +756,9 @@ register_loaded_dll (const char *name, DWORD load_addr, int readsyms)
|
||||
solib_end->next = so;
|
||||
solib_end = so;
|
||||
len = strlen (so->so_name);
|
||||
if (len > max_dll_name_len)
|
||||
max_dll_name_len = len;
|
||||
if (readsyms)
|
||||
solib_symbols_add (so, (CORE_ADDR) load_addr);
|
||||
|
||||
return so->so_name;
|
||||
}
|
||||
|
||||
@ -789,7 +811,6 @@ handle_load_dll (void *dummy)
|
||||
LOAD_DLL_DEBUG_INFO *event = ¤t_event.u.LoadDll;
|
||||
char dll_buf[MAX_PATH + 1];
|
||||
char *dll_name = NULL;
|
||||
char *p;
|
||||
|
||||
dll_buf[0] = dll_buf[sizeof (dll_buf) - 1] = '\0';
|
||||
|
||||
@ -804,7 +825,6 @@ handle_load_dll (void *dummy)
|
||||
return 1;
|
||||
|
||||
register_loaded_dll (dll_name, (DWORD) event->lpBaseOfDll + 0x1000, auto_solib_add);
|
||||
solib_add (NULL, 0, NULL, auto_solib_add);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -860,7 +880,6 @@ win32_clear_solib (void)
|
||||
{
|
||||
solib_start.next = NULL;
|
||||
solib_end = &solib_start;
|
||||
max_dll_name_len = sizeof ("DLL Name") - 1;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -897,31 +916,49 @@ dll_symbol_command (char *args, int from_tty)
|
||||
static int
|
||||
handle_output_debug_string (struct target_waitstatus *ourstatus)
|
||||
{
|
||||
char *s;
|
||||
int gotasig = FALSE;
|
||||
char *s = NULL;
|
||||
int retval = 0;
|
||||
|
||||
if (!target_read_string
|
||||
((CORE_ADDR) current_event.u.DebugString.lpDebugStringData, &s, 1024, 0)
|
||||
|| !s || !*s)
|
||||
return gotasig;
|
||||
|
||||
if (strncmp (s, _CYGWIN_SIGNAL_STRING, sizeof (_CYGWIN_SIGNAL_STRING) - 1) != 0)
|
||||
/* nothing to do */;
|
||||
else if (strncmp (s, _CYGWIN_SIGNAL_STRING, sizeof (_CYGWIN_SIGNAL_STRING) - 1) != 0)
|
||||
{
|
||||
if (strncmp (s, "cYg", 3) != 0)
|
||||
warning (("%s"), s);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Got a cygwin signal marker. A cygwin signal is followed by the signal number
|
||||
itself and then optionally followed by the thread id and address to saved context
|
||||
within the DLL. If these are supplied, then the given thread is assumed to have
|
||||
issued the signal and the context from the thread is assumed to be stored at the
|
||||
given address in the inferior. Tell gdb to treat this like a real signal. */
|
||||
char *p;
|
||||
int sig = strtol (s + sizeof (_CYGWIN_SIGNAL_STRING) - 1, &p, 0);
|
||||
gotasig = target_signal_from_host (sig);
|
||||
int gotasig = target_signal_from_host (sig);
|
||||
ourstatus->value.sig = gotasig;
|
||||
if (gotasig)
|
||||
ourstatus->kind = TARGET_WAITKIND_STOPPED;
|
||||
{
|
||||
LPCVOID x;
|
||||
DWORD n;
|
||||
ourstatus->kind = TARGET_WAITKIND_STOPPED;
|
||||
retval = strtoul (p, &p, 0);
|
||||
if (!retval)
|
||||
retval = main_thread_id;
|
||||
else if ((x = (LPCVOID) strtoul (p, &p, 0))
|
||||
&& ReadProcessMemory (current_process_handle, x,
|
||||
&saved_context, __COPY_CONTEXT_SIZE, &n)
|
||||
&& n == __COPY_CONTEXT_SIZE)
|
||||
have_saved_context = 1;
|
||||
current_event.dwThreadId = retval;
|
||||
}
|
||||
}
|
||||
|
||||
xfree (s);
|
||||
return gotasig;
|
||||
if (s)
|
||||
xfree (s);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1065,11 +1102,17 @@ handle_exception (struct target_waitstatus *ourstatus)
|
||||
DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ACCESS_VIOLATION");
|
||||
ourstatus->value.sig = TARGET_SIGNAL_SEGV;
|
||||
{
|
||||
/* See if the access violation happened within the cygwin DLL itself. Cygwin uses
|
||||
a kind of exception handling to deal with passed-in invalid addresses. gdb
|
||||
should not treat these as real SEGVs since they will be silently handled by
|
||||
cygwin. A real SEGV will (theoretically) be caught by cygwin later in the process
|
||||
and will be sent as a cygwin-specific-signal. So, ignore SEGVs if they show up
|
||||
within the text segment of the DLL itself. */
|
||||
char *fn;
|
||||
if (find_pc_partial_function ((CORE_ADDR) current_event.u.Exception
|
||||
.ExceptionRecord.ExceptionAddress,
|
||||
&fn, NULL, NULL)
|
||||
&& strncmp (fn, "KERNEL32!IsBad", strlen ("KERNEL32!IsBad")) == 0)
|
||||
bfd_vma addr = (bfd_vma) current_event.u.Exception.ExceptionRecord.ExceptionAddress;
|
||||
if ((addr >= cygwin_load_start && addr < cygwin_load_end)
|
||||
|| (find_pc_partial_function (addr, &fn, NULL, NULL)
|
||||
&& strncmp (fn, "KERNEL32!IsBad", strlen ("KERNEL32!IsBad")) == 0))
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
@ -1146,8 +1189,9 @@ handle_exception (struct target_waitstatus *ourstatus)
|
||||
ourstatus->value.sig = TARGET_SIGNAL_ILL;
|
||||
break;
|
||||
default:
|
||||
/* Treat unhandled first chance exceptions specially. */
|
||||
if (current_event.u.Exception.dwFirstChance)
|
||||
return 0;
|
||||
return -1;
|
||||
printf_unfiltered ("gdb: unknown target exception 0x%08lx at 0x%08lx\n",
|
||||
current_event.u.Exception.ExceptionRecord.ExceptionCode,
|
||||
(DWORD) current_event.u.Exception.ExceptionRecord.ExceptionAddress);
|
||||
@ -1175,7 +1219,6 @@ win32_continue (DWORD continue_status, int id)
|
||||
res = ContinueDebugEvent (current_event.dwProcessId,
|
||||
current_event.dwThreadId,
|
||||
continue_status);
|
||||
continue_status = 0;
|
||||
if (res)
|
||||
for (th = &thread_head; (th = th->next) != NULL;)
|
||||
if (((id == -1) || (id == (int) th->id)) && th->suspend_count)
|
||||
@ -1217,6 +1260,87 @@ fake_create_process (void)
|
||||
return main_thread_id;
|
||||
}
|
||||
|
||||
static void
|
||||
win32_resume (ptid_t ptid, int step, enum target_signal sig)
|
||||
{
|
||||
thread_info *th;
|
||||
DWORD continue_status = DBG_CONTINUE;
|
||||
|
||||
int pid = PIDGET (ptid);
|
||||
|
||||
if (sig != TARGET_SIGNAL_0)
|
||||
{
|
||||
if (current_event.dwDebugEventCode != EXCEPTION_DEBUG_EVENT)
|
||||
{
|
||||
DEBUG_EXCEPT(("Cannot continue with signal %d here.\n",sig));
|
||||
}
|
||||
else if (sig == last_sig)
|
||||
continue_status = DBG_EXCEPTION_NOT_HANDLED;
|
||||
else
|
||||
#if 0
|
||||
/* This code does not seem to work, because
|
||||
the kernel does probably not consider changes in the ExceptionRecord
|
||||
structure when passing the exception to the inferior.
|
||||
Note that this seems possible in the exception handler itself. */
|
||||
{
|
||||
int i;
|
||||
for (i = 0; xlate[i].them != -1; i++)
|
||||
if (xlate[i].us == sig)
|
||||
{
|
||||
current_event.u.Exception.ExceptionRecord.ExceptionCode =
|
||||
xlate[i].them;
|
||||
continue_status = DBG_EXCEPTION_NOT_HANDLED;
|
||||
break;
|
||||
}
|
||||
if (continue_status == DBG_CONTINUE)
|
||||
{
|
||||
DEBUG_EXCEPT(("Cannot continue with signal %d.\n",sig));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
DEBUG_EXCEPT(("Can only continue with recieved signal %d.\n",
|
||||
last_sig));
|
||||
}
|
||||
|
||||
last_sig = TARGET_SIGNAL_0;
|
||||
|
||||
DEBUG_EXEC (("gdb: win32_resume (pid=%d, step=%d, sig=%d);\n",
|
||||
pid, step, sig));
|
||||
|
||||
/* Get context for currently selected thread */
|
||||
th = thread_rec (current_event.dwThreadId, FALSE);
|
||||
if (th)
|
||||
{
|
||||
if (step)
|
||||
{
|
||||
/* Single step by setting t bit */
|
||||
win32_fetch_inferior_registers (PS_REGNUM);
|
||||
th->context.EFlags |= FLAG_TRACE_BIT;
|
||||
}
|
||||
|
||||
if (th->context.ContextFlags)
|
||||
{
|
||||
if (debug_registers_changed)
|
||||
{
|
||||
th->context.Dr0 = dr[0];
|
||||
th->context.Dr1 = dr[1];
|
||||
th->context.Dr2 = dr[2];
|
||||
th->context.Dr3 = dr[3];
|
||||
/* th->context.Dr6 = dr[6];
|
||||
FIXME: should we set dr6 also ?? */
|
||||
th->context.Dr7 = dr[7];
|
||||
}
|
||||
CHECK (SetThreadContext (th->h, &th->context));
|
||||
th->context.ContextFlags = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allow continuing with the same signal that interrupted us.
|
||||
Otherwise complain. */
|
||||
|
||||
win32_continue (continue_status, pid);
|
||||
}
|
||||
|
||||
/* Get the next event from the child. Return 1 if the event requires
|
||||
handling by WFI (or whatever).
|
||||
*/
|
||||
@ -1228,6 +1352,7 @@ get_win32_debug_event (int pid, struct target_waitstatus *ourstatus)
|
||||
thread_info *th;
|
||||
static thread_info dummy_thread_info;
|
||||
int retval = 0;
|
||||
ptid_t ptid = {-1};
|
||||
|
||||
last_sig = TARGET_SIGNAL_0;
|
||||
|
||||
@ -1240,6 +1365,7 @@ get_win32_debug_event (int pid, struct target_waitstatus *ourstatus)
|
||||
event_code = current_event.dwDebugEventCode;
|
||||
ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
|
||||
th = NULL;
|
||||
have_saved_context = 0;
|
||||
|
||||
switch (event_code)
|
||||
{
|
||||
@ -1353,10 +1479,19 @@ get_win32_debug_event (int pid, struct target_waitstatus *ourstatus)
|
||||
"EXCEPTION_DEBUG_EVENT"));
|
||||
if (saw_create != 1)
|
||||
break;
|
||||
if (handle_exception (ourstatus))
|
||||
retval = current_event.dwThreadId;
|
||||
else
|
||||
continue_status = DBG_EXCEPTION_NOT_HANDLED;
|
||||
switch (handle_exception (ourstatus))
|
||||
{
|
||||
case 0:
|
||||
continue_status = DBG_EXCEPTION_NOT_HANDLED;
|
||||
break;
|
||||
case 1:
|
||||
retval = current_event.dwThreadId;
|
||||
break;
|
||||
case -1:
|
||||
last_sig = 1;
|
||||
continue_status = -1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case OUTPUT_DEBUG_STRING_EVENT: /* message from the kernel */
|
||||
@ -1366,8 +1501,7 @@ get_win32_debug_event (int pid, struct target_waitstatus *ourstatus)
|
||||
"OUTPUT_DEBUG_STRING_EVENT"));
|
||||
if (saw_create != 1)
|
||||
break;
|
||||
if (handle_output_debug_string (ourstatus))
|
||||
retval = main_thread_id;
|
||||
retval = handle_output_debug_string (ourstatus);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -1382,7 +1516,12 @@ get_win32_debug_event (int pid, struct target_waitstatus *ourstatus)
|
||||
}
|
||||
|
||||
if (!retval || saw_create != 1)
|
||||
CHECK (win32_continue (continue_status, -1));
|
||||
{
|
||||
if (continue_status == -1)
|
||||
win32_resume (ptid, 0, 1);
|
||||
else
|
||||
CHECK (win32_continue (continue_status, -1));
|
||||
}
|
||||
else
|
||||
{
|
||||
inferior_ptid = pid_to_ptid (retval);
|
||||
@ -1981,87 +2120,6 @@ win32_kill_inferior (void)
|
||||
target_mourn_inferior (); /* or just win32_mourn_inferior? */
|
||||
}
|
||||
|
||||
static void
|
||||
win32_resume (ptid_t ptid, int step, enum target_signal sig)
|
||||
{
|
||||
thread_info *th;
|
||||
DWORD continue_status = DBG_CONTINUE;
|
||||
|
||||
int pid = PIDGET (ptid);
|
||||
|
||||
if (sig != TARGET_SIGNAL_0)
|
||||
{
|
||||
if (current_event.dwDebugEventCode != EXCEPTION_DEBUG_EVENT)
|
||||
{
|
||||
DEBUG_EXCEPT(("Cannot continue with signal %d here.\n",sig));
|
||||
}
|
||||
else if (sig == last_sig)
|
||||
continue_status = DBG_EXCEPTION_NOT_HANDLED;
|
||||
else
|
||||
#if 0
|
||||
/* This code does not seem to work, because
|
||||
the kernel does probably not consider changes in the ExceptionRecord
|
||||
structure when passing the exception to the inferior.
|
||||
Note that this seems possible in the exception handler itself. */
|
||||
{
|
||||
int i;
|
||||
for (i = 0; xlate[i].them != -1; i++)
|
||||
if (xlate[i].us == sig)
|
||||
{
|
||||
current_event.u.Exception.ExceptionRecord.ExceptionCode =
|
||||
xlate[i].them;
|
||||
continue_status = DBG_EXCEPTION_NOT_HANDLED;
|
||||
break;
|
||||
}
|
||||
if (continue_status == DBG_CONTINUE)
|
||||
{
|
||||
DEBUG_EXCEPT(("Cannot continue with signal %d.\n",sig));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
DEBUG_EXCEPT(("Can only continue with recieved signal %d.\n",
|
||||
last_sig));
|
||||
}
|
||||
|
||||
last_sig = TARGET_SIGNAL_0;
|
||||
|
||||
DEBUG_EXEC (("gdb: win32_resume (pid=%d, step=%d, sig=%d);\n",
|
||||
pid, step, sig));
|
||||
|
||||
/* Get context for currently selected thread */
|
||||
th = thread_rec (current_event.dwThreadId, FALSE);
|
||||
if (th)
|
||||
{
|
||||
if (step)
|
||||
{
|
||||
/* Single step by setting t bit */
|
||||
win32_fetch_inferior_registers (PS_REGNUM);
|
||||
th->context.EFlags |= FLAG_TRACE_BIT;
|
||||
}
|
||||
|
||||
if (th->context.ContextFlags)
|
||||
{
|
||||
if (debug_registers_changed)
|
||||
{
|
||||
th->context.Dr0 = dr[0];
|
||||
th->context.Dr1 = dr[1];
|
||||
th->context.Dr2 = dr[2];
|
||||
th->context.Dr3 = dr[3];
|
||||
/* th->context.Dr6 = dr[6];
|
||||
FIXME: should we set dr6 also ?? */
|
||||
th->context.Dr7 = dr[7];
|
||||
}
|
||||
CHECK (SetThreadContext (th->h, &th->context));
|
||||
th->context.ContextFlags = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allow continuing with the same signal that interrupted us.
|
||||
Otherwise complain. */
|
||||
|
||||
win32_continue (continue_status, pid);
|
||||
}
|
||||
|
||||
static void
|
||||
win32_prepare_to_store (void)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user