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
7package runtime
8
9import "unsafe"
10
11const (
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
18func debugCallV1()
19func 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
26func 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.
100func 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}
115