使用breakpad定位崩溃(windows&mac)

1 使用breakpad

1.1 安装breakpad

1.1.1 通过vcpkg安装breakpad

注:安装vcpkg时,如果报以下错误可能是电脑不能访问到vcpkg,可以多试几次:
curl: (35) LibreSSL SSL_connect: SSL_ERROR_SYSCALL in connection to github.com:443

1.1.1.1 windows

git clone https://github.com/microsoft/vcpkg
cd vcpkg
bootstrap-vcpkg.bat
vcpkg install breakpad:x64-windows

1.1.1.2 mac

git clone https://github.com/microsoft/vcpkg
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg install breakpad

1.2 通过cmake加载breakpad

1.2.1 cmakelists.txt

cmake_minimum_required(VERSION 3.20)

IF (WIN32)
    MESSAGE(STATUS "Now is windows")
    set(VCPKG_ROOT F:/git/vcpkg)
ELSEIF (APPLE)
    MESSAGE(STATUS "Now is Apple system.")
    set(VCPKG_ROOT /Users/hualongzhang/work/vcpkg)
ENDIF ()
set(VCPKG_CMAKE ${VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake)
set(CMAKE_TOOLCHAIN_FILE ${VCPKG_CMAKE})

project(testbreakpad)

set(CMAKE_CXX_STANDARD 17)

find_package(unofficial-breakpad CONFIG REQUIRED)
link_libraries(unofficial::breakpad::libbreakpad unofficial::breakpad::libbreakpad_client)

add_executable(untitled1 main.cpp)

1.3 代码中使用breakpad

#include 
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
#include "client/windows/handler/exception_handler.h"
#elif defined(__APPLE__) && (defined(__GNUC__) || defined(__xlC__) || defined(__xlc__))
#include "client/mac/handler/exception_handler.h"
#endif


#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)

static bool minidumpCallback(const wchar_t* dump_path, const wchar_t* id,
    void* context, EXCEPTION_POINTERS* exinfo,
    MDRawAssertionInfo* assertion,
    bool succeeded)
{
    if (succeeded) {
        std::wcout << "Mini Dump file: " << id << ".dump Path: " << dump_path << std::endl;
    }
    return succeeded;
}

static google_breakpad::ExceptionHandler eh(
    L".", NULL, minidumpCallback, NULL,
    google_breakpad::ExceptionHandler::HANDLER_ALL);

#else
static bool minidumpCallback(const char* dump_path, const char* id, void* context, bool succeeded)
{
    if (succeeded) {
        std::cout << "Mini Dump file: " << id << ".dump Path: " << dump_path << std::endl;
    }
    return succeeded;
}

static google_breakpad::ExceptionHandler eh(".", NULL, minidumpCallback, NULL, true, NULL);

#endif


void testCrash()
{
    int* ptr = NULL;
    *ptr = 0;
}

int main() {
    testCrash();
    return 0;
}

1.4 build

1.4.1 cmake编译

mkdir build
cd build
cmake ..
cmake --build .

1.4.2 开发工具加载vcpkg编译

参见vcpkg总览

1.5 run

运行代码崩溃,输出:
Mini Dump file: 449BD1E3-1ECA-4968-A25B-DD6D8328D849.dump Path: .

2 排查breakpad崩溃

2.1 windows

参见:Dump调试

2.2 mac

2.2.1 编译dump_syms

打开dump_syms目录:
/Users/hualongzhang/work/vcpkg/buildtrees/breakpad/src/0b5fa7f760-4cf530ff2b.clean/src/tools/mac/dump_syms

用xcode打开dump_syms工程,我本机路径如下:
dump_syms.xcodeproj

配置release:
Product > Scheme > Edit Scheme... > Run > Info > Build Configuration,选择Release

编译,并找到生成的dump_syms,我本机路径如下:
/Users/hualongzhang/Library/Developer/Xcode/DerivedData/dump_syms-fptymbnkqoskmeasatvnedmomwzg/Build/Products/Release

拷贝dump_symsminidump_stackwalk同级目录(方便操作),我本机路径如下:
/Users/hualongzhang/work/vcpkg/buildtrees/breakpad/src/0b5fa7f760-4cf530ff2b.clean/src/processor

2.2.2 分析dump

2.2.2.1 进入processor目录

先cd到processor,即minidump_stackwalk目录:
cd /Users/hualongzhang/work/vcpkg/buildtrees/breakpad/src/0b5fa7f760-4cf530ff2b.clean/src/processor

要想查看完整的崩溃堆栈,app和dylib都得生成符号文件,现以cppdetector来示例

2.2.2.2 生成app sym

以app名称生成sym文件:
./dump_syms /Users/hualongzhang/work/cppdetector/bin/cppdetector > cppdetector.sym

查看sym的信息:

head -n1 cppdetector.sym

输出的sym信息:MODULE mac x86_64 07E8CDAF8CCA3B22849636E1AF94D4D70 cppdetector

根据二进制文件名称:cppdetector和上一步输出的:07E8CDAF8CCA3B22849636E1AF94D4D70创建目录:

mkdir -p ./symbols/cppdetector/07E8CDAF8CCA3B22849636E1AF94D4D70

将cppdetector.sym移动到新创建的目录中
mv cppdetector.sym ./symbols/cppdetector/07E8CDAF8CCA3B22849636E1AF94D4D70

2.2.2.3 生成dylib sym

./dump_syms /Users/hualongzhang/work/cppdetector/bin/libdetector_core.dylib > libdetector_core.dylib.sym
head -n1 libdetector_core.dylib.sym
mkdir -p ./symbols/libdetector_core.dylib/0E1F07DAE411385F9C409F87CDD8C9510
mv libdetector_core.dylib.sym ./symbols/libdetector_core.dylib/0E1F07DAE411385F9C409F87CDD8C9510

2.2.2.4 输出堆栈

通过minidump_stackwalk命令生成堆栈
./minidump_stackwalk /Users/hualongzhang/work/cppdetector/bin/A61B41CB-A7FE-46DD-881D-774AC907AC5C.dmp ./symbols

2.2.2.5 终端结果如下:

➜  processor git:(master) ✗ ./dump_syms /Users/hualongzhang/work/cppdetector/bin/cppdetector > cppdetector.sym
➜  processor git:(master) ✗ head -n1 cppdetector.sym
MODULE mac x86_64 07E8CDAF8CCA3B22849636E1AF94D4D70 cppdetector
➜  processor git:(master) ✗ mkdir -p ./symbols/cppdetector/07E8CDAF8CCA3B22849636E1AF94D4D70
➜  processor git:(master) ✗ mv cppdetector.sym ./symbols/cppdetector/07E8CDAF8CCA3B22849636E1AF94D4D70
➜  processor git:(master) ✗ ./dump_syms /Users/hualongzhang/work/cppdetector/bin/libdetector_core.dylib > libdetector_core.dylib.sym
➜  processor git:(master) ✗ head -n1 libdetector_core.dylib.sym
MODULE mac x86_64 0E1F07DAE411385F9C409F87CDD8C9510 libdetector_core.dylib
➜  processor git:(master) ✗ mkdir -p ./symbols/libdetector_core.dylib/0E1F07DAE411385F9C409F87CDD8C9510
➜  processor git:(master) ✗ mv libdetector_core.dylib.sym ./symbols/libdetector_core.dylib/0E1F07DAE411385F9C409F87CDD8C9510
➜  processor git:(master) ✗ ./minidump_stackwalk /Users/hualongzhang/work/cppdetector/bin/6419528F-7020-4DC1-8FB5-6B9C58395FEE.dmp ./symbols > dump.log

2.2.2.6 自动化脚本

上述示例过程如果全部手动执行及其繁琐,特别是拥有多个库的大型项目更是如此,有必要通过sh脚本将其自动化,将如下自动化脚本保存成:dumpanalyzer.sh

#!/bin/bash
 
if [ $# != 3 ] ; then 
echo "USAGE: $0 TARGET_DIR DMP_NAME OUTPUT_NAME" 
echo " e.g.: $0 appdir 4391167F-D2E0-4CD1-973D-BED11A9A7FE9.dmp callstack.log" 
exit 1; 
fi 
 
#获取输入参数
target_dir=$1
dmp_file_name=$2
output_file_name=$3

target_file_name=${target_dir##*/}
echo $target_file_name
 
getSymbol() {
    echo "@getSymbol: start get symbol: $target_dir/$target_file_name"
    ./dump\_syms $target_dir/$target_file_name > $target_file_name'.sym'
}
 
createSymDir() {
    echo "@getStackTrace: start get StackTrace"
    sym_file_name=$target_file_name'.sym'
 
    #获取符号文件中的第一行
    line1=`head -n1 $sym_file_name`
 
    #从第一行字符串中获取版本号
    OIFS=$IFS; IFS=" "; set -- $line1; aa=$1;bb=$2;cc=$3;dd=$4; IFS=$OIFS 
 
    version_number=$dd
 
    #创建特定的目录结构,并将符号文件移进去
    mkdir -p ./symbols/$target_file_name/$version_number
    mv $sym_file_name ./symbols/$target_file_name/$version_number
}

redirectStackToFile() {
    #将堆栈跟踪信息重定向到文件中
    minidump_stackwalk $dmp_file_name ./symbols > $output_file_name
}

getStackTrace() {
    for target_file_name in `ls $1`
    do
        echo "path: $target_file_name"
        getSymbol $target_file_name 
        createSymDir $target_file_name
    done

    redirectStackToFile
}
main() {
    echo $target_path
    getStackTrace $target_dir
}
 
#运行main
main

调用方式:

./dumpanalyzer.sh /Users/hualongzhang/work/cppdetector/bin /Users/hualongzhang/work/cppdetector/bin/4391167F-D2E0-4CD1-973D-BED11A9A7FE9.dmp callstack.log

第一个参数是app目录,第二个参数是dump文件路径,第三方参数是调用堆栈文件名

2.2.2.7 堆栈信息

堆栈信息如下,可以定位出崩溃的函数,但是:

Operating system: Mac OS X
                  11.1.0 20C69
CPU: amd64
     family 6 model 158 stepping 10
     12 CPUs

GPU: UNKNOWN

Crash reason:  EXC_BAD_ACCESS / KERN_INVALID_ADDRESS
Crash address: 0x0
Process uptime: 0 seconds

Thread 0 (crashed)
 0  libdetector_core.dylib!CPPPath::CPPPath(std::__1::basic_string, std::__1::allocator > const&) + 0x55
    rax = 0x0000000000000000   rdx = 0x00007ffeea448ee8
    rcx = 0x00007ffeea4491c0   rbx = 0x0000000000000000
    rsi = 0x00007ffeea448ef0   rdi = 0x00007ffeea4491d8
    rbp = 0x00007ffeea449160   rsp = 0x00007ffeea448f70
     r8 = 0x0000000000000005    r9 = 0x0000000000000005
    r10 = 0x00007fcc64500000   r11 = 0x0000000000000000
    r12 = 0x0000000000000000   r13 = 0x0000000000000000
    r14 = 0x0000000000000000   r15 = 0x0000000000000000
    rip = 0x00000001058ad4f5
    Found by: given as instruction pointer in context
 1  libdetector_core.dylib!CPPPath::CPPPath(std::__1::basic_string, std::__1::allocator > const&) + 0x1d
    rbp = 0x00007ffeea449180   rsp = 0x00007ffeea449170
    rip = 0x00000001058ade7d
    Found by: previous frame's frame pointer
 2  libdetector_core.dylib!DetectorContext::makePathPairFromDir(std::__1::basic_string, std::__1::allocator > const&) + 0x41
    rbp = 0x00007ffeea449210   rsp = 0x00007ffeea449190
    rip = 0x00000001059378b1
    Found by: previous frame's frame pointer
 3  libdetector_core.dylib!DetectorContext::detect(std::__1::basic_string, std::__1::allocator > const&) + 0xa9
    rbp = 0x00007ffeea449300   rsp = 0x00007ffeea449220
    rip = 0x0000000105937199
    Found by: previous frame's frame pointer
 4  libdetector_core.dylib!DetectorContext::detectWithRuleNames(std::__1::basic_string, std::__1::allocator > const&, std::__1::map, std::__1::allocator >, std::__1::vector, std::__1::allocator >, std::__1::allocator, std::__1::allocator > > >, std::__1::less, std::__1::allocator > >, std::__1::allocator, std::__1::allocator > const, std::__1::vector, std::__1::allocator >, std::__1::allocator, std::__1::allocator > > > > > > const&) + 0x1e0
    rbp = 0x00007ffeea449490   rsp = 0x00007ffeea449310
    rip = 0x00000001059367d0
    Found by: previous frame's frame pointer
 5  libdetector_core.dylib!DetectorContext::detectAll(std::__1::basic_string, std::__1::allocator > const&) + 0x64
    rbp = 0x00007ffeea449510   rsp = 0x00007ffeea4494a0
    rip = 0x00000001059365b4
    Found by: previous frame's frame pointer
 6  cppdetector!main + 0xcdf
    rbp = 0x00007ffeea449a00   rsp = 0x00007ffeea449520
    rip = 0x00000001057bc15f
    Found by: previous frame's frame pointer
 7  libdyld.dylib + 0x15621
    rbp = 0x00007ffeea449a10   rsp = 0x00007ffeea449a10
    rip = 0x00007fff20379621
    Found by: previous frame's frame pointer

Loaded modules:
0x1057b6000 - 0x1057e9fff  cppdetector  ???  (main)
0x105860000 - 0x105bbffff  libdetector_core.dylib  ???
0x7fff20094000 - 0x7fff20095fff  libsystem_blocks.dylib  ???
0x7fff20096000 - 0x7fff200cbfff  libxpc.dylib  ???
0x7fff200cc000 - 0x7fff200e3fff  libsystem_trace.dylib  ???
0x7fff200e4000 - 0x7fff20182fff  libcorecrypto.dylib  ???
0x7fff20183000 - 0x7fff201affff  libsystem_malloc.dylib  ???
0x7fff201b0000 - 0x7fff201f4fff  libdispatch.dylib  ???
0x7fff201f5000 - 0x7fff2022dfff  libobjc.A.dylib  ???
0x7fff2022e000 - 0x7fff20230fff  libsystem_featureflags.dylib  ???
0x7fff20231000 - 0x7fff202b9fff  libsystem_c.dylib  ???
0x7fff202ba000 - 0x7fff2030ffff  libc++.1.dylib  ???
0x7fff20310000 - 0x7fff20328fff  libc++abi.dylib  ???
0x7fff20329000 - 0x7fff20357fff  libsystem_kernel.dylib  ???
0x7fff20358000 - 0x7fff20363fff  libsystem_pthread.dylib  ???
0x7fff20364000 - 0x7fff2039efff  libdyld.dylib  ???  (WARNING: No symbols, libdyld.dylib, 000000000000000000000000000000000)
0x7fff2039f000 - 0x7fff203a8fff  libsystem_platform.dylib  ???
0x7fff203a9000 - 0x7fff203d4fff  libsystem_info.dylib  ???
0x7fff203d5000 - 0x7fff20870fff  CoreFoundation  ???
0x7fff2255f000 - 0x7fff227c0fff  libicucore.A.dylib  ???
0x7fff227c1000 - 0x7fff227cafff  libsystem_darwin.dylib  ???
0x7fff22bdb000 - 0x7fff22be6fff  libsystem_notify.dylib  ???
0x7fff24b36000 - 0x7fff24b44fff  libsystem_networkextension.dylib  ???
0x7fff24ba2000 - 0x7fff24bb8fff  libsystem_asl.dylib  ???
0x7fff262a0000 - 0x7fff262a7fff  libsystem_symptoms.dylib  ???
0x7fff282f2000 - 0x7fff28302fff  libsystem_containermanager.dylib  ???
0x7fff28ffe000 - 0x7fff29001fff  libsystem_configuration.dylib  ???
0x7fff29002000 - 0x7fff29006fff  libsystem_sandbox.dylib  ???
0x7fff29d09000 - 0x7fff29d0bfff  libquarantine.dylib  ???
0x7fff2a28a000 - 0x7fff2a28efff  libsystem_coreservices.dylib  ???
0x7fff2a4a5000 - 0x7fff2a4ecfff  libsystem_m.dylib  ???
0x7fff2a4ee000 - 0x7fff2a4f3fff  libmacho.dylib  ???
0x7fff2a510000 - 0x7fff2a51bfff  libcommonCrypto.dylib  ???
0x7fff2a51c000 - 0x7fff2a526fff  libunwind.dylib  ???
0x7fff2a527000 - 0x7fff2a52efff  liboah.dylib  ???
0x7fff2a52f000 - 0x7fff2a539fff  libcopyfile.dylib  ???
0x7fff2a53a000 - 0x7fff2a541fff  libcompiler_rt.dylib  ???
0x7fff2a542000 - 0x7fff2a544fff  libsystem_collections.dylib  ???
0x7fff2a545000 - 0x7fff2a547fff  libsystem_secinit.dylib  ???
0x7fff2a548000 - 0x7fff2a54afff  libremovefile.dylib  ???
0x7fff2a54b000 - 0x7fff2a54bfff  libkeymgr.dylib  ???
0x7fff2a54c000 - 0x7fff2a553fff  libsystem_dnssd.dylib  ???
0x7fff2a554000 - 0x7fff2a559fff  libcache.dylib  ???
0x7fff2a55a000 - 0x7fff2a55bfff  libSystem.B.dylib  ???
0x7fff2a55c000 - 0x7fff2a55ffff  libfakelink.dylib  ???
0x7fff2a560000 - 0x7fff2a560fff  SoftLinking  ???
0x7fff2d98d000 - 0x7fff2d98dfff  liblaunch.dylib  ???
0x7fff2fe3a000 - 0x7fff2fe3afff  libsystem_product_info_filter.dylib  ???
0x7fff5dc88000 - 0x7fff5dc97fff  libSimplifiedChineseConverter.dylib  ???

备注:
找到模块的符号文件,输出如下:

0x1057b6000 - 0x1057e9fff  cppdetector  ???  (main)
0x105860000 - 0x105bbffff  libdetector_core.dylib  ???

没有找到模块的符号文件会输出:
libdyld.dylib ??? (WARNING: No symbols, libdyld.dylib, 000000000000000000000000000000000)

你可能感兴趣的:(使用breakpad定位崩溃(windows&mac))