wheatyexceptionreport.cpp
来自「一个FTP下载的源代码。代码质量非常高」· C++ 代码 · 共 1,021 行 · 第 1/3 页
CPP
1,021 行
//////////////////////////////////////////////////////////////////////////////
// The function invoked by SymEnumSymbols
//////////////////////////////////////////////////////////////////////////////
BOOL CALLBACK
WheatyExceptionReport::EnumerateSymbolsCallback(
PSYMBOL_INFO pSymInfo,
ULONG SymbolSize,
PVOID UserContext )
{
USES_CONVERSION;
TCHAR szBuffer[4096];
__try
{
if ( FormatSymbolValue( pSymInfo, (STACKFRAME*)UserContext,
szBuffer, sizeof(szBuffer) ) )
_tprintf( _T("\t%s\r\n"), szBuffer );
}
__except( 1 )
{
_tprintf( _T("punting on symbol %s\r\n"), A2T(pSymInfo->Name) );
}
return TRUE;
}
//////////////////////////////////////////////////////////////////////////////
// Given a SYMBOL_INFO representing a particular variable, displays its
// contents. If it's a user defined type, display the members and their
// values.
//////////////////////////////////////////////////////////////////////////////
bool WheatyExceptionReport::FormatSymbolValue(
PSYMBOL_INFO pSym,
STACKFRAME * sf,
TCHAR * pszBuffer,
unsigned cbBuffer )
{
USES_CONVERSION;
TCHAR * pszCurrBuffer = pszBuffer;
// Indicate if the variable is a local or parameter
if ( pSym->Flags & IMAGEHLP_SYMBOL_INFO_PARAMETER )
pszCurrBuffer += _stprintf( pszCurrBuffer, _T("Parameter ") );
else if ( pSym->Flags & IMAGEHLP_SYMBOL_INFO_LOCAL )
pszCurrBuffer += _stprintf( pszCurrBuffer, _T("Local ") );
// If it's a function, don't do anything.
if ( pSym->Tag == 5 ) // SymTagFunction from CVCONST.H from the DIA SDK
return false;
// Emit the variable name
pszCurrBuffer += _stprintf( pszCurrBuffer, _T("\'%s\'"), A2T(pSym->Name) );
DWORD_PTR pVariable = 0; // Will point to the variable's data in memory
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 false; // 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.
bool bHandled;
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 basicType = GetBasicType( pSym->TypeIndex, pSym->ModBase );
pszCurrBuffer = FormatOutputValue(pszCurrBuffer, basicType, pSym->Size,
(PVOID)pVariable );
}
return true;
}
//////////////////////////////////////////////////////////////////////////////
// If it's a user defined type (UDT), recurse through its members until we're
// at fundamental types. When he hit fundamental types, return
// bHandled = false, so that FormatSymbolValue() will format them.
//////////////////////////////////////////////////////////////////////////////
TCHAR * WheatyExceptionReport::DumpTypeIndex(
TCHAR * pszCurrBuffer,
DWORD64 modBase,
DWORD dwTypeIndex,
unsigned nestingLevel,
DWORD_PTR offset,
bool & bHandled )
{
USES_CONVERSION;
bHandled = false;
// Get the name of the symbol. This will either be a Type name (if a UDT),
// or the structure member name.
WCHAR * pwszTypeName;
if ( pSymGetTypeInfo( m_hProcess, modBase, dwTypeIndex, TI_GET_SYMNAME,
&pwszTypeName ) )
{
pszCurrBuffer += _stprintf( pszCurrBuffer, _T(" %ls"), W2T(pwszTypeName) );
LocalFree( pwszTypeName );
}
// Determine how many children this type has.
DWORD dwChildrenCount = 0;
pSymGetTypeInfo( m_hProcess, modBase, dwTypeIndex, TI_GET_CHILDRENCOUNT,
&dwChildrenCount );
if ( !dwChildrenCount ) // If no children, we're done
{
return pszCurrBuffer;
}
// Prepare to get an array of "TypeIds", representing each of the children.
// SymGetTypeInfo(TI_FINDCHILDREN) expects more memory than just a
// TI_FINDCHILDREN_PARAMS struct has. Use derivation to accomplish this.
struct FINDCHILDREN : TI_FINDCHILDREN_PARAMS
{
ULONG MoreChildIds[1024];
FINDCHILDREN(){Count = sizeof(MoreChildIds) / sizeof(MoreChildIds[0]);}
} children;
children.Count = dwChildrenCount;
children.Start= 0;
// Get the array of TypeIds, one for each child type
if ( !pSymGetTypeInfo( m_hProcess, modBase, dwTypeIndex, TI_FINDCHILDREN,
&children ) )
{
return pszCurrBuffer;
}
// Append a line feed
pszCurrBuffer += _stprintf( pszCurrBuffer, _T("\r\n") );
// Iterate through each of the children
for ( unsigned i = 0; i < dwChildrenCount; i++ )
{
// Add appropriate indentation level (since this routine is recursive)
for ( unsigned j = 0; j <= nestingLevel+1; j++ )
pszCurrBuffer += _stprintf( pszCurrBuffer, _T("\t") );
// Recurse for each of the child types
bool bHandled2;
pszCurrBuffer = DumpTypeIndex( pszCurrBuffer, modBase,
children.ChildId[i], nestingLevel+1,
offset, bHandled2 );
// If the child wasn't a UDT, format it appropriately
if ( !bHandled2 )
{
// Get the offset of the child member, relative to its parent
DWORD dwMemberOffset;
pSymGetTypeInfo( m_hProcess, modBase, children.ChildId[i],
TI_GET_OFFSET, &dwMemberOffset );
// Get the real "TypeId" of the child. We need this for the
// SymGetTypeInfo( TI_GET_TYPEID ) call below.
DWORD typeId;
pSymGetTypeInfo( m_hProcess, modBase, children.ChildId[i],
TI_GET_TYPEID, &typeId );
// Get the size of the child member
ULONG64 length;
pSymGetTypeInfo(m_hProcess, modBase, typeId, TI_GET_LENGTH,&length);
// Calculate the address of the member
DWORD_PTR dwFinalOffset = offset + dwMemberOffset;
BasicType basicType = GetBasicType(children.ChildId[i], modBase );
pszCurrBuffer = FormatOutputValue( pszCurrBuffer, basicType,
length, (PVOID)dwFinalOffset );
pszCurrBuffer += _stprintf( pszCurrBuffer, _T("\r\n") );
}
}
bHandled = true;
return pszCurrBuffer;
}
TCHAR * WheatyExceptionReport::FormatOutputValue( TCHAR * pszCurrBuffer,
BasicType basicType,
DWORD64 length,
PVOID pAddress )
{
// Format appropriately (assuming it's a 1, 2, or 4 bytes (!!!)
if ( length == 1 )
pszCurrBuffer += _stprintf( pszCurrBuffer, _T(" = %X"), *(PBYTE)pAddress );
else if ( length == 2 )
pszCurrBuffer += _stprintf( pszCurrBuffer, _T(" = %X"), *(PWORD)pAddress );
else if ( length == 4 )
{
if ( basicType == btFloat )
{
pszCurrBuffer += _stprintf(pszCurrBuffer, _T(" = %f"), *(PFLOAT)pAddress);
}
else if ( basicType == btChar )
{
if ( !IsBadStringPtr( *(LPTSTR*)pAddress, 32) )
{
pszCurrBuffer += _stprintf( pszCurrBuffer, _T(" = \"%.31s\""),
*(PDWORD)pAddress );
}
else
pszCurrBuffer += _stprintf( pszCurrBuffer, _T(" = %X"),
*(PDWORD)pAddress );
}
else
{
pszCurrBuffer += _stprintf(pszCurrBuffer, _T(" = %X"), *(PDWORD)pAddress);
}
}
else if ( length == 8 )
{
if ( basicType == btFloat )
{
pszCurrBuffer += _stprintf( pszCurrBuffer, _T(" = %lf"),
*(double *)pAddress );
}
else
pszCurrBuffer += _stprintf( pszCurrBuffer, _T(" = %I64X"),
*(DWORD64*)pAddress );
}
return pszCurrBuffer;
}
BasicType
WheatyExceptionReport::GetBasicType( DWORD typeIndex, DWORD64 modBase )
{
BasicType basicType;
if ( pSymGetTypeInfo( m_hProcess, modBase, typeIndex,
TI_GET_BASETYPE, &basicType ) )
{
return basicType;
}
// Get the real "TypeId" of the child. We need this for the
// SymGetTypeInfo( TI_GET_TYPEID ) call below.
DWORD typeId;
if (pSymGetTypeInfo(m_hProcess,modBase, typeIndex, TI_GET_TYPEID, &typeId))
{
if ( pSymGetTypeInfo( m_hProcess, modBase, typeId, TI_GET_BASETYPE,
&basicType ) )
{
return basicType;
}
}
return btNoType;
}
//============================================================================
// Helper function that writes to the report file, and allows the user to use
// printf style formating
//============================================================================
int __cdecl WheatyExceptionReport::_tprintf(const TCHAR * format, ...)
{
TCHAR szBuff[1024];
int retValue;
DWORD cbWritten;
va_list argptr;
va_start( argptr, format );
retValue = _vstprintf( szBuff, format, argptr );
va_end( argptr );
WriteFile(m_hReportFile, szBuff, retValue * sizeof(TCHAR), &cbWritten, 0 );
return retValue;
}
bool WheatyExceptionReport::writeMiniDump(PEXCEPTION_POINTERS pExceptionInfo)
{
//
// Write the minidump to the file
//
MINIDUMP_EXCEPTION_INFORMATION eInfo;
eInfo.ThreadId = GetCurrentThreadId();
eInfo.ExceptionPointers = pExceptionInfo;
eInfo.ClientPointers = FALSE;
MINIDUMP_CALLBACK_INFORMATION cbMiniDump;
cbMiniDump.CallbackRoutine = 0;
cbMiniDump.CallbackParam = 0;
pMiniDumpWriteDump(
GetCurrentProcess(),
GetCurrentProcessId(),
m_hDumpFile,
MiniDumpNormal,
pExceptionInfo ? &eInfo : NULL,
NULL,
&cbMiniDump);
// Close file
CloseHandle(m_hDumpFile);
return true;
}
int WheatyExceptionReport::sendMail()
{
CMailMsg mail;
mail.SetTo(_T("tim.kosse@gmx.de"), _T("Tim Kosse"));
TCHAR str[4096];
_stprintf(str, _T("Exception report created by %s\r\n\r\n"), (LPCTSTR)GetVersionString());
mail.SetSubject(str);
mail.SetMessage(_T("Enter your comments here, what did you do with FileZilla before it crashed?"));
mail.AddAttachment(m_szLogFileName, _T("FileZilla.rpt"));
mail.AddAttachment(m_szDmpFileName, _T("FileZilla.dmp"));
return mail.Send();
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?