blob: 8f8268873b21ede2e671f453179651a74e396b81 [file] [log] [blame]
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package runtime
import "unsafe"
// The compiler knows that a print of a value of this type
// should use printhex instead of printuint (decimal).
type hex uint64
func bytes(s string) (ret []byte) {
rp := (*slice)(unsafe.Pointer(&ret))
sp := (*_string)(noescape(unsafe.Pointer(&s)))
rp.array = sp.str
rp.len = uint(sp.len)
rp.cap = uint(sp.len)
return
}
// printf is only called from C code. It has no type information for the args,
// but C stacks are ignored by the garbage collector anyway, so having
// type information would not add anything.
//go:nosplit
func printf(s *byte) {
vprintf(gostringnocopy(s), add(unsafe.Pointer(&s), unsafe.Sizeof(s)))
}
// sprintf is only called from C code. It has no type information for the args,
// but C stacks are ignored by the garbage collector anyway, so having
// type information would not add anything.
//go:nosplit
func snprintf(dst *byte, n int32, s *byte) {
buf := (*[1 << 30]byte)(unsafe.Pointer(dst))[0:n:n]
gp := getg()
gp.writebuf = buf[0:0 : n-1] // leave room for NUL, this is called from C
vprintf(gostringnocopy(s), add(unsafe.Pointer(&s), unsafe.Sizeof(s)))
buf[len(gp.writebuf)] = '\x00'
gp.writebuf = nil
}
//var debuglock mutex
// write to goroutine-local buffer if diverting output,
// or else standard error.
func gwrite(b []byte) {
if len(b) == 0 {
return
}
gp := getg()
if gp == nil || gp.writebuf == nil {
write(2, unsafe.Pointer(&b[0]), int32(len(b)))
return
}
n := copy(gp.writebuf[len(gp.writebuf):cap(gp.writebuf)], b)
gp.writebuf = gp.writebuf[:len(gp.writebuf)+n]
}
func prints(s *byte) {
b := (*[1 << 30]byte)(unsafe.Pointer(s))
for i := 0; ; i++ {
if b[i] == 0 {
gwrite(b[:i])
return
}
}
}
func printsp() {
print(" ")
}
func printnl() {
print("\n")
}
// Very simple printf. Only for debugging prints.
// Do not add to this without checking with Rob.
func vprintf(str string, arg unsafe.Pointer) {
//lock(&debuglock);
s := bytes(str)
start := 0
i := 0
for ; i < len(s); i++ {
if s[i] != '%' {
continue
}
if i > start {
gwrite(s[start:i])
}
if i++; i >= len(s) {
break
}
var siz uintptr
switch s[i] {
case 't', 'c':
siz = 1
case 'd', 'x': // 32-bit
arg = roundup(arg, 4)
siz = 4
case 'D', 'U', 'X', 'f': // 64-bit
arg = roundup(arg, unsafe.Sizeof(uintreg(0)))
siz = 8
case 'C':
arg = roundup(arg, unsafe.Sizeof(uintreg(0)))
siz = 16
case 'p', 's': // pointer-sized
arg = roundup(arg, unsafe.Sizeof(uintptr(0)))
siz = unsafe.Sizeof(uintptr(0))
case 'S': // pointer-aligned but bigger
arg = roundup(arg, unsafe.Sizeof(uintptr(0)))
siz = unsafe.Sizeof(string(""))
case 'a': // pointer-aligned but bigger
arg = roundup(arg, unsafe.Sizeof(uintptr(0)))
siz = unsafe.Sizeof([]byte{})
case 'i', 'e': // pointer-aligned but bigger
arg = roundup(arg, unsafe.Sizeof(uintptr(0)))
siz = unsafe.Sizeof(interface{}(nil))
}
switch s[i] {
case 'a':
printslice(*(*[]byte)(arg))
case 'c':
printbyte(*(*byte)(arg))
case 'd':
printint(int64(*(*int32)(arg)))
case 'D':
printint(int64(*(*int64)(arg)))
case 'e':
printeface(*(*interface{})(arg))
case 'f':
printfloat(*(*float64)(arg))
case 'C':
printcomplex(*(*complex128)(arg))
case 'i':
printiface(*(*fInterface)(arg))
case 'p':
printpointer(*(*unsafe.Pointer)(arg))
case 's':
prints(*(**byte)(arg))
case 'S':
printstring(*(*string)(arg))
case 't':
printbool(*(*bool)(arg))
case 'U':
printuint(*(*uint64)(arg))
case 'x':
printhex(uint64(*(*uint32)(arg)))
case 'X':
printhex(*(*uint64)(arg))
}
arg = add(arg, siz)
start = i + 1
}
if start < i {
gwrite(s[start:i])
}
//unlock(&debuglock);
}
func printpc(p unsafe.Pointer) {
print("PC=", hex(uintptr(p)))
}
func printbool(v bool) {
if v {
print("true")
} else {
print("false")
}
}
func printbyte(c byte) {
gwrite((*[1]byte)(unsafe.Pointer(&c))[:])
}
func printfloat(v float64) {
switch {
case v != v:
print("NaN")
return
case v+v == v && v > 0:
print("+Inf")
return
case v+v == v && v < 0:
print("-Inf")
return
}
const n = 7 // digits printed
var buf [n + 7]byte
buf[0] = '+'
e := 0 // exp
if v == 0 {
if 1/v < 0 {
buf[0] = '-'
}
} else {
if v < 0 {
v = -v
buf[0] = '-'
}
// normalize
for v >= 10 {
e++
v /= 10
}
for v < 1 {
e--
v *= 10
}
// round
h := 5.0
for i := 0; i < n; i++ {
h /= 10
}
v += h
if v >= 10 {
e++
v /= 10
}
}
// format +d.dddd+edd
for i := 0; i < n; i++ {
s := int(v)
buf[i+2] = byte(s + '0')
v -= float64(s)
v *= 10
}
buf[1] = buf[2]
buf[2] = '.'
buf[n+2] = 'e'
buf[n+3] = '+'
if e < 0 {
e = -e
buf[n+3] = '-'
}
buf[n+4] = byte(e/100) + '0'
buf[n+5] = byte(e/10)%10 + '0'
buf[n+6] = byte(e%10) + '0'
gwrite(buf[:])
}
func printcomplex(c complex128) {
print("(", real(c), imag(c), "i)")
}
func printuint(v uint64) {
var buf [100]byte
i := len(buf)
for i--; i > 0; i-- {
buf[i] = byte(v%10 + '0')
if v < 10 {
break
}
v /= 10
}
gwrite(buf[i:])
}
func printint(v int64) {
if v < 0 {
print("-")
v = -v
}
printuint(uint64(v))
}
func printhex(v uint64) {
const dig = "0123456789abcdef"
var buf [100]byte
i := len(buf)
for i--; i > 0; i-- {
buf[i] = dig[v%16]
if v < 16 {
break
}
v /= 16
}
i--
buf[i] = 'x'
i--
buf[i] = '0'
gwrite(buf[i:])
}
func printpointer(p unsafe.Pointer) {
printhex(uint64(uintptr(p)))
}
func printstring(s string) {
if uintptr(len(s)) > maxstring {
gwrite(bytes("[string too long]"))
return
}
gwrite(bytes(s))
}
func printslice(s []byte) {
sp := (*slice)(unsafe.Pointer(&s))
print("[", len(s), "/", cap(s), "]")
printpointer(unsafe.Pointer(sp.array))
}
func printeface(e interface{}) {
ep := (*eface)(unsafe.Pointer(&e))
print("(", ep._type, ",", ep.data, ")")
}
func printiface(i fInterface) {
ip := (*iface)(unsafe.Pointer(&i))
print("(", ip.tab, ",", ip.data, ")")
}