Skip to content

Commit 51ef193

Browse files
avagingvisor-bot
authored andcommitted
kvm: Enhance debugging of unexpected vCPU exits
This change introduces a mechanism to capture additional diagnostic information when a vCPU exits unexpectedly. PiperOrigin-RevId: 783290361
1 parent e35f635 commit 51ef193

File tree

4 files changed

+56
-17
lines changed

4 files changed

+56
-17
lines changed

pkg/sentry/platform/kvm/bluepill.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,17 @@ func (c *vCPU) die(context *arch.SignalContext64, msg string) {
9191
c.dieState.message = msg
9292

9393
// Setup the trampoline.
94-
dieArchSetup(c, context, &c.dieState.guestRegs)
94+
c.dieArchSetup(context, &c.dieState.guestRegs, false)
95+
}
96+
97+
// dieAndDumpExitReason populates registers with the vCPU's exit reason and
98+
// associated data from c.runData. Then it sets the instruction pointer to
99+
// an invalid address (0xabc) to trigger a memory fault immediately after
100+
// sigreturn.
101+
//
102+
//go:nosplit
103+
func (c *vCPU) dieAndDumpExitReason(context *arch.SignalContext64) {
104+
c.dieArchSetup(context, &c.dieState.guestRegs, true)
95105
}
96106

97107
func init() {

pkg/sentry/platform/kvm/bluepill_amd64_unsafe.go

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import (
3535
// provided RIP.
3636
//
3737
//go:nosplit
38-
func dieArchSetup(c *vCPU, context *arch.SignalContext64, guestRegs *userRegs) {
38+
func (c *vCPU) dieArchSetup(context *arch.SignalContext64, guestRegs *userRegs, dumpExitReason bool) {
3939
// Reload all registers to have an accurate stack trace when we return
4040
// to host mode. This means that the stack should be unwound correctly.
4141
if errno := c.getUserRegisters(&c.dieState.guestRegs); errno != 0 {
@@ -55,8 +55,26 @@ func dieArchSetup(c *vCPU, context *arch.SignalContext64, guestRegs *userRegs) {
5555
context.Rbp = guestRegs.RBP
5656
context.Eflags = guestRegs.RFLAGS
5757
}
58-
context.Rbx = uint64(uintptr(unsafe.Pointer(c)))
59-
context.Rip = uint64(dieTrampolineAddr)
58+
if dumpExitReason {
59+
// Store the original instruction pointer in R9 and populates
60+
// registers R10-R14 with the vCPU's exit reason and associated
61+
// data from c.runData. To ensure this information is preserved
62+
// in a crash report, RIP is set to an invalid address (0xabc).
63+
// This forces a memory fault immediately after a sigreturn,
64+
// triggering a crash report that includes the altered register
65+
// state, providing diagnostic details about why the vCPU
66+
// exited.
67+
context.R9 = context.Rip
68+
context.Rip = 0xabc
69+
context.R10 = uint64(c.runData.exitReason)
70+
context.R11 = c.runData.data[0]
71+
context.R12 = c.runData.data[1]
72+
context.R13 = c.runData.data[2]
73+
context.R14 = c.runData.data[3]
74+
} else {
75+
context.Rbx = uint64(uintptr(unsafe.Pointer(c)))
76+
context.Rip = uint64(dieTrampolineAddr)
77+
}
6078
}
6179

6280
// getHypercallID returns hypercall ID.
@@ -142,7 +160,7 @@ func bluepillReadyStopGuest(c *vCPU) bool {
142160
//
143161
//go:nosplit
144162
func bluepillArchHandleExit(c *vCPU, context unsafe.Pointer) {
145-
c.die(bluepillArchContext(context), "unknown")
163+
c.dieAndDumpExitReason(bluepillArchContext(context))
146164
}
147165

148166
func addrOfBluepillUserHandler() uintptr

pkg/sentry/platform/kvm/bluepill_arm64_unsafe.go

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ func fpsimdPtr(addr *byte) *arch.FpsimdContext {
4040
// provided PC.
4141
//
4242
//go:nosplit
43-
func dieArchSetup(c *vCPU, context *arch.SignalContext64, guestRegs *userRegs) {
43+
func (c *vCPU) dieArchSetup(context *arch.SignalContext64, guestRegs *userRegs, dumpExitReason bool) {
4444
// If the vCPU is in user mode, we set the stack to the stored stack
4545
// value in the vCPU itself. We don't want to unwind the user stack.
4646
if guestRegs.Regs.Pstate&ring0.PsrModeMask == ring0.UserFlagsSet {
@@ -54,15 +54,26 @@ func dieArchSetup(c *vCPU, context *arch.SignalContext64, guestRegs *userRegs) {
5454
context.Regs[29] = guestRegs.Regs.Regs[29]
5555
context.Pstate = guestRegs.Regs.Pstate
5656
}
57-
context.Regs[1] = uint64(uintptr(unsafe.Pointer(c)))
58-
context.Pc = uint64(dieTrampolineAddr)
59-
}
60-
61-
// bluepillArchFpContext returns the arch-specific fpsimd context.
62-
//
63-
//go:nosplit
64-
func bluepillArchFpContext(context unsafe.Pointer) *arch.FpsimdContext {
65-
return &((*arch.SignalContext64)(context).Fpsimd64)
57+
if dumpExitReason {
58+
// Store the original instruction pointer in R9 and populates
59+
// registers R10-R14 with the vCPU's exit reason and associated
60+
// data from c.runData. To ensure this information is preserved
61+
// in a crash report, PC is set to an invalid address (0xabc).
62+
// This forces a memory fault immediately after a sigreturn,
63+
// triggering a crash report that includes the altered register
64+
// state, providing diagnostic details about why the vCPU
65+
// exited.
66+
context.Regs[9] = context.Pc
67+
context.Pc = 0xabc
68+
context.Regs[10] = uint64(c.runData.exitReason)
69+
context.Regs[11] = c.runData.data[0]
70+
context.Regs[12] = c.runData.data[1]
71+
context.Regs[13] = c.runData.data[2]
72+
context.Regs[14] = c.runData.data[3]
73+
} else {
74+
context.Regs[1] = uint64(uintptr(unsafe.Pointer(c)))
75+
context.Pc = uint64(dieTrampolineAddr)
76+
}
6677
}
6778

6879
// getHypercallID returns hypercall ID.
@@ -174,6 +185,6 @@ func bluepillArchHandleExit(c *vCPU, context unsafe.Pointer) {
174185
case _KVM_EXIT_ARM_NISV:
175186
bluepillExtDabt(c)
176187
default:
177-
c.die(bluepillArchContext(context), "unknown")
188+
c.dieAndDumpExitReason(bluepillArchContext(context))
178189
}
179190
}

pkg/sentry/platform/kvm/bluepill_unsafe.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ func bluepillHandler(context unsafe.Pointer) {
219219
c.die(bluepillArchContext(context), "shutdown")
220220
return
221221
case _KVM_EXIT_FAIL_ENTRY:
222-
c.die(bluepillArchContext(context), "entry failed")
222+
c.dieAndDumpExitReason(bluepillArchContext(context))
223223
return
224224
default:
225225
bluepillArchHandleExit(c, context)

0 commit comments

Comments
 (0)