2011-11-10 25 views
1

我有一個非常簡單的代理,基本上只是所需的Agent_OnLoad方法簽名。使用g ++編譯jvmti代理無法工作,但cc工作正常

如果我用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 

並創建一個共享lib和在代理

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 

,然後創建一絲一毫的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) 
{ 
} 

時作爲交流文件編譯此工程確定

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 [email protected]@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 

這裏的另一個版本,我加你了外部的「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 [email protected]@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 

跟蹤從納米命令的輸出略有不同,但它們都包括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輸出

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) 

,工作情況(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 = all,非常有用。 這裏是有趣的輸出

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 

我做了一個計算器搜索對此,後建議增加全球對這個符號 所以我添加__gxx_personality_v0作爲 無效* __ gxx_personality_v0;

現在JVM在用g ++編譯時找到了庫。

的java,#GCC

回答

2

你沒有表現出我們的testagent.c內容。

我的猜測是,你正在C++ name mangling咬傷,或者是因爲你定義Agent_OnLoad(),或因爲JNIEXPORT時不包括你的平臺上extern "C"沒有使用JNIEXPORT

Agent_OnLoad()的定義與extern "C" {}應該完全相符。

您可以驗證名稱重整實際上是否是您的問題通過執行

nm libtestagent.so | grep Agent_OnLoad 

和結果比較的工作(gcc)和斷(g++)版本。

更新:

好的,所以C++名稱mangling是不是。你下一步應該找出爲什麼動態鏈接器沒有達到dlopen("libtestagent.so")。你可以通過在你的命令前加上LD_DEBUG=all來做到這一點,收集工作和非工作輸出(輸出將是巨大的),並尋找差異。

更新2:

我添加__gxx_personality_v0作爲一個void * __ gxx_personality_v0;

這不是解決問題的正確方法,並且稍後在開始在代理中使用實際C++時可能會導致問題。

解決此問題的正確方法是將庫與g++鏈接,而不是gcc。這將增加對libstdc++.so.6的依賴,它定義了__gxx_personality_v0以及您的C++代碼需要的其他一些東西。

+0

這裏是我的測試代理的來源。無法讓這個更簡單。 – user1040768

+0

謝謝,我已更新一些額外的信息 – user1040768

+0

請在答案中看到update2。 –

相關問題