delve/pkg/dwarf/line/parse_util.go
Derek Parker 544a803a80
proc,dwarf: Improve DWARF v5 support (#2544)
While Go still mostly uses DWARF v4, newer versions of GCC will emit
DWARF v5 by default. This patch improves support for DWARF v5 by parsing
the .debug_line_str section and using that during file:line lookups.

This patch only includes support for files, not directories.

Co-authored-by: Derek Parker <deparker@redhat.com>
2021-06-22 13:37:46 +02:00

193 lines
3.9 KiB
Go

package line
import (
"bytes"
"encoding/binary"
"errors"
"github.com/go-delve/delve/pkg/dwarf/util"
)
const (
_DW_FORM_block = 0x09
_DW_FORM_block1 = 0x0a
_DW_FORM_block2 = 0x03
_DW_FORM_block4 = 0x04
_DW_FORM_data1 = 0x0b
_DW_FORM_data2 = 0x05
_DW_FORM_data4 = 0x06
_DW_FORM_data8 = 0x07
_DW_FORM_data16 = 0x1e
_DW_FORM_flag = 0x0c
_DW_FORM_line_strp = 0x1f
_DW_FORM_sdata = 0x0d
_DW_FORM_sec_offset = 0x17
_DW_FORM_string = 0x08
_DW_FORM_strp = 0x0e
_DW_FORM_strx = 0x1a
_DW_FORM_strx1 = 0x25
_DW_FORM_strx2 = 0x26
_DW_FORM_strx3 = 0x27
_DW_FORM_strx4 = 0x28
_DW_FORM_udata = 0x0f
)
const (
_DW_LNCT_path = 0x1 + iota
_DW_LNCT_directory_index
_DW_LNCT_timestamp
_DW_LNCT_size
_DW_LNCT_MD5
)
var ErrBufferUnderflow = errors.New("buffer underflow")
type formReader struct {
logf func(string, ...interface{})
contentTypes []uint64
formCodes []uint64
contentType uint64
formCode uint64
block []byte
u64 uint64
i64 int64
str string
err error
nexti int
}
func readEntryFormat(buf *bytes.Buffer, logf func(string, ...interface{})) *formReader {
if buf.Len() < 1 {
return nil
}
count := buf.Next(1)[0]
r := &formReader{
logf: logf,
contentTypes: make([]uint64, count),
formCodes: make([]uint64, count),
}
for i := range r.contentTypes {
r.contentTypes[i], _ = util.DecodeULEB128(buf)
r.formCodes[i], _ = util.DecodeULEB128(buf)
}
return r
}
func (rdr *formReader) reset() {
rdr.err = nil
rdr.nexti = 0
}
func (rdr *formReader) next(buf *bytes.Buffer) bool {
if rdr.err != nil {
return false
}
if rdr.nexti >= len(rdr.contentTypes) {
return false
}
rdr.contentType = rdr.contentTypes[rdr.nexti]
rdr.formCode = rdr.formCodes[rdr.nexti]
switch rdr.formCode {
case _DW_FORM_block:
n, _ := util.DecodeULEB128(buf)
rdr.readBlock(buf, n)
case _DW_FORM_block1:
if buf.Len() < 1 {
rdr.err = ErrBufferUnderflow
return false
}
rdr.readBlock(buf, uint64(buf.Next(1)[0]))
case _DW_FORM_block2:
if buf.Len() < 2 {
rdr.err = ErrBufferUnderflow
return false
}
rdr.readBlock(buf, uint64(binary.LittleEndian.Uint16(buf.Next(2))))
case _DW_FORM_block4:
if buf.Len() < 4 {
rdr.err = ErrBufferUnderflow
return false
}
rdr.readBlock(buf, uint64(binary.LittleEndian.Uint32(buf.Next(4))))
case _DW_FORM_data1, _DW_FORM_flag, _DW_FORM_strx1:
if buf.Len() < 1 {
rdr.err = ErrBufferUnderflow
return false
}
rdr.u64 = uint64(buf.Next(1)[0])
case _DW_FORM_data2, _DW_FORM_strx2:
if buf.Len() < 2 {
rdr.err = ErrBufferUnderflow
return false
}
rdr.u64 = uint64(binary.LittleEndian.Uint16(buf.Next(2)))
case _DW_FORM_data4, _DW_FORM_line_strp, _DW_FORM_sec_offset, _DW_FORM_strp, _DW_FORM_strx4:
if buf.Len() < 4 {
rdr.err = ErrBufferUnderflow
return false
}
rdr.u64 = uint64(binary.LittleEndian.Uint32(buf.Next(4)))
case _DW_FORM_data8:
if buf.Len() < 8 {
rdr.err = ErrBufferUnderflow
return false
}
rdr.u64 = binary.LittleEndian.Uint64(buf.Next(8))
case _DW_FORM_data16:
rdr.readBlock(buf, 16)
case _DW_FORM_sdata:
rdr.i64, _ = util.DecodeSLEB128(buf)
case _DW_FORM_udata, _DW_FORM_strx:
rdr.u64, _ = util.DecodeULEB128(buf)
case _DW_FORM_string:
rdr.str, _ = util.ParseString(buf)
case _DW_FORM_strx3:
if buf.Len() < 3 {
rdr.err = ErrBufferUnderflow
return false
}
rdr.u64 = uint64(binary.LittleEndian.Uint32(append(buf.Next(3), 0x0)))
case ^uint64(0):
// do nothing
default:
if rdr.logf != nil {
rdr.logf("unknown form code %#x", rdr.formCode)
}
rdr.formCodes[rdr.nexti] = ^uint64(0) // only print error once
}
rdr.nexti++
return true
}
func (rdr *formReader) readBlock(buf *bytes.Buffer, n uint64) {
if uint64(buf.Len()) < n {
rdr.err = ErrBufferUnderflow
return
}
if cap(rdr.block) < int(n) {
rdr.block = make([]byte, 0, n)
}
rdr.block = rdr.block[:n]
buf.Read(rdr.block)
}