Android 原生程序使用gdb, addr2line, readelf调试

Platform: RK3368

OS: Android 6.0

Kernel: 3.10.0


一 gdb

GDB(GNU Debugger)是GNU项目调试器,是一种强大的程序调试工具,可以用于调试C、C++、Fortran等多种编程语言编写的程序。它允许程序员在程序运行时监视程序的内部状态和程序的控制流程。

1. 原生程序添加调试符号

在原生程序的Android.mk中添加以下内容:

# 添加调试符号  
LOCAL_CFLAGS += -g -O0  
 
# 不剥离符号  
LOCAL_STRIP_MODULE := false  

2. 主机上adb push 编译好的原生程序到设备

$ adb push out/target/product/$YOUR_DEVICE/system/bin/$YOUR_NATIVE_PROCESS

3. 设备上使用gdbserver运行原生程序

$ gdbserver :9090 /system/bin/$YOUR_NATIVE_PROCESS

4. 主机上设置adb端口转发

表示将本地9090端口转发到设备9090端口:

$ adb forward tcp:9090 tcp:9090

5. 主机上运行gdb调试

$ gdb out/target/product/$YOUR_DEVICE/system/bin/$YOUR_NATIVE_PROCESS
GNU gdb (Ubuntu 15.0.50.20240403-0ubuntu1) 15.0.50.20240403-git
Copyright (C) 2024 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from out/target/product/***/system/bin/****...
(gdb) target remote :9090
Remote debugging using :9090
warning: while parsing target description (at line 1): Target description specified unknown architecture "arm"
warning: Could not load XML target description; ignoring
Reading /system/bin/linker64 from remote target...
warning: File transfers from remote targets can be slow. Use "set sysroot" to access files locally instead.
warning: Unable to find dynamic linker breakpoint function.
GDB will be unable to debug shared library initializers
and track explicitly loaded dynamic code.
0x00000000 in ?? ()

二 addr2line

addr2line用于将程序的地址(例如,崩溃报告中提供的地址)转换为文件名和行号。这对于调试和定位程序中的错误非常有用,尤其是在处理崩溃或异常行为时。

一般在Android源码中source build/envsetup.sh和lunch以后, 就会有很多工具可以直接使用了, 例如:

$ arm-linux-androideabi-addr2line -f -e $YOUR_NATIVE_PROCESS

如果是64位程序需要使用aarch64下面的工具链, 否则会出现"File format not recognized"

$ /prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin/aarch64-linux-android-addr2line -e $YOUR_NATIVE_PROCESS

三 readelf

readelf是一个在Unix和类Unix系统上用于查看ELF(Executable and Linkable Format)文件信息的命令行工具。readelf能够显示ELF文件的各种信息,包括但不限于:

  • 文件头:描述ELF文件的总体信息,包括系统相关、类型相关、加载相关和链接相关等。
  • 程序头:包含程序执行时所需的各种段(segment)的信息。
  • 节头:描述ELF文件中各个节(section)的信息,节是ELF文件的基本组成部分。
  • 符号表:包含程序中定义的符号和引用的外部符号的信息。
    此外,readelf还支持查看动态节、调试信息、版本信息等。

例如查看符号表信息:

$ arm-linux-androideabi-readelf -s $YOUR_NATIVE_PROCESS
### 使用 GDBAddr2line 进行调试和地址转换 #### 启用调试符号编译 为了使 `GDB` 或者 `addr2line` 正常工作并提供有意义的信息,在编译源文件时应当加入 `-g` 选项来包含调试信息。这一步骤对于后续能够成功解析崩溃堆栈以及回溯错误位置至关重要[^2]。 #### 加载 Core 文件进行调试 当应用程序发生异常终止并生成核心转储(`core dump`)之后,可以通过启动带有目标二进制路径及其对应的 core 文件作为参数的方式开启 GDB 实例来进行事后分析: ```bash arm-linux-gnueabihf-gdb out_debug core ``` 这条命令会加载指定的目标程序 (`out_debug`) 及其产生的 core 文件进入 GDB 环境中以便进一步调查问题所在[^1]。 #### 利用 Addr2line 定位代码位置 Addr2line 是一个用来把机器码中的内存地址映射到源代码行列号的小型实用工具。假设有一个特定的函数调用失败发生在某个已知地址处,则可通过如下方式查询该地址对应于哪个源文件哪一行: ```bash $ addr2line -e sigsegv 0x6cc ``` 然而需要注意的是只有当被检查的对象文件确实包含了完整的调试元数据(-g),上述操作才会返回确切的结果;反之则可能仅能得到不确定性的输出(??:0)。 #### 处理共享库内的地址偏移量计算 针对动态链接库(如 `.so` 文件)里的绝对地址,由于这些库在不同进程中可能会有不同的基址装载情况,因此需要先确定所关心的具体模块起始地址再做相应调整。例如给定一个位于 `libiFlyNli.so` 中的指令指针值 `0x00007ffff71f1004` ,减去此 SO 的实际加载起点即可获得相对于该库入口的有效偏移量[^4]: ```python relative_address = absolute_address - base_address_of_library # e.g., relative_address = 0x00007ffff71f1004 - 0x00007ffff6e76470 ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值