Skip to content

Commit beba41a

Browse files
committed
[GR-41196] Provide .debug.* sections that contain build options and properties used in the build of an image.
PullRequest: graal/12960
2 parents 63fe3b8 + 46a2e20 commit beba41a

File tree

9 files changed

+105
-65
lines changed

9 files changed

+105
-65
lines changed

substratevm/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ This changelog summarizes major changes to GraalVM Native Image.
44

55
## Version 23.0.0
66
* (GR-40187) Report invalid use of SVM specific classes on image class- or module-path as error. As a temporary workaround, -H:+TolerateBuilderClassesOnImageClasspath allows turning the error into a warning.
7+
* (GR-41196) Provide `.debug.svm.imagebuild.*` sections that contain build options and properties used in the build of the image.
78

89
## Version 22.3.0
910
* (GR-35721) Remove old build output style and the `-H:±BuildOutputUseNewStyle` option.

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,9 @@ public static Path getDebugInfoSourceCacheRoot() {
665665
@Option(help = "Omit generation of DebugLineInfo originating from inlined methods") //
666666
public static final HostedOptionKey<Boolean> OmitInlinedMethodDebugLineInfo = new HostedOptionKey<>(true);
667667

668+
@Option(help = "Emit debuginfo debug.svm.imagebuild.* sections with detailed image-build options.")//
669+
public static final HostedOptionKey<Boolean> UseImagebuildDebugSections = new HostedOptionKey<>(true);
670+
668671
@Fold
669672
public static boolean supportCompileInIsolates() {
670673
UserError.guarantee(!ConcealedOptions.SupportCompileInIsolates.getValue() || SpawnIsolates.getValue(),

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageClassLoaderSupport.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,8 +191,8 @@ public void loadAllClasses(ForkJoinPool executor, ImageClassLoader imageClassLoa
191191
private List<String> remainingArguments;
192192

193193
public void setupHostedOptionParser(List<String> arguments) {
194-
hostedOptionParser = new HostedOptionParser(getClassLoader());
195-
remainingArguments = Collections.unmodifiableList((hostedOptionParser.parse(arguments)));
194+
hostedOptionParser = new HostedOptionParser(getClassLoader(), arguments);
195+
remainingArguments = Collections.unmodifiableList((hostedOptionParser.parse()));
196196
parsedHostedOptions = new OptionValues(hostedOptionParser.getHostedValues());
197197
}
198198

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/AbstractImage.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,9 +131,7 @@ public NativeLibraries getNativeLibs() {
131131
public abstract void build(String imageName, DebugContext debug);
132132

133133
/**
134-
* Write the image to the named file. This also writes debug information -- either to the same
135-
* or a different file, as decided by the implementation of {@link #getOrCreateDebugObjectFile}.
136-
* If {@link #getOrCreateDebugObjectFile} is not called, no debug information is written.
134+
* Write the image to the named file.
137135
*/
138136
public abstract LinkerInvocation write(DebugContext debug, Path outputDirectory, Path tempDirectory, String imageName, BeforeImageWriteAccessImpl config);
139137

@@ -166,7 +164,7 @@ public NativeImageHeap getHeap() {
166164

167165
public abstract long getImageHeapSize();
168166

169-
public abstract ObjectFile getOrCreateDebugObjectFile();
167+
public abstract ObjectFile getObjectFile();
170168

171169
public boolean requiresCustomDebugRelocation() {
172170
return false;

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,6 @@
6363

6464
import com.oracle.graal.pointsto.meta.AnalysisMethod;
6565
import com.oracle.graal.pointsto.meta.AnalysisType;
66-
import com.oracle.graal.pointsto.util.Timer;
67-
import com.oracle.graal.pointsto.util.TimerCollection;
6866
import com.oracle.objectfile.BasicProgbitsSectionImpl;
6967
import com.oracle.objectfile.BuildDependency;
7068
import com.oracle.objectfile.LayoutDecision;
@@ -75,7 +73,6 @@
7573
import com.oracle.objectfile.ObjectFile.RelocationKind;
7674
import com.oracle.objectfile.ObjectFile.Section;
7775
import com.oracle.objectfile.SectionName;
78-
import com.oracle.objectfile.debuginfo.DebugInfoProvider;
7976
import com.oracle.svm.core.BuildArtifacts;
8077
import com.oracle.svm.core.BuildArtifacts.ArtifactType;
8178
import com.oracle.svm.core.FrameAccess;
@@ -92,18 +89,16 @@
9289
import com.oracle.svm.core.c.CUnsigned;
9390
import com.oracle.svm.core.c.function.GraalIsolateHeader;
9491
import com.oracle.svm.core.config.ConfigurationValues;
92+
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
9593
import com.oracle.svm.core.feature.InternalFeature;
9694
import com.oracle.svm.core.graal.code.CGlobalDataInfo;
9795
import com.oracle.svm.core.graal.code.CGlobalDataReference;
9896
import com.oracle.svm.core.image.ImageHeapLayoutInfo;
9997
import com.oracle.svm.core.image.ImageHeapPartition;
10098
import com.oracle.svm.core.meta.MethodPointer;
101-
import com.oracle.svm.core.option.HostedOptionValues;
102-
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
10399
import com.oracle.svm.core.util.UserError;
104100
import com.oracle.svm.hosted.FeatureImpl;
105101
import com.oracle.svm.hosted.NativeImageOptions;
106-
import com.oracle.svm.hosted.ProgressReporter;
107102
import com.oracle.svm.hosted.c.CGlobalDataFeature;
108103
import com.oracle.svm.hosted.c.NativeLibraries;
109104
import com.oracle.svm.hosted.c.codegen.CSourceCodeWriter;
@@ -112,7 +107,6 @@
112107
import com.oracle.svm.hosted.code.CEntryPointData;
113108
import com.oracle.svm.hosted.image.NativeImageHeap.ObjectInfo;
114109
import com.oracle.svm.hosted.image.RelocatableBuffer.Info;
115-
import com.oracle.svm.hosted.image.sources.SourceManager;
116110
import com.oracle.svm.hosted.meta.HostedMetaAccess;
117111
import com.oracle.svm.hosted.meta.HostedMethod;
118112
import com.oracle.svm.hosted.meta.HostedUniverse;
@@ -465,18 +459,6 @@ public void build(String imageName, DebugContext debug) {
465459
(offset, symbolName, isGlobalSymbol) -> defineRelocationForSymbol(symbolName, offset));
466460
defineDataSymbol(CGlobalDataInfo.CGLOBALDATA_BASE_SYMBOL_NAME, rwDataSection, RWDATA_CGLOBALS_PARTITION_OFFSET);
467461

468-
/*
469-
* If we constructed debug info give the object file a chance to install it
470-
*/
471-
if (SubstrateOptions.GenerateDebugInfo.getValue(HostedOptionValues.singleton()) > 0) {
472-
Timer timer = TimerCollection.singleton().get(TimerCollection.Registry.DEBUG_INFO);
473-
try (Timer.StopTimer t = timer.start()) {
474-
ImageSingletons.add(SourceManager.class, new SourceManager());
475-
DebugInfoProvider provider = new NativeImageDebugInfoProvider(debug, codeCache, heap, metaAccess);
476-
objectFile.installDebugInfo(provider);
477-
}
478-
ProgressReporter.singleton().setDebugInfoTimer(timer);
479-
}
480462
// - Write the heap to its own section.
481463
// Dynamic linkers/loaders generally don't ensure any alignment to more than page
482464
// boundaries, so we take care of this ourselves in CommittedMemoryProvider, if we can.
@@ -770,13 +752,8 @@ public long getImageHeapSize() {
770752
}
771753

772754
@Override
773-
public ObjectFile getOrCreateDebugObjectFile() {
774-
assert objectFile != null;
775-
/*
776-
* FIXME: use ObjectFile.getOrCreateDebugObject, which knows how/whether to split (but is
777-
* somewhat unimplemented right now, i.e. doesn't actually implement splitting, even on
778-
* Mach-O where this is customary).
779-
*/
755+
public ObjectFile getObjectFile() {
756+
assert objectFile != null : "objectFile accessed before set";
780757
return objectFile;
781758
}
782759

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoFeature.java

Lines changed: 83 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,24 +24,48 @@
2424
*/
2525
package com.oracle.svm.hosted.image;
2626

27+
import java.lang.management.ManagementFactory;
28+
import java.nio.file.Path;
29+
import java.util.List;
30+
import java.util.function.Function;
31+
import java.util.stream.Collectors;
32+
33+
import org.graalvm.compiler.debug.DebugContext;
34+
import org.graalvm.compiler.printer.GraalDebugHandlersFactory;
35+
import org.graalvm.nativeimage.ImageSingletons;
36+
import org.graalvm.nativeimage.Platform;
37+
38+
import com.oracle.graal.pointsto.util.GraalAccess;
39+
import com.oracle.graal.pointsto.util.Timer;
40+
import com.oracle.graal.pointsto.util.TimerCollection;
41+
import com.oracle.objectfile.BasicProgbitsSectionImpl;
42+
import com.oracle.objectfile.debuginfo.DebugInfoProvider;
43+
import com.oracle.objectfile.io.AssemblyBuffer;
44+
import com.oracle.svm.core.SubstrateOptions;
2745
import com.oracle.svm.core.UniqueShortNameProvider;
2846
import com.oracle.svm.core.UniqueShortNameProviderDefaultImpl;
2947
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
3048
import com.oracle.svm.core.feature.InternalFeature;
49+
import com.oracle.svm.core.option.HostedOptionValues;
3150
import com.oracle.svm.hosted.FeatureImpl;
32-
import org.graalvm.nativeimage.ImageSingletons;
51+
import com.oracle.svm.hosted.ProgressReporter;
52+
import com.oracle.svm.hosted.image.sources.SourceManager;
3353

34-
import java.util.List;
35-
36-
/**
37-
* An automatic feature class which ensures that the Linux debug unique short name provider is
38-
* registered when generating debug info for Linux.
39-
*/
4054
@AutomaticallyRegisteredFeature
4155
@SuppressWarnings("unused")
4256
class NativeImageDebugInfoFeature implements InternalFeature {
57+
58+
@Override
59+
public boolean isInConfiguration(IsInConfigurationAccess access) {
60+
return SubstrateOptions.GenerateDebugInfo.getValue() > 0;
61+
}
62+
4363
@Override
4464
public void afterRegistration(AfterRegistrationAccess access) {
65+
/*
66+
* Ensure that the Linux debug unique short name provider is registered when generating
67+
* debug info for Linux.
68+
*/
4569
if (!UniqueShortNameProviderDefaultImpl.UseDefault.useDefaultProvider()) {
4670
if (!ImageSingletons.contains(UniqueShortNameProvider.class)) {
4771
// configure a BFD mangler to provide unique short names for method and field
@@ -62,4 +86,56 @@ public void afterRegistration(AfterRegistrationAccess access) {
6286
}
6387
}
6488
}
89+
90+
@Override
91+
@SuppressWarnings("try")
92+
public void beforeImageWrite(BeforeImageWriteAccess access) {
93+
Timer timer = TimerCollection.singleton().get(TimerCollection.Registry.DEBUG_INFO);
94+
try (Timer.StopTimer t = timer.start()) {
95+
ImageSingletons.add(SourceManager.class, new SourceManager());
96+
var accessImpl = (FeatureImpl.BeforeImageWriteAccessImpl) access;
97+
var image = accessImpl.getImage();
98+
var debugContext = new DebugContext.Builder(HostedOptionValues.singleton(), new GraalDebugHandlersFactory(GraalAccess.getOriginalSnippetReflection())).build();
99+
DebugInfoProvider provider = new NativeImageDebugInfoProvider(debugContext, image.getCodeCache(), image.getHeap(), accessImpl.getHostedMetaAccess());
100+
var objectFile = image.getObjectFile();
101+
objectFile.installDebugInfo(provider);
102+
103+
if (Platform.includedIn(Platform.LINUX.class) && SubstrateOptions.UseImagebuildDebugSections.getValue()) {
104+
/*-
105+
* Provide imagebuild infos as special debug.svm.imagebuild.* sections
106+
* The contents of these sections can be dumped with:
107+
* readelf -p .<sectionName> <debuginfo file>
108+
* e.g. readelf -p .debug.svm.imagebuild.arguments helloworld
109+
*/
110+
Function<List<String>, BasicProgbitsSectionImpl> makeSectionImpl = customInfo -> {
111+
var content = AssemblyBuffer.createOutputAssembler(objectFile.getByteOrder());
112+
for (String elem : customInfo) {
113+
content.writeString(elem);
114+
}
115+
return new BasicProgbitsSectionImpl(content.getBlob()) {
116+
@Override
117+
public boolean isLoadable() {
118+
return false;
119+
}
120+
};
121+
};
122+
123+
var imageClassLoader = accessImpl.getImageClassLoader();
124+
125+
var classPath = imageClassLoader.classpath().stream().map(Path::toString).collect(Collectors.toList());
126+
objectFile.newUserDefinedSection(".debug.svm.imagebuild.classpath", makeSectionImpl.apply(classPath));
127+
var modulePath = imageClassLoader.modulepath().stream().map(Path::toString).collect(Collectors.toList());
128+
objectFile.newUserDefinedSection(".debug.svm.imagebuild.modulepath", makeSectionImpl.apply(modulePath));
129+
/* Get original arguments that got passed to the builder when it got started */
130+
var builderArguments = imageClassLoader.classLoaderSupport.getHostedOptionParser().getArguments();
131+
objectFile.newUserDefinedSection(".debug.svm.imagebuild.arguments", makeSectionImpl.apply(builderArguments));
132+
/* System properties that got passed to the VM that runs the builder */
133+
var builderProperties = ManagementFactory.getRuntimeMXBean().getInputArguments().stream()
134+
.filter(arg -> arg.startsWith("-D"))
135+
.sorted().collect(Collectors.toList());
136+
objectFile.newUserDefinedSection(".debug.svm.imagebuild.java.properties", makeSectionImpl.apply(builderProperties));
137+
}
138+
}
139+
ProgressReporter.singleton().setDebugInfoTimer(timer);
140+
}
65141
}

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageViaCC.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ public LinkerInvocation write(DebugContext debug, Path outputDirectory, Path tem
107107
*/
108108

109109
LinkerInvocation inv = CCLinkerInvocation.getLinkerInvocation(imageKind, nativeLibs, codeCache.getCCInputFiles(tempDirectory, imageName),
110-
outputDirectory, tempDirectory, imageName, codeCache.getSymbols(this.getOrCreateDebugObjectFile()));
110+
outputDirectory, tempDirectory, imageName, codeCache.getSymbols(getObjectFile()));
111111
for (Function<LinkerInvocation, LinkerInvocation> fn : config.getLinkerInvocationTransformers()) {
112112
inv = fn.apply(inv);
113113
}

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/option/HostedOptionParser.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import static com.oracle.svm.core.util.VMError.shouldNotReachHere;
2929

3030
import java.util.ArrayList;
31+
import java.util.Collections;
3132
import java.util.HashSet;
3233
import java.util.List;
3334
import java.util.ServiceLoader;
@@ -49,12 +50,14 @@
4950

5051
public class HostedOptionParser implements HostedOptionProvider {
5152

53+
private final List<String> arguments;
5254
private EconomicMap<OptionKey<?>, Object> hostedValues = OptionValues.newOptionMap();
5355
private EconomicMap<OptionKey<?>, Object> runtimeValues = OptionValues.newOptionMap();
5456
private EconomicMap<String, OptionDescriptor> allHostedOptions = EconomicMap.create();
5557
private EconomicMap<String, OptionDescriptor> allRuntimeOptions = EconomicMap.create();
5658

57-
public HostedOptionParser(ClassLoader imageClassLoader) {
59+
public HostedOptionParser(ClassLoader imageClassLoader, List<String> arguments) {
60+
this.arguments = Collections.unmodifiableList(arguments);
5861
collectOptions(ServiceLoader.load(OptionDescriptors.class, imageClassLoader), allHostedOptions, allRuntimeOptions);
5962
}
6063

@@ -83,12 +86,12 @@ public static void collectOptions(ServiceLoader<OptionDescriptors> optionDescrip
8386
});
8487
}
8588

86-
public List<String> parse(List<String> args) {
89+
public List<String> parse() {
8790

8891
List<String> remainingArgs = new ArrayList<>();
8992
Set<String> errors = new HashSet<>();
9093
InterruptImageBuilding interrupt = null;
91-
for (String arg : args) {
94+
for (String arg : arguments) {
9295
boolean isImageBuildOption = false;
9396
try {
9497
isImageBuildOption |= SubstrateOptionsParser.parseHostedOption(SubstrateOptionsParser.HOSTED_OPTION_PREFIX, allHostedOptions, hostedValues, PLUS_MINUS, errors, arg, System.out);
@@ -125,6 +128,10 @@ public List<String> parse(List<String> args) {
125128
return remainingArgs;
126129
}
127130

131+
public List<String> getArguments() {
132+
return arguments;
133+
}
134+
128135
@Override
129136
public EconomicMap<OptionKey<?>, Object> getHostedValues() {
130137
return hostedValues;

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/option/HostedOptionProvider.java

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -24,33 +24,11 @@
2424
*/
2525
package com.oracle.svm.hosted.option;
2626

27-
import java.util.ArrayList;
28-
import java.util.List;
29-
3027
import org.graalvm.collections.EconomicMap;
31-
import org.graalvm.collections.MapCursor;
3228
import org.graalvm.compiler.options.OptionKey;
3329

34-
import com.oracle.svm.core.option.SubstrateOptionsParser;
35-
3630
public interface HostedOptionProvider {
3731
EconomicMap<OptionKey<?>, Object> getHostedValues();
3832

3933
EconomicMap<OptionKey<?>, Object> getRuntimeValues();
40-
41-
default List<String> getAppliedArguments() {
42-
List<String> result = new ArrayList<>();
43-
HostedOptionProviderHelper.addArguments(result, SubstrateOptionsParser.HOSTED_OPTION_PREFIX, getHostedValues());
44-
HostedOptionProviderHelper.addArguments(result, SubstrateOptionsParser.RUNTIME_OPTION_PREFIX, getRuntimeValues());
45-
return result;
46-
}
47-
}
48-
49-
class HostedOptionProviderHelper {
50-
static void addArguments(List<String> result, String prefix, EconomicMap<OptionKey<?>, Object> values) {
51-
MapCursor<OptionKey<?>, Object> cursor = values.getEntries();
52-
while (cursor.advance()) {
53-
result.add(prefix + cursor.getKey().getName() + "=" + cursor.getValue());
54-
}
55-
}
5634
}

0 commit comments

Comments
 (0)