📄 crash_handler.c
字号:
/**
* Trap crashes in Windows, and create a minidump that can be used to chase the issue down.
*
* Licensed under the dual GPL/BSD license. (See LICENSE file for more info.)
*
* \file crash_handler.c
*
* \author chris@open1x.org
*
* $Id: crash_handler.c,v 1.1.2.4 2008/01/21 22:51:43 chessing Exp $
* $Date: 2008/01/21 22:51:43 $
**/
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <dbghelp.h>
#include "crashdump.h"
#pragma comment(linker, "/defaultlib:dbghelp.lib")
LPTOP_LEVEL_EXCEPTION_FILTER previousFilter = NULL;
HANDLE m_hProcess;
FILE *fh = NULL;
char *dumploc = NULL;
typedef enum // Stolen from CVCONST.H in the DIA 2.0 SDK
{
btNoType = 0,
btVoid = 1,
btChar = 2,
btWChar = 3,
btInt = 6,
btUInt = 7,
btFloat = 8,
btBCD = 9,
btBool = 10,
btLong = 13,
btULong = 14,
btCurrency = 25,
btDate = 26,
btVariant = 27,
btComplex = 28,
btBit = 29,
btBSTR = 30,
btHresult = 31
} BasicType;
// A lot of the code below was taken from an MSDN Magazine article from
// March of 2002. (Fairly heavily modified) It can be found at :
// http://msdn.microsoft.com/msdnmag/issues/02/03/hood/default.aspx
//
char *GetExceptionString( DWORD code)
{
#define EXCEPTION(x) case EXCEPTION_##x: return _strdup(#x);
switch (code)
{
EXCEPTION( ACCESS_VIOLATION )
EXCEPTION( DATATYPE_MISALIGNMENT )
EXCEPTION( BREAKPOINT )
EXCEPTION( SINGLE_STEP )
EXCEPTION( ARRAY_BOUNDS_EXCEEDED )
EXCEPTION( FLT_DENORMAL_OPERAND )
EXCEPTION( FLT_DIVIDE_BY_ZERO )
EXCEPTION( FLT_INEXACT_RESULT )
EXCEPTION( FLT_INVALID_OPERATION )
EXCEPTION( FLT_OVERFLOW )
EXCEPTION( FLT_STACK_CHECK )
EXCEPTION( FLT_UNDERFLOW )
EXCEPTION( INT_DIVIDE_BY_ZERO )
EXCEPTION( INT_OVERFLOW )
EXCEPTION( PRIV_INSTRUCTION )
EXCEPTION( IN_PAGE_ERROR )
EXCEPTION( ILLEGAL_INSTRUCTION )
EXCEPTION( NONCONTINUABLE_EXCEPTION )
EXCEPTION( STACK_OVERFLOW )
EXCEPTION( INVALID_DISPOSITION )
EXCEPTION( GUARD_PAGE )
EXCEPTION( INVALID_HANDLE )
default:
return strdup("Unknown");
}
}
/**
* \brief Determine the address of the modules that we crashed in.
**/
void GetLogicalAddress(void *addr, char *fModule, DWORD buflen, DWORD *section,
DWORD *offset)
{
MEMORY_BASIC_INFORMATION mbi;
DWORD hMod;
PIMAGE_DOS_HEADER pDosHdr;
PIMAGE_NT_HEADERS pNtHdr;
PIMAGE_SECTION_HEADER pSection;
DWORD rva;
unsigned i;
DWORD sectionStart;
DWORD sectionEnd;
(*section) = 0;
(*offset) = 0;
if (!VirtualQuery( addr, &mbi, sizeof(mbi))) return;
hMod = (DWORD)mbi.AllocationBase;
if (!GetModuleFileName((HMODULE)hMod, fModule, buflen)) return;
pDosHdr = (PIMAGE_DOS_HEADER)hMod;
pNtHdr = (PIMAGE_NT_HEADERS)(hMod + pDosHdr->e_lfanew);
pSection = IMAGE_FIRST_SECTION(pNtHdr);
rva = (DWORD)addr - hMod;
// Locate the section that holds our address.
for (i = 0; i < pNtHdr->FileHeader.NumberOfSections; i++, pSection++)
{
sectionStart = pSection->VirtualAddress;
sectionEnd = sectionStart + max(pSection->SizeOfRawData, pSection->Misc.VirtualSize);
if ((rva >= sectionStart) && (rva <= sectionEnd))
{
// Found it.
(*section) = i+1;
(*offset) = rva - sectionStart;
return;
}
}
}
/* struct FINDCHILDREN : TI_FINDCHILDREN_PARAMS
{
ULONG MoreChildIds[1024];
FINDCHILDREN(){Count = sizeof(MoreChildIds) / sizeof(MoreChildIds[0]);}
} children;
*/
char *FormatOutputValue( char * pszCurrBuffer,
BasicType basicType,
DWORD64 length,
PVOID pAddress )
{
// Format appropriately (assuming it's a 1, 2, or 4 bytes (!!!)
if ( length == 1 )
pszCurrBuffer += sprintf( pszCurrBuffer, " = %X", *(PBYTE)pAddress );
else if ( length == 2 )
pszCurrBuffer += sprintf( pszCurrBuffer, " = %X", *(PWORD)pAddress );
else if ( length == 4 )
{
if ( basicType == btFloat )
{
pszCurrBuffer += sprintf(pszCurrBuffer," = %f", *(PFLOAT)pAddress);
}
else if ( basicType == btChar )
{
if ( !IsBadStringPtr( *(PSTR*)pAddress, 32) )
{
pszCurrBuffer += sprintf( pszCurrBuffer, " = \"%.31s\"",
*(PDWORD)pAddress );
}
else
pszCurrBuffer += sprintf( pszCurrBuffer, " = %X",
*(PDWORD)pAddress );
}
else
pszCurrBuffer += sprintf(pszCurrBuffer," = %X", *(PDWORD)pAddress);
}
else if ( length == 8 )
{
if ( basicType == btFloat )
{
pszCurrBuffer += sprintf( pszCurrBuffer, " = %lf",
*(double *)pAddress );
}
else
pszCurrBuffer += sprintf( pszCurrBuffer, " = %I64X",
*(DWORD64*)pAddress );
}
return pszCurrBuffer;
}
BasicType GetBasicType( DWORD typeIndex, DWORD64 modBase )
{
BasicType basicType;
DWORD typeId;
if ( SymGetTypeInfo( 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.
if (SymGetTypeInfo(m_hProcess,modBase, typeIndex, TI_GET_TYPEID, &typeId))
{
if ( SymGetTypeInfo( m_hProcess, modBase, typeId, TI_GET_BASETYPE,
&basicType ) )
{
return basicType;
}
}
return btNoType;
}
//////////////////////////////////////////////////////////////////////////////
// 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.
//////////////////////////////////////////////////////////////////////////////
char * DumpTypeIndex(
char * pszCurrBuffer,
DWORD64 modBase,
DWORD dwTypeIndex,
unsigned nestingLevel,
DWORD_PTR offset,
BOOL *bHandled )
{
WCHAR * pwszTypeName;
DWORD dwChildrenCount = 0;
TI_FINDCHILDREN_PARAMS children;
unsigned i, j;
BOOL bHandled2;
DWORD typeId;
ULONG64 length;
DWORD_PTR dwFinalOffset;
BasicType basicType;
bHandled = 0;
// Get the name of the symbol. This will either be a Type name (if a UDT),
// or the structure member name.
if ( SymGetTypeInfo( m_hProcess, modBase, dwTypeIndex, TI_GET_SYMNAME,
&pwszTypeName ) )
{
pszCurrBuffer += sprintf( pszCurrBuffer, " %ls", pwszTypeName );
LocalFree( pwszTypeName );
}
// Determine how many children this type has.
SymGetTypeInfo( 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.
children.Count = dwChildrenCount;
children.Start= 0;
// Get the array of TypeIds, one for each child type
if ( !SymGetTypeInfo( m_hProcess, modBase, dwTypeIndex, TI_FINDCHILDREN,
&children ) )
{
return pszCurrBuffer;
}
// Append a line feed
pszCurrBuffer += sprintf( pszCurrBuffer, "\r\n" );
// Iterate through each of the children
for ( i = 0; i < dwChildrenCount; i++ )
{
// Add appropriate indentation level (since this routine is recursive)
for ( j = 0; j <= nestingLevel+1; j++ )
pszCurrBuffer += sprintf( pszCurrBuffer, "\t" );
// Recurse for each of the child types
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;
SymGetTypeInfo( 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.
SymGetTypeInfo( m_hProcess, modBase, children.ChildId[i],
TI_GET_TYPEID, &typeId );
// Get the size of the child member
SymGetTypeInfo(m_hProcess, modBase, typeId, TI_GET_LENGTH,&length);
// Calculate the address of the member
dwFinalOffset = offset + dwMemberOffset;
basicType = GetBasicType(children.ChildId[i], modBase );
pszCurrBuffer = FormatOutputValue( pszCurrBuffer, basicType,
length, (PVOID)dwFinalOffset );
pszCurrBuffer += sprintf( pszCurrBuffer, "\r\n" );
}
}
(*bHandled) = 1;
return pszCurrBuffer;
}
//////////////////////////////////////////////////////////////////////////////
// Given a SYMBOL_INFO representing a particular variable, displays its
// contents. If it's a user defined type, display the members and their
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -