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