点击量:1180
上篇文章介绍了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
publicclassCoreDumpTest{
//native关键字修饰的方法是对本地方法的声明,具体实现由本地方法完成
publicnativevoidcrash();
static{
//静态方法,载入本地动态库。load方法载入的是绝对路径下面的库
//也可以使用loadLibrary,调用的是"java.library.path"下面的库
//这个方法需要把生成的动态库加到目录里面,比较麻烦,我这边就直接使用绝对路径了。
System.load("/home/fanyy/crash.so");
}
publicstaticvoidmain(String[]args){
newCoreDumpTest().crash();
}
}
2.编译,生成.class文件
1
javacCoreDumpTest.java
3.生成头文件:CoreDumpTest.h
1
javahCoreDumpTest
该文件的内容如下:
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
/* Header for class CoreDumpTest */
#ifndef_Included_CoreDumpTest
#define_Included_CoreDumpTest
#ifdef__cplusplus
extern"C"{
#endif
/*
* Class: CoreDumpTest
* Method: crash
* Signature: ()V
*/
JNIEXPORTvoidJNICALLJava_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"
JNIEXPORTvoidJNICALLJava_CoreDumpTest_crash
(JNIEnv*env,jobjectobj){
int*p=NULL;
*p=3;
}
5.生成动态库
生成动态库的过程分为两步:先生成目标文件,再生成so文件。
1).生成目标文件:
1
gcc-I/usr/local/jdk/include-I/usr/local/jdk/include/linux-fPICcrash.c
参数-I表示需要引入的头文件的目录,-fPIC表示编译的是位置无关代码(position independent code),也就是说这段编译的代码使用的都是相对地址,而不是绝对地址,所以加载器在把代码加载到内存的时候可以放到任意位置,而不需要根据当前的内存地址重新定位。
2).生成so文件
1
gcc-shared-fPIC-ocrash.socrash.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-ocrash.so-I/usr/local/jdk/include-I/usr/local/jdk/include/linuxcrash.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]$javaCoreDumpTest
#
#AfatalerrorhasbeendetectedbytheJavaRuntimeEnvironment:
#
#SIGSEGV(0xb)atpc=0x00007f37956cd554,pid=23687,tid=139881182439168
#
#JREversion:6.0_22-b04
#JavaVM:JavaHotSpot(TM)64-BitServerVM(17.1-b03mixedmodelinux-amd64)
#Problematicframe:
#C[crash.so+0x554]Java_CoreDumpTest_crash+0x18
#
#Anerrorreportfilewithmoreinformationissavedas:
#/home/astd/fanyy/javacoredump/hs_err_pid23687.log
#
#Ifyouwouldliketosubmitabugreport,pleasevisit:
#http://java.sun.com/webapps/bugreport/crash.jsp
#ThecrashhappenedoutsidetheJavaVirtualMachineinnativecode.
#Seeproblematicframeforwheretoreportthebug.
#
Aborted(coredumped)
Duang!coredump了!