C++ 崩溃调用栈打印

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博客


创作不易,小小的支持一下吧!

  • 17
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码力码力我爱你

创作不易,小小的支持一下吧!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值