// printStackRecord prints the function + source line information // for a single stack trace. func printStackRecord(w io.Writer, stk []uintptr, allFrames bool) { show := allFrames frames := runtime.CallersFrames(stk) for { frame, more := frames.Next() name := frame.Function if name == "" { show = true fmt.Fprintf(w, "#\t%#x\n", frame.PC) } else if name != "runtime.goexit" && (show || !strings.HasPrefix(name, "runtime.")) { // Hide runtime.goexit and any runtime functions at the beginning. // This is useful mainly for allocation traces. show = true fmt.Fprintf(w, "#\t%#x\t%s+%#x\t%s:%d\n", frame.PC, name, frame.PC-frame.Entry, frame.File, frame.Line) } if !more { break } } if !show { // We didn't print anything; do it again, // and this time include runtime functions. printStackRecord(w, stk, true) return } fmt.Fprintf(w, "\n") }
func (self *NotifierTrace) AddRuntimeFrames(frames *runtime.Frames) error { if self.Frames != nil { return errors.New("Already added frames") } if frames == nil { pc := make([]uintptr, 100, 100) num := runtime.Callers(3, pc) frames = runtime.CallersFrames(pc[:num]) } notif_frames := make([]*NotifierFrame, 0, 100) for { fr, more := frames.Next() notif_frames = append( notif_frames, &NotifierFrame{ Filename: fr.File, Line: fr.Line, Method: fr.Function, }, ) if !more { break } } self.Frames = notif_frames return nil }
//export G2 func G2() { pc := make([]uintptr, 32) n := runtime.Callers(0, pc) cf := runtime.CallersFrames(pc[:n]) var frames []runtime.Frame for { frame, more := cf.Next() frames = append(frames, frame) if !more { break } } want := []struct { function string line int }{ {"main.G2", 0}, {"cFunction", 0x10200}, {"cFunction", 0x200}, {"cFunction", 0x10201}, {"cFunction", 0x201}, {"main.G1", 0}, {"cFunction", 0x10100}, {"cFunction", 0x100}, {"main.TracebackContext", 0}, } ok := true i := 0 wantLoop: for _, w := range want { for ; i < len(frames); i++ { if w.function == frames[i].Function { if w.line != 0 && w.line != frames[i].Line { fmt.Printf("found function %s at wrong line %#x (expected %#x)\n", w.function, frames[i].Line, w.line) ok = false } i++ continue wantLoop } } fmt.Printf("did not find function %s in\n", w.function) for _, f := range frames { fmt.Println(f) } ok = false break } tracebackOK = ok if got := C.getContextCount(); got != 2 { fmt.Printf("at bottom contextCount == %d, expected 2\n", got) tracebackOK = false } }
func getCallerFrame(i interface{}) *runtime.Frame { pc := reflect.ValueOf(i).Pointer() frames := runtime.CallersFrames([]uintptr{pc}) if frames == nil { return nil } frame, _ := frames.Next() if frame.Entry == 0 { return nil } return &frame }
// printStackRecord prints the function + source line information // for a single stack trace. func printStackRecord(w io.Writer, stk []uintptr, allFrames bool) { show := allFrames frames := runtime.CallersFrames(stk) for { frame, more := frames.Next() name := frame.Function // Hide runtime.goexit and any runtime functions at the beginning. // This is useful mainly for allocation traces. skip := name == "runtime.goexit" if !show { switch { case strings.HasPrefix(name, "runtime."): skip = true case strings.HasPrefix(name, "runtime_"): skip = true case !strings.Contains(name, ".") && strings.HasPrefix(name, "__go_"): skip = true } } if !show && name == "" { // This can happen due to http://gcc.gnu.org/PR65797. } else if name == "" { fmt.Fprintf(w, "#\t%#x\n", frame.PC) } else if !skip { show = true fmt.Fprintf(w, "#\t%#x\t%s+%#x\t%s:%d\n", frame.PC, name, frame.PC-frame.Entry, frame.File, frame.Line) } if !more { break } } if !show { // We didn't print anything; do it again, // and this time include runtime functions. printStackRecord(w, stk, true) return } fmt.Fprintf(w, "\n") }
func testCallers(t *testing.T, pcs []uintptr, pan bool) { m := make(map[string]int, len(pcs)) frames := runtime.CallersFrames(pcs) for { frame, more := frames.Next() if frame.Function != "" { m[frame.Function] = frame.Line } if !more { break } } var seen []string for k := range m { seen = append(seen, k) } t.Logf("functions seen: %s", strings.Join(seen, " ")) var f3Line int if pan { f3Line = 23 } else { f3Line = 26 } want := []struct { name string line int }{ {"f1", 14}, {"f2", 18}, {"f3", f3Line}, } for _, w := range want { if got := m["runtime_test."+w.name]; got != w.line { t.Errorf("%s is line %d, want %d", w.name, got, w.line) } } }