1// Copyright 2009 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
5package runtime
6
7import (
8	"runtime/internal/atomic"
9	"runtime/internal/sys"
10	"unsafe"
11)
12
13// For gccgo, use go:linkname to export compiler-called functions.
14//
15//go:linkname printbool
16//go:linkname printfloat
17//go:linkname printint
18//go:linkname printhex
19//go:linkname printuint
20//go:linkname printcomplex
21//go:linkname printstring
22//go:linkname printpointer
23//go:linkname printiface
24//go:linkname printeface
25//go:linkname printslice
26//go:linkname printnl
27//go:linkname printsp
28//go:linkname printlock
29//go:linkname printunlock
30// Temporary for C code to call:
31//go:linkname gwrite
32//go:linkname printhex
33
34// The compiler knows that a print of a value of this type
35// should use printhex instead of printuint (decimal).
36type hex uint64
37
38//go:nowritebarrier
39func bytes(s string) (ret []byte) {
40	rp := (*slice)(unsafe.Pointer(&ret))
41	sp := stringStructOf(&s)
42	rp.array = sp.str
43	rp.len = sp.len
44	rp.cap = sp.len
45	return
46}
47
48var (
49	// printBacklog is a circular buffer of messages written with the builtin
50	// print* functions, for use in postmortem analysis of core dumps.
51	printBacklog      [512]byte
52	printBacklogIndex int
53)
54
55// recordForPanic maintains a circular buffer of messages written by the
56// runtime leading up to a process crash, allowing the messages to be
57// extracted from a core dump.
58//
59// The text written during a process crash (following "panic" or "fatal
60// error") is not saved, since the goroutine stacks will generally be readable
61// from the runtime datastructures in the core file.
62func recordForPanic(b []byte) {
63	printlock()
64
65	if atomic.Load(&panicking) == 0 {
66		// Not actively crashing: maintain circular buffer of print output.
67		for i := 0; i < len(b); {
68			n := copy(printBacklog[printBacklogIndex:], b[i:])
69			i += n
70			printBacklogIndex += n
71			printBacklogIndex %= len(printBacklog)
72		}
73	}
74
75	printunlock()
76}
77
78var debuglock mutex
79
80// The compiler emits calls to printlock and printunlock around
81// the multiple calls that implement a single Go print or println
82// statement. Some of the print helpers (printslice, for example)
83// call print recursively. There is also the problem of a crash
84// happening during the print routines and needing to acquire
85// the print lock to print information about the crash.
86// For both these reasons, let a thread acquire the printlock 'recursively'.
87
88func printlock() {
89	mp := getg().m
90	mp.locks++ // do not reschedule between printlock++ and lock(&debuglock).
91	mp.printlock++
92	if mp.printlock == 1 {
93		lock(&debuglock)
94	}
95	mp.locks-- // now we know debuglock is held and holding up mp.locks for us.
96}
97
98func printunlock() {
99	mp := getg().m
100	mp.printlock--
101	if mp.printlock == 0 {
102		unlock(&debuglock)
103	}
104}
105
106// write to goroutine-local buffer if diverting output,
107// or else standard error.
108func gwrite(b []byte) {
109	if len(b) == 0 {
110		return
111	}
112	recordForPanic(b)
113	gp := getg()
114	// Don't use the writebuf if gp.m is dying. We want anything
115	// written through gwrite to appear in the terminal rather
116	// than be written to in some buffer, if we're in a panicking state.
117	// Note that we can't just clear writebuf in the gp.m.dying case
118	// because a panic isn't allowed to have any write barriers.
119	if gp == nil || gp.writebuf == nil || gp.m.dying > 0 {
120		writeErr(b)
121		return
122	}
123
124	n := copy(gp.writebuf[len(gp.writebuf):cap(gp.writebuf)], b)
125	gp.writebuf = gp.writebuf[:len(gp.writebuf)+n]
126}
127
128func printsp() {
129	printstring(" ")
130}
131
132func printnl() {
133	printstring("\n")
134}
135
136func printbool(v bool) {
137	if v {
138		printstring("true")
139	} else {
140		printstring("false")
141	}
142}
143
144func printfloat(v float64) {
145	switch {
146	case v != v:
147		printstring("NaN")
148		return
149	case v+v == v && v > 0:
150		printstring("+Inf")
151		return
152	case v+v == v && v < 0:
153		printstring("-Inf")
154		return
155	}
156
157	const n = 7 // digits printed
158	var buf [n + 7]byte
159	buf[0] = '+'
160	e := 0 // exp
161	if v == 0 {
162		if 1/v < 0 {
163			buf[0] = '-'
164		}
165	} else {
166		if v < 0 {
167			v = -v
168			buf[0] = '-'
169		}
170
171		// normalize
172		for v >= 10 {
173			e++
174			v /= 10
175		}
176		for v < 1 {
177			e--
178			v *= 10
179		}
180
181		// round
182		h := 5.0
183		for i := 0; i < n; i++ {
184			h /= 10
185		}
186		v += h
187		if v >= 10 {
188			e++
189			v /= 10
190		}
191	}
192
193	// format +d.dddd+edd
194	for i := 0; i < n; i++ {
195		s := int(v)
196		buf[i+2] = byte(s + '0')
197		v -= float64(s)
198		v *= 10
199	}
200	buf[1] = buf[2]
201	buf[2] = '.'
202
203	buf[n+2] = 'e'
204	buf[n+3] = '+'
205	if e < 0 {
206		e = -e
207		buf[n+3] = '-'
208	}
209
210	buf[n+4] = byte(e/100) + '0'
211	buf[n+5] = byte(e/10)%10 + '0'
212	buf[n+6] = byte(e%10) + '0'
213	gwrite(buf[:])
214}
215
216func printcomplex(c complex128) {
217	print("(", real(c), imag(c), "i)")
218}
219
220func printuint(v uint64) {
221	var buf [100]byte
222	i := len(buf)
223	for i--; i > 0; i-- {
224		buf[i] = byte(v%10 + '0')
225		if v < 10 {
226			break
227		}
228		v /= 10
229	}
230	gwrite(buf[i:])
231}
232
233func printint(v int64) {
234	if v < 0 {
235		printstring("-")
236		v = -v
237	}
238	printuint(uint64(v))
239}
240
241func printhex(v uint64) {
242	const dig = "0123456789abcdef"
243	var buf [100]byte
244	i := len(buf)
245	for i--; i > 0; i-- {
246		buf[i] = dig[v%16]
247		if v < 16 {
248			break
249		}
250		v /= 16
251	}
252	i--
253	buf[i] = 'x'
254	i--
255	buf[i] = '0'
256	gwrite(buf[i:])
257}
258
259func printpointer(p unsafe.Pointer) {
260	printhex(uint64(uintptr(p)))
261}
262func printuintptr(p uintptr) {
263	printhex(uint64(p))
264}
265
266func printstring(s string) {
267	gwrite(bytes(s))
268}
269
270func printslice(s []byte) {
271	sp := (*slice)(unsafe.Pointer(&s))
272	print("[", len(s), "/", cap(s), "]")
273	printpointer(sp.array)
274}
275
276func printeface(e eface) {
277	print("(", e._type, ",", e.data, ")")
278}
279
280func printiface(i iface) {
281	print("(", i.tab, ",", i.data, ")")
282}
283
284// hexdumpWords prints a word-oriented hex dump of [p, end).
285//
286// If mark != nil, it will be called with each printed word's address
287// and should return a character mark to appear just before that
288// word's value. It can return 0 to indicate no mark.
289func hexdumpWords(p, end uintptr, mark func(uintptr) byte) {
290	p1 := func(x uintptr) {
291		var buf [2 * sys.PtrSize]byte
292		for i := len(buf) - 1; i >= 0; i-- {
293			if x&0xF < 10 {
294				buf[i] = byte(x&0xF) + '0'
295			} else {
296				buf[i] = byte(x&0xF) - 10 + 'a'
297			}
298			x >>= 4
299		}
300		gwrite(buf[:])
301	}
302
303	printlock()
304	var markbuf [1]byte
305	markbuf[0] = ' '
306	for i := uintptr(0); p+i < end; i += sys.PtrSize {
307		if i%16 == 0 {
308			if i != 0 {
309				println()
310			}
311			p1(p + i)
312			print(": ")
313		}
314
315		if mark != nil {
316			markbuf[0] = mark(p + i)
317			if markbuf[0] == 0 {
318				markbuf[0] = ' '
319			}
320		}
321		gwrite(markbuf[:])
322		val := *(*uintptr)(unsafe.Pointer(p + i))
323		p1(val)
324		print(" ")
325
326		// Can we symbolize val?
327		name, _, _, _ := funcfileline(val, -1, false)
328		if name != "" {
329			entry := funcentry(val)
330			print("<", name, "+", val-entry, "> ")
331		}
332	}
333	println()
334	printunlock()
335}
336