// if not known. If Func is not nil then Entry ==
// Func.Entry().
Entry uintptr
+
+ // The runtime's internal view of the function. This field
+ // is set (funcInfo.valid() returns true) only for Go functions,
+ // not for C functions.
+ funcInfo funcInfo
}
// CallersFrames takes a slice of PC values returned by Callers and
pc--
}
name := funcname(funcInfo)
- file, line := funcline1(funcInfo, pc, false)
if inldata := funcdata(funcInfo, _FUNCDATA_InlTree); inldata != nil {
inltree := (*[1 << 20]inlinedCall)(inldata)
ix := pcdatavalue(funcInfo, _PCDATA_InlTreeIndex, pc, nil)
PC: pc,
Func: f,
Function: name,
- File: file,
- Line: int(line),
Entry: entry,
+ funcInfo: funcInfo,
+ // Note: File,Line set below
})
}
// Avoid allocation in the common case, which is 1 or 2 frames.
switch len(ci.frames) {
case 0: // In the rare case when there are no frames at all, we return Frame{}.
+ return
case 1:
frame = ci.frames[0]
ci.frames = ci.frameStore[:0]
ci.frames = ci.frames[1:]
}
more = len(ci.frames) > 0
+ if frame.funcInfo.valid() {
+ // Compute file/line just before we need to return it,
+ // as it can be expensive. This avoids computing file/line
+ // for the Frame we find but don't return. See issue 32093.
+ file, line := funcline1(frame.funcInfo, frame.PC, false)
+ frame.File, frame.Line = file, int(line)
+ }
return
}
File: gostring(arg.file),
Line: int(arg.lineno),
Entry: arg.entry,
+ // funcInfo is zero, which implies !funcInfo.valid().
+ // That ensures that we use the File/Line info given here.
})
if arg.more == 0 {
break