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