本机崩溃调用堆栈中的地址和偏移量到底是什么?

问题描述

每当我的android应用程序本机代码崩溃时,我都会使用NDK提供的addr2line工具将地址解析为源代码中的确切代码行。这些天来我一直在忽略调用堆栈中提供的其他信息,即偏移量。崩溃堆栈示例

08-16 07:44:47.328  1349  1349 F DEBUG   :     #00 pc 0000000000e52516  /data/data/com.syam.test/files/data/applibs/libnative.so (offset 0x1702000)

08-16 07:44:47.328  1349  1349 F DEBUG   :     #01 pc 0000000000e5242b  /data/data/com.syam.test/files/data/applibs/libnative.so (offset 0x1702000)

08-16 07:44:47.328  1349  1349 F DEBUG   :     #02 pc 0000000000e5226d  /data/data/com.syam.test/files/data/applibs/libnative.so (offset 0x1702000)

在考虑这些偏移量的同时,我也了解到我也不知道这些地址在物理上对应什么。

有人可以启发我了解崩溃堆栈的这两个方面,即地址和偏移量。这些确切对应什么,我该如何更好地利用它们。

解决方法

偏移量只是该模块(共享库)加载过程中的起始地址。因此,与流程本身相关的实际地址为offset + address

这是OS可以仅根据当时程序寄存器中的地址来识别崩溃的模块的方式。请注意,至少这还有另一层,因为进程本身在全局地址空间中具有其自身的偏移量,并且实际上可以由OS进行移动。但是我离题了。

由于库本身可以加载到进程地址空间内的任何位置,因此除非开发人员也知道偏移量,否则它对开发人员没有用。幸运的是,您可以减去偏移量并返回到在编译时确定的库特定地址。 addr2line就是这样的。

换句话说,偏移量可以更改,但地址是固定的。

所有这些的要点是,您无需编译包含任何调试符号的二进制文件(因此其他人无法轻易地发现您的程序如何工作)。但是,如果有人报告崩溃,并且您至少具有进程地址和库偏移量,则可以使用私有调试符号确定发生错误的位置。

因此,如果您有libnative.so的符号和源代码,这些符号和源代码用于在程序崩溃时构建正在运行的版本,那么您可以使用完全相同的技术来了解发生这种情况的位置。如果幸运的话,该库可能包含一些基本的调试信息,例如函数名。