检测Java9+;运行时模块

检测Java9+;运行时模块,java,java-9,instrumentation,java-11,Java,Java 9,Instrumentation,Java 11,我们的工具()通过在程序的Java字节码中插入插装来计算程序不变量。用户代码在运行时通过普通的ClassFileTransformer::transform方法检测 还需要通过JDK方法跟踪值流。因此,我们还需要为Java运行时提供工具。我们不能使用transform,因为在我们第一次在transform获得控制之前,已经加载了数百个运行时方法 在Java9之前,我们在一个离线步骤中处理这个问题,该步骤读取rt.jar,插入它的方法,并写出一个修改后的版本dcomp-rt.jar。用户将dcom

我们的工具()通过在程序的Java字节码中插入插装来计算程序不变量。用户代码在运行时通过普通的
ClassFileTransformer::transform
方法检测

还需要通过JDK方法跟踪值流。因此,我们还需要为Java运行时提供工具。我们不能使用
transform
,因为在我们第一次在
transform
获得控制之前,已经加载了数百个运行时方法

在Java9之前,我们在一个离线步骤中处理这个问题,该步骤读取
rt.jar
,插入它的方法,并写出一个修改后的版本
dcomp-rt.jar
。用户将
dcomp-rt.jar
放在bootclasspath上,以确保加载修改后的Java运行时方法,而不是标准方法。用户程序调用类似于:

java -cp .:.../daikon/daikon.jar \
  -Xbootclasspath/p:.../daikon/java/dcomp_rt.jar:.:.../daikon/daikon.jar \
  -javaagent:.../daikon/java/dcomp_premain.jar={various dcomp arguments} \
  {user program} {user program arguments}
现在转到Java9+。我们的第一种方法是读取Java运行时jmod文件中的类文件(通过新的
jrt://
文件系统),并像以前一样创建
dcomp\u rt.jar
。我们遇到的问题是,我们无法让系统使用这个jar的内容而不是
jrt:/java.base
(例如)。我们尝试了各种
--module path
-Xbootclasspath
(现在只有
/a
可用,可能是问题的一部分)选项,但均无效。还是希望有办法做到这一点

如果没有,我猜我们需要对每个有趣的运行时jmod进行修改,然后为每个jmod使用
--patch module
参数。这是否可以确保加载修改后的代码而不是标准运行时

有什么想法/建议吗?

看起来,补丁模块起到了作用。我制作了相同的dcomp_rt.jar,但只使用java.base.jmod中的类。然后使用:

 --patch-module java.base={full path}/dcomp_rt.jar
使用-verbose:class运行java显示了从我的jar加载的所有基类


这是实现我目标的最佳方式吗?

也许“你错了”?所有“Java运行时调用中的值和Java运行时调用中的值”都可以通过检测应用程序代码来跟踪,该应用程序代码确实会调用Java运行时,并且可能会被Java运行时调用。检测所有Java运行时类会导致大量内部调用,您必须过滤掉这些调用,因此需要做两次不必要的工作…当您需要覆盖运行时映像中的类时,--patch module选项相当于-Xbootclasspath/p。它应该在这里工作,尽管如果要检测java.base中的类以访问java.base之外的类,需要小心。您是否考虑过编写java代理并使用-javaagent代替静态插装?如果您真的想进行静态插装,那么您可以插装打包模块(jmod文件)中的代码,然后运行jlink以使用插装模块创建新的运行时映像。问题是在我们通过“transform”看到第一个类之前加载的所有java运行时类。没有检测那些“早期加载”的类会使我们的不变分析不那么准确。正如您所指出的(我的实验在下面的回答中指出的)——补丁模块完成了这项工作。插入指令的代码确实可以访问java.base之外的一些我们自己的类。这里有什么问题?@MarkRoberts建议由一个可以重新转换类的代理来解决吗?假设dcomp_rt.jar只包含来自java.base的类的插入指令的版本,那么您应该没问题。如果您在这个JAR文件中有来自其他模块的类,那么它将不起作用。问题是,我们添加的工具包括对运行时例程的调用,以捕获不变数据。使用重传是一个好主意,但在我们的例子中不起作用,因为我们将新方法添加到正在检测的类中。因此,假设基本模块无法引用不包含在基本模块中的方法(?),我认为有两种方法可以实现。一个是看我们是否可以创建一个完全自包含的运行时,然后将其添加到基本模块中。另一个是研究您关于使用jlink构建我们自己的运行时的建议。如果您在启动早期静态检测使用的类,那么您可能在玩火,因为VM仅限于java.base,直到完全初始化为止。JVMTI代理可以在原始阶段启用CFLH事件的功能,但java代理没有相应的功能。另一件事是,您不能在映射到引导类装入器的模块中插入代码,并引用类路径上的代码。从您的评论中不清楚您的“运行时例程”部署在哪里。