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	if gp == nil || gp.writebuf == nil {
114		writeErr(b)
115		return
116	}
117
118	n := copy(gp.writebuf[len(gp.writebuf):cap(gp.writebuf)], b)
119	gp.writebuf = gp.writebuf[:len(gp.writebuf)+n]
120}
121
122func printsp() {
123	printstring(" ")
124}
125
126func printnl() {
127	printstring("\n")
128}
129
130func printbool(v bool) {
131	if v {
132		printstring("true")
133	} else {
134		printstring("false")
135	}
136}
137
138func printfloat(v float64) {
139	switch {
140	case v != v:
141		printstring("NaN")
142		return
143	case v+v == v && v > 0:
144		printstring("+Inf")
145		return
146	case v+v == v && v < 0:
147		printstring("-Inf")
148		return
149	}
150
151	const n = 7 // digits printed
152	var buf [n + 7]byte
153	buf[0] = '+'
154	e := 0 // exp
155	if v == 0 {
156		if 1/v < 0 {
157			buf[0] = '-'
158		}
159	} else {
160		if v < 0 {
161			v = -v
162			buf[0] = '-'
163		}
164
165		// normalize
166		for v >= 10 {
167			e++
168			v /= 10
169		}
170		for v < 1 {
171			e--
172			v *= 10
173		}
174
175		// round
176		h := 5.0
177		for i := 0; i < n; i++ {
178			h /= 10
179		}
180		v += h
181		if v >= 10 {
182			e++
183			v /= 10
184		}
185	}
186
187	// format +d.dddd+edd
188	for i := 0; i < n; i++ {
189		s := int(v)
190		buf[i+2] = byte(s + '0')
191		v -= float64(s)
192		v *= 10
193	}
194	buf[1] = buf[2]
195	buf[2] = '.'
196
197	buf[n+2] = 'e'
198	buf[n+3] = '+'
199	if e < 0 {
200		e = -e
201		buf[n+3] = '-'
202	}
203
204	buf[n+4] = byte(e/100) + '0'
205	buf[n+5] = byte(e/10)%10 + '0'
206	buf[n+6] = byte(e%10) + '0'
207	gwrite(buf[:])
208}
209
210func printcomplex(c complex128) {
211	print("(", real(c), imag(c), "i)")
212}
213
214func printuint(v uint64) {
215	var buf [100]byte
216	i := len(buf)
217	for i--; i > 0; i-- {
218		buf[i] = byte(v%10 + '0')
219		if v < 10 {
220			break
221		}
222		v /= 10
223	}
224	gwrite(buf[i:])
225}
226
227func printint(v int64) {
228	if v < 0 {
229		printstring("-")
230		v = -v
231	}
232	printuint(uint64(v))
233}
234
235func printhex(v uint64) {
236	const dig = "0123456789abcdef"
237	var buf [100]byte
238	i := len(buf)
239	for i--; i > 0; i-- {
240		buf[i] = dig[v%16]
241		if v < 16 {
242			break
243		}
244		v /= 16
245	}
246	i--
247	buf[i] = 'x'
248	i--
249	buf[i] = '0'
250	gwrite(buf[i:])
251}
252
253func printpointer(p unsafe.Pointer) {
254	printhex(uint64(uintptr(p)))
255}
256
257func printstring(s string) {
258	gwrite(bytes(s))
259}
260
261func printslice(s []byte) {
262	sp := (*slice)(unsafe.Pointer(&s))
263	print("[", len(s), "/", cap(s), "]")
264	printpointer(sp.array)
265}
266
267func printeface(e eface) {
268	print("(", e._type, ",", e.data, ")")
269}
270
271func printiface(i iface) {
272	print("(", i.tab, ",", i.data, ")")
273}
274