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