github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/internal/coverage/decodemeta/decode.go (about)

     1  // Copyright 2021 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 decodemeta
     6  
     7  // This package contains APIs and helpers for decoding a single package's
     8  // meta data "blob" emitted by the compiler when coverage instrumentation
     9  // is turned on.
    10  
    11  import (
    12  	"encoding/binary"
    13  	"fmt"
    14  	"internal/coverage"
    15  	"internal/coverage/slicereader"
    16  	"internal/coverage/stringtab"
    17  	"os"
    18  )
    19  
    20  // See comments in the encodecovmeta package for details on the format.
    21  
    22  type CoverageMetaDataDecoder struct {
    23  	r      *slicereader.Reader
    24  	hdr    coverage.MetaSymbolHeader
    25  	strtab *stringtab.Reader
    26  	tmp    []byte
    27  	debug  bool
    28  }
    29  
    30  func NewCoverageMetaDataDecoder(b []byte, readonly bool) (*CoverageMetaDataDecoder, error) {
    31  	slr := slicereader.NewReader(b, readonly)
    32  	x := &CoverageMetaDataDecoder{
    33  		r:   slr,
    34  		tmp: make([]byte, 0, 256),
    35  	}
    36  	if err := x.readHeader(); err != nil {
    37  		return nil, err
    38  	}
    39  	if err := x.readStringTable(); err != nil {
    40  		return nil, err
    41  	}
    42  	return x, nil
    43  }
    44  
    45  func (d *CoverageMetaDataDecoder) readHeader() error {
    46  	if err := binary.Read(d.r, binary.LittleEndian, &d.hdr); err != nil {
    47  		return err
    48  	}
    49  	if d.debug {
    50  		fmt.Fprintf(os.Stderr, "=-= after readHeader: %+v\n", d.hdr)
    51  	}
    52  	return nil
    53  }
    54  
    55  func (d *CoverageMetaDataDecoder) readStringTable() error {
    56  	// Seek to the correct location to read the string table.
    57  	stringTableLocation := int64(coverage.CovMetaHeaderSize + 4*d.hdr.NumFuncs)
    58  	d.r.SeekTo(stringTableLocation)
    59  
    60  	// Read the table itself.
    61  	d.strtab = stringtab.NewReader(d.r)
    62  	d.strtab.Read()
    63  	return nil
    64  }
    65  
    66  func (d *CoverageMetaDataDecoder) PackagePath() string {
    67  	return d.strtab.Get(d.hdr.PkgPath)
    68  }
    69  
    70  func (d *CoverageMetaDataDecoder) PackageName() string {
    71  	return d.strtab.Get(d.hdr.PkgName)
    72  }
    73  
    74  func (d *CoverageMetaDataDecoder) ModulePath() string {
    75  	return d.strtab.Get(d.hdr.ModulePath)
    76  }
    77  
    78  func (d *CoverageMetaDataDecoder) NumFuncs() uint32 {
    79  	return d.hdr.NumFuncs
    80  }
    81  
    82  // ReadFunc reads the coverage meta-data for the function with index
    83  // 'findex', filling it into the FuncDesc pointed to by 'f'.
    84  func (d *CoverageMetaDataDecoder) ReadFunc(fidx uint32, f *coverage.FuncDesc) error {
    85  	if fidx >= d.hdr.NumFuncs {
    86  		return fmt.Errorf("illegal function index")
    87  	}
    88  
    89  	// Seek to the correct location to read the function offset and read it.
    90  	funcOffsetLocation := int64(coverage.CovMetaHeaderSize + 4*fidx)
    91  	d.r.SeekTo(funcOffsetLocation)
    92  	foff := d.r.ReadUint32()
    93  
    94  	// Check assumptions
    95  	if foff < uint32(funcOffsetLocation) || foff > d.hdr.Length {
    96  		return fmt.Errorf("malformed func offset %d", foff)
    97  	}
    98  
    99  	// Seek to the correct location to read the function.
   100  	d.r.SeekTo(int64(foff))
   101  
   102  	// Preamble containing number of units, file, and function.
   103  	numUnits := uint32(d.r.ReadULEB128())
   104  	fnameidx := uint32(d.r.ReadULEB128())
   105  	fileidx := uint32(d.r.ReadULEB128())
   106  
   107  	f.Srcfile = d.strtab.Get(fileidx)
   108  	f.Funcname = d.strtab.Get(fnameidx)
   109  
   110  	// Now the units
   111  	f.Units = f.Units[:0]
   112  	if cap(f.Units) < int(numUnits) {
   113  		f.Units = make([]coverage.CoverableUnit, 0, numUnits)
   114  	}
   115  	for k := uint32(0); k < numUnits; k++ {
   116  		f.Units = append(f.Units,
   117  			coverage.CoverableUnit{
   118  				StLine:  uint32(d.r.ReadULEB128()),
   119  				StCol:   uint32(d.r.ReadULEB128()),
   120  				EnLine:  uint32(d.r.ReadULEB128()),
   121  				EnCol:   uint32(d.r.ReadULEB128()),
   122  				NxStmts: uint32(d.r.ReadULEB128()),
   123  			})
   124  	}
   125  	lit := d.r.ReadULEB128()
   126  	f.Lit = lit != 0
   127  	return nil
   128  }