Source file src/internal/coverage/decodemeta/decode.go

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

View as plain text