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 }