github.com/cnboonhan/delve@v0.0.0-20230908061759-363f2388c2fb/pkg/dwarf/loclist/dwarf5_loclist.go (about) 1 package loclist 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "fmt" 7 8 "github.com/go-delve/delve/pkg/dwarf" 9 "github.com/go-delve/delve/pkg/dwarf/godwarf" 10 "github.com/go-delve/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 if err != nil { 122 it.err = err 123 return false 124 } 125 it.base, it.err = it.debugAddr.Get(baseIdx) 126 it.base += it.staticBase 127 it.onRange = false 128 129 case _DW_LLE_startx_endx: 130 startIdx, _ := leb128.DecodeUnsigned(it.buf) 131 endIdx, _ := leb128.DecodeUnsigned(it.buf) 132 it.readInstr() 133 134 it.start, it.err = it.debugAddr.Get(startIdx) 135 if it.err == nil { 136 it.end, it.err = it.debugAddr.Get(endIdx) 137 } 138 it.onRange = true 139 140 case _DW_LLE_startx_length: 141 startIdx, _ := leb128.DecodeUnsigned(it.buf) 142 length, _ := leb128.DecodeUnsigned(it.buf) 143 it.readInstr() 144 145 it.start, it.err = it.debugAddr.Get(startIdx) 146 it.end = it.start + length 147 it.onRange = true 148 149 case _DW_LLE_offset_pair: 150 off1, _ := leb128.DecodeUnsigned(it.buf) 151 off2, _ := leb128.DecodeUnsigned(it.buf) 152 it.readInstr() 153 154 it.start = it.base + off1 155 it.end = it.base + off2 156 it.onRange = true 157 158 case _DW_LLE_default_location: 159 it.readInstr() 160 it.defaultInstr = it.instr 161 it.onRange = false 162 163 case _DW_LLE_base_address: 164 it.base, it.err = dwarf.ReadUintRaw(it.buf, it.rdr.byteOrder, it.rdr.ptrSz) 165 it.base += it.staticBase 166 it.onRange = false 167 168 case _DW_LLE_start_end: 169 it.start, it.err = dwarf.ReadUintRaw(it.buf, it.rdr.byteOrder, it.rdr.ptrSz) 170 it.end, it.err = dwarf.ReadUintRaw(it.buf, it.rdr.byteOrder, it.rdr.ptrSz) 171 it.readInstr() 172 it.onRange = true 173 174 case _DW_LLE_start_length: 175 it.start, it.err = dwarf.ReadUintRaw(it.buf, it.rdr.byteOrder, it.rdr.ptrSz) 176 length, _ := leb128.DecodeUnsigned(it.buf) 177 it.readInstr() 178 it.end = it.start + length 179 it.onRange = true 180 181 default: 182 it.err = fmt.Errorf("unknown opcode %#x at %#x", opcode, len(it.rdr.data)-it.buf.Len()) 183 it.onRange = false 184 it.atEnd = true 185 return false 186 } 187 188 return true 189 } 190 191 func (it *loclistsIterator) readInstr() { 192 length, _ := leb128.DecodeUnsigned(it.buf) 193 it.instr = it.buf.Next(int(length)) 194 }