Source file src/runtime/print.go

     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/strconv"
     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  // The compiler knows that a print of a value of this type should use
    17  // printquoted instead of printstring.
    18  type quoted string
    19  
    20  func bytes(s string) (ret []byte) {
    21  	rp := (*slice)(unsafe.Pointer(&ret))
    22  	sp := stringStructOf(&s)
    23  	rp.array = sp.str
    24  	rp.len = sp.len
    25  	rp.cap = sp.len
    26  	return
    27  }
    28  
    29  var (
    30  	// printBacklog is a circular buffer of messages written with the builtin
    31  	// print* functions, for use in postmortem analysis of core dumps.
    32  	printBacklog      [512]byte
    33  	printBacklogIndex int
    34  )
    35  
    36  // recordForPanic maintains a circular buffer of messages written by the
    37  // runtime leading up to a process crash, allowing the messages to be
    38  // extracted from a core dump.
    39  //
    40  // The text written during a process crash (following "panic" or "fatal
    41  // error") is not saved, since the goroutine stacks will generally be readable
    42  // from the runtime data structures in the core file.
    43  func recordForPanic(b []byte) {
    44  	printlock()
    45  
    46  	if panicking.Load() == 0 {
    47  		// Not actively crashing: maintain circular buffer of print output.
    48  		for i := 0; i < len(b); {
    49  			n := copy(printBacklog[printBacklogIndex:], b[i:])
    50  			i += n
    51  			printBacklogIndex += n
    52  			printBacklogIndex %= len(printBacklog)
    53  		}
    54  	}
    55  
    56  	printunlock()
    57  }
    58  
    59  var debuglock mutex
    60  
    61  // The compiler emits calls to printlock and printunlock around
    62  // the multiple calls that implement a single Go print or println
    63  // statement. Some of the print helpers (printslice, for example)
    64  // call print recursively. There is also the problem of a crash
    65  // happening during the print routines and needing to acquire
    66  // the print lock to print information about the crash.
    67  // For both these reasons, let a thread acquire the printlock 'recursively'.
    68  
    69  func printlock() {
    70  	mp := getg().m
    71  	mp.locks++ // do not reschedule between printlock++ and lock(&debuglock).
    72  	mp.printlock++
    73  	if mp.printlock == 1 {
    74  		lock(&debuglock)
    75  	}
    76  	mp.locks-- // now we know debuglock is held and holding up mp.locks for us.
    77  }
    78  
    79  func printunlock() {
    80  	mp := getg().m
    81  	mp.printlock--
    82  	if mp.printlock == 0 {
    83  		unlock(&debuglock)
    84  	}
    85  }
    86  
    87  // write to goroutine-local buffer if diverting output,
    88  // or else standard error.
    89  func gwrite(b []byte) {
    90  	if len(b) == 0 {
    91  		return
    92  	}
    93  	recordForPanic(b)
    94  	gp := getg()
    95  	// Don't use the writebuf if gp.m is dying. We want anything
    96  	// written through gwrite to appear in the terminal rather
    97  	// than be written to in some buffer, if we're in a panicking state.
    98  	// Note that we can't just clear writebuf in the gp.m.dying case
    99  	// because a panic isn't allowed to have any write barriers.
   100  	if gp == nil || gp.writebuf == nil || gp.m.dying > 0 {
   101  		writeErr(b)
   102  		return
   103  	}
   104  
   105  	n := copy(gp.writebuf[len(gp.writebuf):cap(gp.writebuf)], b)
   106  	gp.writebuf = gp.writebuf[:len(gp.writebuf)+n]
   107  }
   108  
   109  func printsp() {
   110  	printstring(" ")
   111  }
   112  
   113  func printnl() {
   114  	printstring("\n")
   115  }
   116  
   117  func printbool(v bool) {
   118  	if v {
   119  		printstring("true")
   120  	} else {
   121  		printstring("false")
   122  	}
   123  }
   124  
   125  // float64 requires 1+17+1+1+1+3 = 24 bytes max (sign+digits+decimal point+e+sign+exponent digits).
   126  const float64Bytes = 24
   127  
   128  func printfloat64(v float64) {
   129  	var buf [float64Bytes]byte
   130  	gwrite(strconv.AppendFloat(buf[:0], v, 'g', -1, 64))
   131  }
   132  
   133  // float32 requires 1+9+1+1+1+2 = 15 bytes max (sign+digits+decimal point+e+sign+exponent digits).
   134  const float32Bytes = 15
   135  
   136  func printfloat32(v float32) {
   137  	var buf [float32Bytes]byte
   138  	gwrite(strconv.AppendFloat(buf[:0], float64(v), 'g', -1, 32))
   139  }
   140  
   141  // complex128 requires 24+24+1+1+1 = 51 bytes max (paren+float64+float64+i+paren).
   142  const complex128Bytes = 2*float64Bytes + 3
   143  
   144  func printcomplex128(c complex128) {
   145  	var buf [complex128Bytes]byte
   146  	gwrite(strconv.AppendComplex(buf[:0], c, 'g', -1, 128))
   147  }
   148  
   149  // complex64 requires 15+15+1+1+1 = 33 bytes max (paren+float32+float32+i+paren).
   150  const complex64Bytes = 2*float32Bytes + 3
   151  
   152  func printcomplex64(c complex64) {
   153  	var buf [complex64Bytes]byte
   154  	gwrite(strconv.AppendComplex(buf[:0], complex128(c), 'g', -1, 64))
   155  }
   156  
   157  func printuint(v uint64) {
   158  	// Note: Avoiding strconv.AppendUint so that it's clearer
   159  	// that there are no allocations in this routine.
   160  	// cmd/link/internal/ld.TestAbstractOriginSanity
   161  	// sees the append and doesn't realize it doesn't allocate.
   162  	var buf [20]byte
   163  	i := strconv.RuntimeFormatBase10(buf[:], v)
   164  	gwrite(buf[i:])
   165  }
   166  
   167  func printint(v int64) {
   168  	// Note: Avoiding strconv.AppendUint so that it's clearer
   169  	// that there are no allocations in this routine.
   170  	// cmd/link/internal/ld.TestAbstractOriginSanity
   171  	// sees the append and doesn't realize it doesn't allocate.
   172  	neg := v < 0
   173  	u := uint64(v)
   174  	if neg {
   175  		u = -u
   176  	}
   177  	var buf [20]byte
   178  	i := strconv.RuntimeFormatBase10(buf[:], u)
   179  	if neg {
   180  		i--
   181  		buf[i] = '-'
   182  	}
   183  	gwrite(buf[i:])
   184  }
   185  
   186  var minhexdigits = 0 // protected by printlock
   187  
   188  func printhexopts(include0x bool, mindigits int, v uint64) {
   189  	const dig = "0123456789abcdef"
   190  	var buf [100]byte
   191  	i := len(buf)
   192  	for i--; i > 0; i-- {
   193  		buf[i] = dig[v%16]
   194  		if v < 16 && len(buf)-i >= mindigits {
   195  			break
   196  		}
   197  		v /= 16
   198  	}
   199  	if include0x {
   200  		i--
   201  		buf[i] = 'x'
   202  		i--
   203  		buf[i] = '0'
   204  	}
   205  	gwrite(buf[i:])
   206  }
   207  
   208  func printhex(v uint64) {
   209  	printhexopts(true, minhexdigits, v)
   210  }
   211  
   212  func printquoted(s string) {
   213  	printlock()
   214  	gwrite([]byte(`"`))
   215  	for i, r := range s {
   216  		switch r {
   217  		case '\n':
   218  			gwrite([]byte(`\n`))
   219  			continue
   220  		case '\r':
   221  			gwrite([]byte(`\r`))
   222  			continue
   223  		case '\t':
   224  			gwrite([]byte(`\t`))
   225  			print()
   226  			continue
   227  		case '\\', '"':
   228  			gwrite([]byte{byte('\\'), byte(r)})
   229  			continue
   230  		case runeError:
   231  			// Distinguish errors from a valid encoding of U+FFFD.
   232  			if _, j := decoderune(s, uint(i)); j == uint(i+1) {
   233  				gwrite(bytes(`\x`))
   234  				printhexopts(false, 2, uint64(s[i]))
   235  				continue
   236  			}
   237  			// Fall through to quoting.
   238  		}
   239  		// For now, only allow basic printable ascii through unescaped
   240  		if r >= ' ' && r <= '~' {
   241  			gwrite([]byte{byte(r)})
   242  		} else if r < 127 {
   243  			gwrite(bytes(`\x`))
   244  			printhexopts(false, 2, uint64(r))
   245  		} else if r < 0x1_0000 {
   246  			gwrite(bytes(`\u`))
   247  			printhexopts(false, 4, uint64(r))
   248  		} else {
   249  			gwrite(bytes(`\U`))
   250  			printhexopts(false, 8, uint64(r))
   251  		}
   252  	}
   253  	gwrite([]byte{byte('"')})
   254  	printunlock()
   255  }
   256  
   257  func printpointer(p unsafe.Pointer) {
   258  	printhex(uint64(uintptr(p)))
   259  }
   260  func printuintptr(p uintptr) {
   261  	printhex(uint64(p))
   262  }
   263  
   264  func printstring(s string) {
   265  	gwrite(bytes(s))
   266  }
   267  
   268  func printslice(s []byte) {
   269  	sp := (*slice)(unsafe.Pointer(&s))
   270  	print("[", len(s), "/", cap(s), "]")
   271  	printpointer(sp.array)
   272  }
   273  
   274  func printeface(e eface) {
   275  	print("(", e._type, ",", e.data, ")")
   276  }
   277  
   278  func printiface(i iface) {
   279  	print("(", i.tab, ",", i.data, ")")
   280  }
   281  

View as plain text