QT--Crash cause analysis

This article is a learning record. If there are any errors, please contact the author and be humble and educated.


Preface

You are always free to come and go, if you don't want it anymore, just run away.


First, the purpose

The cause of the crash is analyzed in the released customer version to facilitate problem solving.

2. Implementation steps

1 add2line.exe

Find adde2line.exe in the directory where your QT is installed, for example: D:\Qt\Qt5.12.3\Tools\mingw730_32\bin.
Insert image description here
Copy add2line.exe into your own published version.
Insert image description here

2 Analysis files

Add a class to the code and add addr2line.exe to the folder where the release version is located. After the subsequent program crashes, the code will generate a MyApp folder in the project file, which contains a crash file.
Insert image description here
Insert image description here

3 crash files

Open the crash file and find your addr.
Insert image description here
Open QT's cmd and enter the path of your release version. For example
1. cd D:\TEST\1QTTEST\Thermopile_HM\32X32\Client\V1.0.1Client\release
2. addr2line.exe -f -e software file name crash address (tip: space in the middle)
3. Prompt error message
Insert image description here

3. Related codes

1 pro file

Add the following code to the pro file:

QMAKE_CFLAGS_RELEASE += -g
QMAKE_CXXFLAGS_RELEASE += -g
QMAKE_CFLAGS_RELEASE -= -O2
QMAKE_CXXFLAGS_RELEASE -= -O2
QMAKE_LFLAGS_RELEASE = -mthreads -W

2.ccrashstack.h

#ifndef CCRASHSTACK_H
#define CCRASHSTACK_H
#include <windows.h>
#include <QString>

class ccrashstack
{
    
    
private:
    PEXCEPTION_POINTERS m_pException;
private:
    QString GetModuleByRetAddr(PBYTE Ret_Addr, PBYTE & Module_Addr);
    QString GetCallStack(PEXCEPTION_POINTERS pException);
    QString GetVersionStr();
    bool GetHardwareInaformation(QString &graphics_card, QString &sound_deivce);
public:
    ccrashstack(PEXCEPTION_POINTERS pException);
    QString GetExceptionInfo();
};

#endif // CCRASHSTACK_H

3.ccrashstack.cpp

#include "ccrashstack.h"
#include <tlhelp32.h>
#include <stdio.h>

#define _WIN32_DCOM
#include <comdef.h>
#include <Wbemidl.h>

//#include<base/constants.h>
#include "qdebug.h"

ccrashstack::ccrashstack(PEXCEPTION_POINTERS pException)
{
    
    
    m_pException = pException;
}


QString ccrashstack::GetModuleByRetAddr(PBYTE Ret_Addr, PBYTE & Module_Addr)
{
    
    
    MODULEENTRY32   M = {
    
    sizeof(M)};
    HANDLE  hSnapshot;

    wchar_t Module_Name[MAX_PATH] = {
    
    0};

    hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 0);

    if ((hSnapshot != INVALID_HANDLE_VALUE) &&
            Module32First(hSnapshot, &M))
    {
    
    
            do
            {
    
    
                    if (DWORD(Ret_Addr - M.modBaseAddr) < M.modBaseSize)
                    {
    
    
                            lstrcpyn(Module_Name, M.szExePath, MAX_PATH);
                            Module_Addr = M.modBaseAddr;
                            break;
                    }
            } while (Module32Next(hSnapshot, &M));
    }

    CloseHandle(hSnapshot);

    QString sRet = QString::fromWCharArray(Module_Name);
    return sRet;
}

QString ccrashstack::GetCallStack(PEXCEPTION_POINTERS pException)
{
    
    
        PBYTE   Module_Addr_1;
        char bufer[256]={
    
    0};
        QString sRet;

        typedef struct STACK
        {
    
    
                STACK * Ebp;
                PBYTE   Ret_Addr;
                DWORD   Param[0];
        } STACK, * PSTACK;

        STACK   Stack = {
    
    0, 0};
        PSTACK  Ebp;

        if (pException)     //fake frame for exception address
        {
    
    
                Stack.Ebp = (PSTACK)pException->ContextRecord->Ebp;
                Stack.Ret_Addr = (PBYTE)pException->ExceptionRecord->ExceptionAddress;
                Ebp = &Stack;
        }
        else
        {
    
    
                Ebp = (PSTACK)&pException - 1;  //frame addr of Get_Call_Stack()

                // Skip frame of Get_Call_Stack().
                if (!IsBadReadPtr(Ebp, sizeof(PSTACK)))
                        Ebp = Ebp->Ebp;     //caller ebp
        }

        // Break trace on wrong stack frame.
        for (; !IsBadReadPtr(Ebp, sizeof(PSTACK)) && !IsBadCodePtr(FARPROC(Ebp->Ret_Addr));
                 Ebp = Ebp->Ebp)
        {
    
    
            // If module with Ebp->Ret_Addr found.
            memset(bufer,0, sizeof(0));
            sprintf(bufer, "\n%08X  ", (unsigned int)Ebp->Ret_Addr);
            sRet.append(bufer);

            QString moduleName = this->GetModuleByRetAddr(Ebp->Ret_Addr, Module_Addr_1) ;
            if (moduleName.length() > 0)
            {
    
    
                sRet.append(moduleName);
            }

        }

        return sRet;
} //Get_Call_Stack

QString ccrashstack::GetVersionStr()
{
    
    
        OSVERSIONINFOEX V = {
    
    sizeof(OSVERSIONINFOEX)};  //EX for NT 5.0 and later

        if (!GetVersionEx((POSVERSIONINFO)&V))
        {
    
    
                ZeroMemory(&V, sizeof(V));
                V.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
                GetVersionEx((POSVERSIONINFO)&V);
        }

        if (V.dwPlatformId != VER_PLATFORM_WIN32_NT)
                V.dwBuildNumber = LOWORD(V.dwBuildNumber);  //for 9x HIWORD(dwBuildNumber) = 0x04xx

        QString sRet;
        sRet.append(QString("Windows:  %1.%2.%3, SP %4.%5, Product Type %6\n")
                .arg(V.dwMajorVersion).arg(V.dwMinorVersion).arg(V.dwBuildNumber)
                .arg(V.wServicePackMajor).arg(V.wServicePackMinor).arg(V.wProductType));

//        QString graphics_module = "GraphicsCard: ";
//        QString sound_module = "SoundDevice: ";
//        GetHardwareInaformation(graphics_module, sound_module);
//        sRet.append(graphics_module);
//        sRet.append(sound_module);

        return sRet;
}

QString ccrashstack::GetExceptionInfo()
{
    
    
        WCHAR       Module_Name[MAX_PATH];
        PBYTE       Module_Addr;

        QString sRet;
        char buffer[512]={
    
    0};

        QString sTmp = GetVersionStr();
        sRet.append(sTmp);
        sRet.append("Process:  ");

        GetModuleFileName(NULL, Module_Name, MAX_PATH);
        sRet.append(QString::fromWCharArray(Module_Name));
        sRet.append("\n");

        // If exception occurred.
        if (m_pException)
        {
    
    
                EXCEPTION_RECORD &  E = *m_pException->ExceptionRecord;
                CONTEXT &           C = *m_pException->ContextRecord;

                memset(buffer, 0, sizeof(buffer));
                sprintf(buffer, "Exception Addr:  %08X  ", (int)E.ExceptionAddress);
                sRet.append(buffer);
                // If module with E.ExceptionAddress found - save its path and date.
                QString module = GetModuleByRetAddr((PBYTE)E.ExceptionAddress, Module_Addr);
                if (module.length() > 0)
                {
    
    
                    sRet.append(" Module: ");

                    sRet.append(module);
                }

                memset(buffer, 0, sizeof(buffer));
                sprintf(buffer, "\nException Code:  %08X\n", (int)E.ExceptionCode);
                sRet.append(buffer);

                if (E.ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
                {
    
    
                        // Access violation type - Write/Read.
                    memset(buffer, 0, sizeof(buffer));
                    sprintf(buffer,"%s Address:  %08X\n",
                            (E.ExceptionInformation[0]) ? "Write" : "Read", (int)E.ExceptionInformation[1]);
                    sRet.append(buffer);
                }


                sRet.append("Instruction: ");
                for (int i = 0; i < 16; i++)
                {
    
    
                    memset(buffer, 0, sizeof(buffer));
                    sprintf(buffer, " %02X",  PBYTE(E.ExceptionAddress)[i]);
                    sRet.append(buffer);
                }

                sRet.append("\nRegisters: ");

                memset(buffer, 0, sizeof(buffer));
                sprintf(buffer, "\nEAX: %08X  EBX: %08X  ECX: %08X  EDX: %08X",  (unsigned int)C.Eax,(unsigned int) C.Ebx, (unsigned int)C.Ecx, (unsigned int)C.Edx);
                sRet.append(buffer);

                memset(buffer, 0, sizeof(buffer));
                sprintf(buffer, "\nESI: %08X  EDI: %08X  ESP: %08X  EBP: %08X", (unsigned int)C.Esi, (unsigned int)C.Edi, (unsigned int)C.Esp, (unsigned int)C.Ebp);
                sRet.append(buffer);

                memset(buffer, 0, sizeof(buffer));
                sprintf(buffer, "\nEIP: %08X  EFlags: %08X", (unsigned int)C.Eip,(unsigned int) C.EFlags);
                sRet.append(buffer);

        } //if (pException)

        sRet.append("\nCall Stack:");
        QString sCallstack = this->GetCallStack(m_pException);
        sRet.append(sCallstack);

        return sRet;
}

4.main.cpp

int main(int argc, char *argv[])
{
    
    
    QApplication a(argc, argv);
    SetUnhandledExceptionFilter(callback);
    MainWindow w;
    w.show();
    return a.exec();
}

Summarize

Be good at summarizing and go one step further.

Guess you like

Origin blog.csdn.net/m0_51988927/article/details/132225226