unit.mx raw

   1  // Copyright 2009 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 dwarf
   6  
   7  import (
   8  	"sort"
   9  	"strconv"
  10  )
  11  
  12  // DWARF debug info is split into a sequence of compilation units.
  13  // Each unit has its own abbreviation table and address size.
  14  
  15  type unit struct {
  16  	base   Offset // byte offset of header within the aggregate info
  17  	off    Offset // byte offset of data within the aggregate info
  18  	data   []byte
  19  	atable abbrevTable
  20  	*unit5 // info specific to DWARF 5 units
  21  	asize  int
  22  	vers   int
  23  	is64   bool  // True for 64-bit DWARF format
  24  	utype  uint8 // DWARF 5 unit type
  25  }
  26  
  27  type unit5 struct {
  28  	addrBase       uint64
  29  	strOffsetsBase uint64
  30  	rngListsBase   uint64
  31  	locListsBase   uint64
  32  }
  33  
  34  // Implement the dataFormat interface.
  35  
  36  func (u *unit) version() int {
  37  	return u.vers
  38  }
  39  
  40  func (u *unit) dwarf64() (bool, bool) {
  41  	return u.is64, true
  42  }
  43  
  44  func (u *unit) addrsize() int {
  45  	return u.asize
  46  }
  47  
  48  func (u *unit) addrBase() uint64 {
  49  	if u.unit5 != nil {
  50  		return u.unit5.addrBase
  51  	}
  52  	return 0
  53  }
  54  
  55  func (u *unit) strOffsetsBase() uint64 {
  56  	if u.unit5 != nil {
  57  		return u.unit5.strOffsetsBase
  58  	}
  59  	return 0
  60  }
  61  
  62  func (u *unit) rngListsBase() uint64 {
  63  	if u.unit5 != nil {
  64  		return u.unit5.rngListsBase
  65  	}
  66  	return 0
  67  }
  68  
  69  func (u *unit) locListsBase() uint64 {
  70  	if u.unit5 != nil {
  71  		return u.unit5.locListsBase
  72  	}
  73  	return 0
  74  }
  75  
  76  func (d *Data) parseUnits() ([]unit, error) {
  77  	// Count units.
  78  	nunit := 0
  79  	b := makeBuf(d, unknownFormat{}, "info", 0, d.info)
  80  	for len(b.data) > 0 {
  81  		len, _ := b.unitLength()
  82  		if len != Offset(uint32(len)) {
  83  			b.error("unit length overflow")
  84  			break
  85  		}
  86  		b.skip(int(len))
  87  		if len > 0 {
  88  			nunit++
  89  		}
  90  	}
  91  	if b.err != nil {
  92  		return nil, b.err
  93  	}
  94  
  95  	// Again, this time writing them down.
  96  	b = makeBuf(d, unknownFormat{}, "info", 0, d.info)
  97  	units := []unit{:nunit}
  98  	for i := range units {
  99  		u := &units[i]
 100  		u.base = b.off
 101  		var n Offset
 102  		if b.err != nil {
 103  			return nil, b.err
 104  		}
 105  		for n == 0 {
 106  			n, u.is64 = b.unitLength()
 107  		}
 108  		dataOff := b.off
 109  		vers := b.uint16()
 110  		if vers < 2 || vers > 5 {
 111  			b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
 112  			break
 113  		}
 114  		u.vers = int(vers)
 115  		if vers >= 5 {
 116  			u.utype = b.uint8()
 117  			u.asize = int(b.uint8())
 118  		}
 119  		var abbrevOff uint64
 120  		if u.is64 {
 121  			abbrevOff = b.uint64()
 122  		} else {
 123  			abbrevOff = uint64(b.uint32())
 124  		}
 125  		atable, err := d.parseAbbrev(abbrevOff, u.vers)
 126  		if err != nil {
 127  			if b.err == nil {
 128  				b.err = err
 129  			}
 130  			break
 131  		}
 132  		u.atable = atable
 133  		if vers < 5 {
 134  			u.asize = int(b.uint8())
 135  		}
 136  
 137  		switch u.utype {
 138  		case utSkeleton, utSplitCompile:
 139  			b.uint64() // unit ID
 140  		case utType, utSplitType:
 141  			b.uint64()  // type signature
 142  			if u.is64 { // type offset
 143  				b.uint64()
 144  			} else {
 145  				b.uint32()
 146  			}
 147  		}
 148  
 149  		u.off = b.off
 150  		u.data = b.bytes(int(n - (b.off - dataOff)))
 151  	}
 152  	if b.err != nil {
 153  		return nil, b.err
 154  	}
 155  	return units, nil
 156  }
 157  
 158  // offsetToUnit returns the index of the unit containing offset off.
 159  // It returns -1 if no unit contains this offset.
 160  func (d *Data) offsetToUnit(off Offset) int {
 161  	// Find the unit after off
 162  	next := sort.Search(len(d.unit), func(i int) bool {
 163  		return d.unit[i].off > off
 164  	})
 165  	if next == 0 {
 166  		return -1
 167  	}
 168  	u := &d.unit[next-1]
 169  	if u.off <= off && off < u.off+Offset(len(u.data)) {
 170  		return next - 1
 171  	}
 172  	return -1
 173  }
 174  
 175  func (d *Data) collectDwarf5BaseOffsets(u *unit) error {
 176  	if u.unit5 == nil {
 177  		panic("expected unit5 to be set up already")
 178  	}
 179  	b := makeBuf(d, u, "info", u.off, u.data)
 180  	cu := b.entry(nil, u)
 181  	if cu == nil {
 182  		// Unknown abbreviation table entry or some other fatal
 183  		// problem; bail early on the assumption that this will be
 184  		// detected at some later point.
 185  		return b.err
 186  	}
 187  	if iAddrBase, ok := cu.Val(AttrAddrBase).(int64); ok {
 188  		u.unit5.addrBase = uint64(iAddrBase)
 189  	}
 190  	if iStrOffsetsBase, ok := cu.Val(AttrStrOffsetsBase).(int64); ok {
 191  		u.unit5.strOffsetsBase = uint64(iStrOffsetsBase)
 192  	}
 193  	if iRngListsBase, ok := cu.Val(AttrRnglistsBase).(int64); ok {
 194  		u.unit5.rngListsBase = uint64(iRngListsBase)
 195  	}
 196  	if iLocListsBase, ok := cu.Val(AttrLoclistsBase).(int64); ok {
 197  		u.unit5.locListsBase = uint64(iLocListsBase)
 198  	}
 199  	return nil
 200  }
 201