Source file src/runtime/stkframe.go

     1  // Copyright 2022 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/sys"
    11  	"unsafe"
    12  )
    13  
    14  // A stkframe holds information about a single physical stack frame.
    15  type stkframe struct {
    16  	// fn is the function being run in this frame. If there is
    17  	// inlining, this is the outermost function.
    18  	fn funcInfo
    19  
    20  	// pc is the program counter within fn.
    21  	//
    22  	// The meaning of this is subtle:
    23  	//
    24  	// - Typically, this frame performed a regular function call
    25  	//   and this is the return PC (just after the CALL
    26  	//   instruction). In this case, pc-1 reflects the CALL
    27  	//   instruction itself and is the correct source of symbolic
    28  	//   information.
    29  	//
    30  	// - If this frame "called" sigpanic, then pc is the
    31  	//   instruction that panicked, and pc is the correct address
    32  	//   to use for symbolic information.
    33  	//
    34  	// - If this is the innermost frame, then PC is where
    35  	//   execution will continue, but it may not be the
    36  	//   instruction following a CALL. This may be from
    37  	//   cooperative preemption, in which case this is the
    38  	//   instruction after the call to morestack. Or this may be
    39  	//   from a signal or an un-started goroutine, in which case
    40  	//   PC could be any instruction, including the first
    41  	//   instruction in a function. Conventionally, we use pc-1
    42  	//   for symbolic information, unless pc == fn.entry(), in
    43  	//   which case we use pc.
    44  	pc uintptr
    45  
    46  	// continpc is the PC where execution will continue in fn, or
    47  	// 0 if execution will not continue in this frame.
    48  	//
    49  	// This is usually the same as pc, unless this frame "called"
    50  	// sigpanic, in which case it's either the address of
    51  	// deferreturn or 0 if this frame will never execute again.
    52  	//
    53  	// This is the PC to use to look up GC liveness for this frame.
    54  	continpc uintptr
    55  
    56  	lr   uintptr // program counter at caller aka link register
    57  	sp   uintptr // stack pointer at pc
    58  	fp   uintptr // stack pointer at caller aka frame pointer
    59  	varp uintptr // top of local variables
    60  	argp uintptr // pointer to function arguments
    61  }
    62  
    63  // reflectMethodValue is a partial duplicate of reflect.makeFuncImpl
    64  // and reflect.methodValue.
    65  type reflectMethodValue struct {
    66  	fn     uintptr
    67  	stack  *bitvector // ptrmap for both args and results
    68  	argLen uintptr    // just args
    69  }
    70  
    71  // argBytes returns the argument frame size for a call to frame.fn.
    72  func (frame *stkframe) argBytes() uintptr {
    73  	if frame.fn.args != abi.ArgsSizeUnknown {
    74  		return uintptr(frame.fn.args)
    75  	}
    76  	// This is an uncommon and complicated case. Fall back to fully
    77  	// fetching the argument map to compute its size.
    78  	argMap, _ := frame.argMapInternal()
    79  	return uintptr(argMap.n) * goarch.PtrSize
    80  }
    81  
    82  // argMapInternal is used internally by stkframe to fetch special
    83  // argument maps.
    84  //
    85  // argMap.n is always populated with the size of the argument map.
    86  //
    87  // argMap.bytedata is only populated for dynamic argument maps (used
    88  // by reflect). If the caller requires the argument map, it should use
    89  // this if non-nil, and otherwise fetch the argument map using the
    90  // current PC.
    91  //
    92  // hasReflectStackObj indicates that this frame also has a reflect
    93  // function stack object, which the caller must synthesize.
    94  func (frame *stkframe) argMapInternal() (argMap bitvector, hasReflectStackObj bool) {
    95  	f := frame.fn
    96  	if f.args != abi.ArgsSizeUnknown {
    97  		argMap.n = f.args / goarch.PtrSize
    98  		return
    99  	}
   100  	// Extract argument bitmaps for reflect stubs from the calls they made to reflect.
   101  	switch funcname(f) {
   102  	case "reflect.makeFuncStub", "reflect.methodValueCall":
   103  		// These take a *reflect.methodValue as their
   104  		// context register and immediately save it to 0(SP).
   105  		// Get the methodValue from 0(SP).
   106  		arg0 := frame.sp + sys.MinFrameSize
   107  
   108  		minSP := frame.fp
   109  		if !usesLR {
   110  			// The CALL itself pushes a word.
   111  			// Undo that adjustment.
   112  			minSP -= goarch.PtrSize
   113  		}
   114  		if arg0 >= minSP {
   115  			// The function hasn't started yet.
   116  			// This only happens if f was the
   117  			// start function of a new goroutine
   118  			// that hasn't run yet *and* f takes
   119  			// no arguments and has no results
   120  			// (otherwise it will get wrapped in a
   121  			// closure). In this case, we can't
   122  			// reach into its locals because it
   123  			// doesn't have locals yet, but we
   124  			// also know its argument map is
   125  			// empty.
   126  			if frame.pc != f.entry() {
   127  				print("runtime: confused by ", funcname(f), ": no frame (sp=", hex(frame.sp), " fp=", hex(frame.fp), ") at entry+", hex(frame.pc-f.entry()), "\n")
   128  				throw("reflect mismatch")
   129  			}
   130  			return bitvector{}, false // No locals, so also no stack objects
   131  		}
   132  		hasReflectStackObj = true
   133  		mv := *(**reflectMethodValue)(unsafe.Pointer(arg0))
   134  		// Figure out whether the return values are valid.
   135  		// Reflect will update this value after it copies
   136  		// in the return values.
   137  		retValid := *(*bool)(unsafe.Pointer(arg0 + 4*goarch.PtrSize))
   138  		if mv.fn != f.entry() {
   139  			print("runtime: confused by ", funcname(f), "\n")
   140  			throw("reflect mismatch")
   141  		}
   142  		argMap = *mv.stack
   143  		if !retValid {
   144  			// argMap.n includes the results, but
   145  			// those aren't valid, so drop them.
   146  			n := int32((mv.argLen &^ (goarch.PtrSize - 1)) / goarch.PtrSize)
   147  			if n < argMap.n {
   148  				argMap.n = n
   149  			}
   150  		}
   151  	}
   152  	return
   153  }
   154  
   155  // getStackMap returns the locals and arguments live pointer maps, and
   156  // stack object list for frame.
   157  func (frame *stkframe) getStackMap(debug bool) (locals, args bitvector, objs []stackObjectRecord) {
   158  	targetpc := frame.continpc
   159  	if targetpc == 0 {
   160  		// Frame is dead. Return empty bitvectors.
   161  		return
   162  	}
   163  
   164  	f := frame.fn
   165  	pcdata := int32(-1)
   166  	if targetpc != f.entry() {
   167  		// Back up to the CALL. If we're at the function entry
   168  		// point, we want to use the entry map (-1), even if
   169  		// the first instruction of the function changes the
   170  		// stack map.
   171  		targetpc--
   172  		pcdata = pcdatavalue(f, abi.PCDATA_StackMapIndex, targetpc)
   173  	}
   174  	if pcdata == -1 {
   175  		// We do not have a valid pcdata value but there might be a
   176  		// stackmap for this function. It is likely that we are looking
   177  		// at the function prologue, assume so and hope for the best.
   178  		pcdata = 0
   179  	}
   180  
   181  	// Local variables.
   182  	size := frame.varp - frame.sp
   183  	var minsize uintptr
   184  	switch goarch.ArchFamily {
   185  	case goarch.ARM64:
   186  		minsize = sys.StackAlign
   187  	default:
   188  		minsize = sys.MinFrameSize
   189  	}
   190  	if size > minsize {
   191  		stackid := pcdata
   192  		stkmap := (*stackmap)(funcdata(f, abi.FUNCDATA_LocalsPointerMaps))
   193  		if stkmap == nil || stkmap.n <= 0 {
   194  			print("runtime: frame ", funcname(f), " untyped locals ", hex(frame.varp-size), "+", hex(size), "\n")
   195  			throw("missing stackmap")
   196  		}
   197  		// If nbit == 0, there's no work to do.
   198  		if stkmap.nbit > 0 {
   199  			if stackid < 0 || stackid >= stkmap.n {
   200  				// don't know where we are
   201  				print("runtime: pcdata is ", stackid, " and ", stkmap.n, " locals stack map entries for ", funcname(f), " (targetpc=", hex(targetpc), ")\n")
   202  				throw("bad symbol table")
   203  			}
   204  			locals = stackmapdata(stkmap, stackid)
   205  			if stackDebug >= 3 && debug {
   206  				print("      locals ", stackid, "/", stkmap.n, " ", locals.n, " words ", locals.bytedata, "\n")
   207  			}
   208  		} else if stackDebug >= 3 && debug {
   209  			print("      no locals to adjust\n")
   210  		}
   211  	}
   212  
   213  	// Arguments. First fetch frame size and special-case argument maps.
   214  	var isReflect bool
   215  	args, isReflect = frame.argMapInternal()
   216  	if args.n > 0 && args.bytedata == nil {
   217  		// Non-empty argument frame, but not a special map.
   218  		// Fetch the argument map at pcdata.
   219  		stackmap := (*stackmap)(funcdata(f, abi.FUNCDATA_ArgsPointerMaps))
   220  		if stackmap == nil || stackmap.n <= 0 {
   221  			print("runtime: frame ", funcname(f), " untyped args ", hex(frame.argp), "+", hex(args.n*goarch.PtrSize), "\n")
   222  			throw("missing stackmap")
   223  		}
   224  		if pcdata < 0 || pcdata >= stackmap.n {
   225  			// don't know where we are
   226  			print("runtime: pcdata is ", pcdata, " and ", stackmap.n, " args stack map entries for ", funcname(f), " (targetpc=", hex(targetpc), ")\n")
   227  			throw("bad symbol table")
   228  		}
   229  		if stackmap.nbit == 0 {
   230  			args.n = 0
   231  		} else {
   232  			args = stackmapdata(stackmap, pcdata)
   233  		}
   234  	}
   235  
   236  	// stack objects.
   237  	if (GOARCH == "amd64" || GOARCH == "arm64" || GOARCH == "loong64" || GOARCH == "ppc64" || GOARCH == "ppc64le" || GOARCH == "riscv64") &&
   238  		unsafe.Sizeof(abi.RegArgs{}) > 0 && isReflect {
   239  		// For reflect.makeFuncStub and reflect.methodValueCall,
   240  		// we need to fake the stack object record.
   241  		// These frames contain an internal/abi.RegArgs at a hard-coded offset.
   242  		// This offset matches the assembly code on amd64 and arm64.
   243  		objs = methodValueCallFrameObjs[:]
   244  	} else {
   245  		p := funcdata(f, abi.FUNCDATA_StackObjects)
   246  		if p != nil {
   247  			n := *(*uintptr)(p)
   248  			p = add(p, goarch.PtrSize)
   249  			r0 := (*stackObjectRecord)(noescape(p))
   250  			objs = unsafe.Slice(r0, int(n))
   251  			// Note: the noescape above is needed to keep
   252  			// getStackMap from "leaking param content:
   253  			// frame".  That leak propagates up to getgcmask, then
   254  			// GCMask, then verifyGCInfo, which converts the stack
   255  			// gcinfo tests into heap gcinfo tests :(
   256  		}
   257  	}
   258  
   259  	return
   260  }
   261  
   262  var methodValueCallFrameObjs [1]stackObjectRecord // initialized in stackobjectinit
   263  
   264  func stkobjinit() {
   265  	var abiRegArgsEface any = abi.RegArgs{}
   266  	abiRegArgsType := efaceOf(&abiRegArgsEface)._type
   267  	if abiRegArgsType.Kind_&abi.KindGCProg != 0 {
   268  		throw("abiRegArgsType needs GC Prog, update methodValueCallFrameObjs")
   269  	}
   270  	// Set methodValueCallFrameObjs[0].gcdataoff so that
   271  	// stackObjectRecord.gcdata() will work correctly with it.
   272  	ptr := uintptr(unsafe.Pointer(&methodValueCallFrameObjs[0]))
   273  	var mod *moduledata
   274  	for datap := &firstmoduledata; datap != nil; datap = datap.next {
   275  		if datap.gofunc <= ptr && ptr < datap.end {
   276  			mod = datap
   277  			break
   278  		}
   279  	}
   280  	if mod == nil {
   281  		throw("methodValueCallFrameObjs is not in a module")
   282  	}
   283  	methodValueCallFrameObjs[0] = stackObjectRecord{
   284  		off:       -int32(alignUp(abiRegArgsType.Size_, 8)), // It's always the highest address local.
   285  		size:      int32(abiRegArgsType.Size_),
   286  		_ptrdata:  int32(abiRegArgsType.PtrBytes),
   287  		gcdataoff: uint32(uintptr(unsafe.Pointer(abiRegArgsType.GCData)) - mod.rodata),
   288  	}
   289  }
   290  

View as plain text