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