...

Source file src/runtime/print.go

     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	
     5	package runtime
     6	
     7	import (
     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).
    15	type hex uint64
    16	
    17	func 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	
    26	var (
    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.
    40	func 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	
    56	var 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	
    66	func 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	
    76	func 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.
    86	func 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	
   106	func printsp() {
   107		printstring(" ")
   108	}
   109	
   110	func printnl() {
   111		printstring("\n")
   112	}
   113	
   114	func printbool(v bool) {
   115		if v {
   116			printstring("true")
   117		} else {
   118			printstring("false")
   119		}
   120	}
   121	
   122	func 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	
   194	func printcomplex(c complex128) {
   195		print("(", real(c), imag(c), "i)")
   196	}
   197	
   198	func 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	
   211	func printint(v int64) {
   212		if v < 0 {
   213			printstring("-")
   214			v = -v
   215		}
   216		printuint(uint64(v))
   217	}
   218	
   219	func 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	
   237	func printpointer(p unsafe.Pointer) {
   238		printhex(uint64(uintptr(p)))
   239	}
   240	
   241	func printstring(s string) {
   242		gwrite(bytes(s))
   243	}
   244	
   245	func printslice(s []byte) {
   246		sp := (*slice)(unsafe.Pointer(&s))
   247		print("[", len(s), "/", cap(s), "]")
   248		printpointer(sp.array)
   249	}
   250	
   251	func printeface(e eface) {
   252		print("(", e._type, ",", e.data, ")")
   253	}
   254	
   255	func 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.
   264	func 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	

View as plain text