2014-06-25 19:14:29 +00:00
|
|
|
package frame
|
|
|
|
|
|
|
|
import "fmt"
|
|
|
|
|
|
|
|
// Represents a Common Information Entry in
|
|
|
|
// the Dwarf .debug_frame section.
|
|
|
|
type CommonInformationEntry struct {
|
|
|
|
Length uint32
|
|
|
|
CIE_id uint32
|
|
|
|
Version uint8
|
|
|
|
Augmentation string
|
|
|
|
CodeAlignmentFactor uint64
|
|
|
|
DataAlignmentFactor int64
|
2014-07-29 22:34:53 +00:00
|
|
|
ReturnAddressRegister uint64
|
2014-06-25 19:14:29 +00:00
|
|
|
InitialInstructions []byte
|
|
|
|
}
|
|
|
|
|
2014-06-29 16:52:30 +00:00
|
|
|
type addrange struct {
|
|
|
|
begin, end uint64
|
|
|
|
}
|
|
|
|
|
2014-08-04 23:02:08 +00:00
|
|
|
func (r *addrange) Begin() uint64 {
|
|
|
|
return r.begin
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *addrange) End() uint64 {
|
|
|
|
return r.end
|
|
|
|
}
|
|
|
|
|
2014-06-29 16:52:30 +00:00
|
|
|
func (r *addrange) Cover(addr uint64) bool {
|
|
|
|
if (addr - r.begin) < r.end {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
2014-06-25 19:14:29 +00:00
|
|
|
|
|
|
|
// Represents a Frame Descriptor Entry in the
|
|
|
|
// Dwarf .debug_frame section.
|
|
|
|
type FrameDescriptionEntry struct {
|
|
|
|
Length uint32
|
|
|
|
CIE *CommonInformationEntry
|
|
|
|
AddressRange *addrange
|
|
|
|
Instructions []byte
|
|
|
|
}
|
|
|
|
|
2014-06-29 16:52:21 +00:00
|
|
|
func (fde *FrameDescriptionEntry) EstablishFrame(pc uint64) *FrameContext {
|
|
|
|
return executeDwarfProgramUntilPC(fde, pc)
|
|
|
|
}
|
|
|
|
|
2014-06-29 16:52:30 +00:00
|
|
|
func (fde *FrameDescriptionEntry) ReturnAddressOffset(pc uint64) int64 {
|
2014-06-29 16:52:21 +00:00
|
|
|
frame := fde.EstablishFrame(pc)
|
2014-07-10 23:07:39 +00:00
|
|
|
|
2014-07-29 22:34:53 +00:00
|
|
|
return frame.cfa.offset + frame.regs[fde.CIE.ReturnAddressRegister].offset
|
2014-06-25 19:14:29 +00:00
|
|
|
}
|
|
|
|
|
2014-08-04 23:02:08 +00:00
|
|
|
const (
|
|
|
|
RED = true
|
|
|
|
BLACK = false
|
|
|
|
)
|
|
|
|
|
|
|
|
type FrameDescriptionEntries struct {
|
|
|
|
root *FrameNode
|
|
|
|
}
|
|
|
|
|
|
|
|
type FrameNode struct {
|
|
|
|
entry *FrameDescriptionEntry
|
|
|
|
left, right *FrameNode
|
|
|
|
color bool
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewFrameIndex() *FrameDescriptionEntries {
|
|
|
|
return &FrameDescriptionEntries{}
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
2014-06-25 19:14:29 +00:00
|
|
|
|
2014-06-29 16:52:30 +00:00
|
|
|
func (fdes FrameDescriptionEntries) FDEForPC(pc uint64) (*FrameDescriptionEntry, error) {
|
2014-08-04 23:02:08 +00:00
|
|
|
fde, ok := fdes.Find(pc)
|
|
|
|
if !ok {
|
|
|
|
return nil, fmt.Errorf("Could not find FDE for %#v", pc)
|
2014-06-25 19:14:29 +00:00
|
|
|
}
|
|
|
|
|
2014-08-04 23:02:08 +00:00
|
|
|
return fde, nil
|
2014-06-25 19:14:29 +00:00
|
|
|
}
|