@@ -250,21 +250,10 @@ func findUserFrameRegion(pc uintptr) *userFrameRegion {
250250
251251func userFrameNext (r * userFrameRegion , pc , sp uintptr ) (callerPC , callerSP , callerBP uintptr , ok bool ) {
252252 if m := findUserFrameStackMap (r , pc ); m != nil && m .hasUnwind {
253- base := sp + m . unwindBaseOffset
254- if base < sp {
253+ base , ok := userFrameUnwindBase ( m , sp )
254+ if ! ok {
255255 return 0 , 0 , 0 , false
256256 }
257- if m .unwindBaseUsesDelta {
258- deltaAddr := sp + m .unwindBaseDeltaOffset
259- if deltaAddr < sp {
260- return 0 , 0 , 0 , false
261- }
262- delta := * (* uintptr )(unsafe .Pointer (deltaAddr ))
263- if base + delta < base {
264- return 0 , 0 , 0 , false
265- }
266- base += delta
267- }
268257 callerPCAddr := base + m .callerPCOffset
269258 callerSP = base + m .callerSPOffset
270259 callerBPAddr := base + m .callerBPOffset
@@ -276,6 +265,44 @@ func userFrameNext(r *userFrameRegion, pc, sp uintptr) (callerPC, callerSP, call
276265 return 0 , 0 , 0 , false
277266}
278267
268+ func userFrameUnwindBase (m * userFrameStackMap , sp uintptr ) (uintptr , bool ) {
269+ base := sp + m .unwindBaseOffset
270+ if base < sp {
271+ return 0 , false
272+ }
273+ if m .unwindBaseUsesDelta {
274+ deltaAddr := sp + m .unwindBaseDeltaOffset
275+ if deltaAddr < sp {
276+ return 0 , false
277+ }
278+ delta := * (* uintptr )(unsafe .Pointer (deltaAddr ))
279+ if base + delta < base {
280+ return 0 , false
281+ }
282+ base += delta
283+ }
284+ return base , true
285+ }
286+
287+ // userFrameCallerBPSlot returns the address of the saved caller frame pointer.
288+ // Stack copying must relocate this value even when the user frame has no Go
289+ // pointers of its own. On amd64, Go function epilogues may use LEAVE, so a
290+ // stale frame pointer would also restore SP to the old, freed stack.
291+ //
292+ //go:nosplit
293+ func userFrameCallerBPSlot (pc , sp uintptr ) (uintptr , bool ) {
294+ r := findUserFrameRegion (pc )
295+ m := findUserFrameStackMap (r , pc )
296+ if m == nil || ! m .hasUnwind {
297+ return 0 , false
298+ }
299+ base , ok := userFrameUnwindBase (m , sp )
300+ if ! ok || base + m .callerBPOffset < base {
301+ return 0 , false
302+ }
303+ return base + m .callerBPOffset , true
304+ }
305+
279306// userFramePointerMap resolves one immutable map without calling user code.
280307// Looking the region up again keeps unwinder pointer-free.
281308//
0 commit comments