问题描述
每当我的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
的符号和源代码,这些符号和源代码用于在程序崩溃时构建正在运行的版本,那么您可以使用完全相同的技术来了解发生这种情况的位置。如果幸运的话,该库可能包含一些基本的调试信息,例如函数名。