From c902522a8cb3b2a7f35a9161721aaff2807f9af7 Mon Sep 17 00:00:00 2001 From: Derek Parker Date: Tue, 12 Nov 2019 11:44:08 -0800 Subject: [PATCH] pkg/proc,pkg/dwarf: Introduce loclist package Move the loclist code out of proc and into its own package in `pkg/dwarf`. --- pkg/dwarf/loclist/loclist.go | 81 +++++++++++++++++++++++++++++ pkg/proc/bininfo.go | 98 ++++++------------------------------ pkg/proc/types.go | 5 ++ 3 files changed, 101 insertions(+), 83 deletions(-) create mode 100644 pkg/dwarf/loclist/loclist.go diff --git a/pkg/dwarf/loclist/loclist.go b/pkg/dwarf/loclist/loclist.go new file mode 100644 index 00000000..2fcd5268 --- /dev/null +++ b/pkg/dwarf/loclist/loclist.go @@ -0,0 +1,81 @@ +package loclist + +import ( + "encoding/binary" +) + +// Reader parses and presents DWARF loclist information. +type Reader struct { + data []byte + cur int + ptrSz int +} + +// New returns an initialized loclist Reader. +func New(data []byte, ptrSz int) *Reader { + return &Reader{data: data, ptrSz: ptrSz} +} + +// Empty returns true if this reader has no data. +func (rdr *Reader) Empty() bool { + return rdr.data == nil +} + +// Seek moves the data pointer to the specified offset. +func (rdr *Reader) Seek(off int) { + rdr.cur = off +} + +// Next advances the reader to the next loclist entry, returning +// the entry and true if successful, or nil, false if not. +func (rdr *Reader) Next(e *Entry) bool { + e.LowPC = rdr.oneAddr() + e.HighPC = rdr.oneAddr() + + if e.LowPC == 0 && e.HighPC == 0 { + return false + } + + if e.BaseAddressSelection() { + e.Instr = nil + return true + } + + instrlen := binary.LittleEndian.Uint16(rdr.read(2)) + e.Instr = rdr.read(int(instrlen)) + return true +} + +func (rdr *Reader) read(sz int) []byte { + r := rdr.data[rdr.cur : rdr.cur+sz] + rdr.cur += sz + return r +} + +func (rdr *Reader) oneAddr() uint64 { + switch rdr.ptrSz { + case 4: + addr := binary.LittleEndian.Uint32(rdr.read(rdr.ptrSz)) + if addr == ^uint32(0) { + return ^uint64(0) + } + return uint64(addr) + case 8: + addr := uint64(binary.LittleEndian.Uint64(rdr.read(rdr.ptrSz))) + return addr + default: + panic("bad address size") + } +} + +// Entry represents a single entry in the loclist section. +type Entry struct { + LowPC, HighPC uint64 + Instr []byte +} + +// BaseAddressSelection returns true if entry.highpc should +// be used as the base address for subsequent entries. +func (e *Entry) BaseAddressSelection() bool { + return e.LowPC == ^uint64(0) +} diff --git a/pkg/proc/bininfo.go b/pkg/proc/bininfo.go index daf6e03a..798695a8 100644 --- a/pkg/proc/bininfo.go +++ b/pkg/proc/bininfo.go @@ -24,6 +24,7 @@ import ( "github.com/go-delve/delve/pkg/dwarf/frame" "github.com/go-delve/delve/pkg/dwarf/godwarf" "github.com/go-delve/delve/pkg/dwarf/line" + "github.com/go-delve/delve/pkg/dwarf/loclist" "github.com/go-delve/delve/pkg/dwarf/op" "github.com/go-delve/delve/pkg/dwarf/reader" "github.com/go-delve/delve/pkg/goversion" @@ -233,70 +234,6 @@ type packageVar struct { addr uint64 } -type loclistReader struct { - data []byte - cur int - ptrSz int -} - -func (rdr *loclistReader) Seek(off int) { - rdr.cur = off -} - -func (rdr *loclistReader) read(sz int) []byte { - r := rdr.data[rdr.cur : rdr.cur+sz] - rdr.cur += sz - return r -} - -func (rdr *loclistReader) oneAddr() uint64 { - switch rdr.ptrSz { - case 4: - addr := binary.LittleEndian.Uint32(rdr.read(rdr.ptrSz)) - if addr == ^uint32(0) { - return ^uint64(0) - } - return uint64(addr) - case 8: - addr := uint64(binary.LittleEndian.Uint64(rdr.read(rdr.ptrSz))) - return addr - default: - panic("bad address size") - } -} - -func (rdr *loclistReader) Next(e *loclistEntry) bool { - e.lowpc = rdr.oneAddr() - e.highpc = rdr.oneAddr() - - if e.lowpc == 0 && e.highpc == 0 { - return false - } - - if e.BaseAddressSelection() { - e.instr = nil - return true - } - - instrlen := binary.LittleEndian.Uint16(rdr.read(2)) - e.instr = rdr.read(int(instrlen)) - return true -} - -type loclistEntry struct { - lowpc, highpc uint64 - instr []byte -} - -type runtimeTypeDIE struct { - offset dwarf.Offset - kind int64 -} - -func (e *loclistEntry) BaseAddressSelection() bool { - return e.lowpc == ^uint64(0) -} - type buildIDHeader struct { Namesz uint32 Descsz uint32 @@ -529,7 +466,7 @@ type Image struct { dwarf *dwarf.Data dwarfReader *dwarf.Reader - loclist loclistReader + loclist *loclist.Reader typeCache map[dwarf.Offset]godwarf.Type @@ -670,18 +607,13 @@ func (bi *BinaryInfo) LoadImageFromData(dwdata *dwarf.Data, debugFrameBytes, deb bi.frameEntries = frame.Parse(debugFrameBytes, frame.DwarfEndian(debugFrameBytes), 0) } - image.loclistInit(debugLocBytes, bi.Arch.PtrSize()) + image.loclist = loclist.New(debugLocBytes, bi.Arch.PtrSize()) bi.loadDebugInfoMaps(image, debugLineBytes, nil, nil) bi.Images = append(bi.Images, image) } -func (image *Image) loclistInit(data []byte, ptrSz int) { - image.loclist.data = data - image.loclist.ptrSz = ptrSz -} - func (bi *BinaryInfo) locationExpr(entry reader.Entry, attr dwarf.Attr, pc uint64) ([]byte, string, error) { a := entry.Val(attr) if a == nil { @@ -729,19 +661,19 @@ func (bi *BinaryInfo) LocationCovers(entry *dwarf.Entry, attr dwarf.Attr) ([][2] image := cu.image base := cu.lowPC - if image == nil || image.loclist.data == nil { + if image == nil || image.loclist.Empty() { return nil, errors.New("malformed executable") } r := [][2]uint64{} + var e loclist.Entry image.loclist.Seek(int(off)) - var e loclistEntry for image.loclist.Next(&e) { if e.BaseAddressSelection() { - base = e.highpc + base = e.HighPC continue } - r = append(r, [2]uint64{e.lowpc + base, e.highpc + base}) + r = append(r, [2]uint64{e.LowPC + base, e.HighPC + base}) } return r, nil } @@ -768,19 +700,19 @@ func (bi *BinaryInfo) loclistEntry(off int64, pc uint64) []byte { base = cu.lowPC image = cu.image } - if image == nil || image.loclist.data == nil { + if image == nil || image.loclist.Empty() { return nil } image.loclist.Seek(int(off)) - var e loclistEntry + var e loclist.Entry for image.loclist.Next(&e) { if e.BaseAddressSelection() { - base = e.highpc + base = e.HighPC continue } - if pc >= e.lowpc+base && pc < e.highpc+base { - return e.instr + if pc >= e.LowPC+base && pc < e.HighPC+base { + return e.Instr } } @@ -980,7 +912,7 @@ func loadBinaryInfoElf(bi *BinaryInfo, image *Image, path string, addr uint64, w return err } debugLocBytes, _ := godwarf.GetDebugSectionElf(dwarfFile, "loc") - image.loclistInit(debugLocBytes, bi.Arch.PtrSize()) + image.loclist = loclist.New(debugLocBytes, bi.Arch.PtrSize()) wg.Add(2) go bi.parseDebugFrameElf(image, dwarfFile, wg) @@ -1095,7 +1027,7 @@ func loadBinaryInfoPE(bi *BinaryInfo, image *Image, path string, entryPoint uint return err } debugLocBytes, _ := godwarf.GetDebugSectionPE(peFile, "loc") - image.loclistInit(debugLocBytes, bi.Arch.PtrSize()) + image.loclist = loclist.New(debugLocBytes, bi.Arch.PtrSize()) wg.Add(2) go bi.parseDebugFramePE(image, peFile, wg) @@ -1180,7 +1112,7 @@ func loadBinaryInfoMacho(bi *BinaryInfo, image *Image, path string, entryPoint u return err } debugLocBytes, _ := godwarf.GetDebugSectionMacho(exe, "loc") - image.loclistInit(debugLocBytes, bi.Arch.PtrSize()) + image.loclist = loclist.New(debugLocBytes, bi.Arch.PtrSize()) wg.Add(2) go bi.parseDebugFrameMacho(image, exe, wg) diff --git a/pkg/proc/types.go b/pkg/proc/types.go index c8a26644..e39f5e59 100644 --- a/pkg/proc/types.go +++ b/pkg/proc/types.go @@ -42,6 +42,11 @@ const ( interfacetypeFieldMhdr = "mhdr" ) +type runtimeTypeDIE struct { + offset dwarf.Offset + kind int64 +} + func pointerTo(typ godwarf.Type, arch Arch) godwarf.Type { return &godwarf.PtrType{ CommonType: godwarf.CommonType{