github.com/s1s1ty/go@v0.0.0-20180207192209-104445e3140f/src/runtime/print.go (about) 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 }