...
Run Format

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		"runtime/internal/atomic"
     9		"runtime/internal/sys"
    10		"unsafe"
    11	)
    12	
    13	// Frames may be used to get function/file/line information for a
    14	// slice of PC values returned by Callers.
    15	type Frames struct {
    16		callers []uintptr
    17	
    18		// If previous caller in iteration was a panic, then
    19		// ci.callers[0] is the address of the faulting instruction
    20		// instead of the return address of the call.
    21		wasPanic bool
    22	
    23		// Frames to return for subsequent calls to the Next method.
    24		// Used for non-Go frames.
    25		frames *[]Frame
    26	}
    27	
    28	// Frame is the information returned by Frames for each call frame.
    29	type Frame struct {
    30		// Program counter for this frame; multiple frames may have
    31		// the same PC value.
    32		PC uintptr
    33	
    34		// Func for this frame; may be nil for non-Go code or fully
    35		// inlined functions.
    36		Func *Func
    37	
    38		// Function name, file name, and line number for this call frame.
    39		// May be the empty string or zero if not known.
    40		// If Func is not nil then Function == Func.Name().
    41		Function string
    42		File     string
    43		Line     int
    44	
    45		// Entry point for the function; may be zero if not known.
    46		// If Func is not nil then Entry == Func.Entry().
    47		Entry uintptr
    48	}
    49	
    50	// CallersFrames takes a slice of PC values returned by Callers and
    51	// prepares to return function/file/line information.
    52	// Do not change the slice until you are done with the Frames.
    53	func CallersFrames(callers []uintptr) *Frames {
    54		return &Frames{callers: callers}
    55	}
    56	
    57	// Next returns frame information for the next caller.
    58	// If more is false, there are no more callers (the Frame value is valid).
    59	func (ci *Frames) Next() (frame Frame, more bool) {
    60		if ci.frames != nil {
    61			// We have saved up frames to return.
    62			f := (*ci.frames)[0]
    63			if len(*ci.frames) == 1 {
    64				ci.frames = nil
    65			} else {
    66				*ci.frames = (*ci.frames)[1:]
    67			}
    68			return f, ci.frames != nil || len(ci.callers) > 0
    69		}
    70	
    71		if len(ci.callers) == 0 {
    72			ci.wasPanic = false
    73			return Frame{}, false
    74		}
    75		pc := ci.callers[0]
    76		ci.callers = ci.callers[1:]
    77		more = len(ci.callers) > 0
    78		f := FuncForPC(pc)
    79		if f == nil {
    80			ci.wasPanic = false
    81			if cgoSymbolizer != nil {
    82				return ci.cgoNext(pc, more)
    83			}
    84			return Frame{}, more
    85		}
    86	
    87		entry := f.Entry()
    88		xpc := pc
    89		if xpc > entry && !ci.wasPanic {
    90			xpc--
    91		}
    92		file, line := f.FileLine(xpc)
    93	
    94		function := f.Name()
    95		ci.wasPanic = entry == sigpanicPC
    96	
    97		frame = Frame{
    98			PC:       xpc,
    99			Func:     f,
   100			Function: function,
   101			File:     file,
   102			Line:     line,
   103			Entry:    entry,
   104		}
   105	
   106		return frame, more
   107	}
   108	
   109	// cgoNext returns frame information for pc, known to be a non-Go function,
   110	// using the cgoSymbolizer hook.
   111	func (ci *Frames) cgoNext(pc uintptr, more bool) (Frame, bool) {
   112		arg := cgoSymbolizerArg{pc: pc}
   113		callCgoSymbolizer(&arg)
   114	
   115		if arg.file == nil && arg.funcName == nil {
   116			// No useful information from symbolizer.
   117			return Frame{}, more
   118		}
   119	
   120		var frames []Frame
   121		for {
   122			frames = append(frames, Frame{
   123				PC:       pc,
   124				Func:     nil,
   125				Function: gostring(arg.funcName),
   126				File:     gostring(arg.file),
   127				Line:     int(arg.lineno),
   128				Entry:    arg.entry,
   129			})
   130			if arg.more == 0 {
   131				break
   132			}
   133			callCgoSymbolizer(&arg)
   134		}
   135	
   136		// No more frames for this PC. Tell the symbolizer we are done.
   137		// We don't try to maintain a single cgoSymbolizerArg for the
   138		// whole use of Frames, because there would be no good way to tell
   139		// the symbolizer when we are done.
   140		arg.pc = 0
   141		callCgoSymbolizer(&arg)
   142	
   143		if len(frames) == 1 {
   144			// Return a single frame.
   145			return frames[0], more
   146		}
   147	
   148		// Return the first frame we saw and store the rest to be
   149		// returned by later calls to Next.
   150		rf := frames[0]
   151		frames = frames[1:]
   152		ci.frames = new([]Frame)
   153		*ci.frames = frames
   154		return rf, true
   155	}
   156	
   157	// NOTE: Func does not expose the actual unexported fields, because we return *Func
   158	// values to users, and we want to keep them from being able to overwrite the data
   159	// with (say) *f = Func{}.
   160	// All code operating on a *Func must call raw to get the *_func instead.
   161	
   162	// A Func represents a Go function in the running binary.
   163	type Func struct {
   164		opaque struct{} // unexported field to disallow conversions
   165	}
   166	
   167	func (f *Func) raw() *_func {
   168		return (*_func)(unsafe.Pointer(f))
   169	}
   170	
   171	// funcdata.h
   172	const (
   173		_PCDATA_StackMapIndex       = 0
   174		_FUNCDATA_ArgsPointerMaps   = 0
   175		_FUNCDATA_LocalsPointerMaps = 1
   176		_ArgsSizeUnknown            = -0x80000000
   177	)
   178	
   179	// moduledata records information about the layout of the executable
   180	// image. It is written by the linker. Any changes here must be
   181	// matched changes to the code in cmd/internal/ld/symtab.go:symtab.
   182	// moduledata is stored in read-only memory; none of the pointers here
   183	// are visible to the garbage collector.
   184	type moduledata struct {
   185		pclntable    []byte
   186		ftab         []functab
   187		filetab      []uint32
   188		findfunctab  uintptr
   189		minpc, maxpc uintptr
   190	
   191		text, etext           uintptr
   192		noptrdata, enoptrdata uintptr
   193		data, edata           uintptr
   194		bss, ebss             uintptr
   195		noptrbss, enoptrbss   uintptr
   196		end, gcdata, gcbss    uintptr
   197		types, etypes         uintptr
   198	
   199		textsectmap []textsect
   200		typelinks   []int32 // offsets from types
   201		itablinks   []*itab
   202	
   203		ptab []ptabEntry
   204	
   205		pluginpath string
   206		pkghashes  []modulehash
   207	
   208		modulename   string
   209		modulehashes []modulehash
   210	
   211		gcdatamask, gcbssmask bitvector
   212	
   213		typemap map[typeOff]*_type // offset to *_rtype in previous module
   214	
   215		next *moduledata
   216	}
   217	
   218	// A modulehash is used to compare the ABI of a new module or a
   219	// package in a new module with the loaded program.
   220	//
   221	// For each shared library a module links against, the linker creates an entry in the
   222	// moduledata.modulehashes slice containing the name of the module, the abi hash seen
   223	// at link time and a pointer to the runtime abi hash. These are checked in
   224	// moduledataverify1 below.
   225	//
   226	// For each loaded plugin, the the pkghashes slice has a modulehash of the
   227	// newly loaded package that can be used to check the plugin's version of
   228	// a package against any previously loaded version of the package.
   229	// This is done in plugin.lastmoduleinit.
   230	type modulehash struct {
   231		modulename   string
   232		linktimehash string
   233		runtimehash  *string
   234	}
   235	
   236	// pinnedTypemaps are the map[typeOff]*_type from the moduledata objects.
   237	//
   238	// These typemap objects are allocated at run time on the heap, but the
   239	// only direct reference to them is in the moduledata, created by the
   240	// linker and marked SNOPTRDATA so it is ignored by the GC.
   241	//
   242	// To make sure the map isn't collected, we keep a second reference here.
   243	var pinnedTypemaps []map[typeOff]*_type
   244	
   245	var firstmoduledata moduledata  // linker symbol
   246	var lastmoduledatap *moduledata // linker symbol
   247	var modulesSlice unsafe.Pointer // see activeModules
   248	
   249	// activeModules returns a slice of active modules.
   250	//
   251	// A module is active once its gcdatamask and gcbssmask have been
   252	// assembled and it is usable by the GC.
   253	func activeModules() []*moduledata {
   254		p := (*[]*moduledata)(atomic.Loadp(unsafe.Pointer(&modulesSlice)))
   255		if p == nil {
   256			return nil
   257		}
   258		return *p
   259	}
   260	
   261	// modulesinit creates the active modules slice out of all loaded modules.
   262	//
   263	// When a module is first loaded by the dynamic linker, an .init_array
   264	// function (written by cmd/link) is invoked to call addmoduledata,
   265	// appending to the module to the linked list that starts with
   266	// firstmoduledata.
   267	//
   268	// There are two times this can happen in the lifecycle of a Go
   269	// program. First, if compiled with -linkshared, a number of modules
   270	// built with -buildmode=shared can be loaded at program initialization.
   271	// Second, a Go program can load a module while running that was built
   272	// with -buildmode=plugin.
   273	//
   274	// After loading, this function is called which initializes the
   275	// moduledata so it is usable by the GC and creates a new activeModules
   276	// list.
   277	//
   278	// Only one goroutine may call modulesinit at a time.
   279	func modulesinit() {
   280		modules := new([]*moduledata)
   281		for md := &firstmoduledata; md != nil; md = md.next {
   282			*modules = append(*modules, md)
   283			if md.gcdatamask == (bitvector{}) {
   284				md.gcdatamask = progToPointerMask((*byte)(unsafe.Pointer(md.gcdata)), md.edata-md.data)
   285				md.gcbssmask = progToPointerMask((*byte)(unsafe.Pointer(md.gcbss)), md.ebss-md.bss)
   286			}
   287		}
   288	
   289		// Modules appear in the moduledata linked list in the order they are
   290		// loaded by the dynamic loader, with one exception: the
   291		// firstmoduledata itself the module that contains the runtime. This
   292		// is not always the first module (when using -buildmode=shared, it
   293		// is typically libstd.so, the second module). The order matters for
   294		// typelinksinit, so we swap the first module with whatever module
   295		// contains the main function.
   296		//
   297		// See Issue #18729.
   298		mainText := funcPC(main_main)
   299		for i, md := range *modules {
   300			if md.text <= mainText && mainText <= md.etext {
   301				(*modules)[0] = md
   302				(*modules)[i] = &firstmoduledata
   303				break
   304			}
   305		}
   306	
   307		atomicstorep(unsafe.Pointer(&modulesSlice), unsafe.Pointer(modules))
   308	}
   309	
   310	type functab struct {
   311		entry   uintptr
   312		funcoff uintptr
   313	}
   314	
   315	// Mapping information for secondary text sections
   316	
   317	type textsect struct {
   318		vaddr    uintptr // prelinked section vaddr
   319		length   uintptr // section length
   320		baseaddr uintptr // relocated section address
   321	}
   322	
   323	const minfunc = 16                 // minimum function size
   324	const pcbucketsize = 256 * minfunc // size of bucket in the pc->func lookup table
   325	
   326	// findfunctab is an array of these structures.
   327	// Each bucket represents 4096 bytes of the text segment.
   328	// Each subbucket represents 256 bytes of the text segment.
   329	// To find a function given a pc, locate the bucket and subbucket for
   330	// that pc. Add together the idx and subbucket value to obtain a
   331	// function index. Then scan the functab array starting at that
   332	// index to find the target function.
   333	// This table uses 20 bytes for every 4096 bytes of code, or ~0.5% overhead.
   334	type findfuncbucket struct {
   335		idx        uint32
   336		subbuckets [16]byte
   337	}
   338	
   339	func moduledataverify() {
   340		for datap := &firstmoduledata; datap != nil; datap = datap.next {
   341			moduledataverify1(datap)
   342		}
   343	}
   344	
   345	const debugPcln = false
   346	
   347	func moduledataverify1(datap *moduledata) {
   348		// See golang.org/s/go12symtab for header: 0xfffffffb,
   349		// two zero bytes, a byte giving the PC quantum,
   350		// and a byte giving the pointer width in bytes.
   351		pcln := *(**[8]byte)(unsafe.Pointer(&datap.pclntable))
   352		pcln32 := *(**[2]uint32)(unsafe.Pointer(&datap.pclntable))
   353		if pcln32[0] != 0xfffffffb || pcln[4] != 0 || pcln[5] != 0 || pcln[6] != sys.PCQuantum || pcln[7] != sys.PtrSize {
   354			println("runtime: function symbol table header:", hex(pcln32[0]), hex(pcln[4]), hex(pcln[5]), hex(pcln[6]), hex(pcln[7]))
   355			throw("invalid function symbol table\n")
   356		}
   357	
   358		// ftab is lookup table for function by program counter.
   359		nftab := len(datap.ftab) - 1
   360		var pcCache pcvalueCache
   361		for i := 0; i < nftab; i++ {
   362			// NOTE: ftab[nftab].entry is legal; it is the address beyond the final function.
   363			if datap.ftab[i].entry > datap.ftab[i+1].entry {
   364				f1 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff]))
   365				f2 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff]))
   366				f2name := "end"
   367				if i+1 < nftab {
   368					f2name = funcname(f2)
   369				}
   370				println("function symbol table not sorted by program counter:", hex(datap.ftab[i].entry), funcname(f1), ">", hex(datap.ftab[i+1].entry), f2name)
   371				for j := 0; j <= i; j++ {
   372					print("\t", hex(datap.ftab[j].entry), " ", funcname((*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[j].funcoff]))), "\n")
   373				}
   374				throw("invalid runtime symbol table")
   375			}
   376	
   377			if debugPcln || nftab-i < 5 {
   378				// Check a PC near but not at the very end.
   379				// The very end might be just padding that is not covered by the tables.
   380				// No architecture rounds function entries to more than 16 bytes,
   381				// but if one came along we'd need to subtract more here.
   382				// But don't use the next PC if it corresponds to a foreign object chunk
   383				// (no pcln table, f2.pcln == 0). That chunk might have an alignment
   384				// more than 16 bytes.
   385				f := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff]))
   386				end := f.entry
   387				if i+1 < nftab {
   388					f2 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff]))
   389					if f2.pcln != 0 {
   390						end = f2.entry - 16
   391						if end < f.entry {
   392							end = f.entry
   393						}
   394					}
   395				}
   396				pcvalue(f, f.pcfile, end, &pcCache, true)
   397				pcvalue(f, f.pcln, end, &pcCache, true)
   398				pcvalue(f, f.pcsp, end, &pcCache, true)
   399			}
   400		}
   401	
   402		if datap.minpc != datap.ftab[0].entry ||
   403			datap.maxpc != datap.ftab[nftab].entry {
   404			throw("minpc or maxpc invalid")
   405		}
   406	
   407		for _, modulehash := range datap.modulehashes {
   408			if modulehash.linktimehash != *modulehash.runtimehash {
   409				println("abi mismatch detected between", datap.modulename, "and", modulehash.modulename)
   410				throw("abi mismatch")
   411			}
   412		}
   413	}
   414	
   415	// FuncForPC returns a *Func describing the function that contains the
   416	// given program counter address, or else nil.
   417	func FuncForPC(pc uintptr) *Func {
   418		return (*Func)(unsafe.Pointer(findfunc(pc)))
   419	}
   420	
   421	// Name returns the name of the function.
   422	func (f *Func) Name() string {
   423		return funcname(f.raw())
   424	}
   425	
   426	// Entry returns the entry address of the function.
   427	func (f *Func) Entry() uintptr {
   428		return f.raw().entry
   429	}
   430	
   431	// FileLine returns the file name and line number of the
   432	// source code corresponding to the program counter pc.
   433	// The result will not be accurate if pc is not a program
   434	// counter within f.
   435	func (f *Func) FileLine(pc uintptr) (file string, line int) {
   436		// Pass strict=false here, because anyone can call this function,
   437		// and they might just be wrong about targetpc belonging to f.
   438		file, line32 := funcline1(f.raw(), pc, false)
   439		return file, int(line32)
   440	}
   441	
   442	func findmoduledatap(pc uintptr) *moduledata {
   443		for datap := &firstmoduledata; datap != nil; datap = datap.next {
   444			if datap.minpc <= pc && pc < datap.maxpc {
   445				return datap
   446			}
   447		}
   448		return nil
   449	}
   450	
   451	func findfunc(pc uintptr) *_func {
   452		datap := findmoduledatap(pc)
   453		if datap == nil {
   454			return nil
   455		}
   456		const nsub = uintptr(len(findfuncbucket{}.subbuckets))
   457	
   458		x := pc - datap.minpc
   459		b := x / pcbucketsize
   460		i := x % pcbucketsize / (pcbucketsize / nsub)
   461	
   462		ffb := (*findfuncbucket)(add(unsafe.Pointer(datap.findfunctab), b*unsafe.Sizeof(findfuncbucket{})))
   463		idx := ffb.idx + uint32(ffb.subbuckets[i])
   464	
   465		// If the idx is beyond the end of the ftab, set it to the end of the table and search backward.
   466		// This situation can occur if multiple text sections are generated to handle large text sections
   467		// and the linker has inserted jump tables between them.
   468	
   469		if idx >= uint32(len(datap.ftab)) {
   470			idx = uint32(len(datap.ftab) - 1)
   471		}
   472		if pc < datap.ftab[idx].entry {
   473	
   474			// With multiple text sections, the idx might reference a function address that
   475			// is higher than the pc being searched, so search backward until the matching address is found.
   476	
   477			for datap.ftab[idx].entry > pc && idx > 0 {
   478				idx--
   479			}
   480			if idx == 0 {
   481				throw("findfunc: bad findfunctab entry idx")
   482			}
   483		} else {
   484	
   485			// linear search to find func with pc >= entry.
   486			for datap.ftab[idx+1].entry <= pc {
   487				idx++
   488			}
   489		}
   490		return (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[idx].funcoff]))
   491	}
   492	
   493	type pcvalueCache struct {
   494		entries [16]pcvalueCacheEnt
   495	}
   496	
   497	type pcvalueCacheEnt struct {
   498		// targetpc and off together are the key of this cache entry.
   499		targetpc uintptr
   500		off      int32
   501		// val is the value of this cached pcvalue entry.
   502		val int32
   503	}
   504	
   505	func pcvalue(f *_func, off int32, targetpc uintptr, cache *pcvalueCache, strict bool) int32 {
   506		if off == 0 {
   507			return -1
   508		}
   509	
   510		// Check the cache. This speeds up walks of deep stacks, which
   511		// tend to have the same recursive functions over and over.
   512		//
   513		// This cache is small enough that full associativity is
   514		// cheaper than doing the hashing for a less associative
   515		// cache.
   516		if cache != nil {
   517			for _, ent := range cache.entries {
   518				// We check off first because we're more
   519				// likely to have multiple entries with
   520				// different offsets for the same targetpc
   521				// than the other way around, so we'll usually
   522				// fail in the first clause.
   523				if ent.off == off && ent.targetpc == targetpc {
   524					return ent.val
   525				}
   526			}
   527		}
   528	
   529		datap := findmoduledatap(f.entry) // inefficient
   530		if datap == nil {
   531			if strict && panicking == 0 {
   532				print("runtime: no module data for ", hex(f.entry), "\n")
   533				throw("no module data")
   534			}
   535			return -1
   536		}
   537		p := datap.pclntable[off:]
   538		pc := f.entry
   539		val := int32(-1)
   540		for {
   541			var ok bool
   542			p, ok = step(p, &pc, &val, pc == f.entry)
   543			if !ok {
   544				break
   545			}
   546			if targetpc < pc {
   547				// Replace a random entry in the cache. Random
   548				// replacement prevents a performance cliff if
   549				// a recursive stack's cycle is slightly
   550				// larger than the cache.
   551				if cache != nil {
   552					ci := fastrand() % uint32(len(cache.entries))
   553					cache.entries[ci] = pcvalueCacheEnt{
   554						targetpc: targetpc,
   555						off:      off,
   556						val:      val,
   557					}
   558				}
   559	
   560				return val
   561			}
   562		}
   563	
   564		// If there was a table, it should have covered all program counters.
   565		// If not, something is wrong.
   566		if panicking != 0 || !strict {
   567			return -1
   568		}
   569	
   570		print("runtime: invalid pc-encoded table f=", funcname(f), " pc=", hex(pc), " targetpc=", hex(targetpc), " tab=", p, "\n")
   571	
   572		p = datap.pclntable[off:]
   573		pc = f.entry
   574		val = -1
   575		for {
   576			var ok bool
   577			p, ok = step(p, &pc, &val, pc == f.entry)
   578			if !ok {
   579				break
   580			}
   581			print("\tvalue=", val, " until pc=", hex(pc), "\n")
   582		}
   583	
   584		throw("invalid runtime symbol table")
   585		return -1
   586	}
   587	
   588	func cfuncname(f *_func) *byte {
   589		if f == nil || f.nameoff == 0 {
   590			return nil
   591		}
   592		datap := findmoduledatap(f.entry) // inefficient
   593		if datap == nil {
   594			return nil
   595		}
   596		return &datap.pclntable[f.nameoff]
   597	}
   598	
   599	func funcname(f *_func) string {
   600		return gostringnocopy(cfuncname(f))
   601	}
   602	
   603	func funcline1(f *_func, targetpc uintptr, strict bool) (file string, line int32) {
   604		datap := findmoduledatap(f.entry) // inefficient
   605		if datap == nil {
   606			return "?", 0
   607		}
   608		fileno := int(pcvalue(f, f.pcfile, targetpc, nil, strict))
   609		line = pcvalue(f, f.pcln, targetpc, nil, strict)
   610		if fileno == -1 || line == -1 || fileno >= len(datap.filetab) {
   611			// print("looking for ", hex(targetpc), " in ", funcname(f), " got file=", fileno, " line=", lineno, "\n")
   612			return "?", 0
   613		}
   614		file = gostringnocopy(&datap.pclntable[datap.filetab[fileno]])
   615		return
   616	}
   617	
   618	func funcline(f *_func, targetpc uintptr) (file string, line int32) {
   619		return funcline1(f, targetpc, true)
   620	}
   621	
   622	func funcspdelta(f *_func, targetpc uintptr, cache *pcvalueCache) int32 {
   623		x := pcvalue(f, f.pcsp, targetpc, cache, true)
   624		if x&(sys.PtrSize-1) != 0 {
   625			print("invalid spdelta ", funcname(f), " ", hex(f.entry), " ", hex(targetpc), " ", hex(f.pcsp), " ", x, "\n")
   626		}
   627		return x
   628	}
   629	
   630	func pcdatavalue(f *_func, table int32, targetpc uintptr, cache *pcvalueCache) int32 {
   631		if table < 0 || table >= f.npcdata {
   632			return -1
   633		}
   634		off := *(*int32)(add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(table)*4))
   635		return pcvalue(f, off, targetpc, cache, true)
   636	}
   637	
   638	func funcdata(f *_func, i int32) unsafe.Pointer {
   639		if i < 0 || i >= f.nfuncdata {
   640			return nil
   641		}
   642		p := add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(f.npcdata)*4)
   643		if sys.PtrSize == 8 && uintptr(p)&4 != 0 {
   644			if uintptr(unsafe.Pointer(f))&4 != 0 {
   645				println("runtime: misaligned func", f)
   646			}
   647			p = add(p, 4)
   648		}
   649		return *(*unsafe.Pointer)(add(p, uintptr(i)*sys.PtrSize))
   650	}
   651	
   652	// step advances to the next pc, value pair in the encoded table.
   653	func step(p []byte, pc *uintptr, val *int32, first bool) (newp []byte, ok bool) {
   654		p, uvdelta := readvarint(p)
   655		if uvdelta == 0 && !first {
   656			return nil, false
   657		}
   658		if uvdelta&1 != 0 {
   659			uvdelta = ^(uvdelta >> 1)
   660		} else {
   661			uvdelta >>= 1
   662		}
   663		vdelta := int32(uvdelta)
   664		p, pcdelta := readvarint(p)
   665		*pc += uintptr(pcdelta * sys.PCQuantum)
   666		*val += vdelta
   667		return p, true
   668	}
   669	
   670	// readvarint reads a varint from p.
   671	func readvarint(p []byte) (newp []byte, val uint32) {
   672		var v, shift uint32
   673		for {
   674			b := p[0]
   675			p = p[1:]
   676			v |= (uint32(b) & 0x7F) << shift
   677			if b&0x80 == 0 {
   678				break
   679			}
   680			shift += 7
   681		}
   682		return p, v
   683	}
   684	
   685	type stackmap struct {
   686		n        int32   // number of bitmaps
   687		nbit     int32   // number of bits in each bitmap
   688		bytedata [1]byte // bitmaps, each starting on a byte boundary
   689	}
   690	
   691	//go:nowritebarrier
   692	func stackmapdata(stkmap *stackmap, n int32) bitvector {
   693		if n < 0 || n >= stkmap.n {
   694			throw("stackmapdata: index out of range")
   695		}
   696		return bitvector{stkmap.nbit, (*byte)(add(unsafe.Pointer(&stkmap.bytedata), uintptr(n*((stkmap.nbit+7)/8))))}
   697	}
   698	

View as plain text