Linux下Qt breakpad编译使用

一、下载安装包

  • 下载qbreakpad源码:
git clone https://github.com/buzzySmile/qBreakpad.git
  •  下载breakpad源码
git clone https://github.com/google/breakpad
  • 下载linux-syscall-support
    没有这个文件,编译报错
git clone https://github.com/adelshokhy112/linux-syscall-support.git

 二、编译

第一步:切换到breakpad目录

cd breakpad

第二步:

./configure

cxx@cxx-virtual-machine:~/Demo/breakpad$ ./configure  

 第三步:把linux-syscall-support目录下的lss文件拷贝到breakpad/src/third_party,如下图

 第四步:编译 

make -j12

注意:

如果make提示以下错误

 ./third_party/lss/linux_syscall_support.h: In member function ‘bool google_breakpad::ExceptionHandler::GenerateDump(google_breakpad::ExceptionHandler::CrashContext*)’:
./third_party/lss/linux_syscall_support.h:2146:75: error: listing the stack pointer register ‘rsp’ in a clobber list is deprecated [-Werror=deprecated]
 2146 |                              : "rsp", "memory", "r8", "r10", "r11", "rcx");
      |                                                                           ^

 则修改/lss/linux_syscall_support.h,如下图

如果提示“fatal error: zlib.h: 没有那个文件或目录”错误

src/common/linux/dump_symbols.cc' || echo './'`src/common/linux/dump_symbols.cc
src/common/linux/dump_symbols.cc:53:10: fatal error: zlib.h: 没有那个文件或目录
 #include <zlib.h>
          ^~~~~~~~
compilation terminated. 

解决方法:

在命令行中输入以下内容

sudo apt-get install zlib1g-dev

 重新编译

make -j12

出现以下信息,则编译成功

 第四步:

sudo make install

查看生成文件路径

which dump_syms

cxx@cxx-virtual-machine:~/Demo/breakpad$ which dump_syms
/usr/local/bin/dump_syms
cxx@cxx-virtual-machine:~/Demo/breakpad$ cd /usr/local/bin
cxx@cxx-virtual-machine:/usr/local/bin$ ls
core2md    dump_syms_mac        minidump-2-core  minidump_stackwalk  pid2md
dump_syms  microdump_stackwalk  minidump_dump    minidump_upload     sym_upload

 Qt中如何运用

在.pro文件中添加 

INCLUDEPATH +=/usr/local/include/breakpad
LIBS +=/usr/local/lib/libbreakpad_client.a
LIBS +=/usr/local/lib/libbreakpad.a

在main.cpp中添加头文件和

#include "client/linux/handler/exception_handler.h"
#include "client/linux/handler/minidump_descriptor.h"
#include "mainwindow.h"
#include <iostream>
#include <QApplication>
#include "client/linux/handler/exception_handler.h"
#include "client/linux/handler/minidump_descriptor.h"
using namespace std;

using namespace google_breakpad;

bool minidumpDB(const MinidumpDescriptor& descriptor,void* context,bool succeeded)
{
    if(succeeded){
        std::cout<<"Mini Dump file:"<<descriptor.path()<<std::endl;
    }
    return succeeded;
}
int crash(int a,int b){
    return a/b;
}

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    //获取当前可执行文件的路径
    QString path = QCoreApplication::applicationDirPath();
    //这里设置生成.dmp文件的路径为当前可执行文件的路径
    google_breakpad::MinidumpDescriptor descriptor(path.toStdString());
    google_breakpad::ExceptionHandler eh(descriptor,NULL,minidumpDB,NULL,true,-1);
    MainWindow w;
    w.show();
    crash(5,0);
    return a.exec();
}

在生成的可执行文件目录下,创建一个breakpad.py文件:

 breakpad.py文件,内容如下

# -*- coding: utf-8 -*-
import os 
import sys
import subprocess
import shutil
import traceback

ENVPATH = "/usr/local/bin"
def track_error():
    error_message=""
    (type,value,trace)=sys.exc_info()
    print("**************************************************************")
    print("Error_Type:\t%s\n"%type)
    print("Error_Value:\t%s\n"%value)
    print("%-40s %-20s %-20s %-20s\n"%("Filename", "Function","Linenum", "Source"))
    for filename, linenum, funcname, source in traceback.extract_tb(trace):
        print("%-40s %-20s %-20s%-20s" % (os.path.basename(filename),funcname,linenum, source))
    print("**************************************************************")

class RunDump(object):
    def __init__(self,m_app):
        self.current = os.path.abspath(os.path.dirname(m_app))
        self.appname = os.path.basename(m_app)
        self.app = os.path.abspath(m_app)
        self.symbols = os.path.join(self.current,"symbols")
        self.dump = None
        self.symfile = "%s.sym"%(self.app)
        self.mkdirpath = None
       

        self.Run()

    def __del__(self):
        if  os.path.exists(self.symbols):
            shutil.rmtree(self.symbols)
        if self.dump:
            os.remove(self.dump)
    def Get_Dump(self):
        dmp = list(filter(lambda file:  os.path.splitext(file)[-1] == ".dmp",os.listdir(self.current)))
        if dmp == list():
            print("dmp file not exist...")
            exit(1)
        self.dump = os.path.join(self.current,dmp[-1])
        
      
    def RunCmd(self,cmd):
        new_env = os.environ.copy()
        new_env["PATH"] = ENVPATH
        pid = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True,env = new_env)
        for i in pid.communicate():
            if len(i)>0:
                print(i)
        return pid.wait()
    
    def readlline(self):
        line = ""
        with open(self.symfile) as fd:
            for line in fd:
                break
        linemd5 = line.split()[-2]
        self.mkdirpath = os.path.join(self.symbols,self.appname,linemd5)
        os.makedirs(self.mkdirpath,exist_ok = True)   
        shutil.move(self.symfile,self.mkdirpath)
        print("symbols目录生成:%s"%self.mkdirpath )

    def Run(self):
        self.Get_Dump()
        self.CreatSym()
        self.readlline()
        self.CreatDump()

    def CreatSym(self):
        cmd = "dump_syms %s>%s"%(self.app,self.symfile)
        if self.RunCmd(cmd):
            print("%s 运行出错"%cmd)
            exit(1)
        else:
            print("生成sym文件:%s"%self.symfile)
         
    def CreatDump(self):
        sysmbols = os.path.join(os.path.join(self.current,"symbols"))
        creashlog = os.path.join(os.path.join(self.current,"crash.log"))
        errorlog = os.path.join(os.path.join(self.current,"error.log"))
        cmd = "minidump_stackwalk %s %s >%s 2>%s"%(self.dump,sysmbols,creashlog,errorlog)
        if self.RunCmd(cmd):
            print("%s 运行出错"%cmd)
        else:
            print("crash.log生成成功:%s"%creashlog)
    

if __name__ == "__main__":
    if len(sys.argv[:])<2:
        print("""输入命令:./Breakpad.py  AppPath 
            AppPath:程序app 所在路径
        """)
        exit(1)
    try:
        app = sys.argv[1]
        RunDump(app)
    except BaseException:
            track_error()

 执行程序,即可在可执行目录下生成一个dmp文件

 执行dmp解析

python3 breakpad.py ./breakTest

cxx@cxx-virtual-machine:~/Demo/build-breakTest-Desktop_Qt_5_14_2_GCC_64bit-Debug$ python3 breakpad.py ./breakTest 
生成sym文件:/home/cxx/Demo/build-breakTest-Desktop_Qt_5_14_2_GCC_64bit-Debug/breakTest.sym
symbols目录生成:/home/cxx/Demo/build-breakTest-Desktop_Qt_5_14_2_GCC_64bit-Debug/symbols/breakTest/EC33EEC8E77904C93D41C11D6FAE6E180
crash.log生成成功:/home/cxx/Demo/build-breakTest-Desktop_Qt_5_14_2_GCC_64bit-Debug/crash.log 

 生成crash.log 和error.log文件

 打开crash.log,即可看到记录到的详细错误信息。

dmp 解析脚本:

GitHub - heisai/breakpad: breakpad 解析生成log

猜你喜欢

转载自blog.csdn.net/my_angle2016/article/details/131520845