github.com/undoio/delve@v1.9.0/pkg/dwarf/dwarfbuilder/info.go (about) 1 package dwarfbuilder 2 3 import ( 4 "bytes" 5 "debug/dwarf" 6 "encoding/binary" 7 8 "github.com/undoio/delve/pkg/dwarf/godwarf" 9 "github.com/undoio/delve/pkg/dwarf/util" 10 ) 11 12 // Form represents a DWARF form kind (see Figure 20, page 160 and following, 13 // DWARF v4) 14 type Form uint16 15 16 const ( 17 DW_FORM_addr Form = 0x01 // address 18 DW_FORM_block2 Form = 0x03 // block 19 DW_FORM_block4 Form = 0x04 // block 20 DW_FORM_data2 Form = 0x05 // constant 21 DW_FORM_data4 Form = 0x06 // constant 22 DW_FORM_data8 Form = 0x07 // constant 23 DW_FORM_string Form = 0x08 // string 24 DW_FORM_block Form = 0x09 // block 25 DW_FORM_block1 Form = 0x0a // block 26 DW_FORM_data1 Form = 0x0b // constant 27 DW_FORM_flag Form = 0x0c // flag 28 DW_FORM_sdata Form = 0x0d // constant 29 DW_FORM_strp Form = 0x0e // string 30 DW_FORM_udata Form = 0x0f // constant 31 DW_FORM_ref_addr Form = 0x10 // reference 32 DW_FORM_ref1 Form = 0x11 // reference 33 DW_FORM_ref2 Form = 0x12 // reference 34 DW_FORM_ref4 Form = 0x13 // reference 35 DW_FORM_ref8 Form = 0x14 // reference 36 DW_FORM_ref_udata Form = 0x15 // reference 37 DW_FORM_indirect Form = 0x16 // (see Section 7.5.3) 38 DW_FORM_sec_offset Form = 0x17 // lineptr, loclistptr, macptr, rangelistptr 39 DW_FORM_exprloc Form = 0x18 // exprloc 40 DW_FORM_flag_present Form = 0x19 // flag 41 DW_FORM_ref_sig8 Form = 0x20 // reference 42 ) 43 44 // Encoding represents a DWARF base type encoding (see section 7.8, page 168 45 // and following, DWARF v4). 46 type Encoding uint16 47 48 const ( 49 DW_ATE_address Encoding = 0x01 50 DW_ATE_boolean Encoding = 0x02 51 DW_ATE_complex_float Encoding = 0x03 52 DW_ATE_float Encoding = 0x04 53 DW_ATE_signed Encoding = 0x05 54 DW_ATE_signed_char Encoding = 0x06 55 DW_ATE_unsigned Encoding = 0x07 56 DW_ATE_unsigned_char Encoding = 0x08 57 DW_ATE_imaginary_float Encoding = 0x09 58 DW_ATE_packed_decimal Encoding = 0x0a 59 DW_ATE_numeric_string Encoding = 0x0b 60 DW_ATE_edited Encoding = 0x0c 61 DW_ATE_signed_fixed Encoding = 0x0d 62 DW_ATE_unsigned_fixed Encoding = 0x0e 63 DW_ATE_decimal_float Encoding = 0x0f 64 DW_ATE_UTF Encoding = 0x10 65 DW_ATE_lo_user Encoding = 0x80 66 DW_ATE_hi_user Encoding = 0xff 67 ) 68 69 // Address represents a machine address. 70 type Address uint64 71 72 type tagDescr struct { 73 tag dwarf.Tag 74 75 attr []dwarf.Attr 76 form []Form 77 children bool 78 } 79 80 type tagState struct { 81 off dwarf.Offset 82 tagDescr 83 } 84 85 // TagOpen starts a new DIE, call TagClose after adding all attributes and 86 // children elements. 87 func (b *Builder) TagOpen(tag dwarf.Tag, name string) dwarf.Offset { 88 if len(b.tagStack) > 0 { 89 b.tagStack[len(b.tagStack)-1].children = true 90 } 91 ts := &tagState{off: dwarf.Offset(b.info.Len())} 92 ts.tag = tag 93 b.info.WriteByte(0) 94 b.tagStack = append(b.tagStack, ts) 95 if name != "" { 96 b.Attr(dwarf.AttrName, name) 97 } 98 99 return ts.off 100 } 101 102 // SetHasChildren sets the current DIE as having children (even if none are added). 103 func (b *Builder) SetHasChildren() { 104 if len(b.tagStack) <= 0 { 105 panic("NoChildren with no open tags") 106 } 107 b.tagStack[len(b.tagStack)-1].children = true 108 } 109 110 // TagClose closes the current DIE. 111 func (b *Builder) TagClose() { 112 if len(b.tagStack) <= 0 { 113 panic("TagClose with no open tags") 114 } 115 tag := b.tagStack[len(b.tagStack)-1] 116 abbrev := b.abbrevFor(tag.tagDescr) 117 b.info.Bytes()[tag.off] = abbrev 118 if tag.children { 119 b.info.WriteByte(0) 120 } 121 b.tagStack = b.tagStack[:len(b.tagStack)-1] 122 } 123 124 // Attr adds an attribute to the current DIE. 125 func (b *Builder) Attr(attr dwarf.Attr, val interface{}) dwarf.Offset { 126 if len(b.tagStack) == 0 { 127 panic("Attr with no open tags") 128 } 129 off := dwarf.Offset(b.info.Len()) 130 tag := b.tagStack[len(b.tagStack)-1] 131 if tag.children { 132 panic("Can't add attributes after adding children") 133 } 134 135 tag.attr = append(tag.attr, attr) 136 137 switch x := val.(type) { 138 case string: 139 tag.form = append(tag.form, DW_FORM_string) 140 b.info.Write([]byte(x)) 141 b.info.WriteByte(0) 142 case uint8: 143 tag.form = append(tag.form, DW_FORM_data1) 144 binary.Write(&b.info, binary.LittleEndian, x) 145 case uint16: 146 tag.form = append(tag.form, DW_FORM_data2) 147 binary.Write(&b.info, binary.LittleEndian, x) 148 case uint64: 149 tag.form = append(tag.form, DW_FORM_data8) 150 binary.Write(&b.info, binary.LittleEndian, x) 151 case Address: 152 tag.form = append(tag.form, DW_FORM_addr) 153 binary.Write(&b.info, binary.LittleEndian, x) 154 case dwarf.Offset: 155 tag.form = append(tag.form, DW_FORM_ref_addr) 156 binary.Write(&b.info, binary.LittleEndian, x) 157 case []byte: 158 tag.form = append(tag.form, DW_FORM_block4) 159 binary.Write(&b.info, binary.LittleEndian, uint32(len(x))) 160 b.info.Write(x) 161 case []LocEntry: 162 tag.form = append(tag.form, DW_FORM_sec_offset) 163 binary.Write(&b.info, binary.LittleEndian, uint32(b.loc.Len())) 164 165 // base address 166 binary.Write(&b.loc, binary.LittleEndian, ^uint64(0)) 167 binary.Write(&b.loc, binary.LittleEndian, uint64(0)) 168 169 for _, locentry := range x { 170 binary.Write(&b.loc, binary.LittleEndian, uint64(locentry.Lowpc)) 171 binary.Write(&b.loc, binary.LittleEndian, uint64(locentry.Highpc)) 172 binary.Write(&b.loc, binary.LittleEndian, uint16(len(locentry.Loc))) 173 b.loc.Write(locentry.Loc) 174 } 175 176 // end of loclist 177 binary.Write(&b.loc, binary.LittleEndian, uint64(0)) 178 binary.Write(&b.loc, binary.LittleEndian, uint64(0)) 179 default: 180 panic("unknown value type") 181 } 182 183 return off 184 } 185 186 // PatchOffset writes the offset 'patch' at offset patchedOffset. 187 func (b *Builder) PatchOffset(patchedOffset, patch dwarf.Offset) { 188 infoBytes := b.info.Bytes() 189 buf := new(bytes.Buffer) 190 binary.Write(buf, binary.LittleEndian, patch) 191 copy(infoBytes[patchedOffset:], buf.Bytes()) 192 } 193 194 func sameTagDescr(a, b tagDescr) bool { 195 if a.tag != b.tag { 196 return false 197 } 198 if len(a.attr) != len(b.attr) { 199 return false 200 } 201 if a.children != b.children { 202 return false 203 } 204 for i := range a.attr { 205 if a.attr[i] != b.attr[i] { 206 return false 207 } 208 if a.form[i] != b.form[i] { 209 return false 210 } 211 } 212 return true 213 } 214 215 // abbrevFor returns an abbrev for the given entry description. If no abbrev 216 // for tag already exist a new one is created. 217 func (b *Builder) abbrevFor(tag tagDescr) byte { 218 for abbrev, descr := range b.abbrevs { 219 if sameTagDescr(descr, tag) { 220 return byte(abbrev + 1) 221 } 222 } 223 224 b.abbrevs = append(b.abbrevs, tag) 225 return byte(len(b.abbrevs)) 226 } 227 228 func (b *Builder) makeAbbrevTable() []byte { 229 var abbrev bytes.Buffer 230 231 for i := range b.abbrevs { 232 util.EncodeULEB128(&abbrev, uint64(i+1)) 233 util.EncodeULEB128(&abbrev, uint64(b.abbrevs[i].tag)) 234 if b.abbrevs[i].children { 235 abbrev.WriteByte(0x01) 236 } else { 237 abbrev.WriteByte(0x00) 238 } 239 for j := range b.abbrevs[i].attr { 240 util.EncodeULEB128(&abbrev, uint64(b.abbrevs[i].attr[j])) 241 util.EncodeULEB128(&abbrev, uint64(b.abbrevs[i].form[j])) 242 } 243 util.EncodeULEB128(&abbrev, 0) 244 util.EncodeULEB128(&abbrev, 0) 245 } 246 247 return abbrev.Bytes() 248 } 249 250 func (b *Builder) AddCompileUnit(name string, lowPC uint64) dwarf.Offset { 251 r := b.TagOpen(dwarf.TagCompileUnit, name) 252 b.Attr(dwarf.AttrLowpc, lowPC) 253 return r 254 } 255 256 // AddSubprogram adds a subprogram declaration to debug_info, must call 257 // TagClose after adding all local variables and parameters. 258 // Will write an abbrev corresponding to a DW_TAG_subprogram, followed by a 259 // DW_AT_lowpc and a DW_AT_highpc. 260 func (b *Builder) AddSubprogram(fnname string, lowpc, highpc uint64) dwarf.Offset { 261 r := b.TagOpen(dwarf.TagSubprogram, fnname) 262 b.Attr(dwarf.AttrLowpc, Address(lowpc)) 263 b.Attr(dwarf.AttrHighpc, Address(highpc)) 264 return r 265 } 266 267 // AddVariable adds a new variable entry to debug_info. 268 // Will write a DW_TAG_variable, followed by a DW_AT_type and a 269 // DW_AT_location. 270 func (b *Builder) AddVariable(varname string, typ dwarf.Offset, loc interface{}) dwarf.Offset { 271 r := b.TagOpen(dwarf.TagVariable, varname) 272 b.Attr(dwarf.AttrType, typ) 273 b.Attr(dwarf.AttrLocation, loc) 274 b.TagClose() 275 return r 276 } 277 278 // AddBaseType adds a new base type entry to debug_info. 279 // Will write a DW_TAG_base_type, followed by a DW_AT_encoding and a 280 // DW_AT_byte_size. 281 func (b *Builder) AddBaseType(typename string, encoding Encoding, byteSz uint16) dwarf.Offset { 282 r := b.TagOpen(dwarf.TagBaseType, typename) 283 b.Attr(dwarf.AttrEncoding, uint16(encoding)) 284 b.Attr(dwarf.AttrByteSize, byteSz) 285 b.TagClose() 286 return r 287 } 288 289 // AddStructType adds a new structure type to debug_info. Call TagClose to 290 // finish adding fields. 291 // Will write a DW_TAG_struct_type, followed by a DW_AT_byte_size. 292 func (b *Builder) AddStructType(typename string, byteSz uint16) dwarf.Offset { 293 r := b.TagOpen(dwarf.TagStructType, typename) 294 b.Attr(dwarf.AttrByteSize, byteSz) 295 return r 296 } 297 298 // AddMember adds a new member entry to debug_info. 299 // Writes a DW_TAG_member followed by DW_AT_type and DW_AT_data_member_loc. 300 func (b *Builder) AddMember(fieldname string, typ dwarf.Offset, memberLoc []byte) dwarf.Offset { 301 r := b.TagOpen(dwarf.TagMember, fieldname) 302 b.Attr(dwarf.AttrType, typ) 303 b.Attr(dwarf.AttrDataMemberLoc, memberLoc) 304 b.TagClose() 305 return r 306 } 307 308 // AddPointerType adds a new pointer type to debug_info. 309 func (b *Builder) AddPointerType(typename string, typ dwarf.Offset) dwarf.Offset { 310 r := b.TagOpen(dwarf.TagPointerType, typename) 311 b.Attr(dwarf.AttrType, typ) 312 b.Attr(godwarf.AttrGoKind, uint8(22)) 313 b.TagClose() 314 return r 315 }