1 /* 2 Copyright (c) 2004/2005 KJK::Hyperion 3 4 Permission is hereby granted, free of charge, to any person obtaining a 5 copy of this software and associated documentation files (the "Software"), 6 to deal in the Software without restriction, including without limitation 7 the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 and/or sell copies of the Software, and to permit persons to whom the 9 Software is furnished to do so, subject to the following conditions: 10 11 The above copyright notice and this permission notice shall be included in 12 all copies or substantial portions of the Software. 13 14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 DEALINGS IN THE SOFTWARE. 21 */ 22 23 #define _NTSYSTEM_ 24 #define STRICT 25 #define WIN32_LEAN_AND_MEAN 26 #include <windows.h> 27 28 #include <pseh/pseh.h> 29 #include <pseh/framebased/internal.h> 30 #include <pseh/excpt.h> 31 #include <pseh/framebased.h> 32 33 #include <excpt.h> 34 35 /* Tracing */ 36 #ifdef _SEH_ENABLE_TRACE 37 extern unsigned long __cdecl DbgPrint(const char * format, ...); 38 39 #define _SEH_TRACE_HEADER_(FRAME_) \ 40 DbgPrint("[PSEH:%p]%s:%d:", FRAME_, __FILE__, __LINE__); 41 42 #define _SEH_TRACE_TRAILER_ \ 43 DbgPrint("\n"); 44 45 #define _SEH_FILTER_RET_STRING_(RET_) \ 46 (((int)(RET_) < 0) ? "_SEH_CONTINUE_EXECUTION" : (((int)(RET_) > 0) ? "_SEH_EXECUTE_HANDLER" : "_SEH_CONTINUE_SEARCH")) 47 48 #define _SEH_TRACE_LINE_(FRAME_, ARGS_) \ 49 { \ 50 _SEH_TRACE_HEADER_(FRAME_); \ 51 DbgPrint ARGS_; \ 52 _SEH_TRACE_TRAILER_; \ 53 } 54 55 #define _SEH_TRACE_ENTER(FRAME_, FUNCNAME_, ARGS_) \ 56 { \ 57 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_ENTER_LEAVE) \ 58 { \ 59 _SEH_TRACE_HEADER_(FRAME_); \ 60 DbgPrint(">>> %s(", (FUNCNAME_)); \ 61 DbgPrint ARGS_; \ 62 DbgPrint(")"); \ 63 _SEH_TRACE_TRAILER_; \ 64 } \ 65 } 66 67 #define _SEH_TRACE_LEAVE(FRAME_, FUNCNAME_, ARGS_) \ 68 { \ 69 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_ENTER_LEAVE) \ 70 { \ 71 _SEH_TRACE_HEADER_(FRAME_); \ 72 DbgPrint("<<< %s => ", (FUNCNAME_)); \ 73 DbgPrint ARGS_; \ 74 _SEH_TRACE_TRAILER_; \ 75 } \ 76 } 77 78 #define _SEH_TRACE_EXCEPTION_RECORD(FRAME_, ER_) \ 79 { \ 80 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_EXCEPTION_RECORD) \ 81 { \ 82 _SEH_TRACE_LINE_ \ 83 ( \ 84 (FRAME_), \ 85 ( \ 86 "ExceptionRecord %p = { ExceptionCode : %08X, ExceptionFlags : %08X, ExceptionRecord : %p, ExceptionAddress : %p }", \ 87 (ER_), \ 88 (ER_)->ExceptionCode, \ 89 (ER_)->ExceptionFlags, \ 90 (ER_)->ExceptionRecord, \ 91 (ER_)->ExceptionAddress \ 92 ) \ 93 ); \ 94 } \ 95 } 96 97 #ifdef _X86_ 98 #define _SEH_TRACE_CONTEXT(FRAME_, CONTEXT_) \ 99 { \ 100 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CONTEXT) \ 101 { \ 102 if(((CONTEXT_)->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) \ 103 { \ 104 _SEH_TRACE_LINE_ \ 105 ( \ 106 (FRAME_), \ 107 ( \ 108 "eax=%08X ebx=%08X ecx=%08X edx=%08X esi=%08X edi=%08X", \ 109 (CONTEXT_)->Eax, \ 110 (CONTEXT_)->Ebx, \ 111 (CONTEXT_)->Ecx, \ 112 (CONTEXT_)->Edx, \ 113 (CONTEXT_)->Esi, \ 114 (CONTEXT_)->Edi \ 115 ) \ 116 ); \ 117 } \ 118 \ 119 if(((CONTEXT_)->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) \ 120 { \ 121 _SEH_TRACE_LINE_ \ 122 ( \ 123 (FRAME_), \ 124 ( \ 125 "eip=%08X esp=%08X ebp=%08X efl=%08X cs=%08X ss=%08X", \ 126 (CONTEXT_)->Eip, \ 127 (CONTEXT_)->Esp, \ 128 (CONTEXT_)->Ebp, \ 129 (CONTEXT_)->EFlags, \ 130 (CONTEXT_)->SegCs, \ 131 (CONTEXT_)->SegSs \ 132 ) \ 133 ); \ 134 } \ 135 \ 136 if(((CONTEXT_)->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS) \ 137 { \ 138 _SEH_TRACE_LINE_ \ 139 ( \ 140 (FRAME_), \ 141 ( \ 142 "ds=%08X es=%08X fs=%08X gs=%08X", \ 143 (CONTEXT_)->SegDs, \ 144 (CONTEXT_)->SegEs, \ 145 (CONTEXT_)->SegFs, \ 146 (CONTEXT_)->SegGs \ 147 ) \ 148 ); \ 149 } \ 150 } \ 151 } 152 #else 153 #define _SEH_TRACE_CONTEXT(FRAME_, CONTEXT_) 154 #endif 155 156 #define _SEH_TRACE_UNWIND(FRAME_, ARGS_) \ 157 { \ 158 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_UNWIND) \ 159 { \ 160 _SEH_TRACE_LINE_((FRAME_), ARGS_); \ 161 } \ 162 } 163 164 #define _SEH_TRACE_TRYLEVEL(FRAME_, TRYLEVEL_) \ 165 { \ 166 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_TRYLEVEL) \ 167 { \ 168 _SEH_TRACE_LINE_((FRAME_), ("trylevel %p, filter %p", (TRYLEVEL_), (TRYLEVEL_)->SPT_Handlers.SH_Filter)); \ 169 } \ 170 } 171 172 #define _SEH_TRACE_ENTER_CALL_FILTER(FRAME_, TRYLEVEL_, ER_) \ 173 { \ 174 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CALL_FILTER) \ 175 { \ 176 _SEH_TRACE_LINE_ \ 177 ( \ 178 (FRAME_), \ 179 ( \ 180 "trylevel %p, calling filter %p, ExceptionCode %08X", \ 181 (TRYLEVEL_), \ 182 (TRYLEVEL_)->SPT_Handlers.SH_Filter, \ 183 (ER_)->ExceptionCode \ 184 ) \ 185 ); \ 186 } \ 187 } 188 189 #define _SEH_TRACE_LEAVE_CALL_FILTER(FRAME_, TRYLEVEL_, RET_) \ 190 { \ 191 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CALL_FILTER) \ 192 { \ 193 _SEH_TRACE_LINE_ \ 194 ( \ 195 (FRAME_), \ 196 ( \ 197 "trylevel %p, filter %p => %s", \ 198 (TRYLEVEL_), \ 199 (TRYLEVEL_)->SPT_Handlers.SH_Filter, \ 200 _SEH_FILTER_RET_STRING_(RET_) \ 201 ) \ 202 ); \ 203 } \ 204 } 205 206 #define _SEH_TRACE_FILTER(FRAME_, TRYLEVEL_, RET_) \ 207 { \ 208 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_FILTER) \ 209 { \ 210 _SEH_TRACE_LINE_ \ 211 ( \ 212 (FRAME_), \ 213 ( \ 214 "trylevel %p => %s", \ 215 (TRYLEVEL_), \ 216 _SEH_FILTER_RET_STRING_(RET_) \ 217 ) \ 218 ); \ 219 } \ 220 } 221 222 #define _SEH_TRACE_ENTER_CALL_HANDLER(FRAME_, TRYLEVEL_) \ 223 { \ 224 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CALL_HANDLER) \ 225 { \ 226 _SEH_TRACE_LINE_((FRAME_), ("trylevel %p, handling", (TRYLEVEL_))); \ 227 } \ 228 } 229 230 #define _SEH_TRACE_ENTER_CALL_FINALLY(FRAME_, TRYLEVEL_) \ 231 { \ 232 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CALL_FINALLY) \ 233 { \ 234 _SEH_TRACE_LINE_ \ 235 ( \ 236 (FRAME_), \ 237 ( \ 238 "trylevel %p, calling exit routine %p", \ 239 (TRYLEVEL_), \ 240 (TRYLEVEL_)->SPT_Handlers.SH_Finally \ 241 ) \ 242 ); \ 243 } \ 244 } 245 246 #define _SEH_TRACE_LEAVE_CALL_FINALLY(FRAME_, TRYLEVEL_) \ 247 { \ 248 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CALL_FINALLY) \ 249 { \ 250 _SEH_TRACE_LINE_ \ 251 ( \ 252 (FRAME_), \ 253 ( \ 254 "trylevel %p, exit routine %p returned", \ 255 (TRYLEVEL_), \ 256 (TRYLEVEL_)->SPT_Handlers.SH_Finally \ 257 ) \ 258 ); \ 259 } \ 260 } 261 262 #else 263 #define _SEH_TRACE_ENTER(FRAME_, FUNCNAME_, ARGS_) 264 #define _SEH_TRACE_LEAVE(FRAME_, FUNCNAME_, ARGS_) 265 #define _SEH_TRACE_EXCEPTION_RECORD(FRAME_, ER_) 266 #define _SEH_TRACE_CONTEXT(FRAME_, CONTEXT_) 267 #define _SEH_TRACE_UNWIND(FRAME_, ARGS_) 268 #define _SEH_TRACE_TRYLEVEL(FRAME_, TRYLEVEL_) 269 #define _SEH_TRACE_ENTER_CALL_FILTER(FRAME_, TRYLEVEL_, ER_) 270 #define _SEH_TRACE_LEAVE_CALL_FILTER(FRAME_, TRYLEVEL_, RET_) 271 #define _SEH_TRACE_FILTER(FRAME_, TRYLEVEL_, RET_) 272 #define _SEH_TRACE_ENTER_CALL_HANDLER(FRAME_, TRYLEVEL_) 273 #define _SEH_TRACE_ENTER_CALL_FINALLY(FRAME_, TRYLEVEL_) 274 #define _SEH_TRACE_LEAVE_CALL_FINALLY(FRAME_, TRYLEVEL_) 275 #endif 276 277 /* Assembly helpers, see i386/framebased.asm */ 278 extern void __cdecl _SEHCleanHandlerEnvironment(void); 279 extern struct __SEHRegistration * __cdecl _SEHRegisterFrame(_SEHRegistration_t *); 280 extern void __cdecl _SEHUnregisterFrame(void); 281 extern void __cdecl _SEHGlobalUnwind(_SEHPortableFrame_t *); 282 extern _SEHRegistration_t * __cdecl _SEHCurrentRegistration(void); 283 284 /* Borland C++ uses a different decoration (i.e. none) for stdcall functions */ 285 extern void __stdcall RtlUnwind(void *, void *, PEXCEPTION_RECORD, void *); 286 void const * _SEHRtlUnwind = RtlUnwind; 287 288 static void __stdcall _SEHLocalUnwind 289 ( 290 _SEHPortableFrame_t * frame, 291 _SEHPortableTryLevel_t * dsttrylevel 292 ) 293 { 294 _SEHPortableTryLevel_t * trylevel; 295 296 _SEH_TRACE_UNWIND(frame, ("enter local unwind from %p to %p", frame->SPF_TopTryLevel, dsttrylevel)); 297 298 for 299 ( 300 trylevel = frame->SPF_TopTryLevel; 301 trylevel != dsttrylevel; 302 trylevel = trylevel->SPT_Next 303 ) 304 { 305 _SEHFinally_t pfnFinally; 306 307 /* ASSERT(trylevel); */ 308 309 pfnFinally = trylevel->SPT_Handlers.SH_Finally; 310 311 if(pfnFinally) 312 { 313 _SEH_TRACE_ENTER_CALL_FINALLY(frame, trylevel); 314 pfnFinally(frame); 315 _SEH_TRACE_LEAVE_CALL_FINALLY(frame, trylevel); 316 } 317 } 318 319 _SEH_TRACE_UNWIND(frame, ("leave local unwind from %p to %p", frame->SPF_TopTryLevel, dsttrylevel)); 320 } 321 322 static void __cdecl _SEHCallHandler 323 ( 324 _SEHPortableFrame_t * frame, 325 _SEHPortableTryLevel_t * trylevel 326 ) 327 { 328 _SEHGlobalUnwind(frame); 329 _SEHLocalUnwind(frame, trylevel); 330 _SEH_TRACE_ENTER_CALL_HANDLER(frame, trylevel); 331 frame->SPF_Handler(trylevel); 332 /* ASSERT(0); */ 333 } 334 335 static int __cdecl _SEHFrameHandler 336 ( 337 struct _EXCEPTION_RECORD * ExceptionRecord, 338 void * EstablisherFrame, 339 struct _CONTEXT * ContextRecord, 340 void * DispatcherContext 341 ) 342 { 343 _SEHPortableFrame_t * frame; 344 345 _SEHCleanHandlerEnvironment(); 346 347 frame = EstablisherFrame; 348 349 _SEH_TRACE_ENTER 350 ( 351 frame, 352 "_SEHFrameHandler", 353 ( 354 "%p, %p, %p, %p", 355 ExceptionRecord, 356 EstablisherFrame, 357 ContextRecord, 358 DispatcherContext 359 ) 360 ); 361 362 _SEH_TRACE_EXCEPTION_RECORD(frame, ExceptionRecord); 363 _SEH_TRACE_CONTEXT(frame, ContextRecord); 364 365 /* Unwinding */ 366 if(ExceptionRecord->ExceptionFlags & (4 | 2)) 367 { 368 _SEH_TRACE_UNWIND(frame, ("enter forced unwind")); 369 _SEHLocalUnwind(frame, NULL); 370 _SEH_TRACE_UNWIND(frame, ("leave forced unwind")); 371 } 372 /* Handling */ 373 else 374 { 375 int ret; 376 _SEHPortableTryLevel_t * trylevel; 377 378 if(ExceptionRecord->ExceptionCode) 379 frame->SPF_Code = ExceptionRecord->ExceptionCode; 380 else 381 frame->SPF_Code = 0xC0000001; 382 383 for 384 ( 385 trylevel = frame->SPF_TopTryLevel; 386 trylevel != NULL; 387 trylevel = trylevel->SPT_Next 388 ) 389 { 390 _SEHFilter_t pfnFilter = trylevel->SPT_Handlers.SH_Filter; 391 392 _SEH_TRACE_TRYLEVEL(frame, trylevel); 393 394 switch((UINT_PTR)pfnFilter) 395 { 396 case (UINT_PTR)_SEH_STATIC_FILTER(_SEH_EXECUTE_HANDLER): 397 case (UINT_PTR)_SEH_STATIC_FILTER(_SEH_CONTINUE_SEARCH): 398 case (UINT_PTR)_SEH_STATIC_FILTER(_SEH_CONTINUE_EXECUTION): 399 { 400 ret = (int)((UINT_PTR)pfnFilter) - 2; 401 break; 402 } 403 404 default: 405 { 406 if(trylevel->SPT_Handlers.SH_Filter) 407 { 408 EXCEPTION_POINTERS ep; 409 410 ep.ExceptionRecord = ExceptionRecord; 411 ep.ContextRecord = ContextRecord; 412 413 _SEH_TRACE_ENTER_CALL_FILTER(frame, trylevel, ExceptionRecord); 414 ret = pfnFilter(&ep, frame); 415 _SEH_TRACE_LEAVE_CALL_FILTER(frame, trylevel, ret); 416 } 417 else 418 ret = _SEH_CONTINUE_SEARCH; 419 420 break; 421 } 422 } 423 424 _SEH_TRACE_FILTER(frame, trylevel, ret); 425 426 /* _SEH_CONTINUE_EXECUTION */ 427 if(ret < 0) 428 { 429 _SEH_TRACE_LEAVE(frame, "_SEHFrameHandler", ("ExceptionContinueExecution")); 430 return ExceptionContinueExecution; 431 } 432 /* _SEH_EXECUTE_HANDLER */ 433 else if(ret > 0) 434 _SEHCallHandler(frame, trylevel); 435 /* _SEH_CONTINUE_SEARCH */ 436 else 437 continue; 438 } 439 440 /* FALLTHROUGH */ 441 } 442 443 _SEH_TRACE_LEAVE(frame, "_SEHFrameHandler", ("ExceptionContinueSearch")); 444 return ExceptionContinueSearch; 445 } 446 447 void __stdcall _SEHEnterFrame_s(_SEHPortableFrame_t * frame) 448 { 449 _SEHEnterFrame_f(frame); 450 } 451 452 void __stdcall _SEHLeaveFrame_s(void) 453 { 454 _SEHLeaveFrame_f(); 455 } 456 457 void __stdcall _SEHReturn_s(void) 458 { 459 _SEHReturn_f(); 460 } 461 462 void _SEH_FASTCALL _SEHEnterFrame_f(_SEHPortableFrame_t * frame) 463 { 464 /* ASSERT(frame); */ 465 /* ASSERT(trylevel); */ 466 frame->SPF_Registration.SER_Handler = _SEHFrameHandler; 467 frame->SPF_Code = 0; 468 _SEHRegisterFrame(&frame->SPF_Registration); 469 } 470 471 void _SEH_FASTCALL _SEHLeaveFrame_f(void) 472 { 473 /* _SEHPortableFrame_t * frame; 474 475 frame = _SEH_CONTAINING_RECORD 476 ( 477 _SEHCurrentRegistration(), 478 _SEHPortableFrame_t, 479 SPF_Registration 480 ); */ 481 482 /* ASSERT(frame); */ 483 /* ASSERT(frame->SPF_TopTryLevel == NULL) */ 484 485 _SEHUnregisterFrame(); 486 } 487 488 void _SEH_FASTCALL _SEHReturn_f(void) 489 { 490 _SEHPortableFrame_t * frame; 491 492 frame = _SEH_CONTAINING_RECORD 493 ( 494 _SEHCurrentRegistration(), 495 _SEHPortableFrame_t, 496 SPF_Registration 497 ); 498 499 _SEHLocalUnwind(frame, NULL); 500 _SEHUnregisterFrame(); 501 } 502 503 /* EOF */ 504