mirror of
https://github.com/go-delve/delve.git
synced 2025-10-30 02:07:58 +08:00
Prefer binary search over tree lookup for FDEs
FDEs previously were loaded into a red/black tree and searched. This is significantly more expensive than a binary search over a slice. Not sure what I was thinking using a red/black tree - this binary search implementation is significantly more efficient.
This commit is contained in:
@ -1,10 +1,6 @@
|
||||
package frame
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/derekparker/rbtree"
|
||||
)
|
||||
import "fmt"
|
||||
|
||||
// Represents a Common Information Entry in
|
||||
// the Dwarf .debug_frame section.
|
||||
@ -23,7 +19,6 @@ func (fde *FrameDescriptionEntry) Cover(addr uint64) bool {
|
||||
if (addr - fde.begin) < fde.end {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@ -53,39 +48,42 @@ func (fde *FrameDescriptionEntry) ReturnAddressOffset(pc uint64) int64 {
|
||||
return frame.cfa.offset + frame.regs[fde.CIE.ReturnAddressRegister].offset
|
||||
}
|
||||
|
||||
type FrameDescriptionEntries struct {
|
||||
*rbtree.RedBlackTree
|
||||
type FrameDescriptionEntries []*FrameDescriptionEntry
|
||||
|
||||
func NewFrameIndex() FrameDescriptionEntries {
|
||||
return make(FrameDescriptionEntries, 0, 1000)
|
||||
}
|
||||
|
||||
func NewFrameIndex() *FrameDescriptionEntries {
|
||||
return &FrameDescriptionEntries{rbtree.New()}
|
||||
}
|
||||
|
||||
func (fdes *FrameDescriptionEntries) FDEForPC(pc uint64) (*FrameDescriptionEntry, error) {
|
||||
node, ok := fdes.Find(Addr(pc))
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Could not find FDE for %#v", pc)
|
||||
func (fdes FrameDescriptionEntries) FDEForPC(pc uint64) (*FrameDescriptionEntry, error) {
|
||||
frame := find(fdes, pc)
|
||||
if frame == nil {
|
||||
return nil, fmt.Errorf("could not find FDE for %#v", pc)
|
||||
}
|
||||
|
||||
return node.(*FrameDescriptionEntry), nil
|
||||
return frame, nil
|
||||
}
|
||||
|
||||
func (frame *FrameDescriptionEntry) Less(item rbtree.Item) bool {
|
||||
return frame.Begin() < item.(*FrameDescriptionEntry).Begin()
|
||||
func find(fdes FrameDescriptionEntries, pc uint64) *FrameDescriptionEntry {
|
||||
if len(fdes) == 0 {
|
||||
return nil
|
||||
}
|
||||
idx := len(fdes) / 2
|
||||
frame := fdes[idx]
|
||||
if frame.Cover(pc) {
|
||||
return frame
|
||||
}
|
||||
if frame.Less(pc) {
|
||||
return find(fdes[:idx], pc)
|
||||
}
|
||||
if frame.More(pc) {
|
||||
return find(fdes[idx:], pc)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (frame *FrameDescriptionEntry) More(item rbtree.Item) bool {
|
||||
f := item.(*FrameDescriptionEntry)
|
||||
return frame.End() > f.End()
|
||||
func (frame *FrameDescriptionEntry) Less(pc uint64) bool {
|
||||
return frame.Begin() > pc
|
||||
}
|
||||
|
||||
type Addr uint64
|
||||
|
||||
func (a Addr) Less(item rbtree.Item) bool {
|
||||
return uint64(a) < item.(*FrameDescriptionEntry).Begin()
|
||||
}
|
||||
|
||||
func (a Addr) More(item rbtree.Item) bool {
|
||||
f := item.(*FrameDescriptionEntry)
|
||||
return uint64(a) > f.End()
|
||||
func (frame *FrameDescriptionEntry) More(pc uint64) bool {
|
||||
return frame.End() < pc
|
||||
}
|
||||
|
||||
@ -7,23 +7,23 @@ import (
|
||||
)
|
||||
|
||||
func TestFDEForPC(t *testing.T) {
|
||||
fde1 := &FrameDescriptionEntry{begin: 100, end: 200}
|
||||
fde1 := &FrameDescriptionEntry{begin: 0, end: 49}
|
||||
fde2 := &FrameDescriptionEntry{begin: 50, end: 99}
|
||||
fde3 := &FrameDescriptionEntry{begin: 0, end: 49}
|
||||
fde3 := &FrameDescriptionEntry{begin: 100, end: 200}
|
||||
fde4 := &FrameDescriptionEntry{begin: 201, end: 245}
|
||||
|
||||
tree := NewFrameIndex()
|
||||
tree.Put(fde1)
|
||||
tree.Put(fde2)
|
||||
tree.Put(fde3)
|
||||
tree.Put(fde4)
|
||||
frames := NewFrameIndex()
|
||||
frames = append(frames, fde1)
|
||||
frames = append(frames, fde2)
|
||||
frames = append(frames, fde3)
|
||||
frames = append(frames, fde4)
|
||||
|
||||
node, ok := tree.Find(Addr(35))
|
||||
if !ok {
|
||||
node, err := frames.FDEForPC(35)
|
||||
if err != nil {
|
||||
t.Fatal("Could not find FDE")
|
||||
}
|
||||
|
||||
if node != fde3 {
|
||||
if node != fde1 {
|
||||
t.Fatal("Got incorrect fde")
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,7 +14,7 @@ type parsefunc func(*parseContext) parsefunc
|
||||
|
||||
type parseContext struct {
|
||||
Buf *bytes.Buffer
|
||||
Entries *FrameDescriptionEntries
|
||||
Entries FrameDescriptionEntries
|
||||
Common *CommonInformationEntry
|
||||
Frame *FrameDescriptionEntry
|
||||
Length uint32
|
||||
@ -23,7 +23,7 @@ type parseContext struct {
|
||||
// Parse takes in data (a byte slice) and returns a slice of
|
||||
// CommonInformationEntry structures. Each CommonInformationEntry
|
||||
// has a slice of FrameDescriptionEntry structures.
|
||||
func Parse(data []byte) *FrameDescriptionEntries {
|
||||
func Parse(data []byte) FrameDescriptionEntries {
|
||||
var (
|
||||
buf = bytes.NewBuffer(data)
|
||||
pctx = &parseContext{Buf: buf, Entries: NewFrameIndex()}
|
||||
@ -62,7 +62,7 @@ func parseFDE(ctx *parseContext) parsefunc {
|
||||
|
||||
// Insert into the tree after setting address range begin
|
||||
// otherwise compares won't work.
|
||||
ctx.Entries.Put(ctx.Frame)
|
||||
ctx.Entries = append(ctx.Entries, ctx.Frame)
|
||||
|
||||
// The rest of this entry consists of the instructions
|
||||
// so we can just grab all of the data from the buffer
|
||||
|
||||
Reference in New Issue
Block a user