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