mirror of
https://github.com/go-delve/delve.git
synced 2025-10-30 18:27:37 +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
|
package frame
|
||||||
|
|
||||||
import (
|
import "fmt"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/derekparker/rbtree"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Represents a Common Information Entry in
|
// Represents a Common Information Entry in
|
||||||
// the Dwarf .debug_frame section.
|
// the Dwarf .debug_frame section.
|
||||||
@ -23,7 +19,6 @@ func (fde *FrameDescriptionEntry) Cover(addr uint64) bool {
|
|||||||
if (addr - fde.begin) < fde.end {
|
if (addr - fde.begin) < fde.end {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,39 +48,42 @@ func (fde *FrameDescriptionEntry) ReturnAddressOffset(pc uint64) int64 {
|
|||||||
return frame.cfa.offset + frame.regs[fde.CIE.ReturnAddressRegister].offset
|
return frame.cfa.offset + frame.regs[fde.CIE.ReturnAddressRegister].offset
|
||||||
}
|
}
|
||||||
|
|
||||||
type FrameDescriptionEntries struct {
|
type FrameDescriptionEntries []*FrameDescriptionEntry
|
||||||
*rbtree.RedBlackTree
|
|
||||||
|
func NewFrameIndex() FrameDescriptionEntries {
|
||||||
|
return make(FrameDescriptionEntries, 0, 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFrameIndex() *FrameDescriptionEntries {
|
func (fdes FrameDescriptionEntries) FDEForPC(pc uint64) (*FrameDescriptionEntry, error) {
|
||||||
return &FrameDescriptionEntries{rbtree.New()}
|
frame := find(fdes, pc)
|
||||||
}
|
if frame == nil {
|
||||||
|
return nil, fmt.Errorf("could not find FDE for %#v", pc)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
return frame, nil
|
||||||
return node.(*FrameDescriptionEntry), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (frame *FrameDescriptionEntry) Less(item rbtree.Item) bool {
|
func find(fdes FrameDescriptionEntries, pc uint64) *FrameDescriptionEntry {
|
||||||
return frame.Begin() < item.(*FrameDescriptionEntry).Begin()
|
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 {
|
func (frame *FrameDescriptionEntry) Less(pc uint64) bool {
|
||||||
f := item.(*FrameDescriptionEntry)
|
return frame.Begin() > pc
|
||||||
return frame.End() > f.End()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Addr uint64
|
func (frame *FrameDescriptionEntry) More(pc uint64) bool {
|
||||||
|
return frame.End() < pc
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,23 +7,23 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestFDEForPC(t *testing.T) {
|
func TestFDEForPC(t *testing.T) {
|
||||||
fde1 := &FrameDescriptionEntry{begin: 100, end: 200}
|
fde1 := &FrameDescriptionEntry{begin: 0, end: 49}
|
||||||
fde2 := &FrameDescriptionEntry{begin: 50, end: 99}
|
fde2 := &FrameDescriptionEntry{begin: 50, end: 99}
|
||||||
fde3 := &FrameDescriptionEntry{begin: 0, end: 49}
|
fde3 := &FrameDescriptionEntry{begin: 100, end: 200}
|
||||||
fde4 := &FrameDescriptionEntry{begin: 201, end: 245}
|
fde4 := &FrameDescriptionEntry{begin: 201, end: 245}
|
||||||
|
|
||||||
tree := NewFrameIndex()
|
frames := NewFrameIndex()
|
||||||
tree.Put(fde1)
|
frames = append(frames, fde1)
|
||||||
tree.Put(fde2)
|
frames = append(frames, fde2)
|
||||||
tree.Put(fde3)
|
frames = append(frames, fde3)
|
||||||
tree.Put(fde4)
|
frames = append(frames, fde4)
|
||||||
|
|
||||||
node, ok := tree.Find(Addr(35))
|
node, err := frames.FDEForPC(35)
|
||||||
if !ok {
|
if err != nil {
|
||||||
t.Fatal("Could not find FDE")
|
t.Fatal("Could not find FDE")
|
||||||
}
|
}
|
||||||
|
|
||||||
if node != fde3 {
|
if node != fde1 {
|
||||||
t.Fatal("Got incorrect fde")
|
t.Fatal("Got incorrect fde")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,7 +14,7 @@ type parsefunc func(*parseContext) parsefunc
|
|||||||
|
|
||||||
type parseContext struct {
|
type parseContext struct {
|
||||||
Buf *bytes.Buffer
|
Buf *bytes.Buffer
|
||||||
Entries *FrameDescriptionEntries
|
Entries FrameDescriptionEntries
|
||||||
Common *CommonInformationEntry
|
Common *CommonInformationEntry
|
||||||
Frame *FrameDescriptionEntry
|
Frame *FrameDescriptionEntry
|
||||||
Length uint32
|
Length uint32
|
||||||
@ -23,7 +23,7 @@ type parseContext struct {
|
|||||||
// Parse takes in data (a byte slice) and returns a slice of
|
// Parse takes in data (a byte slice) and returns a slice of
|
||||||
// CommonInformationEntry structures. Each CommonInformationEntry
|
// CommonInformationEntry structures. Each CommonInformationEntry
|
||||||
// has a slice of FrameDescriptionEntry structures.
|
// has a slice of FrameDescriptionEntry structures.
|
||||||
func Parse(data []byte) *FrameDescriptionEntries {
|
func Parse(data []byte) FrameDescriptionEntries {
|
||||||
var (
|
var (
|
||||||
buf = bytes.NewBuffer(data)
|
buf = bytes.NewBuffer(data)
|
||||||
pctx = &parseContext{Buf: buf, Entries: NewFrameIndex()}
|
pctx = &parseContext{Buf: buf, Entries: NewFrameIndex()}
|
||||||
@ -62,7 +62,7 @@ func parseFDE(ctx *parseContext) parsefunc {
|
|||||||
|
|
||||||
// Insert into the tree after setting address range begin
|
// Insert into the tree after setting address range begin
|
||||||
// otherwise compares won't work.
|
// 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
|
// The rest of this entry consists of the instructions
|
||||||
// so we can just grab all of the data from the buffer
|
// so we can just grab all of the data from the buffer
|
||||||
|
|||||||
@ -27,7 +27,7 @@ type DebuggedProcess struct {
|
|||||||
Process *os.Process
|
Process *os.Process
|
||||||
Dwarf *dwarf.Data
|
Dwarf *dwarf.Data
|
||||||
GoSymTable *gosym.Table
|
GoSymTable *gosym.Table
|
||||||
FrameEntries *frame.FrameDescriptionEntries
|
FrameEntries frame.FrameDescriptionEntries
|
||||||
HWBreakPoints [4]*BreakPoint
|
HWBreakPoints [4]*BreakPoint
|
||||||
BreakPoints map[uint64]*BreakPoint
|
BreakPoints map[uint64]*BreakPoint
|
||||||
Threads map[int]*ThreadContext
|
Threads map[int]*ThreadContext
|
||||||
|
|||||||
Reference in New Issue
Block a user