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// For gccgo, use go:linkname to export compiler-called functions. 14// 15//go:linkname printbool 16//go:linkname printfloat 17//go:linkname printint 18//go:linkname printhex 19//go:linkname printuint 20//go:linkname printcomplex 21//go:linkname printstring 22//go:linkname printpointer 23//go:linkname printiface 24//go:linkname printeface 25//go:linkname printslice 26//go:linkname printnl 27//go:linkname printsp 28//go:linkname printlock 29//go:linkname printunlock 30// Temporary for C code to call: 31//go:linkname gwrite 32//go:linkname printhex 33 34// The compiler knows that a print of a value of this type 35// should use printhex instead of printuint (decimal). 36type hex uint64 37 38//go:nowritebarrier 39func bytes(s string) (ret []byte) { 40 rp := (*slice)(unsafe.Pointer(&ret)) 41 sp := stringStructOf(&s) 42 rp.array = sp.str 43 rp.len = sp.len 44 rp.cap = sp.len 45 return 46} 47 48var ( 49 // printBacklog is a circular buffer of messages written with the builtin 50 // print* functions, for use in postmortem analysis of core dumps. 51 printBacklog [512]byte 52 printBacklogIndex int 53) 54 55// recordForPanic maintains a circular buffer of messages written by the 56// runtime leading up to a process crash, allowing the messages to be 57// extracted from a core dump. 58// 59// The text written during a process crash (following "panic" or "fatal 60// error") is not saved, since the goroutine stacks will generally be readable 61// from the runtime datastructures in the core file. 62func recordForPanic(b []byte) { 63 printlock() 64 65 if atomic.Load(&panicking) == 0 { 66 // Not actively crashing: maintain circular buffer of print output. 67 for i := 0; i < len(b); { 68 n := copy(printBacklog[printBacklogIndex:], b[i:]) 69 i += n 70 printBacklogIndex += n 71 printBacklogIndex %= len(printBacklog) 72 } 73 } 74 75 printunlock() 76} 77 78var debuglock mutex 79 80// The compiler emits calls to printlock and printunlock around 81// the multiple calls that implement a single Go print or println 82// statement. Some of the print helpers (printslice, for example) 83// call print recursively. There is also the problem of a crash 84// happening during the print routines and needing to acquire 85// the print lock to print information about the crash. 86// For both these reasons, let a thread acquire the printlock 'recursively'. 87 88func printlock() { 89 mp := getg().m 90 mp.locks++ // do not reschedule between printlock++ and lock(&debuglock). 91 mp.printlock++ 92 if mp.printlock == 1 { 93 lock(&debuglock) 94 } 95 mp.locks-- // now we know debuglock is held and holding up mp.locks for us. 96} 97 98func printunlock() { 99 mp := getg().m 100 mp.printlock-- 101 if mp.printlock == 0 { 102 unlock(&debuglock) 103 } 104} 105 106// write to goroutine-local buffer if diverting output, 107// or else standard error. 108func gwrite(b []byte) { 109 if len(b) == 0 { 110 return 111 } 112 recordForPanic(b) 113 gp := getg() 114 // Don't use the writebuf if gp.m is dying. We want anything 115 // written through gwrite to appear in the terminal rather 116 // than be written to in some buffer, if we're in a panicking state. 117 // Note that we can't just clear writebuf in the gp.m.dying case 118 // because a panic isn't allowed to have any write barriers. 119 if gp == nil || gp.writebuf == nil || gp.m.dying > 0 { 120 writeErr(b) 121 return 122 } 123 124 n := copy(gp.writebuf[len(gp.writebuf):cap(gp.writebuf)], b) 125 gp.writebuf = gp.writebuf[:len(gp.writebuf)+n] 126} 127 128func printsp() { 129 printstring(" ") 130} 131 132func printnl() { 133 printstring("\n") 134} 135 136func printbool(v bool) { 137 if v { 138 printstring("true") 139 } else { 140 printstring("false") 141 } 142} 143 144func printfloat(v float64) { 145 switch { 146 case v != v: 147 printstring("NaN") 148 return 149 case v+v == v && v > 0: 150 printstring("+Inf") 151 return 152 case v+v == v && v < 0: 153 printstring("-Inf") 154 return 155 } 156 157 const n = 7 // digits printed 158 var buf [n + 7]byte 159 buf[0] = '+' 160 e := 0 // exp 161 if v == 0 { 162 if 1/v < 0 { 163 buf[0] = '-' 164 } 165 } else { 166 if v < 0 { 167 v = -v 168 buf[0] = '-' 169 } 170 171 // normalize 172 for v >= 10 { 173 e++ 174 v /= 10 175 } 176 for v < 1 { 177 e-- 178 v *= 10 179 } 180 181 // round 182 h := 5.0 183 for i := 0; i < n; i++ { 184 h /= 10 185 } 186 v += h 187 if v >= 10 { 188 e++ 189 v /= 10 190 } 191 } 192 193 // format +d.dddd+edd 194 for i := 0; i < n; i++ { 195 s := int(v) 196 buf[i+2] = byte(s + '0') 197 v -= float64(s) 198 v *= 10 199 } 200 buf[1] = buf[2] 201 buf[2] = '.' 202 203 buf[n+2] = 'e' 204 buf[n+3] = '+' 205 if e < 0 { 206 e = -e 207 buf[n+3] = '-' 208 } 209 210 buf[n+4] = byte(e/100) + '0' 211 buf[n+5] = byte(e/10)%10 + '0' 212 buf[n+6] = byte(e%10) + '0' 213 gwrite(buf[:]) 214} 215 216func printcomplex(c complex128) { 217 print("(", real(c), imag(c), "i)") 218} 219 220func printuint(v uint64) { 221 var buf [100]byte 222 i := len(buf) 223 for i--; i > 0; i-- { 224 buf[i] = byte(v%10 + '0') 225 if v < 10 { 226 break 227 } 228 v /= 10 229 } 230 gwrite(buf[i:]) 231} 232 233func printint(v int64) { 234 if v < 0 { 235 printstring("-") 236 v = -v 237 } 238 printuint(uint64(v)) 239} 240 241func printhex(v uint64) { 242 const dig = "0123456789abcdef" 243 var buf [100]byte 244 i := len(buf) 245 for i--; i > 0; i-- { 246 buf[i] = dig[v%16] 247 if v < 16 { 248 break 249 } 250 v /= 16 251 } 252 i-- 253 buf[i] = 'x' 254 i-- 255 buf[i] = '0' 256 gwrite(buf[i:]) 257} 258 259func printpointer(p unsafe.Pointer) { 260 printhex(uint64(uintptr(p))) 261} 262func printuintptr(p uintptr) { 263 printhex(uint64(p)) 264} 265 266func printstring(s string) { 267 gwrite(bytes(s)) 268} 269 270func printslice(s []byte) { 271 sp := (*slice)(unsafe.Pointer(&s)) 272 print("[", len(s), "/", cap(s), "]") 273 printpointer(sp.array) 274} 275 276func printeface(e eface) { 277 print("(", e._type, ",", e.data, ")") 278} 279 280func printiface(i iface) { 281 print("(", i.tab, ",", i.data, ")") 282} 283 284// hexdumpWords prints a word-oriented hex dump of [p, end). 285// 286// If mark != nil, it will be called with each printed word's address 287// and should return a character mark to appear just before that 288// word's value. It can return 0 to indicate no mark. 289func hexdumpWords(p, end uintptr, mark func(uintptr) byte) { 290 p1 := func(x uintptr) { 291 var buf [2 * sys.PtrSize]byte 292 for i := len(buf) - 1; i >= 0; i-- { 293 if x&0xF < 10 { 294 buf[i] = byte(x&0xF) + '0' 295 } else { 296 buf[i] = byte(x&0xF) - 10 + 'a' 297 } 298 x >>= 4 299 } 300 gwrite(buf[:]) 301 } 302 303 printlock() 304 var markbuf [1]byte 305 markbuf[0] = ' ' 306 for i := uintptr(0); p+i < end; i += sys.PtrSize { 307 if i%16 == 0 { 308 if i != 0 { 309 println() 310 } 311 p1(p + i) 312 print(": ") 313 } 314 315 if mark != nil { 316 markbuf[0] = mark(p + i) 317 if markbuf[0] == 0 { 318 markbuf[0] = ' ' 319 } 320 } 321 gwrite(markbuf[:]) 322 val := *(*uintptr)(unsafe.Pointer(p + i)) 323 p1(val) 324 print(" ") 325 326 // Can we symbolize val? 327 name, _, _, _ := funcfileline(val, -1, false) 328 if name != "" { 329 entry := funcentry(val) 330 print("<", name, "+", val-entry, "> ") 331 } 332 } 333 println() 334 printunlock() 335} 336