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

Last change on this file since 21662 was 21662, checked in by dmik, 14 years ago

kernel32: SEH: Disabled unwinding Win32 exception handlers in response to the OS/2 unwind procedure to prevent endless recursive crashes inside OS2RtlUnwind() happening due to stack corruption under SMP kernel when too many threads are being unwound at once. Closes #37.

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