source: trunk/src/tools/qsysxcpt_pm.cpp@ 143

Last change on this file since 143 was 143, checked in by dmik, 19 years ago

Common: System Exceptions:

  • Fixed: Using HOMEDRIVE/HOMEPATH to point to the home directory didn't work;
  • Improved: Paths specified in HOME and HOMEDRIVE/HOMEPATH are resolved to full paths before using.
  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 26.3 KB
Line 
1/****************************************************************************
2** $Id: qsysxcpt_pm.cpp 143 2006-10-23 22:47:25Z dmik $
3**
4** OS/2 System Exception handling routines
5**
6** Copyright (C) 2006 netlabs.org.
7**
8** This file is part of the kernel module of the Qt GUI Toolkit.
9**
10** This file may be distributed under the terms of the Q Public License
11** as defined by Trolltech AS of Norway and appearing in the file
12** LICENSE.QPL included in the packaging of this file.
13**
14** This file may be distributed and/or modified under the terms of the
15** GNU General Public License version 2 as published by the Free Software
16** Foundation and appearing in the file LICENSE.GPL included in the
17** packaging of this file.
18**
19** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
20** licenses may use this file in accordance with the Qt Commercial License
21** Agreement provided with the Software.
22**
23** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
24** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
25**
26** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
27** information about Qt Commercial License Agreements.
28** See http://www.trolltech.com/qpl/ for QPL licensing information.
29** See http://www.trolltech.com/gpl/ for GPL licensing information.
30**
31** Contact info@trolltech.com if any conditions of this licensing are
32** not clear to you.
33**
34**********************************************************************/
35
36/*
37 * The below code is partly based on the except.h and except.c sources
38 * from the xwphelpers package (which is a part of the xworkplace product, see
39 * http://www.xworkplace.org, http://xworkplace.netlabs.org/ for more info).
40 * XWorkplace is Copyright (C) 1999-2002 Ulrich Moeller.
41 */
42
43#if !defined(QT_OS2_NO_SYSEXCEPTIONS)
44
45#include "qt_os2.h"
46
47#include <stdio.h>
48#include <stdlib.h>
49#include <stdarg.h>
50#include <unistd.h>
51#include <string.h>
52#include <time.h>
53#include <errno.h>
54#include <sys/stat.h>
55
56/// @todo (r=dmik) add locking to:
57// a) handle simultaneous independent exceptions from different threads
58// b) raise (user) exceptions on all other threads in order to write their
59// contexts to the trap file when a real exception happens on one thread
60
61/*! \class QtOS2SysXcptMainHandler qt_os2.h
62
63 @todo (r=dmik) describe...
64
65 - must be instantiated on the stack of the main thread only
66 - must be instantiated before a QAplication instance is created
67 (does nothing otherwise)
68*/
69
70/* static */
71bool QtOS2SysXcptMainHandler::installed = FALSE;
72QtOS2SysXcptCallback QtOS2SysXcptMainHandler::callback = NULL;
73ERR QtOS2SysXcptMainHandler::libcHandler = NULL;
74
75/*!
76 @todo (r=dmik) describe...
77*/
78QtOS2SysXcptMainHandler::QtOS2SysXcptMainHandler( QtOS2SysXcptCallback cb )
79{
80 rec.prev_structure = NULL;
81 rec.ExceptionHandler = NULL;
82
83 PTIB ptib = NULL;
84 DosGetInfoBlocks( &ptib, NULL );
85 Q_ASSERT( ptib && ptib->tib_ptib2 );
86
87 if ( ptib && ptib->tib_ptib2 )
88 {
89 // must be instantiated only on the main (first) thread
90 Q_ASSERT( ptib->tib_ptib2->tib2_ultid == 1 );
91 if ( ptib->tib_ptib2->tib2_ultid == 1 )
92 {
93 // must not be already instantiated
94 Q_ASSERT( installed == FALSE );
95 Q_ASSERT( libcHandler == NULL );
96 if ( installed == FALSE && libcHandler == NULL )
97 {
98 installed = TRUE;
99 callback = cb;
100 // install the exception handler for the main thread
101 rec.ExceptionHandler = handler;
102 DosSetExceptionHandler( &rec );
103 }
104 }
105 }
106}
107
108/*!
109 @todo (r=dmik) describe...
110*/
111QtOS2SysXcptMainHandler::~QtOS2SysXcptMainHandler()
112{
113 Q_ASSERT( rec.ExceptionHandler == handler || rec.ExceptionHandler == NULL );
114 if ( rec.ExceptionHandler == handler )
115 {
116 // uninstall the exception handler for the main thread
117 DosUnsetExceptionHandler( &rec );
118 rec.ExceptionHandler = NULL;
119 callback = NULL;
120 installed = FALSE;
121 }
122}
123
124static void qt_excEscapeString( FILE *file, const char *pcszStr );
125
126#define XcptPvt QtOS2SysXcptMainHandler::Private
127
128class XcptPvt
129{
130public:
131 static void callbackWriter( const char *msg );
132
133 static inline int askCallback( QtOS2SysXcptReq req )
134 {
135 if ( callback )
136 return callback( req, NULL, 0 );
137 return FALSE;
138 }
139
140 static inline int letCallback( QtOS2SysXcptReq req )
141 {
142 if ( callback )
143 return callback( req, callbackWriter, 0 );
144 return FALSE;
145 }
146
147 static FILE *file;
148};
149
150/* static */
151FILE *XcptPvt::file = NULL;
152
153/* static */
154void XcptPvt::callbackWriter( const char *msg )
155{
156 if ( file )
157 qt_excEscapeString( file, msg );
158}
159
160/*! \internal
161 Writes the given string with [<>&'"] characters escaped for XML.
162*/
163static void qt_excEscapeString( FILE *file, const char *pcszStr )
164{
165 const char *pcszChars = "<>&'\"";
166 const char *aszEntities[] = { "&lt;", "&gt;", "&amp;", "&apos;", "&quot;" };
167
168 const char *pcsz = pcszStr;
169 const char *pcszRepl = NULL;
170 size_t cbLen = 0;
171
172 if ( !pcsz )
173 return;
174
175 while( *pcsz )
176 {
177 cbLen = strcspn( pcsz, pcszChars );
178 fwrite( pcsz, 1, cbLen, file );
179 pcsz += cbLen;
180 if ( !*pcsz )
181 break;
182 cbLen = strchr( pcszChars, *pcsz ) - pcszChars;
183 pcszRepl = aszEntities[cbLen];
184 fwrite( pcszRepl, 1, strlen(pcszRepl), file );
185 ++ pcsz;
186 }
187}
188
189/*! \internal
190 Writes the given error message.
191*/
192static void qt_excWriteErrorMsg( FILE *file, ULONG ulIndent, const char *pcszMsg,
193 ... )
194{
195 char szBuf[1024];
196 va_list args;
197 va_start( args, pcszMsg );
198 fprintf( file, "%*s<Error message=\"", ulIndent, "" );
199 vsnprintf( szBuf, sizeof(szBuf), pcszMsg, args );
200 szBuf[sizeof(szBuf) - 1] = '\0';
201 qt_excEscapeString( file, szBuf );
202 fprintf( file, "\"/>\n" );
203 va_end( args );
204}
205
206/*! \internal
207 Writes the register name, value and optionally memory flags
208*/
209static void qt_excWriteReg( FILE *file, const char *pszName, ULONG ulValue,
210 BOOL bQueryMem = TRUE )
211{
212 fprintf( file, " <Register name=\"%s\" value=\"%08lX\"",
213 pszName, ulValue );
214
215 if ( bQueryMem )
216 {
217 APIRET arc;
218 ULONG ulCountPages = 1;
219 ULONG ulFlagsPage = 0;
220 arc = DosQueryMem( (PVOID) ulValue, &ulCountPages, &ulFlagsPage );
221
222 if ( arc == NO_ERROR || arc == ERROR_INVALID_ADDRESS )
223 {
224 if ( arc == NO_ERROR )
225 fprintf( file, " flags=\"%08lX\"/>\n", ulFlagsPage );
226 else
227 fprintf( file, " flags=\"invalid\"/>\n" );
228 }
229 }
230 else
231 fprintf( file, "/>\n" );
232}
233
234/*! \internal
235 Writes information about a signle stack frame.
236*/
237static void qt_excWriteStackFrame( FILE *file, ULONG ulPointer, ULONG ulAddress )
238{
239 APIRET arc = NO_ERROR;
240 HMODULE hMod = NULLHANDLE;
241 char szMod[CCHMAXPATH] = "unknown";
242 ULONG ulObject = 0,
243 ulOffset = 0;
244
245 if ( ulPointer )
246 fprintf( file, " <Frame pointer=\"%08lX\">\n", ulPointer );
247 else
248 fprintf( file, " <Frame pointer=\"current\">\n" );
249
250 if ( ulAddress )
251 {
252 fprintf( file, " <Location address=\"%08lX\">\n", ulAddress );
253
254 arc = DosQueryModFromEIP( &hMod, &ulObject,
255 sizeof(szMod), szMod, &ulOffset,
256 ulAddress );
257
258 if (arc != NO_ERROR)
259 qt_excWriteErrorMsg( file, 6, "%s: DosQueryModFromEIP returned %lu",
260 szMod, arc );
261 else
262 {
263 DosQueryModuleName( hMod, sizeof(szMod), szMod );
264 fprintf( file, " <Module ID=\"%04lX\" name=\"", hMod );
265 qt_excEscapeString( file, szMod );
266 fprintf( file, "\" \n"
267 " segment=\"%04lX\" offset=\"%08lX\"/>\n",
268 ulObject + 1, ulOffset );
269/// @todo (r=dmik) use .DBG and .SYM files to get symbols
270// (see debug.h and debug.c from the xwphelpers package)
271// dbgPrintStackFrame(file,
272// szFullName,
273// ulObject,
274// ulOffset);
275 }
276 }
277 else
278 qt_excWriteErrorMsg( file, 5, "Unable to access stack frame" );
279
280 fprintf( file, " </Location>\n"
281 " </Frame>\n" );
282}
283
284/*! \internal
285 Walks the stack and writes information about stack frames.
286*/
287static void qt_excWriteStackFrames( FILE *file, PTIB ptib,
288 PCONTEXTRECORD pContextRec )
289{
290 PULONG pulStackWord = 0;
291
292 fprintf( file, " <Frames>\n" );
293
294 // first the trapping address itself
295 qt_excWriteStackFrame( file, 0, pContextRec->ctx_RegEip );
296
297 pulStackWord = (PULONG) pContextRec->ctx_RegEbp;
298
299 while ( pulStackWord != 0
300 && pulStackWord < (PULONG) ptib->tib_pstacklimit )
301 {
302 if ( ((ULONG) pulStackWord & 0x00000FFF) == 0x00000000 )
303 {
304 // we're on a page boundary: check access
305 ULONG ulCountPages = 0x1000;
306 ULONG ulFlagsPage = 0;
307 APIRET arc = DosQueryMem( (void *)pulStackWord,
308 &ulCountPages, &ulFlagsPage );
309 if ( (arc != NO_ERROR)
310 || ( arc == NO_ERROR
311 && (ulFlagsPage & (PAG_COMMIT|PAG_READ))
312 != (PAG_COMMIT|PAG_READ)) )
313 {
314 fprintf( file, " <Frame pointer=\"%08lX\">\n",
315 (ULONG) pulStackWord );
316 qt_excWriteErrorMsg( file, 6,
317 "Unable to access stack frame, DosQueryMem "
318 "returned %lu and flags %08lX",
319 arc, ulFlagsPage );
320 fprintf( file, " </Frame>\n" );
321 pulStackWord += 0x1000;
322 continue; // while
323 }
324 }
325
326 qt_excWriteStackFrame( file, (ULONG) pulStackWord, *(pulStackWord + 1) );
327 pulStackWord = (PULONG) *(pulStackWord);
328 } // end while
329
330 fprintf( file, " </Frames>\n" );
331}
332
333/*! \internal
334 Writes the thread information.
335*/
336static void qt_excWriteThreadInfo( FILE *file, PTIB ptib,
337 PEXCEPTIONREPORTRECORD pReportRec,
338 PCONTEXTRECORD pContextRec )
339{
340 ULONG ul = 0;
341 ULONG ulOldPriority = ~0;
342
343 // raise this thread's priority, because this
344 // might take some time
345 ulOldPriority = ptib->tib_ptib2->tib2_ulpri;
346 DosSetPriority( PRTYS_THREAD, PRTYC_REGULAR, PRTYD_MAXIMUM, 0 );
347
348 fprintf( file, " <Thread ID=\"%04lX\" slot=\"%04lX\" "
349 "priority=\"%04lX\" "
350 "mc=\"%04lX\" mcf=\"%04lX\">\n",
351 ptib->tib_ptib2->tib2_ultid, ptib->tib_ordinal, ulOldPriority,
352 ptib->tib_ptib2->tib2_usMCCount, ptib->tib_ptib2->tib2_fMCForceFlag );
353
354 // *** generic exception info
355
356 fprintf( file,
357 " <Exception type=\"%08lX\" flags=\"%08lX\" address=\"%08lX\">\n",
358 pReportRec->ExceptionNum, pReportRec->fHandlerFlags,
359 (ULONG) pReportRec->ExceptionAddress );
360
361 for ( ul = 0; ul < pReportRec->cParameters; ++ul )
362 {
363 fprintf( file, " <Param value=\"%08lX\"/>\n",
364 pReportRec->ExceptionInfo[ul] );
365 }
366
367 fprintf( file, " </Exception>\n" );
368
369 // *** registers
370
371 fprintf( file, " <CPU>\n"
372 " <Registers>\n" );
373
374 if ( pContextRec->ContextFlags & CONTEXT_SEGMENTS )
375 {
376 qt_excWriteReg( file, "DS", pContextRec->ctx_SegDs, FALSE );
377 qt_excWriteReg( file, "ES", pContextRec->ctx_SegEs, FALSE );
378 qt_excWriteReg( file, "FS", pContextRec->ctx_SegFs, FALSE );
379 qt_excWriteReg( file, "GS", pContextRec->ctx_SegGs, FALSE );
380 }
381
382 if ( pContextRec->ContextFlags & CONTEXT_INTEGER )
383 {
384 qt_excWriteReg( file, "EAX", pContextRec->ctx_RegEax );
385 qt_excWriteReg( file, "EBX", pContextRec->ctx_RegEbx );
386 qt_excWriteReg( file, "ECX", pContextRec->ctx_RegEcx );
387 qt_excWriteReg( file, "EDX", pContextRec->ctx_RegEdx );
388 qt_excWriteReg( file, "ESI", pContextRec->ctx_RegEsi );
389 qt_excWriteReg( file, "EDI", pContextRec->ctx_RegEdi );
390 }
391
392 if ( pContextRec->ContextFlags & CONTEXT_CONTROL )
393 {
394 qt_excWriteReg( file, "CS", pContextRec->ctx_SegCs, FALSE );
395 qt_excWriteReg( file, "EIP", pContextRec->ctx_RegEip );
396 qt_excWriteReg( file, "SS", pContextRec->ctx_SegSs, FALSE );
397 qt_excWriteReg( file, "ESP", pContextRec->ctx_RegEsp );
398 qt_excWriteReg( file, "EBP", pContextRec->ctx_RegEbp );
399 qt_excWriteReg( file, "EFLAGS", pContextRec->ctx_EFlags, FALSE );
400 }
401
402 fprintf( file, " </Registers>\n"
403 " </CPU>\n" );
404
405 // *** stack
406
407 fprintf( file, " <Stack base=\"%08lX\" limit=\"%08lX\">\n",
408 (ULONG) ptib->tib_pstack,
409 (ULONG) ptib->tib_pstacklimit );
410
411 if ( pContextRec->ContextFlags & CONTEXT_CONTROL )
412 {
413 qt_excWriteStackFrames( file, ptib, pContextRec );
414 }
415
416 fprintf( file, " </Stack>\n"
417 " </Thread>\n" );
418
419 // reset old priority
420 DosSetPriority( PRTYS_THREAD, (ulOldPriority & 0x0F00) >> 8,
421 (UCHAR) ulOldPriority,
422 0 );
423}
424
425/*! \internal
426 Writes exception information to the log file.
427*/
428static void qt_excWriteException( FILE *file,
429 const char *pszExeName,
430 const char *pszExeBase,
431 PPIB ppib, PTIB ptib,
432 PEXCEPTIONREPORTRECORD pReportRec,
433 PCONTEXTRECORD pContextRec )
434{
435 ULONG aulBuf[3];
436
437 // *** application info
438
439 {
440 fprintf( file, " <Application name=\"" );
441 if ( XcptPvt::askCallback( QtOS2SysXcptReq_AppName ) == TRUE )
442 XcptPvt::letCallback( QtOS2SysXcptReq_AppName );
443 else
444 qt_excEscapeString( file, pszExeBase );
445 fprintf( file, "\" version=\"" );
446 if ( XcptPvt::askCallback( QtOS2SysXcptReq_AppVer ) == TRUE )
447 XcptPvt::letCallback( QtOS2SysXcptReq_AppVer );
448 else
449 fprintf( file, "unknown" );
450 fprintf( file, "\">\n" );
451
452 if ( XcptPvt::askCallback( QtOS2SysXcptReq_ReportTo ) == TRUE )
453 {
454 fprintf( file, " <Report to=\"" );
455 XcptPvt::letCallback( QtOS2SysXcptReq_ReportTo );
456 if ( XcptPvt::askCallback( QtOS2SysXcptReq_ReportSubj ) == TRUE )
457 {
458 fprintf( file, "\" subject=\"" );
459 XcptPvt::letCallback( QtOS2SysXcptReq_ReportSubj );
460 }
461 fprintf( file, "\"/>\n" );
462 }
463
464 fprintf( file, " </Application>\n" );
465 }
466
467 // *** system info
468
469 DosQuerySysInfo( QSV_VERSION_MAJOR, QSV_VERSION_REVISION,
470 &aulBuf, sizeof(aulBuf) );
471 // Warp 3 is reported as 20.30
472 // Warp 4 is reported as 20.40
473 // Aurora is reported as 20.45
474
475 fprintf( file,
476 " <System name=\"OS/2\" version=\"%u.%u.%u\"/>\n",
477 aulBuf[0], aulBuf[1], aulBuf[2] );
478
479 // *** process info
480
481 if ( ppib )
482 {
483 fprintf( file,
484 " <Process ID=\"%04lX\" parentID=\"%04lX\">\n"
485 " <Module ID=\"%04lX\" name=\"",
486 ppib->pib_ulpid, ppib->pib_ulppid, ppib->pib_hmte );
487 qt_excEscapeString( file, pszExeName );
488 fprintf( file,
489 "\"/>\n"
490 " </Process>\n" );
491 }
492 else
493 qt_excWriteErrorMsg( file, 1, "ppib is NULL" );
494
495 fprintf( file, " <Threads>\n" );
496
497 if ( ptib && ptib->tib_ptib2 )
498 qt_excWriteThreadInfo( file, ptib, pReportRec, pContextRec );
499 else if ( !ptib )
500 qt_excWriteErrorMsg( file, 1, "ptib is NULL" );
501 else
502 qt_excWriteErrorMsg( file, 1, "ptib->tib_ptib2 is NULL" );
503
504 fprintf( file, " </Threads>\n" );
505}
506
507/**
508 * Opens an unique log file using \a pcszBasePath as the base path.
509 * On input, \a pszFileName is the desired base file name w/o extension.
510 * If it doesn't fit into the file name length limit (ENAMETOOLONG) for the
511 * FS of the given disk, then a 8x3 file name is attemptet as a fallback.
512 * On output, \a pszFileName will contain the full file name of the opened
513 * log file. Note that \a pszFileName must be at least CCHMAXPATH bytes length.
514 */
515static FILE *qt_excOpenLogFile( const char *pcszBasePath, char *pszFileName )
516{
517 FILE *file = NULL;
518
519 char szFileName[CCHMAXPATH];
520 char szDir[] = "\\.qt3traps";
521 char szFile[] = "\\12345678.123";
522 enum { cbFileName = sizeof(szFileName) };
523 enum { cbDir = sizeof(szDir) };
524 enum { cbFile = sizeof(szFile) };
525
526 ULONG ul = 0;
527 ULONG cbDirLen = 0;
528 ULONG cbLen = 0;
529 ULONG ulStamp = 0;
530 char *pszStamp = NULL;
531
532 if ( pcszBasePath == NULL || pszFileName == NULL )
533 return NULL;
534
535 if ( access( pcszBasePath, F_OK ) != 0 )
536 return NULL;
537
538 if ( strlen( pcszBasePath ) + cbDir + cbFile - 2 >= CCHMAXPATH )
539 return NULL;
540
541 // get the full path if it's not 'X:'
542 if ( strlen(pcszBasePath) != 2 ||
543 pcszBasePath[1] != ':' )
544 {
545 if( DosQueryPathInfo( pcszBasePath, FIL_QUERYFULLNAME,
546 szFileName, cbFileName ) != NO_ERROR )
547 return NULL;
548 }
549 else
550 strcpy( szFileName, pcszBasePath );
551
552 strcat( szFileName, szDir );
553 if ( access( szFileName, F_OK ) != 0 )
554 if ( mkdir( szFileName, 0777 ) != 0 )
555 return NULL;
556
557 cbDirLen = strlen( szFileName );
558
559 // first, try to use the desired base file name
560
561 // we will append -NN to the file name to add some 'fraction of a
562 // second' granularity to avoid name conflicts (0 <= NNN <= 99)
563 cbLen = strlen( pszFileName );
564 if ( cbDirLen + cbLen + 8 /* \-NN.xml */ < CCHMAXPATH )
565 {
566 strcat( szFileName, "\\" );
567 strcat( szFileName, pszFileName );
568 cbLen += cbDirLen + 1 /* \ */;
569 for( ul = 0; ul < 100; ++ul )
570 {
571 sprintf( szFileName + cbLen, "-%02ld.xml", ul );
572 if ( access( szFileName, F_OK ) == 0 )
573 continue;
574 file = fopen( szFileName, "wt" );
575 if ( file )
576 break;
577 if ( errno == ENAMETOOLONG )
578 break;
579 }
580 }
581
582 // next, try a time stamp as a 8x3 file name
583 if ( file == NULL )
584 {
585 pszStamp = szFileName + cbDirLen + 1;
586 strcat( szFileName, szFile );
587
588 ulStamp = time( NULL );
589
590 // In order to add some 'fraction of a second' granularity to the
591 // timestamp, we shift it by 5 bits. This gives us 0x07FFFFFF seconds
592 // which is a period of approx. 4,25 years. 5 bits in turn give us 32
593 // fractions of a second.
594 ulStamp <<= 5;
595
596 // try some few adajcent stamps if the first one fails
597 for ( ul = 0; ul < 32; ++ul, ++ulStamp )
598 {
599 sprintf( pszStamp, "%08lX.xml", ulStamp );
600 if ( access( szFileName, F_OK ) == 0 )
601 continue;
602 file = fopen( szFileName, "wt" );
603 if ( file )
604 break;
605 }
606 }
607
608 if ( file )
609 {
610 strncpy( pszFileName, szFileName, CCHMAXPATH - 1 );
611 pszFileName[CCHMAXPATH - 1] = '\0';
612 }
613
614 return file;
615}
616
617/*! \internal
618 Qt Exception handler.
619*/
620/* static */
621ULONG APIENTRY
622QtOS2SysXcptMainHandler::handler( PEXCEPTIONREPORTRECORD pReportRec,
623 PEXCEPTIONREGISTRATIONRECORD pRegRec,
624 PCONTEXTRECORD pContextRec,
625 PVOID pv )
626{
627 PTIB ptib = NULL;
628 PPIB ppib = NULL;
629
630 /* From the VAC++3 docs:
631 * "The first thing an exception handler should do is check the
632 * exception flags. If EH_EXIT_UNWIND is set, meaning
633 * the thread is ending, the handler tells the operating system
634 * to pass the exception to the next exception handler. It does the
635 * same if the EH_UNWINDING flag is set, the flag that indicates
636 * this exception handler is being removed.
637 * The EH_NESTED_CALL flag indicates whether the exception
638 * occurred within an exception handler. If the handler does
639 * not check this flag, recursive exceptions could occur until
640 * there is no stack remaining."
641 *
642 * So for all these conditions, we exit immediately.
643 */
644
645 if ( pReportRec->fHandlerFlags &
646 (EH_EXIT_UNWIND | EH_UNWINDING | EH_NESTED_CALL) )
647 return XCPT_CONTINUE_SEARCH;
648
649 // can it ever fail?...
650 DosGetInfoBlocks( &ptib, &ppib );
651
652 switch (pReportRec->ExceptionNum)
653 {
654 case XCPT_ACCESS_VIOLATION:
655 case XCPT_INTEGER_DIVIDE_BY_ZERO:
656 case XCPT_ILLEGAL_INSTRUCTION:
657 case XCPT_PRIVILEGED_INSTRUCTION:
658 case XCPT_INVALID_LOCK_SEQUENCE:
659 case XCPT_INTEGER_OVERFLOW:
660 {
661 // "real" exceptions:
662
663 DATETIME dt;
664 char szFileName[CCHMAXPATH];
665 FILE *file = NULL;
666 char szExeName[CCHMAXPATH] = "unknown";
667 char szExeBase[CCHMAXPATH];
668
669 DosBeep( 880, 200 );
670
671 if ( ppib )
672 {
673 // get the main module name
674 DosQueryModuleName( ppib->pib_hmte, sizeof(szExeName),
675 szExeName );
676
677 // find the base name (w/o path and extension)
678 char *psz = strrchr( szExeName, '\\' );
679 if ( psz )
680 ++ psz;
681 if ( !psz )
682 psz = szExeName;
683 strcpy( szExeBase, psz );
684 psz = strrchr( szExeBase, '.' );
685 if ( psz )
686 *psz = '\0';
687 }
688
689 // compose the desired base file name for the log file
690 // (<datetime>-<exe>)
691 DosGetDateTime( &dt );
692 sprintf( szFileName, "%04d%02d%02d%02d%02d%02d-%s",
693 dt.year, dt.month, dt.day,
694 dt.hours, dt.minutes, dt.seconds,
695 szExeBase );
696
697 // open the log file:
698
699 // first try the home directory, then the root drive
700 // (see QDir::homeDirPath())
701 file = qt_excOpenLogFile( getenv( "HOME" ), szFileName );
702 if ( file == NULL )
703 {
704 char *pszHomeDrive = getenv( "HOMEDRIVE" );
705 char *pszHomePath = getenv( "HOMEPATH" );
706 if ( pszHomeDrive && pszHomePath &&
707 strlen( pszHomeDrive ) + strlen( pszHomePath ) < CCHMAXPATH )
708 {
709 char szHomePath[CCHMAXPATH];
710 strcpy( szHomePath, pszHomeDrive );
711 strcat( szHomePath, pszHomePath );
712 file = qt_excOpenLogFile( szHomePath, szFileName );
713 }
714 }
715 if ( file == NULL )
716 {
717 static char szBootDrive[] = "\0:";
718 if ( !szBootDrive[0] )
719 {
720 ULONG ulBootDrive;
721 DosQuerySysInfo( QSV_BOOT_DRIVE, QSV_BOOT_DRIVE,
722 &ulBootDrive, sizeof(ulBootDrive) );
723 szBootDrive[0] = (char) ulBootDrive + 'A' - 1;
724 }
725 file = qt_excOpenLogFile( szBootDrive, szFileName );
726 }
727
728 if ( file != NULL )
729 {
730 fprintf( file,
731 "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
732 "<!--\n"
733 " A fatal error has occured while running this application.\n"
734 " Please contact the application vendor, describe what happened\n"
735 " and send the contents of this file saved locally as\n"
736 " '%s'.\n"
737 "-->\n",
738 szFileName );
739
740 fprintf( file,
741 "<Trap timestamp=\"%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d\" "
742 "version=\"1.0\"\n"
743 " generator=\"Qt Library Version %s\"\n"
744 " xmlns=\"http://db.hugaida.com/xml/os2/sys/Trap\">\n",
745 dt.year, dt.month, dt.day,
746 dt.hours, dt.minutes, dt.seconds,
747 (dt.timezone > 0 ? '-' : '+'),
748 abs( dt.timezone / 60 ),
749 abs( dt.timezone % 60 ),
750 QT_VERSION_STR );
751
752 XcptPvt::file = file;
753
754 // write trap information
755 qt_excWriteException( file, szExeName, szExeBase,
756 ppib, ptib, pReportRec, pContextRec );
757
758 XcptPvt::file = NULL;
759
760 fprintf( file, "</Trap>\n\n" );
761 fclose( file );
762
763 // attempt to display the created file
764 {
765 STARTDATA SData = {0};
766 PID pid = 0;
767 ULONG ulSessID = 0;
768
769 SData.Length = sizeof(STARTDATA);
770 SData.PgmName = "E.EXE";
771 SData.PgmInputs = szFileName;
772
773 DosStartSession( &SData, &ulSessID, &pid );
774 }
775 }
776 else
777 DosBeep( 220, 200 );
778 }
779 break;
780 }
781
782 // we never handle the exception ourselves
783
784 if ( ptib && ptib->tib_ptib2 && ptib->tib_ptib2->tib2_ultid == 1 &&
785 QtOS2SysXcptMainHandler::libcHandler != NULL )
786 {
787 // we are on the main thread and were installed from qt_init() during
788 // QApplication initialization using a hack; pass control back to the
789 // LIBC exception handler
790 return QtOS2SysXcptMainHandler::libcHandler( pReportRec, pRegRec,
791 pContextRec, pv );
792 }
793
794 return XCPT_CONTINUE_SEARCH;
795}
796
797#endif // !defined(QT_PM_NO_SYSEXCEPTIONS)
Note: See TracBrowser for help on using the repository browser.