我有一个非常简单的代理,基本上只是所需的Agent_OnLoad方法签名。
如果我用g ++编译它。
g++ -g -fno-strict-aliasing -fPIC -fno-omit-frame-pointer -W -Wall -Wno-unused -Wno-parentheses -I. -I../agent_util -I/home/user/apps/Genuitec/Common/binary/com.sun.java.jdk.linux.x86_1.6.0.013//include -I/home/user/apps/Genuitec/Common/binary/com.sun.java.jdk.linux.x86_1.6.0.013//include/linux -c -o ../src/testagent.o -DMAX_THREADS=1000 -DJVMTI_TYPE=1 ../src/testagent.c
创建共享库并在代理上运行测试
LD_LIBRARY_PATH=`pwd` /home/mnc/apps/Genuitec/Common/binary/com.sun.java.jdk.linux.x86_1.6.0.013//bin/java -agentlib:testagent -version
我收到错误
Error occurred during initialization of VM
Could not find agent library on the library path or in the local directory: testagent
make: *** [test] Error 1
如果我使用以下命令编译,即编译为C,则可以正常工作。
gcc -Wl,-soname=calltracer.so -g -fno-strict-aliasing -fPIC -fno-omit-frame-pointer -W -Wall -Wno-unused -Wno-parentheses -I. -I../agent_util -I/home/user/apps/Genuitec/Common/binary/com.sun.java.jdk.linux.x86_1.6.0.013//include -I/home/user/apps/Genuitec/Common/binary/com.sun.java.jdk.linux.x86_1.6.0.013//include/linux -c -o ../src/testagent.o -DMAX_THREADS=1000 -DJVMTI_TYPE=1 ../src/testagent.c
然后创建一个shred lib并测试它
LD_LIBRARY_PATH=`pwd` /home/user/apps/Genuitec/Common/binary/com.sun.java.jdk.linux.x86_1.6.0.013//bin/java -agentlib:testagent -version
java version "1.6.0_13"
Java(TM) SE Runtime Environment (build 1.6.0_13-b03)
Java HotSpot(TM) Server VM (build 11.3-b02, mixed mode)
它运作正常。
问题是我的代码,是实际方法的cpp代码,而不是c。可以使用c ++代码创建代理吗?我怀疑它是,但我不知道我做错了什么。
这是我的测试代理的来源。不能这么简单。
/*testagent.c*/
#include "jni.h"
#include "jvmti.h"
JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
{
return 0;
}
/* Agent_OnUnload() is called last */
JNIEXPORT void JNICALL
Agent_OnUnload(JavaVM *vm)
{
}
编译为c文件时可以正常工作
here's the output from the nm command
0000046c T Agent_OnLoad
00000476 T Agent_OnUnload
00001f18 a _DYNAMIC
00001ff4 a _GLOBAL_OFFSET_TABLE_
w _Jv_RegisterClasses
00001f08 d __CTOR_END__
00001f04 d __CTOR_LIST__
00001f10 d __DTOR_END__
00001f0c d __DTOR_LIST__
000004d4 r __FRAME_END__
00001f14 d __JCR_END__
00001f14 d __JCR_LIST__
0000200c A __bss_start
w __cxa_finalize@@GLIBC_2.1.3
00000480 t __do_global_ctors_aux
000003b0 t __do_global_dtors_aux
00002008 d __dso_handle
w __gmon_start__
00000467 t __i686.get_pc_thunk.bx
0000200c A _edata
00002014 A _end
000004b8 T _fini
00000348 T _init
0000200c b completed.7021
00002010 b dtor_idx.7023
00000430 t frame_dummy
这是另一个版本,我添加了你对extern“C”的建议,但是我得到了和以前一样的结果,找不到库。
/*testagent.c*/
#include "jni.h"
#include "jvmti.h"
extern "C" {
JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
{
return 0;
}
}
/* Agent_OnUnload() is called last */
JNIEXPORT void JNICALL
Agent_OnUnload(JavaVM *vm)
{
}
这是nm命令的输出
000004bc T Agent_OnLoad
000004c6 T Agent_OnUnload
0000200c d DW.ref.__gxx_personality_v0
00001f18 a _DYNAMIC
00001ff4 a _GLOBAL_OFFSET_TABLE_
w _Jv_RegisterClasses
00001f08 d __CTOR_END__
00001f04 d __CTOR_LIST__
00001f10 d __DTOR_END__
00001f0c d __DTOR_LIST__
00000594 r __FRAME_END__
00001f14 d __JCR_END__
00001f14 d __JCR_LIST__
00002010 A __bss_start
w __cxa_finalize@@GLIBC_2.1.3
000004d0 t __do_global_ctors_aux
00000400 t __do_global_dtors_aux
00002008 d __dso_handle
w __gmon_start__
U __gxx_personality_v0
000004b7 t __i686.get_pc_thunk.bx
00002010 A _edata
00002018 A _end
00000508 T _fini
0000039c T _init
00002010 b completed.7021
00002014 b dtor_idx.7023
00000480 t frame_dummy
nm命令的跟踪略有不同,但它们都包含Agent_OnLoad。
这是用于在两种情况下创建共享库的命令行。
cc -g -fno-strict-aliasing -fPIC -fno-omit-frame-pointer -W -Wall -Wno-unused -Wno-parentheses -I. -I../agent_util -I/home/user/apps/Genuitec/Common/binary/com.sun.java.jdk.linux.x86_1.6.0.013//include -I/home/user/apps/Genuitec/Common/binary/com.sun.java.jdk.linux.x86_1.6.0.013//include/linux -Wl,-soname=libtestagent.so -static-libgcc -mimpure-text -shared -o libtestagent.so ../src/testagent.o -lc
从ldd输出,不是工作情况(g ++)
ldd libtestagent.so
linux-gate.so.1 => (0x00d96000)
libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0x0019a000)
/lib/ld-linux.so.2 (0x005ee000)
输出来自ldd,工作案例(gcc)
ldd libtestagent.so
linux-gate.so.1 => (0x00544000)
libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0x00908000)
/lib/ld-linux.so.2 (0x003a2000)
使用linux大约15年从未知道你可以做LD_DEBUG =全部,非常有用。 这是有趣的输出
2689: symbol=__gxx_personality_v0; lookup in file=/home/mnc/apps/Genuitec/Common/binary/com.sun.java.jdk.linux.x86_1.6.0.013//bin/java [0]
2689: symbol=__gxx_personality_v0; lookup in file=/lib/tls/i686/cmov/libpthread.so.0 [0]
2689: symbol=__gxx_personality_v0; lookup in file=/home/mnc/apps/Genuitec/Common/binary/com.sun.java.jdk.linux.x86_1.6.0.013/bin/../jre/lib/i386/jli/libjli.so [0]
2689: symbol=__gxx_personality_v0; lookup in file=/lib/tls/i686/cmov/libdl.so.2 [0]
2689: symbol=__gxx_personality_v0; lookup in file=/lib/tls/i686/cmov/libc.so.6 [0]
2689: symbol=__gxx_personality_v0; lookup in file=/lib/ld-linux.so.2 [0]
2689: symbol=__gxx_personality_v0; lookup in file=/home/mnc/apps/Genuitec/Common/binary/com.sun.java.jdk.linux.x86_1.6.0.013/jre/lib/i386/server/libjvm.so [0]
2689: symbol=__gxx_personality_v0; lookup in file=/lib/tls/i686/cmov/libm.so.6 [0]
2689: symbol=__gxx_personality_v0; lookup in file=/home/mnc/apps/javacalltracer/Calltracer/jvmti/libtestagent.so [0]
2689: symbol=__gxx_personality_v0; lookup in file=/lib/tls/i686/cmov/libc.so.6 [0]
2689: symbol=__gxx_personality_v0; lookup in file=/lib/ld-linux.so.2 [0]
2689: /home/mnc/apps/javacalltracer/Calltracer/jvmti/libtestagent.so: error: symbol lookup error: undefined symbol: __gxx_personality_v0 (fatal)
2689:
2689: file=/home/mnc/apps/javacalltracer/Calltracer/jvmti/libtestagent.so [0]; destroying link map
Error occurred during initialization of VM
我在stackoverflow上搜索了这个,一篇帖子建议为这个符号添加一个全局 所以我添加了__gxx_personality_v0作为 void * __ gxx_personality_v0;
现在JVM在使用g ++进行编译时找到了库。
答案 0 :(得分:2)
您没有向我们展示testagent.c
的内容。
我的猜测是,您被C++ name mangling感染了,原因是您在定义JNIEXPORT
时没有使用Agent_OnLoad()
,或者因为JNIEXPORT
不包含extern "C"
{1}}在您的平台上。
围绕Agent_OnLoad()
与extern "C" {
和}
的定义应该是您所需要的。
您可以通过执行
来验证名称修改是否实际上是您的问题nm libtestagent.so | grep Agent_OnLoad
并比较工作(gcc
)和损坏(g++
)版本的结果。
更新
好的,所以C ++名称错误不是它。下一步应该是找出动态链接器失败的原因dlopen("libtestagent.so")
。您可以通过在命令前添加LD_DEBUG=all
前缀,收集工作和非工作输出(输出很大),并查找差异来实现。
更新2:
我已将__gxx_personality_v0添加为void * __ gxx_personality_v0;
这不是解决问题的正确方法,并且在您开始在代理中使用实际C ++时可能会导致问题。
解决问题的正确方法是将库与g++
相关联,而不是gcc
。这将在libstdc++.so.6
上添加一个依赖项,它定义了__gxx_personality_v0
以及C ++代码所需的一些其他内容。