Reactos
at listview 348 lines 10 kB view raw
1/* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Runtime Library 4 * PURPOSE: User-Mode Exception Support 5 * FILE: lib/rtl/exception.c 6 * PROGRAMERS: Alex Ionescu (alex@relsoft.net) 7 * David Welch <welch@cwcom.net> 8 * Skywing <skywing@valhallalegends.com> 9 * KJK::Hyperion <noog@libero.it> 10 */ 11 12/* INCLUDES *****************************************************************/ 13 14#include <rtl.h> 15 16#define NDEBUG 17#include <debug.h> 18 19/* GLOBALS *****************************************************************/ 20 21PRTLP_UNHANDLED_EXCEPTION_FILTER RtlpUnhandledExceptionFilter; 22 23/* FUNCTIONS ***************************************************************/ 24 25#if !defined(_M_IX86) && !defined(_M_AMD64) 26 27/* 28 * @implemented 29 */ 30VOID 31NTAPI 32RtlRaiseException(IN PEXCEPTION_RECORD ExceptionRecord) 33{ 34 CONTEXT Context; 35 NTSTATUS Status; 36 37 /* Capture the context */ 38 RtlCaptureContext(&Context); 39 40 /* Save the exception address */ 41 ExceptionRecord->ExceptionAddress = _ReturnAddress(); 42 43 /* Write the context flag */ 44 Context.ContextFlags = CONTEXT_FULL; 45 46 /* Check if user mode debugger is active */ 47 if (RtlpCheckForActiveDebugger()) 48 { 49 /* Raise an exception immediately */ 50 Status = ZwRaiseException(ExceptionRecord, &Context, TRUE); 51 } 52 else 53 { 54 /* Dispatch the exception and check if we should continue */ 55 if (!RtlDispatchException(ExceptionRecord, &Context)) 56 { 57 /* Raise the exception */ 58 Status = ZwRaiseException(ExceptionRecord, &Context, FALSE); 59 } 60 else 61 { 62 /* Continue, go back to previous context */ 63 Status = ZwContinue(&Context, FALSE); 64 } 65 } 66 67 /* If we returned, raise a status */ 68 RtlRaiseStatus(Status); 69} 70 71#endif 72 73#if !defined(_M_IX86) 74 75#ifdef _MSC_VER 76#pragma warning(push) 77#pragma warning(disable:4717) // RtlRaiseStatus is recursive by design 78#endif 79 80/* 81 * @implemented 82 */ 83VOID 84NTAPI 85RtlRaiseStatus(IN NTSTATUS Status) 86{ 87 EXCEPTION_RECORD ExceptionRecord; 88 CONTEXT Context; 89 90 /* Capture the context */ 91 RtlCaptureContext(&Context); 92 93 /* Create an exception record */ 94 ExceptionRecord.ExceptionAddress = _ReturnAddress(); 95 ExceptionRecord.ExceptionCode = Status; 96 ExceptionRecord.ExceptionRecord = NULL; 97 ExceptionRecord.NumberParameters = 0; 98 ExceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE; 99 100 /* Write the context flag */ 101 Context.ContextFlags = CONTEXT_FULL; 102 103 /* Check if user mode debugger is active */ 104 if (RtlpCheckForActiveDebugger()) 105 { 106 /* Raise an exception immediately */ 107 ZwRaiseException(&ExceptionRecord, &Context, TRUE); 108 } 109 else 110 { 111 /* Dispatch the exception */ 112 RtlDispatchException(&ExceptionRecord, &Context); 113 114 /* Raise exception if we got here */ 115 Status = ZwRaiseException(&ExceptionRecord, &Context, FALSE); 116 } 117 118 /* If we returned, raise a status */ 119 RtlRaiseStatus(Status); 120} 121 122#ifdef _MSC_VER 123#pragma warning(pop) 124#endif 125 126#endif 127 128/* 129 * @implemented 130 */ 131USHORT 132NTAPI 133RtlCaptureStackBackTrace(IN ULONG FramesToSkip, 134 IN ULONG FramesToCapture, 135 OUT PVOID *BackTrace, 136 OUT PULONG BackTraceHash OPTIONAL) 137{ 138 PVOID Frames[2 * 64]; 139 ULONG FrameCount; 140 ULONG Hash = 0, i; 141 142 /* Skip a frame for the caller */ 143 FramesToSkip++; 144 145 /* Don't go past the limit */ 146 if ((FramesToCapture + FramesToSkip) >= 128) return 0; 147 148 /* Do the back trace */ 149 FrameCount = RtlWalkFrameChain(Frames, FramesToCapture + FramesToSkip, 0); 150 151 /* Make sure we're not skipping all of them */ 152 if (FrameCount <= FramesToSkip) return 0; 153 154 /* Loop all the frames */ 155 for (i = 0; i < FramesToCapture; i++) 156 { 157 /* Don't go past the limit */ 158 if ((FramesToSkip + i) >= FrameCount) break; 159 160 /* Save this entry and hash it */ 161 BackTrace[i] = Frames[FramesToSkip + i]; 162 Hash += PtrToUlong(BackTrace[i]); 163 } 164 165 /* Write the hash */ 166 if (BackTraceHash) *BackTraceHash = Hash; 167 168 /* Clear the other entries and return count */ 169 RtlFillMemoryUlong(Frames, 128, 0); 170 return (USHORT)i; 171} 172 173/* 174* Private helper function to lookup the module name from a given address. 175* The address can point to anywhere within the module. 176*/ 177static const char* 178 _module_name_from_addr(const void* addr, void **module_start_addr, 179 char* psz, size_t nChars) 180{ 181#if 0 182 MEMORY_BASIC_INFORMATION mbi; 183 if (VirtualQuery(addr, &mbi, sizeof(mbi)) != sizeof(mbi) || 184 !GetModuleFileNameA((HMODULE) mbi.AllocationBase, psz, nChars)) 185 { 186 psz[0] = '\0'; 187 *module_start_addr = 0; 188 } 189 else 190 { 191 *module_start_addr = (void *) mbi.AllocationBase; 192 } 193 return psz; 194#else 195 psz[0] = '\0'; 196 *module_start_addr = 0; 197 return psz; 198#endif 199} 200 201 202static VOID 203 _dump_context(PCONTEXT pc) 204{ 205#ifdef _M_IX86 206 /* 207 * Print out the CPU registers 208 */ 209 DbgPrint("CS:EIP %x:%x\n", pc->SegCs & 0xffff, pc->Eip); 210 DbgPrint("DS %x ES %x FS %x GS %x\n", pc->SegDs & 0xffff, pc->SegEs & 0xffff, 211 pc->SegFs & 0xffff, pc->SegGs & 0xfff); 212 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", pc->Eax, pc->Ebx, pc->Ecx); 213 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x ESP: %.8x\n", pc->Edx, 214 pc->Ebp, pc->Esi, pc->Esp); 215 DbgPrint("EDI: %.8x EFLAGS: %.8x\n", pc->Edi, pc->EFlags); 216#elif defined(_M_AMD64) 217 DbgPrint("CS:RIP %x:%I64x\n", pc->SegCs & 0xffff, pc->Rip); 218 DbgPrint("DS %x ES %x FS %x GS %x\n", pc->SegDs & 0xffff, pc->SegEs & 0xffff, 219 pc->SegFs & 0xffff, pc->SegGs & 0xfff); 220 DbgPrint("RAX: %I64x RBX: %I64x RCX: %I64x RDI: %I64x\n", pc->Rax, pc->Rbx, pc->Rcx, pc->Rdi); 221 DbgPrint("RDX: %I64x RBP: %I64x RSI: %I64x RSP: %I64x\n", pc->Rdx, pc->Rbp, pc->Rsi, pc->Rsp); 222 DbgPrint("R8: %I64x R9: %I64x R10: %I64x R11: %I64x\n", pc->R8, pc->R9, pc->R10, pc->R11); 223 DbgPrint("R12: %I64x R13: %I64x R14: %I64x R15: %I64x\n", pc->R12, pc->R13, pc->R14, pc->R15); 224 DbgPrint("EFLAGS: %.8x\n", pc->EFlags); 225#elif defined(_M_ARM) 226 DbgPrint("Pc: %lx Lr: %lx Sp: %lx Cpsr: %lx\n", pc->Pc, pc->Lr, pc->Sp, pc->Cpsr); 227 DbgPrint("R0: %lx R1: %lx R2: %lx R3: %lx\n", pc->R0, pc->R1, pc->R2, pc->R3); 228 DbgPrint("R4: %lx R5: %lx R6: %lx R7: %lx\n", pc->R4, pc->R5, pc->R6, pc->R7); 229 DbgPrint("R8: %lx R9: %lx R10: %lx R11: %lx\n", pc->R8, pc->R9, pc->R10, pc->R11); 230 DbgPrint("R12: %lx\n", pc->R12); 231#else 232#pragma message ("Unknown architecture") 233#endif 234} 235 236static VOID 237PrintStackTrace(struct _EXCEPTION_POINTERS *ExceptionInfo) 238{ 239 PVOID StartAddr; 240 CHAR szMod[128] = ""; 241 PEXCEPTION_RECORD ExceptionRecord = ExceptionInfo->ExceptionRecord; 242 PCONTEXT ContextRecord = ExceptionInfo->ContextRecord; 243 244 /* Print a stack trace */ 245 DbgPrint("Unhandled exception\n"); 246 DbgPrint("ExceptionCode: %8x\n", ExceptionRecord->ExceptionCode); 247 248 if ((NTSTATUS) ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION && 249 ExceptionRecord->NumberParameters == 2) 250 { 251 DbgPrint("Faulting Address: %8x\n", ExceptionRecord->ExceptionInformation[1]); 252 } 253 254 /* Trace the wine special error and show the modulename and functionname */ 255 if (ExceptionRecord->ExceptionCode == 0x80000100 /* EXCEPTION_WINE_STUB */ && 256 ExceptionRecord->NumberParameters == 2) 257 { 258 DbgPrint("Missing function: %s!%s\n", (PSZ)ExceptionRecord->ExceptionInformation[0], (PSZ)ExceptionRecord->ExceptionInformation[1]); 259 } 260 261 _dump_context(ContextRecord); 262 _module_name_from_addr(ExceptionRecord->ExceptionAddress, &StartAddr, szMod, sizeof(szMod)); 263 DbgPrint("Address:\n %8x+%-8x %s\n", 264 (PVOID) StartAddr, 265 (ULONG_PTR) ExceptionRecord->ExceptionAddress - (ULONG_PTR) StartAddr, 266 szMod); 267#ifdef _M_IX86 268 DbgPrint("Frames:\n"); 269 270 _SEH2_TRY 271 { 272 UINT i; 273 PULONG Frame = (PULONG) ContextRecord->Ebp; 274 275 for (i = 0; Frame[1] != 0 && Frame[1] != 0xdeadbeef && i < 128; i++) 276 { 277 //if (IsBadReadPtr((PVOID) Frame[1], 4)) 278 if (Frame[1] == 0) 279 { 280 DbgPrint(" %8x%9s %s\n", Frame[1], "<invalid address>", " "); 281 } 282 else 283 { 284 _module_name_from_addr((const void*) Frame[1], &StartAddr, 285 szMod, sizeof(szMod)); 286 DbgPrint(" %8x+%-8x %s\n", 287 (PVOID) StartAddr, 288 (ULONG_PTR) Frame[1] - (ULONG_PTR) StartAddr, 289 szMod); 290 } 291 292 if (Frame[0] == 0) break; 293 //if (IsBadReadPtr((PVOID) Frame[0], sizeof(*Frame) * 2)) 294 //break; 295 296 Frame = (PULONG) Frame[0]; 297 } 298 } 299 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 300 { 301 DbgPrint("<error dumping stack trace: 0x%x>\n", _SEH2_GetExceptionCode()); 302 } 303 _SEH2_END; 304#endif 305} 306 307 308/* 309 * @unimplemented 310 */ 311LONG 312NTAPI 313RtlUnhandledExceptionFilter( 314 _In_ PEXCEPTION_POINTERS ExceptionInfo) 315{ 316 return RtlUnhandledExceptionFilter2(ExceptionInfo, ""); 317} 318 319/* 320 * @unimplemented 321 */ 322LONG 323NTAPI 324RtlUnhandledExceptionFilter2( 325 _In_ PEXCEPTION_POINTERS ExceptionInfo, 326 _In_ PCSTR Function) 327{ 328 /* This is used by the security cookie checks, and also called externally */ 329 UNIMPLEMENTED; 330 ASSERT(ExceptionInfo && ExceptionInfo->ExceptionRecord); 331 332 PrintStackTrace(ExceptionInfo); 333 334 if (ExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_POSSIBLE_DEADLOCK) 335 return EXCEPTION_CONTINUE_EXECUTION; 336 return EXCEPTION_CONTINUE_SEARCH; 337} 338 339/* 340 * @implemented 341 */ 342VOID 343NTAPI 344RtlSetUnhandledExceptionFilter(IN PRTLP_UNHANDLED_EXCEPTION_FILTER TopLevelExceptionFilter) 345{ 346 /* Set the filter which is used by the CriticalSection package */ 347 RtlpUnhandledExceptionFilter = RtlEncodePointer(TopLevelExceptionFilter); 348}