Android Toolchain编译与GDB调试

在进行linux主机上进行arm跨平台进行pure c++开发时,可能混有Neon intrinsic或者ARM assembly代码,此时进行代码编译和调试,可以使用standalone toolchain进行编译,使用gdb+gdbserver进行调试。

首先需要在NDK website上下载一个NDK工具包并解压,本人使用的是r14b版本,链接:https://dl.google.com/android/repository/android-ndk-r14b-linux-x86_64.zip

  • Standalone Toolchain的编译

    1
    2
    3
    cd android-ndk-r14b/build/tools/
    ./make-standalone-toolchain.sh --platform=android-21 --install-dir=./android-aarch64 --arch=arm64
    ./make-standalone-toolchain.sh --platform=android-21 --install-dir=./android-armv7 --arch=arm

    通过以上命令,会生成android-aarch64,android-armv7两个目录,可以将生成的standalone toolchain拷贝至固定目录

    1
    2
    sudo cp -r android-ndk-r14b/build/tools/android-aarch64 /opt
    sudo cp -r android-ndk-r14b/build/tools/android-armv7 /opt

    以上完成standalone toolchain生成

  • Linux主机编译arm跨平台pure c++程序

    1. 在Linux主机上准备main.cpp源代码文件

    1
    2
    3
    4
    5
    6
    #include <iostream>

    int main() {
    std::cout << "hello world" << std::endl;
    return 0;
    }

    1. 编写CMakeLists.txt文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    cmake_minimum_required(VERSION 3.17)

    project(ARM)

    enable_language(ASM)

    set(CMAKE_CXX_STANDARD 11)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
    add_definitions(-w)
    SET(CMAKE_BUILD_TYPE "Debug")
    SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g2 -ggdb")
    SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")

    set(TARGET_CPU aarch64)

    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static -fPIE -flax-vector-conversions")
    if(TARGET_CPU STREQUAL "aarch64")
    include_directories(/opt/android-ndk-r14b/android-aarch64/lib64/clang/7.0.2/include)
    else()
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfloat-abi=softfp -mfpu=neon")
    include_directories(/opt/android-ndk-r14b/android-armv7/lib64/clang/7.0.2/include)
    endif()

    set(SOURCES
    main.cpp
    # main.s
    )

    add_executable(main ${SOURCES})

    1. 编译ARM平台可执行文件

    1
    2
    3
    4
    CXX_COMPILER=/opt/android-ndk-r14b/android-aarch64/bin/aarch64-linux-android-g++
    CC_COMPILER=/opt/android-ndk-r14b/android-aarch64/bin/aarch64-linux-android-gcc
    cd cmake-build-debug
    cmake .. -DCMAKE_C_COMPILER=$CC_COMPILER -DCMAKE_CXX_COMPILER=$CXX_COMPILER

    1. ARM平台程序的执行

    1
    2
    adb push main /data/local/tmp
    adb shell ./data/local/tmp/main

  • GDB+GDBServer调试

    1. 准备GDBServer

    测试手机一般出厂不会自带gdbserver,可以将NDK工具包中对应平台gdbserver推入手机

    1
    adb push android-ndk-r14b/prebuilt/android-arm64/gdbserver/gdbserver /data/local/tmp

    1. 启动GDBServer

    1
    2
    3
    4
    5
    6
    7
    8
    9
    adb shell # 进入手机shell命令行
    cd /data/local/tmp
    ./gdbserver tcp:9090 main

    # 正常输出如下:
    Process main created; pid = 7201
    gdbserver: Unable to determine the number of hardware watchpoints available.
    gdbserver: Unable to determine the number of hardware breakpoints available.
    Listening on port 9090

    1. 在主机平台启动gdb调试程序

    1
    2
    3
    4
    5
    6
    cd android-ndk-r14b/prebuilt/linux-x86_64/bin # 进入ndk gdb程序目录
    adb forward tcp:9090 tcp:9090 # 端口转发
    ./gdb # 进入gdb程序
    target remote localhost:9090 # 开始获取信息并开始调试
    b main # 设置断点
    # 后续与普通GDB调试相同

    1
    2
    3
    4
    n  # 下一步,不进入函数内部
    s # 下一步,进入函数内部
    l # 代码列表
    info r # 查看寄存器