Skip to content

Commit 1a2d700

Browse files
committed
Add support for Windows x64 unwind info
1 parent 691b208 commit 1a2d700

File tree

11 files changed

+696
-40
lines changed

11 files changed

+696
-40
lines changed

substratevm/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ This changelog summarizes major changes to GraalVM Native Image.
66
* (GR-54476): Issue a deprecation warning on first use of a legacy `graal.` prefix (see GR-49960 in [Compiler changelog](../compiler/CHANGELOG.md)).
77
The warning is planned to be replaced by an error in GraalVM for JDK 25.
88
* (GR-48384) Added a GDB Python script (`gdb-debughelpers.py`) to improve the Native Image debugging experience.
9+
* (GR-49517) Add support for emitting Windows x64 unwind info. This enables stack walking in native tooling such as debuggers and profilers.
910

1011
## GraalVM for JDK 23 (Internal Version 24.1.0)
1112
* (GR-51520) The old class initialization strategy, which was deprecated in GraalVM for JDK 22, is removed. The option `StrictImageHeap` no longer has any effect.

substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,12 @@
4646
import java.util.function.Consumer;
4747
import java.util.stream.StreamSupport;
4848

49-
import jdk.graal.compiler.debug.DebugContext;
50-
5149
import com.oracle.objectfile.debuginfo.DebugInfoProvider;
5250
import com.oracle.objectfile.elf.ELFObjectFile;
5351
import com.oracle.objectfile.macho.MachOObjectFile;
5452
import com.oracle.objectfile.pecoff.PECoffObjectFile;
5553

54+
import jdk.graal.compiler.debug.DebugContext;
5655
import sun.nio.ch.DirectBuffer;
5756

5857
/**
@@ -254,6 +253,11 @@ public enum RelocationKind {
254253
DIRECT_2,
255254
DIRECT_4,
256255
DIRECT_8,
256+
/**
257+
* The relocation's symbol provides an address whose image-base-relative value (plus addend)
258+
* supplies the fixup bytes.
259+
*/
260+
ADDR32NB_4,
257261
/**
258262
* The index of the object file section containing the relocation's symbol supplies the
259263
* fixup bytes. (used in CodeView debug information)
@@ -371,6 +375,7 @@ public static int getRelocationSize(RelocationKind kind) {
371375
return 2;
372376
case DIRECT_4:
373377
case PC_RELATIVE_4:
378+
case ADDR32NB_4:
374379
case SECREL_4:
375380
return 4;
376381
case AARCH64_R_AARCH64_ADR_PREL_PG_HI21:
@@ -522,10 +527,13 @@ public interface NobitsSectionImpl extends ElementImpl {
522527
// convenience overrides when specifying neither segment nor segment name
523528

524529
public Section newUserDefinedSection(String name, ElementImpl impl) {
525-
final Segment segment = getOrCreateSegment(null, name, false, false);
526530
final int alignment = getWordSizeInBytes();
527-
final Section result = newUserDefinedSection(segment, name, alignment, impl);
528-
return result;
531+
return newUserDefinedSection(name, alignment, impl);
532+
}
533+
534+
public Section newUserDefinedSection(String name, int alignment, ElementImpl impl) {
535+
Segment segment = getOrCreateSegment(null, name, false, false);
536+
return newUserDefinedSection(segment, name, alignment, impl);
529537
}
530538

531539
public Section newDebugSection(String name, ElementImpl impl) {

substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoff.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,9 @@ enum IMAGE_RELOCATION {
195195
* Relocation types
196196
*/
197197
static final int IMAGE_REL_AMD64_ABSOLUTE = 0x0;
198-
static final int IMAGE_REL_AMD64_ADDR32 = 0x2;
199198
static final int IMAGE_REL_AMD64_ADDR64 = 0x1;
199+
static final int IMAGE_REL_AMD64_ADDR32 = 0x2;
200+
static final int IMAGE_REL_AMD64_ADDR32NB = 0x3;
200201
static final int IMAGE_REL_AMD64_REL32 = 0x4;
201202
static final int IMAGE_REL_AMD64_REL32_1 = 0x5;
202203
static final int IMAGE_REL_AMD64_REL32_2 = 0x6;

substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffMachine.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ public static PECoffRelocationMethod getRelocation(PECoffMachine m, RelocationKi
5454
return PECoffX86_64Relocation.ADDR32;
5555
case PC_RELATIVE_4:
5656
return PECoffX86_64Relocation.REL32;
57+
case ADDR32NB_4:
58+
return PECoffX86_64Relocation.ADDR32NB;
5759
case SECTION_2:
5860
return PECoffX86_64Relocation.SECTION;
5961
case SECREL_4:
@@ -125,10 +127,16 @@ public long toLong() {
125127
return IMAGE_RELOCATION.IMAGE_REL_AMD64_ADDR32;
126128
}
127129
},
128-
SECREL {
130+
ADDR32NB {
129131
@Override
130132
public long toLong() {
131-
return IMAGE_RELOCATION.IMAGE_REL_AMD64_SECREL;
133+
return IMAGE_RELOCATION.IMAGE_REL_AMD64_ADDR32NB;
134+
}
135+
},
136+
REL32 {
137+
@Override
138+
public long toLong() {
139+
return IMAGE_RELOCATION.IMAGE_REL_AMD64_REL32;
132140
}
133141
},
134142
SECTION {
@@ -137,10 +145,10 @@ public long toLong() {
137145
return IMAGE_RELOCATION.IMAGE_REL_AMD64_SECTION;
138146
}
139147
},
140-
REL32 {
148+
SECREL {
141149
@Override
142150
public long toLong() {
143-
return IMAGE_RELOCATION.IMAGE_REL_AMD64_REL32;
151+
return IMAGE_RELOCATION.IMAGE_REL_AMD64_SECREL;
144152
}
145153
};
146154
}

substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffObjectFile.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ protected Segment getOrCreateSegment(String maybeSegmentName, String sectionName
126126

127127
@Override
128128
public PECoffUserDefinedSection newUserDefinedSection(Segment segment, String name, int alignment, ElementImpl impl) {
129-
PECoffUserDefinedSection userDefined = new PECoffUserDefinedSection(this, name, alignment, impl);
129+
PECoffUserDefinedSection userDefined = new PECoffUserDefinedSection(this, name, alignment, impl, EnumSet.of(PECoffSectionFlag.INITIALIZED_DATA, PECoffSectionFlag.READ));
130130
assert userDefined.getImpl() == impl;
131131
if (segment != null) {
132132
getOrCreateSegment(segment.getName(), name, true, false).add(userDefined);

substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/FramePointerPhase.java

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import java.util.ArrayList;
2828

2929
import com.oracle.svm.core.SubstrateOptions;
30+
import com.oracle.svm.core.graal.code.SubstrateBackend.SubstrateMarkId;
3031

3132
import jdk.graal.compiler.asm.amd64.AMD64MacroAssembler;
3233
import jdk.graal.compiler.core.common.cfg.BasicBlock;
@@ -86,14 +87,13 @@ protected void run(TargetDescription target, LIRGenerationResult lirGenRes, PreA
8687
*/
8788
buffer.init(instructions);
8889
if (block.isExceptionEntry()) {
90+
buffer.append(lirGenRes.getFirstInsertPosition(), new SpillFramePointerOp(true));
8991
buffer.append(lirGenRes.getFirstInsertPosition(), new ReloadFramePointerOp());
9092
}
9193
for (int i = 0; i < instructions.size(); i++) {
9294
if (instructions.get(i) instanceof AMD64Call.CallOp callOp) {
9395
buffer.append(i, new SpillFramePointerOp());
94-
if (callOp.destroysCallerSavedRegisters()) {
95-
buffer.append(i + 1, new ReloadFramePointerOp());
96-
}
96+
buffer.append(i + 1, new ReloadFramePointerOp(!callOp.destroysCallerSavedRegisters()));
9797
}
9898
}
9999
buffer.finish();
@@ -121,29 +121,49 @@ private static boolean modifiesStackPointer(LIR lir) {
121121
public static class SpillFramePointerOp extends AMD64LIRInstruction {
122122
public static final LIRInstructionClass<SpillFramePointerOp> TYPE = LIRInstructionClass.create(SpillFramePointerOp.class);
123123

124+
private final boolean recordMarkOnly;
125+
124126
SpillFramePointerOp() {
127+
this(false);
128+
}
129+
130+
SpillFramePointerOp(boolean recordMarkOnly) {
125131
super(TYPE);
132+
this.recordMarkOnly = recordMarkOnly;
126133
}
127134

128135
@Override
129136
public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
130-
var frameMap = (SubstrateAMD64Backend.SubstrateAMD64FrameMap) crb.frameMap;
131-
masm.movq(masm.makeAddress(AMD64.rsp, frameMap.getFramePointerSaveAreaOffset()), AMD64.rbp);
137+
if (!recordMarkOnly) {
138+
var frameMap = (SubstrateAMD64Backend.SubstrateAMD64FrameMap) crb.frameMap;
139+
masm.movq(masm.makeAddress(AMD64.rsp, frameMap.getFramePointerSaveAreaOffset()), AMD64.rbp);
140+
}
141+
crb.recordMark(SubstrateMarkId.FRAME_POINTER_SPILLED);
132142
}
133143
}
134144

135145
@Opcode("RELOAD_FRAME_POINTER")
136146
public static class ReloadFramePointerOp extends AMD64LIRInstruction {
137147
public static final LIRInstructionClass<ReloadFramePointerOp> TYPE = LIRInstructionClass.create(ReloadFramePointerOp.class);
138148

149+
private final boolean recordMarkOnly;
150+
139151
ReloadFramePointerOp() {
152+
this(false);
153+
}
154+
155+
ReloadFramePointerOp(boolean recordMarkOnly) {
140156
super(TYPE);
157+
this.recordMarkOnly = recordMarkOnly;
141158
}
142159

143160
@Override
144161
public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
145-
var frameMap = (SubstrateAMD64Backend.SubstrateAMD64FrameMap) crb.frameMap;
146-
masm.movq(AMD64.rbp, masm.makeAddress(AMD64.rsp, frameMap.getFramePointerSaveAreaOffset()));
162+
if (!recordMarkOnly) {
163+
var frameMap = (SubstrateAMD64Backend.SubstrateAMD64FrameMap) crb.frameMap;
164+
masm.movq(AMD64.rbp, masm.makeAddress(AMD64.rsp, frameMap.getFramePointerSaveAreaOffset()));
165+
}
166+
crb.recordMark(SubstrateMarkId.FRAME_POINTER_RELOADED);
147167
}
148168
}
149169
}

substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626

2727
import static com.oracle.svm.core.graal.code.SubstrateBackend.SubstrateMarkId.PROLOGUE_DECD_RSP;
2828
import static com.oracle.svm.core.graal.code.SubstrateBackend.SubstrateMarkId.PROLOGUE_END;
29+
import static com.oracle.svm.core.graal.code.SubstrateBackend.SubstrateMarkId.PROLOGUE_PUSH_RBP;
30+
import static com.oracle.svm.core.graal.code.SubstrateBackend.SubstrateMarkId.PROLOGUE_SET_FRAME_POINTER;
2931
import static com.oracle.svm.core.util.VMError.shouldNotReachHere;
3032
import static com.oracle.svm.core.util.VMError.unsupportedFeature;
3133
import static jdk.graal.compiler.lir.LIRInstruction.OperandFlag.REG;
@@ -62,6 +64,7 @@
6264
import com.oracle.svm.core.graal.code.AssignedLocation;
6365
import com.oracle.svm.core.graal.code.CGlobalDataInfo;
6466
import com.oracle.svm.core.graal.code.PatchConsumerFactory;
67+
import com.oracle.svm.core.graal.code.SharedCompilationResult;
6568
import com.oracle.svm.core.graal.code.StubCallingConvention;
6669
import com.oracle.svm.core.graal.code.SubstrateBackend;
6770
import com.oracle.svm.core.graal.code.SubstrateCallingConvention;
@@ -1244,6 +1247,7 @@ protected void maybePushBasePointer(CompilationResultBuilder crb, AMD64MacroAsse
12441247
SubstrateAMD64FrameMap frameMap = (SubstrateAMD64FrameMap) crb.frameMap;
12451248
if (frameMap.preserveFramePointer() || isCalleeSaved(rbp, frameMap.getRegisterConfig(), method)) {
12461249
asm.push(rbp);
1250+
crb.recordMark(PROLOGUE_PUSH_RBP);
12471251
}
12481252
if (frameMap.preserveFramePointer() && !frameMap.needsFramePointer()) {
12491253
/* We won't be using rbp as a frame pointer, so we form a frame chain here. */
@@ -1272,6 +1276,7 @@ private static void maybeSetFramePointer(CompilationResultBuilder crb, AMD64Macr
12721276
/* Set the frame pointer to [rsp]. */
12731277
asm.movq(rbp, rsp);
12741278
}
1279+
crb.recordMark(PROLOGUE_SET_FRAME_POINTER);
12751280
}
12761281
}
12771282

@@ -1296,11 +1301,12 @@ public void leave(CompilationResultBuilder crb) {
12961301
} else {
12971302
asm.incrementq(rsp, frameMap.frameSize());
12981303
}
1304+
crb.recordMark(SubstrateMarkId.EPILOGUE_INCD_RSP);
1305+
12991306
if (frameMap.preserveFramePointer() || isCalleeSaved(rbp, frameMap.getRegisterConfig(), method)) {
13001307
asm.pop(rbp);
1308+
crb.recordMark(SubstrateMarkId.EPILOGUE_POP_RBP);
13011309
}
1302-
1303-
crb.recordMark(SubstrateMarkId.EPILOGUE_INCD_RSP);
13041310
}
13051311

13061312
@Override
@@ -1748,10 +1754,15 @@ public CompilationResultBuilder newCompilationResultBuilder(LIRGenerationResult
17481754
FrameContext frameContext = createFrameContext(method, stubType, callingConvention);
17491755
DebugContext debug = lir.getDebug();
17501756
Register uncompressedNullRegister = useLinearPointerCompression() ? ReservedRegisters.singleton().getHeapBaseRegister() : Register.None;
1751-
CompilationResultBuilder tasm = factory.createBuilder(getProviders(), lirGenResult.getFrameMap(), masm, dataBuilder, frameContext, options, debug, compilationResult,
1752-
uncompressedNullRegister, lir);
1753-
tasm.setTotalFrameSize(lirGenResult.getFrameMap().totalFrameSize());
1754-
return tasm;
1757+
CompilationResultBuilder crb = factory.createBuilder(getProviders(), frameMap, masm, dataBuilder, frameContext, options, debug, compilationResult, uncompressedNullRegister, lir);
1758+
crb.setTotalFrameSize(frameMap.totalFrameSize());
1759+
var sharedCompilationResult = (SharedCompilationResult) compilationResult;
1760+
var substrateAMD64FrameMap = (SubstrateAMD64FrameMap) frameMap;
1761+
sharedCompilationResult.setFrameSize(substrateAMD64FrameMap.frameSize());
1762+
if (substrateAMD64FrameMap.needsFramePointer()) {
1763+
sharedCompilationResult.setFramePointerSaveAreaOffset(substrateAMD64FrameMap.getFramePointerSaveAreaOffset());
1764+
}
1765+
return crb;
17551766
}
17561767

17571768
protected AMD64MacroAssembler createAssembler(OptionValues options) {
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
package com.oracle.svm.core.graal.code;
26+
27+
import jdk.graal.compiler.code.CompilationResult;
28+
import jdk.graal.compiler.core.common.CompilationIdentifier;
29+
30+
/** Base class common to both hosted and runtime compilations. */
31+
public abstract class SharedCompilationResult extends CompilationResult {
32+
private int frameSize = -1;
33+
private int framePointerSaveAreaOffset = -1;
34+
35+
public SharedCompilationResult(CompilationIdentifier compilationId, String name) {
36+
super(compilationId, name);
37+
}
38+
39+
public int getFrameSize() {
40+
assert frameSize != -1 : "frame size not set";
41+
return frameSize;
42+
}
43+
44+
public void setFrameSize(int frameSize) {
45+
this.frameSize = frameSize;
46+
}
47+
48+
public int getFramePointerSaveAreaOffset() {
49+
return framePointerSaveAreaOffset;
50+
}
51+
52+
public void setFramePointerSaveAreaOffset(int framePointerSaveAreaOffset) {
53+
this.framePointerSaveAreaOffset = framePointerSaveAreaOffset;
54+
}
55+
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/SubstrateBackend.java

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,19 @@
2828

2929
import java.lang.reflect.Method;
3030

31+
import org.graalvm.nativeimage.Platform;
32+
import org.graalvm.nativeimage.Platforms;
33+
import org.graalvm.word.LocationIdentity;
34+
35+
import com.oracle.svm.core.SubstrateUtil;
36+
import com.oracle.svm.core.graal.meta.RuntimeConfiguration;
37+
import com.oracle.svm.core.graal.nodes.ComputedIndirectCallTargetNode;
38+
import com.oracle.svm.core.graal.snippets.CFunctionSnippets;
39+
import com.oracle.svm.core.meta.SharedMethod;
40+
import com.oracle.svm.core.nodes.CFunctionPrologueDataNode;
41+
import com.oracle.svm.core.thread.VMThreads.StatusSupport;
42+
import com.oracle.svm.core.util.VMError;
43+
3144
import jdk.graal.compiler.code.CompilationResult;
3245
import jdk.graal.compiler.core.common.CompilationIdentifier;
3346
import jdk.graal.compiler.core.common.alloc.RegisterAllocationConfig;
@@ -43,19 +56,6 @@
4356
import jdk.graal.compiler.phases.BasePhase;
4457
import jdk.graal.compiler.phases.tiers.SuitesProvider;
4558
import jdk.graal.compiler.phases.util.Providers;
46-
import org.graalvm.nativeimage.Platform;
47-
import org.graalvm.nativeimage.Platforms;
48-
import org.graalvm.word.LocationIdentity;
49-
50-
import com.oracle.svm.core.SubstrateUtil;
51-
import com.oracle.svm.core.graal.meta.RuntimeConfiguration;
52-
import com.oracle.svm.core.graal.nodes.ComputedIndirectCallTargetNode;
53-
import com.oracle.svm.core.graal.snippets.CFunctionSnippets;
54-
import com.oracle.svm.core.meta.SharedMethod;
55-
import com.oracle.svm.core.nodes.CFunctionPrologueDataNode;
56-
import com.oracle.svm.core.thread.VMThreads.StatusSupport;
57-
import com.oracle.svm.core.util.VMError;
58-
5959
import jdk.vm.ci.code.CodeCacheProvider;
6060
import jdk.vm.ci.code.RegisterConfig;
6161
import jdk.vm.ci.code.RegisterValue;
@@ -70,11 +70,16 @@ public enum SubstrateMarkId implements CompilationResult.MarkId {
7070
* instructions in the compilation.
7171
*/
7272
PROLOGUE_START(true),
73+
PROLOGUE_PUSH_RBP(true),
7374
PROLOGUE_DECD_RSP(true),
75+
PROLOGUE_SET_FRAME_POINTER(true),
7476
PROLOGUE_SAVED_REGS(true),
7577
PROLOGUE_END(true),
78+
FRAME_POINTER_SPILLED(true),
79+
FRAME_POINTER_RELOADED(true),
7680
EPILOGUE_START(false),
7781
EPILOGUE_INCD_RSP(true),
82+
EPILOGUE_POP_RBP(true),
7883
EPILOGUE_END(true);
7984

8085
final boolean isMarkAfter;
@@ -149,7 +154,7 @@ public SuitesProvider getSuites() {
149154
}
150155

151156
public CompilationResult newCompilationResult(CompilationIdentifier compilationIdentifier, String name) {
152-
return new CompilationResult(compilationIdentifier, name) {
157+
return new SharedCompilationResult(compilationIdentifier, name) {
153158
@Override
154159
public void close(OptionValues options) {
155160
/*

0 commit comments

Comments
 (0)