VOID Get_Exception_Info(PEXCEPTION_POINTERS pException, FILE* fp, UINT dwLastError) { CHAR Module_Name[MAX_PATH]; PBYTE Module_Addr; HANDLE hFile; FILETIME Last_Write_Time; FILETIME Local_File_Time; SYSTEMTIME T; Get_Version_Str(fp); _ftprintf(fp, _T("------------------------------------------------------------------------------\n")); _ftprintf(fp, _T("Process: ") ); GetModuleFileName(NULL, Module_Name, MAX_PATH); _ftprintf(fp, _T("%s\n") , Module_Name); // If exception occurred. if (pException) { EXCEPTION_RECORD & E = *pException->ExceptionRecord; CONTEXT & C = *pException->ContextRecord; // If module with E.ExceptionAddress found - save its path and date. if (Get_Module_By_Ret_Addr((PBYTE)E.ExceptionAddress, Module_Name, Module_Addr)) { _ftprintf(fp, _T("Module: %s\n") , Module_Name); if ((hFile = CreateFile(Module_Name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE) { if (GetFileTime(hFile, NULL, NULL, &Last_Write_Time)) { FileTimeToLocalFileTime(&Last_Write_Time, &Local_File_Time); FileTimeToSystemTime(&Local_File_Time, &T); _ftprintf(fp, _T("Date Modified: %02d/%02d/%d\n") , T.wMonth, T.wDay, T.wYear); } CloseHandle(hFile); } } else { _ftprintf(fp, _T("Exception Addr: %08X\n") , (LONG_PTR)(E.ExceptionAddress)); } _ftprintf(fp, _T("------------------------------------------------------------------------------\n")); //加入具体异常解释信息 CreateExceptionDesc(pException, fp, dwLastError); } _ftprintf(fp, _T("------------------------------------------------------------------------------\n")); // Save call stack info. _ftprintf(fp, _T("Call Stack:\n")); Get_Call_Stack(pException, fp); }
bool shouldUseStackWalker(PSTACK Ebp, int max_depth) { WCHAR Module_Name[MAX_PATH]; PBYTE Module_Addr = 0; int depth = 0; while (depth < max_depth) { if (IsBadReadPtr(Ebp, sizeof(PSTACK)) || IsBadReadPtr(Ebp->Ebp, sizeof(PSTACK)) || Ebp->Ebp < Ebp || Ebp->Ebp - Ebp > 0xFFFFFF || IsBadCodePtr(FARPROC(Ebp->Ebp->Ret_Addr)) || !Get_Module_By_Ret_Addr(Ebp->Ebp->Ret_Addr, Module_Name, Module_Addr)) { return true; } depth++; Ebp = Ebp->Ebp; } return false; }
PBYTE get_valid_frame(PBYTE esp) { PDWORD cur_stack_loc = NULL; const int max_search = 400; WCHAR module_name[MAX_PATH]; PBYTE module_addr = 0; // round to highest multiple of four esp = (esp + (4 - ((int)esp % 4)) % 4); // scroll through stack a few hundred places. for (cur_stack_loc = (PDWORD) esp; cur_stack_loc < (PDWORD)esp + max_search; cur_stack_loc += 1) { // if you can read the pointer, if (IsBadReadPtr(cur_stack_loc, sizeof(PDWORD))) { continue; } // check if it's in a module if (!Get_Module_By_Ret_Addr((PBYTE)*cur_stack_loc, module_name, module_addr)) { continue; } // check if the code before the instruction ptr is a call if(!has_valid_call_before(cur_stack_loc)) { continue; } // if these all pass, return that ebp, otherwise continue till we're dead return (PBYTE)(cur_stack_loc - 1); } return NULL; }
//************************************************************* void Get_Exception_Info(PEXCEPTION_POINTERS pException, FILE* fp, DWORD dwLastError) //************************************************************* // Allocate Str[DUMP_SIZE_MAX] and return Str with dump, if !pException - just return call stack in Str. { int i; TCHAR Module_Name[MAX_PATH]; PBYTE Module_Addr; HANDLE hFile; FILETIME Last_Write_Time; FILETIME Local_File_Time; SYSTEMTIME T; Get_Version_Str(fp); _ftprintf(fp, _T("------------------------------------------------------------------------------")NL); _ftprintf(fp, _T("Process: ") ); GetModuleFileName(NULL, Module_Name, MAX_PATH); _ftprintf(fp, _T("%s") NL, Module_Name); // If exception occurred. if (pException) { EXCEPTION_RECORD & E = *pException->ExceptionRecord; CONTEXT & C = *pException->ContextRecord; // If module with E.ExceptionAddress found - save its path and date. if (Get_Module_By_Ret_Addr((PBYTE)E.ExceptionAddress, Module_Name, Module_Addr)) { _ftprintf(fp, _T("Module: %s") NL, Module_Name); if ((hFile = CreateFile(Module_Name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE) { if (GetFileTime(hFile, NULL, NULL, &Last_Write_Time)) { FileTimeToLocalFileTime(&Last_Write_Time, &Local_File_Time); FileTimeToSystemTime(&Local_File_Time, &T); _ftprintf(fp, _T("Date Modified: %02d/%02d/%d") NL, T.wMonth, T.wDay, T.wYear); } CloseHandle(hFile); } } else { _ftprintf(fp, _T("Exception Addr: %08X") NL , (LONG_PTR)(E.ExceptionAddress)); } _ftprintf(fp, _T("------------------------------------------------------------------------------")NL); //加入具体异常解释信息 CreateExceptionDesc(pException, fp, dwLastError); _ftprintf(fp, _T("------------------------------------------------------------------------------")NL); // Save instruction that caused exception. if(E.ExceptionAddress) { _ftprintf(fp, _T("Instruction: ")NL); for (i = 0; i < 16; i++) _ftprintf(fp, _T(" %02X"), PBYTE(E.ExceptionAddress)[i]); } // Save registers at exception. _ftprintf(fp, NL _T("Registers:") NL); _ftprintf(fp, _T("EAX: %08X EBX: %08X ECX: %08X EDX: %08X") NL, C.Eax, C.Ebx, C.Ecx, C.Edx); _ftprintf(fp, _T("ESI: %08X EDI: %08X ESP: %08X EBP: %08X")NL, C.Esi, C.Edi, C.Esp, C.Ebp); _ftprintf(fp, _T("EIP: %08X EFlags: %08X")NL, C.Eip, C.EFlags); } //if (pException) _ftprintf(fp, _T("------------------------------------------------------------------------------")NL); // Save call stack info. _ftprintf(fp, _T("Call Stack:")NL); Get_Call_Stack(pException, fp); } //Get_Exception_Info
void CreateExceptionDesc(PEXCEPTION_POINTERS pException, FILE* fp, DWORD dwLastError) { if (!pException || !fp) return; EXCEPTION_RECORD & E = *pException->ExceptionRecord; CONTEXT & C = *pException->ContextRecord; //取得异常发生地 TCHAR szModeleInfo[MAX_PATH]; TCHAR Module_Name[MAX_PATH]; PBYTE Module_Addr; if (Get_Module_By_Ret_Addr((PBYTE)E.ExceptionAddress, Module_Name, Module_Addr)) { _sntprintf(szModeleInfo, MAX_PATH, _T("%s"), Module_Name); } else { _sntprintf(szModeleInfo, MAX_PATH, _T("%08X"), (DWORD_PTR)(E.ExceptionAddress)); } switch(E.ExceptionCode) { //核心软异常 case 0XE000C0DE: { tException* pException = (tException*)E.ExceptionInformation[0]; if(!pException) return; //断言错误 if(pException->m_bAssert) { _ftprintf(fp, _T("\t\tAssert \n") _T("\n") _T("File: %s\n") _T("Line: %d\n") _T("Expr: %s\n") _T("LastError: 0X%08X\n"), pException->m_strFileName.c_str(), pException->m_nLineNum, pException->m_strMessage.c_str(), pException->m_dwLastError); } else { _ftprintf(fp, _T("\t\tGeneral \n") _T("\n") _T("Expr: %s\n") _T("LastError: 0x%08X\n"), pException->m_strMessage.c_str(), pException->m_dwLastError); } } break; //试图对一个虚地址进行读写 case EXCEPTION_ACCESS_VIOLATION: { // Access violation type - Write/Read. _ftprintf(fp, _T("\t\tAccess violation\n") _T("\n") _T("@: %s\n") _T("Operate: %s\n") _T("Address: 0x%08X\n") _T("LastError: 0x%08X\n"), szModeleInfo, (E.ExceptionInformation[0]) ? _T("Write") : _T("Read"), E.ExceptionInformation[1], dwLastError); } break; default: { _ftprintf(fp, _T("\t\tOTHER\n") _T("\n") _T("@: %s\n") _T("Code: 0x%08X\n") _T("LastError: 0x%08X\n"), szModeleInfo, E.ExceptionCode, dwLastError); } break; } }
//****************************************************************** void Get_Call_Stack(PEXCEPTION_POINTERS pException, FILE* fp) //****************************************************************** // Fill Str with call stack info. // pException can be either GetExceptionInformation() or NULL. // If pException = NULL - get current call stack. { TCHAR Module_Name[MAX_PATH]; PBYTE Module_Addr = 0; PBYTE Module_Addr_1; #pragma warning(disable: 4200) //nonstandard extension used : zero-sized array in struct/union typedef struct STACK { STACK * Ebp; PBYTE Ret_Addr; DWORD Param[0]; } STACK, * PSTACK; #pragma warning(default: 4200) STACK Stack = {0, 0}; PSTACK Ebp; if (pException) //fake frame for exception address { Stack.Ebp = (PSTACK)(DWORD_PTR)pException->ContextRecord->Ebp; Stack.Ret_Addr = (PBYTE)pException->ExceptionRecord->ExceptionAddress; Ebp = &Stack; } else { Ebp = (PSTACK)&pException - 1; //frame addr of Get_Call_Stack() // Skip frame of Get_Call_Stack(). if (!IsBadReadPtr(Ebp, sizeof(PSTACK))) Ebp = Ebp->Ebp; //caller ebp } // Trace CALL_TRACE_MAX calls maximum - not to exceed DUMP_SIZE_MAX. // Break trace on wrong stack frame. for (int Ret_Addr_I = 0; (Ret_Addr_I < CALL_TRACE_MAX) && !IsBadReadPtr(Ebp, sizeof(PSTACK)) && !IsBadCodePtr(FARPROC(Ebp->Ret_Addr)); Ret_Addr_I++, Ebp = Ebp->Ebp) { // If module with Ebp->Ret_Addr found. if (Get_Module_By_Ret_Addr(Ebp->Ret_Addr, Module_Name, Module_Addr_1)) { if (Module_Addr_1 != Module_Addr) //new module { // Save module's address and full path. Module_Addr = Module_Addr_1; _ftprintf(fp, _T("%08X %s")NL, (LONG_PTR)Module_Addr, Module_Name); } // Save call offset. _ftprintf(fp, _T(" +%08X"), Ebp->Ret_Addr - Module_Addr); // Save 5 params of the call. We don't know the real number of params. if (pException && !Ret_Addr_I) //fake frame for exception address _ftprintf(fp, _T(" Exception Offset") NL); else if (!IsBadReadPtr(Ebp, sizeof(PSTACK) + 5 * sizeof(DWORD))) { _ftprintf(fp, _T(" (%X, %X, %X, %X, %X)") NL, Ebp->Param[0], Ebp->Param[1], Ebp->Param[2], Ebp->Param[3], Ebp->Param[4]); } } else _ftprintf(fp, _T("%08X")NL, (LONG_PTR)(Ebp->Ret_Addr)); } } //Get_Call_Stack
VOID CreateExceptionDesc(PEXCEPTION_POINTERS pException, FILE* fp, UINT dwLastError) { if (!pException || !fp) return; EXCEPTION_RECORD & E = *pException->ExceptionRecord; CONTEXT & C = *pException->ContextRecord; //取得异常发生地 TCHAR szModeleInfo[MAX_PATH]; TCHAR Module_Name[MAX_PATH]; PBYTE Module_Addr; if (Get_Module_By_Ret_Addr((PBYTE)E.ExceptionAddress, Module_Name, Module_Addr)) { _sntprintf(szModeleInfo, MAX_PATH, _T("%s"), Module_Name); } else { _sntprintf(szModeleInfo, MAX_PATH, _T("%08X"), (DWORD_PTR)(E.ExceptionAddress)); } switch(E.ExceptionCode) { //转化后的c++异常 case 0XE000C0DE: { _ftprintf(fp, _T("C++ Exception\n") _T("\n") _T("Expr: %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n"), E.ExceptionInformation[0], E.ExceptionInformation[1], E.ExceptionInformation[2], E.ExceptionInformation[3], E.ExceptionInformation[4], E.ExceptionInformation[5], E.ExceptionInformation[6], E.ExceptionInformation[7], E.ExceptionInformation[8], E.ExceptionInformation[9], E.ExceptionInformation[10], E.ExceptionInformation[11], E.ExceptionInformation[12], E.ExceptionInformation[13], E.ExceptionInformation[14]); } break; //试图对一个虚地址进行读写 case EXCEPTION_ACCESS_VIOLATION: { // Access violation type - Write/Read. _ftprintf(fp, _T("\t\tAccess violation\n") _T("\n") _T("@: %s\n") _T("Operate: %s\n") _T("Address: 0x%08X\n") _T("LastError: 0x%08X\n"), szModeleInfo, (E.ExceptionInformation[0]) ? _T("Write") : _T("Read"), E.ExceptionInformation[1], dwLastError); } break; default: { _ftprintf(fp, _T("\t\tOTHER\n") _T("\n") _T("@: %s\n") _T("Code: 0x%08X\n") _T("LastError: 0x%08X\n"), szModeleInfo, E.ExceptionCode, dwLastError); } break; } }
//************************************************************* LLSD WINAPI Get_Exception_Info(PEXCEPTION_POINTERS pException) //************************************************************* // Allocate Str[DUMP_SIZE_MAX] and return Str with dump, if !pException - just return call stack in Str. { LLSD info; LPWSTR Str; int Str_Len; // int i; LPWSTR Module_Name = new WCHAR[MAX_PATH]; PBYTE Module_Addr; HANDLE hFile; FILETIME Last_Write_Time; FILETIME Local_File_Time; SYSTEMTIME T; Str = new WCHAR[DUMP_SIZE_MAX]; Str_Len = 0; if (!Str) return NULL; Get_Version_Str(info); GetModuleFileName(NULL, Str, MAX_PATH); info["Process"] = ll_convert_wide_to_string(Str); info["ThreadID"] = (S32)GetCurrentThreadId(); // If exception occurred. if (pException) { EXCEPTION_RECORD & E = *pException->ExceptionRecord; CONTEXT & C = *pException->ContextRecord; // If module with E.ExceptionAddress found - save its path and date. if (Get_Module_By_Ret_Addr((PBYTE)E.ExceptionAddress, Module_Name, Module_Addr)) { info["Module"] = ll_convert_wide_to_string(Module_Name); if ((hFile = CreateFile(Module_Name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE) { if (GetFileTime(hFile, NULL, NULL, &Last_Write_Time)) { FileTimeToLocalFileTime(&Last_Write_Time, &Local_File_Time); FileTimeToSystemTime(&Local_File_Time, &T); info["DateModified"] = llformat("%02d/%02d/%d", T.wMonth, T.wDay, T.wYear); } CloseHandle(hFile); } } else { info["ExceptionAddr"] = (int)E.ExceptionAddress; } info["ExceptionCode"] = (int)E.ExceptionCode; /* //TODO: Fix this if (E.ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { // Access violation type - Write/Read. LLSD exception_info; exception_info["Type"] = E.ExceptionInformation[0] ? "Write" : "Read"; exception_info["Address"] = llformat("%08x", E.ExceptionInformation[1]); info["Exception Information"] = exception_info; } */ // Save instruction that caused exception. /* std::string str; for (i = 0; i < 16; i++) str += llformat(" %02X", PBYTE(E.ExceptionAddress)[i]); info["Instruction"] = str; */ LLSD registers; registers["EAX"] = (int)C.Eax; registers["EBX"] = (int)C.Ebx; registers["ECX"] = (int)C.Ecx; registers["EDX"] = (int)C.Edx; registers["ESI"] = (int)C.Esi; registers["EDI"] = (int)C.Edi; registers["ESP"] = (int)C.Esp; registers["EBP"] = (int)C.Ebp; registers["EIP"] = (int)C.Eip; registers["EFlags"] = (int)C.EFlags; info["Registers"] = registers; } //if (pException) // Save call stack info. Get_Call_Stack(pException->ExceptionRecord, pException->ContextRecord, info); return info; } //Get_Exception_Info
//****************************************************************** void WINAPI Get_Call_Stack(const EXCEPTION_RECORD* exception_record, const CONTEXT* context_record, LLSD& info) //****************************************************************** // Fill Str with call stack info. // pException can be either GetExceptionInformation() or NULL. // If pException = NULL - get current call stack. { LPWSTR Module_Name = new WCHAR[MAX_PATH]; PBYTE Module_Addr = 0; LLSD params; PBYTE Esp = NULL; LLSD tmp_info; bool fake_frame = false; bool ebp_used = false; const int HEURISTIC_MAX_WALK = 20; int heuristic_walk_i = 0; int Ret_Addr_I = 0; WSTACK Stack = {0, 0}; PSTACK Ebp; if (exception_record && context_record) //fake frame for exception address { Stack.Ebp = (PSTACK)(context_record->Ebp); Stack.Ret_Addr = (PBYTE)exception_record->ExceptionAddress; Ebp = &Stack; Esp = (PBYTE) context_record->Esp; fake_frame = true; } else if(context_record) { Ebp = (PSTACK)(context_record->Ebp); Esp = (PBYTE)(context_record->Esp); } else { Ebp = (PSTACK)&exception_record - 1; //frame addr of Get_Call_Stack() Esp = (PBYTE)&exception_record; // Skip frame of Get_Call_Stack(). if (!IsBadReadPtr(Ebp, sizeof(PSTACK))) Ebp = Ebp->Ebp; //caller ebp } // Trace CALL_TRACE_MAX calls maximum - not to exceed DUMP_SIZE_MAX. // Break trace on wrong stack frame. for (Ret_Addr_I = 0; heuristic_walk_i < HEURISTIC_MAX_WALK && Ret_Addr_I < CALL_TRACE_MAX && !IsBadReadPtr(Ebp, sizeof(PSTACK)) && !IsBadCodePtr(FARPROC(Ebp->Ret_Addr)); Ret_Addr_I++) { // If module with Ebp->Ret_Addr found. if (Get_Module_By_Ret_Addr(Ebp->Ret_Addr, Module_Name, Module_Addr)) { // Save module's address and full path. tmp_info["CallStack"][Ret_Addr_I]["ModuleName"] = ll_convert_wide_to_string(Module_Name); tmp_info["CallStack"][Ret_Addr_I]["ModuleAddress"] = (int)Module_Addr; tmp_info["CallStack"][Ret_Addr_I]["CallOffset"] = (int)(Ebp->Ret_Addr - Module_Addr); // Save 5 params of the call. We don't know the real number of params. if (fake_frame && !Ret_Addr_I) //fake frame for exception address params[0] = "Exception Offset"; else if (!IsBadReadPtr(Ebp, sizeof(PSTACK) + 5 * sizeof(DWORD))) { for(int j = 0; j < 5; ++j) { params[j] = (int)Ebp->Param[j]; } } tmp_info["CallStack"][Ret_Addr_I]["Parameters"] = params; } tmp_info["CallStack"][Ret_Addr_I]["ReturnAddress"] = (int)Ebp->Ret_Addr; // get ready for next frame // Set ESP to just after return address. Not the real esp, but just enough after the return address if(!fake_frame) { Esp = (PBYTE)Ebp + 8; } else { fake_frame = false; } // is next ebp valid? // only run if we've never found a good ebp // and make sure the one after is valid as well if( !ebp_used && shouldUseStackWalker(Ebp, 2)) { heuristic_walk_i++; PBYTE new_ebp = get_valid_frame(Esp); if (new_ebp != NULL) { Ebp = (PSTACK)new_ebp; } } else { ebp_used = true; Ebp = Ebp->Ebp; } } /* TODO remove or turn this code back on to edit the stack after i see a few raw ones. -Palmer // Now go back through and edit out heuristic stacks that could very well be bogus. // Leave the top and the last 3 stack chosen by the heuristic, however. if(heuristic_walk_i > 2) { info["CallStack"][0] = tmp_info["CallStack"][0]; std::string ttest = info["CallStack"][0]["ModuleName"]; for(int cur_frame = 1; (cur_frame + heuristic_walk_i - 2 < Ret_Addr_I); ++cur_frame) { // edit out the middle heuristic found frames info["CallStack"][cur_frame] = tmp_info["CallStack"][cur_frame + heuristic_walk_i - 2]; } } else { info = tmp_info; } */ info = tmp_info; info["HeuristicWalkI"] = heuristic_walk_i; info["EbpUsed"] = ebp_used; } //Get_Call_Stack