美文网首页
使用breakpad定位崩溃(windows&mac)

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

作者: 龙翱天际 | 来源:发表于2022-01-29 17:22 被阅读0次

    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 <iostream>
    #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 堆栈信息

    堆栈信息如下,可以定位出崩溃的函数,但是\color{red}{在mac下还暂时还不清楚如何定位到行号,有了解的欢迎和我联系红色字体}

    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<char, std::__1::char_traits<char>, std::__1::allocator<char> > 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<char, std::__1::char_traits<char>, std::__1::allocator<char> > 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<char, std::__1::char_traits<char>, std::__1::allocator<char> > 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<char, std::__1::char_traits<char>, std::__1::allocator<char> > 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<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > > > > 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<char, std::__1::char_traits<char>, std::__1::allocator<char> > 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)

          本文链接:https://www.haomeiwen.com/subject/brkfkrtx.html