source: trunk/src/kernel32/exceptions.cpp@ 21999

Last change on this file since 21999 was 21999, checked in by dmik, 13 years ago

kernel32: Make SEH work in OS/2 context.

See #82 for details.

File size: 72.0 KB
Line 
1/* $Id: exceptions.cpp,v 1.74 2004-01-20 13:41:10 sandervl Exp $ */
2
3/*
4 * Win32 Exception functions for OS/2
5 *
6 * Ported Wine exception handling code
7 *
8 * Copyright 1998 Sander van Leeuwen (OS/2 port)
9 *
10 *
11 * Project Odin Software License can be found in LICENSE.TXT
12 *
13 *
14 * (dlls\ntdll\exception.c)
15 *
16 * Copyright 1999 Turchanov Sergey
17 * Copyright 1999 Alexandre Julliard
18 *
19 * (win32\except.c)
20 *
21 * Win32 exception functions
22 *
23 * Copyright (c) 1996 Onno Hovers, (onno@stack.urc.tue.nl)
24 *
25 * Notes:
26 * What really happens behind the scenes of those new
27 * __try{...}__except(..){....} and
28 * __try{...}__finally{...}
29 * statements is simply not documented by Microsoft. There could be different
30 * reasons for this:
31 * One reason could be that they try to hide the fact that exception
32 * handling in Win32 looks almost the same as in OS/2 2.x.
33 * Another reason could be that Microsoft does not want others to write
34 * binary compatible implementations of the Win32 API (like us).
35 *
36 * Whatever the reason, THIS SUCKS!! Ensuring portabilty or future
37 * compatability may be valid reasons to keep some things undocumented.
38 * But exception handling is so basic to Win32 that it should be
39 * documented!
40 *
41 * Fixmes:
42 * -Most functions need better parameter checking.
43 * -I do not know how to handle exceptions within an exception handler.
44 * or what is done when ExceptionNestedException is returned from an
45 * exception handler
46 * -Real exceptions are not yet implemented. only the exception functions
47 * are implemented. A real implementation needs some new code in
48 * loader/signal.c. There would also be a need for showing debugging
49 * information in UnhandledExceptionFilter.
50 *
51 */
52#define INCL_MISC
53#define INCL_BASE
54#define INCL_WIN
55#define INCL_WINBUTTONS
56#include <os2wrap.h> //Odin32 OS/2 api wrappers
57#include <stdio.h>
58#include <stdlib.h>
59#include <assert.h>
60#include <time.h>
61#include <string.h>
62#include <pmscan.h>
63#include "exceptions.h"
64#include "exceptutil.h"
65#include <misc.h>
66#include "mmap.h"
67#include <wprocess.h>
68#include <win32api.h>
69#include "oslibexcept.h"
70#include "oslibmem.h"
71#include "exceptstackdump.h"
72#include "hmthread.h"
73
74#include "WinImageBase.h"
75#include "WinDllBase.h"
76#include "WinExeBase.h"
77
78/* Really lazy! But, including wincon.h means lot's of missing COORD. */
79#define CTRL_C_EVENT 0 //#include <wincon.h>
80#define CTRL_BREAK_EVENT 1 //#include <wincon.h>
81#include "console.h"
82#include "initterm.h"
83
84
85#define DBG_LOCALLOG DBG_exceptions
86#include "dbglocal.h"
87
88#include <_ras.h>
89
90#ifdef WITH_KLIB
91/* quick and dirty - don't wanna mess with includes. */
92typedef enum { enmRead, enmWrite, enmUnknown } ENMACCESS;
93BOOL _Optlink kHeapDbgException(void * pvAccess,
94 ENMACCESS enmAccess,
95 void * pvIP,
96 void * pvOS);
97#endif
98
99/* Exception record for handling exceptions happening inside exception handlers */
100typedef struct
101{
102 WINEXCEPTION_FRAME frame;
103 WINEXCEPTION_FRAME *prevFrame;
104} EXC_NESTED_FRAME;
105
106//Global Process Unhandled exception filter
107static LPTOP_LEVEL_EXCEPTION_FILTER CurrentUnhExceptionFlt = NULL;
108static UINT CurrentErrorMode = 0;
109static PEXCEPTION_HANDLER StartupCodeHandler = NULL;
110
111extern "C" {
112
113PWINEXCEPTION_FRAME GetExceptionRecord(ULONG offset, ULONG segment);
114
115LONG WIN32API UnhandledExceptionFilter(PWINEXCEPTION_POINTERS lpexpExceptionInfo);
116void KillWin32Process(void);
117
118static void sprintfException(PEXCEPTIONREPORTRECORD pERepRec,
119 PEXCEPTIONREGISTRATIONRECORD pERegRec,
120 PCONTEXTRECORD pCtxRec, PVOID p, PSZ szTrapDump);
121
122int __cdecl __seh_handler(PVOID pRec, PVOID pFrame,
123 PVOID pContext, PVOID pVoid);
124
125int __cdecl __seh_handler_win32(PWINEXCEPTION_RECORD pRec,
126 PWINEXCEPTION_FRAME pFrame,
127 PCONTEXTRECORD pContext, PVOID pVoid);
128
129PWINEXCEPTION_FRAME __cdecl __seh_get_prev_frame_win32(PWINEXCEPTION_FRAME pFrame);
130
131#ifdef DEBUG
132static void PrintWin32ExceptionChain(PWINEXCEPTION_FRAME pframe);
133#else
134#define PrintWin32ExceptionChain(a)
135#endif
136
137/*****************************************************************************
138 * Name : UINT SetErrorMode
139 * Purpose :
140 * Parameters: UINT fuErrorMode
141 * Variables :
142 * Result :
143 * Remark :
144 * Status :
145 *
146 * Author : Sander van Leeuwen [Tue, 1999/07/01 09:00]
147 *****************************************************************************/
148
149UINT WIN32API SetErrorMode(UINT fuErrorMode)
150{
151 UINT oldmode = CurrentErrorMode;
152
153 dprintf(("KERNEL32: SetErrorMode(%08xh)\n",
154 fuErrorMode));
155 CurrentErrorMode = fuErrorMode;
156
157 if(fuErrorMode & SEM_FAILCRITICALERRORS || fuErrorMode & SEM_NOOPENFILEERRORBOX)
158 DosError(FERR_DISABLEHARDERR);
159 else
160 DosError(FERR_ENABLEHARDERR);
161
162 // SEM_NOGPFAULTERRORBOX and SEM_NOALIGNMENTFAULTEXCEPT --> UnhandledExceptionFilter()
163
164 return(oldmode);
165}
166
167#ifdef __EMX__
168static inline WINEXCEPTION_FRAME * EXC_push_frame( WINEXCEPTION_FRAME *frame )
169{
170 // TODO: rewrite in assembly
171 TEB *teb = GetThreadTEB();
172 frame->Prev = (PWINEXCEPTION_FRAME)teb->except;
173 teb->except = frame;
174 return frame->Prev;
175}
176
177static inline WINEXCEPTION_FRAME * EXC_pop_frame( WINEXCEPTION_FRAME *frame )
178{
179 // TODO: rewrite in assembly
180 TEB *teb = GetThreadTEB();
181 teb->except = frame->Prev;
182 return frame->Prev;
183}
184#endif
185
186/*****************************************************************************
187 * Name : VOID __cdecl OS2RaiseException
188 * Purpose : Unwinds exception handlers (heavily influenced by Wine)
189 * Parameters: ...
190 * Variables :
191 * Result :
192 * Remark :
193 * Status :
194 *
195 * Author : Sander van Leeuwen [Tue, 1999/07/01 09:00]
196 *****************************************************************************/
197
198void WIN32API RtlRaiseException(WINEXCEPTION_RECORD *rec, WINCONTEXT *context);
199
200VOID __cdecl OS2RaiseException(DWORD dwExceptionCode,
201 DWORD dwExceptionFlags,
202 DWORD cArguments,
203 DWORD *lpArguments,
204 DWORD eip, DWORD esp, DWORD ebp, DWORD flags,
205 DWORD eax, DWORD ebx, DWORD ecx, DWORD edx,
206 DWORD edi, DWORD esi, DWORD cs, DWORD ds,
207 DWORD es, DWORD fs, DWORD gs, DWORD ss)
208{
209 WINEXCEPTION_RECORD record;
210 WINEXCEPTION_POINTERS ExceptionInfo;
211 WINCONTEXT context;
212 int rc;
213 int i;
214
215 dprintf(("KERNEL32: RaiseException(%08xh)\n",
216 dwExceptionCode));
217
218 memset(&record, 0, sizeof(record));
219
220 /* compose an exception record */
221 record.ExceptionCode = dwExceptionCode;
222 record.ExceptionFlags = dwExceptionFlags;
223 record.ExceptionRecord = NULL;
224 record.NumberParameters = cArguments;
225 record.ExceptionAddress = (LPVOID)eip;
226
227 memset(&context, 0, sizeof(context));
228 context.ContextFlags = WINCONTEXT_FULL; //segments, integer, control
229 context.SegGs = gs;
230 context.SegFs = fs;
231 context.SegEs = es;
232 context.SegDs = ds;
233 context.Edi = edi;
234 context.Esi = esi;
235 context.Ebx = ebx;
236 context.Edx = edx;
237 context.Ecx = ecx;
238 context.Eax = eax;
239 context.Ebp = ebp;
240 context.Eip = eip;
241 context.SegCs = cs;
242 context.EFlags = flags;
243 context.Esp = esp;
244 context.SegSs = ss;
245
246 if(lpArguments)
247 {
248 for(i=0;
249 i<cArguments;
250 i++)
251 record.ExceptionInformation[i] = lpArguments[i];
252 }
253
254 rc = RtlDispatchException(&record, &context);
255
256 // and finally, the unhandled exception filter
257 if(rc == ExceptionContinueSearch && UnhandledExceptionFilter != NULL)
258 {
259 dprintf(("KERNEL32: RaiseException calling UnhandledExceptionFilter.\n"));
260
261 ExceptionInfo.ExceptionRecord = &record;
262 ExceptionInfo.ContextRecord = &context;
263
264 rc = UnhandledExceptionFilter(&ExceptionInfo);
265 //FIXME: UnhandledExceptionFilter does NOT return the same values as
266 // other filters!!
267 }
268
269 // terminate the process
270 if(rc != ExceptionContinueExecution ||
271 record.ExceptionFlags & EH_NONCONTINUABLE)
272 {
273 dprintf(("KERNEL32: RaiseException terminating process.\n"));
274 DosExit(EXIT_PROCESS, 0);
275 }
276
277 dprintf(("KERNEL32: RaiseException returns.\n"));
278 return;
279}
280
281/*******************************************************************
282 * EXC_RaiseHandler
283 *
284 * Handler for exceptions happening inside a handler.
285 */
286static DWORD WIN32API EXC_RaiseHandler( WINEXCEPTION_RECORD *rec, WINEXCEPTION_FRAME *frame,
287// WINCONTEXT *context, WINEXCEPTION_FRAME **dispatcher )
288 WINCONTEXT *context, LPVOID dispatcher )
289{
290 if (rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND))
291 return ExceptionContinueSearch;
292 /* We shouldn't get here so we store faulty frame in dispatcher */
293 *(PWINEXCEPTION_FRAME*)dispatcher = ((EXC_NESTED_FRAME*)frame)->prevFrame;
294 return ExceptionNestedException;
295}
296
297/*******************************************************************
298 * EXC_UnwindHandler
299 *
300 * Handler for exceptions happening inside an unwind handler.
301 */
302static DWORD WIN32API EXC_UnwindHandler( WINEXCEPTION_RECORD *rec, WINEXCEPTION_FRAME *frame,
303// WINCONTEXT *context, WINEXCEPTION_FRAME **dispatcher )
304 WINCONTEXT *context, LPVOID dispatcher )
305{
306 if (!(rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND)))
307 return ExceptionContinueSearch;
308 /* We shouldn't get here so we store faulty frame in dispatcher */
309 *(PWINEXCEPTION_FRAME*)dispatcher = ((EXC_NESTED_FRAME*)frame)->prevFrame;
310 return ExceptionCollidedUnwind;
311}
312
313#ifndef __EMX__
314extern "C"
315DWORD EXC_CallHandler( WINEXCEPTION_RECORD *record, WINEXCEPTION_FRAME *frame,
316 WINCONTEXT *context, WINEXCEPTION_FRAME **dispatcher,
317 PEXCEPTION_HANDLER handler, PEXCEPTION_HANDLER nested_handler);
318
319#else
320/*******************************************************************
321 * EXC_CallHandler
322 *
323 * Call an exception handler, setting up an exception frame to catch exceptions
324 * happening during the handler execution.
325 * WARNING:
326 * Please do not change the first 4 parameters order in any way - some exceptions handlers
327 * rely on Base Pointer (EBP) to have a fixed position related to the exception frame
328 */
329static DWORD EXC_CallHandler( WINEXCEPTION_RECORD *record, WINEXCEPTION_FRAME *frame,
330 WINCONTEXT *context, WINEXCEPTION_FRAME **dispatcher,
331 PEXCEPTION_HANDLER handler, PEXCEPTION_HANDLER nested_handler)
332{
333 EXC_NESTED_FRAME newframe;
334 DWORD ret;
335
336 newframe.frame.Handler = nested_handler;
337 newframe.prevFrame = frame;
338 EXC_push_frame( &newframe.frame );
339 dprintf(("KERNEL32: Calling handler at %p code=%lx flags=%lx\n",
340 handler, record->ExceptionCode, record->ExceptionFlags));
341 ret = handler( record, frame, context, dispatcher );
342 dprintf(("KERNEL32: Handler returned %lx\n", ret));
343 EXC_pop_frame( &newframe.frame );
344 return ret;
345}
346#endif
347//******************************************************************************
348//******************************************************************************
349DWORD RtlDispatchException(WINEXCEPTION_RECORD *pRecord, WINCONTEXT *pContext)
350{
351 PWINEXCEPTION_FRAME pFrame, pPrevFrame, dispatch, nested_frame;
352 int rc;
353
354 // get chain of exception frames
355 rc = ExceptionContinueSearch;
356
357 nested_frame = NULL;
358 TEB *winteb = GetThreadTEB();
359 pFrame = (PWINEXCEPTION_FRAME)winteb->except;
360
361 dprintf(("KERNEL32: RtlDispatchException entered"));
362
363 PrintWin32ExceptionChain(pFrame);
364
365 // walk the exception chain
366 while( (pFrame != NULL) && ((ULONG)((ULONG)pFrame & 0xFFFFF000) != 0xFFFFF000) )
367 {
368 pPrevFrame = __seh_get_prev_frame_win32(pFrame);
369
370 dprintf(("KERNEL32: RtlDispatchException - pframe=%08X, pframe->Prev=%08X",
371 pFrame, pPrevFrame));
372 if (pFrame == pPrevFrame) {
373 dprintf(("KERNEL32: RtlDispatchException - Invalid exception frame!!"));
374 return 0;
375 }
376
377 dispatch=0;
378
379 /* Check frame address */
380 if (((void*)pFrame < winteb->stack_low) ||
381 ((void*)(pFrame+1) > winteb->stack_top) ||
382 (int)pFrame & 3)
383 {
384 dprintf(("Invalid stack! low=%08X, top=%08X, pframe = %08X",
385 winteb->stack_low, winteb->stack_top, pFrame));
386
387 pRecord->ExceptionFlags |= EH_STACK_INVALID;
388 break;
389 }
390
391
392 /* call handler */
393 if (pFrame->Handler)
394 {
395 rc = EXC_CallHandler(pRecord, pFrame, pContext, &dispatch,
396 pFrame->Handler, EXC_RaiseHandler);
397 }
398 else
399 {
400 dprintf(("pFrame->Handler is NULL!!!!!"));
401 rc = ExceptionContinueSearch;
402 }
403
404 PrintWin32ExceptionChain(pFrame);
405
406 if (pFrame == nested_frame)
407 {
408 /* no longer nested */
409 nested_frame = NULL;
410 pRecord->ExceptionFlags &= ~EH_NESTED_CALL;
411 }
412
413
414 switch(rc)
415 {
416 case ExceptionContinueExecution:
417 if (!(pRecord->ExceptionFlags & EH_NONCONTINUABLE))
418 {
419 dprintf(("KERNEL32: RtlDispatchException returns %#x (ContinueExecution)", rc));
420 return rc;
421 }
422 break;
423 case ExceptionContinueSearch:
424 break;
425 case ExceptionNestedException:
426 if (nested_frame < dispatch) nested_frame = dispatch;
427 pRecord->ExceptionFlags |= EH_NESTED_CALL;
428 break;
429 default:
430 break;
431 }
432
433 dprintf(("KERNEL32: RtlDispatchException - going from frame %08X to previous frame %08X",
434 pFrame, pPrevFrame));
435 if (pFrame == pPrevFrame)
436 {
437 dprintf(("KERNEL32: RtlDispatchException - Invalid exception frame!!"));
438 break;
439 }
440 pFrame = pPrevFrame;
441 }
442 dprintf(("KERNEL32: RtlDispatchException returns %#x", rc));
443 PrintWin32ExceptionChain(pFrame);
444 return rc;
445}
446/*****************************************************************************
447 * Name : int __cdecl OS2RtlUnwind
448 * Purpose : Unwinds exception handlers (heavily influenced by Wine)
449 * Parameters: ...
450 * Variables :
451 * Result :
452 * Remark :
453 * Status :
454 *
455 * Author : Sander van Leeuwen [Tue, 1999/07/01 09:00]
456 *****************************************************************************/
457
458int __cdecl OS2RtlUnwind(PWINEXCEPTION_FRAME pEndFrame,
459 LPVOID unusedEip,
460 PWINEXCEPTION_RECORD pRecord,
461 DWORD returnEax,
462 DWORD eip, DWORD esp, DWORD ebp, DWORD flags,
463 DWORD eax, DWORD ebx, DWORD ecx, DWORD edx,
464 DWORD edi, DWORD esi, DWORD cs, DWORD ds,
465 DWORD es, DWORD fs, DWORD gs, DWORD ss)
466{
467 PWINEXCEPTION_FRAME frame, prevFrame, dispatch;
468 WINEXCEPTION_RECORD record; //, newrec;
469 WINCONTEXT context;
470 DWORD rc;
471
472 dprintf(("KERNEL32: RtlUnwind pEndFrame=%08X, unusedEip=%08X, pRecord=%08X, returnEax=%#x\n", pEndFrame, unusedEip, pRecord, returnEax));
473
474 TEB *winteb = GetThreadTEB();
475 if (!winteb)
476 {
477 dprintf(("KERNEL32: RtlUnwind TEB is NULL\n"));
478 DebugInt3();
479 return 0;
480 }
481
482 memset(&context, 0, sizeof(context));
483 context.ContextFlags = WINCONTEXT_FULL; //segments, integer, control
484 context.SegGs = gs;
485 context.SegFs = fs;
486 context.SegEs = es;
487 context.SegDs = ds;
488 context.Edi = edi;
489 context.Esi = esi;
490 context.Ebx = ebx;
491 context.Edx = edx;
492 context.Ecx = ecx;
493 context.Eax = returnEax;
494 context.Ebp = ebp;
495 context.Eip = eip;
496 context.SegCs = cs;
497 context.EFlags = flags;
498 context.Esp = esp;
499 context.SegSs = ss;
500
501 /* build an exception record, if we do not have one */
502 if(!pRecord)
503 {
504 memset(&record, 0, sizeof(record));
505 record.ExceptionCode = STATUS_UNWIND;
506 record.ExceptionFlags = 0;
507 record.ExceptionRecord = NULL;
508 record.ExceptionAddress = (LPVOID)eip;
509 record.NumberParameters = 0;
510 pRecord = &record;
511 }
512
513 if(pEndFrame) pRecord->ExceptionFlags |= EH_UNWINDING;
514 else pRecord->ExceptionFlags |= EH_UNWINDING | EH_EXIT_UNWIND;
515
516 /* get chain of exception frames */
517 frame = (PWINEXCEPTION_FRAME)winteb->except;
518
519 PrintWin32ExceptionChain(frame);
520
521 while (((ULONG)((ULONG)frame & 0xFFFFF000) != 0xFFFFF000) && (frame != pEndFrame))
522 {
523 prevFrame = __seh_get_prev_frame_win32(frame);
524
525 /* Check frame address */
526 if (pEndFrame && (frame > pEndFrame))
527 {
528#if 0
529 // TODO
530 newrec.ExceptionCode = STATUS_INVALID_UNWIND_TARGET;
531 newrec.ExceptionFlags = EH_NONCONTINUABLE;
532 newrec.ExceptionRecord = pRecord;
533 newrec.NumberParameters = 0;
534 RtlRaiseException(&newrec, NULL);
535#else
536 dprintf(("KERNEL32: RtlUnwind terminating thread (invalid target).\n"));
537 DosExit(EXIT_THREAD, 0);
538#endif
539 }
540 if (((void*)frame < winteb->stack_low) ||
541 ((void*)(frame+1) > winteb->stack_top) ||
542 (int)frame & 3)
543 {
544#if 0
545 // TODO
546 newrec.ExceptionCode = STATUS_BAD_STACK;
547 newrec.ExceptionFlags = EH_NONCONTINUABLE;
548 newrec.ExceptionRecord = pRecord;
549 newrec.NumberParameters = 0;
550#else
551 dprintf(("KERNEL32: RtlUnwind terminating thread (bad stack).\n"));
552 DosExit(EXIT_THREAD, 0);
553#endif
554 }
555
556 /* Call handler */
557 dprintf(("KERNEL32: RtlUnwind - calling exception handler %08X", frame->Handler));
558 if(frame->Handler) {
559 // ensure the Win32 FS (may be accessed directly in the handler)
560 DWORD oldsel = SetReturnFS(winteb->teb_sel);
561 rc = EXC_CallHandler(pRecord, frame, &context, &dispatch, frame->Handler, EXC_UnwindHandler );
562 // restore FS
563 SetFS(oldsel);
564 }
565 else {
566 dprintf(("pFrame->Handler is NULL!!!!!"));
567 rc = ExceptionContinueSearch;
568 }
569 dprintf(("KERNEL32: RtlUnwind - handler returned %#x", rc));
570 switch (rc)
571 {
572 case ExceptionContinueSearch:
573 break;
574 case ExceptionCollidedUnwind:
575 frame = dispatch;
576 break;
577 default:
578#if 0
579 // TODO
580 newrec.ExceptionCode = STATUS_INVALID_DISPOSITION;
581 newrec.ExceptionFlags = EH_NONCONTINUABLE;
582 newrec.ExceptionRecord = pRecord;
583 newrec.NumberParameters = 0;
584#else
585 dprintf(("KERNEL32: RtlUnwind terminating thread (invalid disposition).\n"));
586 DosExit(EXIT_THREAD, 0);
587#endif
588 break;
589 }
590 dprintf(("KERNEL32: RtlUnwind (before)- frame=%08X, frame->Prev=%08X", frame, prevFrame));
591 winteb->except = (void*)prevFrame;
592 frame = prevFrame;
593 dprintf(("KERNEL32: RtlUnwind (after) - frame=%08X, frame->Prev=%08X", frame,
594 ((ULONG)((ULONG)frame & 0xFFFFF000) != 0xFFFFF000) ?
595 __seh_get_prev_frame_win32(frame) : (void*)0xFFFFFFFF));
596 }
597
598 dprintf(("KERNEL32: RtlUnwind returning.\n"));
599 PrintWin32ExceptionChain(frame);
600 return(0);
601}
602
603
604/*****************************************************************************
605 * Name : LONG WIN32API UnhandledExceptionFilter
606 * Purpose :
607 * Parameters: ...
608 * Variables :
609 * Result :
610 * Remark :
611 * Status :
612 *
613 * Author : Sander van Leeuwen [Tue, 1999/07/01 09:00]
614 *****************************************************************************/
615
616LONG WIN32API UnhandledExceptionFilter(PWINEXCEPTION_POINTERS lpexpExceptionInfo)
617{
618 char szModName[16];
619 char message[128];
620 ULONG iObj;
621 ULONG offObj;
622 HMODULE hmod;
623 DWORD rc;
624
625 dprintf(("KERNEL32: Default UnhandledExceptionFilter, CurrentErrorMode=%X", CurrentErrorMode));
626
627 // We must not care about ErrorMode here!! The app expects that its own
628 // UnhandledExceptionFilter will be cared even if it never touched ErrorMode.
629 if(CurrentUnhExceptionFlt) // && !(CurrentErrorMode & (SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX)))
630 {
631 dprintf(("KERNEL32: Calling user UnhandledExceptionFilter"));
632 rc = CurrentUnhExceptionFlt(lpexpExceptionInfo);
633 if(rc != WINEXCEPTION_CONTINUE_SEARCH)
634 return rc;
635 }
636
637 if (DosQueryModFromEIP(&hmod, &iObj, sizeof(szModName), szModName, &offObj, (ULONG)lpexpExceptionInfo->ExceptionRecord->ExceptionAddress))
638 sprintf(message, "Unhandled exception 0x%08lx at address 0x%08lx. (DQMFEIP rc=%d)",
639 lpexpExceptionInfo->ExceptionRecord->ExceptionCode,
640 lpexpExceptionInfo->ExceptionRecord->ExceptionAddress);
641 else
642 {
643 if (iObj == -1)
644 { /* fault in DosAllocMem allocated memory, hence PE loader.. */
645 Win32ImageBase * pMod;
646 if (WinExe && WinExe->insideModule((ULONG)lpexpExceptionInfo->ExceptionRecord->ExceptionAddress))
647 pMod = WinExe;
648 else
649 pMod = Win32DllBase::findModuleByAddr((ULONG)lpexpExceptionInfo->ExceptionRecord->ExceptionAddress);
650 if (pMod != NULL)
651 {
652 szModName[0] = '\0';
653 strncat(szModName, pMod->getModuleName(), sizeof(szModName) - 1);
654 iObj = 0xFF;
655 offObj = (ULONG)lpexpExceptionInfo->ExceptionRecord->ExceptionAddress
656 - (ULONG)pMod->getInstanceHandle();
657 }
658 }
659 sprintf(message,
660 "Unhandled exception 0x%08lx at address 0x%08lx.\r"
661 "Mod: %s obj: 0x%2lx off:0x%08lx",
662 lpexpExceptionInfo->ExceptionRecord->ExceptionCode,
663 lpexpExceptionInfo->ExceptionRecord->ExceptionAddress,
664 szModName, iObj, offObj);
665 }
666
667/* This is very dangerous. Can hang PM.
668 rc = WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, message, "Application Error",
669 0, MB_ABORTRETRYIGNORE | MB_ERROR);
670 switch (rc)
671 {
672 case MBID_IGNORE:
673 return WINEXCEPTION_CONTINUE_EXECUTION;
674
675 case MBID_ABORT:
676 case MBID_RETRY:
677 default:
678 return WINEXCEPTION_EXECUTE_HANDLER;
679 }
680*/
681 return WINEXCEPTION_EXECUTE_HANDLER;
682}
683/*****************************************************************************
684 * Name : LPTOP_LEVEL_EXCEPTION_FILTER WIN32API SetUnhandledExceptionFilter
685 * Purpose :
686 * Parameters: ...
687 * Variables :
688 * Result :
689 * Remark :
690 * Status :
691 *
692 * Author : Sander van Leeuwen [Tue, 1999/07/01 09:00]
693 *****************************************************************************/
694
695LPTOP_LEVEL_EXCEPTION_FILTER WIN32API SetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter)
696{
697 LPTOP_LEVEL_EXCEPTION_FILTER old = CurrentUnhExceptionFlt;
698
699 dprintf(("KERNEL32: SetUnhandledExceptionFilter to %08X\n",
700 lpTopLevelExceptionFilter));
701
702 CurrentUnhExceptionFlt = lpTopLevelExceptionFilter;
703
704 return(old);
705}
706
707
708/*****************************************************************************
709 * Name : KillWin32Process
710 * Purpose :
711 * Parameters: ...
712 * Variables :
713 * Result :
714 * Remark :
715 * Status :
716 *
717 * Author : Sander van Leeuwen [Tue, 1999/07/01 09:00]
718 *****************************************************************************/
719
720
721//******************************************************************************
722VOID WIN32API ExitProcess(DWORD exitcode);
723//******************************************************************************
724void KillWin32Process(void)
725{
726 static BOOL fEntry = FALSE;
727
728 if(!fExitProcess && fEntry == FALSE) {
729 fEntry = TRUE;
730 ExitProcess(666);
731 return;
732 }
733 //Restore original OS/2 TIB selector
734 RestoreOS2FS();
735
736 DosExit(EXIT_PROCESS, 666);
737}
738//*****************************************************************************
739//*****************************************************************************
740void KillWin32Thread(void)
741{
742// ExitThread(666);
743 //Restore original OS/2 TIB selector
744 RestoreOS2FS();
745
746 DosExit(EXIT_THREAD, 666);
747}
748//*****************************************************************************
749//*****************************************************************************
750static void sprintfException(PEXCEPTIONREPORTRECORD pERepRec,
751 PEXCEPTIONREGISTRATIONRECORD pERegRec,
752 PCONTEXTRECORD pCtxRec,
753 PVOID p,
754 PSZ szTrapDump)
755{
756 if(pERepRec->ExceptionNum == XCPT_GUARD_PAGE_VIOLATION)
757 {
758 strcpy(szTrapDump, "Guard Page Violation");
759 return;
760 }
761
762 PCSZ pszExceptionName = "<unknown>"; /* points to name/type excpt */
763 APIRET rc = XCPT_CONTINUE_SEARCH; /* excpt-dep. code */
764 BOOL fExcptSoftware = FALSE; /* software/hardware gen. exceptn */
765 BOOL fExcptFatal = TRUE; /* fatal exception ? */
766 BOOL fExcptPortable = TRUE; /* portability of exception */
767 PPIB pPIB; /* process information block */
768 PTIB pTIB; /* thread information block */
769 ULONG ulModule; /* module number */
770 ULONG ulObject; /* object number within the module */
771 CHAR szModule[260]; /* buffer for the module name */
772 ULONG ulOffset; /* offset within the object within the module */
773 char szLineException[512];
774 char szLineExceptionType[128];
775
776 szLineException[0] = 0; /* initialize */
777 szLineExceptionType[0] = 0; /* initialize */
778 switch(pERepRec->ExceptionNum) /* take according action */
779 {
780 /* portable, non-fatal software-generated exceptions */
781 case XCPT_GUARD_PAGE_VIOLATION:
782 strcpy(szLineException, "Guard Page Violation");
783 sprintf(szLineExceptionType, "R/W %08xh at %08xh.", pERepRec->ExceptionInfo[0], pERepRec->ExceptionInfo[1]);
784 fExcptSoftware = TRUE;
785 fExcptFatal = FALSE;
786 rc = XCPT_CONTINUE_EXECUTION;
787 break;
788
789 case XCPT_UNABLE_TO_GROW_STACK:
790 strcpy(szLineException, "Unable To Grow Stack");
791 fExcptSoftware = TRUE;
792 fExcptFatal = FALSE;
793 rc = XCPT_CONTINUE_EXECUTION;
794 break;
795
796 /* portable, fatal, hardware-generated exceptions */
797 case XCPT_ACCESS_VIOLATION:
798 strcpy(szLineException, "Access Violation");
799 switch (pERepRec->ExceptionInfo[0])
800 {
801 case XCPT_READ_ACCESS:
802 sprintf (szLineExceptionType, "Read Access at address %08xh", pERepRec->ExceptionInfo[1]);
803 break;
804
805 case XCPT_WRITE_ACCESS:
806 sprintf (szLineExceptionType, "Write Access at address %08x", pERepRec->ExceptionInfo[1]);
807 break;
808
809 case XCPT_SPACE_ACCESS:
810 sprintf (szLineExceptionType, "Space Access at selector %08x", pERepRec->ExceptionInfo[1]);
811 break;
812
813 case XCPT_LIMIT_ACCESS:
814 strcpy (szLineExceptionType, "Limit Access");
815 break;
816
817 case XCPT_UNKNOWN_ACCESS:
818 strcpy (szLineExceptionType, "Unknown Access");
819 break;
820
821 default:
822 strcpy (szLineExceptionType, "(Invalid Access Code)");
823 break;
824 }
825 break;
826
827 case XCPT_INTEGER_DIVIDE_BY_ZERO:
828 strcpy(szLineException, "Division By Zero (Integer)");
829 break;
830
831 case XCPT_FLOAT_DIVIDE_BY_ZERO:
832 strcpy(szLineException, "Division By Zero (Float)");
833 break;
834
835 case XCPT_FLOAT_INVALID_OPERATION:
836 strcpy(szLineException, "Invalid Floating Point Operation");
837 break;
838
839 case XCPT_ILLEGAL_INSTRUCTION:
840 strcpy(szLineException, "Illegal Instruction");
841 break;
842
843 case XCPT_PRIVILEGED_INSTRUCTION:
844 strcpy(szLineException, "Privileged Instruction");
845 break;
846
847 case XCPT_INTEGER_OVERFLOW:
848 strcpy(szLineException, "Integer Overflow");
849 break;
850
851 case XCPT_FLOAT_OVERFLOW:
852 strcpy(szLineException, "Floating Point Overflow");
853 break;
854
855 case XCPT_FLOAT_UNDERFLOW:
856 strcpy(szLineException, "Floating Point Underflow");
857 break;
858
859 case XCPT_FLOAT_DENORMAL_OPERAND:
860 strcpy(szLineException, "Floating Point Denormal Operand");
861 break;
862
863 case XCPT_FLOAT_INEXACT_RESULT:
864 strcpy(szLineException, "Floating Point Inexact Result");
865 break;
866
867 case XCPT_FLOAT_STACK_CHECK:
868 strcpy(szLineException, "Floating Point Stack Check");
869 break;
870
871 case XCPT_DATATYPE_MISALIGNMENT:
872 strcpy(szLineException, "Datatype Misalignment");
873 sprintf(szLineExceptionType, "R/W %08x alignment %08x at %08x.", pERepRec->ExceptionInfo[0],
874 pERepRec->ExceptionInfo[1], pERepRec->ExceptionInfo[2]);
875 break;
876
877 case XCPT_BREAKPOINT:
878 strcpy(szLineException, "Breakpoint (DEBUG)");
879 break;
880
881 case XCPT_SINGLE_STEP:
882 strcpy(szLineException, "Single Step (DEBUG)");
883 break;
884
885 /* portable, fatal, software-generated exceptions */
886 case XCPT_IN_PAGE_ERROR:
887 strcpy(szLineException, "In Page Error");
888 sprintf(szLineExceptionType, "at %08x.", pERepRec->ExceptionInfo[0]);
889 fExcptSoftware = TRUE;
890 break;
891
892 case XCPT_PROCESS_TERMINATE:
893 strcpy(szLineException, "Process Termination");
894 fExcptSoftware = TRUE;
895 break;
896
897 case XCPT_ASYNC_PROCESS_TERMINATE:
898 strcpy(szLineException, "Process Termination (async)");
899 sprintf(szLineExceptionType, "terminating thread TID=%u", pERepRec->ExceptionInfo[0]);
900 fExcptSoftware = TRUE;
901 break;
902
903 case XCPT_NONCONTINUABLE_EXCEPTION:
904 strcpy(szLineException, "Noncontinuable Exception");
905 fExcptSoftware = TRUE;
906 break;
907
908 case XCPT_INVALID_DISPOSITION:
909 strcpy(szLineException, "Invalid Disposition");
910 fExcptSoftware = TRUE;
911 break;
912
913 /* non-portable, fatal exceptions */
914 case XCPT_INVALID_LOCK_SEQUENCE:
915 strcpy(szLineException, "Invalid Lock Sequence");
916 fExcptSoftware = TRUE;
917 fExcptPortable = FALSE;
918 break;
919
920 case XCPT_ARRAY_BOUNDS_EXCEEDED:
921 strcpy(szLineException, "Array Bounds Exceeded");
922 fExcptSoftware = TRUE;
923 fExcptPortable = FALSE;
924 break;
925
926 /* unwind operation exceptions */
927 case XCPT_UNWIND:
928 strcpy(szLineException, "Unwind Exception");
929 fExcptSoftware = TRUE;
930 fExcptPortable = FALSE;
931 break;
932
933 case XCPT_BAD_STACK:
934 strcpy(szLineException, "Unwind Exception, Bad Stack");
935 fExcptSoftware = TRUE;
936 fExcptPortable = FALSE;
937 break;
938
939 case XCPT_INVALID_UNWIND_TARGET:
940 strcpy(szLineException, "Unwind Exception, Invalid Target");
941 fExcptSoftware = TRUE;
942 fExcptPortable = FALSE;
943 break;
944
945 /* fatal signal exceptions */
946 case XCPT_SIGNAL:
947 strcpy(szLineException, "Signal");
948 sprintf(szLineExceptionType, "Signal Number = %08x", pERepRec->ExceptionInfo[0]);
949 fExcptSoftware = TRUE;
950 fExcptPortable = FALSE;
951
952 switch (pERepRec->ExceptionInfo[0]) /* resolve signal information */
953 {
954 case XCPT_SIGNAL_INTR:
955 strcpy(szLineException, "Signal (Interrupt)");
956 break;
957
958 case XCPT_SIGNAL_KILLPROC:
959 strcpy(szLineException, "Signal (Kill Process)");
960 break;
961
962 case XCPT_SIGNAL_BREAK:
963 strcpy(szLineException, "Signal (Break)");
964 break;
965 }
966 break;
967
968 default:
969 strcpy(szLineException, "(unknown exception code)");
970 sprintf(szLineExceptionType, "Exception Code = %08x", pERepRec->ExceptionNum);
971 break;
972 }
973
974 sprintf(szTrapDump, "---[Exception Information]------------\n %s (", szLineException);
975
976 if (fExcptSoftware == TRUE) /* software or hardware generated ? */
977 strcat (szTrapDump, "software generated,");
978 else
979 strcat (szTrapDump, "hardware generated,");
980
981 if (fExcptPortable == TRUE) /* portable exception ? */
982 strcat (szTrapDump, "portable,");
983 else
984 strcat (szTrapDump, "non-portable,");
985
986 if (fExcptFatal == TRUE) /* fatal exception ? */
987 strcat (szTrapDump, "fatal");
988 else
989 strcat (szTrapDump, "non-fatal");
990
991 strcat(szTrapDump, ")\n"); /* add trailing brace */
992
993 if (szLineExceptionType[0])
994 sprintf(szTrapDump + strlen(szTrapDump), " %s\n", szLineExceptionType);
995
996 sprintf(szLineException, " Exception Address = %08x ", pERepRec->ExceptionAddress);
997 strcat(szTrapDump, szLineException);
998
999 rc = DosQueryModFromEIP(&ulModule, &ulObject, sizeof(szModule),
1000 szModule, &ulOffset, (ULONG)pERepRec->ExceptionAddress);
1001
1002 if(rc == NO_ERROR && ulObject != -1)
1003 {
1004 sprintf(szLineException, "<%8.8s> (%04X) obj %04X:%08X", szModule, ulModule, ulObject + 1, ulOffset);
1005#ifdef RAS
1006 char szSYMInfo[260];
1007
1008 DosQueryModuleName(ulModule, sizeof(szModule), szModule);
1009
1010 int namelen = strlen(szModule);
1011 if(namelen > 3)
1012 {
1013 strcpy(szModule + namelen - 3, "SYM");
1014 dbgGetSYMInfo(szModule, ulObject, ulOffset, szSYMInfo, sizeof (szSYMInfo),
1015 FALSE);
1016 strcat(szLineException, " ");
1017 strcat(szLineException, szSYMInfo);
1018 }
1019#else
1020 strcat(szLineException, "\n");
1021#endif
1022 strcat(szTrapDump, szLineException);
1023 }
1024 else
1025 { /* fault in DosAllocMem allocated memory, hence PE loader.. */
1026 Win32ImageBase * pMod;
1027 if (WinExe && WinExe->insideModule((ULONG)pERepRec->ExceptionAddress))
1028 pMod = WinExe;
1029 else
1030 pMod = Win32DllBase::findModuleByAddr((ULONG)pERepRec->ExceptionAddress);
1031 if (pMod != NULL)
1032 {
1033 szModule[0] = '\0';
1034 strncat(szModule, pMod->getModuleName(), sizeof(szModule) - 1);
1035 ulObject = 0xFF;
1036 ulOffset = (ULONG)pERepRec->ExceptionAddress - (ULONG)pMod->getInstanceHandle();
1037 sprintf(szLineException, "<%8.8s> (%04X) obj %04X:%08X", szModule, ulModule, ulObject, ulOffset);
1038 }
1039 else sprintf(szLineException, "<unknown win32 module>\n");
1040
1041 strcat(szTrapDump, szLineException);
1042 }
1043
1044 rc = DosGetInfoBlocks (&pTIB, &pPIB);
1045 if (rc == NO_ERROR)
1046 {
1047 sprintf(szLineException, " Thread: Ordinal TID: %u, TID: %u, Priority: %04xh\n",
1048 pTIB->tib_ordinal, pTIB->tib_ptib2->tib2_ultid, pTIB->tib_ptib2->tib2_ulpri);
1049 strcat(szTrapDump, szLineException);
1050
1051 sprintf(szLineException, " Process: PID: %u, Parent: %u, Status: %u\n", pPIB->pib_ulpid,
1052 pPIB->pib_ulppid, pPIB->pib_flstatus);
1053 strcat(szTrapDump, szLineException);
1054 }
1055
1056 if (pCtxRec->ContextFlags & CONTEXT_CONTROL) { /* check flags */
1057 sprintf(szLineException, " SS:ESP=%04x:%08x EFLAGS=%08x\n", pCtxRec->ctx_SegSs, pCtxRec->ctx_RegEsp,
1058 pCtxRec->ctx_EFlags);
1059 strcat(szTrapDump, szLineException);
1060 sprintf(szLineException, " CS:EIP=%04x:%08x EBP =%08x\n", pCtxRec->ctx_SegCs, pCtxRec->ctx_RegEip,
1061 pCtxRec->ctx_RegEbp);
1062 strcat(szTrapDump, szLineException);
1063 }
1064
1065 if (pCtxRec->ContextFlags & CONTEXT_INTEGER) { /* check flags */
1066 sprintf(szLineException, " EAX=%08x EBX=%08x ESI=%08x\n", pCtxRec->ctx_RegEax, pCtxRec->ctx_RegEbx,
1067 pCtxRec->ctx_RegEsi);
1068 strcat(szTrapDump, szLineException);
1069 sprintf(szLineException, " ECX=%08x EDX=%08x EDI=%08x\n", pCtxRec->ctx_RegEcx, pCtxRec->ctx_RegEdx,
1070 pCtxRec->ctx_RegEdi);
1071 strcat(szTrapDump, szLineException);
1072 }
1073
1074 if (pCtxRec->ContextFlags & CONTEXT_SEGMENTS) { /* check flags */
1075 sprintf(szLineException, " DS=%04x ES=%08x FS=%04x GS=%04x\n", pCtxRec->ctx_SegDs, pCtxRec->ctx_SegEs, pCtxRec->ctx_SegFs, pCtxRec->ctx_SegGs);
1076 strcat(szTrapDump, szLineException);
1077 }
1078
1079 if (pCtxRec->ContextFlags & CONTEXT_FLOATING_POINT) /* check flags */
1080 {
1081 ULONG ulCounter; /* temporary local counter for fp stack */
1082
1083 sprintf(szLineException, " Env[0]=%08x Env[1]=%08x Env[2]=%08x Env[3]=%08x\n",
1084 pCtxRec->ctx_env[0], pCtxRec->ctx_env[1],
1085 pCtxRec->ctx_env[2], pCtxRec->ctx_env[3]);
1086 strcat(szTrapDump, szLineException);
1087
1088 sprintf(szLineException, " Env[4]=%08x Env[5]=%08x Env[6]=%08x\n",
1089 pCtxRec->ctx_env[4], pCtxRec->ctx_env[5], pCtxRec->ctx_env[6]);
1090 strcat(szTrapDump, szLineException);
1091
1092 for (ulCounter = 0; ulCounter < 8; /* see TOOLKIT\INCLUDE\BSEEXPT.H, _CONTEXT structure */
1093 ulCounter ++)
1094 {
1095 sprintf(szLineException, " FP-Stack[%u] losig=%08x hisig=%08x signexp=%04x\n",
1096 ulCounter, pCtxRec->ctx_stack[0].losig, pCtxRec->ctx_stack[0].hisig,
1097 pCtxRec->ctx_stack[0].signexp);
1098 strcat(szTrapDump, szLineException);
1099 }
1100 }
1101 sprintf(szLineException, "---[End Of Exception Information]-----\n");
1102 strcat(szTrapDump, szLineException);
1103}
1104/*****************************************************************************
1105 * Name : void static dprintfException
1106 * Purpose : log the exception to win32os2.log
1107 * Parameters: ...
1108 * Variables :
1109 * Result :
1110 * Remark :
1111 * Status :
1112 *
1113 * Author : Patrick Haller [Tue, 1999/07/01 09:00]
1114 *****************************************************************************/
1115
1116#ifdef DEBUG
1117
1118static void dprintfException(PEXCEPTIONREPORTRECORD pERepRec,
1119 PEXCEPTIONREGISTRATIONRECORD pERegRec,
1120 PCONTEXTRECORD pCtxRec,
1121 PVOID p)
1122{
1123 char szTrapDump[2048];
1124 szTrapDump[0] = '\0';
1125 sprintfException(pERepRec, pERegRec, pCtxRec, p, szTrapDump);
1126#ifdef RAS
1127 RasLog (szTrapDump);
1128#endif
1129 /* now dump the information to the logfile */
1130 dprintf(("\n%s", szTrapDump));
1131}
1132
1133#else // DEBUG
1134#define dprintfException(a,b,c,d) do {} while (0)
1135#endif // DEBUG
1136
1137//*****************************************************************************
1138static char szExceptionLogFileName[CCHMAXPATH] = "";
1139static BOOL fExceptionLoggging = TRUE;
1140//*****************************************************************************
1141//Override filename of exception log (expects full path)
1142//*****************************************************************************
1143void WIN32API SetCustomExceptionLog(LPSTR lpszLogName)
1144{
1145 strcpy(szExceptionLogFileName, lpszLogName);
1146}
1147//*****************************************************************************
1148//*****************************************************************************
1149void WIN32API SetExceptionLogging(BOOL fEnable)
1150{
1151 fExceptionLoggging = fEnable;
1152}
1153//*****************************************************************************
1154//*****************************************************************************
1155static void logException(PEXCEPTIONREPORTRECORD pERepRec, PEXCEPTIONREGISTRATIONRECORD pERegRec, PCONTEXTRECORD pCtxRec, PVOID p)
1156{
1157 APIRET rc;
1158 HFILE hFile;
1159 ULONG ulAction, ulBytesWritten;
1160
1161 if(fExceptionLoggging == FALSE) {
1162 return;
1163 }
1164
1165 if(szExceptionLogFileName[0] == 0) {
1166 strcpy(szExceptionLogFileName, kernel32Path);
1167 strcat(szExceptionLogFileName, "\\except.log");
1168 }
1169 rc = DosOpen(szExceptionLogFileName, /* File path name */
1170 &hFile, /* File handle */
1171 &ulAction, /* Action taken */
1172 0L, /* File primary allocation */
1173 0L, /* File attribute */
1174 OPEN_ACTION_CREATE_IF_NEW |
1175 OPEN_ACTION_OPEN_IF_EXISTS, /* Open function type */
1176 OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE,
1177 0L); /* No extended attribute */
1178
1179 if(rc == NO_ERROR) {
1180 DosSetFilePtr(hFile, 0, FILE_END, &ulBytesWritten);
1181 if(WinExe) {
1182 LPSTR lpszExeName;
1183
1184 lpszExeName = WinExe->getModuleName();
1185
1186 if(lpszExeName) {
1187 DosWrite(hFile, (PVOID)"\n", 2, &ulBytesWritten);
1188 DosWrite(hFile, lpszExeName, strlen(lpszExeName), &ulBytesWritten);
1189 DosWrite(hFile, (PVOID)"\n", 2, &ulBytesWritten);
1190 }
1191 }
1192 LPSTR lpszTime;
1193 time_t curtime;
1194
1195 curtime = time(NULL);
1196 lpszTime = asctime(localtime(&curtime));
1197 if(lpszTime) {
1198 DosWrite(hFile, lpszTime, strlen(lpszTime), &ulBytesWritten);
1199 }
1200
1201 char szTrapDump[2048];
1202 szTrapDump[0] = '\0';
1203 sprintfException(pERepRec, pERegRec, pCtxRec, p, szTrapDump);
1204#ifdef RAS
1205 RasLog (szTrapDump);
1206#endif
1207 DosWrite(hFile, szTrapDump, strlen(szTrapDump), &ulBytesWritten);
1208 DosClose(hFile);
1209 }
1210}
1211
1212/*****************************************************************************
1213 * Name : ERR _System OS2ExceptionHandler
1214 * Purpose :
1215 * Parameters: ...
1216 * Variables :
1217 * Result :
1218 * Remark :
1219 * Status :
1220 *
1221 * Author : Patrick Haller [Tue, 1999/07/01 09:00]
1222 *****************************************************************************/
1223 /* from PPC DDK */
1224#ifndef XCPT_CONTINUE_STOP
1225#define XCPT_CONTINUE_STOP 0x00716668
1226#endif
1227
1228// borrowed from ntddk.h
1229extern "C"
1230void WIN32API RtlUnwind(
1231 LPVOID,
1232 LPVOID,
1233 LPVOID,DWORD);
1234
1235// Assembly wrapper for clearing the direction flag before calling our real
1236// exception handler
1237ULONG APIENTRY OS2ExceptionHandler(PEXCEPTIONREPORTRECORD pERepRec,
1238 PEXCEPTIONREGISTRATIONRECORD pERegRec,
1239 PCONTEXTRECORD pCtxRec,
1240 PVOID p);
1241
1242ULONG APIENTRY OS2ExceptionHandler2ndLevel(PEXCEPTIONREPORTRECORD pERepRec,
1243 PEXCEPTIONREGISTRATIONRECORD pERegRec,
1244 PCONTEXTRECORD pCtxRec,
1245 PVOID p)
1246{
1247 // we need special processing when reused from ___seh_handler
1248 BOOL fSEH = pERegRec->ExceptionHandler == (_ERR *)__seh_handler;
1249
1250#ifdef DEBUG
1251 //SvL: Check if exception inside debug fprintf -> if so, clear lock so
1252 // next dprintf won't wait forever
1253 int prevlock = LogException(ENTER_EXCEPTION);
1254#endif
1255
1256// @@VP20040507: no need to sprintf every exception
1257// //Print exception name & exception type
1258// //Not for a guard page exception as sprintfException uses a lot of stack
1259// //and can trigger nested guard page exceptions (crash)
1260// if(pERepRec->ExceptionNum != XCPT_GUARD_PAGE_VIOLATION) {
1261// sprintfException(pERepRec, pERegRec, pCtxRec, p, szTrapDump);
1262// }
1263
1264 // We have to disable unwinding of the Win32 exception handlers because
1265 // experiments have shown that when running under SMP kernel the stack
1266 // becomes corrupt at the time when unwinding takes place: attempts to
1267 // to follow the exception chain crash when accessing one of the the
1268 // previous frame. Although it may seem that performing unwinding here
1269 // (when we are definitely above any Win32 exception frames installed by
1270 // the application so that the OS could theoretically already discard lower
1271 // stack areas) is wrong, it's not the case of the crash. First, doing the
1272 // very same thing from the SEH handler (see comments in sehutil.s), i.e.
1273 // when the given Win32 stack frame (and all previous ones) is definitely
1274 // alive, crahes due to the same stack corruption too. Second, when running
1275 // under UNI kernel, BOTH approaches don't crash (i.e. the stack is fine).
1276 // This looks like the SMP kernel doesn't manage the stack right during
1277 // exception handling :( See also http://svn.netlabs.org/odin32/ticket/37.
1278 //
1279 // Note that disabling unwinding also breaks support for performing
1280 // setjmp()/lonjmp() that crosses the bounds of the __try {} block.
1281#if 0
1282 if (pERepRec->fHandlerFlags & EH_UNWINDING)
1283 {
1284 // unwind the appropriate portion of the Win32 exception chain
1285 if (pERepRec->fHandlerFlags & EH_EXIT_UNWIND)
1286 {
1287 dprintf(("KERNEL32: OS2ExceptionHandler (fSEH=%d): EH_EXIT_UNWIND, "
1288 "unwinding all the Win32 exception chain", fSEH));
1289 RtlUnwind(NULL, 0, 0, 0);
1290 }
1291 else
1292 {
1293 dprintf(("KERNEL32: OS2ExceptionHandler (fSEH=%d): EH_UNWINDING, "
1294 "unwinding the Win32 exception chain up to 0x%p", fSEH, pERegRec));
1295
1296 // find a Win32 exception frame closest to the OS/2 one (pERegRec)
1297 // and unwind up to the previous one (to unwind the closest frame
1298 // itself too as we are definitely jumping out of it)
1299 TEB *winteb = GetThreadTEB();
1300 PWINEXCEPTION_FRAME frame = (PWINEXCEPTION_FRAME)winteb->except;
1301 while (frame != NULL && ((ULONG)frame)!= 0xFFFFFFFF &&
1302 ((ULONG)frame) <= ((ULONG)pERegRec))
1303 frame = __seh_get_prev_frame_win32(frame);
1304 if (((ULONG)frame) == 0xFFFFFFFF)
1305 frame = NULL;
1306
1307 RtlUnwind(frame, 0, 0, 0);
1308 }
1309 goto continuesearch;
1310 }
1311#endif
1312
1313 /* Access violation at a known location */
1314 switch(pERepRec->ExceptionNum)
1315 {
1316 case XCPT_FLOAT_DENORMAL_OPERAND:
1317 case XCPT_FLOAT_DIVIDE_BY_ZERO:
1318 case XCPT_FLOAT_INEXACT_RESULT:
1319// case XCPT_FLOAT_INVALID_OPERATION:
1320 case XCPT_FLOAT_OVERFLOW:
1321 case XCPT_FLOAT_STACK_CHECK:
1322 case XCPT_FLOAT_UNDERFLOW:
1323 dprintfException(pERepRec, pERegRec, pCtxRec, p);
1324 dprintf(("KERNEL32: OS2ExceptionHandler (fSEH=%d): FPU exception\n", fSEH));
1325 if((!fIsOS2Image || fForceWin32TIB || fSEH) && !fExitProcess) //Only for real win32 apps or when forced
1326 {
1327 if(OSLibDispatchException(pERepRec, pERegRec, pCtxRec, p, fSEH) == FALSE)
1328 {
1329 pCtxRec->ctx_env[0] |= 0x1F;
1330 pCtxRec->ctx_stack[0].losig = 0;
1331 pCtxRec->ctx_stack[0].hisig = 0;
1332 pCtxRec->ctx_stack[0].signexp = 0;
1333 }
1334 else
1335 {
1336 dprintf(("KERNEL32: OS2ExceptionHandler (fSEH=%d): fix and continue\n", fSEH));
1337 goto continueexecution;
1338 }
1339 }
1340 dprintf(("KERNEL32: OS2ExceptionHandler (fSEH=%d): continue search\n", fSEH));
1341 goto continuesearch;
1342
1343 case XCPT_PROCESS_TERMINATE:
1344 case XCPT_ASYNC_PROCESS_TERMINATE:
1345#if 0
1346 dprintfException(pERepRec, pERegRec, pCtxRec, p);
1347 PrintExceptionChain();
1348 // fall through
1349#endif
1350 case XCPT_UNWIND:
1351 // Note that printing through ODINCRT (VACRT) when handling XCPT_UNWIND
1352 // is known to create deadlocks
1353 goto continuesearch;
1354
1355 case XCPT_ACCESS_VIOLATION:
1356 {
1357 Win32MemMap *map;
1358 BOOL fWriteAccess = FALSE;
1359 ULONG offset, accessflag;
1360
1361#ifdef WITH_KLIB
1362 if ( pERepRec->ExceptionInfo[0] == XCPT_READ_ACCESS
1363 || pERepRec->ExceptionInfo[0] == XCPT_WRITE_ACCESS
1364 || pERepRec->ExceptionInfo[0] == XCPT_EXECUTE_ACCESS
1365 || pERepRec->ExceptionInfo[0] == XCPT_UNKNOWN_ACCESS
1366 )
1367 {
1368 ENMACCESS enmAccess = enmRead;
1369 switch (pERepRec->ExceptionInfo[0])
1370 {
1371 case XCPT_WRITE_ACCESS: enmAccess = enmWrite; break;
1372 case XCPT_UNKNOWN_ACCESS: enmAccess = enmUnknown; break;
1373 }
1374
1375 if (kHeapDbgException((void*)pERepRec->ExceptionInfo[1],
1376 enmAccess,
1377 pERepRec->ExceptionAddress,
1378 pERepRec))
1379 goto continueexecution;
1380 }
1381#endif
1382
1383 if(pERepRec->ExceptionInfo[1] == 0 && pERepRec->ExceptionInfo[1] == XCPT_DATA_UNKNOWN) {
1384 goto continueFail;
1385 }
1386
1387//------------->>> WARNING: potentially dangerous workaround!!
1388 /* Some apps set ES = FS and Odin doesn't like that! */
1389 /* Note: maybe we could even check for ES != DS? But maybe */
1390 /* that might cause more harm than good... */
1391 if (pCtxRec->ContextFlags & CONTEXT_SEGMENTS)
1392 if (pCtxRec->ctx_SegEs == pCtxRec->ctx_SegFs) {
1393 /* Let's just reset ES to the DS value and hope it's okay */
1394 pCtxRec->ctx_SegEs = pCtxRec->ctx_SegDs;
1395 goto continueexecution;
1396 }
1397
1398 switch(pERepRec->ExceptionInfo[0]) {
1399 case XCPT_READ_ACCESS:
1400 accessflag = MEMMAP_ACCESS_READ;
1401 break;
1402 case XCPT_WRITE_ACCESS:
1403 accessflag = MEMMAP_ACCESS_WRITE;
1404 fWriteAccess = TRUE;
1405 break;
1406 case XCPT_EXECUTE_ACCESS:
1407 accessflag = MEMMAP_ACCESS_EXECUTE;
1408 break;
1409 default:
1410 goto continueFail;
1411 }
1412
1413 map = Win32MemMapView::findMapByView(pERepRec->ExceptionInfo[1], &offset, accessflag);
1414 if(map == NULL) {
1415 Win32MemMapNotify *map;
1416
1417 map = Win32MemMapNotify::findMapByView(pERepRec->ExceptionInfo[1], &offset, accessflag);
1418 if(!map)
1419 goto continueFail;
1420
1421 BOOL ret = map->notify(pERepRec->ExceptionInfo[1], offset, fWriteAccess);
1422 if(ret == TRUE) goto continueexecution;
1423 goto continueFail;
1424 }
1425 BOOL ret = map->commitPage(pERepRec->ExceptionInfo[1], offset, fWriteAccess);
1426 map->Release();
1427 if(ret == TRUE)
1428 goto continueexecution;
1429
1430 //no break;
1431 }
1432continueFail:
1433
1434 /*
1435 * vladest: OK, try to implement write AUTOCOMMIT
1436 * last chance after MMAP commit is failed
1437 */
1438 if (XCPT_ACCESS_VIOLATION == pERepRec->ExceptionNum &&
1439 (/*pERepRec->ExceptionInfo[0] == XCPT_READ_ACCESS ||*/
1440 pERepRec->ExceptionInfo[0] == XCPT_WRITE_ACCESS) &&
1441 pERepRec->ExceptionInfo[1] != XCPT_DATA_UNKNOWN)
1442 {
1443 ULONG offset, accessflag;
1444
1445 DosQueryMem((PVOID) pERepRec->ExceptionInfo[1],
1446 &offset, &accessflag);
1447 dprintf(("KERNEL32: OS2ExceptionHandler (fSEH=%d): failed address info 0x%X size 0x%X. flag %X\n",
1448 fSEH, pERepRec->ExceptionInfo[1], offset, accessflag));
1449 /* check for valid address */
1450 if (!pERepRec->ExceptionInfo[1] ||
1451 pERepRec->ExceptionInfo[1] == 0xAAAAAAAA ||
1452 !offset || offset == 0xAAAAAAAA)
1453 goto CrashAndBurn;
1454 /* memory committed, but no write access */
1455 if (accessflag & PAG_GUARD)
1456 accessflag &=~PAG_GUARD;
1457
1458 /* set memory aligned on page size and with size counting alignment */
1459 ULONG rc = DosSetMem((PVOID) (pERepRec->ExceptionInfo[1] & 0xFFFFF000),
1460 offset + (pERepRec->ExceptionInfo[1] - (pERepRec->ExceptionInfo[1] & 0xFFFFF000)),
1461 accessflag | PAG_WRITE | PAG_COMMIT);
1462 dprintf(("KERNEL32: OS2ExceptionHandler (fSEH=%d): commiting 0x%X size 0x%X. RC: %i\n",
1463 fSEH, pERepRec->ExceptionInfo[1] & 0xFFFFF000,
1464 offset + (pERepRec->ExceptionInfo[1] - (pERepRec->ExceptionInfo[1] & 0xFFFFF000)),
1465 rc));
1466 if (NO_ERROR == rc)
1467 goto continueexecution;
1468 else
1469 goto CrashAndBurn;
1470 }
1471
1472
1473////#define DEBUGSTACK
1474#ifdef DEBUGSTACK
1475 if(pCtxRec->ContextFlags & CONTEXT_CONTROL) {
1476 ULONG *stackptr;
1477 APIRET rc;
1478 int i;
1479 ULONG ulOffset, ulModule, ulObject;
1480 CHAR szModule[CCHMAXPATH];
1481
1482 stackptr = (ULONG *)pCtxRec->ctx_RegEsp;
1483 dprintf(("Stack DUMP:"));
1484 for(i=0;i<16;i++) {
1485 rc = DosQueryModFromEIP(&ulModule,
1486 &ulObject,
1487 sizeof(szModule),
1488 szModule,
1489 &ulOffset,
1490 (ULONG)*stackptr);
1491
1492 if (rc == NO_ERROR)
1493 dprintf(("0x%8x: 0x%8x %s (#%u), obj #%u:%08x", stackptr, *stackptr, szModule, ulModule, ulObject, ulOffset));
1494 else dprintf(("0x%8x: 0x%8x", stackptr, *stackptr));
1495 stackptr++;
1496 }
1497 dprintf(("Stack DUMP END"));
1498 }
1499#endif
1500 goto CrashAndBurn;
1501
1502 case XCPT_INVALID_LOCK_SEQUENCE:
1503 {
1504 TEB *teb = GetThreadTEB();
1505 USHORT *eip = (USHORT *)pCtxRec->ctx_RegEip;
1506
1507 if(teb && eip && *eip == SETTHREADCONTEXT_INVALID_LOCKOPCODE)
1508 {
1509 //Is this a pending SetThreadContext exception?
1510 //(see detailed description in the HMDeviceThreadClass::SetThreadContext method)
1511 if(teb->o.odin.context.ContextFlags)
1512 {
1513 dprintfException(pERepRec, pERegRec, pCtxRec, p);
1514
1515 //NOTE: This will not work properly in case multiple threads execute this code
1516 dprintf(("KERNEL32: OS2ExceptionHandler (fSEH=%d): Changing thread registers (SetThreadContext)!!", fSEH));
1517
1518 if(teb->o.odin.context.ContextFlags & WINCONTEXT_CONTROL) {
1519 pCtxRec->ctx_RegEbp = teb->o.odin.context.Ebp;
1520 pCtxRec->ctx_RegEip = teb->o.odin.context.Eip;
1521//// pCtxRec->ctx_SegCs = teb->o.odin.context.SegCs;
1522 pCtxRec->ctx_EFlags = teb->o.odin.context.EFlags;
1523 pCtxRec->ctx_RegEsp = teb->o.odin.context.Esp;
1524//// pCtxRec->ctx_SegSs = teb->o.odin.context.SegSs;
1525 }
1526 if(teb->o.odin.context.ContextFlags & WINCONTEXT_INTEGER) {
1527 pCtxRec->ctx_RegEdi = teb->o.odin.context.Edi;
1528 pCtxRec->ctx_RegEsi = teb->o.odin.context.Esi;
1529 pCtxRec->ctx_RegEbx = teb->o.odin.context.Ebx;
1530 pCtxRec->ctx_RegEdx = teb->o.odin.context.Edx;
1531 pCtxRec->ctx_RegEcx = teb->o.odin.context.Ecx;
1532 pCtxRec->ctx_RegEax = teb->o.odin.context.Eax;
1533 }
1534 if(teb->o.odin.context.ContextFlags & WINCONTEXT_SEGMENTS) {
1535 pCtxRec->ctx_SegGs = teb->o.odin.context.SegGs;
1536//// pCtxRec->ctx_SegFs = teb->o.odin.context.SegFs;
1537 pCtxRec->ctx_SegEs = teb->o.odin.context.SegEs;
1538 pCtxRec->ctx_SegDs = teb->o.odin.context.SegDs;
1539 }
1540 if(teb->o.odin.context.ContextFlags & WINCONTEXT_FLOATING_POINT) {
1541 //TODO: First 7 dwords the same?
1542 memcpy(pCtxRec->ctx_env, &teb->o.odin.context.FloatSave, sizeof(pCtxRec->ctx_env));
1543 memcpy(pCtxRec->ctx_stack, &teb->o.odin.context.FloatSave.RegisterArea, sizeof(pCtxRec->ctx_stack));
1544 }
1545 USHORT *lpAlias = (USHORT *)((char *)teb->o.odin.lpAlias + teb->o.odin.dwAliasOffset);
1546 *lpAlias = teb->o.odin.savedopcode;
1547
1548 //Clear SetThreadContext markers
1549 teb->o.odin.context.ContextFlags = 0;
1550
1551 OSLibDosFreeMem(teb->o.odin.lpAlias);
1552
1553 teb->o.odin.lpAlias = NULL;
1554 teb->o.odin.dwAliasOffset = 0;
1555
1556 //restore the original priority (we boosted it to ensure this thread was scheduled first)
1557 SetThreadPriority(teb->o.odin.hThread, GetThreadPriority(teb->o.odin.hThread));
1558 goto continueexecution;
1559 }
1560 else DebugInt3(); //oh, oh!!!!!
1561
1562 }
1563 //no break;
1564 }
1565
1566 case XCPT_PRIVILEGED_INSTRUCTION:
1567 case XCPT_ILLEGAL_INSTRUCTION:
1568 case XCPT_BREAKPOINT:
1569 case XCPT_ARRAY_BOUNDS_EXCEEDED:
1570 case XCPT_DATATYPE_MISALIGNMENT:
1571 case XCPT_INTEGER_DIVIDE_BY_ZERO:
1572 case XCPT_INTEGER_OVERFLOW:
1573 case XCPT_SINGLE_STEP:
1574 case XCPT_IN_PAGE_ERROR:
1575CrashAndBurn:
1576 //SvL: TODO: this may not always be the right thing to do
1577 //MN: If EH_NESTED_CALL is set, an exception occurred during the execution
1578 // of this exception handler. We better bail out ASAP or we'll likely
1579 // recurse infinitely until we run out of stack space!!
1580 if (pERepRec->fHandlerFlags & EH_NESTED_CALL)
1581 goto continuesearch;
1582
1583#if defined(DEBUG)
1584 dprintfException(pERepRec, pERegRec, pCtxRec, p);
1585
1586 if(!fExitProcess && (pCtxRec->ContextFlags & CONTEXT_CONTROL)) {
1587 dbgPrintStack(pERepRec, pERegRec, pCtxRec, p);
1588 }
1589#endif
1590
1591 if((!fIsOS2Image || fForceWin32TIB || fSEH) && !fExitProcess) //Only for real win32 apps or when forced
1592 {
1593 if(OSLibDispatchException(pERepRec, pERegRec, pCtxRec, p, fSEH) == TRUE)
1594 {
1595 dprintf(("KERNEL32: OS2ExceptionHandler (fSEH=%d): fix and continue\n", fSEH));
1596 goto continueexecution;
1597 }
1598 else
1599 {
1600 dprintf(("KERNEL32: OS2ExceptionHandler (fSEH=%d): continue search\n", fSEH));
1601 goto continuesearch;
1602 }
1603 }
1604 else {
1605 if(fExitProcess) {
1606 PPIB pPIB;
1607 PTIB pTIB;
1608 APIRET rc;
1609
1610 rc = DosGetInfoBlocks (&pTIB, &pPIB);
1611 if(rc == NO_ERROR)
1612 {
1613 dprintf(("KERNEL32: OS2ExceptionHandler (fSEH=%d): Continue and kill thread", fSEH));
1614
1615 pCtxRec->ctx_RegEip = (pTIB->tib_ptib2->tib2_ultid != 1) ? (ULONG)KillWin32Thread : (ULONG)KillWin32Process;
1616 pCtxRec->ctx_RegEsp = pCtxRec->ctx_RegEsp + 0x10;
1617 pCtxRec->ctx_RegEax = pERepRec->ExceptionNum;
1618 pCtxRec->ctx_RegEbx = pCtxRec->ctx_RegEip;
1619 goto continueexecution;
1620 }
1621 }
1622 goto continuesearch; //pass on to OS/2 RTL or app exception handler
1623 }
1624
1625 //Log fatal exception here
1626 logException(pERepRec, pERegRec, pCtxRec, p);
1627
1628 dprintf(("KERNEL32: OS2ExceptionHandler (fSEH=%d): Continue and kill\n", fSEH));
1629
1630 pCtxRec->ctx_RegEip = (ULONG)KillWin32Process;
1631 pCtxRec->ctx_RegEsp = pCtxRec->ctx_RegEsp + 0x10;
1632 pCtxRec->ctx_RegEax = pERepRec->ExceptionNum;
1633 pCtxRec->ctx_RegEbx = pCtxRec->ctx_RegEip;
1634 goto continueexecution;
1635
1636 case XCPT_GUARD_PAGE_VIOLATION:
1637 {
1638 //NOTE:!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1639 //Don't print anything here -> fatal hang if exception occurred
1640 //inside fprintf
1641 //NOTE:!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1642 TEB *teb = GetThreadTEB();
1643 DWORD stacktop, stackbottom;
1644
1645 if(teb == NULL) {
1646 goto continuesearch;
1647 }
1648
1649 stacktop = (DWORD)teb->stack_top;
1650 stackbottom = (DWORD)teb->stack_low;
1651
1652 stackbottom = stackbottom & ~0xFFF; //round down to page boundary
1653 stacktop = stacktop & ~0xFFF;
1654
1655 // Make sure we detect a stack overflow condition before the system does
1656 if ((!fIsOS2Image || fForceWin32TIB || fSEH) && //Only for real win32 apps or when forced
1657 pERepRec->ExceptionInfo[1] >= stackbottom &&
1658 pERepRec->ExceptionInfo[1] < stacktop
1659 )
1660 {
1661 // this is a guard page exception for the thread stack
1662
1663 // In order to imitate Windows behavior, we must raise
1664 // EXCEPTION_STACK_OVERFLOW in the Win32 context in two cases:
1665 // 1. When we run out of stack.
1666 // 2. When a guard page not immediately following the committed
1667 // stack area is touched.
1668
1669 APIRET rc;
1670 BOOL bRaise = FALSE;
1671
1672 // round down to page boundary
1673 ULONG ulAddress = pERepRec->ExceptionInfo[1] & ~0xFFF;
1674
1675 if (ulAddress == stackbottom + PAGE_SIZE)
1676 {
1677 // we are about to run out of stack
1678 bRaise = TRUE;
1679 }
1680 else
1681 {
1682 // check if it's an adjacent guard page used to grow stack
1683 ULONG cbSize = ~0, ulMemFlags;
1684 rc = DosQueryMem((PVOID)ulAddress, &cbSize, &ulMemFlags);
1685 if (rc)
1686 {
1687 dprintf(("ERROR: DosQueryMem old guard page failed with rc %d", rc));
1688 goto continueGuardException;
1689 }
1690
1691 if (ulAddress + cbSize == stacktop)
1692 {
1693 // yes, we must pass it on to the system to do the grow magic
1694 goto continuesearch;
1695 }
1696
1697 bRaise = TRUE;
1698 }
1699
1700 if (bRaise)
1701 {
1702 if (!fExitProcess)
1703 {
1704 EXCEPTIONREPORTRECORD recoutofstack;
1705
1706 recoutofstack = *pERepRec;
1707 recoutofstack.ExceptionNum = XCPT_UNABLE_TO_GROW_STACK;
1708 recoutofstack.fHandlerFlags = 0;
1709 recoutofstack.NestedExceptionReportRecord = NULL;
1710 recoutofstack.cParameters = 0;
1711
1712 if(OSLibDispatchException(&recoutofstack, pERegRec, pCtxRec, p, fSEH) == TRUE)
1713 {
1714 goto continueexecution;
1715 }
1716 }
1717 }
1718 }
1719 else
1720 {
1721 // Throw EXCEPTION_GUARD_PAGE_VIOLATION in the Win32 context
1722 if((!fIsOS2Image || fForceWin32TIB || fSEH) && !fExitProcess) //Only for real win32 apps or when forced
1723 {
1724 if(OSLibDispatchException(pERepRec, pERegRec, pCtxRec, p, fSEH) == TRUE)
1725 {
1726 goto continueexecution;
1727 }
1728 }
1729
1730 //check for memory map guard page exception
1731 Win32MemMap *map;
1732 BOOL fWriteAccess = FALSE, ret;
1733 ULONG offset, accessflag;
1734
1735 switch(pERepRec->ExceptionInfo[0]) {
1736 case XCPT_READ_ACCESS:
1737 accessflag = MEMMAP_ACCESS_READ;
1738 break;
1739 case XCPT_WRITE_ACCESS:
1740 accessflag = MEMMAP_ACCESS_WRITE;
1741 fWriteAccess = TRUE;
1742 break;
1743 default:
1744 goto continueGuardException;
1745 }
1746
1747 map = Win32MemMapView::findMapByView(pERepRec->ExceptionInfo[1], &offset, accessflag);
1748 if(map) {
1749 ret = map->commitGuardPage(pERepRec->ExceptionInfo[1], offset, fWriteAccess);
1750 map->Release();
1751 if(ret == TRUE)
1752 goto continueexecution;
1753 }
1754 }
1755
1756continueGuardException:
1757 goto continuesearch;
1758 }
1759
1760 case XCPT_UNABLE_TO_GROW_STACK:
1761 {
1762 //SvL: XCPT_UNABLE_TO_GROW_STACK is typically nested (failed guard page
1763 // exception), so don't ignore them
1764 // We should no longer receive those!!
1765// @@VP20040507: Isn't this a bit dangerous to call dprintfon such exception
1766//#ifdef DEBUG
1767// dprintfException(pERepRec, pERegRec, pCtxRec, p);
1768//#endif
1769 goto continuesearch;
1770 }
1771
1772
1773 /*
1774 * In OS/2 VIO Ctrl-C and Ctrl-Break is special stuff which comes in
1775 * thru the exception handler. In Win32 CUI they are handled by a
1776 * ControlCtrlEvent procedure. So, if we receive one of those signals
1777 * we assume that this is a VIO program and let the handlers handle this.
1778 * (If they want to.)
1779 */
1780 case XCPT_SIGNAL:
1781 {
1782 //This is not a reliable way to distinguish between Ctrl-C & Ctrl-Break
1783 BOOL breakPressed = WinGetKeyState(HWND_DESKTOP,VK_BREAK) & 0x8000;
1784
1785 switch (pERepRec->ExceptionInfo[0])
1786 {
1787 case XCPT_SIGNAL_BREAK:
1788 breakPressed = TRUE;
1789 //no break
1790
1791 case XCPT_SIGNAL_INTR:
1792 dprintfException(pERepRec, pERegRec, pCtxRec, p);
1793 if (InternalGenerateConsoleCtrlEvent((breakPressed) ? CTRL_BREAK_EVENT : CTRL_C_EVENT, 0))
1794 {
1795 DosAcknowledgeSignalException(pERepRec->ExceptionInfo[0]);
1796 goto continueexecution;
1797 }
1798 goto continuesearch;
1799
1800 case XCPT_SIGNAL_KILLPROC: /* resolve signal information */
1801 goto continuesearch;
1802 }
1803 goto CrashAndBurn;
1804 }
1805
1806 default: //non-continuable exceptions
1807 dprintfException(pERepRec, pERegRec, pCtxRec, p);
1808 goto continuesearch;
1809 }
1810continuesearch:
1811#ifdef DEBUG
1812 LogException(LEAVE_EXCEPTION, prevlock);
1813#endif
1814 return XCPT_CONTINUE_SEARCH;
1815
1816continueexecution:
1817#ifdef DEBUG
1818 LogException(LEAVE_EXCEPTION, prevlock);
1819#endif
1820 return XCPT_CONTINUE_EXECUTION;
1821}
1822
1823/*****************************************************************************
1824 * Name : void OS2SetExceptionHandler
1825 * Purpose : Sets the main thread exception handler in FS:[0] (original OS/2 FS selector)
1826 * Parameters: exceptframe: pointer to exception handler frame on stack (2 ULONGs)
1827 * Variables :
1828 * Result :
1829 * Remark :
1830 * Status :
1831 *
1832 * Author : Sander van Leeuwen [Sun, 1999/08/21 12:16]
1833 *****************************************************************************/
1834void SYSTEM OS2SetExceptionHandler(void *exceptframe)
1835{
1836 PEXCEPTIONREGISTRATIONRECORD pExceptRec = (PEXCEPTIONREGISTRATIONRECORD)exceptframe;
1837
1838 pExceptRec->prev_structure = (PEXCEPTIONREGISTRATIONRECORD)0;
1839 pExceptRec->ExceptionHandler = OS2ExceptionHandler;
1840
1841 /* disable trap popups */
1842// DosError(FERR_DISABLEEXCEPTION | FERR_DISABLEHARDERR);
1843
1844 DosSetExceptionHandler(pExceptRec);
1845 dprintf(("OS2SetExceptionHandler: exception chain %x", pExceptRec));
1846#ifdef DEBUG_ENABLELOG_LEVEL2
1847 PrintExceptionChain();
1848#endif
1849}
1850//*****************************************************************************
1851// Set exception handler if our handler has not yet been registered
1852//*****************************************************************************
1853void WIN32API ODIN_SetExceptionHandler(void *pExceptionRegRec)
1854{
1855 BOOL fFound = FALSE;
1856 USHORT sel = RestoreOS2FS();
1857 PEXCEPTIONREGISTRATIONRECORD pExceptRec = (PEXCEPTIONREGISTRATIONRECORD)QueryExceptionChain();
1858
1859 while(pExceptRec != 0 && (ULONG)pExceptRec != -1)
1860 {
1861 if(pExceptRec->ExceptionHandler == OS2ExceptionHandler)
1862 {
1863 fFound = TRUE;
1864 break;
1865 }
1866 pExceptRec = pExceptRec->prev_structure;
1867 }
1868 if(!fFound)
1869 {
1870 OS2SetExceptionHandler(pExceptionRegRec);
1871 }
1872 SetFS(sel);
1873}
1874//*****************************************************************************
1875// Remove exception handler if it was registered previously
1876//
1877//*****************************************************************************
1878void WIN32API ODIN_UnsetExceptionHandler(void *pExceptionRegRec)
1879{
1880 USHORT sel = RestoreOS2FS();
1881 PEXCEPTIONREGISTRATIONRECORD pExceptRec = (PEXCEPTIONREGISTRATIONRECORD)QueryExceptionChain();
1882 BOOL fFound = FALSE;
1883
1884 while(pExceptRec != 0 && (ULONG)pExceptRec != -1)
1885 {
1886 if(pExceptRec == pExceptionRegRec)
1887 {
1888 fFound = TRUE;
1889 break;
1890 }
1891 pExceptRec = pExceptRec->prev_structure;
1892 }
1893
1894#ifdef DEBUG
1895 pExceptRec = (PEXCEPTIONREGISTRATIONRECORD)QueryExceptionChain();
1896
1897 if(fFound && pExceptRec != (PEXCEPTIONREGISTRATIONRECORD)pExceptionRegRec)
1898 {
1899 dprintf(("ERROR: ODIN_UnsetExceptionHandler: INSIDE!!!: exc rec %p, head %p\n", pExceptionRegRec, pExceptRec));
1900 PrintExceptionChain ();
1901 }
1902#endif
1903 if(fFound) {
1904 OS2UnsetExceptionHandler(pExceptionRegRec);
1905 }
1906 SetFS(sel);
1907}
1908//*****************************************************************************
1909//*****************************************************************************
1910#ifdef DEBUG
1911void PrintExceptionChain()
1912{
1913 USHORT sel = RestoreOS2FS();
1914 PEXCEPTIONREGISTRATIONRECORD pExceptRec = (PEXCEPTIONREGISTRATIONRECORD)QueryExceptionChain();
1915
1916 dprintf(("OS/2 Exception chain:"));
1917 while(pExceptRec != 0 && (ULONG)pExceptRec != -1)
1918 {
1919 char szBuf[512];
1920 ULONG ulModule;
1921 ULONG ulObject, ulOffset;
1922 CHAR szModule[260];
1923
1924 *szBuf = '\0';
1925 APIRET rc = DosQueryModFromEIP(&ulModule, &ulObject, sizeof(szModule),
1926 szModule, &ulOffset, (ULONG)pExceptRec->ExceptionHandler);
1927 if(rc == NO_ERROR && ulObject != -1)
1928 {
1929 sprintf(szBuf, " <%8.8s> (%04X) obj %04X:%08X", szModule, ulModule, ulObject + 1, ulOffset);
1930#ifdef RAS
1931 char szSYMInfo[260];
1932
1933 DosQueryModuleName(ulModule, sizeof(szModule), szModule);
1934
1935 int namelen = strlen(szModule);
1936 if(namelen > 3)
1937 {
1938 strcpy(szModule + namelen - 3, "SYM");
1939 dbgGetSYMInfo(szModule, ulObject, ulOffset,
1940 szSYMInfo, sizeof (szSYMInfo), TRUE);
1941 strcat(szBuf, " ");
1942 strcat(szBuf, szSYMInfo);
1943 // remove trailing \n or space
1944 szBuf[strlen(szBuf) - 1] = '\0';
1945 }
1946#endif
1947 }
1948 else
1949 {
1950 *szBuf = '\0';
1951 }
1952
1953 dprintf((" record %08X, prev %08X, handler %08X%s",
1954 pExceptRec, pExceptRec->prev_structure, pExceptRec->ExceptionHandler,
1955 szBuf));
1956
1957 pExceptRec = pExceptRec->prev_structure;
1958 }
1959 dprintf(("END of OS/2 Exception chain."));
1960 SetFS(sel);
1961}
1962//*****************************************************************************
1963//*****************************************************************************
1964void PrintWin32ExceptionChain(PWINEXCEPTION_FRAME pFrame)
1965{
1966 dprintf(("Win32 exception chain:"));
1967 while ((pFrame != NULL) && ((ULONG)pFrame != 0xFFFFFFFF))
1968 {
1969 PWINEXCEPTION_FRAME pPrevFrame = __seh_get_prev_frame_win32(pFrame);
1970 dprintf((" Record at %08X, Prev at %08X, handler at %08X%s",
1971 pFrame, pPrevFrame, pFrame->Handler,
1972 pFrame->Handler == (PEXCEPTION_HANDLER)__seh_handler ? " (SEH)" :
1973 pFrame->Handler == (PEXCEPTION_HANDLER)__seh_handler_win32 ? " (SEH Win32)" : ""));
1974 if (pFrame == pPrevFrame)
1975 {
1976 dprintf(("Chain corrupted! Record at %08X pointing to itself!",
1977 pFrame));
1978 break;
1979 }
1980 pFrame = pPrevFrame;
1981 }
1982 dprintf(("END of Win32 exception chain."));
1983}
1984#endif
1985
1986/*****************************************************************************
1987 * Name : void OS2UnsetExceptionHandler
1988 * Purpose : Removes the main thread exception handler in FS:[0] (original OS/2 FS selector)
1989 * Parameters: exceptframe: pointer to exception handler frame on stack (2 ULONGs)
1990 * Variables :
1991 * Result :
1992 * Remark :
1993 * Status :
1994 *
1995 * Author : Sander van Leeuwen [Sun, 1999/08/21 12:16]
1996 *****************************************************************************/
1997void SYSTEM OS2UnsetExceptionHandler(void *exceptframe)
1998{
1999 PEXCEPTIONREGISTRATIONRECORD pExceptRec = (PEXCEPTIONREGISTRATIONRECORD)exceptframe;
2000
2001 DosUnsetExceptionHandler(pExceptRec);
2002 dprintf(("OS2UnsetExceptionHandler: exception chain %x", pExceptRec));
2003#ifdef DEBUG_ENABLELOG_LEVEL2
2004 PrintExceptionChain();
2005#endif
2006}
2007//*****************************************************************************
2008//*****************************************************************************
2009int _System CheckCurFS()
2010{
2011 USHORT sel = RestoreOS2FS();
2012 PEXCEPTIONREGISTRATIONRECORD pExceptRec;
2013
2014 if(sel == 0x150b) {
2015 SetFS(sel);
2016 return FALSE;
2017 }
2018 pExceptRec = (PEXCEPTIONREGISTRATIONRECORD)QueryExceptionChain();
2019 if(pExceptRec->ExceptionHandler != OS2ExceptionHandler) {
2020 SetFS(sel);
2021 return FALSE;
2022 }
2023 SetFS(sel);
2024 return TRUE;
2025}
2026//*****************************************************************************
2027//*****************************************************************************
2028
2029} // extern "C"
2030
Note: See TracBrowser for help on using the repository browser.