📄 crash_handler.c
字号:
// values.
//////////////////////////////////////////////////////////////////////////////
BOOL FormatSymbolValue(
PSYMBOL_INFO pSym,
STACKFRAME * sf,
char * pszBuffer,
unsigned cbBuffer )
{
char * pszCurrBuffer = pszBuffer;
DWORD_PTR pVariable = 0; // Will point to the variable's data in memory
BOOL bHandled;
BasicType basicType;
// Indicate if the variable is a local or parameter
if ( pSym->Flags & IMAGEHLP_SYMBOL_INFO_PARAMETER )
pszCurrBuffer += sprintf( pszCurrBuffer, "Parameter " );
else if ( pSym->Flags & IMAGEHLP_SYMBOL_INFO_LOCAL )
pszCurrBuffer += sprintf( pszCurrBuffer, "Local " );
// If it's a function, don't do anything.
if ( pSym->Tag == 5 ) // SymTagFunction from CVCONST.H from the DIA SDK
return 0;
// Emit the variable name
pszCurrBuffer += sprintf( pszCurrBuffer, "\'%s\'", pSym->Name );
if ( pSym->Flags & IMAGEHLP_SYMBOL_INFO_REGRELATIVE )
{
// if ( pSym->Register == 8 ) // EBP is the value 8 (in DBGHELP 5.1)
{ // This may change!!!
pVariable = sf->AddrFrame.Offset;
pVariable += (DWORD_PTR)pSym->Address;
}
// else
// return false;
}
else if ( pSym->Flags & IMAGEHLP_SYMBOL_INFO_REGISTER )
{
return 0; // Don't try to report register variable
}
else
{
pVariable = (DWORD_PTR)pSym->Address; // It must be a global variable
}
// Determine if the variable is a user defined type (UDT). IF so, bHandled
// will return true.
pszCurrBuffer = DumpTypeIndex(pszCurrBuffer,pSym->ModBase, pSym->TypeIndex,
0, pVariable, &bHandled );
if ( !bHandled )
{
// The symbol wasn't a UDT, so do basic, stupid formatting of the
// variable. Based on the size, we're assuming it's a char, WORD, or
// DWORD.
basicType = GetBasicType( pSym->TypeIndex, pSym->ModBase );
pszCurrBuffer = FormatOutputValue(pszCurrBuffer, basicType, pSym->Size,
(PVOID)pVariable );
}
return 1;
}
BOOL CALLBACK
EnumerateSymbolsCallback(
PSYMBOL_INFO pSymInfo,
ULONG SymbolSize,
PVOID UserContext )
{
char szBuffer[2048];
__try
{
if ( FormatSymbolValue( pSymInfo, (STACKFRAME*)UserContext,
szBuffer, sizeof(szBuffer) ) )
fprintf(fh, "\t%s\r\n", szBuffer );
}
__except( 1 )
{
fprintf(fh, "punting on symbol %s\r\n", pSymInfo->Name );
}
return TRUE;
}
void WriteStackDetails(PCONTEXT pContext, int writevars)
{
DWORD dwMachineType = 0;
STACKFRAME sf;
unsigned char symbolBuffer[ sizeof(SYMBOL_INFO) + 1024 ];
PSYMBOL_INFO pSymbol;
DWORD64 symDisplacement = 0;
char fModule[MAX_PATH];
DWORD section = 0, offset = 0;
IMAGEHLP_LINE lineInfo = { sizeof(IMAGEHLP_LINE) };
DWORD dwLineDisplacement;
IMAGEHLP_STACK_FRAME imagehlpStackFrame;
fprintf(fh, "\nCall stack:\n");
fprintf(fh, "Address Frame Function Source File\n");
fprintf(fh, "===============================================================\n");
memset(&sf, 0x00, sizeof(sf));
#ifdef _M_IX86
sf.AddrPC.Offset = pContext->Eip;
sf.AddrPC.Mode = AddrModeFlat;
sf.AddrStack.Offset = pContext->Esp;
sf.AddrStack.Mode = AddrModeFlat;
sf.AddrFrame.Offset = pContext->Ebp;
dwMachineType = IMAGE_FILE_MACHINE_I386;
#endif
while (1)
{
if (!StackWalk( dwMachineType, m_hProcess, GetCurrentThread(), &sf, pContext,
0, SymFunctionTableAccess, SymGetModuleBase, 0))
break;
if ( 0 == sf.AddrFrame.Offset)
break;
fprintf(fh, "%08X %08X ", sf.AddrPC.Offset, sf.AddrFrame.Offset);
pSymbol = (PSYMBOL_INFO)symbolBuffer;
pSymbol->SizeOfStruct = sizeof(symbolBuffer);
pSymbol->MaxNameLen = 1024;
symDisplacement = 0;
if (SymFromAddr(m_hProcess, sf.AddrPC.Offset, &symDisplacement, pSymbol))
{
fprintf(fh, "%hs+%I64X", pSymbol->Name, symDisplacement);
}
else
{
GetLogicalAddress( (PVOID)sf.AddrPC.Offset, fModule, sizeof(fModule), §ion, &offset);
fprintf(fh, "%04X:%08X %s", section, offset, fModule);
}
if (SymGetLineFromAddr( m_hProcess, sf.AddrPC.Offset, &dwLineDisplacement, &lineInfo))
{
fprintf(fh, " %s line %u", lineInfo.FileName, lineInfo.LineNumber);
}
fprintf(fh, "\n");
// Consider adding the stuff below at a later date, if it makes sense.
if (writevars == 1)
{
imagehlpStackFrame.InstructionOffset = sf.AddrPC.Offset;
SymSetContext( m_hProcess, &imagehlpStackFrame, 0 );
SymEnumSymbols( m_hProcess, 0, 0, EnumerateSymbolsCallback, &sf );
fprintf(fh, "\n");
}
}
}
/**
* \brief Dump extra details not included in the minidump to a dump log text
* file.
**/
void GenerateTextDump(PEXCEPTION_POINTERS pExceptionInfo)
{
EXCEPTION_RECORD *pExceptionRecord = NULL;
char *temp = NULL;
char faultingModule[MAX_PATH];
DWORD section, offset;
PCONTEXT pCtx = NULL;
CONTEXT trashableContext;
temp = (char *)malloc(strlen(dumploc)+10);
if (temp == NULL) return; // ACK! Can't do anything!
strcpy(temp, dumploc);
strcat(temp, ".log");
fh = fopen(temp, "w");
if (fh == NULL)
{
free(temp);
return; // Nothing we can do.
}
free(temp);
temp = NULL;
pExceptionRecord = pExceptionInfo->ExceptionRecord;
temp = GetExceptionString(pExceptionRecord->ExceptionCode);
fprintf(fh, "Exception code : %08X -- %s\n", pExceptionRecord->ExceptionCode,
temp);
free(temp);
temp = NULL;
GetLogicalAddress( pExceptionRecord->ExceptionAddress,
faultingModule, sizeof(faultingModule), §ion, &offset);
fprintf(fh, "Fault Address: %08X %02X:%08X %s\n", pExceptionRecord->ExceptionAddress,
section, offset, faultingModule);
pCtx = pExceptionInfo->ContextRecord;
#ifdef _M_IX86 // Only do this if we are running in an X86 machine.
fprintf(fh, "\nRegisters :\n");
fprintf(fh, "EAX:%08X\n", pCtx->Eax);
fprintf(fh, "EBX:%08X\n", pCtx->Ebx);
fprintf(fh, "ECX:%08X\n", pCtx->Ecx);
fprintf(fh, "EDX:%08X\n", pCtx->Edx);
fprintf(fh, "ESI:%08X\n", pCtx->Esi);
fprintf(fh, "EDI:%08X\n", pCtx->Edi);
fprintf(fh, "CS:EIP:%04X:%08X\n", pCtx->SegCs, pCtx->Eip);
fprintf(fh, "SS:ESP:%04X:%08X EBP:%08X\n", pCtx->SegSs, pCtx->Esp,
pCtx->Ebp);
fprintf(fh, "DS:%04X ES:%04X FS:%04X GS:%04X\n", pCtx->SegDs, pCtx->SegEs,
pCtx->SegFs, pCtx->SegGs);
fprintf(fh, "Flags:%08X\n", pCtx->EFlags);
#endif
SymSetOptions( SYMOPT_DEFERRED_LOADS );
if (!SymInitialize( GetCurrentProcess(), 0, TRUE ))
{
fclose(fh);
return;
}
trashableContext = *pCtx;
WriteStackDetails(&trashableContext, 0 );
#ifdef _M_IX86 // X86 Only!
fprintf(fh, "========================\r\n");
fprintf(fh, "Local Variables And Parameters\r\n");
trashableContext = *pCtx;
WriteStackDetails( &trashableContext, 1 );
#if 0
fprintf(fh, "========================\r\n");
fprintf(fh, "Global Variables\r\n");
SymEnumSymbols( GetCurrentProcess(),
(DWORD64)GetModuleHandle(faultingModule),
0, EnumerateSymbolsCallback, 0 );
#endif
#endif // X86 Only!
SymCleanup( GetCurrentProcess() );
fclose(fh);
}
/**
* \brief The callback that is processed when we experience a crash.
*
* @param[in] pExceptionInfo Information related to the crash, and used to generate the crash information.
*
* \retval LONG A value that tells the windows handler what to do next.
**/
LONG WINAPI crash_handler_callback(PEXCEPTION_POINTERS pExceptionInfo)
{
HANDLE hFile;
MINIDUMP_EXCEPTION_INFORMATION eInfo;
// Note: BUILDNUM is a quoted string.
hFile = CreateFileA( dumploc, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
m_hProcess = GetCurrentProcess();
eInfo.ThreadId = GetCurrentThreadId();
eInfo.ClientPointers = FALSE;
eInfo.ExceptionPointers = pExceptionInfo;
GenerateTextDump(pExceptionInfo);
MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &eInfo, NULL, NULL);
}
CloseHandle(hFile);
crashdump_gather_files();
if (previousFilter)
return previousFilter( pExceptionInfo );
else
return EXCEPTION_CONTINUE_SEARCH;
}
/**
* \brief Called at the point that we want to start the crash handler. (Which is probably the first thing
* we want to do.)
**/
void crash_handler_install(char *dumpname)
{
dumploc = strdup(dumpname);
previousFilter = SetUnhandledExceptionFilter(crash_handler_callback);
}
/**
* \brief Clean up any memory the crash handler was using so that we don't leave droppings.
**/
void crash_handler_cleanup()
{
free(dumploc);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -