文章目录
一、下载
https://github.com/google/breakpad
二、编译安装
1、Linux平台
(1)编译安装
解压到目录breakpad,然后在命令窗口cd到改目录下。执行命令:
常规编译
./configure --prefix=/opt/breakpad-ubuntu-x64
交叉编译
# 设置交叉编译工具链到环境变量
export PATH=/opt/tools-master/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin:$PATH
./configure \
CC=arm-linux-gnueabihf-gcc \
CXX=arm-linux-gnueabihf-g++ \
AR=arm-linux-gnueabihf-gcc-ar \
RANLIB=arm-linux-gnueabihf-gcc-ranlib \
--host=arm-linux-gnueabihf \
--prefix=/opt/breakpad-raspberrypi-armv7l
执行命令:make。会报错:
In file included from ./src/client/linux/dump_writer_common/thread_info.h:37:0,
from ./src/client/linux/minidump_writer/linux_dumper.h:54,
from ./src/client/linux/minidump_writer/minidump_writer.h:42,
from src/tools/linux/core2md/core2md.cc:34:
./src/common/memory_allocator.h:50:51: fatal error: third_party/lss/linux_syscall_support.h: 没有那个文件或目录
compilation terminated.
Makefile:5685: recipe for target 'src/tools/linux/core2md/core2md.o' failed
make: *** [src/tools/linux/core2md/core2md.o] Error 1
解决方法: 下载linux_syscall_support.h文件,创建目录breakpad/src/third_party/lss/,并把文件放入其中,然后重新执行make命令。
编译结束后,执行命令:sudo make install,即可安装到目录/opt/breakpad-ubuntu-x64中,如:

(2)环境配置
export BREADKPAD_ROOT=/opt/breakpad-ubuntu-x64
# 运行依赖
export LD_LIBRARY_PATH=$BREADKPAD_ROOT/lib:$LD_LIBRARY_PATH
# 开发依赖
export PATH=$BREADKPAD_ROOT/bin:$PATH
export CPATH=$BREADKPAD_ROOT/include/breakpad:$CPATH
export LIBRARY_PATH=$BREADKPAD_ROOT/lib:$LIBRARY_PATH
(3)使用
#include <iostream>
#include "client/linux/handler/exception_handler.h"
/* 写完minidump后的回调函数 */
static bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, void* context, bool succeeded)
{
std::cout << "Dump path: " << descriptor.path() << std::endl;
return succeeded;
}
/* 触发crash来测试 */
void crash()
{
volatile int* a = (int*)(NULL);
*a = 1;
}
int main(int argc, char* argv[])
{
/* 初始化 */
ExceptionHandler google_breakpad::MinidumpDescriptor descriptor("/home/jaron/dump");
/* minidump文件写入到的目录 */
google_breakpad::ExceptionHandler eh(descriptor, NULL, dumpCallback, NULL, true, -1);
crash();
return 0;
}
需要链接静态库:libbreakpad_client.a
- 这样就会在
/home/jaron/dump(目录必须预先创建好)下生成*.dmp文件,如:d0aedfee-2b7a-46a5-49180aa1-7b7c6f5f.dmp。 - 为了生成可读的stacktrace, 需要你将binaries里的调试符号(debugging symbols)转换成基于文本格式的symbol files。
- 运行
dump_syms命令来生成symbol files,如下:
/opt/breakpad-ubuntu-x64/bin/dump_syms _build/test > test.sym
- 运行命令:
head -n1 test.sym,如下:
jaron@jaron-VirtualBox:~/test$ head -n1 test.sym
MODULE Linux x86_64 3A681570B189906CB746EEC92E4BABF00 test
- 创建个特定的目录,目录名是根据上面的信息得出,然后把test.sym文件拷贝进去,如下:
mkdir -p symbols/test/3A681570B189906CB746EEC92E4BABF00
mv test.sym symbols/test/3A681570B189906CB746EEC92E4BABF00
- breakpad包含一个叫做
minidump_stackwalk的工具来将minidump文件,外加symbol files来生成一个人可读的stacktrace。
/opt/breakpad-ubuntu-x64/bin/minidump_stackwalk d0aedfee-2b7a-46a5-49180aa1-7b7c6f5f.dmp symbols > d0aedfee-2b7a-46a5-49180aa1-7b7c6f5f.txt
d0aedfee-2b7a-46a5-49180aa1-7b7c6f5f.txt就是最终生成的可读的异常文件可用于分析,如下:
Operating system: Linux
0.0.0 Linux 4.15.0-142-generic #146~16.04.1-Ubuntu SMP Tue Apr 13 09:27:15 UTC 2021 x86_64
CPU: amd64
family 6 model 140 stepping 1
1 CPU
GPU: UNKNOWN
Crash reason: SIGSEGV /SEGV_MAPERR
Crash address: 0x0
Process uptime: not available
Thread 0 (crashed)
0 test!main [main.cpp : 15 + 0x0]
rax = 0xffffffffffffffff rdx = 0x0000000000402246
rcx = 0x00007f35f7887b20 rbx = 0x0000000000000010
rsi = 0x0000000000000000 rdi = 0x00000000006199c0
rbp = 0x00007ffd9858cbe0 rsp = 0x00007ffd9858ca40
r8 = 0x0000000000000000 r9 = 0x0000000000000000
r10 = 0x0000000000000131 r11 = 0x00007f35f7e304c0
r12 = 0x0000000000402360 r13 = 0x00007ffd9858ccc0
r14 = 0x000000000156ec20 r15 = 0x0000000000000000
rip = 0x0000000000402271
Found by: given as instruction pointer in context
1 libc.so.6 + 0x20840
rbx = 0x0000000000000000 rbp = 0x0000000000413770
rsp = 0x00007ffd9858cbf0 r12 = 0x0000000000402360
r13 = 0x00007ffd9858ccc0 r14 = 0x0000000000000000
r15 = 0x0000000000000000 rip = 0x00007f35f74e3840
Found by: call frame info
2 test!_start + 0x29
rsp = 0x00007ffd9858ccb0 rip = 0x0000000000402389
Found by: stack scanning
3 0x7ffd9858ccb8
rsp = 0x00007ffd9858ccb8 rip = 0x00007ffd9858ccb8
Found by: call frame info
Loaded modules:
0x00400000 - 0x00418fff test ??? (main)
0x7f35f71ba000 - 0x7f35f72c1fff libm.so.6 ???
0x7f35f74c3000 - 0x7f35f7682fff libc.so.6 ??? (WARNING: No symbols, libc.so.6, E83B77305BCFD9FED910C8473DD44EAA0)
0x7f35f788d000 - 0x7f35f78a2fff libgcc_s.so.1 ???
0x7f35f7aa3000 - 0x7f35f7c14fff libstdc++.so.6 ???
0x7f35f7e25000 - 0x7f35f7e3cfff libpthread.so.0 ???
0x7f35f8042000 - 0x7f35f8067fff ld-linux-x86-64.so.2 ???
0x7ffd985a2000 - 0x7ffd985a3fff linux-gate.so ???
根据堆栈信息,可以看到崩溃的地方在文件main.cpp,第15行。
(4)addr2line
使用addr2line可以定位程序文件指定地址的函数位置,用法如:
root@kylin:~# addr2line -e /usr/lib/aarch64-linux-gnu/libstdc++.so.6 0xa18c8 -f
_ZN9__gnu_cxx27__verbose_terminate_handlerEv
??:?
(5)脚本工具
dump_assist.sh
#!/bin/bash
################################################################################
# 说 明: 根据可执行程序文件以及崩溃时产生的dmp文文件, 生成具有可阅读性的崩溃堆栈txt文件
# 参 数: -pname 指定可执行程序文件(全路径), 例如: /home/bin/test.exe
# -pver 指定可执行程序文件版本号, 例如: 1.0.0
# -dname 指定崩溃堆栈文件(全路径), 例如: /home/dump/d0aedfee-2b7a-46a5-49180aa1-7b7c6f5f.dmp
# 返回值: 返回json字符串, 格式如: {"code": 0, "file": "/home/dump/test1.0.0_20210609135634409.txt", "msg": "ok"}
# 用 法: dump_assist.sh -pname /home/bin/test.exe -pver 1.0.0 -dname /home/dump/d0aedfee-2b7a-46a5-49180aa1-7b7c6f5f.dmp
################################################################################
# 程序文件全路径名(外部输入)
proc_file=
# 程序文件版本(外部输入)
proc_ver=
# 堆栈文件全路径名(外部输入)
dump_file=
# 解析参数-pname和-dname
function parseParams() {
foundProc=0
foundVer=0
foundDump=0
for item in $@ ; do
if [ $foundProc == 1 ]; then
proc_file="$item"
foundProc=2
fi
if [ $foundVer == 1 ]; then
proc_ver="$item"
foundVer=2
fi
if [ $foundDump == 1 ]; then
dump_file="$item"
foundDump=2
fi
if [ "$item" == "-pname" ]; then
foundProc=1
fi
if [ "$item" == "-pver" ]; then
foundVer=1
fi
if [ "$item" == "-dname" ]; then
foundDump=1
fi
done
}
parseParams $@
# 判断文件是否存在
if [ ! -f "$proc_file" ]; then # 程序文件不存在
echo "{\"code\": 1, \"file\": \"$proc_file\", \"msg\": \"proc file not exist\"}"
exit 0
fi
if [ ! -f "$dump_file" ]; then # 堆栈文件不存在
echo "{\"code\": 2, \"file\": \"$dump_file\", \"msg\": \"dump file not exist\"}"
exit 0
fi
# 计算变量值
now_date_time=$(date +%Y%m%d%H%M%S%N | cut -b 1-17)
proc_filename=$(basename $proc_file)
proc_basename=${proc_filename%%.*}
dump_path=$(dirname $dump_file)
symbol_path=$dump_path/symbol
if [ ! -d "$symbol_path" ]; then
mkdir -p $symbol_path
fi
tmp_symbol_file=$symbol_path/$proc_filename.sym
tmp_dump_file=$dump_path/$proc_basename$proc_ver'_'$now_date_time.dmp
target_file=$dump_path/$proc_basename$proc_ver'_'$now_date_time.txt
# 重命名dump文件
mv $dump_file $tmp_dump_file
if [ ! -f "$tmp_dump_file" ]; then # 重命名堆栈文件失败
echo "{\"code\": 3, \"file\": \"$tmp_dump_file\", \"msg\": \"dump file rename fail\"}"
exit 0
fi
dump_file=$tmp_dump_file
# 生成符号文件
dump_syms $proc_file > $tmp_symbol_file
if [ ! -f "$tmp_symbol_file" ]; then # 生成符号文件失败
echo "{\"code\": 4, \"file\": \"$tmp_symbol_file\", \"msg\": \"symbol file generate fail\"}"
exit 0
fi
head_line_str=$(head -n1 $tmp_symbol_file) # 获取第一行数据
head_line_array=(${head_line_str// / }) # 使用空格分割字符串
head_line_array_len=${#head_line_array[@]}
if [ $head_line_array_len -ne 5 ]; then # 符号文件格式错误
echo "{\"code\": 5, \"file\": \"$tmp_symbol_file\", \"msg\": \"symbol file format error\"}"
exit 0
fi
proc_symbol_path=$symbol_path/${head_line_array[4]}/${head_line_array[3]}
if [ ! -d "$proc_symbol_path" ]; then
mkdir -p $proc_symbol_path
fi
proc_symbol_file=$proc_symbol_path/$proc_filename.sym
mv $tmp_symbol_file $proc_symbol_file
if [ ! -f "$proc_symbol_file" ]; then # 移动符号文件失败
echo "{\"code\": 6, \"file\": \"$proc_symbol_file\", \"msg\": \"symbol file move fail\"}"
exit 0
fi
# 翻译堆栈文件
minidump_stackwalk $dump_file $symbol_path > $target_file
if [ ! -f "$target_file" ]; then # 生成目标文件失败
echo "{\"code\": 7, \"file\": \"$target_file\", \"msg\": \"target file generate fail\"}"
exit 0
fi
rm $dump_file
echo "{\"code\": 0, \"file\": \"$target_file\", \"msg\": \"ok\"}"
2、Windows平台
(1)编译安装
- 安装
python2.x,注意: 使用python3.x后面会报错。 - 下载
gyp并解压,拷贝到目录breakpad\src\tools目录下,如:

- 通过命令行进入
gyp目录,安装gyp,执行命令:
python setup.py install
- 然后生成vs工程,执行命令:
gyp.bat --no-circular-check ../../client/windows/breakpad_client.gyp
注意: 这里不能使用绝对路径,需要使用相对路径。
会在目录breakpad\src\client\windows下生成vs工程文件,如:

编译的时候会报错,可以忽略掉,如:
编译结束后,会生成如下库文件:

(2)开发程序包整理
-
创建目录,例如:
breakpad-windows-x64-msvc,然后创建子目录,例如:

-
把生成的
.lib静态库文件拷贝到目录lib下,如:

-
在
include目录下创建子目录breakpad,例如:

-
把源目录
breakpad\src下的相关目录拷贝到include目录下,例如:

其中client目录可以只拷贝windows平台,其他目录只拷贝.h头文件,例如:

(3)使用
-
需要在程序工程中添加头文件搜索路径

-
需要添加依赖库搜索路径和添加依赖库


(4)常见错误
- 若编译时出现错误:
则表示程序工程属性的C/C++|代码生成|运行库和依赖库的工程属性不一致,如:


只要把两者设置为一致即可编译通过。
(5)分析dmp文件
程序发生崩溃时,会自动生成.dmp文件,例如:

查看崩溃的具体代码处,可以使用Visual Studio打开该文件,选择文件|打开|文件,例如:


选择使用 仅限本机 进行调试。即可查看崩溃的堆栈信息,例如:

本文详细介绍了如何在Linux和Windows平台上编译安装Google Breakpad,包括下载源码、编译过程、环境配置、使用方法以及如何通过addr2line和相关脚本工具分析dmp文件,以获取程序崩溃的详细堆栈信息。
1万+

被折叠的 条评论
为什么被折叠?



