github.com/neilgarb/delve@v1.9.2-nobreaks/pkg/dwarf/loclist/dwarf5_loclist.go (about)

     1  package loclist
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"fmt"
     7  
     8  	"github.com/go-delve/delve/pkg/dwarf/godwarf"
     9  	"github.com/go-delve/delve/pkg/dwarf/util"
    10  )
    11  
    12  // Dwarf5Reader parses and presents DWARF loclist information for DWARF version 5 and later.
    13  // See DWARFv5 section 7.29 page 243 and following.
    14  type Dwarf5Reader struct {
    15  	byteOrder binary.ByteOrder
    16  	ptrSz     int
    17  	data      []byte
    18  }
    19  
    20  func NewDwarf5Reader(data []byte) *Dwarf5Reader {
    21  	if len(data) == 0 {
    22  		return nil
    23  	}
    24  	r := &Dwarf5Reader{data: data}
    25  
    26  	_, dwarf64, _, byteOrder := util.ReadDwarfLengthVersion(data)
    27  	r.byteOrder = byteOrder
    28  
    29  	data = data[6:]
    30  	if dwarf64 {
    31  		data = data[8:]
    32  	}
    33  
    34  	addrSz := data[0]
    35  	segSelSz := data[1]
    36  	r.ptrSz = int(addrSz + segSelSz)
    37  
    38  	// Not read:
    39  	// - offset_entry_count (4 bytes)
    40  	// - offset table (offset_entry_count*4 or offset_entry_count*8 if dwarf64 is set)
    41  
    42  	return r
    43  }
    44  
    45  func (rdr *Dwarf5Reader) Empty() bool {
    46  	return rdr == nil
    47  }
    48  
    49  // Find returns the loclist entry for the specified PC address, inside the
    50  // loclist stating at off. Base is the base address of the compile unit and
    51  // staticBase is the static base at which the image is loaded.
    52  func (rdr *Dwarf5Reader) Find(off int, staticBase, base, pc uint64, debugAddr *godwarf.DebugAddr) (*Entry, error) {
    53  	it := &loclistsIterator{rdr: rdr, debugAddr: debugAddr, buf: bytes.NewBuffer(rdr.data), base: base, staticBase: staticBase}
    54  	it.buf.Next(off)
    55  
    56  	for it.next() {
    57  		if !it.onRange {
    58  			continue
    59  		}
    60  		if it.start <= pc && pc < it.end {
    61  			return &Entry{it.start, it.end, it.instr}, nil
    62  		}
    63  	}
    64  
    65  	if it.err != nil {
    66  		return nil, it.err
    67  	}
    68  
    69  	if it.defaultInstr != nil {
    70  		return &Entry{pc, pc + 1, it.defaultInstr}, nil
    71  	}
    72  
    73  	return nil, nil
    74  }
    75  
    76  type loclistsIterator struct {
    77  	rdr        *Dwarf5Reader
    78  	debugAddr  *godwarf.DebugAddr
    79  	buf        *bytes.Buffer
    80  	staticBase uint64
    81  	base       uint64 // base for offsets in the list
    82  
    83  	onRange      bool
    84  	atEnd        bool
    85  	start, end   uint64
    86  	instr        []byte
    87  	defaultInstr []byte
    88  	err          error
    89  }
    90  
    91  const (
    92  	_DW_LLE_end_of_list      uint8 = 0x0
    93  	_DW_LLE_base_addressx    uint8 = 0x1
    94  	_DW_LLE_startx_endx      uint8 = 0x2
    95  	_DW_LLE_startx_length    uint8 = 0x3
    96  	_DW_LLE_offset_pair      uint8 = 0x4
    97  	_DW_LLE_default_location uint8 = 0x5
    98  	_DW_LLE_base_address     uint8 = 0x6
    99  	_DW_LLE_start_end        uint8 = 0x7
   100  	_DW_LLE_start_length     uint8 = 0x8
   101  )
   102  
   103  func (it *loclistsIterator) next() bool {
   104  	if it.err != nil || it.atEnd {
   105  		return false
   106  	}
   107  	opcode, err := it.buf.ReadByte()
   108  	if err != nil {
   109  		it.err = err
   110  		return false
   111  	}
   112  	switch opcode {
   113  	case _DW_LLE_end_of_list:
   114  		it.atEnd = true
   115  		it.onRange = false
   116  		return false
   117  
   118  	case _DW_LLE_base_addressx:
   119  		baseIdx, _ := util.DecodeULEB128(it.buf)
   120  		if err != nil {
   121  			it.err = err
   122  			return false
   123  		}
   124  		it.base, it.err = it.debugAddr.Get(baseIdx)
   125  		it.base += it.staticBase
   126  		it.onRange = false
   127  
   128  	case _DW_LLE_startx_endx:
   129  		startIdx, _ := util.DecodeULEB128(it.buf)
   130  		endIdx, _ := util.DecodeULEB128(it.buf)
   131  		it.readInstr()
   132  
   133  		it.start, it.err = it.debugAddr.Get(startIdx)
   134  		if it.err == nil {
   135  			it.end, it.err = it.debugAddr.Get(endIdx)
   136  		}
   137  		it.onRange = true
   138  
   139  	case _DW_LLE_startx_length:
   140  		startIdx, _ := util.DecodeULEB128(it.buf)
   141  		length, _ := util.DecodeULEB128(it.buf)
   142  		it.readInstr()
   143  
   144  		it.start, it.err = it.debugAddr.Get(startIdx)
   145  		it.end = it.start + length
   146  		it.onRange = true
   147  
   148  	case _DW_LLE_offset_pair:
   149  		off1, _ := util.DecodeULEB128(it.buf)
   150  		off2, _ := util.DecodeULEB128(it.buf)
   151  		it.readInstr()
   152  
   153  		it.start = it.base + off1
   154  		it.end = it.base + off2
   155  		it.onRange = true
   156  
   157  	case _DW_LLE_default_location:
   158  		it.readInstr()
   159  		it.defaultInstr = it.instr
   160  		it.onRange = false
   161  
   162  	case _DW_LLE_base_address:
   163  		it.base, it.err = util.ReadUintRaw(it.buf, it.rdr.byteOrder, it.rdr.ptrSz)
   164  		it.base += it.staticBase
   165  		it.onRange = false
   166  
   167  	case _DW_LLE_start_end:
   168  		it.start, it.err = util.ReadUintRaw(it.buf, it.rdr.byteOrder, it.rdr.ptrSz)
   169  		it.end, it.err = util.ReadUintRaw(it.buf, it.rdr.byteOrder, it.rdr.ptrSz)
   170  		it.readInstr()
   171  		it.onRange = true
   172  
   173  	case _DW_LLE_start_length:
   174  		it.start, it.err = util.ReadUintRaw(it.buf, it.rdr.byteOrder, it.rdr.ptrSz)
   175  		length, _ := util.DecodeULEB128(it.buf)
   176  		it.readInstr()
   177  		it.end = it.start + length
   178  		it.onRange = true
   179  
   180  	default:
   181  		it.err = fmt.Errorf("unknown opcode %#x at %#x", opcode, len(it.rdr.data)-it.buf.Len())
   182  		it.onRange = false
   183  		it.atEnd = true
   184  		return false
   185  	}
   186  
   187  	return true
   188  }
   189  
   190  func (it *loclistsIterator) readInstr() {
   191  	length, _ := util.DecodeULEB128(it.buf)
   192  	it.instr = it.buf.Next(int(length))
   193  }