#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)
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)
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",
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__ */
system_printf ("Stack trace not yet supported on this machine.");
}
#endif
-}
/* Utilities to call a user supplied exception handler. */
sigsave.func = (void (*)(int)) handler;
sigsave.sig = sig;
sigsave.saved_errno = -1; // Flag: no errno to save
+ sigsave.ebp = 0;
}
static void
}
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;
}
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)
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 */
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);
}
int __stdcall
-sig_handle (int sig)
+sig_handle (int sig, int nonmain)
{
int rc = 0;
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);
DWORD res = WaitForSingleObject (output_mutex, ms);
if (res == WAIT_OBJECT_0)
{
-#ifdef DEBUGGING
+#ifndef DEBUGGING
+ if (strace.active)
+ strace.prntf (_STRACE_TERMIOS, "%F (%d): tty output_mutex: acquired", fn, ln, res);
+#else
ostack[osi].fn = fn;
ostack[osi].ln = ln;
ostack[osi].tname = threadname (0, 0);
osi++;
#endif
}
- if (strace.active)
- strace.prntf (_STRACE_TERMIOS, "%F (%d): tty output_mutex: acquired", fn, ln, res);
return res;
}
{
if (ReleaseMutex (output_mutex))
{
-#ifdef DEBUGGING
+#ifndef DEBUGGING
+ if (strace.active)
+ strace.prntf (_STRACE_TERMIOS, "%F (%d): tty output_mutex released", fn, ln);
+#else
if (osi > 0)
osi--;
termios_printf ("released at %s:%d, osi %d", fn, ln, osi);
ostack[osi].ln = -ln;
#endif
}
- if (strace.active)
- strace.prntf (_STRACE_TERMIOS, "%F (%d): tty output_mutex released", fn, ln);
}
#define acquire_output_mutex(ms) \
}
if (get_ttyp ()->OutputStopped)
- WaitForSingleObject (restart_output_event, INFINITE);
+ {
+ termios_printf ("waiting for restart_output_event");
+ WaitForSingleObject (restart_output_event, INFINITE);
+ }
if (get_ttyp ()->ti.c_oflag & OPOST) // post-process output
{
while (len)
{
- wait:
termios_printf ("reading %d bytes (vtime %d)",
min ((unsigned) vmin, min (len, sizeof (buf))), vtime);
if (ReadFile (get_handle (), (unsigned *) buf,
if (get_flags () & (O_NONBLOCK | O_NDELAY))
break;
- /* We can't enter to blocking Readfile - signals will be lost!
+ /* We can't enter the blocking Readfile as signals will be lost.
* So, poll the pipe for data.
* FIXME: try to avoid polling...
* FIXME: Current EINTR scheme does not take vmin/vtime into account.
if (vmin == 0 && vtime == 0)
return 0; // min = 0, time = 0
if (vtime == 0)
- goto wait; // min > 0, time = 0
+ continue; // min > 0, time = 0
while (vtime--)
{
PeekNamedPipe (get_handle (), NULL, 0, NULL, &n, NULL);
* completed before returning.
*/
int __stdcall
-sig_send (pinfo *p, int sig)
+sig_send (pinfo *p, int sig, DWORD ebp)
{
int rc = 1;
DWORD tid = GetCurrentThreadId ();
HANDLE thiscatch = NULL;
HANDLE thiscomplete = NULL;
BOOL wait_for_completion;
+ extern signal_dispatch sigsave;
if (p == myself_nowait_nonmain)
p = (tid == maintid) ? myself : myself_nowait;
{
thiscatch = sigcatch_main;
thiscomplete = sigcomplete_main;
- ResetEvent (thiscomplete);
+ sigsave.ebp = ebp ?: (DWORD) __builtin_frame_address (1);
}
}
else if (!(thiscatch = getsem (p, "sigcatch", 0, 0)))
sigcatch_nonmain = CreateSemaphore (&sec_none_nih, 0, MAXLONG, NULL);
sigcatch_main = CreateSemaphore (&sec_none_nih, 0, MAXLONG, NULL);
sigcomplete_nonmain = CreateSemaphore (&sec_none_nih, 0, MAXLONG, NULL);
- sigcomplete_main = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL);
+ sigcomplete_main = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL);
sigproc_printf ("sigcatch_nonmain %p", sigcatch_nonmain);
/* Setting dwProcessId flags that this process is now capable of receiving
int dispatched_sigchld = 0;
for (int sig = -__SIGOFFSET; sig < NSIG; sig++)
{
-#ifdef NOSIGQUEUE
- if (InterlockedExchange (myself->getsigtodo(sig), 0L) > 0)
-#else
while (InterlockedDecrement (myself->getsigtodo(sig)) >= 0)
-#endif
{
if (sig == SIGCHLD)
saw_sigchld = 1;
/* Signalled from a child process that it has stopped */
case __SIGCHILDSTOPPED:
sip_printf ("Received child stopped notification");
- dispatched |= sig_handle (SIGCHLD);
+ dispatched |= sig_handle (SIGCHLD, rc);
if (proc_subproc (PROC_CHILDSTOPPED, 0))
dispatched |= 1;
break;
/* A normal UNIX signal */
default:
sip_printf ("Got signal %d", sig);
- int wasdispatched = sig_handle (sig);
+ int wasdispatched = sig_handle (sig, rc);
dispatched |= wasdispatched;
if (sig == SIGCHLD && wasdispatched)
dispatched_sigchld = 1;
goto nextsig;
}
}
-#ifndef NOSIGQUEUE
/* Decremented too far. */
if (InterlockedIncrement (myself->getsigtodo(sig)) > 0)
pending_signals = 1;
-#endif
nextsig:
continue;
}