source: trunk/src/kernel/qsysxcpt_pm.cpp@ 138

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

Fixed: Forgot to set the Id keyword substitution.

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