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