diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/DefaultStripDebugPlugin.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/DefaultStripDebugPlugin.java index b3644bdde85..283ca11decc 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/DefaultStripDebugPlugin.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/DefaultStripDebugPlugin.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2019, Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -27,12 +28,13 @@ package jdk.tools.jlink.internal.plugins; import java.util.Map; +import jdk.tools.jlink.internal.Platform; import jdk.tools.jlink.internal.PluginRepository; import jdk.tools.jlink.internal.ResourcePoolManager; -import jdk.tools.jlink.internal.ResourcePoolManager.ResourcePoolImpl; import jdk.tools.jlink.plugin.Plugin; import jdk.tools.jlink.plugin.ResourcePool; import jdk.tools.jlink.plugin.ResourcePoolBuilder; +import jdk.tools.jlink.plugin.ResourcePoolModule; /** * Combined debug stripping plugin: Java debug attributes and native debug @@ -43,6 +45,7 @@ public final class DefaultStripDebugPlugin extends AbstractPlugin { private static final String STRIP_NATIVE_DEBUG_PLUGIN = "strip-native-debug-symbols"; private static final String EXCLUDE_DEBUGINFO = "exclude-debuginfo-files"; + private static final String EXCLUDE_FILES_PLUGIN = "exclude-files"; private final Plugin javaStripPlugin; private final NativePluginFactory stripNativePluginFactory; @@ -68,26 +71,46 @@ public final class DefaultStripDebugPlugin extends AbstractPlugin { @Override public ResourcePool transform(ResourcePool in, ResourcePoolBuilder out) { Plugin stripNativePlugin = stripNativePluginFactory.create(); - if (stripNativePlugin != null) { - Map stripNativeConfig = Map.of( - STRIP_NATIVE_DEBUG_PLUGIN, EXCLUDE_DEBUGINFO); - stripNativePlugin.configure(stripNativeConfig); - if (!isJavaStripPluginEnabled) { - return stripNativePlugin.transform(in, out); - } + String pattern = debugFilePattern(in); + ExcludeFilesPlugin excludeFilesPlugin = new ExcludeFilesPlugin(); + excludeFilesPlugin.configure(Map.of(EXCLUDE_FILES_PLUGIN, pattern)); - ResourcePoolManager outRes = - new ResourcePoolManager(in.byteOrder(), - ((ResourcePoolImpl)in).getStringTable()); - ResourcePool strippedJava = javaStripPlugin.transform(in, - outRes.resourcePoolBuilder()); - return stripNativePlugin.transform(strippedJava, out); - } else if (isJavaStripPluginEnabled) { - return javaStripPlugin.transform(in, out); - } else { - return in; + ResourcePool result = in; + if (isJavaStripPluginEnabled) { + result = pipe(result, javaStripPlugin); } + if (stripNativePlugin != null) { + stripNativePlugin.configure(Map.of(STRIP_NATIVE_DEBUG_PLUGIN, EXCLUDE_DEBUGINFO)); + result = pipe(result, stripNativePlugin); + } + return excludeFilesPlugin.transform(result, out); + } + + // Returns the glob pattern for debug files matching the target platform. + // Mirrors the per-OS exclusion logic in make/CreateJmods.gmk. + private static String debugFilePattern(ResourcePool in) { + Platform platform; + try { + String tp = in.moduleView() + .findModule("java.base") + .map(ResourcePoolModule::targetPlatform) + .orElse(null); + platform = tp != null ? Platform.parsePlatform(tp) : Platform.runtime(); + } catch (IllegalArgumentException e) { + platform = Platform.runtime(); + } + return switch (platform.os()) { + case WINDOWS -> "**.pdb,**.map,**.diz"; + case MACOS -> "**.dSYM/**,**.diz"; + default -> "**.debuginfo,**.diz"; // Linux, AIX + }; + } + + private ResourcePool pipe(ResourcePool pool, Plugin plugin) { + ResourcePoolManager mgr = new ResourcePoolManager( + pool.byteOrder(), ((ResourcePoolManager.ResourcePoolImpl)pool).getStringTable()); + return plugin.transform(pool, mgr.resourcePoolBuilder()); } public interface NativePluginFactory { diff --git a/test/jdk/tools/jlink/plugins/DefaultStripDebugPluginTest.java b/test/jdk/tools/jlink/plugins/DefaultStripDebugPluginTest.java index 379b89adc9f..c0a08093a4a 100644 --- a/test/jdk/tools/jlink/plugins/DefaultStripDebugPluginTest.java +++ b/test/jdk/tools/jlink/plugins/DefaultStripDebugPluginTest.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2019, Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -23,6 +24,7 @@ import java.util.Map; +import jdk.tools.jlink.internal.Platform; import jdk.tools.jlink.internal.ResourcePoolManager; import jdk.tools.jlink.internal.plugins.DefaultStripDebugPlugin; import jdk.tools.jlink.internal.plugins.DefaultStripDebugPlugin.NativePluginFactory; @@ -51,12 +53,23 @@ public class DefaultStripDebugPluginTest { DefaultStripDebugPlugin plugin = new DefaultStripDebugPlugin(javaPlugin, nativeFactory); ResourcePoolManager inManager = new ResourcePoolManager(); + inManager.add(ResourcePoolEntry.create(MockStripPlugin.DEBUGINFO_PATH, + ResourcePoolEntry.Type.NATIVE_LIB, new byte[]{0, 1, 2, 3})); + inManager.add(ResourcePoolEntry.create(MockStripPlugin.DIZ_PATH, + ResourcePoolEntry.Type.NATIVE_LIB, new byte[]{0, 1, 2, 3})); + ResourcePoolManager outManager = new ResourcePoolManager(); ResourcePool pool = plugin.transform(inManager.resourcePool(), - inManager.resourcePoolBuilder()); + outManager.resourcePoolBuilder()); if (!pool.findEntry(MockStripPlugin.JAVA_PATH).isPresent() || !pool.findEntry(MockStripPlugin.NATIVE_PATH).isPresent()) { throw new AssertionError("Expected both native and java to get called"); } + if (pool.findEntry(MockStripPlugin.DEBUGINFO_PATH).isPresent()) { + throw new AssertionError(".debuginfo file should have been excluded"); + } + if (pool.findEntry(MockStripPlugin.DIZ_PATH).isPresent()) { + throw new AssertionError(".diz file should have been excluded"); + } } public void testNoNativeStripPluginPresent() { @@ -66,11 +79,22 @@ public class DefaultStripDebugPluginTest { DefaultStripDebugPlugin plugin = new DefaultStripDebugPlugin(javaPlugin, nativeFactory); ResourcePoolManager inManager = new ResourcePoolManager(); + inManager.add(ResourcePoolEntry.create(MockStripPlugin.DEBUGINFO_PATH, + ResourcePoolEntry.Type.NATIVE_LIB, new byte[]{0, 1, 2, 3})); + inManager.add(ResourcePoolEntry.create(MockStripPlugin.DIZ_PATH, + ResourcePoolEntry.Type.NATIVE_LIB, new byte[]{0, 1, 2, 3})); + ResourcePoolManager outManager = new ResourcePoolManager(); ResourcePool pool = plugin.transform(inManager.resourcePool(), - inManager.resourcePoolBuilder()); + outManager.resourcePoolBuilder()); if (!pool.findEntry(MockStripPlugin.JAVA_PATH).isPresent()) { throw new AssertionError("Expected java strip plugin to get called"); } + if (pool.findEntry(MockStripPlugin.DEBUGINFO_PATH).isPresent()) { + throw new AssertionError(".debuginfo file should have been excluded"); + } + if (pool.findEntry(MockStripPlugin.DIZ_PATH).isPresent()) { + throw new AssertionError(".diz file should have been excluded"); + } } // Disable embedded strip Java plugin, with native plugin present. @@ -84,12 +108,23 @@ public class DefaultStripDebugPluginTest { plugin.enableJavaStripPlugin(false); ResourcePoolManager inManager = new ResourcePoolManager(); + inManager.add(ResourcePoolEntry.create(MockStripPlugin.DEBUGINFO_PATH, + ResourcePoolEntry.Type.NATIVE_LIB, new byte[]{0, 1, 2, 3})); + inManager.add(ResourcePoolEntry.create(MockStripPlugin.DIZ_PATH, + ResourcePoolEntry.Type.NATIVE_LIB, new byte[]{0, 1, 2, 3})); + ResourcePoolManager outManager = new ResourcePoolManager(); ResourcePool pool = plugin.transform(inManager.resourcePool(), - inManager.resourcePoolBuilder()); + outManager.resourcePoolBuilder()); if (pool.findEntry(MockStripPlugin.JAVA_PATH).isPresent() || !pool.findEntry(MockStripPlugin.NATIVE_PATH).isPresent()) { throw new AssertionError("Expected only native to get called"); } + if (pool.findEntry(MockStripPlugin.DEBUGINFO_PATH).isPresent()) { + throw new AssertionError(".debuginfo file should have been excluded"); + } + if (pool.findEntry(MockStripPlugin.DIZ_PATH).isPresent()) { + throw new AssertionError(".diz file should have been excluded"); + } } // Disable embedded strip Java plugin, and without native plugin present. @@ -101,12 +136,23 @@ public class DefaultStripDebugPluginTest { nativeFactory); plugin.enableJavaStripPlugin(false); ResourcePoolManager inManager = new ResourcePoolManager(); + inManager.add(ResourcePoolEntry.create(MockStripPlugin.DEBUGINFO_PATH, + ResourcePoolEntry.Type.NATIVE_LIB, new byte[]{0, 1, 2, 3})); + inManager.add(ResourcePoolEntry.create(MockStripPlugin.DIZ_PATH, + ResourcePoolEntry.Type.NATIVE_LIB, new byte[]{0, 1, 2, 3})); + ResourcePoolManager outManager = new ResourcePoolManager(); ResourcePool pool = plugin.transform(inManager.resourcePool(), - inManager.resourcePoolBuilder()); + outManager.resourcePoolBuilder()); if (pool.findEntry(MockStripPlugin.JAVA_PATH).isPresent() || pool.findEntry(MockStripPlugin.NATIVE_PATH).isPresent()) { throw new AssertionError("Expected both native and java not called"); } + if (pool.findEntry(MockStripPlugin.DEBUGINFO_PATH).isPresent()) { + throw new AssertionError(".debuginfo file should have been excluded"); + } + if (pool.findEntry(MockStripPlugin.DIZ_PATH).isPresent()) { + throw new AssertionError(".diz file should have been excluded"); + } } public static void main(String[] args) { @@ -121,10 +167,25 @@ public class DefaultStripDebugPluginTest { private static final String NATIVE_PATH = "/foo/lib/test.so.debug"; private static final String JAVA_PATH = "/foo/TestClass.class"; + // Platform-appropriate debug file paths, matching the patterns chosen by + // DefaultStripDebugPlugin.debugFilePattern() for the runtime platform. + static final String DEBUGINFO_PATH = platformDebugPath(); + static final String DIZ_PATH = "/foo/lib/libfoo.diz"; private static final String STRIP_NATIVE_NAME = "strip-native-debug-symbols"; private static final String OMIT_ARG = "exclude-debuginfo-files"; private final boolean isNative; + private static String platformDebugPath() { + String platform = Platform.runtime().toString(); + if (platform.startsWith("windows")) { + return "/foo/bin/libfoo.pdb"; + } else if (platform.startsWith("macos")) { + return "/foo/lib/libfoo.dylib.dSYM/Contents/Resources/DWARF/libfoo.dylib"; + } else { + return "/foo/lib/libfoo.so.debuginfo"; + } + } + MockStripPlugin(boolean isNative) { this.isNative = isNative; } @@ -153,8 +214,7 @@ public class DefaultStripDebugPluginTest { resPath = NATIVE_PATH; type = Type.NATIVE_LIB; } - ResourcePoolEntry entry = createMockEntry(resPath, type); - out.add(entry); + out.add(createMockEntry(resPath, type)); return out.build(); }