For #59670.
Change-Id: I517e97ea74cf232e5cfbb77b127fa8804f74d84b
Reviewed-on: https://go-review.googlesource.com/c/go/+/485495
Reviewed-by: Michael Pratt <mpratt@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Austin Clements <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
"bytes"
"cmd/internal/objabi"
"encoding/binary"
+ "internal/abi"
)
// CUFileIndex is used to index the filenames that are stored in the
type FuncInfo struct {
Args uint32
Locals uint32
- FuncID objabi.FuncID
+ FuncID abi.FuncID
FuncFlag objabi.FuncFlag
StartLine int32
File []CUFileIndex
func (*FuncInfo) ReadLocals(b []byte) uint32 { return binary.LittleEndian.Uint32(b[4:]) }
-func (*FuncInfo) ReadFuncID(b []byte) objabi.FuncID { return objabi.FuncID(b[8]) }
+func (*FuncInfo) ReadFuncID(b []byte) abi.FuncID { return abi.FuncID(b[8]) }
func (*FuncInfo) ReadFuncFlag(b []byte) objabi.FuncFlag { return objabi.FuncFlag(b[9]) }
"cmd/internal/sys"
"encoding/binary"
"fmt"
+ "internal/abi"
"sync"
"sync/atomic"
)
Args int32
Locals int32
Align int32
- FuncID objabi.FuncID
+ FuncID abi.FuncID
FuncFlag objabi.FuncFlag
StartLine int32
Text *Prog
package objabi
-import "strings"
+import (
+ "internal/abi"
+ "strings"
+)
// A FuncFlag records bits about a function, passed to the runtime.
type FuncFlag uint8
FuncFlag_ASM
)
-// A FuncID identifies particular functions that need to be treated
-// specially by the runtime.
-// Note that in some situations involving plugins, there may be multiple
-// copies of a particular special runtime function.
-type FuncID uint8
-
-// Note: this list must match the list in runtime/symtab.go.
-const (
- FuncID_normal FuncID = iota // not a special function
- FuncID_abort
- FuncID_asmcgocall
- FuncID_asyncPreempt
- FuncID_cgocallback
- FuncID_debugCallV2
- FuncID_gcBgMarkWorker
- FuncID_goexit
- FuncID_gogo
- FuncID_gopanic
- FuncID_handleAsyncEvent
- FuncID_mcall
- FuncID_morestack
- FuncID_mstart
- FuncID_panicwrap
- FuncID_rt0_go
- FuncID_runfinq
- FuncID_runtime_main
- FuncID_sigpanic
- FuncID_systemstack
- FuncID_systemstack_switch
- FuncID_wrapper // any autogenerated code (hash/eq algorithms, method wrappers, etc.)
-)
-
-var funcIDs = map[string]FuncID{
- "abort": FuncID_abort,
- "asmcgocall": FuncID_asmcgocall,
- "asyncPreempt": FuncID_asyncPreempt,
- "cgocallback": FuncID_cgocallback,
- "debugCallV2": FuncID_debugCallV2,
- "gcBgMarkWorker": FuncID_gcBgMarkWorker,
- "rt0_go": FuncID_rt0_go,
- "goexit": FuncID_goexit,
- "gogo": FuncID_gogo,
- "gopanic": FuncID_gopanic,
- "handleAsyncEvent": FuncID_handleAsyncEvent,
- "main": FuncID_runtime_main,
- "mcall": FuncID_mcall,
- "morestack": FuncID_morestack,
- "mstart": FuncID_mstart,
- "panicwrap": FuncID_panicwrap,
- "runfinq": FuncID_runfinq,
- "sigpanic": FuncID_sigpanic,
- "systemstack_switch": FuncID_systemstack_switch,
- "systemstack": FuncID_systemstack,
+var funcIDs = map[string]abi.FuncID{
+ "abort": abi.FuncID_abort,
+ "asmcgocall": abi.FuncID_asmcgocall,
+ "asyncPreempt": abi.FuncID_asyncPreempt,
+ "cgocallback": abi.FuncID_cgocallback,
+ "debugCallV2": abi.FuncID_debugCallV2,
+ "gcBgMarkWorker": abi.FuncID_gcBgMarkWorker,
+ "rt0_go": abi.FuncID_rt0_go,
+ "goexit": abi.FuncID_goexit,
+ "gogo": abi.FuncID_gogo,
+ "gopanic": abi.FuncID_gopanic,
+ "handleAsyncEvent": abi.FuncID_handleAsyncEvent,
+ "main": abi.FuncID_runtime_main,
+ "mcall": abi.FuncID_mcall,
+ "morestack": abi.FuncID_morestack,
+ "mstart": abi.FuncID_mstart,
+ "panicwrap": abi.FuncID_panicwrap,
+ "runfinq": abi.FuncID_runfinq,
+ "sigpanic": abi.FuncID_sigpanic,
+ "systemstack_switch": abi.FuncID_systemstack_switch,
+ "systemstack": abi.FuncID_systemstack,
// Don't show in call stack but otherwise not special.
- "deferreturn": FuncID_wrapper,
- "runOpenDeferFrame": FuncID_wrapper,
- "deferCallSave": FuncID_wrapper,
+ "deferreturn": abi.FuncIDWrapper,
+ "runOpenDeferFrame": abi.FuncIDWrapper,
+ "deferCallSave": abi.FuncIDWrapper,
}
// Get the function ID for the named function in the named file.
// The function should be package-qualified.
-func GetFuncID(name string, isWrapper bool) FuncID {
+func GetFuncID(name string, isWrapper bool) abi.FuncID {
if isWrapper {
- return FuncID_wrapper
+ return abi.FuncIDWrapper
}
if strings.HasPrefix(name, "runtime.") {
if id, ok := funcIDs[name[len("runtime."):]]; ok {
return id
}
}
- return FuncID_normal
+ return abi.FuncIDNormal
}
"cmd/link/internal/loader"
"cmd/link/internal/sym"
"fmt"
+ "internal/abi"
"internal/buildcfg"
"os"
"path/filepath"
}
inlFunc := ldr.FuncInfo(call.Func)
- var funcID objabi.FuncID
+ var funcID abi.FuncID
startLine := int32(0)
if inlFunc.Valid() {
funcID = inlFunc.FuncID()
off = sb.SetUint32(ctxt.Arch, off, uint32(startLine))
// funcID uint8
- var funcID objabi.FuncID
+ var funcID abi.FuncID
if fi.Valid() {
funcID = fi.FuncID()
}
"cmd/link/internal/sym"
"debug/elf"
"fmt"
+ "internal/abi"
"io"
"log"
"math/bits"
return int((*goobj.FuncInfo)(nil).ReadLocals(fi.data))
}
-func (fi *FuncInfo) FuncID() objabi.FuncID {
+func (fi *FuncInfo) FuncID() abi.FuncID {
return (*goobj.FuncInfo)(nil).ReadFuncID(fi.data)
}
--- /dev/null
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package abi
+
+// A FuncID identifies particular functions that need to be treated
+// specially by the runtime.
+// Note that in some situations involving plugins, there may be multiple
+// copies of a particular special runtime function.
+type FuncID uint8
+
+const (
+ // If you add a FuncID, you probably also want to add an entry to the map in
+ // ../../cmd/internal/objabi/funcid.go
+
+ FuncIDNormal FuncID = iota // not a special function
+ FuncID_abort
+ FuncID_asmcgocall
+ FuncID_asyncPreempt
+ FuncID_cgocallback
+ FuncID_debugCallV2
+ FuncID_gcBgMarkWorker
+ FuncID_goexit
+ FuncID_gogo
+ FuncID_gopanic
+ FuncID_handleAsyncEvent
+ FuncID_mcall
+ FuncID_morestack
+ FuncID_mstart
+ FuncID_panicwrap
+ FuncID_rt0_go
+ FuncID_runfinq
+ FuncID_runtime_main
+ FuncID_sigpanic
+ FuncID_systemstack
+ FuncID_systemstack_switch
+ FuncIDWrapper // any autogenerated code (hash/eq algorithms, method wrappers, etc.)
+)
package runtime
import (
+ "internal/abi"
"internal/goarch"
"runtime/internal/atomic"
"runtime/internal/sys"
print("scanframe ", funcname(frame.fn), "\n")
}
- isAsyncPreempt := frame.fn.valid() && frame.fn.funcID == funcID_asyncPreempt
- isDebugCall := frame.fn.valid() && frame.fn.funcID == funcID_debugCallV2
+ isAsyncPreempt := frame.fn.valid() && frame.fn.funcID == abi.FuncID_asyncPreempt
+ isDebugCall := frame.fn.valid() && frame.fn.funcID == abi.FuncID_debugCallV2
if state.conservative || isAsyncPreempt || isDebugCall {
if debugScanConservative {
println("conservatively scanning function", funcname(frame.fn), "at PC", hex(frame.continpc))
package runtime
import (
+ "internal/abi"
"internal/goarch"
"runtime/internal/atomic"
"runtime/internal/sys"
if !f.valid() {
return false
}
- return f.funcID == funcID_abort
+ return f.funcID == abi.FuncID_abort
}
u, uf := newInlineUnwinder(fi, pc, nil)
for ; uf.valid(); uf = u.next(uf) {
sf := u.srcFunc(uf)
- if sf.funcID == funcID_wrapper {
+ if sf.funcID == abi.FuncIDWrapper {
// ignore wrappers
continue
}
package runtime
import (
+ "internal/abi"
"internal/goarch"
"runtime/internal/atomic"
"runtime/internal/sys"
pcfile uint32
pcln uint32
npcdata uint32
- cuOffset uint32 // runtime.cutab offset of this function's CU
- startLine int32 // line number of start of function (func keyword/TEXT directive)
- funcID funcID // set for certain special runtime functions
+ cuOffset uint32 // runtime.cutab offset of this function's CU
+ startLine int32 // line number of start of function (func keyword/TEXT directive)
+ funcID abi.FuncID // set for certain special runtime functions
flag funcFlag
_ [1]byte // pad
nfuncdata uint8 // must be last, must end on a uint32-aligned boundary
if stackDebug >= 2 {
print(" adjusting ", funcname(f), " frame=[", hex(frame.sp), ",", hex(frame.fp), "] pc=", hex(frame.pc), " continpc=", hex(frame.continpc), "\n")
}
- if f.funcID == funcID_systemstack_switch {
+ if f.funcID == abi.FuncID_systemstack_switch {
// A special routine at the bottom of stack of a goroutine that does a systemstack call.
// We will allow it to be copied even though we don't
// have full GC info for it (because it is written in asm).
return
}
f := findfunc(gp.startpc)
- if f.valid() && f.funcID == funcID_gcBgMarkWorker {
+ if f.valid() && f.funcID == abi.FuncID_gcBgMarkWorker {
// We're not allowed to shrink the gcBgMarkWorker
// stack (see gcBgMarkWorker for explanation).
return
package runtime
import (
+ "internal/abi"
"internal/goarch"
"runtime/internal/atomic"
"runtime/internal/sys"
// Treat the previous func as normal. We haven't actually checked, but
// since this pc was included in the stack, we know it shouldn't be
// elided.
- calleeID := funcID_normal
+ calleeID := abi.FuncIDNormal
// Remove pc from stk; we'll re-add it below.
stk = stk[:len(stk)-1]
for ; uf.valid(); uf = u.next(uf) {
funcID := u.srcFunc(uf).funcID
- if funcID == funcID_wrapper && elideWrapperCalling(calleeID) {
+ if funcID == abi.FuncIDWrapper && elideWrapperCalling(calleeID) {
// ignore wrappers
} else {
stk = append(stk, uf.pc+1)
_PCDATA_RestartAtEntry = -5
)
-// A FuncID identifies particular functions that need to be treated
-// specially by the runtime.
-// Note that in some situations involving plugins, there may be multiple
-// copies of a particular special runtime function.
-// Note: this list must match the list in cmd/internal/objabi/funcid.go.
-type funcID uint8
-
-const (
- funcID_normal funcID = iota // not a special function
- funcID_abort
- funcID_asmcgocall
- funcID_asyncPreempt
- funcID_cgocallback
- funcID_debugCallV2
- funcID_gcBgMarkWorker
- funcID_goexit
- funcID_gogo
- funcID_gopanic
- funcID_handleAsyncEvent
- funcID_mcall
- funcID_morestack
- funcID_mstart
- funcID_panicwrap
- funcID_rt0_go
- funcID_runfinq
- funcID_runtime_main
- funcID_sigpanic
- funcID_systemstack
- funcID_systemstack_switch
- funcID_wrapper // any autogenerated code (hash/eq algorithms, method wrappers, etc.)
-)
-
// A FuncFlag holds bits about a function.
// This list must match the list in cmd/internal/objabi/funcid.go.
type funcFlag uint8
datap *moduledata
nameOff int32
startLine int32
- funcID funcID
+ funcID abi.FuncID
}
func (f funcInfo) srcFunc() srcFunc {
package runtime
+import "internal/abi"
+
// inlinedCall is the encoding of entries in the FUNCDATA_InlTree table.
type inlinedCall struct {
- funcID funcID // type of the called function
+ funcID abi.FuncID // type of the called function
_ [3]byte
nameOff int32 // offset into pclntab for name of called function
parentPc int32 // position of an instruction whose source position is the call site (offset from entry)
if start != wantStart[name] {
t.Errorf("tiuTest+%#x: want startLine %d, got %d", pc-pc1, wantStart[name], start)
}
- if sf.funcID != funcID_normal {
+ if sf.funcID != abi.FuncIDNormal {
t.Errorf("tiuTest+%#x: bad funcID %v", pc-pc1, sf.funcID)
}
package runtime
import (
+ "internal/abi"
"internal/goarch"
"runtime/internal/atomic"
"runtime/internal/sys"
var (
cache pcvalueCache
- lastFuncID = funcID_normal
+ lastFuncID = abi.FuncIDNormal
newPCBuf = make([]uintptr, 0, traceStackSize)
skip = pcBuf[0]
// skipOrAdd skips or appends retPC to newPCBuf and returns true if more
u, uf := newInlineUnwinder(fi, callPC, &cache)
for ; uf.valid(); uf = u.next(uf) {
sf := u.srcFunc(uf)
- if sf.funcID == funcID_wrapper && elideWrapperCalling(lastFuncID) {
+ if sf.funcID == abi.FuncIDWrapper && elideWrapperCalling(lastFuncID) {
// ignore wrappers
} else if more := skipOrAdd(uf.pc + 1); !more {
break outer
package runtime
import (
+ "internal/abi"
"internal/bytealg"
"internal/goarch"
"runtime/internal/sys"
// calleeFuncID is the function ID of the caller of the current
// frame.
- calleeFuncID funcID
+ calleeFuncID abi.FuncID
// flags are the flags to this unwind. Some of these are updated as we
// unwind (see the flags documentation).
frame: frame,
g: gp.guintptr(),
cgoCtxt: len(gp.cgoCtxt) - 1,
- calleeFuncID: funcID_normal,
+ calleeFuncID: abi.FuncIDNormal,
flags: flags,
}
// Compute function info flags.
flag := f.flag
- if f.funcID == funcID_cgocallback {
+ if f.funcID == abi.FuncID_cgocallback {
// cgocallback does write SP to switch from the g0 to the curg stack,
// but it carefully arranges that during the transition BOTH stacks
// have cgocallback frame valid for unwinding through.
// This ensures gp.m doesn't change from a stack jump.
if u.flags&unwindJumpStack != 0 && gp == gp.m.g0 && gp.m.curg != nil && gp.m.curg.m == gp.m {
switch f.funcID {
- case funcID_morestack:
+ case abi.FuncID_morestack:
// morestack does not return normally -- newstack()
// gogo's to curg.sched. Match that.
// This keeps morestack() from showing up in the backtrace,
frame.lr = gp.sched.lr
frame.sp = gp.sched.sp
u.cgoCtxt = len(gp.cgoCtxt) - 1
- case funcID_systemstack:
+ case abi.FuncID_systemstack:
// systemstack returns normally, so just follow the
// stack transition.
if usesLR && funcspdelta(f, frame.pc, &u.cache) == 0 {
// deferproc a second time (if the corresponding deferred func recovers).
// In the latter case, use a deferreturn call site as the continuation pc.
frame.continpc = frame.pc
- if u.calleeFuncID == funcID_sigpanic {
+ if u.calleeFuncID == abi.FuncID_sigpanic {
if frame.fn.deferreturn != 0 {
frame.continpc = frame.fn.entry() + uintptr(frame.fn.deferreturn) + 1
// Note: this may perhaps keep return variables alive longer than
// get everything, so crash loudly.
fail := u.flags&(unwindPrintErrors|unwindSilentErrors) == 0
doPrint := u.flags&unwindSilentErrors == 0
- if doPrint && gp.m.incgo && f.funcID == funcID_sigpanic {
+ if doPrint && gp.m.incgo && f.funcID == abi.FuncID_sigpanic {
// We can inject sigpanic
// calls directly into C code,
// in which case we'll see a C
throw("traceback stuck")
}
- injectedCall := f.funcID == funcID_sigpanic || f.funcID == funcID_asyncPreempt || f.funcID == funcID_debugCallV2
+ injectedCall := f.funcID == abi.FuncID_sigpanic || f.funcID == abi.FuncID_asyncPreempt || f.funcID == abi.FuncID_debugCallV2
if injectedCall {
u.flags |= unwindTrap
} else {
// If the current frame is not a cgo frame or if there's no registered cgo
// unwinder, it returns 0.
func (u *unwinder) cgoCallers(pcBuf []uintptr) int {
- if cgoTraceback == nil || u.frame.fn.funcID != funcID_cgocallback || u.cgoCtxt < 0 {
+ if cgoTraceback == nil || u.frame.fn.funcID != abi.FuncID_cgocallback || u.cgoCtxt < 0 {
// We don't have a cgo unwinder (typical case), or we do but we're not
// in a cgo frame or we're out of cgo context.
return 0
// TODO: Why does &u.cache cause u to escape? (Same in traceback2)
for iu, uf := newInlineUnwinder(f, u.symPC(), noEscapePtr(&u.cache)); n < len(pcBuf) && uf.valid(); uf = iu.next(uf) {
sf := iu.srcFunc(uf)
- if sf.funcID == funcID_wrapper && elideWrapperCalling(u.calleeFuncID) {
+ if sf.funcID == abi.FuncIDWrapper && elideWrapperCalling(u.calleeFuncID) {
// ignore wrappers
} else if skip > 0 {
skip--
// Show what created goroutine, except main goroutine (goid 1).
pc := gp.gopc
f := findfunc(pc)
- if f.valid() && showframe(f.srcFunc(), gp, false, funcID_normal) && gp.goid != 1 {
+ if f.valid() && showframe(f.srcFunc(), gp, false, abi.FuncIDNormal) && gp.goid != 1 {
printcreatedby1(f, pc, gp.parentGoid)
}
}
print("[originating from goroutine ", ancestor.goid, "]:\n")
for fidx, pc := range ancestor.pcs {
f := findfunc(pc) // f previously validated
- if showfuncinfo(f.srcFunc(), fidx == 0, funcID_normal) {
+ if showfuncinfo(f.srcFunc(), fidx == 0, abi.FuncIDNormal) {
printAncestorTracebackFuncInfo(f, pc)
}
}
}
// Show what created goroutine, except main goroutine (goid 1).
f := findfunc(ancestor.gopc)
- if f.valid() && showfuncinfo(f.srcFunc(), false, funcID_normal) && ancestor.goid != 1 {
+ if f.valid() && showfuncinfo(f.srcFunc(), false, abi.FuncIDNormal) && ancestor.goid != 1 {
// In ancestor mode, we'll already print the goroutine ancestor.
// Pass 0 for the goid parameter so we don't print it again.
printcreatedby1(f, ancestor.gopc, 0)
// showframe reports whether the frame with the given characteristics should
// be printed during a traceback.
-func showframe(sf srcFunc, gp *g, firstFrame bool, calleeID funcID) bool {
+func showframe(sf srcFunc, gp *g, firstFrame bool, calleeID abi.FuncID) bool {
mp := getg().m
if mp.throwing >= throwTypeRuntime && gp != nil && (gp == mp.curg || gp == mp.caughtsig.ptr()) {
return true
// showfuncinfo reports whether a function with the given characteristics should
// be printed during a traceback.
-func showfuncinfo(sf srcFunc, firstFrame bool, calleeID funcID) bool {
+func showfuncinfo(sf srcFunc, firstFrame bool, calleeID abi.FuncID) bool {
level, _, _ := gotraceback()
if level > 1 {
// Show all frames.
return true
}
- if sf.funcID == funcID_wrapper && elideWrapperCalling(calleeID) {
+ if sf.funcID == abi.FuncIDWrapper && elideWrapperCalling(calleeID) {
return false
}
// elideWrapperCalling reports whether a wrapper function that called
// function id should be elided from stack traces.
-func elideWrapperCalling(id funcID) bool {
+func elideWrapperCalling(id abi.FuncID) bool {
// If the wrapper called a panic function instead of the
// wrapped function, we want to include it in stacks.
- return !(id == funcID_gopanic || id == funcID_sigpanic || id == funcID_panicwrap)
+ return !(id == abi.FuncID_gopanic || id == abi.FuncID_sigpanic || id == abi.FuncID_panicwrap)
}
var gStatusStrings = [...]string{
if !f.valid() {
return false
}
- if f.funcID == funcID_runtime_main || f.funcID == funcID_handleAsyncEvent {
+ if f.funcID == abi.FuncID_runtime_main || f.funcID == abi.FuncID_handleAsyncEvent {
return false
}
- if f.funcID == funcID_runfinq {
+ if f.funcID == abi.FuncID_runfinq {
// We include the finalizer goroutine if it's calling
// back into user code.
if fixed {