компиляция агента jvmti с помощью g ++ не работает, но cc работает нормально - PullRequest
1 голос
/ 11 ноября 2011

У меня очень простой агент, в основном только необходимая подпись метода 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

, затем создайте крошечную библиотеку и протестируйте ее

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

Вот еще одна версия, я добавил ваше предложение о внешнем "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 ++.

Java, # НКУ

1 Ответ

2 голосов
/ 11 ноября 2011

Вы не показывали нам содержимое testagent.c.

Я предполагаю, что вас укусила искажение имени в C ++ , либо потому, что вы не использовали JNIEXPORT при определении Agent_OnLoad(), либо потому что JNIEXPORT не включает extern "C" на вашей платформе.

Окружение вашего определения Agent_OnLoad() с extern "C" { и } должно быть всем, что вам нужно.

Вы можете проверить, действительно ли искажение имени является вашей проблемой, выполнив

nm libtestagent.so | grep Agent_OnLoad

и сравнение результатов для рабочей (gcc) и неработающей (g++) версий.

Обновление:

Хорошо, значит, искажение имен в C ++ было не так. Следующим шагом вы должны выяснить, почему динамический компоновщик не может dlopen("libtestagent.so"). Вы можете сделать это, добавив к вашей команде префикс LD_DEBUG=all, собрав рабочий и нерабочий выходные данные (выходные данные будут огромными), и найдя различия.

Обновление 2:

Я добавил __gxx_personality_v0 как пустоту * __ gxx_personality_v0;

Это не совсем правильный способ решения проблемы, который, вероятно, вызовет проблемы позже, когда вы начнете использовать настоящий C ++ в агенте.

Правильный способ решения проблемы - связать библиотеку с g++, а не gcc. Это добавит зависимость от libstdc++.so.6, которая определяет __gxx_personality_v0 и кучу других вещей, которые понадобятся вашему C ++ коду.

...