...
Run Format

Source file src/runtime/print.go

Documentation: runtime

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

View as plain text