gitlab.com/Raven-IO/raven-delve@v1.22.4/pkg/dwarf/loclist/dwarf5_loclist.go (about) 1 package loclist 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "fmt" 7 8 "gitlab.com/Raven-IO/raven-delve/pkg/dwarf" 9 "gitlab.com/Raven-IO/raven-delve/pkg/dwarf/godwarf" 10 "gitlab.com/Raven-IO/raven-delve/pkg/dwarf/leb128" 11 ) 12 13 // Dwarf5Reader parses and presents DWARF loclist information for DWARF version 5 and later. 14 // See DWARFv5 section 7.29 page 243 and following. 15 type Dwarf5Reader struct { 16 byteOrder binary.ByteOrder 17 ptrSz int 18 data []byte 19 } 20 21 func NewDwarf5Reader(data []byte) *Dwarf5Reader { 22 if len(data) == 0 { 23 return nil 24 } 25 r := &Dwarf5Reader{data: data} 26 27 _, dwarf64, _, byteOrder := dwarf.ReadDwarfLengthVersion(data) 28 r.byteOrder = byteOrder 29 30 data = data[6:] 31 if dwarf64 { 32 data = data[8:] 33 } 34 35 addrSz := data[0] 36 segSelSz := data[1] 37 r.ptrSz = int(addrSz + segSelSz) 38 39 // Not read: 40 // - offset_entry_count (4 bytes) 41 // - offset table (offset_entry_count*4 or offset_entry_count*8 if dwarf64 is set) 42 43 return r 44 } 45 46 func (rdr *Dwarf5Reader) Empty() bool { 47 return rdr == nil 48 } 49 50 // Find returns the loclist entry for the specified PC address, inside the 51 // loclist stating at off. Base is the base address of the compile unit and 52 // staticBase is the static base at which the image is loaded. 53 func (rdr *Dwarf5Reader) Find(off int, staticBase, base, pc uint64, debugAddr *godwarf.DebugAddr) (*Entry, error) { 54 it := &loclistsIterator{rdr: rdr, debugAddr: debugAddr, buf: bytes.NewBuffer(rdr.data), base: base, staticBase: staticBase} 55 it.buf.Next(off) 56 57 for it.next() { 58 if !it.onRange { 59 continue 60 } 61 if it.start <= pc && pc < it.end { 62 return &Entry{it.start, it.end, it.instr}, nil 63 } 64 } 65 66 if it.err != nil { 67 return nil, it.err 68 } 69 70 if it.defaultInstr != nil { 71 return &Entry{pc, pc + 1, it.defaultInstr}, nil 72 } 73 74 return nil, nil 75 } 76 77 type loclistsIterator struct { 78 rdr *Dwarf5Reader 79 debugAddr *godwarf.DebugAddr 80 buf *bytes.Buffer 81 staticBase uint64 82 base uint64 // base for offsets in the list 83 84 onRange bool 85 atEnd bool 86 start, end uint64 87 instr []byte 88 defaultInstr []byte 89 err error 90 } 91 92 const ( 93 _DW_LLE_end_of_list uint8 = 0x0 94 _DW_LLE_base_addressx uint8 = 0x1 95 _DW_LLE_startx_endx uint8 = 0x2 96 _DW_LLE_startx_length uint8 = 0x3 97 _DW_LLE_offset_pair uint8 = 0x4 98 _DW_LLE_default_location uint8 = 0x5 99 _DW_LLE_base_address uint8 = 0x6 100 _DW_LLE_start_end uint8 = 0x7 101 _DW_LLE_start_length uint8 = 0x8 102 ) 103 104 func (it *loclistsIterator) next() bool { 105 if it.err != nil || it.atEnd { 106 return false 107 } 108 opcode, err := it.buf.ReadByte() 109 if err != nil { 110 it.err = err 111 return false 112 } 113 switch opcode { 114 case _DW_LLE_end_of_list: 115 it.atEnd = true 116 it.onRange = false 117 return false 118 119 case _DW_LLE_base_addressx: 120 baseIdx, _ := leb128.DecodeUnsigned(it.buf) 121 it.base, it.err = it.debugAddr.Get(baseIdx) 122 it.base += it.staticBase 123 it.onRange = false 124 125 case _DW_LLE_startx_endx: 126 startIdx, _ := leb128.DecodeUnsigned(it.buf) 127 endIdx, _ := leb128.DecodeUnsigned(it.buf) 128 it.readInstr() 129 130 it.start, it.err = it.debugAddr.Get(startIdx) 131 if it.err == nil { 132 it.end, it.err = it.debugAddr.Get(endIdx) 133 } 134 it.onRange = true 135 136 case _DW_LLE_startx_length: 137 startIdx, _ := leb128.DecodeUnsigned(it.buf) 138 length, _ := leb128.DecodeUnsigned(it.buf) 139 it.readInstr() 140 141 it.start, it.err = it.debugAddr.Get(startIdx) 142 it.end = it.start + length 143 it.onRange = true 144 145 case _DW_LLE_offset_pair: 146 off1, _ := leb128.DecodeUnsigned(it.buf) 147 off2, _ := leb128.DecodeUnsigned(it.buf) 148 it.readInstr() 149 150 it.start = it.base + off1 151 it.end = it.base + off2 152 it.onRange = true 153 154 case _DW_LLE_default_location: 155 it.readInstr() 156 it.defaultInstr = it.instr 157 it.onRange = false 158 159 case _DW_LLE_base_address: 160 it.base, it.err = dwarf.ReadUintRaw(it.buf, it.rdr.byteOrder, it.rdr.ptrSz) 161 it.base += it.staticBase 162 it.onRange = false 163 164 case _DW_LLE_start_end: 165 it.start, it.err = dwarf.ReadUintRaw(it.buf, it.rdr.byteOrder, it.rdr.ptrSz) 166 it.end, it.err = dwarf.ReadUintRaw(it.buf, it.rdr.byteOrder, it.rdr.ptrSz) 167 it.readInstr() 168 it.onRange = true 169 170 case _DW_LLE_start_length: 171 it.start, it.err = dwarf.ReadUintRaw(it.buf, it.rdr.byteOrder, it.rdr.ptrSz) 172 length, _ := leb128.DecodeUnsigned(it.buf) 173 it.readInstr() 174 it.end = it.start + length 175 it.onRange = true 176 177 default: 178 it.err = fmt.Errorf("unknown opcode %#x at %#x", opcode, len(it.rdr.data)-it.buf.Len()) 179 it.onRange = false 180 it.atEnd = true 181 return false 182 } 183 184 return true 185 } 186 187 func (it *loclistsIterator) readInstr() { 188 length, _ := leb128.DecodeUnsigned(it.buf) 189 it.instr = it.buf.Next(int(length)) 190 }