github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/src/pkg/runtime/debug/stack.go (about) 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 }