github.com/cnboonhan/delve@v0.0.0-20230908061759-363f2388c2fb/pkg/dwarf/parseutil.go (about) 1 package dwarf 2 3 import ( 4 "bytes" 5 "debug/dwarf" 6 "encoding/binary" 7 "fmt" 8 "io" 9 ) 10 11 // ReadString reads a null-terminated string from data. 12 func ReadString(data *bytes.Buffer) (string, error) { 13 str, err := data.ReadString(0x0) 14 if err != nil { 15 return "", err 16 } 17 18 return str[:len(str)-1], nil 19 } 20 21 // ReadUintRaw reads an integer of ptrSize bytes, with the specified byte order, from reader. 22 func ReadUintRaw(reader io.Reader, order binary.ByteOrder, ptrSize int) (uint64, error) { 23 switch ptrSize { 24 case 2: 25 var n uint16 26 if err := binary.Read(reader, order, &n); err != nil { 27 return 0, err 28 } 29 return uint64(n), nil 30 case 4: 31 var n uint32 32 if err := binary.Read(reader, order, &n); err != nil { 33 return 0, err 34 } 35 return uint64(n), nil 36 case 8: 37 var n uint64 38 if err := binary.Read(reader, order, &n); err != nil { 39 return 0, err 40 } 41 return n, nil 42 } 43 return 0, fmt.Errorf("pointer size %d not supported", ptrSize) 44 } 45 46 // WriteUint writes an integer of ptrSize bytes to writer, in the specified byte order. 47 func WriteUint(writer io.Writer, order binary.ByteOrder, ptrSize int, data uint64) error { 48 switch ptrSize { 49 case 4: 50 return binary.Write(writer, order, uint32(data)) 51 case 8: 52 return binary.Write(writer, order, data) 53 } 54 return fmt.Errorf("pointer size %d not supported", ptrSize) 55 } 56 57 // ReadDwarfLengthVersion reads a DWARF length field followed by a version field 58 func ReadDwarfLengthVersion(data []byte) (length uint64, dwarf64 bool, version uint8, byteOrder binary.ByteOrder) { 59 if len(data) < 4 { 60 return 0, false, 0, binary.LittleEndian 61 } 62 63 lengthfield := binary.LittleEndian.Uint32(data) 64 voff := 4 65 if lengthfield == ^uint32(0) { 66 dwarf64 = true 67 voff = 12 68 } 69 70 if voff+1 >= len(data) { 71 return 0, false, 0, binary.LittleEndian 72 } 73 74 byteOrder = binary.LittleEndian 75 x, y := data[voff], data[voff+1] 76 switch { 77 default: 78 fallthrough 79 case x == 0 && y == 0: 80 version = 0 81 byteOrder = binary.LittleEndian 82 case x == 0: 83 version = y 84 byteOrder = binary.BigEndian 85 case y == 0: 86 version = x 87 byteOrder = binary.LittleEndian 88 } 89 90 if dwarf64 { 91 length = byteOrder.Uint64(data[4:]) 92 } else { 93 length = uint64(byteOrder.Uint32(data)) 94 } 95 96 return length, dwarf64, version, byteOrder 97 } 98 99 const ( 100 _DW_UT_compile = 0x1 + iota 101 _DW_UT_type 102 _DW_UT_partial 103 _DW_UT_skeleton 104 _DW_UT_split_compile 105 _DW_UT_split_type 106 ) 107 108 // ReadUnitVersions reads the DWARF version of each unit in a debug_info section and returns them as a map. 109 func ReadUnitVersions(data []byte) map[dwarf.Offset]uint8 { 110 r := make(map[dwarf.Offset]uint8) 111 off := dwarf.Offset(0) 112 for len(data) > 0 { 113 length, dwarf64, version, _ := ReadDwarfLengthVersion(data) 114 115 data = data[4:] 116 off += 4 117 secoffsz := 4 118 if dwarf64 { 119 off += 8 120 secoffsz = 8 121 data = data[8:] 122 } 123 124 var headerSize int 125 126 switch version { 127 case 2, 3, 4: 128 headerSize = 3 + secoffsz 129 default: // 5 and later? 130 unitType := data[2] 131 132 switch unitType { 133 case _DW_UT_compile, _DW_UT_partial: 134 headerSize = 5 + secoffsz 135 136 case _DW_UT_skeleton, _DW_UT_split_compile: 137 headerSize = 4 + secoffsz + 8 138 139 case _DW_UT_type, _DW_UT_split_type: 140 headerSize = 4 + secoffsz + 8 + secoffsz 141 } 142 } 143 144 r[off+dwarf.Offset(headerSize)] = version 145 146 data = data[length:] // skip contents 147 off += dwarf.Offset(length) 148 } 149 return r 150 }