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 }