Source file src/debug/dwarf/unit.go

     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 := make([]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  

View as plain text