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  	"internal/strconv"
    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 data structures in the core file.
    40  func recordForPanic(b []byte) {
    41  	printlock()
    42  
    43  	if panicking.Load() == 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  	// Don't use the writebuf if gp.m is dying. We want anything
    93  	// written through gwrite to appear in the terminal rather
    94  	// than be written to in some buffer, if we're in a panicking state.
    95  	// Note that we can't just clear writebuf in the gp.m.dying case
    96  	// because a panic isn't allowed to have any write barriers.
    97  	if gp == nil || gp.writebuf == nil || gp.m.dying > 0 {
    98  		writeErr(b)
    99  		return
   100  	}
   101  
   102  	n := copy(gp.writebuf[len(gp.writebuf):cap(gp.writebuf)], b)
   103  	gp.writebuf = gp.writebuf[:len(gp.writebuf)+n]
   104  }
   105  
   106  func printsp() {
   107  	printstring(" ")
   108  }
   109  
   110  func printnl() {
   111  	printstring("\n")
   112  }
   113  
   114  func printbool(v bool) {
   115  	if v {
   116  		printstring("true")
   117  	} else {
   118  		printstring("false")
   119  	}
   120  }
   121  
   122  func printfloat64(v float64) {
   123  	var buf [20]byte
   124  	gwrite(strconv.AppendFloat(buf[:0], v, 'g', -1, 64))
   125  }
   126  
   127  func printfloat32(v float32) {
   128  	var buf [20]byte
   129  	gwrite(strconv.AppendFloat(buf[:0], float64(v), 'g', -1, 32))
   130  }
   131  
   132  func printcomplex128(c complex128) {
   133  	var buf [44]byte
   134  	gwrite(strconv.AppendComplex(buf[:0], c, 'g', -1, 128))
   135  }
   136  
   137  func printcomplex64(c complex64) {
   138  	var buf [44]byte
   139  	gwrite(strconv.AppendComplex(buf[:0], complex128(c), 'g', -1, 64))
   140  }
   141  
   142  func printuint(v uint64) {
   143  	// Note: Avoiding strconv.AppendUint so that it's clearer
   144  	// that there are no allocations in this routine.
   145  	// cmd/link/internal/ld.TestAbstractOriginSanity
   146  	// sees the append and doesn't realize it doesn't allocate.
   147  	var buf [20]byte
   148  	i := strconv.RuntimeFormatBase10(buf[:], v)
   149  	gwrite(buf[i:])
   150  }
   151  
   152  func printint(v int64) {
   153  	// Note: Avoiding strconv.AppendUint so that it's clearer
   154  	// that there are no allocations in this routine.
   155  	// cmd/link/internal/ld.TestAbstractOriginSanity
   156  	// sees the append and doesn't realize it doesn't allocate.
   157  	neg := v < 0
   158  	u := uint64(v)
   159  	if neg {
   160  		u = -u
   161  	}
   162  	var buf [20]byte
   163  	i := strconv.RuntimeFormatBase10(buf[:], u)
   164  	if neg {
   165  		i--
   166  		buf[i] = '-'
   167  	}
   168  	gwrite(buf[i:])
   169  }
   170  
   171  var minhexdigits = 0 // protected by printlock
   172  
   173  func printhex(v uint64) {
   174  	const dig = "0123456789abcdef"
   175  	var buf [100]byte
   176  	i := len(buf)
   177  	for i--; i > 0; i-- {
   178  		buf[i] = dig[v%16]
   179  		if v < 16 && len(buf)-i >= minhexdigits {
   180  			break
   181  		}
   182  		v /= 16
   183  	}
   184  	i--
   185  	buf[i] = 'x'
   186  	i--
   187  	buf[i] = '0'
   188  	gwrite(buf[i:])
   189  }
   190  
   191  func printpointer(p unsafe.Pointer) {
   192  	printhex(uint64(uintptr(p)))
   193  }
   194  func printuintptr(p uintptr) {
   195  	printhex(uint64(p))
   196  }
   197  
   198  func printstring(s string) {
   199  	gwrite(bytes(s))
   200  }
   201  
   202  func printslice(s []byte) {
   203  	sp := (*slice)(unsafe.Pointer(&s))
   204  	print("[", len(s), "/", cap(s), "]")
   205  	printpointer(sp.array)
   206  }
   207  
   208  func printeface(e eface) {
   209  	print("(", e._type, ",", e.data, ")")
   210  }
   211  
   212  func printiface(i iface) {
   213  	print("(", i.tab, ",", i.data, ")")
   214  }
   215  
   216  // hexdumpWords prints a word-oriented hex dump of [p, end).
   217  //
   218  // If mark != nil, it will be called with each printed word's address
   219  // and should return a character mark to appear just before that
   220  // word's value. It can return 0 to indicate no mark.
   221  func hexdumpWords(p, end uintptr, mark func(uintptr) byte) {
   222  	printlock()
   223  	var markbuf [1]byte
   224  	markbuf[0] = ' '
   225  	minhexdigits = int(unsafe.Sizeof(uintptr(0)) * 2)
   226  	for i := uintptr(0); p+i < end; i += goarch.PtrSize {
   227  		if i%16 == 0 {
   228  			if i != 0 {
   229  				println()
   230  			}
   231  			print(hex(p+i), ": ")
   232  		}
   233  
   234  		if mark != nil {
   235  			markbuf[0] = mark(p + i)
   236  			if markbuf[0] == 0 {
   237  				markbuf[0] = ' '
   238  			}
   239  		}
   240  		gwrite(markbuf[:])
   241  		val := *(*uintptr)(unsafe.Pointer(p + i))
   242  		print(hex(val))
   243  		print(" ")
   244  
   245  		// Can we symbolize val?
   246  		fn := findfunc(val)
   247  		if fn.valid() {
   248  			print("<", funcname(fn), "+", hex(val-fn.entry()), "> ")
   249  		}
   250  	}
   251  	minhexdigits = 0
   252  	println()
   253  	printunlock()
   254  }
   255  

View as plain text