Use external red/black tree package

This commit is contained in:
Derek Parker
2014-08-07 11:03:42 -05:00
parent d977810626
commit 0af47b64ce
4 changed files with 37 additions and 105 deletions

View File

@ -1,6 +1,10 @@
package frame package frame
import "fmt" import (
"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.
@ -54,112 +58,40 @@ 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
} }
const (
RED = true
BLACK = false
)
type FrameDescriptionEntries struct { type FrameDescriptionEntries struct {
root *FrameNode *rbtree.RedBlackTree
}
type FrameNode struct {
entry *FrameDescriptionEntry
left, right *FrameNode
color bool
} }
func NewFrameIndex() *FrameDescriptionEntries { func NewFrameIndex() *FrameDescriptionEntries {
return &FrameDescriptionEntries{} return &FrameDescriptionEntries{rbtree.New()}
} }
func (fs *FrameDescriptionEntries) Find(pc uint64) (*FrameDescriptionEntry, bool) { func (fdes *FrameDescriptionEntries) FDEForPC(pc uint64) (*FrameDescriptionEntry, error) {
return find(fs.root, pc) node, ok := fdes.Find(Addr(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)
if !ok { if !ok {
return nil, fmt.Errorf("Could not find FDE for %#v", pc) 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
} }

View File

@ -19,12 +19,12 @@ func TestFDEForPC(t *testing.T) {
tree.Put(fde3) tree.Put(fde3)
tree.Put(fde4) tree.Put(fde4)
fde, ok := tree.Find(35) node, ok := tree.Find(Addr(35))
if !ok { if !ok {
t.Fatal("Could not find FDE") t.Fatal("Could not find FDE")
} }
if fde != fde3 { if node != fde3 {
t.Fatal("Got incorrect fde") t.Fatal("Got incorrect fde")
} }
} }

View File

@ -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,10 +23,10 @@ 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} pctx = &parseContext{Buf: buf, Entries: NewFrameIndex()}
) )
for fn := parseLength; buf.Len() != 0; { for fn := parseLength; buf.Len() != 0; {

View File

@ -30,7 +30,7 @@ type DebuggedProcess struct {
Executable *elf.File Executable *elf.File
Symbols []elf.Symbol Symbols []elf.Symbol
GoSymTable *gosym.Table GoSymTable *gosym.Table
FrameEntries frame.FrameDescriptionEntries FrameEntries *frame.FrameDescriptionEntries
DebugLine *line.DebugLineInfo DebugLine *line.DebugLineInfo
BreakPoints map[string]*BreakPoint BreakPoints map[string]*BreakPoint
TempBreakPoints map[uint64]*BreakPoint TempBreakPoints map[uint64]*BreakPoint