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

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

Kernel/Tools: Improved OS/2 exception handling:

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