]> Cypherpunks.ru repositories - gostls13.git/blob - src/runtime/debugcall.go
runtime: whitelist debugCall32..debugCall65536 in debugCallCheck
[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                 name := funcname(f)
50
51                 switch name {
52                 case "debugCall32",
53                         "debugCall64",
54                         "debugCall128",
55                         "debugCall256",
56                         "debugCall512",
57                         "debugCall1024",
58                         "debugCall2048",
59                         "debugCall4096",
60                         "debugCall8192",
61                         "debugCall16384",
62                         "debugCall32768",
63                         "debugCall65536":
64                         // These functions are whitelisted so that the debugger can initiate multiple function calls.
65                         // See: https://golang.org/cl/161137/
66                         return
67                 }
68
69                 // Disallow calls from the runtime. We could
70                 // potentially make this condition tighter (e.g., not
71                 // when locks are held), but there are enough tightly
72                 // coded sequences (e.g., defer handling) that it's
73                 // better to play it safe.
74                 if pfx := "runtime."; len(name) > len(pfx) && name[:len(pfx)] == pfx {
75                         ret = debugCallRuntime
76                         return
77                 }
78
79                 // Look up PC's register map.
80                 pcdata := int32(-1)
81                 if pc != f.entry {
82                         pc--
83                         pcdata = pcdatavalue(f, _PCDATA_RegMapIndex, pc, nil)
84                 }
85                 if pcdata == -1 {
86                         pcdata = 0 // in prologue
87                 }
88                 stkmap := (*stackmap)(funcdata(f, _FUNCDATA_RegPointerMaps))
89                 if pcdata == -2 || stkmap == nil {
90                         // Not at a safe point.
91                         ret = debugCallUnsafePoint
92                         return
93                 }
94         })
95         return ret
96 }
97
98 // debugCallWrap pushes a defer to recover from panics in debug calls
99 // and then calls the dispatching function at PC dispatch.
100 func debugCallWrap(dispatch uintptr) {
101         var dispatchF func()
102         dispatchFV := funcval{dispatch}
103         *(*unsafe.Pointer)(unsafe.Pointer(&dispatchF)) = noescape(unsafe.Pointer(&dispatchFV))
104
105         var ok bool
106         defer func() {
107                 if !ok {
108                         err := recover()
109                         debugCallPanicked(err)
110                 }
111         }()
112         dispatchF()
113         ok = true
114 }