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

View as plain text