summaryrefslogtreecommitdiffstats
path: root/winsup/cygwin/exceptions.cc
diff options
context:
space:
mode:
Diffstat (limited to 'winsup/cygwin/exceptions.cc')
-rw-r--r--winsup/cygwin/exceptions.cc213
1 files changed, 76 insertions, 137 deletions
diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc
index dae689285..57cb232c9 100644
--- a/winsup/cygwin/exceptions.cc
+++ b/winsup/cygwin/exceptions.cc
@@ -191,27 +191,11 @@ exception (EXCEPTION_RECORD *e, CONTEXT *in)
#endif
}
-extern "C" {
-static LPVOID __stdcall
-sfta(HANDLE, DWORD)
-{
- return NULL;
-}
-
-static DWORD __stdcall
-sgmb(HANDLE, DWORD)
-{
- return 4;
-}
-
#ifdef __i386__
/* Print a stack backtrace. */
#define HAVE_STACK_TRACE
-/* Set from CYGWIN environment variable if want to use old method. */
-BOOL NO_COPY oldstack = 0;
-
/* The function used to load the imagehlp DLL. Returns TRUE if the
DLL was found. */
static LoadDLLinitfunc (imagehlp)
@@ -227,53 +211,38 @@ LoadDLLfunc (StackWalk, StackWalk@36, imagehlp)
class stack_info
{
int first_time; /* True if just starting to iterate. */
- HANDLE hproc; /* Handle of process to inspect. */
- HANDLE hthread; /* Handle of thread to inspect. */
- int (stack_info::*get) (HANDLE, HANDLE); /* Gets the next stack frame */
+ int walk (); /* Uses the "old" method */
public:
STACKFRAME sf; /* For storing the stack information */
- int walk (HANDLE, HANDLE); /* Uses the StackWalk function */
- int brute_force (HANDLE, HANDLE); /* Uses the "old" method */
- void init (CONTEXT *); /* Called the first time that stack info is needed */
-
- /* The constructor remembers hproc and hthread and determines which stack walking
- method to use */
- stack_info (int use_old_stack, HANDLE hp, HANDLE ht): hproc(hp), hthread(ht)
- {
- if (!use_old_stack && LoadDLLinitnow (imagehlp))
- get = &stack_info::walk;
- else
- get = &stack_info::brute_force;
- }
+ void init (DWORD); /* Called the first time that stack info is needed */
+ stack_info (): first_time(1) {}
+
/* Postfix ++ iterates over the stack, returning zero when nothing is left. */
- int operator ++(int) { return (this->*get) (hproc, hthread); }
+ int operator ++(int) { return this->walk (); }
};
/* The number of parameters used in STACKFRAME */
-#define NPARAMS (sizeof(thestack->sf.Params) / sizeof(thestack->sf.Params[0]))
+#define NPARAMS (sizeof(thestack.sf.Params) / sizeof(thestack.sf.Params[0]))
/* This is the main stack frame info for this process. */
-static stack_info *thestack = NULL;
-static signal_dispatch sigsave;
+static NO_COPY stack_info thestack;
+signal_dispatch NO_COPY sigsave;
/* Initialize everything needed to start iterating. */
void
-stack_info::init (CONTEXT *cx)
+stack_info::init (DWORD ebp)
{
first_time = 1;
memset (&sf, 0, sizeof(sf));
- sf.AddrPC.Offset = cx->Eip;
- sf.AddrPC.Mode = AddrModeFlat;
- sf.AddrStack.Offset = cx->Esp;
- sf.AddrStack.Mode = AddrModeFlat;
- sf.AddrFrame.Offset = cx->Ebp;
+ sf.AddrFrame.Offset = ebp;
+ sf.AddrPC.Offset = ((DWORD *) ebp)[1];
sf.AddrFrame.Mode = AddrModeFlat;
}
/* Walk the stack by looking at successive stored 'bp' frames.
This is not foolproof. */
int
-stack_info::brute_force (HANDLE, HANDLE)
+stack_info::walk ()
{
char **ebp;
if (first_time)
@@ -300,44 +269,20 @@ stack_info::brute_force (HANDLE, HANDLE)
return 1;
}
-/* Use Win32 StackWalk() API to display the stack. This is theoretically
- more foolproof than the brute force method above. */
-int
-stack_info::walk (HANDLE hproc, HANDLE hthread)
-{
-#ifdef SOMEDAY
- /* It would be nice to get more information (like DLL symbols and module name)
- for each stack frame but in order to do that we have to call SymInitialize.
- It doesn't seem to be possible to do this inside of an excaption handler for
- some reason. */
- static int initialized = 0;
- if (!initialized && !SymInitialize(hproc, NULL, TRUE))
- small_printf("SymInitialize error, %E\n");
- initialized = 1;
-#endif
-
- return StackWalk (IMAGE_FILE_MACHINE_I386, hproc, hthread, &sf, NULL, NULL,
- sfta, sgmb, NULL) && !!sf.AddrFrame.Offset;
-}
-
/* Dump the stack using either the old method or the new Win32 API method */
void
stack (HANDLE hproc, HANDLE hthread, CONTEXT *cx)
{
int i;
- /* Set this up if it's the first time. */
- if (!thestack)
- thestack = new stack_info (oldstack, hproc, hthread);
-
- thestack->init (cx); /* Initialize from the input CONTEXT */
+ thestack.init (cx->Ebp); /* Initialize from the input CONTEXT */
small_printf ("Stack trace:\r\nFrame Function Args\r\n");
- for (i = 0; i < 16 && (*thestack)++ ; i++)
+ for (i = 0; i < 16 && thestack++ ; i++)
{
- small_printf ("%08x %08x ", thestack->sf.AddrFrame.Offset,
- thestack->sf.AddrPC.Offset);
+ small_printf ("%08x %08x ", thestack.sf.AddrFrame.Offset,
+ thestack.sf.AddrPC.Offset);
for (unsigned j = 0; j < NPARAMS; j++)
- small_printf ("%s%08x", j == 0 ? " (" : ", ", thestack->sf.Params[j]);
+ small_printf ("%s%08x", j == 0 ? " (" : ", ", thestack.sf.Params[j]);
small_printf (")\r\n");
}
small_printf ("End of stack trace%s",
@@ -551,18 +496,15 @@ handle_exceptions (EXCEPTION_RECORD *e, void *, CONTEXT *in, void *)
debug_printf ("In cygwin_except_handler calling %p",
myself->getsig(sig).sa_handler);
- DWORD *bp = (DWORD *)in->Esp;
- for (DWORD *bpend = bp - 8; bp > bpend; bp--)
- if (*bp == in->SegCs && bp[-1] == in->Eip)
+ DWORD *ebp = (DWORD *)in->Esp;
+ for (DWORD *bpend = ebp - 8; ebp > bpend; ebp--)
+ if (*ebp == in->SegCs && ebp[-1] == in->Eip)
{
- bp -= 2;
+ ebp -= 2;
break;
}
- in->Ebp = (DWORD) bp;
- sigsave.cx = in;
- sig_send (NULL, sig); // Signal myself
- sigsave.cx = NULL;
+ sig_send (NULL, sig, (DWORD) ebp); // Signal myself
return 0;
}
#endif /* __i386__ */
@@ -574,7 +516,6 @@ stack (void)
system_printf ("Stack trace not yet supported on this machine.");
}
#endif
-}
/* Utilities to call a user supplied exception handler. */
@@ -659,6 +600,7 @@ interrupt_setup (int sig, struct sigaction& siga, void *handler, DWORD retaddr)
sigsave.func = (void (*)(int)) handler;
sigsave.sig = sig;
sigsave.saved_errno = -1; // Flag: no errno to save
+ sigsave.ebp = 0;
}
static void
@@ -670,24 +612,19 @@ interrupt_now (CONTEXT *ctx, int sig, struct sigaction& siga, void *handler)
}
static int
-interrupt_on_return (CONTEXT *ctx, int sig, struct sigaction& siga, void *handler)
+interrupt_on_return (DWORD ebp, int sig, struct sigaction& siga, void *handler)
{
int i;
if (sigsave.sig)
return 0; /* Already have a signal stacked up */
- /* Set this up if it's the first time. */
- /* FIXME: Eventually augment to handle more than one thread */
- if (!thestack)
- thestack = new stack_info (oldstack, hMainProc, hMainThread);
-
- thestack->init (ctx); /* Initialize from the input CONTEXT */
- for (i = 0; i < 32 && (*thestack)++ ; i++)
- if (interruptible (thestack->sf.AddrReturn.Offset))
+ thestack.init (ebp); /* Initialize from the input CONTEXT */
+ for (i = 0; i < 32 && thestack++ ; i++)
+ if (interruptible (thestack.sf.AddrReturn.Offset))
{
- DWORD *addr_retaddr = ((DWORD *)thestack->sf.AddrFrame.Offset) + 1;
- if (*addr_retaddr == thestack->sf.AddrReturn.Offset)
+ DWORD *addr_retaddr = ((DWORD *)thestack.sf.AddrFrame.Offset) + 1;
+ if (*addr_retaddr == thestack.sf.AddrReturn.Offset)
{
interrupt_setup (sig, siga, handler, *addr_retaddr);
*addr_retaddr = (DWORD) sigdelayed;
@@ -707,11 +644,12 @@ set_sig_errno (int e)
}
static int
-call_handler (int sig, struct sigaction& siga, void *handler)
+call_handler (int sig, struct sigaction& siga, void *handler, int nonmain)
{
- CONTEXT *cx, orig;
+ CONTEXT cx;
+ DWORD ebp;
int interrupted = 1;
- HANDLE hth;
+ HANDLE hth = NULL;
int res;
if (hExeced != NULL && hExeced != INVALID_HANDLE_VALUE)
@@ -721,56 +659,52 @@ call_handler (int sig, struct sigaction& siga, void *handler)
exec_exit = sig; // Maybe we'll exit with this value
goto out1;
}
- hth = myself->getthread2signal ();
-
- /* Suspend the thread which will receive the signal. But first ensure that
- this thread doesn't have the sync_proc_subproc and mask_sync mutos, since
- we need those (hack alert). If the thread-to-be-suspended has either of
- these mutos, enter a busy loop until it is released. If the thread is
- already suspended (which should never occur) then just queue the signal. */
- for (;;)
+
+ if (!nonmain)
+ ebp = sigsave.ebp;
+ else
{
- sigproc_printf ("suspending mainthread");
- res = SuspendThread (hth);
+ hth = myself->getthread2signal ();
+ /* Suspend the thread which will receive the signal. But first ensure that
+ this thread doesn't have the sync_proc_subproc and mask_sync mutos, since
+ we need those (hack alert). If the thread-to-be-suspended has either of
+ these mutos, enter a busy loop until it is released. If the thread is
+ already suspended (which should never occur) then just queue the signal. */
+ for (;;)
+ {
+ sigproc_printf ("suspending mainthread");
+ res = SuspendThread (hth);
- /* FIXME: Make multi-thread aware */
- for (muto *m = muto_start.next; m != NULL; m = m->next)
- if (m->unstable () || m->owner () == maintid)
- goto keep_looping;
+ /* FIXME: Make multi-thread aware */
+ for (muto *m = muto_start.next; m != NULL; m = m->next)
+ if (m->unstable () || m->owner () == maintid)
+ goto keep_looping;
- break;
+ break;
- keep_looping:
- sigproc_printf ("suspended thread owns a muto");
- if (res)
- goto set_pending;
+ keep_looping:
+ sigproc_printf ("suspended thread owns a muto");
+ if (res)
+ goto set_pending;
- ResumeThread (hth);
- Sleep (0);
- }
+ ResumeThread (hth);
+ Sleep (0);
+ }
- sigproc_printf ("SuspendThread returned %d", res);
+ sigproc_printf ("SuspendThread returned %d", res);
- if (sigsave.cx)
- {
- cx = sigsave.cx;
- sigsave.cx = NULL;
- }
- else
- {
- cx = &orig;
- /* FIXME - this does not preserve FPU state */
- orig.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
- if (!GetThreadContext (hth, cx))
+ cx.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
+ if (!GetThreadContext (hth, &cx))
{
system_printf ("couldn't get context of main thread, %E");
goto out;
}
+ ebp = cx.Ebp;
}
- if (cx == &orig && interruptible (cx->Eip))
- interrupt_now (cx, sig, siga, handler);
- else if (!interrupt_on_return (cx, sig, siga, handler))
+ if (nonmain && interruptible (cx.Eip))
+ interrupt_now (&cx, sig, siga, handler);
+ else if (!interrupt_on_return (ebp, sig, siga, handler))
{
set_pending:
pending_signals = 1; /* FIXME: Probably need to be more tricky here */
@@ -780,15 +714,20 @@ call_handler (int sig, struct sigaction& siga, void *handler)
if (interrupted)
{
- (void) SetEvent (signal_arrived); // For an EINTR case
+ res = SetEvent (signal_arrived); // For an EINTR case
sigproc_printf ("armed signal_arrived %p, res %d", signal_arrived, res);
/* Clear any waiting threads prior to dispatching to handler function */
proc_subproc(PROC_CLEARWAIT, 1);
}
out:
- res = ResumeThread (hth);
- sigproc_printf ("ResumeThread returned %d", res);
+ if (!hth)
+ sigproc_printf ("modified main-thread stack");
+ else
+ {
+ res = ResumeThread (hth);
+ sigproc_printf ("ResumeThread returned %d", res);
+ }
out1:
sigproc_printf ("returning %d", interrupted);
@@ -892,7 +831,7 @@ sig_handle_tty_stop (int sig)
}
int __stdcall
-sig_handle (int sig)
+sig_handle (int sig, int nonmain)
{
int rc = 0;
@@ -971,7 +910,7 @@ stop:
dosig:
/* Dispatch to the appropriate function. */
sigproc_printf ("signal %d, about to call %p", sig, thissig.sa_handler);
- rc = call_handler (sig, thissig, handler);
+ rc = call_handler (sig, thissig, handler, nonmain);
done:
sigproc_printf ("returning %d", rc);