| // Copyright 2009 The Go Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style | 
 | // license that can be found in the LICENSE file. | 
 |  | 
 | package runtime | 
 |  | 
 | import ( | 
 | 	"internal/goarch" | 
 | 	"runtime/internal/atomic" | 
 | 	"unsafe" | 
 | ) | 
 |  | 
 | // The compiler knows that a print of a value of this type | 
 | // should use printhex instead of printuint (decimal). | 
 | type hex uint64 | 
 |  | 
 | func bytes(s string) (ret []byte) { | 
 | 	rp := (*slice)(unsafe.Pointer(&ret)) | 
 | 	sp := stringStructOf(&s) | 
 | 	rp.array = sp.str | 
 | 	rp.len = sp.len | 
 | 	rp.cap = sp.len | 
 | 	return | 
 | } | 
 |  | 
 | var ( | 
 | 	// printBacklog is a circular buffer of messages written with the builtin | 
 | 	// print* functions, for use in postmortem analysis of core dumps. | 
 | 	printBacklog      [512]byte | 
 | 	printBacklogIndex int | 
 | ) | 
 |  | 
 | // recordForPanic maintains a circular buffer of messages written by the | 
 | // runtime leading up to a process crash, allowing the messages to be | 
 | // extracted from a core dump. | 
 | // | 
 | // The text written during a process crash (following "panic" or "fatal | 
 | // error") is not saved, since the goroutine stacks will generally be readable | 
 | // from the runtime datastructures in the core file. | 
 | func recordForPanic(b []byte) { | 
 | 	printlock() | 
 |  | 
 | 	if atomic.Load(&panicking) == 0 { | 
 | 		// Not actively crashing: maintain circular buffer of print output. | 
 | 		for i := 0; i < len(b); { | 
 | 			n := copy(printBacklog[printBacklogIndex:], b[i:]) | 
 | 			i += n | 
 | 			printBacklogIndex += n | 
 | 			printBacklogIndex %= len(printBacklog) | 
 | 		} | 
 | 	} | 
 |  | 
 | 	printunlock() | 
 | } | 
 |  | 
 | var debuglock mutex | 
 |  | 
 | // The compiler emits calls to printlock and printunlock around | 
 | // the multiple calls that implement a single Go print or println | 
 | // statement. Some of the print helpers (printslice, for example) | 
 | // call print recursively. There is also the problem of a crash | 
 | // happening during the print routines and needing to acquire | 
 | // the print lock to print information about the crash. | 
 | // For both these reasons, let a thread acquire the printlock 'recursively'. | 
 |  | 
 | func printlock() { | 
 | 	mp := getg().m | 
 | 	mp.locks++ // do not reschedule between printlock++ and lock(&debuglock). | 
 | 	mp.printlock++ | 
 | 	if mp.printlock == 1 { | 
 | 		lock(&debuglock) | 
 | 	} | 
 | 	mp.locks-- // now we know debuglock is held and holding up mp.locks for us. | 
 | } | 
 |  | 
 | func printunlock() { | 
 | 	mp := getg().m | 
 | 	mp.printlock-- | 
 | 	if mp.printlock == 0 { | 
 | 		unlock(&debuglock) | 
 | 	} | 
 | } | 
 |  | 
 | // write to goroutine-local buffer if diverting output, | 
 | // or else standard error. | 
 | func gwrite(b []byte) { | 
 | 	if len(b) == 0 { | 
 | 		return | 
 | 	} | 
 | 	recordForPanic(b) | 
 | 	gp := getg() | 
 | 	// Don't use the writebuf if gp.m is dying. We want anything | 
 | 	// written through gwrite to appear in the terminal rather | 
 | 	// than be written to in some buffer, if we're in a panicking state. | 
 | 	// Note that we can't just clear writebuf in the gp.m.dying case | 
 | 	// because a panic isn't allowed to have any write barriers. | 
 | 	if gp == nil || gp.writebuf == nil || gp.m.dying > 0 { | 
 | 		writeErr(b) | 
 | 		return | 
 | 	} | 
 |  | 
 | 	n := copy(gp.writebuf[len(gp.writebuf):cap(gp.writebuf)], b) | 
 | 	gp.writebuf = gp.writebuf[:len(gp.writebuf)+n] | 
 | } | 
 |  | 
 | func printsp() { | 
 | 	printstring(" ") | 
 | } | 
 |  | 
 | func printnl() { | 
 | 	printstring("\n") | 
 | } | 
 |  | 
 | func printbool(v bool) { | 
 | 	if v { | 
 | 		printstring("true") | 
 | 	} else { | 
 | 		printstring("false") | 
 | 	} | 
 | } | 
 |  | 
 | func printfloat(v float64) { | 
 | 	switch { | 
 | 	case v != v: | 
 | 		printstring("NaN") | 
 | 		return | 
 | 	case v+v == v && v > 0: | 
 | 		printstring("+Inf") | 
 | 		return | 
 | 	case v+v == v && v < 0: | 
 | 		printstring("-Inf") | 
 | 		return | 
 | 	} | 
 |  | 
 | 	const n = 7 // digits printed | 
 | 	var buf [n + 7]byte | 
 | 	buf[0] = '+' | 
 | 	e := 0 // exp | 
 | 	if v == 0 { | 
 | 		if 1/v < 0 { | 
 | 			buf[0] = '-' | 
 | 		} | 
 | 	} else { | 
 | 		if v < 0 { | 
 | 			v = -v | 
 | 			buf[0] = '-' | 
 | 		} | 
 |  | 
 | 		// normalize | 
 | 		for v >= 10 { | 
 | 			e++ | 
 | 			v /= 10 | 
 | 		} | 
 | 		for v < 1 { | 
 | 			e-- | 
 | 			v *= 10 | 
 | 		} | 
 |  | 
 | 		// round | 
 | 		h := 5.0 | 
 | 		for i := 0; i < n; i++ { | 
 | 			h /= 10 | 
 | 		} | 
 | 		v += h | 
 | 		if v >= 10 { | 
 | 			e++ | 
 | 			v /= 10 | 
 | 		} | 
 | 	} | 
 |  | 
 | 	// format +d.dddd+edd | 
 | 	for i := 0; i < n; i++ { | 
 | 		s := int(v) | 
 | 		buf[i+2] = byte(s + '0') | 
 | 		v -= float64(s) | 
 | 		v *= 10 | 
 | 	} | 
 | 	buf[1] = buf[2] | 
 | 	buf[2] = '.' | 
 |  | 
 | 	buf[n+2] = 'e' | 
 | 	buf[n+3] = '+' | 
 | 	if e < 0 { | 
 | 		e = -e | 
 | 		buf[n+3] = '-' | 
 | 	} | 
 |  | 
 | 	buf[n+4] = byte(e/100) + '0' | 
 | 	buf[n+5] = byte(e/10)%10 + '0' | 
 | 	buf[n+6] = byte(e%10) + '0' | 
 | 	gwrite(buf[:]) | 
 | } | 
 |  | 
 | func printcomplex(c complex128) { | 
 | 	print("(", real(c), imag(c), "i)") | 
 | } | 
 |  | 
 | func printuint(v uint64) { | 
 | 	var buf [100]byte | 
 | 	i := len(buf) | 
 | 	for i--; i > 0; i-- { | 
 | 		buf[i] = byte(v%10 + '0') | 
 | 		if v < 10 { | 
 | 			break | 
 | 		} | 
 | 		v /= 10 | 
 | 	} | 
 | 	gwrite(buf[i:]) | 
 | } | 
 |  | 
 | func printint(v int64) { | 
 | 	if v < 0 { | 
 | 		printstring("-") | 
 | 		v = -v | 
 | 	} | 
 | 	printuint(uint64(v)) | 
 | } | 
 |  | 
 | var minhexdigits = 0 // protected by printlock | 
 |  | 
 | func printhex(v uint64) { | 
 | 	const dig = "0123456789abcdef" | 
 | 	var buf [100]byte | 
 | 	i := len(buf) | 
 | 	for i--; i > 0; i-- { | 
 | 		buf[i] = dig[v%16] | 
 | 		if v < 16 && len(buf)-i >= minhexdigits { | 
 | 			break | 
 | 		} | 
 | 		v /= 16 | 
 | 	} | 
 | 	i-- | 
 | 	buf[i] = 'x' | 
 | 	i-- | 
 | 	buf[i] = '0' | 
 | 	gwrite(buf[i:]) | 
 | } | 
 |  | 
 | func printpointer(p unsafe.Pointer) { | 
 | 	printhex(uint64(uintptr(p))) | 
 | } | 
 | func printuintptr(p uintptr) { | 
 | 	printhex(uint64(p)) | 
 | } | 
 |  | 
 | func printstring(s string) { | 
 | 	gwrite(bytes(s)) | 
 | } | 
 |  | 
 | func printslice(s []byte) { | 
 | 	sp := (*slice)(unsafe.Pointer(&s)) | 
 | 	print("[", len(s), "/", cap(s), "]") | 
 | 	printpointer(sp.array) | 
 | } | 
 |  | 
 | func printeface(e eface) { | 
 | 	print("(", e._type, ",", e.data, ")") | 
 | } | 
 |  | 
 | func printiface(i iface) { | 
 | 	print("(", i.tab, ",", i.data, ")") | 
 | } | 
 |  | 
 | // hexdumpWords prints a word-oriented hex dump of [p, end). | 
 | // | 
 | // If mark != nil, it will be called with each printed word's address | 
 | // and should return a character mark to appear just before that | 
 | // word's value. It can return 0 to indicate no mark. | 
 | func hexdumpWords(p, end uintptr, mark func(uintptr) byte) { | 
 | 	printlock() | 
 | 	var markbuf [1]byte | 
 | 	markbuf[0] = ' ' | 
 | 	minhexdigits = int(unsafe.Sizeof(uintptr(0)) * 2) | 
 | 	for i := uintptr(0); p+i < end; i += goarch.PtrSize { | 
 | 		if i%16 == 0 { | 
 | 			if i != 0 { | 
 | 				println() | 
 | 			} | 
 | 			print(hex(p+i), ": ") | 
 | 		} | 
 |  | 
 | 		if mark != nil { | 
 | 			markbuf[0] = mark(p + i) | 
 | 			if markbuf[0] == 0 { | 
 | 				markbuf[0] = ' ' | 
 | 			} | 
 | 		} | 
 | 		gwrite(markbuf[:]) | 
 | 		val := *(*uintptr)(unsafe.Pointer(p + i)) | 
 | 		print(hex(val)) | 
 | 		print(" ") | 
 |  | 
 | 		// Can we symbolize val? | 
 | 		fn := findfunc(val) | 
 | 		if fn.valid() { | 
 | 			print("<", funcname(fn), "+", hex(val-fn.entry()), "> ") | 
 | 		} | 
 | 	} | 
 | 	minhexdigits = 0 | 
 | 	println() | 
 | 	printunlock() | 
 | } |