irecore2/rde/CrashHandler.cpp at dbb15499e415f20b2192a351582ad663f7d9a2a1 · AeanSR/irecore2 · GitHub
#include <iostream>
#ifdef WIN32
#include <windows.h>
#include <dbghelp.h>
#include <vector>
#pragma comment(lib, "dbghelp.lib")
bool InitSymbols()
{
static bool ls_initialized(false);
if (!ls_initialized)
{
DWORD options = SYMOPT_FAIL_CRITICAL_ERRORS |
SYMOPT_DEFERRED_LOADS |
SYMOPT_LOAD_LINES |
SYMOPT_UNDNAME;
SymSetOptions(options);
const char* dir = NULL;
if (!SymInitialize(GetCurrentProcess(), dir, options & SYMOPT_DEFERRED_LOADS))
{
OutputDebugString("Cannot initialize symbol engine");
return false;
}
ls_initialized = true;
}
return true;
}
void GetFileFromPath(const char* path, char* file, int fileNameSize)
{
char ext[_MAX_EXT] = { 0 };
_splitpath_s(path, 0, 0, 0, 0, file, fileNameSize, ext, _MAX_EXT);
strncat_s(file, fileNameSize, ext, _MAX_EXT);
}
int GetSymbolInfo(UINT64 address, char* symbol, int maxSymbolLen)
{
if (!InitSymbols())
return 0;
// Start with address.
int charsAdded =
_snprintf_s(symbol, maxSymbolLen, _TRUNCATE, "%p ", address);
symbol += charsAdded;
maxSymbolLen -= charsAdded;
if (maxSymbolLen < 0)
return charsAdded;
const DWORD64 address64 = (DWORD64)address;
// Module name
IMAGEHLP_MODULE64 moduleInfo;
ZeroMemory(&moduleInfo, sizeof(moduleInfo));
moduleInfo.SizeOfStruct = sizeof(moduleInfo);
const HANDLE hCurrentProcess = GetCurrentProcess();
if (SymGetModuleInfo64(hCurrentProcess, address64, &moduleInfo))
{
char moduleName[_MAX_PATH + 1];
GetFileFromPath(moduleInfo.ImageName, moduleName, _MAX_PATH);
const int moduleLen = (int)strlen(moduleName);
strncpy_s(symbol, maxSymbolLen, moduleName, _TRUNCATE);
symbol += moduleLen;
charsAdded += moduleLen;
maxSymbolLen -= moduleLen;
}
if (maxSymbolLen <= 0)
return charsAdded;
// Symbol name
ULONG64 symbolBuffer[(sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR) +
sizeof(ULONG64) - 1) / sizeof(ULONG64)] = { 0 };
IMAGEHLP_SYMBOL64* symbolInfo = reinterpret_cast<IMAGEHLP_SYMBOL64*>(symbolBuffer);
symbolInfo->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
symbolInfo->MaxNameLength = MAX_SYM_NAME;
DWORD64 disp(0);
if (SymGetSymFromAddr64(hCurrentProcess, address64, &disp, symbolInfo))
{
const int symbolChars =
_snprintf_s(symbol, maxSymbolLen, _TRUNCATE, " %s + 0x%X", symbolInfo->Name, disp);
symbol += symbolChars;
maxSymbolLen -= symbolChars;
charsAdded += symbolChars;
}
if (maxSymbolLen <= 0)
return charsAdded;
// File + line
DWORD displacementLine;
IMAGEHLP_LINE64 lineInfo;
ZeroMemory(&lineInfo, sizeof(lineInfo));
lineInfo.SizeOfStruct = sizeof(lineInfo);
if (SymGetLineFromAddr64(hCurrentProcess, address64, &displacementLine, &lineInfo))
{
char fileName[_MAX_PATH + 1];
GetFileFromPath(lineInfo.FileName, fileName, _MAX_PATH);
int fileLineChars(0);
if (displacementLine > 0)
{
fileLineChars = _snprintf_s(symbol, maxSymbolLen, _TRUNCATE,
" %s(%d+%04d byte(s))", fileName, lineInfo.LineNumber, displacementLine);
}
else
{
fileLineChars = _snprintf_s(symbol, maxSymbolLen, _TRUNCATE,
" %s(%d)", fileName, lineInfo.LineNumber);
}
symbol += fileLineChars;
maxSymbolLen -= fileLineChars;
charsAdded += fileLineChars;
}
return charsAdded;
}
LONG WINAPI exceptionHandler(LPEXCEPTION_POINTERS info)
{
CONTEXT* context = info->ContextRecord;
std::shared_ptr<void> RaiiSysCleaner(nullptr, [&](void*) {
SymCleanup(GetCurrentProcess());
});
const size_t dumpSize = 64;
std::vector<uint64_t> frameVector(dumpSize);
DWORD machine_type = 0;
STACKFRAME64 frame = {};
frame.AddrPC.Mode = AddrModeFlat;
frame.AddrFrame.Mode = AddrModeFlat;
frame.AddrStack.Mode = AddrModeFlat;
#ifdef _M_IX86
frame.AddrPC.Offset = context->Eip;
frame.AddrFrame.Offset = context->Ebp;
frame.AddrStack.Offset = context->Esp;
machine_type = IMAGE_FILE_MACHINE_I386;
#elif _M_X64
frame.AddrPC.Offset = context->Rip;
frame.AddrFrame.Offset = context->Rbp;
frame.AddrStack.Offset = context->Rsp;
machine_type = IMAGE_FILE_MACHINE_AMD64;
#elif _M_IA64
frame.AddrPC.Offset = context->StIIP;
frame.AddrFrame.Offset = context->IntSp;
frame.AddrStack.Offset = context->IntSp;
machine_type = IMAGE_FILE_MACHINE_IA64;
frame.AddrBStore.Offset = context.RsBSP;
frame.AddrBStore.Mode = AddrModeFlat;
#else
frame.AddrPC.Offset = context->Eip;
frame.AddrFrame.Offset = context->Ebp;
frame.AddrStack.Offset = context->Esp;
machine_type = IMAGE_FILE_MACHINE_I386;
#endif
for (size_t index = 0; index < frameVector.size(); ++index)
{
if (StackWalk64(machine_type,
GetCurrentProcess(),
GetCurrentThread(),
&frame,
context,
NULL,
SymFunctionTableAccess64,
SymGetModuleBase64,
NULL)) {
frameVector[index] = frame.AddrPC.Offset;
}
else {
break;
}
}
std::string dump;
const size_t kSize = frameVector.size();
char buffer[2048];
auto symobolLen = kSize * 1024;
for (size_t index = 0; index < kSize && frameVector[index]; ++index) {
if (0 == frameVector[index])
break;
auto charsLen = GetSymbolInfo(frameVector[index], buffer, 2048);
dump += buffer;
dump += "\n";
}
std::cout << dump;
return EXCEPTION_CONTINUE_EXECUTION;
}
LPTOP_LEVEL_EXCEPTION_FILTER WINAPI MyDummySetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter)
{
return NULL;
}
BOOL PreventSetUnhandledExceptionFilter()
{
DWORD dwOrgEntryAddr = 0;
HMODULE hKernel32 = NULL;
void* pOrgEntry = NULL;
unsigned char newJump[100] = { 0 };
void* pNewFunc = NULL;
DWORD dwNewEntryAddr = 0;
DWORD dwRelativeAddr = 0;
SIZE_T bytesWritten = 0;
if (NULL == (hKernel32 = LoadLibrary("kernel32.dll")))
{
return FALSE;
}
if (NULL == (pOrgEntry = GetProcAddress(hKernel32, "SetUnhandledExceptionFilter")))
{
return FALSE;
}
dwOrgEntryAddr = (DWORD)pOrgEntry;
dwOrgEntryAddr += 5; // add 5 for 5 op-codes for jmp far
pNewFunc = &MyDummySetUnhandledExceptionFilter;
dwNewEntryAddr = (DWORD)pNewFunc;
dwRelativeAddr = dwNewEntryAddr - dwOrgEntryAddr;
newJump[0] = 0xE9; // JMP absolute
memcpy(&newJump[1], &dwRelativeAddr, sizeof(pNewFunc));
return WriteProcessMemory(GetCurrentProcess(), pOrgEntry, newJump, sizeof(pNewFunc) + 1, &bytesWritten);
}
bool WriteMiniDump(EXCEPTION_POINTERS* exceptionPtrs, const char* fileName)
{
HANDLE hDump = ::CreateFile(fileName, GENERIC_WRITE, FILE_SHARE_READ, 0,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if (hDump != INVALID_HANDLE_VALUE)
{
MINIDUMP_EXCEPTION_INFORMATION dumpInfo = { 0 };
dumpInfo.ClientPointers = TRUE;
dumpInfo.ExceptionPointers = exceptionPtrs;
dumpInfo.ThreadId = ::GetCurrentThreadId();
MINIDUMP_TYPE dumpType = (MINIDUMP_TYPE)(MiniDumpWithPrivateReadWriteMemory |
MiniDumpWithThreadInfo | MiniDumpWithUnloadedModules);
const BOOL success = ::MiniDumpWriteDump(
::GetCurrentProcess(), ::GetCurrentProcessId(), hDump,
dumpType, &dumpInfo, 0, 0);
::CloseHandle(hDump);
return success == TRUE;
}
return false;
}
#else
#include <execinfo.h>
#include <cxxabi.h>
#include <signal.h>
const std::map<int, std::string> Signals = {
{SIGINT, "SIGINT"},
{SIGABRT, "SIGABRT"},
{SIGFPE, "SIGFPE"},
{SIGILL, "SIGILL"},
{SIGSEGV, "SIGSEGV"}
// 可以添加其他信号
};
void sigHandler(int signum, siginfo_t* info, void* ctx)
{
const size_t dump_size = 50;
void* array[dump_size];
int size = backtrace(array, dump_size);
char** symbols = backtrace_symbols(array, size);
std::ostringstream oss;
for (int i = 0; i < size; ++i)
{
char* mangleName = 0;
char* offsetBegin = 0;
char* offsetEnd = 0;
for (char* p = symbols[i]; *p; ++p)
{
if ('(' == *p)
{
mangleName = p;
}
else if ('+' == *p)
{
offsetBegin = p;
}
else if (')' == *p)
{
offsetEnd = p;
break;
}
}
if (mangleName && offsetBegin && offsetEnd && mangleName < offsetBegin)
{
*mangleName++ = '\0';
*offsetBegin++ = '\0';
*offsetEnd++ = '\0';
int status;
char* realName = abi::__cxa_demangle(mangleName, 0, 0, &status);
if (0 == status)
oss << "\tstack dump [" << i << "] " << symbols[i] << " : " << realName << "+";
else
oss << "\tstack dump [" << i << "] " << symbols[i] << mangleName << "+";
oss << offsetBegin << offsetEnd << std::endl;
free(realName);
}
else
{
oss << "\tstack dump [" << i << "] " << symbols[i] << std::endl;
}
}
free(symbols);
oss << std::endl;
std::cout << oss.str(); // 打印函数调用栈信息
}
#endif
void registerDump() {
#ifdef WIN32
//SetUnhandledExceptionFilter(MyExceptionFilter);
AddVectoredExceptionHandler(1, exceptionHandler);
PreventSetUnhandledExceptionFilter();
#else
struct sigaction action;
sigemptyset(&action.sa_mask);
action.sa_sigaction = &sigHandler;
action.sa_flags = SA_SIGINFO;
for (const auto& sigPair : Signals)
{
if (sigaction(sigPair.first, &action, NULL) < 0)
fprintf(stderr, "Error: sigaction failed! \n");
}
#endif
}
class A {
public:
int word;
};
void dumpFunc() {
int* p = nullptr;
*p = 32;
std::cout << "test" << std::endl;
int* a = new int;
*a = 555;
delete a;
*a = 1;
*a = 2;
*a = 3;
A* b = new A;
b->word = 12312;
delete b;
b->word = 2244;
}
void test() {
registerDump();
dumpFunc();
}
输出
00007FF7531BCA54 test.exe dumpFunc + 0x14 main_callstack.cpp(326+0005 byte(s))
CCCCCCCCCCCCCCCC
linux程序崩溃调用栈打印工具
catchsegv program [args]
malloc_trim(0); 这一行代码会将空闲的堆内存归还给操作系统,供其他进程使用
gdb打印
gdb ./myapp
输入 r 开始运行
等到出 SIGSEGV
输入 bt 即可查看栈回溯,从上往下看
Linux+Windows: 程序崩溃时,在 C++ 代码中,如何获取函数调用栈信息-腾讯云开发者社区-腾讯云
wasm chrome崩溃分析_wasm内存崩溃-CSDN博客