点击量:1563
上篇文章介绍了coredump的基本知识以及gdb调试core文件的相关操作,这篇文章主要介绍如何生成Java进程的coredump,也就是说如何写一段java代码使它被操作系统kill掉。我们都知道因为jvm的存在,java层面的代码无论你怎么写都是不太可能crash的,顶多是OOM或者stackoverflow,然而这些都会被jvm捕捉并抛出异常,而不是被操作系统直接kill掉。所以如果一个java进程crash掉,那肯定是挂在native code上了(当然JVM本身的bug就另说了),因此思路就是通过java的JNI(java native interface)调用本地方法,使进程挂掉。具体步骤如下:
1.编写java代码,调用本地方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public class CoreDumpTest { //native关键字修饰的方法是对本地方法的声明,具体实现由本地方法完成 public native void crash(); static { //静态方法,载入本地动态库。load方法载入的是绝对路径下面的库 //也可以使用loadLibrary,调用的是"java.library.path"下面的库 //这个方法需要把生成的动态库加到目录里面,比较麻烦,我这边就直接使用绝对路径了。 System.load("/home/fanyy/crash.so"); } public static void main(String[] args) { new CoreDumpTest().crash(); } } |
2.编译,生成.class文件
1 |
javac CoreDumpTest.java |
3.生成头文件:CoreDumpTest.h
1 |
javah CoreDumpTest |
该文件的内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class CoreDumpTest */ #ifndef _Included_CoreDumpTest #define _Included_CoreDumpTest #ifdef __cplusplus extern "C" { #endif /* * Class: CoreDumpTest * Method: crash * Signature: ()V */ JNIEXPORT void JNICALL Java_CoreDumpTest_crash (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif |
这段代码是自动生成的,不可以修改,我们可以看到有一个声明的函数叫:Java_CoreDumpTest_crash,接下来我们需要用C来具体实现这个函数。
4.编写具体的本地代码
实现头文件中的方法,命名为crash.c
1 2 3 4 5 6 7 8 |
#include "jni.h" #include "CoreDumpTest.h" JNIEXPORT void JNICALL Java_CoreDumpTest_crash (JNIEnv * env, jobject obj){ int *p = NULL; *p = 3; } |
5.生成动态库
生成动态库的过程分为两步:先生成目标文件,再生成so文件。
1).生成目标文件:
1 |
gcc -I /usr/local/jdk/include -I /usr/local/jdk/include/linux -fPIC crash.c |
参数-I表示需要引入的头文件的目录,-fPIC表示编译的是位置无关代码(position independent code),也就是说这段编译的代码使用的都是相对地址,而不是绝对地址,所以加载器在把代码加载到内存的时候可以放到任意位置,而不需要根据当前的内存地址重新定位。
2).生成so文件
1 |
gcc -shared -fPIC -o crash.so crash.o |
值得注意的是,如果你遇到这个报错:relocation R_X86_64_32 against `.rodata’ can not be used when making a shared object; recompile with -fPIC,很有可能是上一步上成目标文件时没有加上参数-fPIC,因为动态库的编译是基于目标文件的,如果要编译位置无关的动态库,他所需要的目标文件也必须是位置无关的。
当然了,这两步也可以合并成一步:
1 |
gcc -shared -fPIC -o crash.so -I /usr/local/jdk/include -I /usr/local/jdk/include/linux crash.c |
6.运行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
[fanyy@VM_72_32_tlinux ~/fanyy]$ java CoreDumpTest # # A fatal error has been detected by the Java Runtime Environment: # # SIGSEGV (0xb) at pc=0x00007f37956cd554, pid=23687, tid=139881182439168 # # JRE version: 6.0_22-b04 # Java VM: Java HotSpot(TM) 64-Bit Server VM (17.1-b03 mixed mode linux-amd64 ) # Problematic frame: # C [crash.so+0x554] Java_CoreDumpTest_crash+0x18 # # An error report file with more information is saved as: # /home/astd/fanyy/javacoredump/hs_err_pid23687.log # # 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. # Aborted (core dumped) |
Duang!coredump了!
博主写的真棒,大道至简