diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java index 1d3d2e08baeb..889e0404ab29 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java @@ -748,8 +748,12 @@ public static int codeAlignment() { public static final HostedOptionKey GenerateDebugInfo = new HostedOptionKey<>(0, SubstrateOptions::validateGenerateDebugInfo) { @Override protected void onValueUpdate(EconomicMap, Object> values, Integer oldValue, Integer newValue) { - if (OS.WINDOWS.isCurrent()) { - /* Keep symbols on Windows. The symbol table is part of the pdb-file. */ + if (!OS.DARWIN.isCurrent()) { + /* + * Keep the symbol table, as it may be used by debugging or profiling tools (e.g., + * perf). On Windows, the symbol table is included in the pdb-file, while on Linux, + * it is part of the .debug file. + */ DeleteLocalSymbols.update(values, newValue == 0); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoStripFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoStripFeature.java index 3d454d147768..982aad62ef8e 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoStripFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoStripFeature.java @@ -28,10 +28,8 @@ import java.nio.file.Files; import java.nio.file.Path; -import jdk.graal.compiler.debug.DebugContext; -import jdk.graal.compiler.debug.DebugContext.Builder; -import jdk.graal.compiler.debug.Indent; -import jdk.graal.compiler.printer.GraalDebugHandlersFactory; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.impl.InternalPlatform; import com.oracle.graal.pointsto.util.GraalAccess; import com.oracle.objectfile.ObjectFile; @@ -47,12 +45,18 @@ import com.oracle.svm.hosted.c.util.FileUtils; import com.oracle.svm.util.LogUtils; +import jdk.graal.compiler.core.common.SuppressFBWarnings; +import jdk.graal.compiler.debug.DebugContext; +import jdk.graal.compiler.debug.DebugContext.Builder; +import jdk.graal.compiler.debug.Indent; +import jdk.graal.compiler.printer.GraalDebugHandlersFactory; + @AutomaticallyRegisteredFeature public class NativeImageDebugInfoStripFeature implements InternalFeature { @Override public boolean isInConfiguration(IsInConfigurationAccess access) { - return SubstrateOptions.useDebugInfoGeneration() && SubstrateOptions.StripDebugInfo.getValue(); + return SubstrateOptions.StripDebugInfo.getValue(); } @SuppressWarnings("try") @@ -77,13 +81,17 @@ public void afterImageWrite(AfterImageWriteAccess access) { } } + @SuppressFBWarnings(value = "", justification = "FB reports null pointer dereferencing although it is not possible in this case.") private static void stripLinux(AfterImageWriteAccessImpl accessImpl) { String objcopyExe = "objcopy"; String debugExtension = ".debug"; Path imagePath = accessImpl.getImagePath(); + if (imagePath == null) { + assert !Platform.includedIn(InternalPlatform.NATIVE_ONLY.class); + return; + } + Path imageName = imagePath.getFileName(); - Path outputDirectory = imagePath.getParent(); - String debugInfoName = imageName + debugExtension; boolean objcopyAvailable = false; try { objcopyAvailable = FileUtils.executeCommand(objcopyExe, "--version") == 0; @@ -94,16 +102,21 @@ private static void stripLinux(AfterImageWriteAccessImpl accessImpl) { } if (!objcopyAvailable) { - LogUtils.warning("%s not available. Skipping generation of separate debuginfo file %s, debuginfo will remain embedded in the executable.", objcopyExe, debugInfoName); + LogUtils.warning("%s not available. The debuginfo will remain embedded in the executable.", objcopyExe); } else { try { + Path outputDirectory = imagePath.getParent(); String imageFilePath = outputDirectory.resolve(imageName).toString(); - Path debugInfoFilePath = outputDirectory.resolve(debugInfoName); - FileUtils.executeCommand(objcopyExe, "--only-keep-debug", imageFilePath, debugInfoFilePath.toString()); - BuildArtifacts.singleton().add(ArtifactType.DEBUG_INFO, debugInfoFilePath); + if (SubstrateOptions.useDebugInfoGeneration()) { + /* Generate a separate debug file before stripping the executable. */ + String debugInfoName = imageName + debugExtension; + Path debugInfoFilePath = outputDirectory.resolve(debugInfoName); + FileUtils.executeCommand(objcopyExe, "--only-keep-debug", imageFilePath, debugInfoFilePath.toString()); + BuildArtifacts.singleton().add(ArtifactType.DEBUG_INFO, debugInfoFilePath); + FileUtils.executeCommand(objcopyExe, "--add-gnu-debuglink=" + debugInfoFilePath, imageFilePath); + } Path exportedSymbolsPath = createKeepSymbolsListFile(accessImpl); FileUtils.executeCommand(objcopyExe, "--strip-all", "--keep-symbols=" + exportedSymbolsPath, imageFilePath); - FileUtils.executeCommand(objcopyExe, "--add-gnu-debuglink=" + debugInfoFilePath, imageFilePath); } catch (IOException e) { throw UserError.abort("Generation of separate debuginfo file failed", e); } catch (InterruptedException e) { @@ -114,7 +127,7 @@ private static void stripLinux(AfterImageWriteAccessImpl accessImpl) { private static Path createKeepSymbolsListFile(AfterImageWriteAccessImpl accessImpl) throws IOException { Path exportedSymbolsPath = accessImpl.getTempDirectory().resolve("keep-symbols.list").toAbsolutePath(); - Files.write(exportedSymbolsPath, accessImpl.getImageSymbols(false)); + Files.write(exportedSymbolsPath, accessImpl.getImageSymbols(true)); return exportedSymbolsPath; } }