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 if gp == nil || gp.writebuf == nil { 114 writeErr(b) 115 return 116 } 117 118 n := copy(gp.writebuf[len(gp.writebuf):cap(gp.writebuf)], b) 119 gp.writebuf = gp.writebuf[:len(gp.writebuf)+n] 120} 121 122func printsp() { 123 printstring(" ") 124} 125 126func printnl() { 127 printstring("\n") 128} 129 130func printbool(v bool) { 131 if v { 132 printstring("true") 133 } else { 134 printstring("false") 135 } 136} 137 138func printfloat(v float64) { 139 switch { 140 case v != v: 141 printstring("NaN") 142 return 143 case v+v == v && v > 0: 144 printstring("+Inf") 145 return 146 case v+v == v && v < 0: 147 printstring("-Inf") 148 return 149 } 150 151 const n = 7 // digits printed 152 var buf [n + 7]byte 153 buf[0] = '+' 154 e := 0 // exp 155 if v == 0 { 156 if 1/v < 0 { 157 buf[0] = '-' 158 } 159 } else { 160 if v < 0 { 161 v = -v 162 buf[0] = '-' 163 } 164 165 // normalize 166 for v >= 10 { 167 e++ 168 v /= 10 169 } 170 for v < 1 { 171 e-- 172 v *= 10 173 } 174 175 // round 176 h := 5.0 177 for i := 0; i < n; i++ { 178 h /= 10 179 } 180 v += h 181 if v >= 10 { 182 e++ 183 v /= 10 184 } 185 } 186 187 // format +d.dddd+edd 188 for i := 0; i < n; i++ { 189 s := int(v) 190 buf[i+2] = byte(s + '0') 191 v -= float64(s) 192 v *= 10 193 } 194 buf[1] = buf[2] 195 buf[2] = '.' 196 197 buf[n+2] = 'e' 198 buf[n+3] = '+' 199 if e < 0 { 200 e = -e 201 buf[n+3] = '-' 202 } 203 204 buf[n+4] = byte(e/100) + '0' 205 buf[n+5] = byte(e/10)%10 + '0' 206 buf[n+6] = byte(e%10) + '0' 207 gwrite(buf[:]) 208} 209 210func printcomplex(c complex128) { 211 print("(", real(c), imag(c), "i)") 212} 213 214func printuint(v uint64) { 215 var buf [100]byte 216 i := len(buf) 217 for i--; i > 0; i-- { 218 buf[i] = byte(v%10 + '0') 219 if v < 10 { 220 break 221 } 222 v /= 10 223 } 224 gwrite(buf[i:]) 225} 226 227func printint(v int64) { 228 if v < 0 { 229 printstring("-") 230 v = -v 231 } 232 printuint(uint64(v)) 233} 234 235func printhex(v uint64) { 236 const dig = "0123456789abcdef" 237 var buf [100]byte 238 i := len(buf) 239 for i--; i > 0; i-- { 240 buf[i] = dig[v%16] 241 if v < 16 { 242 break 243 } 244 v /= 16 245 } 246 i-- 247 buf[i] = 'x' 248 i-- 249 buf[i] = '0' 250 gwrite(buf[i:]) 251} 252 253func printpointer(p unsafe.Pointer) { 254 printhex(uint64(uintptr(p))) 255} 256 257func printstring(s string) { 258 gwrite(bytes(s)) 259} 260 261func printslice(s []byte) { 262 sp := (*slice)(unsafe.Pointer(&s)) 263 print("[", len(s), "/", cap(s), "]") 264 printpointer(sp.array) 265} 266 267func printeface(e eface) { 268 print("(", e._type, ",", e.data, ")") 269} 270 271func printiface(i iface) { 272 print("(", i.tab, ",", i.data, ")") 273} 274