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 5package dwarf 6 7import ( 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 15type 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 asize int 21 vers int 22 utype uint8 // DWARF 5 unit type 23 is64 bool // True for 64-bit DWARF format 24} 25 26// Implement the dataFormat interface. 27 28func (u *unit) version() int { 29 return u.vers 30} 31 32func (u *unit) dwarf64() (bool, bool) { 33 return u.is64, true 34} 35 36func (u *unit) addrsize() int { 37 return u.asize 38} 39 40func (d *Data) parseUnits() ([]unit, error) { 41 // Count units. 42 nunit := 0 43 b := makeBuf(d, unknownFormat{}, "info", 0, d.info) 44 for len(b.data) > 0 { 45 len, _ := b.unitLength() 46 if len != Offset(uint32(len)) { 47 b.error("unit length overflow") 48 break 49 } 50 b.skip(int(len)) 51 nunit++ 52 } 53 if b.err != nil { 54 return nil, b.err 55 } 56 57 // Again, this time writing them down. 58 b = makeBuf(d, unknownFormat{}, "info", 0, d.info) 59 units := make([]unit, nunit) 60 for i := range units { 61 u := &units[i] 62 u.base = b.off 63 var n Offset 64 n, u.is64 = b.unitLength() 65 dataOff := b.off 66 vers := b.uint16() 67 if vers < 2 || vers > 5 { 68 b.error("unsupported DWARF version " + strconv.Itoa(int(vers))) 69 break 70 } 71 u.vers = int(vers) 72 if vers >= 5 { 73 u.utype = b.uint8() 74 u.asize = int(b.uint8()) 75 } 76 var abbrevOff uint64 77 if u.is64 { 78 abbrevOff = b.uint64() 79 } else { 80 abbrevOff = uint64(b.uint32()) 81 } 82 atable, err := d.parseAbbrev(abbrevOff, u.vers) 83 if err != nil { 84 if b.err == nil { 85 b.err = err 86 } 87 break 88 } 89 u.atable = atable 90 if vers < 5 { 91 u.asize = int(b.uint8()) 92 } 93 94 switch u.utype { 95 case utSkeleton, utSplitCompile: 96 b.uint64() // unit ID 97 case utType, utSplitType: 98 b.uint64() // type signature 99 if u.is64 { // type offset 100 b.uint64() 101 } else { 102 b.uint32() 103 } 104 } 105 106 u.off = b.off 107 u.data = b.bytes(int(n - (b.off - dataOff))) 108 } 109 if b.err != nil { 110 return nil, b.err 111 } 112 return units, nil 113} 114 115// offsetToUnit returns the index of the unit containing offset off. 116// It returns -1 if no unit contains this offset. 117func (d *Data) offsetToUnit(off Offset) int { 118 // Find the unit after off 119 next := sort.Search(len(d.unit), func(i int) bool { 120 return d.unit[i].off > off 121 }) 122 if next == 0 { 123 return -1 124 } 125 u := &d.unit[next-1] 126 if u.off <= off && off < u.off+Offset(len(u.data)) { 127 return next - 1 128 } 129 return -1 130} 131