gitlab.com/Raven-IO/raven-delve@v1.22.4/pkg/dwarf/loclist/dwarf5_loclist.go (about)

     1  package loclist
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"fmt"
     7  
     8  	"gitlab.com/Raven-IO/raven-delve/pkg/dwarf"
     9  	"gitlab.com/Raven-IO/raven-delve/pkg/dwarf/godwarf"
    10  	"gitlab.com/Raven-IO/raven-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  		it.base, it.err = it.debugAddr.Get(baseIdx)
   122  		it.base += it.staticBase
   123  		it.onRange = false
   124  
   125  	case _DW_LLE_startx_endx:
   126  		startIdx, _ := leb128.DecodeUnsigned(it.buf)
   127  		endIdx, _ := leb128.DecodeUnsigned(it.buf)
   128  		it.readInstr()
   129  
   130  		it.start, it.err = it.debugAddr.Get(startIdx)
   131  		if it.err == nil {
   132  			it.end, it.err = it.debugAddr.Get(endIdx)
   133  		}
   134  		it.onRange = true
   135  
   136  	case _DW_LLE_startx_length:
   137  		startIdx, _ := leb128.DecodeUnsigned(it.buf)
   138  		length, _ := leb128.DecodeUnsigned(it.buf)
   139  		it.readInstr()
   140  
   141  		it.start, it.err = it.debugAddr.Get(startIdx)
   142  		it.end = it.start + length
   143  		it.onRange = true
   144  
   145  	case _DW_LLE_offset_pair:
   146  		off1, _ := leb128.DecodeUnsigned(it.buf)
   147  		off2, _ := leb128.DecodeUnsigned(it.buf)
   148  		it.readInstr()
   149  
   150  		it.start = it.base + off1
   151  		it.end = it.base + off2
   152  		it.onRange = true
   153  
   154  	case _DW_LLE_default_location:
   155  		it.readInstr()
   156  		it.defaultInstr = it.instr
   157  		it.onRange = false
   158  
   159  	case _DW_LLE_base_address:
   160  		it.base, it.err = dwarf.ReadUintRaw(it.buf, it.rdr.byteOrder, it.rdr.ptrSz)
   161  		it.base += it.staticBase
   162  		it.onRange = false
   163  
   164  	case _DW_LLE_start_end:
   165  		it.start, it.err = dwarf.ReadUintRaw(it.buf, it.rdr.byteOrder, it.rdr.ptrSz)
   166  		it.end, it.err = dwarf.ReadUintRaw(it.buf, it.rdr.byteOrder, it.rdr.ptrSz)
   167  		it.readInstr()
   168  		it.onRange = true
   169  
   170  	case _DW_LLE_start_length:
   171  		it.start, it.err = dwarf.ReadUintRaw(it.buf, it.rdr.byteOrder, it.rdr.ptrSz)
   172  		length, _ := leb128.DecodeUnsigned(it.buf)
   173  		it.readInstr()
   174  		it.end = it.start + length
   175  		it.onRange = true
   176  
   177  	default:
   178  		it.err = fmt.Errorf("unknown opcode %#x at %#x", opcode, len(it.rdr.data)-it.buf.Len())
   179  		it.onRange = false
   180  		it.atEnd = true
   181  		return false
   182  	}
   183  
   184  	return true
   185  }
   186  
   187  func (it *loclistsIterator) readInstr() {
   188  	length, _ := leb128.DecodeUnsigned(it.buf)
   189  	it.instr = it.buf.Next(int(length))
   190  }