From 350370aa3fee849c6f821bc69235d854a0ed2f26 Mon Sep 17 00:00:00 2001
From: Kevin Bracey <kbracey@gitlab.riscosopen.org>
Date: Tue, 29 Jan 2002 16:03:36 +0000
Subject: [PATCH] Abort and error handling massively overhauled:

  Aborts now give standard error messages (Abort on Data Transfer at... etc)
  *ShowRegs now filled in after aborts
  assert(), abort(), "free failed" and standard signal handlers now use Wimp
    error boxes if in the desktop
  Postmortem button on error boxes to view the postmortem

Also, x$multiply, x$divide, __rt_sdiv, x$remainder, x$udivide, __rt_udiv and
x$uremainder optimised.

Version 5.35. Tagged as 'RISC_OSLib-5_35'
---
 Doc/AbortNotes  |  40 ++++++++
 VersionASM      |  15 +--
 VersionNum      |  22 +++--
 c/armsys        | 129 +++++++++++++++++++++++-
 c/error         |   8 +-
 c/signal        |  15 ++-
 clib/s/cl_body  | 149 ++++++++++------------------
 h/hostsys       |   3 +
 kernel/s/k_body | 258 +++++++++++++++++++++++++++---------------------
 9 files changed, 401 insertions(+), 238 deletions(-)
 create mode 100644 Doc/AbortNotes

diff --git a/Doc/AbortNotes b/Doc/AbortNotes
new file mode 100644
index 0000000..8981a6d
--- /dev/null
+++ b/Doc/AbortNotes
@@ -0,0 +1,40 @@
+R0 -> error, R1-R9 as returned from SWI, R10-R12, SWI addr on stack, R14=SPSR
+
+On entry to error handler, for SWI errors:
+
+User mode - IRQs on
+
+R0 -> error handler's buffer (containing PC error occured at (address of instr after SWI),
+                              and a copy of the error)
+R1-R9 as returned from the SWI
+R10-R12 recovered from stack (may be wrong if SWI wasn't top level - bad person)
+User R13,R14 as it was when SWI called
+
+
+Default abort handler:
+Register block filled in with registers for current mode at time of abort.
+Stacks flattened
+R10-R12, PC from dump placed in SVC stack
+OS_Generate error called.
+End result: R0-> error
+            R1-R9 corrupt
+            R10-R12 = registers at instant of abort (from mode in which abort happened)
+            R13,R14 = USR registers at instant of abort
+            Register block contains registers for current mode at time of abort.
+
+
+C abort handler should note USR mode registers (only) then pass it on.
+C error handler should note that it is an abort, and not touch the register dump.
+
+Error numbers:
+&800000XX - machine exceptions: 00=Undef, 01=PAbort, 02=DAbort, 03=AddrEx, 04=Unknown IRQ?
+                                05=BThru0
+&800002XX - FP exceptions:      00=IVO, 01=OFL, 02=DVZ, 03=UFL, 04=INX, 05=Faulty
+
+
+FP exceptions:
+
+User mode registers go into integer register dump.
+FP registers go into FP register dump
+OS_GenerateError from inside FPEm - error handler called with all except R1 intact.
+
diff --git a/VersionASM b/VersionASM
index 91da504..c28713d 100644
--- a/VersionASM
+++ b/VersionASM
@@ -1,5 +1,6 @@
 ;
 ; This file is automatically maintained by srccommit, do not edit manually.
+; Last processed by srccommit version: 1.62.
 ;
                         GBLS    Module_MajorVersion
                         GBLA    Module_Version
@@ -11,14 +12,14 @@
                         GBLS    Module_HelpVersion
                         GBLS    Module_ComponentName
                         GBLS    Module_ComponentPath
-Module_MajorVersion     SETS    "5.34"
-Module_Version          SETA    534
+Module_MajorVersion     SETS    "5.35"
+Module_Version          SETA    535
 Module_MinorVersion     SETS    ""
-Module_Date             SETS    "23 Aug 2001"
-Module_ApplicationDate2 SETS    "23-Aug-01"
-Module_ApplicationDate4 SETS    "23-Aug-2001"
+Module_Date             SETS    "29 Jan 2002"
+Module_ApplicationDate2 SETS    "29-Jan-02"
+Module_ApplicationDate4 SETS    "29-Jan-2002"
 Module_ComponentName    SETS    "RISC_OSLib"
 Module_ComponentPath    SETS    "RiscOS/Sources/Lib/RISC_OSLib"
-Module_FullVersion      SETS    "5.34"
-Module_HelpVersion      SETS    "5.34 (23 Aug 2001)"
+Module_FullVersion      SETS    "5.35"
+Module_HelpVersion      SETS    "5.35 (29 Jan 2002)"
                         END
diff --git a/VersionNum b/VersionNum
index 4894d1e..6989597 100644
--- a/VersionNum
+++ b/VersionNum
@@ -1,22 +1,24 @@
-/* (5.34)
+/* (5.35)
  *
  * This file is automatically maintained by srccommit, do not edit manually.
+ * Last processed by srccommit version: 1.62.
  *
  */
-#define Module_MajorVersion_CMHG        5.34
+#define Module_MajorVersion_CMHG        5.35
 #define Module_MinorVersion_CMHG        
-#define Module_Date_CMHG                23 Aug 2001
+#define Module_Date_CMHG                29 Jan 2002
 
-#define Module_MajorVersion             "5.34"
-#define Module_Version                  534
+#define Module_MajorVersion             "5.35"
+#define Module_Version                  535
 #define Module_MinorVersion             ""
-#define Module_Date                     "23 Aug 2001"
+#define Module_Date                     "29 Jan 2002"
 
-#define Module_ApplicationDate2         "23-Aug-01"
-#define Module_ApplicationDate4         "23-Aug-2001"
+#define Module_ApplicationDate2         "29-Jan-02"
+#define Module_ApplicationDate4         "29-Jan-2002"
 
 #define Module_ComponentName            "RISC_OSLib"
 #define Module_ComponentPath            "RiscOS/Sources/Lib/RISC_OSLib"
 
-#define Module_FullVersion              "5.34"
-#define Module_HelpVersion              "5.34 (23 Aug 2001)"
+#define Module_FullVersion              "5.35"
+#define Module_HelpVersion              "5.35 (29 Jan 2002)"
+#define Module_LibraryVersionInfo       "5:35"
diff --git a/c/armsys b/c/armsys
index 4b270b6..21723b2 100644
--- a/c/armsys
+++ b/c/armsys
@@ -33,6 +33,7 @@
 #include <string.h>                             /* for strlen()          */
 #include <time.h>                               /* for clock             */
 #include <errno.h>
+#include <stdbool.h>
 
 /* IMPORTS */
 extern int main(int argc, char **argv);         /* the point of it all   */
@@ -40,11 +41,14 @@ extern FILEHANDLE __dup(int new, int old);
 extern void _ctype_init(void);
 extern int _fprintf_lf(FILE *fp, const char *fmt, ...);
 extern int _sprintf_lf(char *buff, const char *fmt, ...);
+extern _kernel_oserror *_kernel_peek_last_oserror(void);
 
 /* HIDDEN EXPORTS */
 void _main(char *s, int (*main)(int, char **));
 void _backtrace(int why, int *address, _kernel_unwindblock *uwb);
 const char *_clib_version(void);
+int _sys_msg_1(const char *s, const char *but);
+int _desktop_task(void);
 
 #define str(x)  #x
 #define xstr(x) str(x)
@@ -149,9 +153,118 @@ time_t time(time_t *timer)
 
 #define istty(fh) ((fh) == TTYHANDLE)
 
+/*
+ * We're a desktop task if we're in user mode, TaskWindow_TaskInfo 0 returns 0 (or an error),
+ * and Wimp_ReadSysInfo 3 says we're in the desktop, and Wimp_ReadSysInfo 5 gives us a
+ * task handle.
+ */
+int _desktop_task()
+{
+    int h = 0;
+    if (_kernel_processor_mode() & 0xF) return 0;
+    _swix(TaskWindow_TaskInfo, _IN(0)|_OUT(0), 0, &h);
+    if (h) return 0;
+    _swix(Wimp_ReadSysInfo, _IN(0)|_OUT(0), 3, &h);
+    if (h == 0) return 0;
+    _swix(Wimp_ReadSysInfo, _IN(0)|_OUT(0), 5, &h);
+    return h;
+}
+
+static int _desktop_report(const char *s, const char *but)
+{
+    _kernel_oserror err, *e;
+    const char *n = NULL;
+    char *p, *end;
+    int flags, r, h = _desktop_task();
+    if (h == 0) return 0;
+
+    flags = 0x102; /* New error, cancel button */
+
+    if ((e = _kernel_last_oserror()) != NULL && s == e->errmess)
+    {
+        flags |= 2 << 9;
+    }
+    else
+    {
+        while (*s == ' ')
+            s++;
+
+        if (s[0] == '*') /* If leading '*'s then make it a serious one */
+        {
+            while (*s == '*' || *s == ' ') /* Strip off the '*'s */
+                s++;
+            flags |= 3 << 9;
+            err.errnum = 0x1B << 24;
+        }
+        else
+        {
+            flags |= 2 << 9;
+            err.errnum = 0;
+        }
+
+        for (p = err.errmess, end = err.errmess + sizeof err.errmess - 1; p < end && *s >= ' '; )
+            *p++ = *s++;
+
+        *p = '\0';
+        err.errmess[0] = toupper(err.errmess[0]);
+
+        e = &err;
+    }
+    _swix(TaskManager_TaskNameFromHandle, _IN(0)|_OUT(0), h, &n);
+
+    r = 0;
+    _swix(Wimp_ReportError, _INR(0,5)|_OUT(1), e, flags, n, NULL, 1, but, &r);
+    return r;
+}
+
+bool _sys__assert(const char *s, const char *expr, const char *file, int line)
+{
+    char buffer[252];
+    int len, exprlen, filelen;
+
+    if (!istty(stderr->__file)) return false;
+
+    if (!_desktop_task()) return false;
+
+    if (strlen(s) > 200) return false; /* Be safe */
+
+    len = sprintf(buffer, s, "", "", line);
+    exprlen = strlen(expr);
+    filelen = strlen(file);
+    if (len + exprlen + filelen < 251)
+    {
+        sprintf(buffer, s, expr, file, line);
+    }
+    else
+    {
+        char expr2[200];
+        char file2[100];
+
+        #define min(a,b) a<b?a:b
+        exprlen = min(exprlen, 199);
+        filelen = min(filelen, 99);
+        filelen = min(filelen, 251-len-exprlen);
+        if (filelen < 0) filelen = 0;
+        exprlen = min(exprlen, 251-len-filelen);
+        memcpy(expr2, expr, exprlen);
+        memcpy(file2, file, filelen);
+        expr2[exprlen]='\0';
+        file2[filelen]='\0';
+        sprintf(buffer, s, expr2, file2, line);
+    }
+    return _desktop_report(buffer, NULL);
+}
+
 static int _error_recursion;
-void _sys_msg(const char *s)
-{   /* write out s carefully for intimate system use.                      */
+int _sys_msg_1(const char *s, const char *but)
+{
+    if (istty(stderr->__file))
+    {
+        int r = _desktop_report(s, but);
+        if (r) return r;
+    }
+
+    /* write out s carefully for intimate system use.                      */
     if ((stderr->__flag & _IOWRITE) && !_error_recursion)
     {
         _error_recursion = 1;
@@ -166,6 +279,13 @@ void _sys_msg(const char *s)
         _ttywrite((unsigned char *)s, strlen(s), 0);
         _ttywrite((unsigned char *)"\n", 1, 0);
     }
+
+    return 0;
+}
+
+void _sys_msg(const char *s)
+{
+    _sys_msg_1(s, NULL);
 }
 
 #define LF '\n'
@@ -195,9 +315,8 @@ FILEHANDLE _sys_open(const char *filename, int openmode)
         (openmode & OPEN_W) ||
         (openmode & ~OPEN_B) == OPEN_A)           /* or mode = w, w+, or a */
     {   if (_kernel_osfile(9, name, &fb) == _kernel_ERROR)
-        {   if (_kernel_last_oserror()->errnum == 0x108c9)
-            {   (void)_kernel_osfile(9, name, &fb); /* to restore the error */
-                errno = -1;
+        {   if (_kernel_peek_last_oserror()->errnum == 0x108c9)
+            {   errno = -1;
                 return NONHANDLE;                       /* (Protected disc) */
             }
         }
diff --git a/c/error b/c/error
index d6fdcfc..00c3eac 100644
--- a/c/error
+++ b/c/error
@@ -49,9 +49,11 @@ void _sysdie(const char *s)
 /* from <assert.h> */
 void __assert(char *expr, char *file, int line)
 {
-    _fprintf_lf(stderr,
-                _kernel_getmessage("*** assertion failed: %s, file %s, line %d", "C34"),
-                expr, file, line);
+    const char *s;
+    s = _kernel_getmessage("*** assertion failed: %s, file %s, line %d", "C34");
+
+    if (!_sys__assert(s, expr, file, line))
+        _fprintf_lf(stderr, s, expr, file, line);
     fputc('\n', stderr);
     abort();
 }
diff --git a/c/signal b/c/signal
index 1186109..fb4417e 100644
--- a/c/signal
+++ b/c/signal
@@ -29,6 +29,9 @@
 extern int _fprintf_lf(FILE *fp, const char *fmt, ...);
 extern int _sprintf_lf(char *buff, const char *fmt, ...);
 
+extern int _SignalNumber(int errnum);
+extern _kernel_oserror *_kernel_peek_last_oserror(void);
+
 #define SIGLAST 11  /* one after highest signal number (see <signal.h>) */
 
 static void (*_signalvector[SIGLAST+1])(int);
@@ -47,6 +50,14 @@ extern void __ignore_signal_handler(int sig)
 static void _real_default_signal_handler(int sig)
 {
     char *s, v[128];
+    _kernel_oserror *e = _kernel_peek_last_oserror();
+
+    if (((sig == SIGSEGV || sig == SIGILL) && _SignalNumber(e->errnum) == sig) ||
+        sig == SIGFPE || sig == SIGOSERROR)
+    {
+        _postmortem(e->errmess, *((int *)"mesg"));
+        return;
+    }
 
     switch (sig)
     {
@@ -56,10 +67,6 @@ case SIGABRT:
 #endif
         s = _kernel_getmessage(s, "C39");
         break;
-case SIGFPE:
-case SIGOSERROR:
-        s = &(_kernel_last_oserror()->errmess[0]);
-        break;
 case SIGILL:
 #ifdef DEFAULT_TEXT
 #ifdef __arm
diff --git a/clib/s/cl_body b/clib/s/cl_body
index 5a0f957..e4272d6 100644
--- a/clib/s/cl_body
+++ b/clib/s/cl_body
@@ -68,6 +68,7 @@ $Label  RFS     r1
         IMPORT  |_signal_real_handler|
         IMPORT  |_armsys_lib_init|
         IMPORT  |_sys_msg|
+        IMPORT  |_sys_msg_1|
 
         IMPORT  |_kernel_fpavailable|
         IMPORT  |_kernel_exittraphandler|
@@ -103,11 +104,7 @@ $Label  RFS     r1
         EXPORT  |x$stack_overflow|
         EXPORT  |x$stack_overflow_1|
         EXPORT  |_raise_stacked_interrupts|
-        EXPORT  |x$udivide|
-        EXPORT  |x$uremainder|
-        EXPORT  |x$divide|
         EXPORT  |x$divtest|
-        EXPORT  |x$remainder|
         EXPORT  |x$multiply|
         EXPORT  |_rd1chk|
         EXPORT  |_rd2chk|
@@ -137,14 +134,13 @@ $Label  RFS     r1
         EXPORT  |_count|
         EXPORT  |_count1|
         EXPORT  |_default_sigstak_handler|
+        EXPORT  |_SignalNumber|
 
         EXPORT  |_ldfp|
         EXPORT  |_stfp|
 
         EXPORT  |__rt_stkovf_split_small|
         EXPORT  |__rt_stkovf_split_big|
-        EXPORT  |__rt_udiv|
-        EXPORT  |__rt_sdiv|
         EXPORT  |__rt_divtest|
         EXPORT  |__rt_rd1chk|
         EXPORT  |__rt_rd2chk|
@@ -242,6 +238,7 @@ UnhandledEventHandler Keep
 02      MOV     a1, #1          ; we wish to handle it, but not just yet
         Return  ,LinkNotStacked
 
+|_SignalNumber|
 SignalNumber Keep
         ; nb required not to disturb a4
         MOV     a2, #SIGOSERROR
@@ -316,39 +313,21 @@ Raised
 
 |x$multiply|
 ; a1 := a2 * a1.
-; sets a2 to 0 and a3 to a copy of the product.
-        MOV     a3, #0
-m0loop  MOVS    a2, a2, LSR #1
-        ADDCS   a3, a3, a1
-        ADD     a1, a1, a1
-        BNE     m0loop
-        MOV     a1, a3
+; a2, a3 can be scrambled.
+        MUL     a1, a2, a1
         Return  ,LinkNotStacked
 
-|x$remainder|
-        B       |_kernel_srem|
-
         IMPORT  |_kernel_copyerror|
         IMPORT  |_kernel_fault|
 |__rt_divtest|
 |x$divtest|
 ; test for division by zero (used when division is voided)
-        CMPS    a1, #0
+        TEQS    a1, #0
         Return  ,LinkNotStacked, NE
         STMFD   sp!, {r0}
         ADR     r0, E_DivideByZero
         B       |_kernel_fault|
 
-|__rt_sdiv|
-|x$divide|
-        B       |_kernel_sdiv|
-
-|__rt_udiv|
-|x$udivide|
-        B       |_kernel_udiv|
-
-|x$uremainder|
-        B       |_kernel_urem|
 
 |__rt_rd1chk|
 |_rd1chk|
@@ -492,10 +471,6 @@ readfail
         Return
 
 mesg    DCB     "mesg"
-wimp_title
-        DCB     "WindowManager", 0
-utility_title
-        DCB     "UtilityModule", 0
       [ :DEF:DEFAULT_TEXT
 postmortem_title
         DCB     "Postmortem", 0
@@ -504,70 +479,13 @@ postmortem_tag
         DCB     "C65", 0
         ALIGN
 
-n_module_lookup  EQU 18
-wimp_preinitflag EQU &80000000
-zp_wimpdomain    EQU &ff8
-
+        IMPORT  |_desktop_task|
         IMPORT  |_kernel_unwind|
+        IMPORT  exit
 |_postmortem|
         ; Prepare window manager for output
         ; First check this is a wimp task
         STMFD   sp!, {r0-r5, r14}
-        MOV     r0, #n_module_lookup
-        ADR     r1, utility_title
-        SWI     XOS_Module
-        BVS     postmortem2
-        LDR     r0, [r3, #5 * 4]
-        MOV     r1, #0
-        ADD     r0, r0, r3
-postmortem3
-        LDRB    r2, [r0], #1
-        CMP     r2, #9
-        ORREQ   r1, r1, #7
-        ADD     r1, r1, #1
-        CMP     r1, #16
-        BCC     postmortem3
-        LDRB    r1, [r0]
-        SUB     r1, r1, #'0'
-        LDRB    r2, [r0, #2]
-        SUB     r2, r2, #'0'
-        ADD     r1, r1, r1, LSL #2
-        ADD     r1, r2, r1, LSL #1
-        LDRB    r2, [r0, #3]
-        SUB     r2, r2, #'0'
-        ADD     r1, r1, r1, LSL #2
-        ADD     r1, r2, r1, LSL #1
-        CMP     r1, #202
-        BCC     postmortem2
-        MOV     r0, #0
-        SWI     XTaskWindow_TaskInfo
-        MOVVS   r0, #0
-        CMP     r0, #0
-        BNE     postmortem0
-        MOV     r0, #3
-        SWI     XWimp_ReadSysInfo
-        BVS     postmortem0
-        CMP     r0, #0
-        BEQ     postmortem0
-        B       postmortem4
-postmortem2
-        MOV     r0, #0
-        SWI     XWimp_ReadSysInfo
-        BVS     postmortem0
-        CMP     r0, #0
-        BEQ     postmortem0
-        ; In desktop, now check Wimp_Initialise has been called
-        MOV     r0, #n_module_lookup
-        ADR     r1, wimp_title
-        SWI     XOS_Module
-        BVS     postmortem0
-        MOV     r0, #0
-        LDR     r0, [r0, #zp_wimpdomain]
-        LDR     r0, [r4, r0]
-        TST     r0, #wimp_preinitflag
-        BNE     postmortem0
-        ; If so reopen command window
-postmortem4
         [ :DEF:DEFAULT_TEXT
         ADR     r0, postmortem_title
         ADR     r1, postmortem_tag
@@ -575,13 +493,32 @@ postmortem4
         ADR     r0, postmortem_tag
         ]
         BL      |_kernel_getmessage|
-        SWI     XWimp_CommandWindow
+        MOV     r5, r0
 postmortem0
-        LDMFD   sp!, {r0-r5}
-        LDR     a3, mesg
-        CMP     a2, a3
-        BLEQ    |_sys_msg|                      ; BL<cond> 32-bit OK
+        LDMFD   sp, {a1-a2}
+        LDR     a3, mesg                ; if magic arg2 != "mesg"
+        CMP     a2, a3                  ; then go straight onto postmortem
+        BNE     postmortem1
+        MOV     a2, r5                  ; if so, offer postmortem
+        BL      |_sys_msg_1|
+        TEQ     r4, #1
+        TEQ     a1, #0                  ; if didn't display the button
+        TEQNE   a1, #3                  ; or if he selected it, then carry on with postmortem
+        MOVNE   a1, #1                  ; otherwise exit(EXIT_FAILURE)
+        BNE     exit
 postmortem1
+        BL      _desktop_task
+        TEQ     a1, #0
+        BEQ     postmortem2
+        LoadStaticAddress __iob + 2 * 40, a2, a3 ; a2 -> stderr
+        LDR     r4, [a2, #20]           ; a2 = stderr->__file
+        TEQ     r4, #0                  ; istty(stderr->__file)?
+        BNE     postmortem2
+        MOV     r0, r5                  ; if desktop, and stderr = tty
+        SWI     XWimp_CommandWindow     ; then open command window,
+        SWI     XOS_WriteI + 14         ; page mode on
+postmortem2
+        LDMFD   sp!, {r0-r5}
         BL      |_kernel_fpavailable|
         LDMFD   sp!, {r14}
         CMP     a1, #0
@@ -645,6 +582,28 @@ postmortem_nofp
         ADD     sp, sp, #22*4
         MOV     a3, sp
         B       |_backtrace|
+        ;MOV     a1, #&4000
+        ;MOV     a2, #&4000
+        ;MOV     a3, #&20
+        ;MOV     a4, #&FF
+        ;SWI     XOS_ReadLine
+        ;MOVCS   a1, #124
+        ;SWICS   XOS_Byte
+        ;SWI     XWimp_CloseDown
+        ;ADR     a1, debug_cmd
+        ;SWI     XOS_CLI
+        ;MOVVC   a1, #0
+        ;LDRVS   a1, [a1]
+        ;TEQ     a1, #0
+        ;TEQNE   a1, #&11
+        ;MOVEQ   a1, #-1
+        ;SWIEQ   XWimp_CommandWindow
+        ;MOV     a1, #1
+        ;B       exit
+
+debug_cmd
+        DCB     "Debug", 0
+        ALIGN
 
 |__rt_stkovf_split_small|
 |x$stack_overflow|
diff --git a/h/hostsys b/h/hostsys
index a51bf5b..d0cf537 100644
--- a/h/hostsys
+++ b/h/hostsys
@@ -23,6 +23,7 @@
 #define __hostsys_h
 
 #include <stdio.h>
+#include <stdbool.h>
 
 #undef MACHINE
 #ifdef __arm
@@ -99,6 +100,8 @@ extern void *_sys_alloc(size_t n);
 extern void _init_user_alloc(void);
 extern void _terminate_user_alloc(void);
 extern void _sys_msg(const char *);
+extern bool _sys__assert(const char *fmt,
+                         const char *expr, const char *file, int line);
 extern void _exit(int n);
 extern void _terminate_getenv(void);
 
diff --git a/kernel/s/k_body b/kernel/s/k_body
index 8e2f5c1..87badcd 100644
--- a/kernel/s/k_body
+++ b/kernel/s/k_body
@@ -47,6 +47,7 @@
         EXPORT  |_kernel_osargs|
         EXPORT  |_kernel_oscli|
         EXPORT  |_kernel_last_oserror|
+        EXPORT  |_kernel_peek_last_oserror|
         EXPORT  |_kernel_system|
         EXPORT  |_kernel_getenv|
         EXPORT  |_kernel_setenv|
@@ -88,9 +89,16 @@
         EXPORT  |_kernel_call_client|
         EXPORT  |_kernel_raise_error|
 
+        EXPORT  |__rt_sdiv|
+        EXPORT  |__rt_udiv|
         EXPORT  |__rt_udiv10|
         EXPORT  |__rt_sdiv10|
 
+        EXPORT  |x$divide|
+        EXPORT  |x$udivide|
+        EXPORT  |x$remainder|
+        EXPORT  |x$uremainder|
+
         EXPORT  |__counter|
 
 PSRBits         *       &FC000003
@@ -719,7 +727,7 @@ ABEXString
 ; tacked on the end.
 
 IIHandlerInDataInitValue
-        STMFD   r13!, {r0, r12}
+        STMFD   r13!, {r0-r4, r12, r14, pc}
         SUB     r12, pc, #O_IIHandlerInData+12
 
 ; Now the bits of the abort handlers which get executed from the code.
@@ -728,81 +736,88 @@ IIHandlerInDataInitValue
 
 IIHandler Keep
         SUB     r14, r14, #4
-        ADR     r0, E_IllegalInstruction
+        STR     r14, [r12, #O_registerDump + 15 * 4]
+
+        LDR     r14, [r12, #O_oldAbortHandlers + 0]
+        STR     r14, [r13, #28]
         B       Aborted
 
+
 PAHandlerInDataInitValue
-        STMFD   r13!, {r0, r12}
+        STMFD   r13!, {r0-r4, r12, r14, pc}
         SUB     r12, pc, #O_PAHandlerInData+12
 PAHandler Keep
         SUB     r14, r14, #4
-        ADR     r0, E_PrefetchAbort
+        STR     r14, [r12, #O_registerDump + 15 * 4]
+
+        LDR     r14, [r12, #O_oldAbortHandlers + 4]
+        STR     r14, [r13, #28]
         B       Aborted
 
 DAHandlerInDataInitValue
-        STMFD   r13!, {r0, r12}
+        STMFD   r13!, {r0-r4, r12, r14, pc}
         SUB     r12, pc, #O_DAHandlerInData+12
 DAHandler Keep
         SUB     r14, r14, #8
-        ADR     r0, E_DataAbort
+        STR     r14, [r12, #O_registerDump + 15 * 4]
+
+        LDR     r14, [r12, #O_oldAbortHandlers + 8]
+        STR     r14, [r13, #28]
         B       Aborted2
 
 AEHandlerInDataInitValue
-        STMFD   r13!, {r0, r12}
+        STMFD   r13!, {r0-r4, r12, r14, pc}
         SUB     r12, pc, #O_AEHandlerInData+12
 AEHandler Keep
         SUB     r14, r14, #8
-        ADR     r0, E_AddressException
+        STR     r14, [r12, #O_registerDump + 15 * 4]
+
+        LDR     r14, [r12, #O_oldAbortHandlers + 12]
+        STR     r14, [r13, #28]
 ;       B       Aborted2
 
 Aborted2 Keep
 ; Abort which may be in the FP emulator, and if so should be reported
 ; as occurring at the instruction being emulated.
 ; Try the FPEmulator_Abort SWI
-        STMFD   sp!, {r0-r2, r14}
+
+        LDR     r2, [sp, #24]
       [ {CONFIG}=26
-        BIC     r14, r14, #PSRBits
+        BIC     r2, r2, #PSRBits
       |
-        MOV     r0, #0
-        MRS     r0, CPSR
-        TST     r0, #2_11100
-        BICEQ   r14, r14, #PSRBits
+        TEQ     pc, pc
+        BICNE   r2, r2, #PSRBits
       ]
         MOV     r0, #-2                 ; current context
         LDR     r1, [sp, #20]           ; original r12
-        ADD     r2, r14, #8             ; original r14
+        ADD     r2, r2, #8              ; original r14
         SWI     XFPEmulator_Abort
         BVS     NoFPEAbortSWI
         TEQ     r0, #0
-        LDMEQFD sp!, {r0-r2, r14}
+        LDMEQFD sp, {r0-r2}
         BEQ     Aborted                 ; not in FPEmulator
-        STR     r0, [sp, #20]           ; update r12 in stack
-        LDMFD   sp!, {r0-r2, r14}
         B       FPEFault
 
 NoFPEAbortSWI
 ; If in user mode, can't be in FPE
       [ {CONFIG}=26
-        LDR     r1, [sp, #12]
+        LDR     r1, [sp, #24]
         TST     r1, #PSRPrivileged
       |
-        MOV     r2, #0
-        MRS     r2, CPSR
-        TST     r2, #2_11100
-        LDREQ   r1, [sp, #12]
-        ANDEQ   r1, r1, #3              ; obtain aborter's mode from R14
-        MRSNE   r1, SPSR                ; obtain aborter's mode from SPSR
+        TEQ     pc, pc
+        LDRNE   r1, [sp, #24]
+        ANDNE   r1, r1, #PSRMode        ; obtain aborter's mode from R14
+        MRSEQ   r1, SPSR                ; obtain aborter's mode from SPSR
         TST     r1, #PSR32Privileged
       ]
-        LDMEQFD sp!, {r0-r2, r14}
+        LDMEQFD sp, {r0-r4}
         BEQ     Aborted
 
 ; Otherwise, find out where the FPE module is
       [ {CONFIG} <> 26
         TST     r2, #2_11100
       ]
-        LDMFD   sp!, {r0-r2, r14}
-        STMFD   sp!, {r0 - r6, r14}
+        STMFD   sp!, {r0 - r6}
       [ {CONFIG} = 26
         BIC     r6, r14, #PSRBits
       |
@@ -812,65 +827,60 @@ NoFPEAbortSWI
         MOV     r0, #18
         ADR     r1, FPEName
         SWI     Module
-        LDMVSFD sp!, {r0 - r6, r14}
+        LDMVSFD sp!, {r0 - r6}
         BVS     Aborted
 ; (r3 = code base of FPE; word before is length of FPE code)
         CMP     r6, r3
         LDRGE   r4, [r3, #-4]
         ADDGE   r3, r3, r4
         CMPGE   r3, r6
-        LDMFD   sp!, {r0 - r6, r14}
+        LDMFD   sp!, {r0 - r6}
         BLT     Aborted
 
 ; It was a storage fault in the FP emulator.
-; We assume FPEmulator 4.00 or later - r12 in the register dump
+; We assume FPEmulator 4.00 or later - r0
 ; will point to a full register save. The format differs slightly
 ; depending on whether the FPEmulator is 32-bit or not. If we're
 ; in a 32-bit mode, we know the FPEmulator will be. If not, check
 ; to see if the saved r12 is in the UND stack.
 FPEFault
-        LDR     r1, [r13, #4]           ; r1 -> FPE stack frame
-        ADD     r13, r13, #8            ; pop the saved values of r0 and r12
         ADD     r14, r12, #O_registerDump
-        LDMIA   r1!, {r2-r9}            ; copy R0-R15
-        STMIA   r14!, {r2-r9}
-        LDMIA   r1!, {r2-r9}
-        SUB     r9, r9, #4
-        STMIA   r14!, {r2-r9}
+        LDMIA   r0!, {r1-r4}            ; copy R0-R15
+        STMIA   r14!, {r1-r4}
+        LDMIA   r0!, {r1-r4}
+        STMIA   r14!, {r1-r4}
+        LDMIA   r0!, {r1-r4}
+        STMIA   r14!, {r1-r4}
+        LDMIA   r0!, {r1-r4}
+        SUB     r4, r4, #4              ; adjust PC back 4
+        STMIA   r14!, {r1-r4}
       [ {CONFIG}<>26
-        MOV     r2, #0
-        MRS     r2, CPSR
-        TST     r2, #2_11100
-        BNE     FPEFault_32on32
+        TEQ     pc, pc
+        BEQ     FPEFault_32on32
       ]
         LDR     r3, [r12, #O_undStack]
         MOV     r2, r1, LSR #20         ; we're on a 26-bit system
         TEQ     r2, r3, LSR #20         ; is the stack frame in the UND stack?
         BEQ     FPEFault_32on26
 FPEFault_26on26
-        MOV     sp, r1                  ; pull the SVC stack up
-        B       AbortFindHandler
+        B       FPEFault_Continue
 
 FPEFault_32on26
-        LDR     r2, [r1, #-72]          ; get the SPSR
+        LDR     r2, [r0, #-72]          ; get the SPSR
         AND     r2, r2, #PSRBits
-        BIC     r9, r9, #PSRBits
-        ORR     r9, r9, r2
-        STR     r9, [r14, #-4]          ; merge it with pc in register dump
-        B       FPEFault_32
+        BIC     r4, r4, #PSRBits
+        ORR     r4, r4, r2
+        STR     r4, [r14, #-4]          ; merge it with pc in register dump
+      [ {CONFIG}<>26
+        B       FPEFault_Continue
 
 FPEFault_32on32
         LDR     r2, [r1, #-72]          ; get the SPSR
         STR     r2, [r14]               ; store it in the register dump
+      ]
 
-FPEFault_32
-        MRS     r2, CPSR
-        BIC     r3, r2, #PSR32Mode
-        ORR     r3, r3, #PSR32IBit + PSR32UNDMode
-        MSR     CPSR_c, r3
-        MOV     sp, r1                  ; pull the UND stack up
-        MSR     CPSR_c, r2
-        B       AbortFindHandler
+FPEFault_Continue
+        LDMFD   r13!, {r0-r4, r12, r14, pc}
 
         ErrorBlock  PrefetchAbort,      "Prefetch Abort", C60
         ErrorBlock  DataAbort,          "Data Abort", C61
@@ -880,59 +890,49 @@ FPEName =       "FPEmulator",0
         ALIGN
 
 Aborted Keep
-; entry here in SVC26, SVC32, ABT32 or UND32 mode
-; r0 a pointer to an error block describing the abort.
-; all user registers except r0, r12 are as at the time of the abort.
-; r0 & r12 are on the stack.
-; First, save all user registers in registerDump.
-        STMFD   r13!, {r14}         ; remember the abort pc
-        BL      |_kernel_copyerror|
         ADD     r14, r12, #O_registerDump
-
   [ SASTMhatbroken
-	STMIB	r14!, {r1-r12}
-	STMIB	r14, {r13,r14}^
-	NOP
-	SUB	r14, r14, #12*4
+        STMIA   r14!, {r0-r12}
+        STMIA   r14, {r13,r14}^
+        NOP
+        SUB     r14, r14, #13*4
   |
-        STMIB   r14, {r1-r14}^
+        STMIA   r14, {r0-r14}^
+        NOP
   ]
 
-        LDMFD   r13!, {r1, r2, r3}      ; abort PC, R0, R12
-
-        MOV     r6, r14                 ; switch it to a non-banked register
-        MOV     r4, #0
-        MRS     r4, CPSR
-        TST     r4, #2_11100
-        ANDEQ   r5, r1, #3              ; obtain aborter's mode from R14
-        MRSNE   r5, SPSR                ; obtain aborter's mode from SPSR
-        STRNE   r5, [r14, #16*4]        ; store aborter's SPSR if in 32-bit mode
-        BICNE   r4, r4, #PSR32Mode
-        ORRNE   r4, r4, #PSR32SVCMode
-        MSRNE   CPSR_c, r4              ; switch to SVC32 (already in SVC26 if 26bit)
-        TST     r5, #PSR32Privileged
-        LDRNE   r1, [r6, #lr*4]         ; if aborted in a privileged mode, save
-        STR     r1, [r6, #pc*4]         ; PC as user R14
-        STR     r2, [r6, #r0*4]
-        STREQ   r3, [r6, #r12*4]
-        BEQ     AbortFlattenStacks
-        LDR     r4, [r12, #O_svcStack]
-        SUB     r1, r4, sp
-        CMP     r1, #3 * 4
-        BCC     AbortFlattenStacks
-        LDMEA   r4, {r1, r2, r3}
-        ADD     r4, r6, #10 * 4
-        STMIA   r4, {r1, r2, r3}
-
-; should really fall through to error handler and let the OS clean up,
-; but this is a lot better than it was!
-AbortFlattenStacks
-        MRS     r4, CPSR                ; MRS and MSR here will be NOPs on
-        ORR     r1, r4, #PSR32UNDMode   ; ARM2/3, so we'll end up setting
-        MSR     CPSR_c, r1              ; R13_svc twice; just make sure
-        LDR     sp, [r12, #O_undStack]  ; we set the real value last.
-        MSR     CPSR_c, r4
-        LDR     sp, [r12, #O_svcStack]
+        LDR     r0, [r13, #20]
+        STR     r0, [r14, #r12*4]
+
+        MOV     r3, pc
+        AND     r3, r3, #PSRBits
+        MRS     r3, CPSR
+        TST     r3, #2_11100
+        LDREQ   r0, [sp, #24]
+        ANDEQ   r0, r0, #PSRMode        ; obtain aborter's mode from R14
+        MRSNE   r0, SPSR                ; obtain aborter's mode from SPSR
+        STRNE   r0, [r14, #16*4]        ; store aborter's SPSR if in 32-bit mode
+        TST     r0, #PSR32Privileged
+        BEQ     NotPrivileged
+        LDR     r0, [r14, #r14*4]       ; if abort in a privileged mode, save
+        STR     r0, [r14, #pc*4]        ; PC as user R14
+        LDR     r0, [r12, #O_svcStack]  ; switch to SVC mode and look at R13_svc
+        TEQ     pc, pc
+        MSREQ   CPSR_c, #PSR32SVCMode
+        TEQNEP  pc, #PSRSVCMode
+        NOP
+        SUB     r12, r0, sp
+        CMP     r12, #3 * 4
+        BLT     NotPrivileged
+        LDMDB   r0, {r0-r2}             ; Pull R10-R12 off of top of SVC stack
+        ADD     r4, r14, #10 * 4        ; if there were at least 3 words on it
+        STMIA   r4, {r0-r2}
+        TEQ     pc, pc
+        MSREQ   CPSR_cxs, r3
+        TEQNEP  pc, r3
+        NOP
+NotPrivileged
+        LDMFD   r13!, {r0-r4, r12, r14, pc}
 
 AbortFindHandler Keep
 ; We can only call an abort handler if we had a stack at the
@@ -1493,19 +1493,26 @@ ErrorHandler Keep
 ; Since it would be nice to preserve as much as possible for the FP fault case
 ; we switch back to SWI mode to save the registers.
         SWI     EnterSVC
-        ADD     r14, r0, #O_registerDump
 
+        LDR     r14, [r0, #O_errorNumber]
+        TEQ     r14, #Error_IllegalInstruction
+        TEQNE   r14, #Error_PrefetchAbort
+        TEQNE   r14, #Error_DataAbort
+        TEQNE   r14, #Error_AddressException
   [ SASTMhatbroken
-	STMIA	r14!, {r0-r12}
-	STMIA	r14, {r13,r14}^
-	NOP
-	SUB	r14, r14, #13*4
+        ADDNE   r14, r0, #O_registerDump
+        STMNEIA r14!, {r0-r12}
+        STMNEIA r14, {r13,r14}^
+        NOP
+        SUBNE   r14, r14, #13*4
   |
-        STMIA   r14, {r0-r14}^
+        STMNEIA r14, {r0-r14}^
   ]
 
         MOV     r12, r0
         ADD     r0, r0, #O_errorNumber
+        BEQ     AbortFindHandler
+
         LDMDA   r0, {r1, r2}            ; r1 is error pc, r2 error number
         MOV     r14, #0
         STR     r14, [r12, #O_registerDump+16*4]        ; zero PSR
@@ -1582,13 +1589,20 @@ EndFastEventHandlers
 
 EscapeHandler Keep
         TSTS    r11, #&40
-        MOVEQ   pc, r14         ; ignore flag going away
+        BNE     haveEscape
+        STMFD   r13!, {r0}
+        MOV     r0, #0
+        STRB    r0, [r12, #O_hadEscape]
+        LDMFD   r13!, {r0}
+        MOV     pc, r14         ; ignore flag going away
 
+haveEscape
         ; In Arthur, it is NEVER safe to call a handler now: we always have to
         ; wait for CallBack.
         STMFD   r13!, {r0}
         MOV     r0, #-1
         STRB    r0, [r12, #O_hadEscape]
+        LDRB    r0, [r12, #O_eventCode]
         STRB    r0, [r12, #O_escapeSeen]
         STR     r0, [r12, #O_eventCode]
         LDRB    r11, [r12, #O_callbackInactive]
@@ -1652,9 +1666,12 @@ Event_NoStackForHandler
         MOV     r1, #0
         STRB    r1, [v6, #O_hadEscape]
         LDR     v1, [v6, #O_eventCode]
+        TEQ     r0, #0                  ; if hadEscape = 0
+        CMPEQ   v1, #-1                 ; and it's an escape event
+        BEQ     %FT02                   ; then the escape's gone.
         CMP     r0, #0
         BEQ     %FT01
-        MOV     r0, #&7e
+        MOV     r0, #126                ; acknowledge escape
         SWI     Byte
         MOV     v1, #-1                 ; escape overrides everything else
 01
@@ -1667,7 +1684,7 @@ Event_NoStackForHandler
 
         CMP     r12, #0
         BGE     CallEventHandlers
-
+02
         ADD     r0, v6, #O_registerDump
         B       ReloadUserState
 
@@ -2116,6 +2133,13 @@ ErrorExitV6Stacked
         STRNE   a2, [ip, #O_errorBuffer]
         Return  ,LinkNotStacked
 
+|_kernel_peek_last_oserror|
+        LoadStaticBase ip, a1
+        LDR     a1, [ip, #O_errorBuffer]
+        TEQ     a1, #0
+        ADDNE   a1, ip, #O_errorNumber
+        Return  ,LinkNotStacked
+
 |_kernel_system|
 ; Execute the string a1 as a command;  if a2 is zero, as a subprogram,
 ; otherwise a replacement.
@@ -2853,7 +2877,9 @@ StackOverflowFault Keep
  ;* Arithmetic                                                        *
  ;*-------------------------------------------------------------------*
 
+|__rt_udiv|
 |_kernel_udiv|
+|x$udivide|
 ; Unsigned divide of a2 by a1: returns quotient in a1, remainder in a2
 ; Destroys a3 and ip
 
@@ -2913,6 +2939,7 @@ u_sh0   RSBS    ip, a1, a2
 ; codegenerator will call udiv directly and use the result in a2
 
 |_kernel_urem|
+|x$uremainder|
         FunctionEntry
         BL      |_kernel_udiv|
         MOV     a1, a2
@@ -2936,7 +2963,9 @@ u_sh0   RSBS    ip, a1, a2
         Return  ,LinkNotStacked
 
 
+|__rt_sdiv|
 |_kernel_sdiv|
+|x$divide|
 ; Signed divide of a2 by a1: returns quotient in a1, remainder in a2
 ; Quotient is truncated (rounded towards zero).
 ; Sign of remainder = sign of dividend.
@@ -3001,6 +3030,7 @@ s_sh0   RSBS    ip, a1, a2
 ; Signed remainder of a2 by a1: returns remainder in a1
 
 |_kernel_srem|
+|x$remainder|
         FunctionEntry
         BL      |_kernel_sdiv|
         MOV     a1, a2
-- 
GitLab