macOS 10.15.7安装配置gdb

分享:  

问题简介

gdb作为一款符号级调试器,是广大开发人员排查问题的神兵利器,但是因为macOS darwin内核的一些调整,gdb出现了各种神奇的bug行为,如权限问题导致的无法启动调试、启动调试后调试会话卡死等等。

作者此前也曾经因为此类问题而苦恼,甚至不得不放弃了使用gdb调试器而使用其他办法来排查。最近在通过homebrew安装jupyterlab的时候发现gdb被升级了,就突然想起了之前被搁置的这个问题,测试后发现gdb还是不可正常使用。因此google一圈加不断测试,最终终于成功了。

这里总结下方便日后查阅,也供遇到类似问题的朋友参考,这确实是一个老大难的问题了。google能发现很多针对该问题的讨论,难兄难弟们,let’s go。

如何解决

  1. download the source code zip file from https://github.com/bminor/binutils-gdb.git, unzip the zipfile to ./binutils-gdb-master

  2. then try to build from master HEAD

    mkdir build
    cd build
    ../binutils-gdb-master/configure \
        --disable-unit-tests         \
        --disable-binutils           \
        --without-guile
    make -j8
    

    the built gdb binary is put here: ./gdb/gdb. Because I want to make package management simpler, so I don’t want to run make install to install the gdb and other files.

    ps: there’s no make uninstall target in the Makefile, if you want to remove all installed files, try this:

    make install DESTDIR=/tmp/gccinst
    find /tmp/gccinst | sed -e s,/tmp/gccinst,, | \
    (while read F; do rm "$F"; done)
    
  3. I then run brew install gdb to install the homebrew latest version, then I replace the gdb binary by:

    cp ./gdb/gdb /usr/local/Cellar/gdb/11.2/bin/gdb -f
    
  4. Then codesign mentioned above, OK, I put it here for convenience: write a gdb-entitlement.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
    "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
        <key>com.apple.security.cs.allow-jit</key>
        <true/>
        <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
        <true/>
        <key>com.apple.security.cs.allow-dyld-environment-variables</key>
        <true/>
        <key>com.apple.security.cs.disable-library-validation</key>
        <true/>
        <key>com.apple.security.cs.disable-executable-page-protection</key>
        <true/>
        <key>com.apple.security.cs.debugger</key>
        <true/>
        <key>com.apple.security.get-task-allow</key>
        <true/>
    </dict>
    </plist>
    

    then run following command to codesign:

    sudo codesign --entitlements gdb-entitlement.xml -fs gdb-cert $(which gdb)
    

    If you haven’t created gdb-cert before, run following command to create:

    # download the script, or create one with the content in Appendix
    https://github.com/conda-forge/gdb-feedstock/blob/main/recipe/macos-codesign/macos-setup-codesign.sh
    
    # replace the certificate name
    sed -i 's/gdb-codesign/gdb-cert/g' macos-setup-codesign.sh
    
    # run the script to create the certificate and trust it
    ./macos-setup-codesign.sh
    
    # check the certificate is create or not
    security find-certificate -p -c gdb-cert | openssl x509 -checkend 0
    or
    security find-certificate -p -c gdb-cert |openssl x509 -noout -text\
    
  5. then you can start your debugging, it works.

小节

本文总结了解决macOS平台上gdb无法正常调试的问题,这个办法只是解决了我和部分开发人员遇到的问题,但是并没有从根本上修复问题,不排除在您的环境下依然存在问题,请自己尝试是否有效,不行就继续寻找其他解决方案。

附录

  1. macos-setup-codesign.sh

    #!/bin/bash
    
    # This script is copied from https://github.com/llvm/llvm-project/blob/master/lldb/scripts/macos-setup-codesign.sh
    
    CERT="gdb_codesign"
    
    function error() {
        echo error: "$@" 1>&2
        exit 1
    }
    
    function cleanup {
        # Remove generated files
        rm -f "$TMPDIR/$CERT.tmpl" "$TMPDIR/$CERT.cer" "$TMPDIR/$CERT.key" > /dev/null 2>&1
    }
    
    trap cleanup EXIT
    
    # Check if the certificate is already present in the system keychain
    security find-certificate -Z -p -c "$CERT" /Library/Keychains/System.keychain > /dev/null 2>&1
    if [ $? -eq 0 ]; then
        echo Certificate has already been generated and installed
        exit 0
    fi
    
    # Create the certificate template
    cat <<EOF >$TMPDIR/$CERT.tmpl
    [ req ]
    default_bits       = 2048        # RSA key size
    encrypt_key        = no          # Protect private key
    default_md         = sha512      # MD to use
    prompt             = no          # Prompt for DN
    distinguished_name = codesign_dn # DN template
    [ codesign_dn ]
    commonName         = "$CERT"
    [ codesign_reqext ]
    keyUsage           = critical,digitalSignature
    extendedKeyUsage   = critical,codeSigning
    EOF
    
    echo Generating and installing gdb_codesign certificate
    
    # Generate a new certificate
    openssl req -new -newkey rsa:2048 -x509 -days 3650 -nodes -config "$TMPDIR/$CERT.tmpl" -extensions codesign_reqext -batch -out "$TMPDIR/$CERT.cer" -keyout "$TMPDIR/$CERT.key" > /dev/null 2>&1
    [ $? -eq 0 ] || error Something went wrong when generating the certificate
    
    # Install the certificate in the system keychain
    sudo security add-trusted-cert -d -r trustRoot -p codeSign -k /Library/Keychains/System.keychain "$TMPDIR/$CERT.cer" > /dev/null 2>&1
    [ $? -eq 0 ] || error Something went wrong when installing the certificate
    
    # Install the key for the certificate in the system keychain
    sudo security import "$TMPDIR/$CERT.key" -A -k /Library/Keychains/System.keychain > /dev/null 2>&1
    [ $? -eq 0 ] || error Something went wrong when installing the key
    
    # Kill task_for_pid access control daemon
    sudo pkill -f /usr/libexec/taskgated > /dev/null 2>&1
    
    # Exit indicating the certificate is now generated and installed
    exit 0