Index: trunk/src/tools/qsysxcpt_pm.cpp
===================================================================
--- trunk/src/tools/qsysxcpt_pm.cpp	(revision 145)
+++ trunk/src/tools/qsysxcpt_pm.cpp	(revision 146)
@@ -64,6 +64,7 @@
     
     - must be instantiated on the stack of the main thread only
-    - must be instantiated before a QAplication instance is created
+    - should be instantiated before a QAplication instance is created
       (does nothing otherwise)
+    - note that callback can be called on any thread
 */
 
@@ -252,36 +253,27 @@
     APIRET  arc = NO_ERROR;
     HMODULE hMod = NULLHANDLE;
-    char    szMod[CCHMAXPATH] = "unknown";
+    char   szMod[CCHMAXPATH] = "";
     ULONG   ulObject = 0,
             ulOffset = 0;
 
-    if ( ulPointer )
-        fprintf( file, "     <Frame pointer=\"%08lX\">\n", ulPointer );
+    if (ulPointer)
+        fprintf (file, "     <Frame pointer=\"%08lX\">\n", ulPointer);
     else
-        fprintf( file, "     <Frame pointer=\"current\">\n" );
-
-    fprintf( file, "      <Location address=\"%08lX\">\n", ulAddress );
-    
-    arc = DosQueryModFromEIP( &hMod, &ulObject,
-                              sizeof(szMod), szMod, &ulOffset,
-                              ulAddress );
+        fprintf (file, "     <Frame pointer=\"current\">\n");
+
+    fprintf (file, "      <Location address=\"%08lX\">\n", ulAddress);
+    
+    arc = DosQueryModFromEIP (&hMod, &ulObject,
+                              sizeof (szMod), szMod, &ulOffset,
+                              ulAddress);
 
     if (arc != NO_ERROR)
-        qt_excWriteErrorMsg( file, 7, "%s: DosQueryModFromEIP returned %lu",
-                             szMod, arc );
+        qt_excWriteErrorMsg (file, 7, "%s: DosQueryModFromEIP returned %lu",
+                             szMod, arc);
     else
     {
-        DosQueryModuleName( hMod, sizeof(szMod), szMod );
-        fprintf( file, "       <Module ID=\"%04lX\" name=\"", hMod );
-        qt_excEscapeString( file, szMod ); 
-        fprintf( file, "\" \n"
-                       "               segment=\"%04lX\" offset=\"%08lX\"/>\n",
-                 ulObject + 1, ulOffset ); 
-/// @todo (r=dmik) use .DBG and .SYM files to get symbols
-//  (see debug.h and debug.c from the xwphelpers package) 
-//        dbgPrintStackFrame(file,
-//                           szFullName,
-//                           ulObject,
-//                           ulOffset);
+        fprintf (file, "       <Module ID=\"%04lX\" segment=\"%04lX\" "
+                                      "offset=\"%08lX\"/>\n",
+                 hMod, ulObject + 1, ulOffset); 
     }
 
@@ -293,46 +285,48 @@
         ULONG ulFlags = 0;
         APIRET arc = NO_ERROR;
-        while ( 1 )
-        {
-            arc = DosQueryMem( (void *) (ULONG) pch, &ulCount, &ulFlags );
-            if ( arc == NO_ERROR )
-            {
-                if ( ulCount >= enmDelta * 2 )
+        while (1)
+        {
+            arc = DosQueryMem ((void *) (ULONG) pch, &ulCount, &ulFlags);
+            if (arc == NO_ERROR)
+            {
+                if (ulCount >= enmDelta * 2)
                     break;
-                if ( pch + ulCount <= (UCHAR *) ulAddress )
-                {   // ulAddress is outside the pch object
+                if (pch + ulCount <= (UCHAR *) ulAddress)
+                {
+                    /* ulAddress is outside the pch object */
                     pch += ulCount;
                     ulCount = enmDelta * 2 - ulCount;
                 }
                 else
-                {   // ulAddress is within the pch object
+                {
+                    /* ulAddress is within the pch object */
                     pchEnd = pch += ulCount;
                     break;
                 }
             }
-            else if ( arc == ERROR_INVALID_ADDRESS )
-            {
-                if ( ((ULONG) pch) & 0xFFFFF000 == ulAddress & 0xFFFFF000 )
-                    break; // the same page, ulAddress inaccessible
+            else if (arc == ERROR_INVALID_ADDRESS)
+            {
+                if (((ULONG) pch) & 0xFFFFF000 == ulAddress & 0xFFFFF000)
+                    break; /* the same page, ulAddress inaccessible */
                 pch = (UCHAR *) (ulAddress & 0xFFFFF000);
             }
         }
-        fprintf( file, "       <Dump address=\"%08lX\">\n        ", pch );
-        if ( arc == NO_ERROR &&
-             ulFlags & (PAG_COMMIT|PAG_READ) == (PAG_COMMIT | PAG_READ) )
-        {
-            for ( ; pch < pchEnd; ++pch )
-                fprintf( file, "%02lX%c", (ULONG) *pch,
-                         ulAddress - (ULONG) pch == 1 ? '-' : ' ' );
-            fprintf( file, "\n" );
+        fprintf (file, "       <Dump address=\"%08lX\">\n        ", pch);
+        if (arc == NO_ERROR &&
+            ulFlags & (PAG_COMMIT|PAG_READ) == (PAG_COMMIT | PAG_READ))
+        {
+            for (; pch < pchEnd; ++pch)
+                fprintf (file, "%02lX%c", (ULONG) *pch,
+                         ulAddress - (ULONG) pch == 1 ? '-' : ' ');
+            fprintf (file, "\n");
         }
         else
-            qt_excWriteErrorMsg( file, 0, "%08lX: DosQueryMem returned %lu"
-                                 "and flags %08lX", pch, arc, ulFlags );
-        fprintf( file, "       </Dump>\n" );
-    }
-    
-    fprintf( file, "      </Location>\n"
-                   "     </Frame>\n" );
+            qt_excWriteErrorMsg (file, 0, "%08lX: DosQueryMem returned %lu"
+                                 "and flags %08lX", pch, arc, ulFlags);
+        fprintf (file, "       </Dump>\n");
+    }
+    
+    fprintf (file, "      </Location>\n"
+                   "     </Frame>\n");
 }
 
@@ -340,138 +334,284 @@
     Walks the stack and writes information about stack frames.
 */
-static void qt_excWriteStackFrames( FILE *file, PTIB ptib,
-                                    PCONTEXTRECORD pContextRec )
+static void qt_excWriteStackFrames (FILE *file, PTIB ptib,
+                                    PCONTEXTRECORD pContextRec)
 {
     PULONG pulStackWord = 0;
 
-    fprintf( file, "    <Frames>\n" );
-
-    // first the trapping address itself
-    qt_excWriteStackFrame( file, 0, pContextRec->ctx_RegEip );
+    fprintf (file, "    <Frames>\n");
+
+    /* first the trapping address itself */
+    qt_excWriteStackFrame (file, 0, pContextRec->ctx_RegEip);
 
     pulStackWord = (PULONG) pContextRec->ctx_RegEbp;
     
-    while (    pulStackWord != 0
-            && pulStackWord < (PULONG) ptib->tib_pstacklimit )
-    {
-        if ( ((ULONG) pulStackWord & 0x00000FFF) == 0x00000000 )
-        {
-            // we're on a page boundary: check access
+    while (   pulStackWord != 0
+           && pulStackWord < (PULONG) ptib->tib_pstacklimit)
+    {
+        if (((ULONG) pulStackWord & 0x00000FFF) == 0x00000000)
+        {
+            /* we're on a page boundary: check access */
             ULONG ulCount = 0x1000;
             ULONG ulFlags = 0;
-            APIRET arc = DosQueryMem( (void *) pulStackWord,
-                                      &ulCount, &ulFlags );
-            if (    (arc != NO_ERROR)
-                 || (   arc == NO_ERROR
-                     && (ulFlags & (PAG_COMMIT|PAG_READ))
-                         != (PAG_COMMIT|PAG_READ)) )
-            {
-                fprintf( file, "     <Frame pointer=\"%08lX\">\n",
-                         (ULONG) pulStackWord );
-                qt_excWriteErrorMsg( file, 6, "DosQueryMem returned %lu "
-                                     "and flags %08lX", arc, ulFlags );
-                fprintf( file, "     </Frame>\n" );
+            APIRET arc = DosQueryMem ((void *) pulStackWord,
+                                      &ulCount, &ulFlags);
+            if (   (arc != NO_ERROR)
+                || (   arc == NO_ERROR
+                    && (ulFlags & (PAG_COMMIT|PAG_READ))
+                        != (PAG_COMMIT|PAG_READ)))
+            {
+                fprintf (file, "     <Frame pointer=\"%08lX\">\n",
+                         (ULONG) pulStackWord);
+                qt_excWriteErrorMsg (file, 6, "DosQueryMem returned %lu "
+                                     "and flags %08lX", arc, ulFlags);
+                fprintf (file, "     </Frame>\n");
                 pulStackWord += 0x1000;
-                continue; // while
-            }
-        }
-
-        qt_excWriteStackFrame( file, (ULONG) pulStackWord, *(pulStackWord + 1) );
+                continue; /* while */
+            }
+        }
+
+        qt_excWriteStackFrame (file, (ULONG) pulStackWord, *(pulStackWord + 1));
         pulStackWord = (PULONG) *(pulStackWord);
-    } // end while
-
-    fprintf( file, "    </Frames>\n" );
+    } /* end while */
+
+    fprintf (file, "    </Frames>\n");
 }
 
 /*! \internal
     Writes the thread information.
-*/
-static void qt_excWriteThreadInfo( FILE *file, PTIB ptib,
-                                   PEXCEPTIONREPORTRECORD pReportRec,
-                                   PCONTEXTRECORD pContextRec )
-{
-    ULONG       ul = 0;
-    ULONG       ulOldPriority = ~0;
-
-    // raise this thread's priority, because this
-    // might take some time
-    ulOldPriority = ptib->tib_ptib2->tib2_ulpri;
-    DosSetPriority( PRTYS_THREAD, PRTYC_REGULAR, PRTYD_MAXIMUM, 0 );
-
-    fprintf( file, "  <Thread ID=\"%04lX\" slot=\"%04lX\" "
-                             "priority=\"%04lX\" "
-                             "mc=\"%04lX\" mcf=\"%04lX\">\n",
-             ptib->tib_ptib2->tib2_ultid, ptib->tib_ordinal, ulOldPriority,
-             ptib->tib_ptib2->tib2_usMCCount, ptib->tib_ptib2->tib2_fMCForceFlag );
-
-    // *** generic exception info
-
-    fprintf( file,
-             "   <Exception type=\"%08lX\" flags=\"%08lX\" address=\"%08lX\">\n",
-             pReportRec->ExceptionNum, pReportRec->fHandlerFlags,
-             (ULONG) pReportRec->ExceptionAddress );
-    
-    for ( ul = 0; ul < pReportRec->cParameters;  ++ul )
-    {
-        fprintf( file, "    <Param value=\"%08lX\"/>\n",
-                 pReportRec->ExceptionInfo[ul] );
-    }
-
-    fprintf( file, "   </Exception>\n" );
-    
-    // *** registers
-
-    fprintf( file, "   <CPU>\n"
-                   "    <Registers>\n" );
-
-    if ( pContextRec->ContextFlags & CONTEXT_SEGMENTS )
-    {
-        qt_excWriteReg( file, "DS", pContextRec->ctx_SegDs, FALSE );
-        qt_excWriteReg( file, "ES", pContextRec->ctx_SegEs, FALSE );
-        qt_excWriteReg( file, "FS", pContextRec->ctx_SegFs, FALSE );
-        qt_excWriteReg( file, "GS", pContextRec->ctx_SegGs, FALSE );
-    }
-    
-    if ( pContextRec->ContextFlags & CONTEXT_INTEGER )
-    {
-        qt_excWriteReg( file, "EAX", pContextRec->ctx_RegEax );
-        qt_excWriteReg( file, "EBX", pContextRec->ctx_RegEbx );
-        qt_excWriteReg( file, "ECX", pContextRec->ctx_RegEcx );
-        qt_excWriteReg( file, "EDX", pContextRec->ctx_RegEdx );
-        qt_excWriteReg( file, "ESI", pContextRec->ctx_RegEsi );
-        qt_excWriteReg( file, "EDI", pContextRec->ctx_RegEdi );
-    }
-
-    if ( pContextRec->ContextFlags & CONTEXT_CONTROL )
-    {
-        qt_excWriteReg( file, "CS", pContextRec->ctx_SegCs, FALSE );
-        qt_excWriteReg( file, "EIP", pContextRec->ctx_RegEip );
-        qt_excWriteReg( file, "SS", pContextRec->ctx_SegSs, FALSE );
-        qt_excWriteReg( file, "ESP", pContextRec->ctx_RegEsp );
-        qt_excWriteReg( file, "EBP", pContextRec->ctx_RegEbp );
-        qt_excWriteReg( file, "EFLAGS", pContextRec->ctx_EFlags, FALSE );
-    }
-    
-    fprintf( file, "    </Registers>\n"
-                   "   </CPU>\n" );
-
-    // *** stack
-
-    fprintf( file, "   <Stack base=\"%08lX\" limit=\"%08lX\">\n",
+    If ptib is not NULL, the current thread's information is to be written.
+    If ptib is NULL, pThrdRec is guaranted not to be NULL.
+*/
+static void qt_excWriteThreadInfo (FILE *file, PTIB ptib, QSTREC *pThrdRec,
+                                   PCONTEXTRECORD pContextRec)
+{
+    if (ptib)
+    {
+        fprintf (file, "  <Thread ID=\"%04lX\" slot=\"%04lX\" "
+                                 "priority=\"%04lX\" ",
+                 ptib->tib_ptib2->tib2_ultid, ptib->tib_ordinal,
+                 ptib->tib_ptib2->tib2_ulpri);
+        if (pThrdRec)
+            fprintf (file, "state=\"%02lX\" ", (ULONG) pThrdRec->state);
+        fprintf (file, "mc=\"%04lX\" mcf=\"%04lX\">\n",
+                 ptib->tib_ptib2->tib2_usMCCount,
+                 ptib->tib_ptib2->tib2_fMCForceFlag);
+    }
+    else
+    {
+        fprintf (file, "  <Thread ID=\"%04lX\" slot=\"%04lX\" "
+                                 "priority=\"%04lX\" state=\"%02lX\">\n",
+                 pThrdRec->tid, pThrdRec->slot, pThrdRec->priority,
+                 pThrdRec->state);
+    }
+
+    /* *** registers */
+
+    fprintf (file, "   <CPU>\n"
+                   "    <Registers>\n");
+
+    if  (pContextRec->ContextFlags & CONTEXT_SEGMENTS)
+    {
+        qt_excWriteReg (file, "DS", pContextRec->ctx_SegDs, FALSE);
+        qt_excWriteReg (file, "ES", pContextRec->ctx_SegEs, FALSE);
+        qt_excWriteReg (file, "FS", pContextRec->ctx_SegFs, FALSE);
+        qt_excWriteReg (file, "GS", pContextRec->ctx_SegGs, FALSE);
+    }
+    
+    if  (pContextRec->ContextFlags & CONTEXT_INTEGER)
+    {
+        qt_excWriteReg (file, "EAX", pContextRec->ctx_RegEax);
+        qt_excWriteReg (file, "EBX", pContextRec->ctx_RegEbx);
+        qt_excWriteReg (file, "ECX", pContextRec->ctx_RegEcx);
+        qt_excWriteReg (file, "EDX", pContextRec->ctx_RegEdx);
+        qt_excWriteReg (file, "ESI", pContextRec->ctx_RegEsi);
+        qt_excWriteReg (file, "EDI", pContextRec->ctx_RegEdi);
+    }
+
+    if  (pContextRec->ContextFlags & CONTEXT_CONTROL)
+    {
+        qt_excWriteReg (file, "CS", pContextRec->ctx_SegCs, FALSE);
+        qt_excWriteReg (file, "EIP", pContextRec->ctx_RegEip);
+        qt_excWriteReg (file, "SS", pContextRec->ctx_SegSs, FALSE);
+        qt_excWriteReg (file, "ESP", pContextRec->ctx_RegEsp);
+        qt_excWriteReg (file, "EBP", pContextRec->ctx_RegEbp);
+        qt_excWriteReg (file, "EFLAGS", pContextRec->ctx_EFlags, FALSE);
+    }
+    
+    fprintf (file, "    </Registers>\n"
+                   "   </CPU>\n");
+
+    /* *** stack */
+
+    fprintf (file, "   <Stack base=\"%08lX\" limit=\"%08lX\">\n",
              (ULONG) ptib->tib_pstack,
-             (ULONG) ptib->tib_pstacklimit );
-    
-    if ( pContextRec->ContextFlags & CONTEXT_CONTROL )
-    {
-        qt_excWriteStackFrames( file, ptib, pContextRec );
+             (ULONG) ptib->tib_pstacklimit);
+    
+    if (pContextRec->ContextFlags & CONTEXT_CONTROL)
+    {
+        qt_excWriteStackFrames (file, ptib, pContextRec);
     }    
     
-    fprintf( file, "   </Stack>\n"
-                   "  </Thread>\n" );
-    
-    // reset old priority
-    DosSetPriority( PRTYS_THREAD, (ulOldPriority & 0x0F00) >> 8,
-                                  (UCHAR) ulOldPriority,
-                                  0 );
+    fprintf (file, "   </Stack>\n"
+                   "  </Thread>\n");
+}
+
+typedef struct _PROCESSINFO
+{
+    /* common values */
+    char *pszFullName;
+    char *pszBaseName;
+    /* direct info pointers */
+    PPIB ppib;
+    PTIB ptib;
+    BOOL bHaveSysState; /**< TRUE when both pProcRec and pLibRec are not NULL */ 
+    QSPREC *pProcRec;   /**< NULL when bHaveSysState is FALSE */
+    QSLREC *pLibRec;    /**< NULL when bHaveSysState is FALSE */
+} PROCESSINFO;
+
+/*! \internal
+    Writes module information to the log file.
+    \a ulOrigin is 1 (self), 2 (imported), or 3 (loaded). Other values are
+    ignored.
+*/
+static void qt_excWriteModule (FILE *file, USHORT hmte, char *pszName,
+                               ULONG ulOrigin = 0)
+{
+    static const char *apszOrigins[] = { "self", "imported", "loaded" };
+
+    fprintf (file, "   <Module ID=%\"%04lX\" name=\"", hmte);
+    qt_excEscapeString (file, pszName);
+    if (ulOrigin >= 1 && ulOrigin <= 3)
+        fprintf (file, "\"\n"
+                       "           origin=\"%s\"/>\n",
+                       apszOrigins [ulOrigin - 1]);
+    else
+        fprintf (file, "\"/>\n");
+}
+
+/*! \internal
+    Writes module and all its imports information to the log file.
+    \a ulOrigin is 1 (self), or 3 (loaded), other values are ignored.
+*/
+static void qt_excWriteModules (FILE *file, USHORT hmte, QSLREC *pFirstLibRec,
+                                ULONG ulOrigin)
+{
+    QSLREC *pLibRec = pFirstLibRec;
+    while (pLibRec)
+    {
+        if (pLibRec->hmte == hmte &&
+            pLibRec->pName /* not yet visited */)
+        {
+            qt_excWriteModule (file, hmte, (char *) pLibRec->pName, ulOrigin);
+            /* mark as visited */
+            pLibRec->pName = NULL;
+            /* go through imports */
+            if (pLibRec->ctImpMod)
+            {
+                USHORT *pHmte = (USHORT *) (pLibRec + 1);
+                for (ULONG i = 0; i < pLibRec->ctImpMod; ++ i, ++ pHmte)
+                    qt_excWriteModules (file, *pHmte, pFirstLibRec,
+                                        ulOrigin == 1 ? 2 : ulOrigin);
+                break;
+            }
+        }
+        pLibRec = (QSLREC *) pLibRec->pNextRec; 
+    }
+}
+
+/** Struct for recursive qt_excWriteModulesOnStack() to reduce stack usage */
+typedef struct _WMOS_STATE
+{
+    FILE *file;
+    ULONG ulRegEbp;
+    ULONG ulRegEip;
+    ULONG ulStackLimit;
+    USHORT hmteExe;
+    ULONG cLevel;
+    USHORT *pHmteOuter;
+} WMOS_STATE;
+
+/*! \internal
+    Walks the stack and writes information about all encountered modules.
+    Used only when DosQuerySysState() fails (so qt_excWriteModules() is not
+    applicable). We use recursiveness to avoid module record duplicates.
+*/
+static void qt_excWriteModulesOnStack (WMOS_STATE *pState)
+{
+    USHORT hmteThis = 0;
+    
+    {
+        APIRET  arc = NO_ERROR;
+        char    szMod [CCHMAXPATH] = "";
+        ULONG   ulObject = 0, ulOffset = 0;
+    
+        arc = DosQueryModFromEIP ((HMODULE *) &hmteThis, &ulObject,
+                                  sizeof (szMod), szMod, &ulOffset,
+                                  pState->ulRegEip);
+        if (arc == NO_ERROR && hmteThis != pState->hmteExe)
+        {
+            /* look if we've already seen this module using the hmteThis chain
+             * on the stack */
+            USHORT *pH = &hmteThis;
+            /* calculate distance between recursive hmteThis on the stack */
+            ULONG ulOuter = (ULONG) pState->pHmteOuter - (ULONG) pH;
+            ULONG cL = pState->cLevel;
+            while (cL != 0)
+            {
+                pH = (USHORT *)(((ULONG) pH) + ulOuter);
+                if (*pH == hmteThis)
+                    break;
+                -- cL;
+            }
+            if (cL == 0)
+            {
+                /* got an unique module handle */
+                DosQueryModuleName (hmteThis, sizeof (szMod), szMod);
+                qt_excWriteModule (pState->file, hmteThis, szMod);
+            }
+        }
+    }
+    
+    /* we do EBP validity check here as well as before the recursive call below
+     * to get a chance to translate EIP passed on the first call (as taken
+     * from the CONTEXTRECORD even if EBP there is invalid. */
+    if (pState->ulRegEbp != 0 && pState->ulRegEbp < pState->ulStackLimit)
+    {
+        if ((pState->ulRegEbp & 0x00000FFF) == 0x00000000)
+        {
+            /* we're on a page boundary: check access */
+            while (pState->ulRegEbp < pState->ulStackLimit)
+            {
+                ULONG ulCount = 0x1000;
+                ULONG ulFlags = 0;
+                APIRET arc = DosQueryMem ((void *) pState->ulRegEbp,
+                                          &ulCount, &ulFlags);
+                if (   (arc != NO_ERROR)
+                    || (   arc == NO_ERROR
+                        && (ulFlags & (PAG_COMMIT|PAG_READ))
+                            != (PAG_COMMIT|PAG_READ)))
+                {
+                    /* try go to the next page */
+                    /// @todo (r=dmik) I'm not sure how much it is correct,
+                    //  I've just taken the logic from xwphelpers sources.
+                    pState->ulRegEbp += 0x1000;
+                    continue; /* while */
+                }
+                break;
+            }
+        }
+
+        /* get the return address to the previous call */
+        pState->ulRegEip = *(((PULONG) pState->ulRegEbp) + 1);
+        /* get the address of the outer stack frame */
+        pState->ulRegEbp = *((PULONG) pState->ulRegEbp);
+    
+        if (pState->ulRegEbp != 0 && pState->ulRegEbp < pState->ulStackLimit)
+        {
+            pState->cLevel ++;
+            pState->pHmteOuter = &hmteThis;
+            qt_excWriteModulesOnStack (pState);
+        }
+    }
 }
 
@@ -479,81 +619,117 @@
     Writes exception information to the log file.
 */
-static void qt_excWriteException( FILE *file,
-                                  const char *pszExeName,
-                                  const char *pszExeBase,
-                                  PPIB ppib, PTIB ptib,
+static void qt_excWriteException (FILE *file,
+                                  PROCESSINFO *pInfo,
                                   PEXCEPTIONREPORTRECORD pReportRec,
-                                  PCONTEXTRECORD pContextRec )
-{
-    ULONG       aulBuf[3];
-
-    // *** application info
-
-    {
-        fprintf( file, " <Application name=\"" );
-        if ( XcptPvt::askCallback( QtOS2SysXcptReq_AppName ) == TRUE )
-            XcptPvt::letCallback( QtOS2SysXcptReq_AppName );
+                                  PCONTEXTRECORD pContextRec)
+{
+    ULONG ul = 0;
+    ULONG aulBuf [3];
+
+    /* *** application info */
+
+    {
+        fprintf (file, " <Application name=\"");
+        if (XcptPvt::askCallback (QtOS2SysXcptReq_AppName) == TRUE)
+            XcptPvt::letCallback (QtOS2SysXcptReq_AppName);
         else
-            qt_excEscapeString( file, pszExeBase );
-        fprintf( file, "\" version=\"" );
-        if ( XcptPvt::askCallback( QtOS2SysXcptReq_AppVer ) == TRUE )
-            XcptPvt::letCallback( QtOS2SysXcptReq_AppVer );
+            qt_excEscapeString (file, pInfo->pszBaseName);
+        fprintf (file, "\" version=\"");
+        if (XcptPvt::askCallback (QtOS2SysXcptReq_AppVer) == TRUE)
+            XcptPvt::letCallback (QtOS2SysXcptReq_AppVer);
         else
-            fprintf( file, "unknown" );
-        fprintf( file, "\">\n" );
-
-        if ( XcptPvt::askCallback( QtOS2SysXcptReq_ReportTo ) == TRUE )
-        {
-            fprintf( file, "  <Report to=\"" );
-            XcptPvt::letCallback( QtOS2SysXcptReq_ReportTo );
-            if ( XcptPvt::askCallback( QtOS2SysXcptReq_ReportSubj ) == TRUE )
-            {
-                fprintf( file, "\" subject=\"" );
-                XcptPvt::letCallback( QtOS2SysXcptReq_ReportSubj );
-            }
-            fprintf( file, "\"/>\n" );
+            fprintf (file, "unknown");
+        fprintf (file, "\">\n");
+
+        if (XcptPvt::askCallback (QtOS2SysXcptReq_ReportTo) == TRUE)
+        {
+            fprintf (file, "  <Report to=\"");
+            XcptPvt::letCallback (QtOS2SysXcptReq_ReportTo);
+            if (XcptPvt::askCallback (QtOS2SysXcptReq_ReportSubj) == TRUE)
+            {
+                fprintf (file, "\" subject=\"");
+                XcptPvt::letCallback (QtOS2SysXcptReq_ReportSubj);
+            }
+            fprintf (file, "\"/>\n");
         }
         
-        fprintf( file, " </Application>\n" );
-    }
-    
-    // *** system info
-
-    DosQuerySysInfo( QSV_VERSION_MAJOR, QSV_VERSION_REVISION,
-                     &aulBuf, sizeof(aulBuf) );
-    // Warp 3 is reported as 20.30
-    // Warp 4 is reported as 20.40
-    // Aurora is reported as 20.45
-
-    fprintf( file,
+        fprintf (file, " </Application>\n");
+    }
+    
+    /* *** generic exception info */
+
+    fprintf (file,
+             " <Exception type=\"%08lX\" flags=\"%08lX\" address=\"%08lX\">\n",
+             pReportRec->ExceptionNum, pReportRec->fHandlerFlags,
+             (ULONG) pReportRec->ExceptionAddress);
+    
+    for (ul = 0; ul < pReportRec->cParameters;  ++ul)
+    {
+        fprintf (file, "  <Param value=\"%08lX\"/>\n",
+                 pReportRec->ExceptionInfo [ul]);
+    }
+
+    fprintf (file, " </Exception>\n");
+    
+    /* *** system info */
+
+    DosQuerySysInfo (QSV_VERSION_MAJOR, QSV_VERSION_REVISION,
+                     &aulBuf, sizeof (aulBuf));
+    /* Warp 3 is reported as 20.30 */
+    /* Warp 4 is reported as 20.40 */
+    /* Aurora is reported as 20.45 */
+
+    fprintf (file,
              " <System name=\"OS/2\" version=\"%u.%u.%u\"/>\n",
-             aulBuf[0], aulBuf[1], aulBuf[2] );
-
-    // *** process info
-
-    if ( ppib )
-    {
-        fprintf( file,
-                 " <Process ID=\"%04lX\" parentID=\"%04lX\">\n"
-                 "  <Module ID=\"%04lX\" name=\"",
-                ppib->pib_ulpid, ppib->pib_ulppid, ppib->pib_hmte );
-        qt_excEscapeString( file, pszExeName );
-        fprintf( file,
-                 "\"/>\n"
-                 " </Process>\n" );
+             aulBuf[0], aulBuf[1], aulBuf[2]);
+
+    /* *** process info */
+
+    fprintf (file, " <Process ID=\"%04lX\" parentID=\"%04lX\">\n",
+             pInfo->ppib->pib_ulpid, pInfo->ppib->pib_ulppid);
+
+    fprintf (file, "  <Modules>\n");
+    if (pInfo->bHaveSysState)
+    {
+        /* write process module and it's imports */
+        qt_excWriteModules (file, pInfo->ppib->pib_hmte, pInfo->pLibRec, 1);
+        /* write loaded modules and their imports */
+        if (pInfo->pProcRec->cLib && pInfo->pProcRec->pLibRec)
+        {
+            for (ULONG i = 0; i < pInfo->pProcRec->cLib; ++ i)
+                qt_excWriteModules (file, pInfo->pProcRec->pLibRec [i],
+                                    pInfo->pLibRec, 3);
+        }
     }
     else
-        qt_excWriteErrorMsg( file, 1, "ppib is NULL" );
-
-	fprintf( file, " <Threads>\n" );
-	
-    if ( ptib && ptib->tib_ptib2 )
-        qt_excWriteThreadInfo( file, ptib, pReportRec, pContextRec );
-    else if ( !ptib )
-        qt_excWriteErrorMsg( file, 1, "ptib is NULL" );
-    else
-        qt_excWriteErrorMsg( file, 1, "ptib->tib_ptib2 is NULL" );
-
-	fprintf( file, " </Threads>\n" );
+    {
+        qt_excWriteModule (file, pInfo->ppib->pib_hmte, pInfo->pszFullName, 1);
+        WMOS_STATE State = { file, pContextRec->ctx_RegEbp,
+                             pContextRec->ctx_RegEip,
+                             (ULONG) pInfo->ptib->tib_pstacklimit,
+                             pInfo->ppib->pib_hmte,
+                             0 /* cLevel */, NULL /* pHmteOuter */ };
+        qt_excWriteModulesOnStack (&State);
+    }
+    fprintf (file, "  </Modules>\n");
+    
+    fprintf (file, "  <Threads>\n");
+    
+    /* first, the current thread */
+    QSTREC *pThrdRec = pInfo->pProcRec->pThrdRec;
+    if (pThrdRec)
+    {
+        /* locate the current thread structure */
+        for (ul = 0; ul < pInfo->pProcRec->cTCB; ++ ul, ++ pThrdRec)
+            if ((ULONG) pThrdRec->tid == pInfo->ptib->tib_ptib2->tib2_ultid)
+                break;
+        if (ul == pInfo->pProcRec->cTCB)
+            pThrdRec = NULL;
+    }
+    qt_excWriteThreadInfo (file, pInfo->ptib, pThrdRec, pContextRec);
+    
+    fprintf (file, "  </Threads>\n");
+
+    fprintf (file, " </Process>\n");
 }
 
@@ -678,7 +854,6 @@
                                   PVOID pv )
 {
-    PTIB ptib = NULL;
-    PPIB ppib = NULL;
-    
+    PROCESSINFO Info = {0};
+
     /* From the VAC++3 docs:
      *      "The first thing an exception handler should do is check the
@@ -696,11 +871,11 @@
      */
 
-    if ( pReportRec->fHandlerFlags &
-         (EH_EXIT_UNWIND | EH_UNWINDING | EH_NESTED_CALL) )
+    if (pReportRec->fHandlerFlags &
+        (EH_EXIT_UNWIND | EH_UNWINDING | EH_NESTED_CALL))
         return XCPT_CONTINUE_SEARCH;
 
-    // can it ever fail?...
-    DosGetInfoBlocks( &ptib, &ppib );
-        
+    /* setup the process info structure */
+    DosGetInfoBlocks (&Info.ptib, &Info.ppib);
+
     switch (pReportRec->ExceptionNum)
     {
@@ -712,84 +887,125 @@
         case XCPT_INTEGER_OVERFLOW:
         {
-            // "real" exceptions:
-
+            /* "real" exceptions: */
+
+            APIRET arc = NO_ERROR;
+            PVOID pBuf = NULL;
+            
+            char szFullExeName [CCHMAXPATH] = "";
+            char szBaseExeName [CCHMAXPATH] = "";
+            
+            TIB2 Tib2Orig;
             DATETIME dt;
-            char szFileName[CCHMAXPATH];
+
+            char szFileName [CCHMAXPATH];
             FILE *file = NULL;
-            char szExeName[CCHMAXPATH] = "unknown";
-            char szExeBase[CCHMAXPATH];
-            
-            DosBeep( 880, 200 );
-
-            if ( ppib )
-            {
-                // get the main module name
-                DosQueryModuleName( ppib->pib_hmte, sizeof(szExeName),
-                                    szExeName );
-                
-                // find the base name (w/o path and extension) 
-                char *psz = strrchr( szExeName, '\\' );
+
+            /* raise this thread's priority to do it fast */ 
+            Tib2Orig = *Info.ptib->tib_ptib2;
+            Info.ptib->tib_ptib2 = &Tib2Orig;
+            DosSetPriority (PRTYS_THREAD, PRTYC_REGULAR, PRTYD_MAXIMUM, 0);
+
+            DosBeep (880, 200);
+
+            /* query system state */
+            {
+                ULONG ulCB = 64 * 1024;
+                ULONG cTries = 3;
+                while (-- cTries)
+                {
+                    arc = DosAllocMem (&pBuf, ulCB, PAG_WRITE | PAG_COMMIT);
+                    if (arc == NO_ERROR)
+                    {
+                        memset (pBuf, 0, ulCB);
+                        arc = DosQuerySysState (QS_PROCESS | QS_MTE, 0,
+                                                Info.ppib->pib_ulpid, 0,
+                                                pBuf, ulCB);
+                        if (arc == NO_ERROR)
+                        {
+                            QSPTRREC *pPtrRec = (QSPTRREC *) pBuf;
+                            Info.bHaveSysState = TRUE;
+                            Info.pProcRec = pPtrRec->pProcRec;
+                            Info.pLibRec = pPtrRec->pLibRec;
+                        }
+                        else if (arc == ERROR_BUFFER_OVERFLOW)
+                        {
+                            /* retry with some bigger buffer size */
+                            DosFreeMem (pBuf);
+                            pBuf = NULL;
+                            ulCB *= 2;
+                            continue;
+                        }
+                    }
+                    break;
+                }
+            }
+        
+            /* get the main module name */
+            DosQueryModuleName (Info.ppib->pib_hmte,
+                                sizeof (szFullExeName), szFullExeName);
+            {
+                /* find the base name (w/o path and extension) */ 
+                char *psz = strrchr (szFullExeName, '\\');
                 if ( psz )
                     ++ psz;
                 if ( !psz )
-                    psz = szExeName;
-                strcpy( szExeBase, psz );
-                psz = strrchr( szExeBase, '.' );
-                if ( psz )
+                    psz = szFullExeName;
+                strcpy (szBaseExeName, psz);
+                psz = strrchr (szBaseExeName, '.');
+                if (psz)
                     *psz = '\0';
-            }
-
-            // compose the desired base file name for the log file
-            // (<datetime>-<exe>)
-            DosGetDateTime( &dt );
-            sprintf( szFileName, "%04d%02d%02d%02d%02d%02d-%s",
+                Info.pszFullName = szFullExeName;
+                Info.pszBaseName = szBaseExeName;
+            }
+            
+            /* compose the desired base file name for the log file
+             * (<datetime>-<exe>) */
+            DosGetDateTime (&dt);
+            sprintf (szFileName, "%04d%02d%02d%02d%02d%02d-%s",
                      dt.year, dt.month, dt.day,
                      dt.hours, dt.minutes, dt.seconds,
-                     szExeBase );
+                     szBaseExeName);
             
-            // open the log file:
+            /* open the log file: */
             
-            // first try the home directory, then the root drive
-            // (see QDir::homeDirPath())
-            file = qt_excOpenLogFile( getenv( "HOME" ), szFileName );
-            if ( file == NULL )
-            {
-                char *pszHomeDrive = getenv( "HOMEDRIVE" );
-                char *pszHomePath = getenv( "HOMEPATH" );
-                if ( pszHomeDrive && pszHomePath &&
-                     strlen( pszHomeDrive ) + strlen( pszHomePath ) < CCHMAXPATH )
+            /* first, try the home directory, then the root drive
+             * (see QDir::homeDirPath()) */
+            file = qt_excOpenLogFile (getenv ("HOME"), szFileName);
+            if (file == NULL)
+            {
+                char *pszHomeDrive = getenv ("HOMEDRIVE");
+                char *pszHomePath = getenv ("HOMEPATH");
+                if (pszHomeDrive && pszHomePath &&
+                    strlen (pszHomeDrive) + strlen (pszHomePath) < CCHMAXPATH)
                 {
-                    char szHomePath[CCHMAXPATH];
-                    strcpy( szHomePath, pszHomeDrive );
-                    strcat( szHomePath, pszHomePath );
-                    file = qt_excOpenLogFile( szHomePath, szFileName );
+                    char szHomePath [CCHMAXPATH];
+                    strcpy (szHomePath, pszHomeDrive);
+                    strcat (szHomePath, pszHomePath);
+                    file = qt_excOpenLogFile (szHomePath, szFileName);
                 }
             }
-            if ( file == NULL )
-            {
-                static char szBootDrive[] = "\0:";
-                if ( !szBootDrive[0] )
-                {
-                    ULONG ulBootDrive;
-                    DosQuerySysInfo( QSV_BOOT_DRIVE, QSV_BOOT_DRIVE,
-                                     &ulBootDrive, sizeof(ulBootDrive) );
-                    szBootDrive[0] = (char) ulBootDrive + 'A' - 1;
-                }
-                file = qt_excOpenLogFile( szBootDrive, szFileName );
-            }
-
-            if ( file != NULL )
-            {
-                fprintf( file,
-                        "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
-                        "<!--\n"
-                        "  A fatal error has occured while running this application.\n"
-                        "  Please contact the application vendor, describe what happened\n"
-                        "  and send the contents of this file saved locally as\n"
-                        "  '%s'.\n"
-                        "-->\n",
-                        szFileName );
-
-                fprintf( file,
+            if (file == NULL)
+            {
+                char szBootDrive[] = "\0:";
+                ULONG ulBootDrive;
+                DosQuerySysInfo( QSV_BOOT_DRIVE, QSV_BOOT_DRIVE,
+                                 &ulBootDrive, sizeof(ulBootDrive) );
+                szBootDrive[0] = (char) ulBootDrive + 'A' - 1;
+                file = qt_excOpenLogFile (szBootDrive, szFileName);
+            }
+
+            if (file != NULL)
+            {
+                fprintf (file,
+                         "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
+                         "<!--\n"
+                         "  A fatal error has occured while running this application.\n"
+                         "  Please contact the application vendor, describe what happened\n"
+                         "  and send the contents of this file saved locally as\n"
+                         "  '%s'.\n"
+                         "-->\n",
+                         szFileName);
+
+                fprintf (file,
                          "<Trap timestamp=\"%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d\" "
                                "version=\"1.0\"\n"
@@ -799,20 +1015,19 @@
                          dt.hours, dt.minutes, dt.seconds,
                          (dt.timezone > 0 ? '-' : '+'),
-                         abs( dt.timezone / 60 ),
-                         abs( dt.timezone % 60 ),
+                         abs (dt.timezone / 60),
+                         abs (dt.timezone % 60),
                          QT_VERSION_STR );
 
                 XcptPvt::file = file;
                 
-                // write trap information
-                qt_excWriteException( file, szExeName, szExeBase,
-                                      ppib, ptib, pReportRec, pContextRec );
+                /* write trap information */
+                qt_excWriteException (file, &Info, pReportRec, pContextRec);
 
                 XcptPvt::file = NULL;
                 
-                fprintf( file, "</Trap>\n\n" );
-                fclose( file );
+                fprintf (file, "</Trap>\n\n");
+                fclose (file);
                 
-                // attempt to display the created file
+                /* attempt to display the created file */
                 {
                     STARTDATA SData       = {0};
@@ -820,27 +1035,35 @@
                     ULONG     ulSessID    = 0;
                     
-                    SData.Length  = sizeof(STARTDATA);
+                    SData.Length  = sizeof (STARTDATA);
                     SData.PgmName = "E.EXE";
                     SData.PgmInputs = szFileName;
                     
-                    DosStartSession( &SData, &ulSessID, &pid );
+                    DosStartSession (&SData, &ulSessID, &pid);
                 }
             }
             else
-                DosBeep( 220, 200 );
+                DosBeep (220, 200);
+
+            if (pBuf != NULL)
+                DosFreeMem (pBuf);
+            
+            /* reset old priority */
+            DosSetPriority (PRTYS_THREAD, (Tib2Orig.tib2_ulpri & 0x0F00) >> 8,
+                                          (UCHAR) Tib2Orig.tib2_ulpri,
+                                          0);
         }
         break;
     }
 
-    // we never handle the exception ourselves
-
-    if ( ptib && ptib->tib_ptib2 && ptib->tib_ptib2->tib2_ultid == 1 &&
-         QtOS2SysXcptMainHandler::libcHandler != NULL )
-    {
-        // we are on the main thread and were installed from qt_init() during
-        // QApplication initialization using a hack; pass control back to the
-        // LIBC exception handler
-        return QtOS2SysXcptMainHandler::libcHandler( pReportRec, pRegRec,
-                                                     pContextRec, pv );
+    /* we never handle the exception ourselves */
+
+    if (Info.ptib->tib_ptib2->tib2_ultid == 1 &&
+        QtOS2SysXcptMainHandler::libcHandler != NULL)
+    {
+        /* we are on the main thread and were installed from qt_init() during
+         * QApplication initialization using a hack; pass control back to the
+         * LIBC exception handler */
+        return QtOS2SysXcptMainHandler::libcHandler (pReportRec, pRegRec,
+                                                     pContextRec, pv);
     }
     
