Initial original import from: fuse-2.4.2-2.fc4
[captive.git] / src / libcaptive / ps / signal.c
index c042f54..68a08b3 100644 (file)
 #include "captive/ldr_exports.h"       /* for struct captive_ModuleList_patchpoint */
 
 
-#if 0  /* Currently implemented for real by "pass" to native ntoskrnl. */
+int _abnormal_termination_orig(void);
+extern greg_t fs_KPCR_ExceptionList;
+
 /**
- * _abnormal_termination:
+ * _abnormal_termination_wrap:
+ *
+ * This call can be also accessed as AbnormalTermination() or _abnormal_termination().
+ * It is a captive wrapper around _abnormal_termination() function.
  *
- * This call can be also accessed as AbnormalTermination() or abnormal_termination().
+ * Returns whether some exception occured in the current #try block we are currently
+ * #finish -ing. Any functions called from current #finish block will be considered
+ * for returning zero back again. It is forbidden to call this function outside
+ * of #finish block, result of such call is undefined.
  *
- * Returns whether some exception occured (FIXME: in what scope?).
  * Exception handlers are registered from W32 binary in stack frames stored in "fs:[0x00000000]"
  * value which gets mapped by libcaptive/ps/signal.c to #fs_KPCR_ExceptionList
  * variable.
  *
- * libcaptive currently does not raise any exceptions therefore this call always returns value %0.
- * See RtlpDispatchException().
+ * If no exception handler was registered yet this function returns zero.
+ *
+ * See also RtlpDispatchException().
  *
- * Returns: non-zero if some exception is now registered and pending.
+ * Returns: non-zero if some exception is now being handled as pending.
  */
-int _abnormal_termination(void)
+int _abnormal_termination_wrap(void)
 {
-       return 0;
+       /* No handler registered yet? ntoskrnl _abnormal_termination() does not handle it
+        * and I do not want to bother with registering toplevel handler.
+        */
+       if (fs_KPCR_ExceptionList==(greg_t)-1)
+               return 0;
+
+       return _abnormal_termination_orig();
 }
-#endif
 
 
 #if 0
@@ -175,6 +188,7 @@ static void sigaction_SIGSEGV(int signo,siginfo_t *siginfo,struct ucontext *ucon
 {
 guint8 *reg_eip;
 const void *reg_eip_aligned;
+static const void *reg_eip_aligned_last_valid=NULL;    /* performance cache */
 
        g_return_if_fail(signo==SIGSEGV);
        g_return_if_fail(siginfo->si_signo==SIGSEGV);
@@ -187,7 +201,14 @@ const void *reg_eip_aligned;
         */
        reg_eip_aligned=(const void *)(((char *)reg_eip)-(GPOINTER_TO_UINT(reg_eip)&(PAGE_SIZE-1)));
        g_assert(reg_eip_aligned!=NULL);
-       g_return_if_fail(!(captive_mmap_map_get(reg_eip_aligned)&PROT_EXEC));
+
+       /* We do not expect any pages can get un-PROT_EXEC-ed
+        * and therefore we never invalidate our cache 'reg_eip_aligned_last_valid'.
+        */
+       if (reg_eip_aligned_last_valid!=reg_eip_aligned) {
+               g_return_if_fail(!(captive_mmap_map_get(reg_eip_aligned)&PROT_EXEC));
+               reg_eip_aligned_last_valid=reg_eip_aligned;
+               }
        
        /* all instruction notation comments are written in AT&T 'instr src,dest' syntax! */
        if (*reg_eip==0x64) {   /* prefix '%fs:' */