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/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  }
   302  

View as plain text