Source file src/runtime/symtab.go

     1  // Copyright 2014 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 runtime
     6  
     7  import (
     8  	"internal/abi"
     9  	"internal/goarch"
    10  	"internal/runtime/atomic"
    11  	"runtime/internal/sys"
    12  	"unsafe"
    13  )
    14  
    15  // Frames may be used to get function/file/line information for a
    16  // slice of PC values returned by [Callers].
    17  type Frames struct {
    18  	// callers is a slice of PCs that have not yet been expanded to frames.
    19  	callers []uintptr
    20  
    21  	// nextPC is a next PC to expand ahead of processing callers.
    22  	nextPC uintptr
    23  
    24  	// frames is a slice of Frames that have yet to be returned.
    25  	frames     []Frame
    26  	frameStore [2]Frame
    27  }
    28  
    29  // Frame is the information returned by [Frames] for each call frame.
    30  type Frame struct {
    31  	// PC is the program counter for the location in this frame.
    32  	// For a frame that calls another frame, this will be the
    33  	// program counter of a call instruction. Because of inlining,
    34  	// multiple frames may have the same PC value, but different
    35  	// symbolic information.
    36  	PC uintptr
    37  
    38  	// Func is the Func value of this call frame. This may be nil
    39  	// for non-Go code or fully inlined functions.
    40  	Func *Func
    41  
    42  	// Function is the package path-qualified function name of
    43  	// this call frame. If non-empty, this string uniquely
    44  	// identifies a single function in the program.
    45  	// This may be the empty string if not known.
    46  	// If Func is not nil then Function == Func.Name().
    47  	Function string
    48  
    49  	// File and Line are the file name and line number of the
    50  	// location in this frame. For non-leaf frames, this will be
    51  	// the location of a call. These may be the empty string and
    52  	// zero, respectively, if not known.
    53  	File string
    54  	Line int
    55  
    56  	// startLine is the line number of the beginning of the function in
    57  	// this frame. Specifically, it is the line number of the func keyword
    58  	// for Go functions. Note that //line directives can change the
    59  	// filename and/or line number arbitrarily within a function, meaning
    60  	// that the Line - startLine offset is not always meaningful.
    61  	//
    62  	// This may be zero if not known.
    63  	startLine int
    64  
    65  	// Entry point program counter for the function; may be zero
    66  	// if not known. If Func is not nil then Entry ==
    67  	// Func.Entry().
    68  	Entry uintptr
    69  
    70  	// The runtime's internal view of the function. This field
    71  	// is set (funcInfo.valid() returns true) only for Go functions,
    72  	// not for C functions.
    73  	funcInfo funcInfo
    74  }
    75  
    76  // CallersFrames takes a slice of PC values returned by [Callers] and
    77  // prepares to return function/file/line information.
    78  // Do not change the slice until you are done with the [Frames].
    79  func CallersFrames(callers []uintptr) *Frames {
    80  	f := &Frames{callers: callers}
    81  	f.frames = f.frameStore[:0]
    82  	return f
    83  }
    84  
    85  // Next returns a [Frame] representing the next call frame in the slice
    86  // of PC values. If it has already returned all call frames, Next
    87  // returns a zero [Frame].
    88  //
    89  // The more result indicates whether the next call to Next will return
    90  // a valid [Frame]. It does not necessarily indicate whether this call
    91  // returned one.
    92  //
    93  // See the [Frames] example for idiomatic usage.
    94  func (ci *Frames) Next() (frame Frame, more bool) {
    95  	for len(ci.frames) < 2 {
    96  		// Find the next frame.
    97  		// We need to look for 2 frames so we know what
    98  		// to return for the "more" result.
    99  		if len(ci.callers) == 0 {
   100  			break
   101  		}
   102  		var pc uintptr
   103  		if ci.nextPC != 0 {
   104  			pc, ci.nextPC = ci.nextPC, 0
   105  		} else {
   106  			pc, ci.callers = ci.callers[0], ci.callers[1:]
   107  		}
   108  		funcInfo := findfunc(pc)
   109  		if !funcInfo.valid() {
   110  			if cgoSymbolizer != nil {
   111  				// Pre-expand cgo frames. We could do this
   112  				// incrementally, too, but there's no way to
   113  				// avoid allocation in this case anyway.
   114  				ci.frames = append(ci.frames, expandCgoFrames(pc)...)
   115  			}
   116  			continue
   117  		}
   118  		f := funcInfo._Func()
   119  		entry := f.Entry()
   120  		if pc > entry {
   121  			// We store the pc of the start of the instruction following
   122  			// the instruction in question (the call or the inline mark).
   123  			// This is done for historical reasons, and to make FuncForPC
   124  			// work correctly for entries in the result of runtime.Callers.
   125  			pc--
   126  		}
   127  		// It's important that interpret pc non-strictly as cgoTraceback may
   128  		// have added bogus PCs with a valid funcInfo but invalid PCDATA.
   129  		u, uf := newInlineUnwinder(funcInfo, pc)
   130  		sf := u.srcFunc(uf)
   131  		if u.isInlined(uf) {
   132  			// Note: entry is not modified. It always refers to a real frame, not an inlined one.
   133  			// File/line from funcline1 below are already correct.
   134  			f = nil
   135  
   136  			// When CallersFrame is invoked using the PC list returned by Callers,
   137  			// the PC list includes virtual PCs corresponding to each outer frame
   138  			// around an innermost real inlined PC.
   139  			// We also want to support code passing in a PC list extracted from a
   140  			// stack trace, and there only the real PCs are printed, not the virtual ones.
   141  			// So check to see if the implied virtual PC for this PC (obtained from the
   142  			// unwinder itself) is the next PC in ci.callers. If not, insert it.
   143  			// The +1 here correspond to the pc-- above: the output of Callers
   144  			// and therefore the input to CallersFrames is return PCs from the stack;
   145  			// The pc-- backs up into the CALL instruction (not the first byte of the CALL
   146  			// instruction, but good enough to find it nonetheless).
   147  			// There are no cycles in implied virtual PCs (some number of frames were
   148  			// inlined, but that number is finite), so this unpacking cannot cause an infinite loop.
   149  			for unext := u.next(uf); unext.valid() && len(ci.callers) > 0 && ci.callers[0] != unext.pc+1; unext = u.next(unext) {
   150  				snext := u.srcFunc(unext)
   151  				if snext.funcID == abi.FuncIDWrapper && elideWrapperCalling(sf.funcID) {
   152  					// Skip, because tracebackPCs (inside runtime.Callers) would too.
   153  					continue
   154  				}
   155  				ci.nextPC = unext.pc + 1
   156  				break
   157  			}
   158  		}
   159  		ci.frames = append(ci.frames, Frame{
   160  			PC:        pc,
   161  			Func:      f,
   162  			Function:  funcNameForPrint(sf.name()),
   163  			Entry:     entry,
   164  			startLine: int(sf.startLine),
   165  			funcInfo:  funcInfo,
   166  			// Note: File,Line set below
   167  		})
   168  	}
   169  
   170  	// Pop one frame from the frame list. Keep the rest.
   171  	// Avoid allocation in the common case, which is 1 or 2 frames.
   172  	switch len(ci.frames) {
   173  	case 0: // In the rare case when there are no frames at all, we return Frame{}.
   174  		return
   175  	case 1:
   176  		frame = ci.frames[0]
   177  		ci.frames = ci.frameStore[:0]
   178  	case 2:
   179  		frame = ci.frames[0]
   180  		ci.frameStore[0] = ci.frames[1]
   181  		ci.frames = ci.frameStore[:1]
   182  	default:
   183  		frame = ci.frames[0]
   184  		ci.frames = ci.frames[1:]
   185  	}
   186  	more = len(ci.frames) > 0
   187  	if frame.funcInfo.valid() {
   188  		// Compute file/line just before we need to return it,
   189  		// as it can be expensive. This avoids computing file/line
   190  		// for the Frame we find but don't return. See issue 32093.
   191  		file, line := funcline1(frame.funcInfo, frame.PC, false)
   192  		frame.File, frame.Line = file, int(line)
   193  	}
   194  	return
   195  }
   196  
   197  // runtime_FrameStartLine returns the start line of the function in a Frame.
   198  //
   199  // runtime_FrameStartLine should be an internal detail,
   200  // but widely used packages access it using linkname.
   201  // Notable members of the hall of shame include:
   202  //   - github.com/grafana/pyroscope-go/godeltaprof
   203  //
   204  // Do not remove or change the type signature.
   205  // See go.dev/issue/67401.
   206  //
   207  //go:linkname runtime_FrameStartLine runtime/pprof.runtime_FrameStartLine
   208  func runtime_FrameStartLine(f *Frame) int {
   209  	return f.startLine
   210  }
   211  
   212  // runtime_FrameSymbolName returns the full symbol name of the function in a Frame.
   213  // For generic functions this differs from f.Function in that this doesn't replace
   214  // the shape name to "...".
   215  //
   216  // runtime_FrameSymbolName should be an internal detail,
   217  // but widely used packages access it using linkname.
   218  // Notable members of the hall of shame include:
   219  //   - github.com/grafana/pyroscope-go/godeltaprof
   220  //
   221  // Do not remove or change the type signature.
   222  // See go.dev/issue/67401.
   223  //
   224  //go:linkname runtime_FrameSymbolName runtime/pprof.runtime_FrameSymbolName
   225  func runtime_FrameSymbolName(f *Frame) string {
   226  	if !f.funcInfo.valid() {
   227  		return f.Function
   228  	}
   229  	u, uf := newInlineUnwinder(f.funcInfo, f.PC)
   230  	sf := u.srcFunc(uf)
   231  	return sf.name()
   232  }
   233  
   234  // runtime_expandFinalInlineFrame expands the final pc in stk to include all
   235  // "callers" if pc is inline.
   236  //
   237  // runtime_expandFinalInlineFrame should be an internal detail,
   238  // but widely used packages access it using linkname.
   239  // Notable members of the hall of shame include:
   240  //   - github.com/grafana/pyroscope-go/godeltaprof
   241  //   - github.com/pyroscope-io/godeltaprof
   242  //
   243  // Do not remove or change the type signature.
   244  // See go.dev/issue/67401.
   245  //
   246  //go:linkname runtime_expandFinalInlineFrame runtime/pprof.runtime_expandFinalInlineFrame
   247  func runtime_expandFinalInlineFrame(stk []uintptr) []uintptr {
   248  	// TODO: It would be more efficient to report only physical PCs to pprof and
   249  	// just expand the whole stack.
   250  	if len(stk) == 0 {
   251  		return stk
   252  	}
   253  	pc := stk[len(stk)-1]
   254  	tracepc := pc - 1
   255  
   256  	f := findfunc(tracepc)
   257  	if !f.valid() {
   258  		// Not a Go function.
   259  		return stk
   260  	}
   261  
   262  	u, uf := newInlineUnwinder(f, tracepc)
   263  	if !u.isInlined(uf) {
   264  		// Nothing inline at tracepc.
   265  		return stk
   266  	}
   267  
   268  	// Treat the previous func as normal. We haven't actually checked, but
   269  	// since this pc was included in the stack, we know it shouldn't be
   270  	// elided.
   271  	calleeID := abi.FuncIDNormal
   272  
   273  	// Remove pc from stk; we'll re-add it below.
   274  	stk = stk[:len(stk)-1]
   275  
   276  	for ; uf.valid(); uf = u.next(uf) {
   277  		funcID := u.srcFunc(uf).funcID
   278  		if funcID == abi.FuncIDWrapper && elideWrapperCalling(calleeID) {
   279  			// ignore wrappers
   280  		} else {
   281  			stk = append(stk, uf.pc+1)
   282  		}
   283  		calleeID = funcID
   284  	}
   285  
   286  	return stk
   287  }
   288  
   289  // expandCgoFrames expands frame information for pc, known to be
   290  // a non-Go function, using the cgoSymbolizer hook. expandCgoFrames
   291  // returns nil if pc could not be expanded.
   292  func expandCgoFrames(pc uintptr) []Frame {
   293  	arg := cgoSymbolizerArg{pc: pc}
   294  	callCgoSymbolizer(&arg)
   295  
   296  	if arg.file == nil && arg.funcName == nil {
   297  		// No useful information from symbolizer.
   298  		return nil
   299  	}
   300  
   301  	var frames []Frame
   302  	for {
   303  		frames = append(frames, Frame{
   304  			PC:       pc,
   305  			Func:     nil,
   306  			Function: gostring(arg.funcName),
   307  			File:     gostring(arg.file),
   308  			Line:     int(arg.lineno),
   309  			Entry:    arg.entry,
   310  			// funcInfo is zero, which implies !funcInfo.valid().
   311  			// That ensures that we use the File/Line info given here.
   312  		})
   313  		if arg.more == 0 {
   314  			break
   315  		}
   316  		callCgoSymbolizer(&arg)
   317  	}
   318  
   319  	// No more frames for this PC. Tell the symbolizer we are done.
   320  	// We don't try to maintain a single cgoSymbolizerArg for the
   321  	// whole use of Frames, because there would be no good way to tell
   322  	// the symbolizer when we are done.
   323  	arg.pc = 0
   324  	callCgoSymbolizer(&arg)
   325  
   326  	return frames
   327  }
   328  
   329  // NOTE: Func does not expose the actual unexported fields, because we return *Func
   330  // values to users, and we want to keep them from being able to overwrite the data
   331  // with (say) *f = Func{}.
   332  // All code operating on a *Func must call raw() to get the *_func
   333  // or funcInfo() to get the funcInfo instead.
   334  
   335  // A Func represents a Go function in the running binary.
   336  type Func struct {
   337  	opaque struct{} // unexported field to disallow conversions
   338  }
   339  
   340  func (f *Func) raw() *_func {
   341  	return (*_func)(unsafe.Pointer(f))
   342  }
   343  
   344  func (f *Func) funcInfo() funcInfo {
   345  	return f.raw().funcInfo()
   346  }
   347  
   348  func (f *_func) funcInfo() funcInfo {
   349  	// Find the module containing fn. fn is located in the pclntable.
   350  	// The unsafe.Pointer to uintptr conversions and arithmetic
   351  	// are safe because we are working with module addresses.
   352  	ptr := uintptr(unsafe.Pointer(f))
   353  	var mod *moduledata
   354  	for datap := &firstmoduledata; datap != nil; datap = datap.next {
   355  		if len(datap.pclntable) == 0 {
   356  			continue
   357  		}
   358  		base := uintptr(unsafe.Pointer(&datap.pclntable[0]))
   359  		if base <= ptr && ptr < base+uintptr(len(datap.pclntable)) {
   360  			mod = datap
   361  			break
   362  		}
   363  	}
   364  	return funcInfo{f, mod}
   365  }
   366  
   367  // pcHeader holds data used by the pclntab lookups.
   368  type pcHeader struct {
   369  	magic          uint32  // 0xFFFFFFF1
   370  	pad1, pad2     uint8   // 0,0
   371  	minLC          uint8   // min instruction size
   372  	ptrSize        uint8   // size of a ptr in bytes
   373  	nfunc          int     // number of functions in the module
   374  	nfiles         uint    // number of entries in the file tab
   375  	textStart      uintptr // base for function entry PC offsets in this module, equal to moduledata.text
   376  	funcnameOffset uintptr // offset to the funcnametab variable from pcHeader
   377  	cuOffset       uintptr // offset to the cutab variable from pcHeader
   378  	filetabOffset  uintptr // offset to the filetab variable from pcHeader
   379  	pctabOffset    uintptr // offset to the pctab variable from pcHeader
   380  	pclnOffset     uintptr // offset to the pclntab variable from pcHeader
   381  }
   382  
   383  // moduledata records information about the layout of the executable
   384  // image. It is written by the linker. Any changes here must be
   385  // matched changes to the code in cmd/link/internal/ld/symtab.go:symtab.
   386  // moduledata is stored in statically allocated non-pointer memory;
   387  // none of the pointers here are visible to the garbage collector.
   388  type moduledata struct {
   389  	sys.NotInHeap // Only in static data
   390  
   391  	pcHeader     *pcHeader
   392  	funcnametab  []byte
   393  	cutab        []uint32
   394  	filetab      []byte
   395  	pctab        []byte
   396  	pclntable    []byte
   397  	ftab         []functab
   398  	findfunctab  uintptr
   399  	minpc, maxpc uintptr
   400  
   401  	text, etext           uintptr
   402  	noptrdata, enoptrdata uintptr
   403  	data, edata           uintptr
   404  	bss, ebss             uintptr
   405  	noptrbss, enoptrbss   uintptr
   406  	covctrs, ecovctrs     uintptr
   407  	end, gcdata, gcbss    uintptr
   408  	types, etypes         uintptr
   409  	rodata                uintptr
   410  	gofunc                uintptr // go.func.*
   411  
   412  	textsectmap []textsect
   413  	typelinks   []int32 // offsets from types
   414  	itablinks   []*itab
   415  
   416  	ptab []ptabEntry
   417  
   418  	pluginpath string
   419  	pkghashes  []modulehash
   420  
   421  	// This slice records the initializing tasks that need to be
   422  	// done to start up the program. It is built by the linker.
   423  	inittasks []*initTask
   424  
   425  	modulename   string
   426  	modulehashes []modulehash
   427  
   428  	hasmain uint8 // 1 if module contains the main function, 0 otherwise
   429  	bad     bool  // module failed to load and should be ignored
   430  
   431  	gcdatamask, gcbssmask bitvector
   432  
   433  	typemap map[typeOff]*_type // offset to *_rtype in previous module
   434  
   435  	next *moduledata
   436  }
   437  
   438  // A modulehash is used to compare the ABI of a new module or a
   439  // package in a new module with the loaded program.
   440  //
   441  // For each shared library a module links against, the linker creates an entry in the
   442  // moduledata.modulehashes slice containing the name of the module, the abi hash seen
   443  // at link time and a pointer to the runtime abi hash. These are checked in
   444  // moduledataverify1 below.
   445  //
   446  // For each loaded plugin, the pkghashes slice has a modulehash of the
   447  // newly loaded package that can be used to check the plugin's version of
   448  // a package against any previously loaded version of the package.
   449  // This is done in plugin.lastmoduleinit.
   450  type modulehash struct {
   451  	modulename   string
   452  	linktimehash string
   453  	runtimehash  *string
   454  }
   455  
   456  // pinnedTypemaps are the map[typeOff]*_type from the moduledata objects.
   457  //
   458  // These typemap objects are allocated at run time on the heap, but the
   459  // only direct reference to them is in the moduledata, created by the
   460  // linker and marked SNOPTRDATA so it is ignored by the GC.
   461  //
   462  // To make sure the map isn't collected, we keep a second reference here.
   463  var pinnedTypemaps []map[typeOff]*_type
   464  
   465  var firstmoduledata moduledata // linker symbol
   466  
   467  // lastmoduledatap should be an internal detail,
   468  // but widely used packages access it using linkname.
   469  // Notable members of the hall of shame include:
   470  //   - github.com/cloudwego/frugal
   471  //
   472  // Do not remove or change the type signature.
   473  // See go.dev/issue/67401.
   474  //
   475  //go:linkname lastmoduledatap
   476  var lastmoduledatap *moduledata // linker symbol
   477  
   478  var modulesSlice *[]*moduledata // see activeModules
   479  
   480  // activeModules returns a slice of active modules.
   481  //
   482  // A module is active once its gcdatamask and gcbssmask have been
   483  // assembled and it is usable by the GC.
   484  //
   485  // This is nosplit/nowritebarrier because it is called by the
   486  // cgo pointer checking code.
   487  //
   488  //go:nosplit
   489  //go:nowritebarrier
   490  func activeModules() []*moduledata {
   491  	p := (*[]*moduledata)(atomic.Loadp(unsafe.Pointer(&modulesSlice)))
   492  	if p == nil {
   493  		return nil
   494  	}
   495  	return *p
   496  }
   497  
   498  // modulesinit creates the active modules slice out of all loaded modules.
   499  //
   500  // When a module is first loaded by the dynamic linker, an .init_array
   501  // function (written by cmd/link) is invoked to call addmoduledata,
   502  // appending to the module to the linked list that starts with
   503  // firstmoduledata.
   504  //
   505  // There are two times this can happen in the lifecycle of a Go
   506  // program. First, if compiled with -linkshared, a number of modules
   507  // built with -buildmode=shared can be loaded at program initialization.
   508  // Second, a Go program can load a module while running that was built
   509  // with -buildmode=plugin.
   510  //
   511  // After loading, this function is called which initializes the
   512  // moduledata so it is usable by the GC and creates a new activeModules
   513  // list.
   514  //
   515  // Only one goroutine may call modulesinit at a time.
   516  func modulesinit() {
   517  	modules := new([]*moduledata)
   518  	for md := &firstmoduledata; md != nil; md = md.next {
   519  		if md.bad {
   520  			continue
   521  		}
   522  		*modules = append(*modules, md)
   523  		if md.gcdatamask == (bitvector{}) {
   524  			scanDataSize := md.edata - md.data
   525  			md.gcdatamask = progToPointerMask((*byte)(unsafe.Pointer(md.gcdata)), scanDataSize)
   526  			scanBSSSize := md.ebss - md.bss
   527  			md.gcbssmask = progToPointerMask((*byte)(unsafe.Pointer(md.gcbss)), scanBSSSize)
   528  			gcController.addGlobals(int64(scanDataSize + scanBSSSize))
   529  		}
   530  	}
   531  
   532  	// Modules appear in the moduledata linked list in the order they are
   533  	// loaded by the dynamic loader, with one exception: the
   534  	// firstmoduledata itself the module that contains the runtime. This
   535  	// is not always the first module (when using -buildmode=shared, it
   536  	// is typically libstd.so, the second module). The order matters for
   537  	// typelinksinit, so we swap the first module with whatever module
   538  	// contains the main function.
   539  	//
   540  	// See Issue #18729.
   541  	for i, md := range *modules {
   542  		if md.hasmain != 0 {
   543  			(*modules)[0] = md
   544  			(*modules)[i] = &firstmoduledata
   545  			break
   546  		}
   547  	}
   548  
   549  	atomicstorep(unsafe.Pointer(&modulesSlice), unsafe.Pointer(modules))
   550  }
   551  
   552  type functab struct {
   553  	entryoff uint32 // relative to runtime.text
   554  	funcoff  uint32
   555  }
   556  
   557  // Mapping information for secondary text sections
   558  
   559  type textsect struct {
   560  	vaddr    uintptr // prelinked section vaddr
   561  	end      uintptr // vaddr + section length
   562  	baseaddr uintptr // relocated section address
   563  }
   564  
   565  // findfuncbucket is an array of these structures.
   566  // Each bucket represents 4096 bytes of the text segment.
   567  // Each subbucket represents 256 bytes of the text segment.
   568  // To find a function given a pc, locate the bucket and subbucket for
   569  // that pc. Add together the idx and subbucket value to obtain a
   570  // function index. Then scan the functab array starting at that
   571  // index to find the target function.
   572  // This table uses 20 bytes for every 4096 bytes of code, or ~0.5% overhead.
   573  type findfuncbucket struct {
   574  	idx        uint32
   575  	subbuckets [16]byte
   576  }
   577  
   578  func moduledataverify() {
   579  	for datap := &firstmoduledata; datap != nil; datap = datap.next {
   580  		moduledataverify1(datap)
   581  	}
   582  }
   583  
   584  const debugPcln = false
   585  
   586  // moduledataverify1 should be an internal detail,
   587  // but widely used packages access it using linkname.
   588  // Notable members of the hall of shame include:
   589  //   - github.com/cloudwego/frugal
   590  //
   591  // Do not remove or change the type signature.
   592  // See go.dev/issue/67401.
   593  //
   594  //go:linkname moduledataverify1
   595  func moduledataverify1(datap *moduledata) {
   596  	// Check that the pclntab's format is valid.
   597  	hdr := datap.pcHeader
   598  	if hdr.magic != 0xfffffff1 || hdr.pad1 != 0 || hdr.pad2 != 0 ||
   599  		hdr.minLC != sys.PCQuantum || hdr.ptrSize != goarch.PtrSize || hdr.textStart != datap.text {
   600  		println("runtime: pcHeader: magic=", hex(hdr.magic), "pad1=", hdr.pad1, "pad2=", hdr.pad2,
   601  			"minLC=", hdr.minLC, "ptrSize=", hdr.ptrSize, "pcHeader.textStart=", hex(hdr.textStart),
   602  			"text=", hex(datap.text), "pluginpath=", datap.pluginpath)
   603  		throw("invalid function symbol table")
   604  	}
   605  
   606  	// ftab is lookup table for function by program counter.
   607  	nftab := len(datap.ftab) - 1
   608  	for i := 0; i < nftab; i++ {
   609  		// NOTE: ftab[nftab].entry is legal; it is the address beyond the final function.
   610  		if datap.ftab[i].entryoff > datap.ftab[i+1].entryoff {
   611  			f1 := funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff])), datap}
   612  			f2 := funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff])), datap}
   613  			f2name := "end"
   614  			if i+1 < nftab {
   615  				f2name = funcname(f2)
   616  			}
   617  			println("function symbol table not sorted by PC offset:", hex(datap.ftab[i].entryoff), funcname(f1), ">", hex(datap.ftab[i+1].entryoff), f2name, ", plugin:", datap.pluginpath)
   618  			for j := 0; j <= i; j++ {
   619  				println("\t", hex(datap.ftab[j].entryoff), funcname(funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[j].funcoff])), datap}))
   620  			}
   621  			if GOOS == "aix" && isarchive {
   622  				println("-Wl,-bnoobjreorder is mandatory on aix/ppc64 with c-archive")
   623  			}
   624  			throw("invalid runtime symbol table")
   625  		}
   626  	}
   627  
   628  	min := datap.textAddr(datap.ftab[0].entryoff)
   629  	max := datap.textAddr(datap.ftab[nftab].entryoff)
   630  	if datap.minpc != min || datap.maxpc != max {
   631  		println("minpc=", hex(datap.minpc), "min=", hex(min), "maxpc=", hex(datap.maxpc), "max=", hex(max))
   632  		throw("minpc or maxpc invalid")
   633  	}
   634  
   635  	for _, modulehash := range datap.modulehashes {
   636  		if modulehash.linktimehash != *modulehash.runtimehash {
   637  			println("abi mismatch detected between", datap.modulename, "and", modulehash.modulename)
   638  			throw("abi mismatch")
   639  		}
   640  	}
   641  }
   642  
   643  // textAddr returns md.text + off, with special handling for multiple text sections.
   644  // off is a (virtual) offset computed at internal linking time,
   645  // before the external linker adjusts the sections' base addresses.
   646  //
   647  // The text, or instruction stream is generated as one large buffer.
   648  // The off (offset) for a function is its offset within this buffer.
   649  // If the total text size gets too large, there can be issues on platforms like ppc64
   650  // if the target of calls are too far for the call instruction.
   651  // To resolve the large text issue, the text is split into multiple text sections
   652  // to allow the linker to generate long calls when necessary.
   653  // When this happens, the vaddr for each text section is set to its offset within the text.
   654  // Each function's offset is compared against the section vaddrs and ends to determine the containing section.
   655  // Then the section relative offset is added to the section's
   656  // relocated baseaddr to compute the function address.
   657  //
   658  // It is nosplit because it is part of the findfunc implementation.
   659  //
   660  //go:nosplit
   661  func (md *moduledata) textAddr(off32 uint32) uintptr {
   662  	off := uintptr(off32)
   663  	res := md.text + off
   664  	if len(md.textsectmap) > 1 {
   665  		for i, sect := range md.textsectmap {
   666  			// For the last section, include the end address (etext), as it is included in the functab.
   667  			if off >= sect.vaddr && off < sect.end || (i == len(md.textsectmap)-1 && off == sect.end) {
   668  				res = sect.baseaddr + off - sect.vaddr
   669  				break
   670  			}
   671  		}
   672  		if res > md.etext && GOARCH != "wasm" { // on wasm, functions do not live in the same address space as the linear memory
   673  			println("runtime: textAddr", hex(res), "out of range", hex(md.text), "-", hex(md.etext))
   674  			throw("runtime: text offset out of range")
   675  		}
   676  	}
   677  	return res
   678  }
   679  
   680  // textOff is the opposite of textAddr. It converts a PC to a (virtual) offset
   681  // to md.text, and returns if the PC is in any Go text section.
   682  //
   683  // It is nosplit because it is part of the findfunc implementation.
   684  //
   685  //go:nosplit
   686  func (md *moduledata) textOff(pc uintptr) (uint32, bool) {
   687  	res := uint32(pc - md.text)
   688  	if len(md.textsectmap) > 1 {
   689  		for i, sect := range md.textsectmap {
   690  			if sect.baseaddr > pc {
   691  				// pc is not in any section.
   692  				return 0, false
   693  			}
   694  			end := sect.baseaddr + (sect.end - sect.vaddr)
   695  			// For the last section, include the end address (etext), as it is included in the functab.
   696  			if i == len(md.textsectmap)-1 {
   697  				end++
   698  			}
   699  			if pc < end {
   700  				res = uint32(pc - sect.baseaddr + sect.vaddr)
   701  				break
   702  			}
   703  		}
   704  	}
   705  	return res, true
   706  }
   707  
   708  // funcName returns the string at nameOff in the function name table.
   709  func (md *moduledata) funcName(nameOff int32) string {
   710  	if nameOff == 0 {
   711  		return ""
   712  	}
   713  	return gostringnocopy(&md.funcnametab[nameOff])
   714  }
   715  
   716  // FuncForPC returns a *[Func] describing the function that contains the
   717  // given program counter address, or else nil.
   718  //
   719  // If pc represents multiple functions because of inlining, it returns
   720  // the *Func describing the innermost function, but with an entry of
   721  // the outermost function.
   722  //
   723  // For completely unclear reasons, even though they can import runtime,
   724  // some widely used packages access this using linkname.
   725  // Notable members of the hall of shame include:
   726  //   - gitee.com/quant1x/gox
   727  //
   728  // Do not remove or change the type signature.
   729  // See go.dev/issue/67401.
   730  //
   731  //go:linkname FuncForPC
   732  func FuncForPC(pc uintptr) *Func {
   733  	f := findfunc(pc)
   734  	if !f.valid() {
   735  		return nil
   736  	}
   737  	// This must interpret PC non-strictly so bad PCs (those between functions) don't crash the runtime.
   738  	// We just report the preceding function in that situation. See issue 29735.
   739  	// TODO: Perhaps we should report no function at all in that case.
   740  	// The runtime currently doesn't have function end info, alas.
   741  	u, uf := newInlineUnwinder(f, pc)
   742  	if !u.isInlined(uf) {
   743  		return f._Func()
   744  	}
   745  	sf := u.srcFunc(uf)
   746  	file, line := u.fileLine(uf)
   747  	fi := &funcinl{
   748  		ones:      ^uint32(0),
   749  		entry:     f.entry(), // entry of the real (the outermost) function.
   750  		name:      sf.name(),
   751  		file:      file,
   752  		line:      int32(line),
   753  		startLine: sf.startLine,
   754  	}
   755  	return (*Func)(unsafe.Pointer(fi))
   756  }
   757  
   758  // Name returns the name of the function.
   759  func (f *Func) Name() string {
   760  	if f == nil {
   761  		return ""
   762  	}
   763  	fn := f.raw()
   764  	if fn.isInlined() { // inlined version
   765  		fi := (*funcinl)(unsafe.Pointer(fn))
   766  		return funcNameForPrint(fi.name)
   767  	}
   768  	return funcNameForPrint(funcname(f.funcInfo()))
   769  }
   770  
   771  // Entry returns the entry address of the function.
   772  func (f *Func) Entry() uintptr {
   773  	fn := f.raw()
   774  	if fn.isInlined() { // inlined version
   775  		fi := (*funcinl)(unsafe.Pointer(fn))
   776  		return fi.entry
   777  	}
   778  	return fn.funcInfo().entry()
   779  }
   780  
   781  // FileLine returns the file name and line number of the
   782  // source code corresponding to the program counter pc.
   783  // The result will not be accurate if pc is not a program
   784  // counter within f.
   785  func (f *Func) FileLine(pc uintptr) (file string, line int) {
   786  	fn := f.raw()
   787  	if fn.isInlined() { // inlined version
   788  		fi := (*funcinl)(unsafe.Pointer(fn))
   789  		return fi.file, int(fi.line)
   790  	}
   791  	// Pass strict=false here, because anyone can call this function,
   792  	// and they might just be wrong about targetpc belonging to f.
   793  	file, line32 := funcline1(f.funcInfo(), pc, false)
   794  	return file, int(line32)
   795  }
   796  
   797  // startLine returns the starting line number of the function. i.e., the line
   798  // number of the func keyword.
   799  func (f *Func) startLine() int32 {
   800  	fn := f.raw()
   801  	if fn.isInlined() { // inlined version
   802  		fi := (*funcinl)(unsafe.Pointer(fn))
   803  		return fi.startLine
   804  	}
   805  	return fn.funcInfo().startLine
   806  }
   807  
   808  // findmoduledatap looks up the moduledata for a PC.
   809  //
   810  // It is nosplit because it's part of the isgoexception
   811  // implementation.
   812  //
   813  //go:nosplit
   814  func findmoduledatap(pc uintptr) *moduledata {
   815  	for datap := &firstmoduledata; datap != nil; datap = datap.next {
   816  		if datap.minpc <= pc && pc < datap.maxpc {
   817  			return datap
   818  		}
   819  	}
   820  	return nil
   821  }
   822  
   823  type funcInfo struct {
   824  	*_func
   825  	datap *moduledata
   826  }
   827  
   828  func (f funcInfo) valid() bool {
   829  	return f._func != nil
   830  }
   831  
   832  func (f funcInfo) _Func() *Func {
   833  	return (*Func)(unsafe.Pointer(f._func))
   834  }
   835  
   836  // isInlined reports whether f should be re-interpreted as a *funcinl.
   837  func (f *_func) isInlined() bool {
   838  	return f.entryOff == ^uint32(0) // see comment for funcinl.ones
   839  }
   840  
   841  // entry returns the entry PC for f.
   842  //
   843  // entry should be an internal detail,
   844  // but widely used packages access it using linkname.
   845  // Notable members of the hall of shame include:
   846  //   - github.com/phuslu/log
   847  //
   848  // Do not remove or change the type signature.
   849  // See go.dev/issue/67401.
   850  func (f funcInfo) entry() uintptr {
   851  	return f.datap.textAddr(f.entryOff)
   852  }
   853  
   854  //go:linkname badFuncInfoEntry runtime.funcInfo.entry
   855  func badFuncInfoEntry(funcInfo) uintptr
   856  
   857  // findfunc looks up function metadata for a PC.
   858  //
   859  // It is nosplit because it's part of the isgoexception
   860  // implementation.
   861  //
   862  // findfunc should be an internal detail,
   863  // but widely used packages access it using linkname.
   864  // Notable members of the hall of shame include:
   865  //   - github.com/cloudwego/frugal
   866  //   - github.com/phuslu/log
   867  //
   868  // Do not remove or change the type signature.
   869  // See go.dev/issue/67401.
   870  //
   871  //go:nosplit
   872  //go:linkname findfunc
   873  func findfunc(pc uintptr) funcInfo {
   874  	datap := findmoduledatap(pc)
   875  	if datap == nil {
   876  		return funcInfo{}
   877  	}
   878  	const nsub = uintptr(len(findfuncbucket{}.subbuckets))
   879  
   880  	pcOff, ok := datap.textOff(pc)
   881  	if !ok {
   882  		return funcInfo{}
   883  	}
   884  
   885  	x := uintptr(pcOff) + datap.text - datap.minpc // TODO: are datap.text and datap.minpc always equal?
   886  	b := x / abi.FuncTabBucketSize
   887  	i := x % abi.FuncTabBucketSize / (abi.FuncTabBucketSize / nsub)
   888  
   889  	ffb := (*findfuncbucket)(add(unsafe.Pointer(datap.findfunctab), b*unsafe.Sizeof(findfuncbucket{})))
   890  	idx := ffb.idx + uint32(ffb.subbuckets[i])
   891  
   892  	// Find the ftab entry.
   893  	for datap.ftab[idx+1].entryoff <= pcOff {
   894  		idx++
   895  	}
   896  
   897  	funcoff := datap.ftab[idx].funcoff
   898  	return funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[funcoff])), datap}
   899  }
   900  
   901  // A srcFunc represents a logical function in the source code. This may
   902  // correspond to an actual symbol in the binary text, or it may correspond to a
   903  // source function that has been inlined.
   904  type srcFunc struct {
   905  	datap     *moduledata
   906  	nameOff   int32
   907  	startLine int32
   908  	funcID    abi.FuncID
   909  }
   910  
   911  func (f funcInfo) srcFunc() srcFunc {
   912  	if !f.valid() {
   913  		return srcFunc{}
   914  	}
   915  	return srcFunc{f.datap, f.nameOff, f.startLine, f.funcID}
   916  }
   917  
   918  // name should be an internal detail,
   919  // but widely used packages access it using linkname.
   920  // Notable members of the hall of shame include:
   921  //   - github.com/phuslu/log
   922  //
   923  // Do not remove or change the type signature.
   924  // See go.dev/issue/67401.
   925  func (s srcFunc) name() string {
   926  	if s.datap == nil {
   927  		return ""
   928  	}
   929  	return s.datap.funcName(s.nameOff)
   930  }
   931  
   932  //go:linkname badSrcFuncName runtime.srcFunc.name
   933  func badSrcFuncName(srcFunc) string
   934  
   935  type pcvalueCache struct {
   936  	entries [2][8]pcvalueCacheEnt
   937  	inUse   int
   938  }
   939  
   940  type pcvalueCacheEnt struct {
   941  	// targetpc and off together are the key of this cache entry.
   942  	targetpc uintptr
   943  	off      uint32
   944  
   945  	val   int32   // The value of this entry.
   946  	valPC uintptr // The PC at which val starts
   947  }
   948  
   949  // pcvalueCacheKey returns the outermost index in a pcvalueCache to use for targetpc.
   950  // It must be very cheap to calculate.
   951  // For now, align to goarch.PtrSize and reduce mod the number of entries.
   952  // In practice, this appears to be fairly randomly and evenly distributed.
   953  func pcvalueCacheKey(targetpc uintptr) uintptr {
   954  	return (targetpc / goarch.PtrSize) % uintptr(len(pcvalueCache{}.entries))
   955  }
   956  
   957  // Returns the PCData value, and the PC where this value starts.
   958  func pcvalue(f funcInfo, off uint32, targetpc uintptr, strict bool) (int32, uintptr) {
   959  	// If true, when we get a cache hit, still look up the data and make sure it
   960  	// matches the cached contents.
   961  	const debugCheckCache = false
   962  
   963  	if off == 0 {
   964  		return -1, 0
   965  	}
   966  
   967  	// Check the cache. This speeds up walks of deep stacks, which
   968  	// tend to have the same recursive functions over and over,
   969  	// or repetitive stacks between goroutines.
   970  	var checkVal int32
   971  	var checkPC uintptr
   972  	ck := pcvalueCacheKey(targetpc)
   973  	{
   974  		mp := acquirem()
   975  		cache := &mp.pcvalueCache
   976  		// The cache can be used by the signal handler on this M. Avoid
   977  		// re-entrant use of the cache. The signal handler can also write inUse,
   978  		// but will always restore its value, so we can use a regular increment
   979  		// even if we get signaled in the middle of it.
   980  		cache.inUse++
   981  		if cache.inUse == 1 {
   982  			for i := range cache.entries[ck] {
   983  				// We check off first because we're more
   984  				// likely to have multiple entries with
   985  				// different offsets for the same targetpc
   986  				// than the other way around, so we'll usually
   987  				// fail in the first clause.
   988  				ent := &cache.entries[ck][i]
   989  				if ent.off == off && ent.targetpc == targetpc {
   990  					val, pc := ent.val, ent.valPC
   991  					if debugCheckCache {
   992  						checkVal, checkPC = ent.val, ent.valPC
   993  						break
   994  					} else {
   995  						cache.inUse--
   996  						releasem(mp)
   997  						return val, pc
   998  					}
   999  				}
  1000  			}
  1001  		} else if debugCheckCache && (cache.inUse < 1 || cache.inUse > 2) {
  1002  			// Catch accounting errors or deeply reentrant use. In principle
  1003  			// "inUse" should never exceed 2.
  1004  			throw("cache.inUse out of range")
  1005  		}
  1006  		cache.inUse--
  1007  		releasem(mp)
  1008  	}
  1009  
  1010  	if !f.valid() {
  1011  		if strict && panicking.Load() == 0 {
  1012  			println("runtime: no module data for", hex(f.entry()))
  1013  			throw("no module data")
  1014  		}
  1015  		return -1, 0
  1016  	}
  1017  	datap := f.datap
  1018  	p := datap.pctab[off:]
  1019  	pc := f.entry()
  1020  	prevpc := pc
  1021  	val := int32(-1)
  1022  	for {
  1023  		var ok bool
  1024  		p, ok = step(p, &pc, &val, pc == f.entry())
  1025  		if !ok {
  1026  			break
  1027  		}
  1028  		if targetpc < pc {
  1029  			// Replace a random entry in the cache. Random
  1030  			// replacement prevents a performance cliff if
  1031  			// a recursive stack's cycle is slightly
  1032  			// larger than the cache.
  1033  			// Put the new element at the beginning,
  1034  			// since it is the most likely to be newly used.
  1035  			if debugCheckCache && checkPC != 0 {
  1036  				if checkVal != val || checkPC != prevpc {
  1037  					print("runtime: table value ", val, "@", prevpc, " != cache value ", checkVal, "@", checkPC, " at PC ", targetpc, " off ", off, "\n")
  1038  					throw("bad pcvalue cache")
  1039  				}
  1040  			} else {
  1041  				mp := acquirem()
  1042  				cache := &mp.pcvalueCache
  1043  				cache.inUse++
  1044  				if cache.inUse == 1 {
  1045  					e := &cache.entries[ck]
  1046  					ci := cheaprandn(uint32(len(cache.entries[ck])))
  1047  					e[ci] = e[0]
  1048  					e[0] = pcvalueCacheEnt{
  1049  						targetpc: targetpc,
  1050  						off:      off,
  1051  						val:      val,
  1052  						valPC:    prevpc,
  1053  					}
  1054  				}
  1055  				cache.inUse--
  1056  				releasem(mp)
  1057  			}
  1058  
  1059  			return val, prevpc
  1060  		}
  1061  		prevpc = pc
  1062  	}
  1063  
  1064  	// If there was a table, it should have covered all program counters.
  1065  	// If not, something is wrong.
  1066  	if panicking.Load() != 0 || !strict {
  1067  		return -1, 0
  1068  	}
  1069  
  1070  	print("runtime: invalid pc-encoded table f=", funcname(f), " pc=", hex(pc), " targetpc=", hex(targetpc), " tab=", p, "\n")
  1071  
  1072  	p = datap.pctab[off:]
  1073  	pc = f.entry()
  1074  	val = -1
  1075  	for {
  1076  		var ok bool
  1077  		p, ok = step(p, &pc, &val, pc == f.entry())
  1078  		if !ok {
  1079  			break
  1080  		}
  1081  		print("\tvalue=", val, " until pc=", hex(pc), "\n")
  1082  	}
  1083  
  1084  	throw("invalid runtime symbol table")
  1085  	return -1, 0
  1086  }
  1087  
  1088  func funcname(f funcInfo) string {
  1089  	if !f.valid() {
  1090  		return ""
  1091  	}
  1092  	return f.datap.funcName(f.nameOff)
  1093  }
  1094  
  1095  func funcpkgpath(f funcInfo) string {
  1096  	name := funcNameForPrint(funcname(f))
  1097  	i := len(name) - 1
  1098  	for ; i > 0; i-- {
  1099  		if name[i] == '/' {
  1100  			break
  1101  		}
  1102  	}
  1103  	for ; i < len(name); i++ {
  1104  		if name[i] == '.' {
  1105  			break
  1106  		}
  1107  	}
  1108  	return name[:i]
  1109  }
  1110  
  1111  func funcfile(f funcInfo, fileno int32) string {
  1112  	datap := f.datap
  1113  	if !f.valid() {
  1114  		return "?"
  1115  	}
  1116  	// Make sure the cu index and file offset are valid
  1117  	if fileoff := datap.cutab[f.cuOffset+uint32(fileno)]; fileoff != ^uint32(0) {
  1118  		return gostringnocopy(&datap.filetab[fileoff])
  1119  	}
  1120  	// pcln section is corrupt.
  1121  	return "?"
  1122  }
  1123  
  1124  // funcline1 should be an internal detail,
  1125  // but widely used packages access it using linkname.
  1126  // Notable members of the hall of shame include:
  1127  //   - github.com/phuslu/log
  1128  //
  1129  // Do not remove or change the type signature.
  1130  // See go.dev/issue/67401.
  1131  //
  1132  //go:linkname funcline1
  1133  func funcline1(f funcInfo, targetpc uintptr, strict bool) (file string, line int32) {
  1134  	datap := f.datap
  1135  	if !f.valid() {
  1136  		return "?", 0
  1137  	}
  1138  	fileno, _ := pcvalue(f, f.pcfile, targetpc, strict)
  1139  	line, _ = pcvalue(f, f.pcln, targetpc, strict)
  1140  	if fileno == -1 || line == -1 || int(fileno) >= len(datap.filetab) {
  1141  		// print("looking for ", hex(targetpc), " in ", funcname(f), " got file=", fileno, " line=", lineno, "\n")
  1142  		return "?", 0
  1143  	}
  1144  	file = funcfile(f, fileno)
  1145  	return
  1146  }
  1147  
  1148  func funcline(f funcInfo, targetpc uintptr) (file string, line int32) {
  1149  	return funcline1(f, targetpc, true)
  1150  }
  1151  
  1152  func funcspdelta(f funcInfo, targetpc uintptr) int32 {
  1153  	x, _ := pcvalue(f, f.pcsp, targetpc, true)
  1154  	if debugPcln && x&(goarch.PtrSize-1) != 0 {
  1155  		print("invalid spdelta ", funcname(f), " ", hex(f.entry()), " ", hex(targetpc), " ", hex(f.pcsp), " ", x, "\n")
  1156  		throw("bad spdelta")
  1157  	}
  1158  	return x
  1159  }
  1160  
  1161  // funcMaxSPDelta returns the maximum spdelta at any point in f.
  1162  func funcMaxSPDelta(f funcInfo) int32 {
  1163  	datap := f.datap
  1164  	p := datap.pctab[f.pcsp:]
  1165  	pc := f.entry()
  1166  	val := int32(-1)
  1167  	most := int32(0)
  1168  	for {
  1169  		var ok bool
  1170  		p, ok = step(p, &pc, &val, pc == f.entry())
  1171  		if !ok {
  1172  			return most
  1173  		}
  1174  		most = max(most, val)
  1175  	}
  1176  }
  1177  
  1178  func pcdatastart(f funcInfo, table uint32) uint32 {
  1179  	return *(*uint32)(add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(table)*4))
  1180  }
  1181  
  1182  func pcdatavalue(f funcInfo, table uint32, targetpc uintptr) int32 {
  1183  	if table >= f.npcdata {
  1184  		return -1
  1185  	}
  1186  	r, _ := pcvalue(f, pcdatastart(f, table), targetpc, true)
  1187  	return r
  1188  }
  1189  
  1190  func pcdatavalue1(f funcInfo, table uint32, targetpc uintptr, strict bool) int32 {
  1191  	if table >= f.npcdata {
  1192  		return -1
  1193  	}
  1194  	r, _ := pcvalue(f, pcdatastart(f, table), targetpc, strict)
  1195  	return r
  1196  }
  1197  
  1198  // Like pcdatavalue, but also return the start PC of this PCData value.
  1199  //
  1200  // pcdatavalue2 should be an internal detail,
  1201  // but widely used packages access it using linkname.
  1202  // Notable members of the hall of shame include:
  1203  //   - github.com/cloudwego/frugal
  1204  //
  1205  // Do not remove or change the type signature.
  1206  // See go.dev/issue/67401.
  1207  //
  1208  //go:linkname pcdatavalue2
  1209  func pcdatavalue2(f funcInfo, table uint32, targetpc uintptr) (int32, uintptr) {
  1210  	if table >= f.npcdata {
  1211  		return -1, 0
  1212  	}
  1213  	return pcvalue(f, pcdatastart(f, table), targetpc, true)
  1214  }
  1215  
  1216  // funcdata returns a pointer to the ith funcdata for f.
  1217  // funcdata should be kept in sync with cmd/link:writeFuncs.
  1218  func funcdata(f funcInfo, i uint8) unsafe.Pointer {
  1219  	if i < 0 || i >= f.nfuncdata {
  1220  		return nil
  1221  	}
  1222  	base := f.datap.gofunc // load gofunc address early so that we calculate during cache misses
  1223  	p := uintptr(unsafe.Pointer(&f.nfuncdata)) + unsafe.Sizeof(f.nfuncdata) + uintptr(f.npcdata)*4 + uintptr(i)*4
  1224  	off := *(*uint32)(unsafe.Pointer(p))
  1225  	// Return off == ^uint32(0) ? 0 : f.datap.gofunc + uintptr(off), but without branches.
  1226  	// The compiler calculates mask on most architectures using conditional assignment.
  1227  	var mask uintptr
  1228  	if off == ^uint32(0) {
  1229  		mask = 1
  1230  	}
  1231  	mask--
  1232  	raw := base + uintptr(off)
  1233  	return unsafe.Pointer(raw & mask)
  1234  }
  1235  
  1236  // step advances to the next pc, value pair in the encoded table.
  1237  //
  1238  // step should be an internal detail,
  1239  // but widely used packages access it using linkname.
  1240  // Notable members of the hall of shame include:
  1241  //   - github.com/cloudwego/frugal
  1242  //
  1243  // Do not remove or change the type signature.
  1244  // See go.dev/issue/67401.
  1245  //
  1246  //go:linkname step
  1247  func step(p []byte, pc *uintptr, val *int32, first bool) (newp []byte, ok bool) {
  1248  	// For both uvdelta and pcdelta, the common case (~70%)
  1249  	// is that they are a single byte. If so, avoid calling readvarint.
  1250  	uvdelta := uint32(p[0])
  1251  	if uvdelta == 0 && !first {
  1252  		return nil, false
  1253  	}
  1254  	n := uint32(1)
  1255  	if uvdelta&0x80 != 0 {
  1256  		n, uvdelta = readvarint(p)
  1257  	}
  1258  	*val += int32(-(uvdelta & 1) ^ (uvdelta >> 1))
  1259  	p = p[n:]
  1260  
  1261  	pcdelta := uint32(p[0])
  1262  	n = 1
  1263  	if pcdelta&0x80 != 0 {
  1264  		n, pcdelta = readvarint(p)
  1265  	}
  1266  	p = p[n:]
  1267  	*pc += uintptr(pcdelta * sys.PCQuantum)
  1268  	return p, true
  1269  }
  1270  
  1271  // readvarint reads a varint from p.
  1272  func readvarint(p []byte) (read uint32, val uint32) {
  1273  	var v, shift, n uint32
  1274  	for {
  1275  		b := p[n]
  1276  		n++
  1277  		v |= uint32(b&0x7F) << (shift & 31)
  1278  		if b&0x80 == 0 {
  1279  			break
  1280  		}
  1281  		shift += 7
  1282  	}
  1283  	return n, v
  1284  }
  1285  
  1286  type stackmap struct {
  1287  	n        int32   // number of bitmaps
  1288  	nbit     int32   // number of bits in each bitmap
  1289  	bytedata [1]byte // bitmaps, each starting on a byte boundary
  1290  }
  1291  
  1292  // stackmapdata should be an internal detail,
  1293  // but widely used packages access it using linkname.
  1294  // Notable members of the hall of shame include:
  1295  //   - github.com/cloudwego/frugal
  1296  //
  1297  // Do not remove or change the type signature.
  1298  // See go.dev/issue/67401.
  1299  //
  1300  //go:linkname stackmapdata
  1301  //go:nowritebarrier
  1302  func stackmapdata(stkmap *stackmap, n int32) bitvector {
  1303  	// Check this invariant only when stackDebug is on at all.
  1304  	// The invariant is already checked by many of stackmapdata's callers,
  1305  	// and disabling it by default allows stackmapdata to be inlined.
  1306  	if stackDebug > 0 && (n < 0 || n >= stkmap.n) {
  1307  		throw("stackmapdata: index out of range")
  1308  	}
  1309  	return bitvector{stkmap.nbit, addb(&stkmap.bytedata[0], uintptr(n*((stkmap.nbit+7)>>3)))}
  1310  }
  1311  

View as plain text