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