delve/pkg/dwarf/loclist/dwarf5_loclist.go
Alessandro Arzilli 328cf87808
dwarf/loclist,godwarf,proc: support DWARF version 5 loclists and debug_addr (#2097)
Parses and uses the new debug_loclists section added to DWARFv5.
2020-08-17 17:19:46 -07:00

194 lines
4.4 KiB
Go

package loclist
import (
"bytes"
"encoding/binary"
"fmt"
"github.com/go-delve/delve/pkg/dwarf/godwarf"
"github.com/go-delve/delve/pkg/dwarf/util"
)
// Dwarf5Reader parses and presents DWARF loclist information for DWARF version 5 and later.
// See DWARFv5 section 7.29 page 243 and following.
type Dwarf5Reader struct {
byteOrder binary.ByteOrder
ptrSz int
data []byte
}
func NewDwarf5Reader(data []byte) *Dwarf5Reader {
if len(data) == 0 {
return nil
}
r := &Dwarf5Reader{data: data}
_, dwarf64, _, byteOrder := util.ReadDwarfLengthVersion(data)
r.byteOrder = byteOrder
data = data[6:]
if dwarf64 {
data = data[8:]
}
addrSz := data[0]
segSelSz := data[1]
r.ptrSz = int(addrSz + segSelSz)
// Not read:
// - offset_entry_count (4 bytes)
// - offset table (offset_entry_count*4 or offset_entry_count*8 if dwarf64 is set)
return r
}
func (rdr *Dwarf5Reader) Empty() bool {
return rdr == nil
}
// Find returns the loclist entry for the specified PC address, inside the
// loclist stating at off. Base is the base address of the compile unit and
// staticBase is the static base at which the image is loaded.
func (rdr *Dwarf5Reader) Find(off int, staticBase, base, pc uint64, debugAddr *godwarf.DebugAddr) (*Entry, error) {
it := &loclistsIterator{rdr: rdr, debugAddr: debugAddr, buf: bytes.NewBuffer(rdr.data), base: base, staticBase: staticBase}
it.buf.Next(off)
for it.next() {
if !it.onRange {
continue
}
if it.start <= pc && pc < it.end {
return &Entry{it.start, it.end, it.instr}, nil
}
}
if it.err != nil {
return nil, it.err
}
if it.defaultInstr != nil {
return &Entry{pc, pc + 1, it.defaultInstr}, nil
}
return nil, nil
}
type loclistsIterator struct {
rdr *Dwarf5Reader
debugAddr *godwarf.DebugAddr
buf *bytes.Buffer
staticBase uint64
base uint64 // base for offsets in the list
onRange bool
atEnd bool
start, end uint64
instr []byte
defaultInstr []byte
err error
}
const (
_DW_LLE_end_of_list uint8 = 0x0
_DW_LLE_base_addressx uint8 = 0x1
_DW_LLE_startx_endx uint8 = 0x2
_DW_LLE_startx_length uint8 = 0x3
_DW_LLE_offset_pair uint8 = 0x4
_DW_LLE_default_location uint8 = 0x5
_DW_LLE_base_address uint8 = 0x6
_DW_LLE_start_end uint8 = 0x7
_DW_LLE_start_length uint8 = 0x8
)
func (it *loclistsIterator) next() bool {
if it.err != nil || it.atEnd {
return false
}
opcode, err := it.buf.ReadByte()
if err != nil {
it.err = err
return false
}
switch opcode {
case _DW_LLE_end_of_list:
it.atEnd = true
it.onRange = false
return false
case _DW_LLE_base_addressx:
baseIdx, _ := util.DecodeULEB128(it.buf)
if err != nil {
it.err = err
return false
}
it.base, it.err = it.debugAddr.Get(baseIdx)
it.base += it.staticBase
it.onRange = false
case _DW_LLE_startx_endx:
startIdx, _ := util.DecodeULEB128(it.buf)
endIdx, _ := util.DecodeULEB128(it.buf)
it.readInstr()
it.start, it.err = it.debugAddr.Get(startIdx)
if it.err == nil {
it.end, it.err = it.debugAddr.Get(endIdx)
}
it.onRange = true
case _DW_LLE_startx_length:
startIdx, _ := util.DecodeULEB128(it.buf)
length, _ := util.DecodeULEB128(it.buf)
it.readInstr()
it.start, it.err = it.debugAddr.Get(startIdx)
it.end = it.start + length
it.onRange = true
case _DW_LLE_offset_pair:
off1, _ := util.DecodeULEB128(it.buf)
off2, _ := util.DecodeULEB128(it.buf)
it.readInstr()
it.start = it.base + off1
it.end = it.base + off2
it.onRange = true
case _DW_LLE_default_location:
it.readInstr()
it.defaultInstr = it.instr
it.onRange = false
case _DW_LLE_base_address:
it.base, it.err = util.ReadUintRaw(it.buf, it.rdr.byteOrder, it.rdr.ptrSz)
it.base += it.staticBase
it.onRange = false
case _DW_LLE_start_end:
it.start, it.err = util.ReadUintRaw(it.buf, it.rdr.byteOrder, it.rdr.ptrSz)
it.end, it.err = util.ReadUintRaw(it.buf, it.rdr.byteOrder, it.rdr.ptrSz)
it.readInstr()
it.onRange = true
case _DW_LLE_start_length:
it.start, it.err = util.ReadUintRaw(it.buf, it.rdr.byteOrder, it.rdr.ptrSz)
length, _ := util.DecodeULEB128(it.buf)
it.readInstr()
it.end = it.start + length
it.onRange = true
default:
it.err = fmt.Errorf("unknown opcode %#x at %#x", opcode, len(it.rdr.data)-it.buf.Len())
it.onRange = false
it.atEnd = true
return false
}
return true
}
func (it *loclistsIterator) readInstr() {
length, _ := util.DecodeULEB128(it.buf)
it.instr = it.buf.Next(int(length))
}