lin
2025-06-05 ed3dd9d3e7519a82bb871d5eedb24a2fa0c91f47
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
 
// +build amd64
 
package runtime
 
import "unsafe"
 
const (
   debugCallSystemStack = "executing on Go runtime stack"
   debugCallUnknownFunc = "call from unknown function"
   debugCallRuntime     = "call from within the Go runtime"
   debugCallUnsafePoint = "call not at safe point"
)
 
func debugCallV1()
func debugCallPanicked(val interface{})
 
// debugCallCheck checks whether it is safe to inject a debugger
// function call with return PC pc. If not, it returns a string
// explaining why.
//
//go:nosplit
func debugCallCheck(pc uintptr) string {
   // No user calls from the system stack.
   if getg() != getg().m.curg {
       return debugCallSystemStack
   }
   if sp := getcallersp(); !(getg().stack.lo < sp && sp <= getg().stack.hi) {
       // Fast syscalls (nanotime) and racecall switch to the
       // g0 stack without switching g. We can't safely make
       // a call in this state. (We can't even safely
       // systemstack.)
       return debugCallSystemStack
   }
 
   // Switch to the system stack to avoid overflowing the user
   // stack.
   var ret string
   systemstack(func() {
       f := findfunc(pc)
       if !f.valid() {
           ret = debugCallUnknownFunc
           return
       }
 
       // Disallow calls from the runtime. We could
       // potentially make this condition tighter (e.g., not
       // when locks are held), but there are enough tightly
       // coded sequences (e.g., defer handling) that it's
       // better to play it safe.
       if name, pfx := funcname(f), "runtime."; len(name) > len(pfx) && name[:len(pfx)] == pfx {
           ret = debugCallRuntime
           return
       }
 
       // Look up PC's register map.
       pcdata := int32(-1)
       if pc != f.entry {
           pc--
           pcdata = pcdatavalue(f, _PCDATA_RegMapIndex, pc, nil)
       }
       if pcdata == -1 {
           pcdata = 0 // in prologue
       }
       stkmap := (*stackmap)(funcdata(f, _FUNCDATA_RegPointerMaps))
       if pcdata == -2 || stkmap == nil {
           // Not at a safe point.
           ret = debugCallUnsafePoint
           return
       }
   })
   return ret
}
 
// debugCallWrap pushes a defer to recover from panics in debug calls
// and then calls the dispatching function at PC dispatch.
func debugCallWrap(dispatch uintptr) {
   var dispatchF func()
   dispatchFV := funcval{dispatch}
   *(*unsafe.Pointer)(unsafe.Pointer(&dispatchF)) = noescape(unsafe.Pointer(&dispatchFV))
 
   var ok bool
   defer func() {
       if !ok {
           err := recover()
           debugCallPanicked(err)
       }
   }()
   dispatchF()
   ok = true
}