如何从Java核心转储获取自研JNI库的错误行号?
如何从Java核心转储中获取自研JNI库的错误行号?
问题背景
想要从Java核心转储(或hs_err日志)中获取自研JNI库的错误行号,以下是不同JVM参数下的hs_err日志片段(AMIn2_*为自研C函数名):
日志示例1
$ grep AMIn2 /tmp/hs_err_pid3688886.log J 11555 net.hep.ami.utility.n2edm.AMIreadN2DataJNI.AMIn2_GetRunNumbersJSON(Ljava/lang/String;I)Ljava/lang/String; (0 bytes) @ 0x00007f003d64e3fa [0x00007f003d64e3a0+0x000000000000005a]
日志示例2(添加了-XX:+UnlockDiagnosticVMOptions和-XX:+ShowHiddenFrames)
$ grep AMIn2 /tmp/hs_err_pid1598986.log j net.hep.ami.utility.n2edm.AMIreadN2DataJNI.AMIn2_GetSubsystemsJSON(Ljava/lang/String;II)Ljava/lang/String;+0 j net.hep.ami.utility.n2edm.AMIreadN2Data.AMIn2_GetSubsystemsJSON(Ljava/lang/String;II)Ljava/lang/String;+3 R13={method} {0x00007f20f8ba29f8} 'AMIn2_GetSubsystemsJSON' '(Ljava/lang/String;II)Ljava/lang/String;' in 'net/hep/ami/utility/n2edm/AMIreadN2DataJNI' stack at sp + 4 slots: 0x00007f21100a7fea: AMIn2_GetSubsystemsJSON+0x000000000000022d in /opt/AMI/externalLib/libAMIreadN2Data_swig.so at 0x00007f211009c000
尝试了以下addr2line命令但未得到有效结果:
$ addr2line -e lib*_swig.so -a 0x00007f20f8ba29f8 0x00007f20f8ba29f8 ??:0 $ addr2line -e lib*_swig.so -f -C 0x00007f20f8ba29f8 ?? ??:0
疑问:是否需要加减基地址?如何在核心转储中找到基地址?
解决方法
1. 错误原因:用错了地址
你传入addr2line的0x00007f20f8ba29f8是Java方法的内存地址,不是JNI库中C函数的实际执行地址,因此无法解析出行号。
2. 提取正确的C函数地址
从日志示例2的stack at sp + 4 slots行中,能获取关键信息:
- JNI库的加载基地址:
0x00007f211009c000(日志末尾的at 0x...部分) - C函数的绝对执行地址:
0x00007f21100a7fea - 函数入口的偏移量:
AMIn2_GetSubsystemsJSON+0x22d(相对于函数入口的偏移)
3. 正确使用addr2line
方法一:计算相对偏移后解析
先计算绝对地址相对于库基地址的偏移:
0x00007f21100a7fea - 0x00007f211009c000 = 0x9fea
然后用这个相对偏移执行addr2line:
addr2line -e libAMIreadN2Data_swig.so -f -C 0x9fea
方法二:直接用绝对地址(部分addr2line版本支持)
如果你的addr2line支持解析绝对地址,可以直接传入:
addr2line -e libAMIreadN2Data_swig.so -f -C 0x00007f21100a7fea
4. 如何获取JNI库的基地址
- 从hs_err日志获取:查看日志中的
Loaded Libraries区块,里面会列出所有加载的库及其基地址,比如你的日志已经给出了libAMIreadN2Data_swig.so的基地址。 - 从核心转储获取:用gdb加载核心转储后查看:
输出中会显示库的加载基地址。gdb <你的Java可执行文件路径> <核心转储文件路径> (gdb) info sharedlibrary libAMIreadN2Data_swig.so
5. 关键前提:编译JNI库时生成调试信息
必须确保编译JNI库时添加了-g参数(GCC)或对应调试参数,否则即使地址正确,addr2line也无法解析出具体的行号。
内容的提问来源于stack exchange,提问作者dargaud
相关产品推荐
相关产品推荐

