source: trunk/src/kernel32/exceptions.cpp

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

kernel32: Pick up register changes in try/except filter.

This is a regression of r21999. Fixes endless exceptions eventually
leading to program termination.

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