3

如何在 Android 中为原生库加载事件设置断点?

我假设在dlopen()上设置断点是一个很好的起点,但是,即使加载了libc.so/system/bin/linker的符号,gdb 也找不到 dlopen 函数。

看起来 Android 正在使用一些特殊格式的 .so 文件,因为 nm 工具也不报告dlopen()位置。

是否有任何解决该问题的方法或特定于 Android 的 .so 转储工具可以帮助按名称定位函数地址,以便我可以手动设置断点?

编辑:

我要做的是设置一个断点,该断点应该在加载任何本机库时触发,即当任何代码(甚至在我的库中)调用dlopen()函数时。

问题是 Android GDB 不支持挂起的断点。我的场景是这样的:

  1. 我启动我的应用程序并停止它。
  2. 该应用程序已恢复并加载我的本机库。
  3. 我的函数是从库中调用的(仅在加载应用程序时调用一次)。

如果我在 #1 之后设置断点,它将无法工作,因为该库仍然不存在并且 android-gdb 将无法重新绑定它。如果我让程序运行,然后再次停止并设置断点,我已经过了#3,所以断点将无用。

我试图通过在#1 处为dlopen()设置断点来解决它,然后当它命中并加载库(即#2)时,我将设置实际的断点。

使用普通的 ARM nm 和 objdump 没有任何帮助。NM'ing libc.so 表明dlopen()未定义:

00016188 T dlmemalign
         U dlopen
00016338 T dlpvalloc

/ system/bin/linker二进制文件物理上包含dlopen文本(.rodata部分的第一个字节),但是nm显示以下文本:

arm-linux-androideabi-nm.exe: linker: No symbols

用 objdump 反汇编它不会给出符号名称。

谷歌搜索 android 源发现了这个源文件:

http://dexandroid.googlecode.com/svn/trunk/bionic/linker/dlfcn.c

看起来 dlopen() 确实在 /system/bin/linker 中定义,但它使用了一些非标准的符号解析机制(至少,基于第一条评论):

/* This file hijacks the symbols stubbed out in libdl.so. */

那么,回到问题上来,如何在dlopen()中设置断点,以便在加载库时设置实际断点?

4

1 回答 1

3

通常任何 arm objdump 都应该可以工作,但在您的 ndk 目录中会有一个。即使是非手臂 readelf 也可以工作。

我不确定您为什么希望在库中找到 dlopen() ,除非它明确使用它来打开另一个库 - 通常,人们会认为它会从 libdvm.so 中调用,无论如何我相信实现在libdl.so(拥有一个为 android 构建的 grep 版本是一件非常有用的事情 - 您可以在 lib 目录中找到字符串,但如果您想查找它们是导入还是导出,您可能需要 adb pull 和 objdump 的文件兴趣)。

如果您尝试对正在加载的库文件设置断点,则可以尝试实现其中一个静态初始化函数(C 级或加载时的 jni)并在此处设置断点。

编辑:

事实证明,用于 arm 的 objdump 不会通过用于从共享库导入的符号的 plt 来解码链接,尽管它适用于 x86 等其他一些平台。这使得很难理解去除了调试符号的二进制文件,正如您对设备上的系统库所期望的那样。我能够修补 binutils 源来为 arm 执行此操作。最终我希望在某个地方提交,但与此同时,修补版本的源代码可在https://github.com/cstratton/binutils-android-decodeplt获得

我将 objdump 二进制文件放在 prebuilt-linux-x86/ 目录中,尽管我不知道它的可移植性如何。

于 2012-06-24T23:55:34.593 回答