Skip to content

Commit 775c923

Browse files
authored
proc: support reading deferred calls' arguments on linux/arm64 (go-delve#2210)
1 parent 1a782d3 commit 775c923

File tree

5 files changed

+20
-10
lines changed

5 files changed

+20
-10
lines changed

Documentation/backend_test_health.md

+1-2
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@ Tests skipped by each supported backend:
33
* 386 skipped = 2.1% (3/145)
44
* 1 broken
55
* 2 broken - cgo stacktraces
6-
* arm64 skipped = 2.8% (4/145)
6+
* arm64 skipped = 2.1% (3/145)
77
* 2 broken
88
* 1 broken - global variable symbolication
9-
* 1 broken - reading defers
109
* darwin/lldb skipped = 0.69% (1/145)
1110
* 1 upstream issue
1211
* freebsd skipped = 7.6% (11/145)

pkg/proc/arch.go

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ type Arch struct {
1515
breakpointInstruction []byte
1616
breakInstrMovesPC bool
1717
derefTLS bool
18+
usesLR bool // architecture uses a link register, also called RA on some architectures
1819

1920
// asmDecode decodes the assembly instruction starting at mem[0:] into asmInst.
2021
// It assumes that the Loc and AtPC fields of asmInst have already been filled.

pkg/proc/arm64_arch.go

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ func ARM64Arch(goos string) *Arch {
4040
DwarfRegisterToString: arm64DwarfRegisterToString,
4141
inhibitStepInto: func(*BinaryInfo, uint64) bool { return false },
4242
asmDecode: arm64AsmDecode,
43+
usesLR: true,
4344
}
4445
}
4546

pkg/proc/proc_test.go

-1
Original file line numberDiff line numberDiff line change
@@ -4160,7 +4160,6 @@ func TestNextUnknownInstr(t *testing.T) {
41604160
}
41614161

41624162
func TestReadDeferArgs(t *testing.T) {
4163-
skipOn(t, "broken - reading defers", "arm64")
41644163
var tests = []struct {
41654164
frame, deferCall int
41664165
a, b int64

pkg/proc/stack.go

+17-7
Original file line numberDiff line numberDiff line change
@@ -660,13 +660,23 @@ func (d *Defer) EvalScope(thread Thread) (*EvalScope, error) {
660660
}
661661

662662
// The arguments are stored immediately after the defer header struct, i.e.
663-
// addr+sizeof(_defer). Since CFA in go is always the address of the first
664-
// argument, that's what we use for the value of CFA.
665-
// For SP we use CFA minus the size of one pointer because that would be
666-
// the space occupied by pushing the return address on the stack during the
667-
// CALL.
668-
scope.Regs.CFA = (int64(d.variable.Addr) + d.variable.RealType.Common().ByteSize)
669-
scope.Regs.Reg(scope.Regs.SPRegNum).Uint64Val = uint64(scope.Regs.CFA - int64(bi.Arch.PtrSize()))
663+
// addr+sizeof(_defer).
664+
665+
if !bi.Arch.usesLR {
666+
// On architectures that don't have a link register CFA is always the address of the first
667+
// argument, that's what we use for the value of CFA.
668+
// For SP we use CFA minus the size of one pointer because that would be
669+
// the space occupied by pushing the return address on the stack during the
670+
// CALL.
671+
scope.Regs.CFA = (int64(d.variable.Addr) + d.variable.RealType.Common().ByteSize)
672+
scope.Regs.Reg(scope.Regs.SPRegNum).Uint64Val = uint64(scope.Regs.CFA - int64(bi.Arch.PtrSize()))
673+
} else {
674+
// On architectures that have a link register CFA and SP have the same
675+
// value but the address of the first argument is at CFA+ptrSize so we set
676+
// CFA to the start of the argument frame minus one pointer size.
677+
scope.Regs.CFA = int64(d.variable.Addr) + d.variable.RealType.Common().ByteSize - int64(bi.Arch.PtrSize())
678+
scope.Regs.Reg(scope.Regs.SPRegNum).Uint64Val = uint64(scope.Regs.CFA)
679+
}
670680

671681
rdr := scope.Fn.cu.image.dwarfReader
672682
rdr.Seek(scope.Fn.offset)

0 commit comments

Comments
 (0)