CALL runtime·abort(SB)
RET
- // Prevent dead-code elimination of debugCallV2, which is
+ // Prevent dead-code elimination of debugCallV2 and debugPinnerV1, which are
// intended to be called by debuggers.
+ MOVQ $runtime·debugPinnerV1<ABIInternal>(SB), AX
MOVQ $runtime·debugCallV2<ABIInternal>(SB), AX
RET
// start this M
BL runtime·mstart(SB)
- // Prevent dead-code elimination of debugCallV2, which is
+ // Prevent dead-code elimination of debugCallV2 and debugPinnerV1, which are
// intended to be called by debuggers.
+ MOVD $runtime·debugPinnerV1<ABIInternal>(SB), R0
MOVD $runtime·debugCallV2<ABIInternal>(SB), R0
MOVD $0, R0
// start this M
BL runtime·mstart(SB)
- // Prevent dead-code elimination of debugCallV2, which is
+ // Prevent dead-code elimination of debugCallV2 and debugPinnerV1, which are
// intended to be called by debuggers.
#ifdef GOARCH_ppc64le
+ MOVD $runtime·debugPinnerV1<ABIInternal>(SB), R31
MOVD $runtime·debugCallV2<ABIInternal>(SB), R31
#endif
MOVD R0, 0(R0)
gp.stackguard0 = stackForceMove
}
}
+
+// debugPinnerKeepUnpin is used to make runtime.(*Pinner).Unpin reachable.
+var debugPinnerKeepUnpin bool = false
+
+// debugPinnerV1 returns a new Pinner that pins itself. This function can be
+// used by debuggers to easily obtain a Pinner that will not be garbage
+// collected (or moved in memory) even if no references to it exist in the
+// target program. This pinner in turn can be used to extend this property
+// to other objects, which debuggers can use to simplify the evaluation of
+// expressions involving multiple call injections.
+func debugPinnerV1() *Pinner {
+ p := new(Pinner)
+ p.Pin(unsafe.Pointer(p))
+ if debugPinnerKeepUnpin {
+ // Make Unpin reachable.
+ p.Unpin()
+ }
+ return p
+}