【发布时间】:2012-03-19 15:23:39
【问题描述】:
我试图找出我的 Java 应用程序崩溃的原因。其实是JVM的crash,是通过JNI调用原生库引起的。
这是我在生成的hs_err_pidxxxx.log 中看到的内容:
#
# A fatal error has been detected by the Java Runtime Environment:
#
# EXCEPTION_INT_DIVIDE_BY_ZERO (0xc0000094) at pc=0x4fa19409, pid=1456, tid=4068
#
# JRE version: 6.0_30-b12
# Java VM: Java HotSpot(TM) Client VM (20.5-b03 mixed mode windows-x86 )
# Problematic frame:
# C [JCustomOpc.dll+0x9409]
#
# If you would like to submit a bug report, please visit:
# http://java.sun.com/webapps/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
--------------- T H R E A D ---------------
Current thread (0x4ab1c400): JavaThread "opc_service" daemon [_thread_in_native, id=4068, stack(0x4f200000,0x4f250000)]
siginfo: ExceptionCode=0xc0000094
Registers:
EAX=0x00000000, EBX=0x00000000, ECX=0x4f24f958, EDX=0x80000000
ESP=0x4f24f93c, EBP=0x4f24f940, ESI=0x4f24f9a4, EDI=0x52d396f4
EIP=0x4fa19409, EFLAGS=0x00010286
Top of Stack: (sp=0x4f24f93c)
0x4f24f93c: 4f24f98a 4f24f970 4fa1968a 52220000
0x4f24f94c: 5042f418 4f24f9a4 4b1ba6e8 00000004
0x4f24f95c: 52d396f4 4ab1c528 4f24f9a8 4f24f9a6
0x4f24f96c: 4f24f9a4 4f24f98c 4fa197cc 4f24f98a
0x4f24f97c: 52220000 5042f418 00000036 4f24f9a8
0x4f24f98c: 4ab33d1c 4fa6388f 52220000 5042f418
0x4f24f99c: 4ab1c528 4ab33d24 00000008 6d92f61f
0x4f24f9ac: 4ab1c528 4ab33d1c 00000022 0000000a
Instructions: (pc=0x4fa19409)
0x4fa193e9: db 89 c1 dd 45 08 d8 8b 88 21 a7 4f 83 ec 08 df
0x4fa193f9: 3c 24 9b 58 5a 09 d2 79 11 f7 da f7 d8 83 da 00
0x4fa19409: f7 b3 8c 21 a7 4f f7 d8 eb 06 f7 b3 8c 21 a7 4f
0x4fa19419: 05 5a 95 0a 00 89 11 89 41 04 5b 5d c2 08 00 55
Register to memory mapping:
EAX=0x00000000 is an unknown value
EBX=0x00000000 is an unknown value
ECX=0x4f24f958 is pointing into the stack for thread: 0x4ab1c400
EDX=0x80000000 is an unknown value
ESP=0x4f24f93c is pointing into the stack for thread: 0x4ab1c400
EBP=0x4f24f940 is pointing into the stack for thread: 0x4ab1c400
ESI=0x4f24f9a4 is pointing into the stack for thread: 0x4ab1c400
EDI=0x52d396f4 is an unknown value
Stack: [0x4f200000,0x4f250000], sp=0x4f24f93c, free space=318k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C [JCustomOpc.dll+0x9409]
C [JCustomOpc.dll+0x968a]
C [JCustomOpc.dll+0x97cc]
Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
J javafish.clients.opc.JOpc.getDownloadGroupNative()Ljavafish/clients/opc/component/OpcGroup;
J fr.def.iss.vd2.mod_opc_service.JEasyFacade.getPossiblyChangedGroups()Ljava/util/Collection;
J fr.def.iss.vd2.mod_opc_service.OpcServiceImpl.updateState()V
j fr.def.iss.vd2.mod_opc_service.OpcServiceImpl.access$3000(Lfr/def/iss/vd2/mod_opc_service/OpcServiceImpl;)V+1
j fr.def.iss.vd2.mod_opc_service.OpcServiceImpl$5.handlOpcEvents()V+103
j fr.def.iss.vd2.mod_opc_service.OpcServiceImpl$Worker.run()V+156
j java.lang.Thread.run()V+11
v ~StubRoutines::call_stub
所以,它表明JCustomOpc.dll 中有一个被零除。 JCustomOpc.dll 是一个第三方库,用 Delphi 编写,由我们的团队使用 Borland Delphi pro 7.0 编译。我现在要做的是在 Delphi 源代码中找到这种被零除的位置。
我主要是一名 Java 程序员,我不习惯调试本机代码。所以,我关注了tutorial on JVM crash analysis。
我按照说明进行操作:
> dumpbin /headers JCustomOpc.dll
...
OPTIONAL HEADER VALUES
10B magic #
2.25 linker version
60800 size of code
12400 size of initialized data
0 size of uninitialized data
616A8 RVA of entry point
1000 base of code
62000 base of data
400000 image base
...
因此,图像基数为 400000,根据教程,我希望除法指令位于偏移量 409409。
我们用反汇编来看看:
> dumpbin /exports /disasm JCustomOpc.dll
...
004093E0: C3 ret
004093E1: 8D 40 00 lea eax,[eax]
004093E4: 55 push ebp
004093E5: 8B EC mov ebp,esp
004093E7: 53 push ebx
004093E8: 31 DB xor ebx,ebx
004093EA: 89 C1 mov ecx,eax
004093EC: DD 45 08 fld qword ptr [ebp+8]
004093EF: D8 8B 88 21 46 00 fmul dword ptr [ebx+00462188h]
004093F5: 83 EC 08 sub esp,8
004093F8: DF 3C 24 fistp qword ptr [esp]
004093FB: 9B wait
004093FC: 58 pop eax
004093FD: 5A pop edx
004093FE: 09 D2 or edx,edx
00409400: 79 11 jns 00409413
00409402: F7 DA neg edx
00409404: F7 D8 neg eax
00409406: 83 DA 00 sbb edx,0
00409409: F7 B3 8C 21 46 00 div eax,dword ptr [ebx+0046218Ch]
0040940F: F7 D8 neg eax
00409411: EB 06 jmp 00409419
00409413: F7 B3 8C 21 46 00 div eax,dword ptr [ebx+0046218Ch]
00409419: 05 5A 95 0A 00 add eax,0A955Ah
0040941E: 89 11 mov dword ptr [ecx],edx
00409420: 89 41 04 mov dword ptr [ecx+4],eax
00409423: 5B pop ebx
00409424: 5D pop ebp
00409425: C2 08 00 ret 8
...
409409 确实是 div 指令。
我对汇编知之甚少,但这段代码似乎在操纵浮点值并进行整数除法。我搜索了 Delphi 源代码,但没有发现任何看起来像算术运算的东西。
我很确定有一种可靠的方法可以找到与该程序集匹配的 Delphi 函数,但我不知道该怎么做。我有这个 dll 的全部源代码,并且我可以完全控制如何编译它。
delphi 源 (.pas) 生成编译文件 (.dcu),也许这些文件可以帮助解决我的问题,但我不知道如何处理它们。链接器有一个选项,用于创建映射文件。它确实创建了一个 JCustomOpc.map 文件,该文件是一个包含大量符号和偏移量的文本文件。但偏移量与 9404 附近的任何值都不匹配。
我必须补充一点,此崩溃发生在我们客户的机器上,但无法在我们的机器上重现。此外,实际上不可能在客户的机器上进行一些测试,所以我有点坚持只在hs_err_pid file 上工作。
我现在该怎么做才能找到有问题的源代码行在哪里?
编辑
【问题讨论】:
-
您必须知道 DLL 加载地址才能将感兴趣的地址映射到图像中的 VA。
-
我会将 Jedi JCL Debug 或 MadExcept 添加到您的 dll 中,围绕您导出的每个 DLL 函数执行一个大的 try-catch 块,并转储包括整个堆栈跟踪的异常日志。您绝对不应该允许访问违规或异常再次引发到托管 DLL 的应用程序中。
标签: java delphi debugging assembly java-native-interface