]> Cypherpunks.ru repositories - gostls13.git/blob - src/runtime/debug/stack.go
all: switch to the new deprecation convention
[gostls13.git] / src / 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 // 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 }