mirror of
https://github.com/go-delve/delve.git
synced 2025-11-01 12:01:35 +08:00
proc: fix RFLAGS corruption after call injection on amd64 (#3002)
debugCallV2 for amd64 has a bug where it corrupts the flags registers every time it is called, this commit works around that problem by restoring flags one extra time to its original value after stepping out of debugCallV2. Fixes #2985
This commit is contained in:
committed by
GitHub
parent
51090f003b
commit
b53fcbe43a
@ -5852,3 +5852,59 @@ func TestStepIntoAutogeneratedSkip(t *testing.T) {
|
||||
assertLineNumber(p, t, 12, "After step")
|
||||
})
|
||||
}
|
||||
|
||||
func TestCallInjectionFlagCorruption(t *testing.T) {
|
||||
// debugCallV2 has a bug in amd64 where its tail corrupts the FLAGS register by running an ADD instruction.
|
||||
// Since this problem exists in many versions of Go, instead of fixing
|
||||
// debugCallV2, we work around this problem by restoring FLAGS, one extra
|
||||
// time, after stepping out of debugCallV2.
|
||||
// Fixes issue https://github.com/go-delve/delve/issues/2985
|
||||
skipUnlessOn(t, "not relevant", "amd64")
|
||||
|
||||
withTestProcessArgs("badflags", t, ".", []string{"0"}, 0, func(p *proc.Target, fixture protest.Fixture) {
|
||||
mainfn := p.BinInfo().LookupFunc["main.main"]
|
||||
|
||||
// Find JNZ instruction on line :14
|
||||
var addr uint64
|
||||
text, err := proc.Disassemble(p.Memory(), nil, p.Breakpoints(), p.BinInfo(), mainfn.Entry, mainfn.End)
|
||||
assertNoError(err, t, "Disassemble")
|
||||
for _, instr := range text {
|
||||
if instr.Loc.Line != 14 {
|
||||
continue
|
||||
}
|
||||
if proc.IsJNZ(instr.Inst) {
|
||||
addr = instr.Loc.PC
|
||||
}
|
||||
}
|
||||
if addr == 0 {
|
||||
t.Fatalf("Could not find JNZ instruction at line :14")
|
||||
}
|
||||
|
||||
// Create breakpoint
|
||||
_, err = p.SetBreakpoint(0, addr, proc.UserBreakpoint, nil)
|
||||
assertNoError(err, t, "SetBreakpoint")
|
||||
|
||||
// Continue to breakpoint
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
assertLineNumber(p, t, 14, "expected line :14")
|
||||
|
||||
// Save RFLAGS register
|
||||
rflagsBeforeCall := p.BinInfo().Arch.RegistersToDwarfRegisters(0, getRegisters(p, t)).Uint64Val(regnum.AMD64_Rflags)
|
||||
t.Logf("rflags before = %#x", rflagsBeforeCall)
|
||||
|
||||
// Inject call to main.g()
|
||||
assertNoError(proc.EvalExpressionWithCalls(p, p.SelectedGoroutine(), "g()", normalLoadConfig, true), t, "Call")
|
||||
|
||||
// Check RFLAGS register after the call
|
||||
rflagsAfterCall := p.BinInfo().Arch.RegistersToDwarfRegisters(0, getRegisters(p, t)).Uint64Val(regnum.AMD64_Rflags)
|
||||
t.Logf("rflags after = %#x", rflagsAfterCall)
|
||||
|
||||
if rflagsBeforeCall != rflagsAfterCall {
|
||||
t.Errorf("mismatched rflags value")
|
||||
}
|
||||
|
||||
// Single step and check where we end up
|
||||
assertNoError(p.Step(), t, "Step()")
|
||||
assertLineNumber(p, t, 17, "expected line :17") // since we passed "0" as argument we should be going into the false branch at line :17
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user