diff --git a/phosphor-instrument-jigsaw/pom.xml b/phosphor-instrument-jigsaw/pom.xml index ee59f2268..3169721cc 100644 --- a/phosphor-instrument-jigsaw/pom.xml +++ b/phosphor-instrument-jigsaw/pom.xml @@ -40,35 +40,6 @@ - - org.apache.maven.plugins - maven-javadoc-plugin - 3.1.1 - - true - - - - attach-javadoc - - jar - - - - - - org.apache.maven.plugins - maven-plugin-plugin - 3.6.0 - - - mojo-descriptor - - descriptor - - - - org.apache.maven.plugins maven-shade-plugin @@ -119,34 +90,6 @@ - - - release-sign-artifacts - - - gpg.passphrase - - - - - - org.apache.maven.plugins - maven-gpg-plugin - 1.4 - - - sign-artifacts - verify - - sign - - - - - - - - edu.gmu.swe.phosphor diff --git a/phosphor-instrument-jigsaw/src/main/java/edu/columbia/cs/psl/jigsaw/phosphor/instrumenter/JLinkInvoker.java b/phosphor-instrument-jigsaw/src/main/java/edu/columbia/cs/psl/jigsaw/phosphor/instrumenter/JLinkInvoker.java index 6111cd943..b26793847 100644 --- a/phosphor-instrument-jigsaw/src/main/java/edu/columbia/cs/psl/jigsaw/phosphor/instrumenter/JLinkInvoker.java +++ b/phosphor-instrument-jigsaw/src/main/java/edu/columbia/cs/psl/jigsaw/phosphor/instrumenter/JLinkInvoker.java @@ -1,48 +1,41 @@ package edu.columbia.cs.psl.jigsaw.phosphor.instrumenter; import edu.columbia.cs.psl.phosphor.Configuration; +import edu.columbia.cs.psl.phosphor.PhosphorOption; +import edu.columbia.cs.psl.phosphor.org.apache.commons.cli.Option; +import edu.columbia.cs.psl.phosphor.org.apache.commons.cli.Options; + import java.io.File; import java.io.IOException; import java.net.URISyntaxException; import java.util.HashSet; import java.util.Properties; import java.util.Set; +import java.util.stream.Collectors; public class JLinkInvoker { - public static final String MODULES_PROPERTY = "jvmModules"; + public static final String PACK_KEY = "phosphor.pack"; public static void invokeJLink(File jvmDir, File instJVMDir, Properties properties) { - String jlinkBin = jvmDir + File.separator + "bin" + File.separator + "jlink"; - File jlinkFile = getPhosphorJLinkJarFile(); + File jlinkFile = getClassPathElement(JLinkInvoker.class); String modulesToAdd = properties.getProperty(MODULES_PROPERTY, "java.base,jdk.jdwp.agent,java.instrument,jdk.unsupported"); - - Set classPaths = new HashSet<>(); - if (Configuration.PRIOR_CLASS_VISITOR != null) { - classPaths.add(Configuration.PRIOR_CLASS_VISITOR.getProtectionDomain().getCodeSource().getLocation().getPath()); - } - if (Configuration.POST_CLASS_VISITOR != null) { - classPaths.add(Configuration.POST_CLASS_VISITOR.getProtectionDomain().getCodeSource().getLocation().getPath()); - } - if (Configuration.taintTagFactoryPackage != null) { - classPaths.add(Configuration.taintTagFactory.getClass().getProtectionDomain().getCodeSource().getLocation().getPath()); - } - - ProcessBuilder pb = new ProcessBuilder(jlinkBin, "-J-javaagent:" + jlinkFile, + String classPath = buildClassPath(properties); + ProcessBuilder pb = new ProcessBuilder( + jlinkBin, + String.format("-J-D%s=%s", PACK_KEY, classPath), + "-J-javaagent:" + jlinkFile, "-J--module-path=" + jlinkFile, "-J--add-modules=edu.columbia.cs.psl.jigsaw.phosphor.instrumenter", - "-J--class-path=" + String.join(":", classPaths), + "-J--class-path=" + classPath, "--output=" + instJVMDir, "--phosphor-transformer=transform" + createPhosphorJLinkPluginArgument(properties), "--add-modules=" + modulesToAdd ); try { - for(String s : pb.command()){ - System.out.print(s + " "); - } - System.out.println(); + System.out.println(String.join(" ", pb.command())); Process p = pb.inheritIO().start(); p.waitFor(); } catch (IOException | InterruptedException e) { @@ -50,15 +43,36 @@ public static void invokeJLink(File jvmDir, File instJVMDir, Properties properti } } - /** - * @return a File object pointing to the JAR file for Phosphor-jlink bridge - */ - public static File getPhosphorJLinkJarFile() { - try { - return new File(JLinkInvoker.class.getProtectionDomain().getCodeSource().getLocation().toURI()); - } catch (URISyntaxException e) { - throw new AssertionError(); + private static String buildClassPath(Properties properties) { + Set> classes = new HashSet<>(); + Options options = PhosphorOption.createOptions(false); + for (Option option : options.getOptions()) { + if (option.getType().equals(Class.class)) { + String key = option.getOpt(); + if (properties.containsKey(key)) { + try { + Class clazz = Class.forName(properties.getProperty(key)); + classes.add(clazz); + } catch (ReflectiveOperationException e) { + String message = String.format("Failed to create %s class: %s", key, properties.getProperty(key)); + throw new IllegalArgumentException(message, e); + } + } + } + } + if (Configuration.PRIOR_CLASS_VISITOR != null) { + classes.add(Configuration.PRIOR_CLASS_VISITOR); + } + if (Configuration.POST_CLASS_VISITOR != null) { + classes.add(Configuration.POST_CLASS_VISITOR); } + if (Configuration.taintTagFactoryPackage != null) { + classes.add(Configuration.taintTagFactory.getClass()); + } + return classes.stream() + .map(JLinkInvoker::getClassPathElement) + .map(File::getAbsolutePath) + .collect(Collectors.joining(File.pathSeparator)); } /** @@ -74,7 +88,7 @@ public static String createPhosphorJLinkPluginArgument(Properties properties) { StringBuilder builder = new StringBuilder(); Set propNames = properties.stringPropertyNames(); for (String propName : propNames) { - if(propName.equals(MODULES_PROPERTY)) { + if (propName.equals(MODULES_PROPERTY)) { continue; } builder.append(':'); @@ -84,4 +98,12 @@ public static String createPhosphorJLinkPluginArgument(Properties properties) { return builder.toString(); } } + + public static File getClassPathElement(Class clazz) { + try { + return new File(clazz.getProtectionDomain().getCodeSource().getLocation().toURI()); + } catch (URISyntaxException e) { + throw new AssertionError(); + } + } } diff --git a/phosphor-instrument-jigsaw/src/main/java/edu/columbia/cs/psl/jigsaw/phosphor/instrumenter/PhosphorJLinkPlugin.java b/phosphor-instrument-jigsaw/src/main/java/edu/columbia/cs/psl/jigsaw/phosphor/instrumenter/PhosphorJLinkPlugin.java index 304885b65..cd0f75be6 100644 --- a/phosphor-instrument-jigsaw/src/main/java/edu/columbia/cs/psl/jigsaw/phosphor/instrumenter/PhosphorJLinkPlugin.java +++ b/phosphor-instrument-jigsaw/src/main/java/edu/columbia/cs/psl/jigsaw/phosphor/instrumenter/PhosphorJLinkPlugin.java @@ -8,13 +8,12 @@ import jdk.tools.jlink.plugin.ResourcePoolEntry; import java.io.File; -import java.net.URISyntaxException; import java.util.*; public class PhosphorJLinkPlugin implements Plugin { public static final String NAME = "phosphor-transformer"; - private static File phosphorJar; + private Set elementsToPack; @Override public boolean hasArguments() { @@ -31,15 +30,15 @@ public Category getType() { * created arguments * @return an array formatted for {@link Instrumenter#main(String[])} Instrumenter.main's} String[] argument */ - public static String[] createPhosphorMainArguments(Map properties) { + public static String[] createPhosphorMainArguments(Map properties) { LinkedList arguments = new LinkedList<>(); Set propNames = properties.keySet(); - for(String propName : propNames) { - if(propName.equals("phosphor-transformer")){ + for (String propName : propNames) { + if (propName.equals("phosphor-transformer")) { continue; } arguments.addLast("-" + propName); - if(!"true".equals(properties.get(propName))) { + if (!"true".equals(properties.get(propName))) { arguments.addLast(properties.get(propName)); } } @@ -54,8 +53,16 @@ public void configure(Map config) { TaintTrackingClassVisitor.IS_RUNTIME_INST = false; TaintUtils.VERIFY_CLASS_GENERATION = true; PhosphorOption.configure(false, createPhosphorMainArguments(config)); - phosphorJar = getPhosphorJarFile(); + File phosphorJar = JLinkInvoker.getClassPathElement(Instrumenter.class); System.out.println("Embedding Phosphor from: " + phosphorJar); + String pack = System.getProperty(JLinkInvoker.PACK_KEY); + this.elementsToPack = new HashSet<>(); + elementsToPack.add(phosphorJar); + if (pack != null && !pack.isEmpty()) { + Arrays.stream(pack.split(File.pathSeparator)) + .map(File::new) + .forEach(elementsToPack::add); + } //TODO process args } @@ -63,7 +70,7 @@ public void configure(Map config) { public ResourcePool transform(ResourcePool in, ResourcePoolBuilder out) { TaintUtils.VERIFY_CLASS_GENERATION = true; PreMain.RUNTIME_INST = false; - PhosphorPacker packer = new PhosphorPacker(in, phosphorJar); + PhosphorPacker packer = new PhosphorPacker(in, elementsToPack); in.transformAndCopy((resourcePoolEntry) -> { if (resourcePoolEntry.type().equals(ResourcePoolEntry.Type.CLASS_OR_RESOURCE)) { if (resourcePoolEntry.path().endsWith(".class")) { @@ -74,7 +81,8 @@ public ResourcePool transform(ResourcePool in, ResourcePoolBuilder out) { resourcePoolEntry = packer.pack(resourcePoolEntry, out); } } else { - byte[] newContent = Instrumenter.instrumentClass(resourcePoolEntry.path(), resourcePoolEntry.content(), true); + byte[] newContent = Instrumenter.instrumentClass(resourcePoolEntry.path(), + resourcePoolEntry.content(), true); if (newContent != null) { resourcePoolEntry = resourcePoolEntry.copyWithContent(newContent); } @@ -95,17 +103,6 @@ public String getName() { public String getDescription() { return "Transforms the runtime image to be compatible with Phosphor"; } - - /** - * @return a File object pointing to the JAR file for Phosphor - */ - public static File getPhosphorJarFile() { - try { - return new File(Instrumenter.class.getProtectionDomain().getCodeSource().getLocation().toURI()); - } catch(URISyntaxException e) { - throw new AssertionError(); - } - } } diff --git a/phosphor-instrument-jigsaw/src/main/java/edu/columbia/cs/psl/jigsaw/phosphor/instrumenter/PhosphorPacker.java b/phosphor-instrument-jigsaw/src/main/java/edu/columbia/cs/psl/jigsaw/phosphor/instrumenter/PhosphorPacker.java index 1ebf98b29..45b7df43c 100644 --- a/phosphor-instrument-jigsaw/src/main/java/edu/columbia/cs/psl/jigsaw/phosphor/instrumenter/PhosphorPacker.java +++ b/phosphor-instrument-jigsaw/src/main/java/edu/columbia/cs/psl/jigsaw/phosphor/instrumenter/PhosphorPacker.java @@ -8,21 +8,22 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collections; import java.util.Enumeration; import java.util.HashSet; import java.util.Set; +import java.util.stream.Stream; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; class PhosphorPacker { - private final File phosphorJar; private final PhosphorPatcher patcher; + private final Set elementsToPack; - PhosphorPacker(ResourcePool pool, File phosphorJar) { - if (phosphorJar == null) { - throw new NullPointerException(); - } - this.phosphorJar = phosphorJar; + PhosphorPacker(ResourcePool pool, Set elementsToPack) { + this.elementsToPack = Collections.unmodifiableSet(new HashSet<>(elementsToPack)); ResourcePoolEntry entry = pool.findEntry("/java.base/jdk/internal/misc/Unsafe.class") .orElseThrow(() -> new IllegalArgumentException("Unable to find entry for jdk/internal/misc/Unsafe")); try (InputStream in = entry.content()) { @@ -53,10 +54,42 @@ ResourcePoolEntry pack(ResourcePoolEntry entry, ResourcePoolBuilder out) { } private Set packClasses(ResourcePoolBuilder out) throws IOException { - // Pack the Phosphor JAR into the resource pool + // Pack the JARs and directories into the resource pool // Return the set of packages for packed classes Set packages = new HashSet<>(); - try (ZipFile zip = new ZipFile(phosphorJar)) { + for (File element : elementsToPack) { + if (element.isDirectory()) { + packDirectory(out, element, packages); + } else { + packJar(out, element, packages); + } + } + return packages; + } + + private void packClass(ResourcePoolBuilder out, String name, File classFile, Set packages) { + try { + if (shouldInclude(name)) { + byte[] content = patcher.patch(name, Files.readAllBytes(classFile.toPath())); + out.add(ResourcePoolEntry.create("/java.base/" + name, content)); + packages.add(name.substring(0, name.lastIndexOf('/'))); + } + } catch (IOException e) { + throw new IllegalArgumentException("Failed to pack: " + name, e); + } + } + + private void packDirectory(ResourcePoolBuilder out, File directory, Set packages) throws IOException { + try (Stream walk = Files.walk(directory.toPath())) { + walk.filter(Files::isRegularFile) + .forEach(p -> packClass(out, directory.toPath().relativize(p).toFile().getPath(), + p.toAbsolutePath().toFile(), + packages)); + } + } + + private void packJar(ResourcePoolBuilder out, File element, Set packages) throws IOException { + try (ZipFile zip = new ZipFile(element)) { Enumeration entries = zip.entries(); while (entries.hasMoreElements()) { ZipEntry entry = entries.nextElement(); @@ -69,6 +102,5 @@ private Set packClasses(ResourcePoolBuilder out) throws IOException { } } } - return packages; } } diff --git a/phosphor-instrument-jigsaw/src/main/java/module-info.java b/phosphor-instrument-jigsaw/src/main/java/module-info.java index 36e590539..5361cd48f 100644 --- a/phosphor-instrument-jigsaw/src/main/java/module-info.java +++ b/phosphor-instrument-jigsaw/src/main/java/module-info.java @@ -1,8 +1,23 @@ module edu.columbia.cs.psl.jigsaw.phosphor.instrumenter { exports edu.columbia.cs.psl.jigsaw.phosphor.instrumenter; - opens edu.columbia.cs.psl.phosphor.instrumenter; + opens edu.columbia.cs.psl.jigsaw.phosphor.instrumenter; + opens edu.columbia.cs.psl.phosphor.instrumenter.analyzer; opens edu.columbia.cs.psl.phosphor.struct.harmony.util; + opens edu.columbia.cs.psl.phosphor.control.graph; + opens edu.columbia.cs.psl.phosphor.instrumenter; + opens edu.columbia.cs.psl.phosphor.runtime.jdk.unsupported; + opens edu.columbia.cs.psl.phosphor.control.type; + opens edu.columbia.cs.psl.phosphor.org.objectweb.asm.tree; + opens edu.columbia.cs.psl.phosphor.org.objectweb.asm.commons; + opens edu.columbia.cs.psl.phosphor.struct; + opens edu.columbia.cs.psl.phosphor.control.standard; + opens edu.columbia.cs.psl.phosphor.instrumenter.asm; + opens edu.columbia.cs.psl.phosphor.control; + opens edu.columbia.cs.psl.phosphor.org.objectweb.asm.analysis; + opens edu.columbia.cs.psl.phosphor; opens edu.columbia.cs.psl.phosphor.org.objectweb.asm; + opens edu.columbia.cs.psl.phosphor.runtime; + opens edu.columbia.cs.psl.phosphor.runtime.proxied; requires jdk.jlink; requires java.instrument; }