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	"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 data structures in the core file.
39func recordForPanic(b []byte) {
40	printlock()
41
42	if panicking.Load() == 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 (printslice, 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	// Don't use the writebuf if gp.m is dying. We want anything
92	// written through gwrite to appear in the terminal rather
93	// than be written to in some buffer, if we're in a panicking state.
94	// Note that we can't just clear writebuf in the gp.m.dying case
95	// because a panic isn't allowed to have any write barriers.
96	if gp == nil || gp.writebuf == nil || gp.m.dying > 0 {
97		writeErr(b)
98		return
99	}
100
101	n := copy(gp.writebuf[len(gp.writebuf):cap(gp.writebuf)], b)
102	gp.writebuf = gp.writebuf[:len(gp.writebuf)+n]
103}
104
105func printsp() {
106	printstring(" ")
107}
108
109func printnl() {
110	printstring("\n")
111}
112
113func printbool(v bool) {
114	if v {
115		printstring("true")
116	} else {
117		printstring("false")
118	}
119}
120
121func printfloat(v float64) {
122	switch {
123	case v != v:
124		printstring("NaN")
125		return
126	case v+v == v && v > 0:
127		printstring("+Inf")
128		return
129	case v+v == v && v < 0:
130		printstring("-Inf")
131		return
132	}
133
134	const n = 7 // digits printed
135	var buf [n + 7]byte
136	buf[0] = '+'
137	e := 0 // exp
138	if v == 0 {
139		if 1/v < 0 {
140			buf[0] = '-'
141		}
142	} else {
143		if v < 0 {
144			v = -v
145			buf[0] = '-'
146		}
147
148		// normalize
149		for v >= 10 {
150			e++
151			v /= 10
152		}
153		for v < 1 {
154			e--
155			v *= 10
156		}
157
158		// round
159		h := 5.0
160		for i := 0; i < n; i++ {
161			h /= 10
162		}
163		v += h
164		if v >= 10 {
165			e++
166			v /= 10
167		}
168	}
169
170	// format +d.dddd+edd
171	for i := 0; i < n; i++ {
172		s := int(v)
173		buf[i+2] = byte(s + '0')
174		v -= float64(s)
175		v *= 10
176	}
177	buf[1] = buf[2]
178	buf[2] = '.'
179
180	buf[n+2] = 'e'
181	buf[n+3] = '+'
182	if e < 0 {
183		e = -e
184		buf[n+3] = '-'
185	}
186
187	buf[n+4] = byte(e/100) + '0'
188	buf[n+5] = byte(e/10)%10 + '0'
189	buf[n+6] = byte(e%10) + '0'
190	gwrite(buf[:])
191}
192
193func printcomplex(c complex128) {
194	print("(", real(c), imag(c), "i)")
195}
196
197func printuint(v uint64) {
198	var buf [100]byte
199	i := len(buf)
200	for i--; i > 0; i-- {
201		buf[i] = byte(v%10 + '0')
202		if v < 10 {
203			break
204		}
205		v /= 10
206	}
207	gwrite(buf[i:])
208}
209
210func printint(v int64) {
211	if v < 0 {
212		printstring("-")
213		v = -v
214	}
215	printuint(uint64(v))
216}
217
218var minhexdigits = 0 // protected by printlock
219
220func printhex(v uint64) {
221	const dig = "0123456789abcdef"
222	var buf [100]byte
223	i := len(buf)
224	for i--; i > 0; i-- {
225		buf[i] = dig[v%16]
226		if v < 16 && len(buf)-i >= minhexdigits {
227			break
228		}
229		v /= 16
230	}
231	i--
232	buf[i] = 'x'
233	i--
234	buf[i] = '0'
235	gwrite(buf[i:])
236}
237
238func printpointer(p unsafe.Pointer) {
239	printhex(uint64(uintptr(p)))
240}
241func printuintptr(p uintptr) {
242	printhex(uint64(p))
243}
244
245func printstring(s string) {
246	gwrite(bytes(s))
247}
248
249func printslice(s []byte) {
250	sp := (*slice)(unsafe.Pointer(&s))
251	print("[", len(s), "/", cap(s), "]")
252	printpointer(sp.array)
253}
254
255func printeface(e eface) {
256	print("(", e._type, ",", e.data, ")")
257}
258
259func printiface(i iface) {
260	print("(", i.tab, ",", i.data, ")")
261}
262
263// hexdumpWords prints a word-oriented hex dump of [p, end).
264//
265// If mark != nil, it will be called with each printed word's address
266// and should return a character mark to appear just before that
267// word's value. It can return 0 to indicate no mark.
268func hexdumpWords(p, end uintptr, mark func(uintptr) byte) {
269	printlock()
270	var markbuf [1]byte
271	markbuf[0] = ' '
272	minhexdigits = int(unsafe.Sizeof(uintptr(0)) * 2)
273	for i := uintptr(0); p+i < end; i += goarch.PtrSize {
274		if i%16 == 0 {
275			if i != 0 {
276				println()
277			}
278			print(hex(p+i), ": ")
279		}
280
281		if mark != nil {
282			markbuf[0] = mark(p + i)
283			if markbuf[0] == 0 {
284				markbuf[0] = ' '
285			}
286		}
287		gwrite(markbuf[:])
288		val := *(*uintptr)(unsafe.Pointer(p + i))
289		print(hex(val))
290		print(" ")
291
292		// Can we symbolize val?
293		fn := findfunc(val)
294		if fn.valid() {
295			print("<", funcname(fn), "+", hex(val-fn.entry()), "> ")
296		}
297	}
298	minhexdigits = 0
299	println()
300	printunlock()
301}
302