Run Format

Source file src/pkg/runtime/debug/stack.go

     1	// Copyright 2011 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 debug contains facilities for programs to debug themselves while
     6	// they are running.
     7	package debug
     8	
     9	import (
    10		"bytes"
    11		"fmt"
    12		"io/ioutil"
    13		"os"
    14		"runtime"
    15	)
    16	
    17	var (
    18		dunno     = []byte("???")
    19		centerDot = []byte("·")
    20		dot       = []byte(".")
    21	)
    22	
    23	// PrintStack prints to standard error the stack trace returned by Stack.
    24	func PrintStack() {
    25		os.Stderr.Write(stack())
    26	}
    27	
    28	// Stack returns a formatted stack trace of the goroutine that calls it.
    29	// For each routine, it includes the source line information and PC value,
    30	// then attempts to discover, for Go functions, the calling function or
    31	// method and the text of the line containing the invocation.
    32	//
    33	// This function is deprecated. Use package runtime's Stack instead.
    34	func Stack() []byte {
    35		return stack()
    36	}
    37	
    38	// stack implements Stack, skipping 2 frames
    39	func stack() []byte {
    40		buf := new(bytes.Buffer) // the returned data
    41		// As we loop, we open files and read them. These variables record the currently
    42		// loaded file.
    43		var lines [][]byte
    44		var lastFile string
    45		for i := 2; ; i++ { // Caller we care about is the user, 2 frames up
    46			pc, file, line, ok := runtime.Caller(i)
    47			if !ok {
    48				break
    49			}
    50			// Print this much at least.  If we can't find the source, it won't show.
    51			fmt.Fprintf(buf, "%s:%d (0x%x)\n", file, line, pc)
    52			if file != lastFile {
    53				data, err := ioutil.ReadFile(file)
    54				if err != nil {
    55					continue
    56				}
    57				lines = bytes.Split(data, []byte{'\n'})
    58				lastFile = file
    59			}
    60			line-- // in stack trace, lines are 1-indexed but our array is 0-indexed
    61			fmt.Fprintf(buf, "\t%s: %s\n", function(pc), source(lines, line))
    62		}
    63		return buf.Bytes()
    64	}
    65	
    66	// source returns a space-trimmed slice of the n'th line.
    67	func source(lines [][]byte, n int) []byte {
    68		if n < 0 || n >= len(lines) {
    69			return dunno
    70		}
    71		return bytes.Trim(lines[n], " \t")
    72	}
    73	
    74	// function returns, if possible, the name of the function containing the PC.
    75	func function(pc uintptr) []byte {
    76		fn := runtime.FuncForPC(pc)
    77		if fn == nil {
    78			return dunno
    79		}
    80		name := []byte(fn.Name())
    81		// The name includes the path name to the package, which is unnecessary
    82		// since the file name is already included.  Plus, it has center dots.
    83		// That is, we see
    84		//	runtime/debug.*T·ptrmethod
    85		// and want
    86		//	*T.ptrmethod
    87		if period := bytes.Index(name, dot); period >= 0 {
    88			name = name[period+1:]
    89		}
    90		name = bytes.Replace(name, centerDot, dot, -1)
    91		return name
    92	}

View as plain text