github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/runtime/symtabinl.go (about)

     1  // Copyright 2023 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 "internal/abi"
     8  
     9  // inlinedCall is the encoding of entries in the FUNCDATA_InlTree table.
    10  type inlinedCall struct {
    11  	funcID    abi.FuncID // type of the called function
    12  	_         [3]byte
    13  	nameOff   int32 // offset into pclntab for name of called function
    14  	parentPc  int32 // position of an instruction whose source position is the call site (offset from entry)
    15  	startLine int32 // line number of start of function (func keyword/TEXT directive)
    16  }
    17  
    18  // An inlineUnwinder iterates over the stack of inlined calls at a PC by
    19  // decoding the inline table. The last step of iteration is always the frame of
    20  // the physical function, so there's always at least one frame.
    21  //
    22  // This is typically used as:
    23  //
    24  //	for u, uf := newInlineUnwinder(...); uf.valid(); uf = u.next(uf) { ... }
    25  //
    26  // Implementation note: This is used in contexts that disallow write barriers.
    27  // Hence, the constructor returns this by value and pointer receiver methods
    28  // must not mutate pointer fields. Also, we keep the mutable state in a separate
    29  // struct mostly to keep both structs SSA-able, which generates much better
    30  // code.
    31  type inlineUnwinder struct {
    32  	f       funcInfo
    33  	cache   *pcvalueCache
    34  	inlTree *[1 << 20]inlinedCall
    35  }
    36  
    37  // An inlineFrame is a position in an inlineUnwinder.
    38  type inlineFrame struct {
    39  	// pc is the PC giving the file/line metadata of the current frame. This is
    40  	// always a "call PC" (not a "return PC"). This is 0 when the iterator is
    41  	// exhausted.
    42  	pc uintptr
    43  
    44  	// index is the index of the current record in inlTree, or -1 if we are in
    45  	// the outermost function.
    46  	index int32
    47  }
    48  
    49  // newInlineUnwinder creates an inlineUnwinder initially set to the inner-most
    50  // inlined frame at PC. PC should be a "call PC" (not a "return PC").
    51  //
    52  // This unwinder uses non-strict handling of PC because it's assumed this is
    53  // only ever used for symbolic debugging. If things go really wrong, it'll just
    54  // fall back to the outermost frame.
    55  func newInlineUnwinder(f funcInfo, pc uintptr, cache *pcvalueCache) (inlineUnwinder, inlineFrame) {
    56  	inldata := funcdata(f, abi.FUNCDATA_InlTree)
    57  	if inldata == nil {
    58  		return inlineUnwinder{f: f}, inlineFrame{pc: pc, index: -1}
    59  	}
    60  	inlTree := (*[1 << 20]inlinedCall)(inldata)
    61  	u := inlineUnwinder{f: f, cache: cache, inlTree: inlTree}
    62  	return u, u.resolveInternal(pc)
    63  }
    64  
    65  func (u *inlineUnwinder) resolveInternal(pc uintptr) inlineFrame {
    66  	return inlineFrame{
    67  		pc: pc,
    68  		// Conveniently, this returns -1 if there's an error, which is the same
    69  		// value we use for the outermost frame.
    70  		index: pcdatavalue1(u.f, abi.PCDATA_InlTreeIndex, pc, u.cache, false),
    71  	}
    72  }
    73  
    74  func (uf inlineFrame) valid() bool {
    75  	return uf.pc != 0
    76  }
    77  
    78  // next returns the frame representing uf's logical caller.
    79  func (u *inlineUnwinder) next(uf inlineFrame) inlineFrame {
    80  	if uf.index < 0 {
    81  		uf.pc = 0
    82  		return uf
    83  	}
    84  	parentPc := u.inlTree[uf.index].parentPc
    85  	return u.resolveInternal(u.f.entry() + uintptr(parentPc))
    86  }
    87  
    88  // isInlined returns whether uf is an inlined frame.
    89  func (u *inlineUnwinder) isInlined(uf inlineFrame) bool {
    90  	return uf.index >= 0
    91  }
    92  
    93  // srcFunc returns the srcFunc representing the given frame.
    94  func (u *inlineUnwinder) srcFunc(uf inlineFrame) srcFunc {
    95  	if uf.index < 0 {
    96  		return u.f.srcFunc()
    97  	}
    98  	t := &u.inlTree[uf.index]
    99  	return srcFunc{
   100  		u.f.datap,
   101  		t.nameOff,
   102  		t.startLine,
   103  		t.funcID,
   104  	}
   105  }
   106  
   107  // fileLine returns the file name and line number of the call within the given
   108  // frame. As a convenience, for the innermost frame, it returns the file and
   109  // line of the PC this unwinder was started at (often this is a call to another
   110  // physical function).
   111  //
   112  // It returns "?", 0 if something goes wrong.
   113  func (u *inlineUnwinder) fileLine(uf inlineFrame) (file string, line int) {
   114  	file, line32 := funcline1(u.f, uf.pc, false)
   115  	return file, int(line32)
   116  }