티스토리 툴바


'Linux/유용한 Tip'에 해당되는 글 18건

  1. 2009/08/03 리눅스에서 Java JNI call 함수를 GDB로 디버깅하기
우선 간단한 자바 클래스를 작성합니다.

[HelloWorld.java]
import java.io.*;

public class HelloWorld {
public native void printMessage();   // native call을 할 함수명입니다.

static {
System.loadLibrary("hello");  // native call 함수가 들어있는 라이브러리 이름입니다.
}

public static void main(String[] ar) {
HelloWorld hello = new HelloWorld();
hello.printMessage();  // native call 호출
}
}


위에서 작성한 자바 소스를 컴파일합니다.


[root@localhost]# javac HelloWorld.java


이렇게 되면 HelloWorld.class라는 파일이 생성됩니다.
그리고 Native Method가 사용할 헤더파일을 생성합니다.


[root@localhost]# javah -jni HelloWorld


아래와 같은 HelloWorld.h 파일이 생성됩니다.

[HelloWorld.h]
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloWorld */

#ifndef _Included_HelloWorld
#define _Included_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: HelloWorld
* Method: printMessage
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_HelloWorld_printMessage (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

이 파일을 바탕으로 실제 Native Method를 작성합니다.

[HelloWorld.c]
#include "HelloWorld.h"

/*
* Class: HelloWorld
* Method: printMessage
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_HelloWorld_printMessage (JNIEnv *env, jobject me)
{
while(1)
printf("Helo World!!!\n");
return; 
}

여기까지 오면 HelloWorld.java, HelloWorld.class, HelloWorld.h, HelloWorld.c 까지 만들어집니다.
그리고 Native Method가 들어간 라이브러리를 컴파일합니다.

gcc -g -I/usr/local/java/include -I/usr/local/java/include/linux -shared HelloWorld.c -o libhello.so

분홍색 : 디버깅을 위한 옵션(일반적인 경우 뺀다)
빨간색 : jni.h 경로
파란색 : jni_md.h 경로
녹색   : Shared Library를 사용하는 옵션
노란색 : 소스파일
보라색 : 컴파일된 라이브러리 파일명(HelloWorld.java의 loadLibrary에서는 loadLibrary("hello")만 하면된다)

jni.h, jni_md.h의 경로는 설치된 jdk의 경로에 따라 달라질 수 있으므로 경로를 검색하여 자신의 환경에 맞게 바꿔줍니다.
[root@localhost]# find / -name "jni.h"
[root@localhost]# find / -name "jni_md.h"

이제 Native Method 라이브러리까지 작성되었습니다. 실행을 해봅니다.

[root@localhost]# java HelloWorld

보통은 원하는 문자가 바로 나오지만 아래와 에러 메세지를 나타내는 경우도 있습니다.
java.lang.UnsatisfiedLinkError: no hello in java.library.path
          at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1709)
          at java.lang.Runtime.loadLibrary0(Runtime.java:823)
          at java.lang.System.loadLibrary(System.java:1030)
          at HelloWorld.<clinit>(HelloWorld.java:<line number>)
Could not find the main class: HelloWorld. Program will exit.

라이브러리의 위치가 제대로 지정이 되어 있지 않아서 나타나는 문제입니다.
이럴때는 아래와 같이 입력해줍니다.

[root@localhost]# chcon -t texrel_shlib_t libhello.so

실행을 해봅니다.
HelloWorld가 무한 반복되는 것을 볼 수 있습니다. 이 상황에서 다른 터미널을 더 열어서
현재 진행중인 HelloWorld의 pid를 알아냅니다.


[root@localhost]# ps -ax


해당 프로세스의 pid가 18942라면 이 값을 가지고 GDB를 실행합니다.


[root@localhost]# gdb -p 18942


무한반복중인 프로세스가 멈추고 gdb가 실행됩니다.
gdb 명령은 다른 글을 참고하세요
ps. 현재 진행중인 프로세스를 멈췄으므로 디버깅을 계속 진행할 때 아래와 같이 run 대신 continue를 입력합니다.

(gdb) continue
Posted by 베리머치 트랙백 0 : 댓글 0