Index: trunk/src/emx/ChangeLog.LIBC
===================================================================
--- trunk/src/emx/ChangeLog.LIBC	(revision 2203)
+++ trunk/src/emx/ChangeLog.LIBC	(revision 2204)
@@ -1,3 +1,12 @@
 /* $Id$ */
+
+2005-07-03: knut st. osmundsen <bird-gccos2-spam@anduin.net>
+    - libc:
+        o Collected the different panic routines into one single routine
+          in the backend, __libc_Back_panic[V](). The routine supports
+          very simple printf like message formatting. By default it wil
+          dump any available registers and attempt dumping the process
+          before killing it. This behaviour can be configured with the
+          env var.: LIBC_PANIC=[nodump][terse][quiet][breakpoint]
 
 2005-07-02: knut st. osmundsen <bird-gccos2-spam@anduin.net>
Index: trunk/src/emx/include/InnoTekLIBC/backend.h
===================================================================
--- trunk/src/emx/include/InnoTekLIBC/backend.h	(revision 2203)
+++ trunk/src/emx/include/InnoTekLIBC/backend.h	(revision 2204)
@@ -38,4 +38,5 @@
 #include <signal.h>
 #include <emx/io.h>
+#include <stdarg.h>
 
 
@@ -1040,4 +1041,36 @@
 /** @} */
 
+
+/** @defgroup grp_Back_panic    LIBC Backend - Panic Routines
+ * @{ */
+
+/** The panic was caused by a signal. Drop the LIBC PANIC line. */
+#define __LIBC_PANIC_SIGNAL         1
+/** Don't set the SPM termination code / status. When set the caller is
+ * responsible for doing this. */
+#define __LIBC_PANIC_NO_SPM_TERM    2
+
+/**
+ * Print a panic message and dump/kill the process.
+ *
+ * @param   fFlags      A combination of the __LIBC_PANIC_* defines.
+ * @param   pvCtx       Pointer to a context record if available. This is a PCONTEXTRECORD.
+ * @param   pszFormat   User message which may contain %s and %x.
+ * @param   ...         String pointers and unsigned intergers as specified by the %s and %x in pszFormat.
+ */
+void __libc_Back_panic(unsigned fFlags, void *pvCtx, const char *pszFormat, ...) __attribute__((__noreturn__));
+
+/**
+ * Print a panic message and dump/kill the process.
+ *
+ * @param   fFlags      A combination of the __LIBC_PANIC_* defines.
+ * @param   pvCtx       Pointer to a context record if available. This is a PCONTEXTRECORD.
+ * @param   pszFormat   User message which may contain %s and %x.
+ * @param   args        String pointers and unsigned intergers as specified by the %s and %x in pszFormat.
+ */
+void __libc_Back_panicV(unsigned fFlags, void *pvCtx, const char *pszFormat, va_list args) __attribute__((__noreturn__));
+
+/* @} */
+
 __END_DECLS
 
Index: trunk/src/emx/include/emx/umalloc.h
===================================================================
--- trunk/src/emx/include/emx/umalloc.h	(revision 2203)
+++ trunk/src/emx/include/emx/umalloc.h	(revision 2204)
@@ -807,21 +807,5 @@
 
 
-static __inline__ void _um_abort (const char *pszmsg)
-{
-  /* Use the 'syscall' write for safest possible path. */
-  extern int __write (int handle, const void *buf, size_t nbytes);
-  __write (2, "\r\n!_um_abort!", 13);
-  if (pszmsg)
-    {
-      const char *psz = pszmsg;
-      while (*psz)
-        psz++;
-      __write (2, " ", 1);
-      __write (2, pszmsg, psz - pszmsg);
-    }
-  __write (2, "\r\n", 2);
-  __asm__ __volatile__ ("int $3");
-}
-
+void _um_abort (const char *, ...)  __attribute__((__noreturn__));
 
 #if defined (__cplusplus)
Index: trunk/src/emx/src/lib/libc.def
===================================================================
--- trunk/src/emx/src/lib/libc.def	(revision 2203)
+++ trunk/src/emx/src/lib/libc.def	(revision 2204)
@@ -1917,2 +1917,5 @@
     "__ufc_output_conversion_r" @1916
     "__ufc_setup_salt_r" @1917
+    "___libc_Back_panic" @1918
+    "___libc_Back_panicV" @1919
+    "__um_abort" @1920
Index: trunk/src/emx/src/lib/malloc/_hinitheap.c
===================================================================
--- trunk/src/emx/src/lib/malloc/_hinitheap.c	(revision 2203)
+++ trunk/src/emx/src/lib/malloc/_hinitheap.c	(revision 2204)
@@ -90,5 +90,5 @@
     if (!pvInitial)
     {
-        abort();
+        _um_abort("_hinitheap: __libc_HimemDefaultAlloc failed!\n");
         return NULL;
     }
@@ -103,10 +103,10 @@
     if (Heap == NULL)
     {
-        abort();
+        _um_abort("_hinitheap: _ucreate2 failed!\n");
         return NULL;
     }
     if (_uopen(Heap) != 0)
     {
-        abort();
+        _um_abort("_hinitheap: _uopen(%p) failed!\n", Heap);
         return NULL;
     }
Index: trunk/src/emx/src/lib/malloc/_linitheap.c
===================================================================
--- trunk/src/emx/src/lib/malloc/_linitheap.c	(revision 2203)
+++ trunk/src/emx/src/lib/malloc/_linitheap.c	(revision 2204)
@@ -75,5 +75,5 @@
     if (pvInitial == (void *)-1)
     {
-        abort();
+        _um_abort("_linitheap: sbrk failed!\n");
         return NULL;
     }
@@ -88,10 +88,10 @@
     if (Heap == NULL)
     {
-        abort();
+        _um_abort("_linitheap: _ucreate2 failed!\n");
         return NULL;
     }
     if (_uopen(Heap) != 0)
     {
-        abort();
+        _um_abort("_linitheap: _uopen(%p) failed!\n", Heap);
         return NULL;
     }
Index: trunk/src/emx/src/lib/malloc/ifree.c
===================================================================
--- trunk/src/emx/src/lib/malloc/ifree.c	(revision 2203)
+++ trunk/src/emx/src/lib/malloc/ifree.c	(revision 2204)
@@ -40,5 +40,6 @@
   if (*patch == NULL)
     {
-      _um_abort ("Corrupt heap? (Patch not found.)");
+      _um_abort ("_um_crate_free: patch not found! patch=%p crate=%p crateset=%p\n",
+                 patch, crate, crateset);
       return;
     }
@@ -126,5 +127,6 @@
   if (_UM_HDR_STATUS (hdr) == _UMS_FREE)
     {
-      _um_abort ("Tried to free block twice! (free)");
+      _um_abort ("_um_free_maybe_lock: Tried to free block twice - block=%p lock=%d\n",
+                 block, lock);
       return;
     }
@@ -141,5 +143,6 @@
       break;
     default:
-      _um_abort ("Corrupt heap or passing wrong pointer to free! (bad parent magic)");
+      _um_abort ("_um_free_maybe_lock: bad parent magic %x, parent=%p block=%p lock=%d\n",
+                 *parent, parent, block, lock);
       return;
 
Index: trunk/src/emx/src/lib/malloc/imisc.c
===================================================================
--- trunk/src/emx/src/lib/malloc/imisc.c	(revision 2203)
+++ trunk/src/emx/src/lib/malloc/imisc.c	(revision 2204)
@@ -9,4 +9,5 @@
 #include <sys/fmutex.h>
 #include <emx/umalloc.h>
+#include <InnoTekLIBC/backend.h>
 
 /* Leave FLS undefined if __fls() is not available.  __fls() is
@@ -33,5 +34,5 @@
     if (_UM_BUCKET_SIZE (bucket) <= rsize)
       return bucket;
-  abort ();                     /* RSIZE is probably not rounded! */
+  _um_abort ("_um_find_bucked: rsize=%x\n", rsize); /* RSIZE is probably not rounded! */
 #endif
 }
@@ -162,2 +163,12 @@
   _um_lump_link_heap (h, lump);
 }
+
+
+void _um_abort (const char *pszMsg, ...)
+{
+  va_list args;
+  va_start(args, pszMsg);
+  __libc_Back_panicV(0, NULL, pszMsg, args);
+  va_end(args);
+}
+
Index: trunk/src/emx/src/lib/malloc/irealloc.c
===================================================================
--- trunk/src/emx/src/lib/malloc/irealloc.c	(revision 2203)
+++ trunk/src/emx/src/lib/malloc/irealloc.c	(revision 2204)
@@ -316,5 +316,6 @@
   if (_UM_HDR_STATUS (hdr) == _UMS_FREE)
     {
-      _um_abort ("Tried to free block twice! (realloc)");
+      _um_abort ("_um_free_maybe_lock: Tried to reallocate freed block - block=%p new_size=%x align=%x flags=%x\n",
+                 block, new_size, align, flags);
       errno = EINVAL;
       return NULL;
@@ -337,5 +338,6 @@
     default:
       {
-        _um_abort ("Corrupt heap or passing wrong pointer to realloc! (bad parent magic)");
+        _um_abort ("_um_realloc: bad parent magic %x, parent=%p block=%p new_size=%x align=%x flags=%x\n",
+                   *parent, parent, block, new_size, align, flags);
         errno = EINVAL;
         return NULL;
Index: trunk/src/emx/src/lib/malloc/uheapmin.c
===================================================================
--- trunk/src/emx/src/lib/malloc/uheapmin.c	(revision 2203)
+++ trunk/src/emx/src/lib/malloc/uheapmin.c	(revision 2204)
@@ -64,5 +64,5 @@
                 }
               else
-                abort ();
+                 _um_abort ("_uheapmin: shrink_size=%x seg->size=%x\n", shrink_size, seg->size);
             }
           else
Index: trunk/src/emx/src/lib/process/fmutex.c
===================================================================
--- trunk/src/emx/src/lib/process/fmutex.c	(revision 2203)
+++ trunk/src/emx/src/lib/process/fmutex.c	(revision 2204)
@@ -17,4 +17,5 @@
 #define __LIBC_LOG_GROUP __LIBC_LOG_GRP_MUTEX
 #include <InnoTekLIBC/logstrict.h>
+#include <InnoTekLIBC/backend.h>
 
 /*******************************************************************************
@@ -308,72 +309,13 @@
 }
 
-static void __fmutex_deadlock_hex(unsigned u, unsigned cDigits)
-{
-    static const char szHex[17] = "0123456789abcdef";
-    ULONG cb;
-    char sz[32];
-    if (u <= 0xf && cDigits <= 1)
-    {
-        sz[0] = szHex[u & 0xf];
-        sz[1] = '\0';
-        cb = 1;
-    }
-    if (u <= 0xff && cDigits <= 2)
-    {
-        sz[0] = szHex[u >> 4];
-        sz[1] = szHex[u & 0xf];
-        sz[2] = '\0';
-        cb = 2;
-    }
-    else if (u <= 0xffff && cDigits <= 4)
-    {
-        sz[0] = szHex[u >> 12];
-        sz[1] = szHex[(u >> 8) & 0xf];
-        sz[2] = szHex[(u >> 4) & 0xf];
-        sz[3] = szHex[u & 0xf];
-        sz[4] = '\0';
-        cb = 4;
-    }
-    else
-    {
-        sz[0] = szHex[u >> 28];
-        sz[1] = szHex[(u >> 24) & 0xf];
-        sz[2] = szHex[(u >> 20) & 0xf];
-        sz[3] = szHex[(u >> 16) & 0xf];
-        sz[4] = szHex[(u >> 12) & 0xf];
-        sz[5] = szHex[(u >>  8) & 0xf];
-        sz[6] = szHex[(u >>  4) & 0xf];
-        sz[7] = szHex[u & 0xf];
-        sz[8] = '\0';
-        cb = 8;
-    }
-    DosWrite(2, sz, cb, &cb);
-}
-
 static void __fmutex_deadlock(_fmutex *pSem, const char *pszMsg)
 {
-    ULONG ul;
-    static const char szMsg[] = "\r\n!!!deadlock!!! fmutex ";
-    DosWrite(2, szMsg, sizeof(szMsg) - 1, &ul);
-    if (pSem->pszDesc)
-        DosWrite(2, pSem->pszDesc, strlen(pSem->pszDesc), &ul);
-    if (pszMsg)
-    {
-        DosWrite(2, ": ", 2, &ul);
-        DosWrite(2, pszMsg, strlen(pszMsg), &ul);
-    }
-    static const char szMsg2[] = "\r\nOwner=0x";
-    DosWrite(2, szMsg2, sizeof(szMsg2) - 1, &ul);
-    __fmutex_deadlock_hex(pSem->Owner, 8);
-    static const char szMsg3[] = " Self=0x";
-    DosWrite(2, szMsg3, sizeof(szMsg3) - 1, &ul);
-    __fmutex_deadlock_hex(fibGetTidPid(), 8);
-    static const char szMsg4[] = " fs=0x";
-    DosWrite(2, szMsg4, sizeof(szMsg4) - 1, &ul);
-    __fmutex_deadlock_hex(pSem->fs, 2);
-    static const char szMsg5[] = "\r\n";
-    DosWrite(2, szMsg5, sizeof(szMsg5) - 1, &ul);
-
-    __asm__ __volatile__("movl $0xdead10cc, %%eax; movl $0xdead10cc, %%edx; movl %0, %%ecx; int $3" : : "m" (pSem) : "%eax", "%edx", "%ecx");
+    __libc_Back_panic(0, NULL,
+                      "fmutex deadlock: %s\n"
+                      "%x: Owner=%x Self=%x fs=%x flags=%x hev=%x\n"
+                      "            Desc=\"%s\"\n",
+                      pszMsg,
+                      pSem, pSem->Owner, fibGetTidPid(), pSem->fs, pSem->flags, pSem->hev,
+                      pSem->pszDesc);
 }
 
Index: trunk/src/emx/src/lib/sys/b_panic.c
===================================================================
--- trunk/src/emx/src/lib/sys/b_panic.c	(revision 2204)
+++ trunk/src/emx/src/lib/sys/b_panic.c	(revision 2204)
@@ -0,0 +1,432 @@
+/* $Id$ */
+/** @file
+ *
+ * LIBC SYS Backend - panic.
+ *
+ * Copyright (c) 2005 knut st. osmundsen <bird@anduin.net>
+ *
+ *
+ * This file is part of InnoTek LIBC.
+ *
+ * InnoTek LIBC is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * InnoTek LIBC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with InnoTek LIBC; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#define INCL_BASE
+#define INCL_ERRORS
+#define INCL_FSMACROS
+#define _GNU_SOURCE
+#include <string.h>
+#include <InnotekLIBC/backend.h>
+#include <InnotekLIBC/sharedpm.h>
+#define __LIBC_LOG_GROUP __LIBC_LOG_GRP_NOGROUP
+#include <InnotekLIBC/logstrict.h>
+#include <os2emx.h>
+
+
+/*******************************************************************************
+*   Defined Constants And Macros                                               *
+*******************************************************************************/
+/** OS/2 default standard error handle. */
+#define HFILE_STDERR    ((HFILE)2)
+
+
+/**
+ * Calculates the length of a string.
+ * @returns String length in bytes.
+ * @param   psz     Pointer to the string.
+ */
+static size_t panicStrLen(const char *psz)
+{
+    const char *pszEnd = psz;
+    while (*pszEnd)
+        pszEnd++;
+    return pszEnd - psz;
+}
+
+/**
+ * Compare and advance if found.
+ *
+ * @returns 1 if match.
+ * @returns 0 if no match.
+ */
+static int panicStrICmp(const char **ppsz, const char *pszLower, const char *pszUpper)
+{
+    const char *psz = *ppsz;
+    while (*psz == *pszLower || *psz == *pszUpper)
+    {
+        psz++;
+        pszUpper++;
+        if (!*pszUpper)
+        {
+            *ppsz = psz;
+            return 1;
+        }
+        pszLower++;
+    }
+    return 0;
+}
+
+
+/**
+ * Termination time hex formatter.
+ *
+ * @returns number of bytes formatted.
+ * @param   pszBuf  Where to store the formatted number.
+ * @param   u       Number to format.
+ * @param   cDigits Minimum number of digits in the output. Use 0 for whatever fits.
+ */
+static int panicHex(char *pszBuf, unsigned u, unsigned cDigits)
+{
+    static const char szHex[17] = "0123456789abcdef";
+    if (u <= 0xf && cDigits <= 1)
+    {
+        pszBuf[0] = szHex[u & 0xf];
+        pszBuf[1] = '\0';
+        return 1;
+    }
+    if (u <= 0xff && cDigits <= 2)
+    {
+        pszBuf[0] = szHex[u >> 4];
+        pszBuf[1] = szHex[u & 0xf];
+        pszBuf[2] = '\0';
+        return 2;
+    }
+    else if (u <= 0xffff && cDigits <= 4)
+    {
+        pszBuf[0] = szHex[u >> 12];
+        pszBuf[1] = szHex[(u >> 8) & 0xf];
+        pszBuf[2] = szHex[(u >> 4) & 0xf];
+        pszBuf[3] = szHex[u & 0xf];
+        pszBuf[4] = '\0';
+        return 4;
+    }
+    else
+    {
+        pszBuf[0] = szHex[u >> 28];
+        pszBuf[1] = szHex[(u >> 24) & 0xf];
+        pszBuf[2] = szHex[(u >> 20) & 0xf];
+        pszBuf[3] = szHex[(u >> 16) & 0xf];
+        pszBuf[4] = szHex[(u >> 12) & 0xf];
+        pszBuf[5] = szHex[(u >>  8) & 0xf];
+        pszBuf[6] = szHex[(u >>  4) & 0xf];
+        pszBuf[7] = szHex[u & 0xf];
+        pszBuf[8] = '\0';
+        return 8;
+    }
+}
+
+
+/**
+ * Print a panic message and dump/kill the process.
+ *
+ * @param   fFlags      A combination of the __LIBC_PANIC_* defines.
+ * @param   pvCtx       Pointer to a context record if available. This is a PCONTEXTRECORD.
+ * @param   pszFormat   User message which may contain %s and %x.
+ * @param   ...         String pointers and unsigned intergers as specified by the %s and %x in pszFormat.
+ */
+void __libc_Back_panic(unsigned fFlags, void *pvCtx, const char *pszFormat, ...)
+{
+    va_list args;
+    va_start(args, pszFormat);
+    __libc_Back_panicV(fFlags, pvCtx, pszFormat, args);
+    va_end(args);
+}
+
+
+/**
+ * Print a panic message and dump/kill the process.
+ *
+ * @param   fFlags      A combination of the __LIBC_PANIC_* defines.
+ * @param   pvCtx       Pointer to a context record if available. This is a PCONTEXTRECORD.
+ * @param   pszFormat   User message which may contain %s and %x.
+ * @param   args        String pointers and unsigned intergers as specified by the %s and %x in pszFormat.
+ */
+void __libc_Back_panicV(unsigned fFlags, void *pvCtx, const char *pszFormat, va_list args)
+{
+    LIBCLOG_ENTER("fFlags=%#x pvCtx=%p pszFormat=%p:{%s}\n", fFlags, pvCtx, (void *)pszFormat, args);
+
+    /*
+     * First, terminate the exception handler chain to avoid recursive trouble.
+     */
+    FS_VAR();
+    FS_SAVE_LOAD();
+    PTIB pTib;
+    PPIB pPib;
+    DosGetInfoBlocks(&pTib, &pPib);
+    pTib->tib_pexchain = END_OF_CHAIN;
+
+    /*
+     * Set the exit reason in SPM.
+     */
+    if (!(fFlags & __LIBC_PANIC_NO_SPM_TERM))
+        __libc_spmTerm(__LIBC_EXIT_REASON_KILL, 127);
+
+    /*
+     * Get the panic config.
+     */
+    BOOL fQuiet = FALSE;
+    BOOL fVerbose = TRUE;
+    BOOL fBreakpoint = FALSE;
+    BOOL fDumpProcess = TRUE;
+    const char *pszPanicCfg = NULL;
+    int rc = DosScanEnv((PCSZ)"LIBC_PANIC", (PSZ *)(void *)&pszPanicCfg);
+    if (!rc && pszPanicCfg && strnlen(pszPanicCfg, 512) < 512)
+    {
+        int c = 512;
+        while (c-- > 0 && *pszPanicCfg)
+        {
+            if (panicStrICmp(&pszPanicCfg, "quiet", "QUIET"))
+                fQuiet = TRUE;
+            //else if (panicStrICmp(&pszPanicCfg, "noquiet", "NOQUIET"))
+            //    fQuiet = FALSE;
+            else if (panicStrICmp(&pszPanicCfg, "terse", "TERSE"))
+                fVerbose = FALSE;
+            //else if (panicStrICmp(&pszPanicCfg, "verbose", "VERBOSE"))
+            //    fVerbose = TRUE;
+            else if (panicStrICmp(&pszPanicCfg, "breakpoint", "BREAKPOINT"))
+                fBreakpoint = FALSE;
+            //else if (panicStrICmp(&pszPanicCfg, "dump", "DUMP"))
+            //    fDumpProcess = TRUE;
+            else if (panicStrICmp(&pszPanicCfg, "nodump", "NODUMP"))
+                fDumpProcess = FALSE;
+            else
+                pszPanicCfg++;
+        }
+    }
+
+    ULONG   cb;
+    char    szHexNum[12];
+    if (!fQuiet)
+    {
+        /*
+         * Write user message to stderr.
+         */
+#define PRINT_CHAR(ch)  DosWrite(HFILE_STDERR, &ch,      1,                                    &cb)
+#define PRINT_C(msg)    DosWrite(HFILE_STDERR, msg,      sizeof(msg) - 1,                      &cb)
+#define PRINT_P(msg)    DosWrite(HFILE_STDERR, msg,      panicStrLen(msg),           &cb)
+#define PRINT_H(hex)    DosWrite(HFILE_STDERR, szHexNum, panicHex(szHexNum, hex, 0), &cb)
+#define PRINT_H16(hex)  DosWrite(HFILE_STDERR, szHexNum, panicHex(szHexNum, hex, 4), &cb)
+#define PRINT_H32(hex)  DosWrite(HFILE_STDERR, szHexNum, panicHex(szHexNum, hex, 8), &cb)
+        if (!(fFlags & __LIBC_PANIC_SIGNAL) && fVerbose)
+            PRINT_C("\r\nLIBC PANIC!!\r\n");
+        else
+            PRINT_C("\r\n");
+        char ch;
+        while ((ch = *pszFormat++) != '\0')
+        {
+            switch (ch)
+            {
+                case '\n':
+                    PRINT_C("\r\n");
+                    break;
+                case '\r':
+                    break;
+                case '%':
+                    ch = *pszFormat++;
+                    switch (ch)
+                    {
+                        /* string */
+                        case 's':
+                        {
+                            const char *psz = va_arg(args, const char *);
+                            if ((uintptr_t)psz >= 0x10000 && (uintptr_t)psz < 0xe0000000)
+                                PRINT_P(psz);
+                            else if (!psz)
+                                PRINT_C("<null>");
+                            else
+                            {
+                                PRINT_C("<bogus string ptr 0x");
+                                PRINT_H((uintptr_t)psz);
+                                PRINT_C(">");
+                            }
+                            break;
+                        }
+
+                        /* it's all hex to me */
+                        case 'd':
+                        case 'x':
+                        case 'u':
+                        {
+                            unsigned u = va_arg(args, unsigned);
+                            PRINT_C("0x");
+                            PRINT_H(u);
+                            break;
+                        }
+
+                        case '%':
+                            PRINT_C("%");
+                            break;
+
+                        default:
+                        {
+                            PRINT_C("<Unknown format %");
+                            PRINT_CHAR(ch);
+                            PRINT_C(" arg 0x");
+                            unsigned u = va_arg(args, unsigned);
+                            PRINT_H(u);
+                            PRINT_C(">");
+                            break;
+                        }
+                    }
+                    break;
+
+                default:
+                    PRINT_CHAR(ch);
+                    break;
+            }
+        } /* print loop */
+
+        if (fVerbose)
+        {
+            /*
+             * Write generic message to stderr.
+             */
+
+            /* pid, tid and stuff */
+            PRINT_C("pid=0x");   PRINT_H16(pPib->pib_ulpid);
+            PRINT_C(" ppid=0x"); PRINT_H16(pPib->pib_ulppid);
+            PRINT_C(" tid=0x");  PRINT_H16(pTib->tib_ptib2->tib2_ultid);
+            PRINT_C(" slot=0x"); PRINT_H16(pTib->tib_ordinal);
+            PRINT_C(" pri=0x");  PRINT_H16(pTib->tib_ptib2->tib2_ulpri);
+            PRINT_C(" mc=0x");   PRINT_H16(pTib->tib_ptib2->tib2_usMCCount);
+
+            /* executable name. */
+            static char szExeName[CCHMAXPATH];
+            if (!DosQueryModuleName(pPib->pib_hmte, sizeof(szExeName), &szExeName[0]))
+            {
+                szExeName[CCHMAXPATH - 1] = '\0';
+                PRINT_C("\r\n");
+                PRINT_P(szExeName);
+            }
+
+            /*
+             * Context dump
+             */
+            if (pvCtx)
+            {
+                PCONTEXTRECORD pCtx = (PCONTEXTRECORD)pvCtx;
+
+                /* the module name */
+                if (pCtx->ctx_RegEip >= 0x10000)
+                {
+                    HMODULE hmod;
+                    ULONG iObj = 0;
+                    ULONG offObj = 0;
+                    if (!DosQueryModFromEIP(&hmod, &iObj, sizeof(szExeName), szExeName, &offObj, pCtx->ctx_RegEip))
+                    {
+                        PRINT_C("\r\n");
+                        PRINT_P(szExeName);
+                        PRINT_C(" ");
+                        PRINT_H(iObj);
+                        PRINT_C(":");
+                        PRINT_H32(offObj);
+
+                    }
+                }
+
+                /* registers */
+                PRINT_C("\r\ncs:eip=");
+                PRINT_H16(pCtx->ctx_SegCs);
+                PRINT_C(":");
+                PRINT_H32(pCtx->ctx_RegEip);
+
+                PRINT_C("      ss:esp=");
+                PRINT_H16(pCtx->ctx_SegSs);
+                PRINT_C(":");
+                PRINT_H32(pCtx->ctx_RegEsp);
+
+                PRINT_C("      ebp=");
+                PRINT_H32(pCtx->ctx_RegEbp);
+
+                PRINT_C("\r\n ds=");
+                PRINT_H16(pCtx->ctx_SegDs);
+                PRINT_C("      es=");
+                PRINT_H16(pCtx->ctx_SegEs);
+                PRINT_C("      fs=");
+                PRINT_H16(pCtx->ctx_SegFs);
+                PRINT_C("      gs=");
+                PRINT_H16(pCtx->ctx_SegGs);
+                PRINT_C("     efl=");
+                PRINT_H32(pCtx->ctx_EFlags);
+
+                PRINT_C("\r\neax=");
+                PRINT_H32(pCtx->ctx_RegEax);
+                PRINT_C(" ebx=");
+                PRINT_H32(pCtx->ctx_RegEbx);
+                PRINT_C(" ecx=");
+                PRINT_H32(pCtx->ctx_RegEcx);
+                PRINT_C(" edx=");
+                PRINT_H32(pCtx->ctx_RegEdx);
+                PRINT_C(" edi=");
+                PRINT_H32(pCtx->ctx_RegEdi);
+                PRINT_C(" esi=");
+                PRINT_H32(pCtx->ctx_RegEsi);
+                /** @todo fpu */
+            }
+
+            /* final newline */
+            PRINT_C("\r\n");
+        }
+    } /* !QUIET */
+
+    /*
+     * Breakpoint
+     */
+    if (fBreakpoint)
+    {
+        LIBCLOG_MSG("Breakpoint\n");
+        __asm__ __volatile__ ("int3\n\t"
+                              "nop\n\t");
+    }
+
+    /*
+     * Attempt dumping the process.
+     */
+    if (fDumpProcess)
+    {
+        LIBCLOG_MSG("Calling DosDumpProcess()\n");
+        rc = DosDumpProcess(DDP_PERFORMPROCDUMP, 0, 0);
+        if (!fQuiet)
+        {
+            if (!rc)
+                PRINT_C("Process have been dumped\r\n");
+            else if (rc == 0x00011176 || rc == ERROR_INVALID_PARAMETER) /* first is actual, 2nd is docs */
+                PRINT_C("Process dumping was disabled, use DUMPPROC to enable it.\r\n");
+            else
+            {
+                PRINT_C("DosDumpProcess failed with rc=0x");
+                PRINT_H(rc);
+                PRINT_C("\r\n");
+            }
+        }
+    }
+
+    /*
+     * Terminate the process.
+     */
+    LIBCLOG_MSG("Calling DosKillProcess()\n");
+    for (;;)
+    {
+        DosKillProcess(DKP_PROCESS, pPib->pib_ulpid);
+        DosExit(EXIT_PROCESS, 127);
+    }
+}
+
Index: trunk/src/emx/src/lib/sys/libcfork.c
===================================================================
--- trunk/src/emx/src/lib/sys/libcfork.c	(revision 2203)
+++ trunk/src/emx/src/lib/sys/libcfork.c	(revision 2204)
@@ -155,5 +155,5 @@
 static int                  forkBthCallbacksCall(__LIBC_PFORKCALLBACK *papCallbacks, __LIBC_PFORKHANDLE pForkHandle, __LIBC_FORKOP enmOperation);
 static void                 forkBthDumpMemFlags(void *pv);
-static void                 forkChlFatalError(__LIBC_PFORKHANDLE pForkHandle, int rc) __attribute__((__noreturn__));
+static void                 forkChlFatalError(__LIBC_PFORKHANDLE pForkHandle, int rc, void *pvCtx) __attribute__((__noreturn__));
 static ULONG _System        forkChlExceptionHandler(PEXCEPTIONREPORTRECORD       pXcptRepRec,
                                                     PEXCEPTIONREGISTRATIONRECORD pXcptRegRec,
@@ -1061,5 +1061,5 @@
                            PAG_READ | PAG_WRITE | PAG_COMMIT);
         if (rc)
-            forkChlFatalError(pForkHandle, -__libc_native2errno(rc));
+            forkChlFatalError(pForkHandle, -__libc_native2errno(rc), NULL);
     }
     else
@@ -1118,5 +1118,5 @@
     rc = forkBthBufferGiveWaitNext(pForkHandle, __LIBC_FORK_CTX_CHILD);
     if (rc < 0)
-        forkChlFatalError(pForkHandle, rc);
+        forkChlFatalError(pForkHandle, rc, NULL);
 
     /*
@@ -1130,5 +1130,5 @@
     LIBC_ASSERTM(pModules, "No fork modules in child process!!!!\n");
     if (!pModules)
-        forkChlFatalError(pForkHandle, -EDOOFUS);
+        forkChlFatalError(pForkHandle, -EDOOFUS, NULL);
 
     /*
@@ -1137,5 +1137,5 @@
     rc = forkChlRunForkChild(pForkHandle, pModules);
     if (rc < 0)
-        forkChlFatalError(pForkHandle, rc);
+        forkChlFatalError(pForkHandle, rc, NULL);
 
 
@@ -2019,5 +2019,5 @@
                 rc = pHdr->u.Abort.err;
                 if (enmCtx == __LIBC_FORK_CTX_CHILD)
-                    forkChlFatalError(pForkHandle, rc);
+                    forkChlFatalError(pForkHandle, rc, NULL);
                 break;
 
@@ -2510,10 +2510,9 @@
  * @param   pForkHandle     Pointer to fork handle.
  * @param   rc              The return code (negative) which caused the failure.
- */
-void                 forkChlFatalError(__LIBC_PFORKHANDLE pForkHandle, int rc)
-{
-    LIBCLOG_ENTER("pForkHandle=%p rc=%d\n", (void *)pForkHandle, rc);
-    static const char   szMsg[] = "LIBC Error: Child aborting fork()!\r\n";
-    ULONG               cbWritten;
+ * @param   pvCtx           Context if available.
+ */
+void                 forkChlFatalError(__LIBC_PFORKHANDLE pForkHandle, int rc, void *pvCtx)
+{
+    LIBCLOG_ENTER("pForkHandle=%p rc=%d pvCtx=%p\n", (void *)pForkHandle, rc, pvCtx);
     PID                 pid;
     TID                 tid;
@@ -2569,10 +2568,5 @@
      * Exit process.
      */
-    DosWrite(2, szMsg, sizeof(szMsg) - 1, &cbWritten);
-    for (;;)
-    {
-        LIBCLOG_MSG("Calling DosExit(EXIT_PROCESS, 0xffff)...\n");
-        DosExit(EXIT_PROCESS, /*fixme*/0xffff);
-    }
+    __libc_Back_panic(__LIBC_PANIC_NO_SPM_TERM, pvCtx, "LIBC fork: Child aborting fork()! rc=%x\n", rc);
 }
 
@@ -2755,5 +2749,5 @@
             {
                 DosPostEventSem(pForkHandle->hevParent);
-                forkChlFatalError(pForkHandle, -EINTR);
+                forkChlFatalError(pForkHandle, -EINTR, pCtx);
             }
             break;
Index: trunk/src/emx/src/lib/sys/sharedpm.c
===================================================================
--- trunk/src/emx/src/lib/sys/sharedpm.c	(revision 2203)
+++ trunk/src/emx/src/lib/sys/sharedpm.c	(revision 2204)
@@ -3805,5 +3805,5 @@
     {
         /*
-         * This isn't wrong just unlikely and must be ignored!
+         * This isn't wrong, just unlikely and must be ignored!
          */
         case XCPT_ASYNC_PROCESS_TERMINATE:
@@ -3891,4 +3891,12 @@
     spmCheck(1, 1);
 #endif
+    __libc_Back_panic(__LIBC_PANIC_NO_SPM_TERM, pCtx,
+                      "SPM Exception %x (%x,%x,%x,%x)%s\n",
+                      pRepRec->ExceptionNum,
+                      pRepRec->ExceptionInfo[0],
+                      pRepRec->ExceptionInfo[1],
+                      pRepRec->ExceptionInfo[2],
+                      pRepRec->ExceptionInfo[3],
+                      !rc && pPib->pib_ulpid == pid && pTib->tib_ptib2->tib2_ultid == tid ? " - Owner of the mutex" : "");
     return XCPT_CONTINUE_SEARCH;
 }
Index: trunk/src/emx/src/lib/sys/signals.c
===================================================================
--- trunk/src/emx/src/lib/sys/signals.c	(revision 2203)
+++ trunk/src/emx/src/lib/sys/signals.c	(revision 2204)
@@ -1893,5 +1893,5 @@
 
                 /*
-                 * Kill process / dump core (no cores for LIBC!).
+                 * Kill process / dump core.
                  */
                 case SPA_NEXT_KILL:
@@ -2078,67 +2078,4 @@
 
 /**
- * Calculates the length of a string.
- * @returns String length in bytes.
- * @param   psz     Pointer to the string.
- */
-static size_t signalTerminateStrLen(const char *psz)
-{
-    const char *pszEnd = psz;
-    while (*pszEnd)
-        pszEnd++;
-    return pszEnd - psz;
-}
-
-
-/**
- * Termination time hex formatter.
- *
- * @returns number of bytes formatted.
- * @param   pszBuf  Where to store the formatted number.
- * @param   u       Number to format.
- * @param   cDigits Minimum number of digits in the output. Use 0 for whatever fits.
- */
-static int signalTerminateHex(char *pszBuf, unsigned u, unsigned cDigits)
-{
-    static const char szHex[17] = "0123456789abcdef";
-    if (u <= 0xf && cDigits <= 1)
-    {
-        pszBuf[0] = szHex[u & 0xf];
-        pszBuf[1] = '\0';
-        return 1;
-    }
-    if (u <= 0xff && cDigits <= 2)
-    {
-        pszBuf[0] = szHex[u >> 4];
-        pszBuf[1] = szHex[u & 0xf];
-        pszBuf[2] = '\0';
-        return 2;
-    }
-    else if (u <= 0xffff && cDigits <= 4)
-    {
-        pszBuf[0] = szHex[u >> 12];
-        pszBuf[1] = szHex[(u >> 8) & 0xf];
-        pszBuf[2] = szHex[(u >> 4) & 0xf];
-        pszBuf[3] = szHex[u & 0xf];
-        pszBuf[4] = '\0';
-        return 4;
-    }
-    else
-    {
-        pszBuf[0] = szHex[u >> 28];
-        pszBuf[1] = szHex[(u >> 24) & 0xf];
-        pszBuf[2] = szHex[(u >> 20) & 0xf];
-        pszBuf[3] = szHex[(u >> 16) & 0xf];
-        pszBuf[4] = szHex[(u >> 12) & 0xf];
-        pszBuf[5] = szHex[(u >>  8) & 0xf];
-        pszBuf[6] = szHex[(u >>  4) & 0xf];
-        pszBuf[7] = szHex[u & 0xf];
-        pszBuf[8] = '\0';
-        return 8;
-    }
-}
-
-
-/**
  * Cause immediate process termination because of the given signal.
  *
@@ -2150,4 +2087,5 @@
 {
     LIBCLOG_ENTER("iSignalNo=%d\n", iSignalNo);
+
     /*
      * Set the exit reason in SPM.
@@ -2156,104 +2094,13 @@
 
     /*
-     * Before we go crazy here, let's release the semaphore.
-     *
-     * If possible we'll stay in the must complete section to
-     * be sure we get to the exit. If not we'll have to mess with
-     * exception handlers and such now.
-     */
-    //if (__libc_back_signalSemIsOwner())
-    //    DosReleaseMutexSem(ghmtxSignals);
-
-    /*
-     * Terminate the exception handler chain to avoid recursive trouble.
-     */
-    FS_VAR();
-    FS_SAVE_LOAD();
-    PTIB pTib;
-    PPIB pPib;
-    DosGetInfoBlocks(&pTib, &pPib);
-    pTib->tib_pexchain = END_OF_CHAIN;
-
-    /*
-     * Write message to stderr.
-     */
-    ULONG   cb;
-    char szHexNum[12];
-#define SIG_PRINT_C(msg)  DosWrite(HFILE_STDERR, msg, sizeof(msg) - 1, &cb)
-#define SIG_PRINT_P(msg)  DosWrite(HFILE_STDERR, msg, signalTerminateStrLen(msg), &cb)
-#define SIG_PRINT_H(hex)  DosWrite(HFILE_STDERR, szHexNum, signalTerminateHex(szHexNum, hex, 0), &cb)
-#define SIG_PRINT_H16(hex)  DosWrite(HFILE_STDERR, szHexNum, signalTerminateHex(szHexNum, hex, 4), &cb)
-#define SIG_PRINT_H32(hex)  DosWrite(HFILE_STDERR, szHexNum, signalTerminateHex(szHexNum, hex, 8), &cb)
-    if (iSignalNo == SIGABRT)
-        SIG_PRINT_C("\n\rAbnormal program termination");
+     * Panic
+     */
+    PCONTEXTRECORD pCtx = pvXcptParams ? pCtx = ((PEXCPTPARAMS)pvXcptParams)->pCtx : NULL;
+    if (iSignalNo < sizeof(gaszSignalNames) / sizeof(gaszSignalNames[0]))
+        __libc_Back_panic(__LIBC_PANIC_SIGNAL | __LIBC_PANIC_NO_SPM_TERM, pCtx, "Killed by %s\n", gaszSignalNames[iSignalNo]);
     else
-    {
-        SIG_PRINT_C("\n\rProcess terminated by ");
-
-        if (iSignalNo < sizeof(gaszSignalNames) / sizeof(gaszSignalNames[0]))
-            SIG_PRINT_P(gaszSignalNames[iSignalNo]);
-        else
-        {
-            SIG_PRINT_C("unknown signal ");
-            SIG_PRINT_H(iSignalNo);
-        }
-    }
-
-    /* pid */
-    SIG_PRINT_C(" - pid=0x"); SIG_PRINT_H16(pPib->pib_ulpid);
-
-    /* tid */
-    SIG_PRINT_C(" - tid=0x"); SIG_PRINT_H16(pTib->tib_ptib2->tib2_ultid);
-
-    /* executable name. */
-    static char szExeName[CCHMAXPATH];
-    if (!DosQueryModuleName(pPib->pib_hmte, sizeof(szExeName), &szExeName[0]))
-    {
-        static const char szHypen[] = " - ";
-        DosWrite(HFILE_STDERR, szHypen, sizeof(szHypen) - 1, &cb);
-
-        for (cb = 0; szExeName[cb];)
-            cb++;
-        DosWrite(HFILE_STDERR, szExeName, cb, &cb);
-    }
-
-    /* eip */
-    PCONTEXTRECORD pCtx;
-    if (    pvXcptParams
-        &&  (pCtx = ((PEXCPTPARAMS)pvXcptParams)->pCtx))
-    {
-        SIG_PRINT_C("\r\ncs:eip=");
-        SIG_PRINT_H16(pCtx->ctx_SegCs);
-        SIG_PRINT_C(":");
-        SIG_PRINT_H32(pCtx->ctx_RegEip);
-        if (pCtx->ctx_RegEip >= 0x10000)
-        {
-            HMODULE hmod;
-            ULONG iObj = 0;
-            ULONG offObj = 0;
-            if (!DosQueryModFromEIP(&hmod, &iObj, sizeof(szExeName), szExeName, &offObj, pCtx->ctx_RegEip))
-            {
-                SIG_PRINT_C(" - ");
-                SIG_PRINT_H(iObj);
-                SIG_PRINT_C(":");
-                SIG_PRINT_H32(offObj);
-                SIG_PRINT_C(" ");
-                SIG_PRINT_P(szExeName);
-            }
-        }
-    }
-
-    /* final newline */
-    SIG_PRINT_C("\r\n");
-
-    /*
-     * Terminate the process.
-     */
-    LIBCLOG_MSG("Calling DosKillProcess()\n");
-    for (;;)
-    {
-        DosKillProcess(DKP_PROCESS, fibGetPid());
-        DosExit(EXIT_PROCESS, 127);
-    }
+        __libc_Back_panic(__LIBC_PANIC_SIGNAL | __LIBC_PANIC_NO_SPM_TERM, pCtx, "Killed by unknown signal %d\n", iSignalNo);
+    LIBCLOG_MSG("panic failed\n"); /* shuts up gcc */
+    asm("int3");
 }
 
