github.com/cnboonhan/delve@v0.0.0-20230908061759-363f2388c2fb/pkg/dwarf/loclist/dwarf2_loclist.go (about)

     1  package loclist
     2  
     3  import (
     4  	"encoding/binary"
     5  
     6  	"github.com/go-delve/delve/pkg/dwarf/godwarf"
     7  )
     8  
     9  // Reader represents a loclist reader.
    10  type Reader interface {
    11  	Find(off int, staticBase, base, pc uint64, debugAddr *godwarf.DebugAddr) (*Entry, error)
    12  	Empty() bool
    13  }
    14  
    15  // Dwarf2Reader parses and presents DWARF loclist information for DWARF versions 2 through 4.
    16  type Dwarf2Reader struct {
    17  	data  []byte
    18  	cur   int
    19  	ptrSz int
    20  }
    21  
    22  // NewDwarf2Reader returns an initialized loclist Reader for DWARF versions 2 through 4.
    23  func NewDwarf2Reader(data []byte, ptrSz int) *Dwarf2Reader {
    24  	return &Dwarf2Reader{data: data, ptrSz: ptrSz}
    25  }
    26  
    27  // Empty returns true if this reader has no data.
    28  func (rdr *Dwarf2Reader) Empty() bool {
    29  	return rdr.data == nil
    30  }
    31  
    32  // Seek moves the data pointer to the specified offset.
    33  func (rdr *Dwarf2Reader) Seek(off int) {
    34  	rdr.cur = off
    35  }
    36  
    37  // Next advances the reader to the next loclist entry, returning
    38  // the entry and true if successful, or nil, false if not.
    39  func (rdr *Dwarf2Reader) Next(e *Entry) bool {
    40  	e.LowPC = rdr.oneAddr()
    41  	e.HighPC = rdr.oneAddr()
    42  
    43  	if e.LowPC == 0 && e.HighPC == 0 {
    44  		return false
    45  	}
    46  
    47  	if e.BaseAddressSelection() {
    48  		e.Instr = nil
    49  		return true
    50  	}
    51  
    52  	instrlen := binary.LittleEndian.Uint16(rdr.read(2))
    53  	e.Instr = rdr.read(int(instrlen))
    54  	return true
    55  }
    56  
    57  // Find returns the loclist entry for the specified PC address, inside the
    58  // loclist stating at off. Base is the base address of the compile unit and
    59  // staticBase is the static base at which the image is loaded.
    60  func (rdr *Dwarf2Reader) Find(off int, staticBase, base, pc uint64, debugAddr *godwarf.DebugAddr) (*Entry, error) {
    61  	rdr.Seek(off)
    62  	var e Entry
    63  	for rdr.Next(&e) {
    64  		if e.BaseAddressSelection() {
    65  			base = e.HighPC + staticBase
    66  			continue
    67  		}
    68  		if pc >= e.LowPC+base && pc < e.HighPC+base {
    69  			return &e, nil
    70  		}
    71  	}
    72  	return nil, nil
    73  }
    74  
    75  func (rdr *Dwarf2Reader) read(sz int) []byte {
    76  	r := rdr.data[rdr.cur : rdr.cur+sz]
    77  	rdr.cur += sz
    78  	return r
    79  }
    80  
    81  func (rdr *Dwarf2Reader) oneAddr() uint64 {
    82  	switch rdr.ptrSz {
    83  	case 4:
    84  		addr := binary.LittleEndian.Uint32(rdr.read(rdr.ptrSz))
    85  		if addr == ^uint32(0) {
    86  			return ^uint64(0)
    87  		}
    88  		return uint64(addr)
    89  	case 8:
    90  		addr := uint64(binary.LittleEndian.Uint64(rdr.read(rdr.ptrSz)))
    91  		return addr
    92  	default:
    93  		panic("bad address size")
    94  	}
    95  }
    96  
    97  // Entry represents a single entry in the loclist section.
    98  type Entry struct {
    99  	LowPC, HighPC uint64
   100  	Instr         []byte
   101  }
   102  
   103  // BaseAddressSelection returns true if entry.highpc should
   104  // be used as the base address for subsequent entries.
   105  func (e *Entry) BaseAddressSelection() bool {
   106  	return e.LowPC == ^uint64(0)
   107  }