github.com/undoio/delve@v1.9.0/pkg/dwarf/util/util.go (about) 1 package util 2 3 import ( 4 "bytes" 5 "debug/dwarf" 6 "encoding/binary" 7 "fmt" 8 "io" 9 ) 10 11 // ByteReaderWithLen is a io.ByteReader with a Len method. This interface is 12 // satisified by both bytes.Buffer and bytes.Reader. 13 type ByteReaderWithLen interface { 14 io.ByteReader 15 io.Reader 16 Len() int 17 } 18 19 // The Little Endian Base 128 format is defined in the DWARF v4 standard, 20 // section 7.6, page 161 and following. 21 22 // DecodeULEB128 decodes an unsigned Little Endian Base 128 23 // represented number. 24 func DecodeULEB128(buf ByteReaderWithLen) (uint64, uint32) { 25 var ( 26 result uint64 27 shift uint64 28 length uint32 29 ) 30 31 if buf.Len() == 0 { 32 return 0, 0 33 } 34 35 for { 36 b, err := buf.ReadByte() 37 if err != nil { 38 panic("Could not parse ULEB128 value") 39 } 40 length++ 41 42 result |= uint64((uint(b) & 0x7f) << shift) 43 44 // If high order bit is 1. 45 if b&0x80 == 0 { 46 break 47 } 48 49 shift += 7 50 } 51 52 return result, length 53 } 54 55 // DecodeSLEB128 decodes a signed Little Endian Base 128 56 // represented number. 57 func DecodeSLEB128(buf ByteReaderWithLen) (int64, uint32) { 58 var ( 59 b byte 60 err error 61 result int64 62 shift uint64 63 length uint32 64 ) 65 66 if buf.Len() == 0 { 67 return 0, 0 68 } 69 70 for { 71 b, err = buf.ReadByte() 72 if err != nil { 73 panic("Could not parse SLEB128 value") 74 } 75 length++ 76 77 result |= int64((int64(b) & 0x7f) << shift) 78 shift += 7 79 if b&0x80 == 0 { 80 break 81 } 82 } 83 84 if (shift < 8*uint64(length)) && (b&0x40 > 0) { 85 result |= -(1 << shift) 86 } 87 88 return result, length 89 } 90 91 // EncodeULEB128 encodes x to the unsigned Little Endian Base 128 format 92 // into out. 93 func EncodeULEB128(out io.ByteWriter, x uint64) { 94 for { 95 b := byte(x & 0x7f) 96 x = x >> 7 97 if x != 0 { 98 b = b | 0x80 99 } 100 out.WriteByte(b) 101 if x == 0 { 102 break 103 } 104 } 105 } 106 107 // EncodeSLEB128 encodes x to the signed Little Endian Base 128 format 108 // into out. 109 func EncodeSLEB128(out io.ByteWriter, x int64) { 110 for { 111 b := byte(x & 0x7f) 112 x >>= 7 113 114 signb := b & 0x40 115 116 last := false 117 if (x == 0 && signb == 0) || (x == -1 && signb != 0) { 118 last = true 119 } else { 120 b = b | 0x80 121 } 122 out.WriteByte(b) 123 124 if last { 125 break 126 } 127 } 128 } 129 130 // ParseString reads a null-terminated string from data. 131 func ParseString(data *bytes.Buffer) (string, error) { 132 str, err := data.ReadString(0x0) 133 if err != nil { 134 return "", err 135 } 136 137 return str[:len(str)-1], nil 138 } 139 140 // ReadUintRaw reads an integer of ptrSize bytes, with the specified byte order, from reader. 141 func ReadUintRaw(reader io.Reader, order binary.ByteOrder, ptrSize int) (uint64, error) { 142 switch ptrSize { 143 case 2: 144 var n uint16 145 if err := binary.Read(reader, order, &n); err != nil { 146 return 0, err 147 } 148 return uint64(n), nil 149 case 4: 150 var n uint32 151 if err := binary.Read(reader, order, &n); err != nil { 152 return 0, err 153 } 154 return uint64(n), nil 155 case 8: 156 var n uint64 157 if err := binary.Read(reader, order, &n); err != nil { 158 return 0, err 159 } 160 return n, nil 161 } 162 return 0, fmt.Errorf("pointer size %d not supported", ptrSize) 163 } 164 165 // WriteUint writes an integer of ptrSize bytes to writer, in the specified byte order. 166 func WriteUint(writer io.Writer, order binary.ByteOrder, ptrSize int, data uint64) error { 167 switch ptrSize { 168 case 4: 169 return binary.Write(writer, order, uint32(data)) 170 case 8: 171 return binary.Write(writer, order, data) 172 } 173 return fmt.Errorf("pointer size %d not supported", ptrSize) 174 } 175 176 // ReadDwarfLengthVersion reads a DWARF length field followed by a version field 177 func ReadDwarfLengthVersion(data []byte) (length uint64, dwarf64 bool, version uint8, byteOrder binary.ByteOrder) { 178 if len(data) < 4 { 179 return 0, false, 0, binary.LittleEndian 180 } 181 182 lengthfield := binary.LittleEndian.Uint32(data) 183 voff := 4 184 if lengthfield == ^uint32(0) { 185 dwarf64 = true 186 voff = 12 187 } 188 189 if voff+1 >= len(data) { 190 return 0, false, 0, binary.LittleEndian 191 } 192 193 byteOrder = binary.LittleEndian 194 x, y := data[voff], data[voff+1] 195 switch { 196 default: 197 fallthrough 198 case x == 0 && y == 0: 199 version = 0 200 byteOrder = binary.LittleEndian 201 case x == 0: 202 version = y 203 byteOrder = binary.BigEndian 204 case y == 0: 205 version = x 206 byteOrder = binary.LittleEndian 207 } 208 209 if dwarf64 { 210 length = byteOrder.Uint64(data[4:]) 211 } else { 212 length = uint64(byteOrder.Uint32(data)) 213 } 214 215 return length, dwarf64, version, byteOrder 216 } 217 218 const ( 219 _DW_UT_compile = 0x1 + iota 220 _DW_UT_type 221 _DW_UT_partial 222 _DW_UT_skeleton 223 _DW_UT_split_compile 224 _DW_UT_split_type 225 ) 226 227 // ReadUnitVersions reads the DWARF version of each unit in a debug_info section and returns them as a map. 228 func ReadUnitVersions(data []byte) map[dwarf.Offset]uint8 { 229 r := make(map[dwarf.Offset]uint8) 230 off := dwarf.Offset(0) 231 for len(data) > 0 { 232 length, dwarf64, version, _ := ReadDwarfLengthVersion(data) 233 234 data = data[4:] 235 off += 4 236 secoffsz := 4 237 if dwarf64 { 238 off += 8 239 secoffsz = 8 240 data = data[8:] 241 } 242 243 var headerSize int 244 245 switch version { 246 case 2, 3, 4: 247 headerSize = 3 + secoffsz 248 default: // 5 and later? 249 unitType := data[2] 250 251 switch unitType { 252 case _DW_UT_compile, _DW_UT_partial: 253 headerSize = 5 + secoffsz 254 255 case _DW_UT_skeleton, _DW_UT_split_compile: 256 headerSize = 4 + secoffsz + 8 257 258 case _DW_UT_type, _DW_UT_split_type: 259 headerSize = 4 + secoffsz + 8 + secoffsz 260 } 261 } 262 263 r[off+dwarf.Offset(headerSize)] = version 264 265 data = data[length:] // skip contents 266 off += dwarf.Offset(length) 267 } 268 return r 269 }