Left: | ||
Right: |
OLD | NEW |
---|---|
(Empty) | |
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 // The debug package contains facilities for programs to debug themselves | |
6 // while 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. | |
rsc
2011/01/19 18:31:42
s/()//
| |
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 func Stack() []byte { | |
33 return stack() | |
34 } | |
35 | |
36 // stack implements Stack(), skipping 2 frames | |
rsc
2011/01/19 18:31:42
s/()//
| |
37 func stack() []byte { | |
38 buf := new(bytes.Buffer) // the returned data | |
39 // As we loop, we open files and read them. These variables record the c urrently | |
40 // loaded file. | |
41 var lines [][]byte | |
42 var lastFile string | |
43 for i := 2; ; i++ { // Caller we care about is the user, 2 frames up | |
44 pc, file, line, ok := runtime.Caller(i) | |
45 if !ok { | |
46 break | |
47 } | |
48 // Print this much at least. If we can't find the source, it wo n't show. | |
49 fmt.Fprintf(buf, "%s:%d (0x%x)\n", file, line, pc) | |
50 if file != lastFile { | |
51 data, err := ioutil.ReadFile(file) | |
52 if err != nil { | |
53 continue | |
54 } | |
55 lines = bytes.Split(data, []byte{'\n'}, -1) | |
56 lastFile = file | |
57 } | |
58 line-- // in stack trace, lines are 1-indexed but our array is 0 -indexed | |
59 fmt.Fprintf(buf, "\t%s: %s\n", function(pc), source(lines, line) ) | |
60 } | |
61 return buf.Bytes() | |
62 } | |
63 | |
64 // source returns a space-trimmed slice of the n'th line. | |
65 func source(lines [][]byte, n int) []byte { | |
66 if n < 0 || n >= len(lines) { | |
67 return dunno | |
68 } | |
69 return bytes.Trim(lines[n], " \t") | |
70 } | |
71 | |
72 // function returns, if possible, the name of the function containing the PC. | |
73 func function(pc uintptr) []byte { | |
74 fn := runtime.FuncForPC(pc) | |
75 if fn == nil { | |
76 return dunno | |
77 } | |
78 name := []byte(fn.Name()) | |
79 // The name includes the path name to the package, which is unnecessary | |
80 // since the file name is already included. Plus, it has center dots. | |
81 // That is, we see | |
82 // runtime/debug.*T·ptrmethod | |
83 // and want | |
84 // *T.ptrmethod | |
85 if period := bytes.Index(name, dot); period >= 0 { | |
86 name = name[period+1:] | |
87 } | |
88 name = bytes.Replace(name, centerDot, dot, -1) | |
89 return name | |
90 } | |
OLD | NEW |