编译JDK源码并调试Native方法
编译JDK源码并调试Native方法
在学习反射的过程中核心方法Native反射的invoke0方法是Native的,还想多研究一下C层的代码,于是开始捣鼓如何调试JDK源码中Native方法。
概要:编译自己的JDK源码、通过Clion与IDEA调试Native方法
编译JDK源码
个人环境
Linux: 5.10.121-1-MANJARO
gcc/g++: 12.1.0
Java:
java version "1.7.0_80"
Java(TM) SE Runtime Environment (build 1.7.0_80-b15)
Java HotSpot(TM) Server VM (build 24.80-b11, mixed mode)
准备
下载JDK源码
注意是要下载JDK SourceCode 而非是DevelopmentKit 之类的
由于JDK8版本的编译在我的Manjaro上屡次出错(这里之后会提到),我将待编译的JDK版本暂时提升到15,先编译高版本的。这里下载 OpenJDK 15
当然这里还有另外一种方式,通过Mercurial的hg clone下载,不过更有效的是针对老版本的JDK8之类的,先hg clone 指定的JDK版本,再sh get_source.sh去获取指定的内容
环境配置
由于AUR中已经有比较全面的编译工具base-devel,所以这里只需要再安装一个ccache即可
编译
sh configure --disable-warnings-as-errors --enable-debug --with-jvm-variants=server --with-boot-jdk=/home/pplong/.jdks/corretto-15.0.2
成功后再make images或make all
make images
即可得到源码
错误
编译JDK8时不论是什么版本一直会出现这样的报错,我猜应该是gcc和g++的版本过高导致warning被当成error对待,但是换成gcc 7时也不能成功编译,出现同样的错误,不知道是哪里依赖缺失?
## Starting langtools
Compiling 2 files for BUILD_TOOLS
/opt/SourceCode/jdk8u60/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java:310: 错误: 找不到符号
return tk.accepts(S.token(lookahead + 1).kind);
^
符号: 变量 kind
位置: 类 Token
/opt/SourceCode/jdk8u60/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java:318: 错误: 找不到符号
return tk1.accepts(S.token(lookahead + 1).kind) &&
^
符号: 变量 kind
位置: 类 Token
/opt/SourceCode/jdk8u60/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java:319: 错误: 找不到符号
这个问题以后还有待解决
安装
在IDEA ProjectStucture中进行如下设置,添加编译好的JDK,注意路径

不过这个时候无法查看和修改源码,需要在设置中切换源码目录,删除掉原有的SourcePath并且添加该源码主目录下src文件夹

快速编译
在IDEA中修改源码文件后,重新在源码主目录中进行make images
(因为不是全量编译了,只编译更改的部分,所以很快),再次运行项目便能实现源码的更改
调试
前置
项目的JDK必须与Clion中打开的源码目录相同
public static void main(String[] args) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
Class<Obj> objClass = Obj.class;
Obj obj = objClass.newInstance();
Method go = objClass.getMethod("go");
go.invoke(obj); // break point
System.out.println("finish");
}

在native方法invoke0中断点,并且相应的在Clion中对应的方法断点

开始
需要调试Java项目到对应的断点,然后项目目录内命令行 jps
查看对应的进程,找到类名与当前断点类相同的进程(若是源码类,可能出现unknown)
在Clion项目下Ctrl + alt + 5
attach to process,将Clion依附到正在执行的进程中,这一步可能会报错,ptrace permissioin not permitted之类的,需要echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
设置一下ptrace_scope
然后再在Java项目中深入断点,这样便成功进入到C层的项目中并且可以进行断点调试。
📖 参考文章
🔗 Biliblii - CodeSheep - JDK都没手动编译过,敢说自己是Java程序员吗?实战编译Java源码(JDK源码,JVM)视频教程
🔗 Youtube - recipeNoD002 - Debugging JNI code with IntelliJ/CLion