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  }