一、下载安装包
- 下载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