diff --git a/dwarf/frame/frame_entries.go b/dwarf/frame/frame_entries.go index 657b9db9..1bf3aba4 100644 --- a/dwarf/frame/frame_entries.go +++ b/dwarf/frame/frame_entries.go @@ -1,6 +1,10 @@ package frame -import "fmt" +import ( + "fmt" + + "github.com/derekparker/rbtree" +) // Represents a Common Information Entry in // the Dwarf .debug_frame section. @@ -54,112 +58,40 @@ func (fde *FrameDescriptionEntry) ReturnAddressOffset(pc uint64) int64 { return frame.cfa.offset + frame.regs[fde.CIE.ReturnAddressRegister].offset } -const ( - RED = true - BLACK = false -) - type FrameDescriptionEntries struct { - root *FrameNode -} - -type FrameNode struct { - entry *FrameDescriptionEntry - left, right *FrameNode - color bool + *rbtree.RedBlackTree } func NewFrameIndex() *FrameDescriptionEntries { - return &FrameDescriptionEntries{} + return &FrameDescriptionEntries{rbtree.New()} } -func (fs *FrameDescriptionEntries) Find(pc uint64) (*FrameDescriptionEntry, bool) { - return find(fs.root, pc) -} - -func find(fn *FrameNode, pc uint64) (*FrameDescriptionEntry, bool) { - switch { - case fn == nil: - return nil, false - case fn.entry.AddressRange.Cover(pc): - return fn.entry, true - case pc < fn.entry.AddressRange.begin: - return find(fn.left, pc) - case pc > fn.entry.AddressRange.begin+fn.entry.AddressRange.end: - return find(fn.right, pc) - } - - return nil, false -} - -func (fs *FrameDescriptionEntries) Put(entry *FrameDescriptionEntry) { - fs.root = put(fs.root, entry) - fs.root.color = BLACK -} - -func put(fn *FrameNode, entry *FrameDescriptionEntry) *FrameNode { - switch { - case fn == nil: - return &FrameNode{entry: entry, color: RED} - case entry.AddressRange.begin < fn.entry.AddressRange.begin: - fn.left = put(fn.left, entry) - case entry.AddressRange.begin > fn.entry.AddressRange.begin: - fn.right = put(fn.right, entry) - } - - leftRed := isRed(fn.left) - rightRed := isRed(fn.right) - - if !leftRed && rightRed { - fn = rotateLeft(fn) - } else if leftRed && isRed(fn.left.left) { - fn = rotateRight(fn) - } - - if leftRed && rightRed { - fn.left.color = BLACK - fn.right.color = BLACK - fn.color = RED - } - - return fn -} - -func isRed(fn *FrameNode) bool { - if fn == nil { - return false - } - - return fn.color -} - -func rotateLeft(fn *FrameNode) *FrameNode { - x := fn.right - fn.right = x.left - x.left = fn - - x.color = fn.color - fn.color = RED - - return x -} - -func rotateRight(fn *FrameNode) *FrameNode { - x := fn.left - fn.left = x.right - x.right = fn - - x.color = fn.color - fn.color = RED - - return x -} - -func (fdes FrameDescriptionEntries) FDEForPC(pc uint64) (*FrameDescriptionEntry, error) { - fde, ok := fdes.Find(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 fde, nil + return node.(*FrameDescriptionEntry), nil +} + +func (frame *FrameDescriptionEntry) Less(item rbtree.Item) bool { + return frame.AddressRange.begin < item.(*FrameDescriptionEntry).AddressRange.begin +} + +func (frame *FrameDescriptionEntry) More(item rbtree.Item) bool { + r := item.(*FrameDescriptionEntry).AddressRange + fnr := frame.AddressRange + return fnr.begin+fnr.end > r.begin+r.end +} + +type Addr uint64 + +func (a Addr) Less(item rbtree.Item) bool { + return uint64(a) < item.(*FrameDescriptionEntry).AddressRange.begin +} + +func (a Addr) More(item rbtree.Item) bool { + r := item.(*FrameDescriptionEntry).AddressRange + return uint64(a) > r.begin+r.end } diff --git a/dwarf/frame/frame_entries_test.go b/dwarf/frame/frame_entries_test.go index 5a1e0d33..4b83a22d 100644 --- a/dwarf/frame/frame_entries_test.go +++ b/dwarf/frame/frame_entries_test.go @@ -19,12 +19,12 @@ func TestFDEForPC(t *testing.T) { tree.Put(fde3) tree.Put(fde4) - fde, ok := tree.Find(35) + node, ok := tree.Find(Addr(35)) if !ok { t.Fatal("Could not find FDE") } - if fde != fde3 { + if node != fde3 { t.Fatal("Got incorrect fde") } } diff --git a/dwarf/frame/frame_parser.go b/dwarf/frame/frame_parser.go index 719a78ee..f9e62df0 100644 --- a/dwarf/frame/frame_parser.go +++ b/dwarf/frame/frame_parser.go @@ -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,10 +23,10 @@ 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} + pctx = &parseContext{Buf: buf, Entries: NewFrameIndex()} ) for fn := parseLength; buf.Len() != 0; { diff --git a/proctl/proctl_linux_amd64.go b/proctl/proctl_linux_amd64.go index 5be60e2b..c6e27924 100644 --- a/proctl/proctl_linux_amd64.go +++ b/proctl/proctl_linux_amd64.go @@ -30,7 +30,7 @@ type DebuggedProcess struct { Executable *elf.File Symbols []elf.Symbol GoSymTable *gosym.Table - FrameEntries frame.FrameDescriptionEntries + FrameEntries *frame.FrameDescriptionEntries DebugLine *line.DebugLineInfo BreakPoints map[string]*BreakPoint TempBreakPoints map[uint64]*BreakPoint