194 lines
4.4 KiB
Go
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))
|
||
|
}
|