C++ Debug:如何使用DbgHelp来为crash的release版本收集崩溃信息

头文件

#include <windows.h>
#include <QDebug>
#pragma comment(lib, "dbghelp.lib")

class CCrashStack
{

public:
    CCrashStack(PEXCEPTION_POINTERS pException);
    void generateDumpFile(struct _EXCEPTION_POINTERS* exceptionInfo);
    QStringList SaveCallStack(const EXCEPTION_POINTERS* pException);
private:
    PEXCEPTION_POINTERS m_pException;
};

cpp

//key : 
// 1. CaptureStackBackTrace(0, maxFrames, framePointers, nullptr);
// 2. SYMBOL_INFO symbolInfo;
// 3. SymFromAddr(process, (DWORD64)(framePointers[i]), nullptr, &symbolInfo)
#include <tlhelp32.h>
#include "DbgHelp.h"
#include "LogServer.h"

CCrashStack::CCrashStack(PEXCEPTION_POINTERS pException)
{
    m_pException = pException;
}
const int MAX_STACK_FRAMES = 64;
const int MAX_SYM_NAME_LEN = 64;

QStringList CCrashStack::SaveCallStack(const EXCEPTION_POINTERS* pException)
{
    QStringList callStack;

    const int maxFrames = 50;
    void* framePointers[maxFrames];
    unsigned int frameCount = CaptureStackBackTrace(0, maxFrames, framePointers, nullptr);

    HANDLE process = GetCurrentProcess();
    SymInitialize(process, nullptr, TRUE);


    for (unsigned int i = 0; i < frameCount; ++i)
    {
        SYMBOL_INFO symbolInfo;
        symbolInfo.SizeOfStruct = sizeof(SYMBOL_INFO);
        symbolInfo.MaxNameLen = 256;

        if (SymFromAddr(process, (DWORD64)(framePointers[i]), nullptr, &symbolInfo))
        {
            callStack.push_back(QString("%1 : Address : %2")
                                .arg(symbolInfo.Name)
                                .arg(symbolInfo.Address));
//                IMAGEHLP_LINE64 lineInfo = { sizeof(IMAGEHLP_LINE64) };
//                if (SymGetLineFromAddr64(process, (DWORD64)(framePointers[i]), nullptr, &lineInfo))
//                {

//                    callStack.push_back(QString("%1 : Address : %2")
//                                        .arg(lineInfo.FileName)
//                                        .arg(lineInfo.LineNumber));
//                } else {
//                    callStack.push_back(QString("<unknown file> : Address : 0"));
//                }
        } else
        {
            callStack.push_back("<unknown>");
        }
    }

//    for (const auto& frame : callStack)
//    {
//        LOGE(QString(frame));
//    }
    SymCleanup(process);

    return callStack;
}

void CCrashStack::generateDumpFile(struct _EXCEPTION_POINTERS* exceptionInfo)
{
    QStringList sCrashInfo = SaveCallStack(exceptionInfo);
    QString Time = CURRENT_TIME_MS;
    QString sFileName = "testcrash_" + Time + ".log";

    QFile file(sFileName);
    if (file.open(QIODevice::WriteOnly|QIODevice::Truncate))
    {
        file.write("Dump Stack Info : \n");
        for (int i = 0; i < sCrashInfo.size(); i++)
            file.write(sCrashInfo[i].toUtf8() + "\n");
        file.write("\n\n");
        file.write("Log Info : \n");
        QStringList messageList = LogServer::instance()->messageList();
        for (int i = 0; i < messageList.size(); i++)
            file.write(messageList[i].toUtf8());
        file.close();
    }

    qDebug()<<"Error:\n"<<sCrashInfo;
    QString CrashDump = QString("CrashDump_%1.dmp").arg(Time);
    HANDLE hDumpFile = CreateFile(CrashDump.toStdWString().c_str(),
                                  GENERIC_WRITE,
                                  0,
                                  NULL,
                                  CREATE_ALWAYS,
                                  FILE_ATTRIBUTE_NORMAL,
                                  NULL);

    MINIDUMP_EXCEPTION_INFORMATION dumpInfo;
    dumpInfo.ThreadId = GetCurrentThreadId();
    dumpInfo.ExceptionPointers = exceptionInfo;
    dumpInfo.ClientPointers = TRUE;
    MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hDumpFile, MiniDumpNormal, &dumpInfo, NULL, NULL);

    CloseHandle(hDumpFile);
}

how to callback: SetUnhandledExceptionFilter

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    SetUnhandledExceptionFilter(callback);
    return a.exec();
}

result

Dump Stack Info : 
CCrashStack::SaveCallStack : Address : 140696195610800
<unknown>
callback : Address : 140696195637056
UnhandledExceptionFilter : Address : 140720007597360
memcpy : Address : 140720052592384
_C_specific_handler : Address : 140720052498688
_chkstk : Address : 140720052585200
RtlFindCharInUnicodeString : Address : 140720052034000
KiUserExceptionDispatcher : Address : 140720052581344
QByteArray::QByteArray : Address : 140718069457184
EvaluatorThread::run : Address : 140717834213072
QThread::start : Address : 140718071360352
BaseThreadInitThunk : Address : 140720023741792
RtlUserThreadStart : Address : 140720052283952


Log Info : 
"[2024-04-09 10:56:05:009] [2608] [D] [     LinearityTester] 294 : 479.862,798.501,795.139,534.052,"
"[2024-04-09 10:56:05:009] [2608] [D] [              GC32E1] exposureTime = 295, realExposureTime = 295, line = 295"
"[2024-04-09 10:56:05:009] [2608] [D] [     DxDevicePrivate] [I2C][W] slaveID = 0x94, reg = 0x0202, value = 0x0001, mode = 0x3"
"[2024-04-09 10:56:05:010] [2608] [D] [     DxDevicePrivate] [I2C][W] slaveID = 0x94, reg = 0x0203, value = 0x0027, mode = 0x3"
"[2024-04-09 10:56:05:010] [2608] [D] [     LinearityTester] abandon frame : 0"
"[2024-04-09 10:56:05:070] [2608] [D] [     LinearityTester] abandon frame : 1"
"[2024-04-09 10:56:05:136] [2608] [D] [     LinearityTester] abandon frame : 2"

wait to do

// IMAGEHLP_LINE64 lineInfo = { sizeof(IMAGEHLP_LINE64) };
// if (SymGetLineFromAddr64(process, (DWORD64)(framePointers[i]), nullptr, &lineInfo))
// {

//      callStack.push_back(QString("%1 : Address : %2")
//                                        .arg(lineInfo.FileName)
//                                        .arg(lineInfo.LineNumber));
//                } else {
//                    callStack.push_back(QString("<unknown file> : Address : 0"));
//                }

You may use SymGetLineFromAddr64 to get line infomation. 
Howerver, even i`ve produce the .dmp data, i haven`t get the expected result

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值