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