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	"internal/goarch"
9	"runtime/internal/atomic"
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
219var minhexdigits = 0 // protected by printlock
220
221func printhex(v uint64) {
222	const dig = "0123456789abcdef"
223	var buf [100]byte
224	i := len(buf)
225	for i--; i > 0; i-- {
226		buf[i] = dig[v%16]
227		if v < 16 && len(buf)-i >= minhexdigits {
228			break
229		}
230		v /= 16
231	}
232	i--
233	buf[i] = 'x'
234	i--
235	buf[i] = '0'
236	gwrite(buf[i:])
237}
238
239func printpointer(p unsafe.Pointer) {
240	printhex(uint64(uintptr(p)))
241}
242func printuintptr(p uintptr) {
243	printhex(uint64(p))
244}
245
246func printstring(s string) {
247	gwrite(bytes(s))
248}
249
250func printslice(s []byte) {
251	sp := (*slice)(unsafe.Pointer(&s))
252	print("[", len(s), "/", cap(s), "]")
253	printpointer(sp.array)
254}
255
256func printeface(e eface) {
257	print("(", e._type, ",", e.data, ")")
258}
259
260func printiface(i iface) {
261	print("(", i.tab, ",", i.data, ")")
262}
263
264// hexdumpWords prints a word-oriented hex dump of [p, end).
265//
266// If mark != nil, it will be called with each printed word's address
267// and should return a character mark to appear just before that
268// word's value. It can return 0 to indicate no mark.
269func hexdumpWords(p, end uintptr, mark func(uintptr) byte) {
270	printlock()
271	var markbuf [1]byte
272	markbuf[0] = ' '
273	minhexdigits = int(unsafe.Sizeof(uintptr(0)) * 2)
274	for i := uintptr(0); p+i < end; i += goarch.PtrSize {
275		if i%16 == 0 {
276			if i != 0 {
277				println()
278			}
279			print(hex(p+i), ": ")
280		}
281
282		if mark != nil {
283			markbuf[0] = mark(p + i)
284			if markbuf[0] == 0 {
285				markbuf[0] = ' '
286			}
287		}
288		gwrite(markbuf[:])
289		val := *(*uintptr)(unsafe.Pointer(p + i))
290		print(hex(val))
291		print(" ")
292
293		// Can we symbolize val?
294		fn := findfunc(val)
295		if fn.valid() {
296			print("<", funcname(fn), "+", hex(val-fn.entry()), "> ")
297		}
298	}
299	minhexdigits = 0
300	println()
301	printunlock()
302}
303