目录

Android平台使用lldb调试遇到的几个问题

lldb随机crash

Android V代码里预编译好的lldb经常会在执行取类成员变量地址,或执行一些cast操作的时候出现crash,有时候在crash栈里能看到一些ndk相关的逻辑,

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
source build/envsetup.sh
# 请根据实际项目选择实际要lunch的选项
lunch xxx

# 调试com.wwm.demo
lldbclient.py -n com.wwm.demo

(lldb) expr (art::mirror::String*)0x73de6320
LLDB diagnostics will be written to /tmp/diagnostics-9ef8bb
Please include the directory content when filing a bug report
PLEASE submit a bug report to https://github.com/android-ndk/ndk/issues and include the crash backtrace.
Stack dump:
0.      Program arguments: /home/wwm/aosp/prebuilts/clang/host/linux-x86/clang-r522817/bin/lldb --source /tmp/tmpnij9jjx0
 #0 0x0000559dd6cb4702 (/home/wwm/aosp/prebuilts/clang/host/linux-x86/clang-r522817/bin/lldb+0x82702)
 #1 0x0000559dd6cb36d0 (/home/wwm/aosp/prebuilts/clang/host/linux-x86/clang-r522817/bin/lldb+0x816d0)
 #2 0x0000559dd6cb4b82 (/home/wwm/aosp/prebuilts/clang/host/linux-x86/clang-r522817/bin/lldb+0x82b82)
 #3 0x00007fdeb2b46520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #4 0x00007fdeb5517ccf clang::CXXRecordDecl::addedMember(clang::Decl*) DeclCXX.cpp:0:0
 #5 0x00007fdeb5513fe9 clang::DeclContext::addDecl(clang::Decl*) DeclBase.cpp:0:0
 ...
 /home/wwm/aosp/prebuilts/clang/host/linux-x86/clang-r522817/bin/lldb.sh: line 6: 731181 Segmentation fault      (core dumped) "$CURDIR/lldb" "$@"

怀疑是Google修改的部分代码有问题,但没时间去调查具体原因,就想先使用llvm官方的lldb,但发现它又不支持lzma压缩算法,没法正确读取.gne_debuginfo段,那就没法调试Android odex文件里的汇编了;

最终不得不我们自己编译一个支持lzma压缩算法的lldb使用:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
# 下载最新的llvm整个项目代码
1.下载 https://github.com/llvm/llvm-project/archive/refs/tags/llvmorg-19.1.1.zip 
2. 解压llvm-project-llvmorg-19.1.0.zip
3. mv llvm-project-llvmorg-19.1.0 llvm-project

# 安装依赖
sudo apt install build-essential \
         libedit-dev libxml2-dev llvm-dev \
         doxygen liblzma-dev

# 准备
cd llvm-project
mkdir mybuild && cd mybuild
# 把最终的工具安装到mybuild/out下
mkdir out

# 编译clang和lldb
cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=$PWD/out -DLLVM_ENABLE_PROJECTS="clang;lldb" -DLLVM_ENABLE_LZMA=ON -DCMAKE_BUILD_TYPE=Release -DLLDB_TEST_COMPILER=/usr/bin/clang ../llvm

make -j32
# 待编译完成后,会在 mybuild/bin/目录下看到lldb,clang等可执行文件

把Android V源码里的prebuilts/clang/host/linux-x86/clang-r522817/bin/lldb.sh里的lldb路径换成我们编译好的lldb,然后再使用lldbclient.py就没再crash了

无法回溯出完整的调用栈

发现公司ROM的symbols文件中boot.oat等文件是在out/target/product/ssi/symbols/apex/art_boot_images/目录下,需把它们移动到out/target/product/ssi/symbols/apex/com.android.art/:

1
mv out/target/product/ssi/symbols/apex/art_boot_images/javalib out/target/product/ssi/symbols/apex/com.android.art/

然后重行执行lldbclient/gdbclient后应该就可以回溯出完整的调用栈了

加载App的so/odex里的symbols

需要把app的so/odex目录放到symbols目录下的对应位置

1
2
3
4
5
6
7
8
adb shell pm path com.wwm.demo
package:/data/app/~~cGEMvclUneLY3buiqk0CVA==/com.wwm.demo-nQ84CPYSeMSgWTm-mD7lTw==/base.apk

# 为了简单,把app的安装目录都pull出来,因为odex在/data/app/~~cGEMvclUneLY3buiqk0CVA==/com.wwm.demo-nQ84CPYSeMSgWTm-mD7lTw==/oat/arm64下
mkdir -p out/target/product/ssi/symbols/data/app
adb pull /data/app/~~cGEMvclUneLY3buiqk0CVA==/ out/target/product/ssi/symbols/data/app/
# 而so文件在/data/app/~~cGEMvclUneLY3buiqk0CVA==/com.wwm.demo-nQ84CPYSeMSgWTm-mD7lTw==/lib/arm64下
# 所以得把带有symbols的so文件再放到out/target/product/ssi/symbols/data/app/~~cGEMvclUneLY3buiqk0CVA==/com.wwm.demo-nQ84CPYSeMSgWTm-mD7lTw==/lib/arm64

查看一个lib的symbol文件是否被成功加载上了

以前用gdb的话,就很简单

1
(gdb) info sharedlibrary libc.so

lldb的话,没有等价于info sharedlibrary的命令,但可以随便找这个lib的一个函数,例如libc里的malloc

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
(lldb) image lookup -vn malloc
1 match found in /home/wwm/aosp/out/target/product/missi/symbols/apex/com.android.runtime/lib64/bionic/libc.so:
        Address: libc.so[0x00000000000476bc] (libc.so.PT_LOAD[1]..text + 5820)
        Summary: libc.so`::malloc(size_t) at malloc_common.cpp:136
         Module: file = "/home/wwm/aosp/out/target/product/missi/symbols/apex/com.android.runtime/lib64/bionic/libc.so", arch = "aarch64"
    CompileUnit: id = {0x00000004}, file = "bionic/libc/bionic/malloc_common.cpp", language = "c++14"
       Function: id = {0x00004b8e}, name = "::malloc(size_t)", range = [0x0000007720d486bc-0x0000007720d48740)
       FuncType: id = {0x00004b8e}, byte-size = 0, decl = malloc_common.cpp:136, compiler_type = "void *(size_t)"
         Blocks: id = {0x00004b8e}, range = [0x7720d486bc-0x7720d48740)
      LineEntry: [0x0000007720d486bc-0x0000007720d486cc): bionic/libc/bionic/malloc_common.cpp:136
         Symbol: id = {0x000027c4}, range = [0x0000007720d486bc-0x0000007720d48740), name="malloc"
       Variable: id = {0x00004b9d}, name = "bytes", type = "size_t", valid ranges = <block>, location = [0x00000000000476bc, 0x00000000000476d8) -> DW_OP_reg0 W0, decl = malloc_common.cpp:136

如果输出包含 CompileUnit: id = 则说明libc的symbol加载成功了