decode.mx raw

   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: []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() []byte {
  70  	return d.strtab.Get(d.hdr.PkgPath)
  71  }
  72  
  73  func (d *CoverageMetaDataDecoder) PackageName() []byte {
  74  	return d.strtab.Get(d.hdr.PkgName)
  75  }
  76  
  77  func (d *CoverageMetaDataDecoder) ModulePath() []byte {
  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 = []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