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