📄 crash.cpp
字号:
static bool PointerIsInAnySegment( const VDDebugInfoContext *pctx, unsigned rva )
{
for( int i=0; i<pctx->nSegments; ++i )
{
if (rva >= pctx->pSegments[i][0] && rva < pctx->pSegments[i][0] + pctx->pSegments[i][1])
return true;
}
return false;
}
long VDDebugInfoLookupRVA(VDDebugInfoContext *pctx, unsigned rva, char *buf, int buflen)
{
if ( !PointerIsInAnySegment(pctx, rva) )
return -1;
const unsigned char *pr = pctx->pRVAHeap;
const unsigned char *pr_limit = (const unsigned char *)pctx->pFuncNameHeap;
int idx = 0;
// Linearly unpack RVA deltas and find lower_bound
rva -= pctx->nFirstRVA;
if ((signed)rva < 0)
return -1;
while(pr < pr_limit) {
unsigned char c;
unsigned diff = 0;
do {
c = *pr++;
diff = (diff << 7) | (c & 0x7f);
} while(c & 0x80);
rva -= diff;
if ((signed)rva < 0) {
rva += diff;
break;
}
++idx;
}
if (pr >= pr_limit)
return -1;
// Decompress name for RVA
const char *fn_name = GetNameFromHeap(pctx->pFuncNameHeap, idx);
if (!*fn_name)
fn_name = "(special)";
strncpy( buf, fn_name, buflen );
buf[buflen-1]=0;
return rva;
}
///////////////////////////////////////////////////////////////////////////
#include "ddk/dbghelp.h"
#pragma comment(lib, "crash/windows/ddk/dbghelp.lib")
static bool InitDbghelp()
{
static bool initted = false;
if( !initted )
{
SymSetOptions( SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS );
if (!SymInitialize(GetCurrentProcess(), NULL, TRUE))
return false;
initted = true;
}
return true;
}
static SYMBOL_INFO *GetSym( unsigned long ptr, DWORD64 &disp )
{
InitDbghelp();
static BYTE buffer[1024];
SYMBOL_INFO *pSymbol = (PSYMBOL_INFO)buffer;
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
pSymbol->MaxNameLen = sizeof(buffer) - sizeof(SYMBOL_INFO) + 1;
if (!SymFromAddr(GetCurrentProcess(), ptr, &disp, pSymbol))
return NULL;
return pSymbol;
}
static const char *Demangle( const char *buf )
{
if( !InitDbghelp() )
return buf;
static char obuf[1024];
if( !UnDecorateSymbolName(buf, obuf, sizeof(obuf),
UNDNAME_COMPLETE
| UNDNAME_NO_CV_THISTYPE
| UNDNAME_NO_ALLOCATION_MODEL
| UNDNAME_NO_ACCESS_SPECIFIERS // no public:
| UNDNAME_NO_MS_KEYWORDS // no __cdecl
) )
{
return buf;
}
if( obuf[0] == '_' )
{
strcat( obuf, "()" ); /* _main -> _main() */
return obuf+1; /* _main -> main */
}
return obuf;
}
static bool PointsToValidCall( unsigned long ptr )
{
char buf[7];
int len = 7;
memset( buf, 0, sizeof(buf) );
while(len > 0 && !ReadProcessMemory(GetCurrentProcess(), (void *)(ptr-len), buf+7-len, len, NULL))
--len;
return IsValidCall(buf+7, len);
}
void do_backtrace( const void **buf, size_t size,
HANDLE hProcess, HANDLE hThread, const CONTEXT *pContext )
{
// Retrieve stack pointers.
const char *pStackBase;
{
LDT_ENTRY sel;
if( !GetThreadSelectorEntry( hThread, pContext->SegFs, &sel ) )
{
buf[0] = NULL;
return;
}
const NT_TIB *tib = (NT_TIB *) ((sel.HighWord.Bits.BaseHi<<24)+(sel.HighWord.Bits.BaseMid<<16)+sel.BaseLow);
const NT_TIB *pTib = tib->Self;
pStackBase = (char *)pTib->StackBase;
}
// Walk up the stack.
const char *lpAddr = (const char *)pContext->Esp;
const void *data = (void *) pContext->Eip;
size_t i = 0;
do {
if( i+1 >= size )
break;
bool fValid = true;
/* The first entry is EIP, which is always interesting, even if it's not valid. */
if( i != 0 )
{
MEMORY_BASIC_INFORMATION meminfo;
VirtualQuery((void *)data, &meminfo, sizeof meminfo);
if (!IsExecutableProtection(meminfo.Protect) || meminfo.State!=MEM_COMMIT)
fValid = false;
if ( data != (void *) pContext->Eip && !PointsToValidCall((unsigned long)data) )
fValid = false;
}
if( fValid )
buf[i++] = data;
if (lpAddr >= pStackBase)
break;
lpAddr += 4;
} while( ReadProcessMemory(hProcess, lpAddr-4, &data, 4, NULL));
buf[i++] = NULL;
}
void SymLookup( const void *ptr, char *buf )
{
VDDebugInfoInitFromFile( &g_debugInfo );
if( !g_debugInfo.Loaded() )
{
strcpy( buf, "error" );
return;
}
MEMORY_BASIC_INFORMATION meminfo;
VirtualQuery( ptr, &meminfo, sizeof meminfo );
char tmp[512];
if( VDDebugInfoLookupRVA(&g_debugInfo, (unsigned int)ptr, tmp, sizeof(tmp)) >= 0 )
{
wsprintf( buf, "%08x: %s", ptr, Demangle(tmp) );
return;
}
char szName[MAX_PATH];
if( !CrashGetModuleBaseName((HMODULE)meminfo.AllocationBase, szName) )
strcpy( szName, "???" );
DWORD64 disp;
SYMBOL_INFO *pSymbol = GetSym( (unsigned int)ptr, disp );
if( pSymbol )
{
wsprintf( buf, "%08lx: %s!%s [%08lx+%lx+%lx]",
(unsigned long) ptr, szName, pSymbol->Name,
(unsigned long) meminfo.AllocationBase,
(unsigned long) (pSymbol->Address) - (unsigned long) (meminfo.AllocationBase),
(unsigned long) disp);
return;
}
wsprintf( buf, "%08lx: %s!%08lx",
(unsigned long) ptr, szName,
(unsigned long) meminfo.AllocationBase );
}
static bool ReportCallStack( HWND hwnd, HANDLE hFile, const void **Backtrace )
{
VDDebugInfoInitFromFile( &g_debugInfo );
if( !g_debugInfo.Loaded() )
{
Report( hwnd, hFile, "Could not open debug resource file (%s).", g_debugInfo.sFilename );
return false;
}
for( int i = 0; Backtrace[i]; ++i )
{
char buf[10240];
SymLookup( Backtrace[i], buf );
Report( hwnd, hFile, "%s", buf );
}
return true;
}
void WriteBuf( HANDLE hFile, const char *buf )
{
DWORD dwActual;
WriteFile(hFile, buf, strlen(buf), &dwActual, NULL);
}
static void DoSave()
{
char szModName2[MAX_PATH];
SpliceProgramPath(szModName2, sizeof szModName2, "../crashinfo.txt");
HANDLE hFile = CreateFile(szModName2, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE == hFile)
return;
Report(NULL, hFile,
"%s crash report (build %d)\r\n"
"--------------------------------------"
"\r\n", PRODUCT_NAME_VER, version_num);
ReportReason( NULL, hFile, &g_CrashInfo );
Report(NULL, hFile, "");
// Dump thread stacks
static char buf[1024*32];
// Checkpoints::GetLogs( buf, sizeof(buf), "\r\n" );
// WriteBuf( hFile, buf );
// Report(NULL, hFile, "");
ReportCallStack( NULL, hFile, g_CrashInfo.m_BacktracePointers );
Report(NULL, hFile, "");
if( g_CrashInfo.m_AlternateThreadBacktrace[0] )
{
for( int i = 0; i < CrashInfo::MAX_BACKTRACE_THREADS; ++i )
{
if( !g_CrashInfo.m_AlternateThreadBacktrace[i][0] )
continue;
Report( NULL, hFile, "Thread %s:", g_CrashInfo.m_AlternateThreadName[i] );
Report( NULL, hFile, "" );
ReportCallStack( NULL, hFile, g_CrashInfo.m_AlternateThreadBacktrace[i] );
Report(NULL, hFile, "");
}
}
//+++Write your static/partial logs here
Report(NULL, hFile, "-- End of report");
CloseHandle(hFile);
}
void ViewWithNotepad(const char *str)
{
char buf[256] = "";
strcat(buf, "notepad.exe ");
strcat(buf, str);
char cwd[MAX_PATH];
SpliceProgramPath(cwd, MAX_PATH, "");
PROCESS_INFORMATION pi;
STARTUPINFO si;
ZeroMemory( &si, sizeof(si) );
CreateProcess(
NULL, // pointer to name of executable module
buf, // pointer to command line string
NULL, // process security attributes
NULL, // thread security attributes
false, // handle inheritance flag
0, // creation flags
NULL, // pointer to new environment block
cwd, // pointer to current directory name
&si, // pointer to STARTUPINFO
&pi // pointer to PROCESS_INFORMATION
);
}
BOOL APIENTRY CrashDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
static bool s_bHaveCallstack;
switch(msg)
{
case WM_INITDIALOG:
{
HWND hwndList = GetDlgItem(hDlg, IDC_CALL_STACK);
HWND hwndReason = GetDlgItem(hDlg, IDC_STATIC_BOMBREASON);
ReportReason( hwndReason, NULL, &g_CrashInfo );
s_bHaveCallstack = ReportCallStack( hwndList, NULL, g_CrashInfo.m_BacktracePointers );
}
return TRUE;
case WM_COMMAND:
switch(LOWORD(wParam)) {
case IDC_BUTTON_CLOSE:
EndDialog(hDlg, FALSE);
return TRUE;
case IDOK:
// EndDialog(hDlg, TRUE); /* don't always exit on ENTER */
return TRUE;
case IDC_VIEW_LOG:
ViewWithNotepad("../log.txt");
break;
case IDC_CRASH_SAVE:
if (!s_bHaveCallstack)
if (IDOK != MessageBox(hDlg,
PRODUCT_NAME " cannot load its crash resource file, and thus the crash dump will be "
"missing the most important part, the call stack. Crash dumps are much less useful "
"without the call stack.",
PRODUCT_NAME " warning", MB_OK|MB_ICONEXCLAMATION))
return TRUE;
ViewWithNotepad("../crashinfo.txt");
return TRUE;
}
break;
}
return FALSE;
}
void NORETURN debug_crash()
{
#if defined( _MSC_VER )
__try {
__asm xor ebx,ebx
__asm mov eax,dword ptr [ebx]
// __asm mov dword ptr [ebx],eax
// __asm lock add dword ptr cs:[00000000h], 12345678h
} __except(CrashHandler((EXCEPTION_POINTERS*)_exception_info())) {
}
#endif
//If we get here, we arent on MSVC so oh well
exit(0);
}
/* Get a stack trace of the current thread and the specified thread. If
* iID == GetInvalidThreadId(), then output a stack trace for every thread. */
void ForceCrashHandlerDeadlock( MString reason, uint64_t iID )
{
strncpy( g_CrashInfo.m_CrashReason, reason, sizeof(g_CrashInfo.m_CrashReason) );
g_CrashInfo.m_CrashReason[ sizeof(g_CrashInfo.m_CrashReason)-1 ] = 0;
{
//Set your threads here
const HANDLE hThread = GetCurrentThread();//Win32ThreadIdToHandle( iID );
CONTEXT context;
context.ContextFlags = CONTEXT_FULL;
if( !GetThreadContext( hThread, &context ) )
strcat( g_CrashInfo.m_CrashReason, "(GetThreadContext failed)" );
else
{
static const void *BacktracePointers[BACKTRACE_MAX_SIZE];
do_backtrace( g_CrashInfo.m_AlternateThreadBacktrace[0], BACKTRACE_MAX_SIZE, GetCurrentProcess(), hThread, &context );
//const char *pName = RageThread::GetThreadNameByID( iID );
//+++Name your thread here
const char *pName = "Current thread.";
strncpy( g_CrashInfo.m_AlternateThreadName[0], pName? pName:"???", sizeof(g_CrashInfo.m_AlternateThreadName[0])-1 );
}
}
debug_crash();
}
void ForceCrashHandler( const char *reason )
{
strncpy( g_CrashInfo.m_CrashReason, reason, sizeof(g_CrashInfo.m_CrashReason) );
g_CrashInfo.m_CrashReason[ sizeof(g_CrashInfo.m_CrashReason)-1 ] = 0;
debug_crash();
}
/*
* (c) 1998-2001 Avery Lee
* (c) 2003-2004 Glenn Maynard
* (c) 2004 Charles Lohr (strictly code removal)
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -