mirror of
https://github.com/beego/bee.git
synced 2025-06-21 10:00:18 +00:00
Use Delve v0.12.1 instead of master
This commit is contained in:
95
vendor/github.com/derekparker/delve/dwarf/frame/entries.go
generated
vendored
Normal file
95
vendor/github.com/derekparker/delve/dwarf/frame/entries.go
generated
vendored
Normal file
@ -0,0 +1,95 @@
|
||||
package frame
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// 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
|
||||
ReturnAddressRegister uint64
|
||||
InitialInstructions []byte
|
||||
}
|
||||
|
||||
// Represents a Frame Descriptor Entry in the
|
||||
// Dwarf .debug_frame section.
|
||||
type FrameDescriptionEntry struct {
|
||||
Length uint32
|
||||
CIE *CommonInformationEntry
|
||||
Instructions []byte
|
||||
begin, end uint64
|
||||
order binary.ByteOrder
|
||||
}
|
||||
|
||||
// Returns whether or not the given address is within the
|
||||
// bounds of this frame.
|
||||
func (fde *FrameDescriptionEntry) Cover(addr uint64) bool {
|
||||
if (addr - fde.begin) < fde.end {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Address of first location for this frame.
|
||||
func (fde *FrameDescriptionEntry) Begin() uint64 {
|
||||
return fde.begin
|
||||
}
|
||||
|
||||
// Address of last location for this frame.
|
||||
func (fde *FrameDescriptionEntry) End() uint64 {
|
||||
return fde.begin + fde.end
|
||||
}
|
||||
|
||||
// Set up frame for the given PC.
|
||||
func (fde *FrameDescriptionEntry) EstablishFrame(pc uint64) *FrameContext {
|
||||
return executeDwarfProgramUntilPC(fde, pc)
|
||||
}
|
||||
|
||||
// Return the offset from the current SP that the return address is stored at.
|
||||
func (fde *FrameDescriptionEntry) ReturnAddressOffset(pc uint64) (frameOffset, returnAddressOffset int64) {
|
||||
frame := fde.EstablishFrame(pc)
|
||||
return frame.cfa.offset, frame.regs[fde.CIE.ReturnAddressRegister].offset
|
||||
}
|
||||
|
||||
type FrameDescriptionEntries []*FrameDescriptionEntry
|
||||
|
||||
func NewFrameIndex() FrameDescriptionEntries {
|
||||
return make(FrameDescriptionEntries, 0, 1000)
|
||||
}
|
||||
|
||||
type NoFDEForPCError struct {
|
||||
PC uint64
|
||||
}
|
||||
|
||||
func (err *NoFDEForPCError) Error() string {
|
||||
return fmt.Sprintf("could not find FDE for PC %#v", err.PC)
|
||||
}
|
||||
|
||||
// Returns the Frame Description Entry for the given PC.
|
||||
func (fdes FrameDescriptionEntries) FDEForPC(pc uint64) (*FrameDescriptionEntry, error) {
|
||||
idx := sort.Search(len(fdes), func(i int) bool {
|
||||
if fdes[i].Cover(pc) {
|
||||
return true
|
||||
}
|
||||
if fdes[i].LessThan(pc) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
if idx == len(fdes) {
|
||||
return nil, &NoFDEForPCError{pc}
|
||||
}
|
||||
return fdes[idx], nil
|
||||
}
|
||||
|
||||
func (frame *FrameDescriptionEntry) LessThan(pc uint64) bool {
|
||||
return frame.End() <= pc
|
||||
}
|
164
vendor/github.com/derekparker/delve/dwarf/frame/expression_constants.go
generated
vendored
Normal file
164
vendor/github.com/derekparker/delve/dwarf/frame/expression_constants.go
generated
vendored
Normal file
@ -0,0 +1,164 @@
|
||||
package frame
|
||||
|
||||
// Operation opcodes
|
||||
const (
|
||||
DW_OP_addr = 0x03
|
||||
DW_OP_const1s = 0x09
|
||||
)
|
||||
|
||||
const (
|
||||
DW_OP_const2u = 0x0a
|
||||
DW_OP_const2s = 0x0b
|
||||
DW_OP_const4u = iota
|
||||
DW_OP_const4s
|
||||
DW_OP_const8u
|
||||
DW_OP_const8s
|
||||
DW_OP_constu
|
||||
DW_OP_consts
|
||||
DW_OP_dup
|
||||
DW_OP_drop
|
||||
DW_OP_over
|
||||
DW_OP_pick
|
||||
DW_OP_swap
|
||||
DW_OP_rot
|
||||
DW_OP_xderef
|
||||
DW_OP_abs
|
||||
DW_OP_and
|
||||
DW_OP_div
|
||||
DW_OP_minus
|
||||
DW_OP_mod
|
||||
DW_OP_mul
|
||||
DW_OP_neg
|
||||
DW_OP_not
|
||||
DW_OP_or
|
||||
DW_OP_plus
|
||||
DW_OP_plus_uconst
|
||||
DW_OP_shl
|
||||
DW_OP_shr
|
||||
DW_OP_shra
|
||||
DW_OP_xor
|
||||
DW_OP_skip
|
||||
DW_OP_bra
|
||||
DW_OP_eq
|
||||
DW_OP_ge
|
||||
DW_OP_gt
|
||||
DW_OP_le
|
||||
DW_OP_lt
|
||||
DW_OP_ne
|
||||
)
|
||||
|
||||
const (
|
||||
DW_OP_lit0 = 0x30
|
||||
DW_OP_lit1 = 0x31
|
||||
DW_OP_lit2 = iota
|
||||
DW_OP_lit3
|
||||
DW_OP_lit4
|
||||
DW_OP_lit5
|
||||
DW_OP_lit6
|
||||
DW_OP_lit7
|
||||
DW_OP_lit8
|
||||
DW_OP_lit9
|
||||
DW_OP_lit10
|
||||
DW_OP_lit11
|
||||
DW_OP_lit12
|
||||
DW_OP_lit13
|
||||
DW_OP_lit14
|
||||
DW_OP_lit15
|
||||
DW_OP_lit16
|
||||
DW_OP_lit17
|
||||
DW_OP_lit18
|
||||
DW_OP_lit19
|
||||
DW_OP_lit20
|
||||
DW_OP_lit21
|
||||
DW_OP_lit22
|
||||
DW_OP_lit23
|
||||
DW_OP_lit24
|
||||
DW_OP_lit25
|
||||
DW_OP_lit26
|
||||
DW_OP_lit27
|
||||
DW_OP_lit28
|
||||
DW_OP_lit29
|
||||
DW_OP_lit30
|
||||
DW_OP_lit31
|
||||
DW_OP_reg0
|
||||
DW_OP_reg1
|
||||
DW_OP_reg2
|
||||
DW_OP_reg3
|
||||
DW_OP_reg4
|
||||
DW_OP_reg5
|
||||
DW_OP_reg6
|
||||
DW_OP_reg7
|
||||
DW_OP_reg8
|
||||
DW_OP_reg9
|
||||
DW_OP_reg10
|
||||
DW_OP_reg11
|
||||
DW_OP_reg12
|
||||
DW_OP_reg13
|
||||
DW_OP_reg14
|
||||
DW_OP_reg15
|
||||
DW_OP_reg16
|
||||
DW_OP_reg17
|
||||
DW_OP_reg18
|
||||
DW_OP_reg19
|
||||
DW_OP_reg20
|
||||
DW_OP_reg21
|
||||
DW_OP_reg22
|
||||
DW_OP_reg23
|
||||
DW_OP_reg24
|
||||
DW_OP_reg25
|
||||
DW_OP_reg26
|
||||
DW_OP_reg27
|
||||
DW_OP_reg28
|
||||
DW_OP_reg29
|
||||
DW_OP_reg30
|
||||
DW_OP_reg31
|
||||
DW_OP_breg0
|
||||
DW_OP_breg1
|
||||
DW_OP_breg2
|
||||
DW_OP_breg3
|
||||
DW_OP_breg4
|
||||
DW_OP_breg5
|
||||
DW_OP_breg6
|
||||
DW_OP_breg7
|
||||
DW_OP_breg8
|
||||
DW_OP_breg9
|
||||
DW_OP_breg10
|
||||
DW_OP_breg11
|
||||
DW_OP_breg12
|
||||
DW_OP_breg13
|
||||
DW_OP_breg14
|
||||
DW_OP_breg15
|
||||
DW_OP_breg16
|
||||
DW_OP_breg17
|
||||
DW_OP_breg18
|
||||
DW_OP_breg19
|
||||
DW_OP_breg20
|
||||
DW_OP_breg21
|
||||
DW_OP_breg22
|
||||
DW_OP_breg23
|
||||
DW_OP_breg24
|
||||
DW_OP_breg25
|
||||
DW_OP_breg26
|
||||
DW_OP_breg27
|
||||
DW_OP_breg28
|
||||
DW_OP_breg29
|
||||
DW_OP_breg30
|
||||
DW_OP_breg31
|
||||
DW_OP_regx
|
||||
DW_OP_fbreg
|
||||
DW_OP_bregx
|
||||
DW_OP_piece
|
||||
DW_OP_deref_size
|
||||
DW_OP_xderef_size
|
||||
DW_OP_nop
|
||||
DW_OP_push_object_address
|
||||
DW_OP_call2
|
||||
DW_OP_call4
|
||||
DW_OP_call_ref
|
||||
DW_OP_form_tls_address
|
||||
DW_OP_call_frame_cfa
|
||||
DW_OP_bit_piece
|
||||
|
||||
DW_OP_lo_user = 0xe0
|
||||
DW_OP_hi_user = 0xff
|
||||
)
|
125
vendor/github.com/derekparker/delve/dwarf/frame/parser.go
generated
vendored
Normal file
125
vendor/github.com/derekparker/delve/dwarf/frame/parser.go
generated
vendored
Normal file
@ -0,0 +1,125 @@
|
||||
// Package frame contains data structures and
|
||||
// related functions for parsing and searching
|
||||
// through Dwarf .debug_frame data.
|
||||
package frame
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/derekparker/delve/dwarf/util"
|
||||
)
|
||||
|
||||
type parsefunc func(*parseContext) parsefunc
|
||||
|
||||
type parseContext struct {
|
||||
buf *bytes.Buffer
|
||||
entries FrameDescriptionEntries
|
||||
common *CommonInformationEntry
|
||||
frame *FrameDescriptionEntry
|
||||
length uint32
|
||||
}
|
||||
|
||||
// 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, order binary.ByteOrder) FrameDescriptionEntries {
|
||||
var (
|
||||
buf = bytes.NewBuffer(data)
|
||||
pctx = &parseContext{buf: buf, entries: NewFrameIndex()}
|
||||
)
|
||||
|
||||
for fn := parselength; buf.Len() != 0; {
|
||||
fn = fn(pctx)
|
||||
}
|
||||
|
||||
for i := range pctx.entries {
|
||||
pctx.entries[i].order = order
|
||||
}
|
||||
|
||||
return pctx.entries
|
||||
}
|
||||
|
||||
func cieEntry(data []byte) bool {
|
||||
return bytes.Equal(data, []byte{0xff, 0xff, 0xff, 0xff})
|
||||
}
|
||||
|
||||
func parselength(ctx *parseContext) parsefunc {
|
||||
var data = ctx.buf.Next(8)
|
||||
|
||||
ctx.length = binary.LittleEndian.Uint32(data[:4]) - 4 // take off the length of the CIE id / CIE pointer.
|
||||
|
||||
if cieEntry(data[4:]) {
|
||||
ctx.common = &CommonInformationEntry{Length: ctx.length}
|
||||
return parseCIE
|
||||
}
|
||||
|
||||
ctx.frame = &FrameDescriptionEntry{Length: ctx.length, CIE: ctx.common}
|
||||
return parseFDE
|
||||
}
|
||||
|
||||
func parseFDE(ctx *parseContext) parsefunc {
|
||||
r := ctx.buf.Next(int(ctx.length))
|
||||
|
||||
ctx.frame.begin = binary.LittleEndian.Uint64(r[:8])
|
||||
ctx.frame.end = binary.LittleEndian.Uint64(r[8:16])
|
||||
|
||||
// Insert into the tree after setting address range begin
|
||||
// otherwise compares won't work.
|
||||
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
|
||||
// cursor to length.
|
||||
ctx.frame.Instructions = r[16:]
|
||||
ctx.length = 0
|
||||
|
||||
return parselength
|
||||
}
|
||||
|
||||
func parseCIE(ctx *parseContext) parsefunc {
|
||||
data := ctx.buf.Next(int(ctx.length))
|
||||
buf := bytes.NewBuffer(data)
|
||||
// parse version
|
||||
ctx.common.Version = data[0]
|
||||
|
||||
// parse augmentation
|
||||
ctx.common.Augmentation, _ = util.ParseString(buf)
|
||||
|
||||
// parse code alignment factor
|
||||
ctx.common.CodeAlignmentFactor, _ = util.DecodeULEB128(buf)
|
||||
|
||||
// parse data alignment factor
|
||||
ctx.common.DataAlignmentFactor, _ = util.DecodeSLEB128(buf)
|
||||
|
||||
// parse return address register
|
||||
ctx.common.ReturnAddressRegister, _ = util.DecodeULEB128(buf)
|
||||
|
||||
// parse initial instructions
|
||||
// The rest of this entry consists of the instructions
|
||||
// so we can just grab all of the data from the buffer
|
||||
// cursor to length.
|
||||
ctx.common.InitialInstructions = buf.Bytes() //ctx.buf.Next(int(ctx.length))
|
||||
ctx.length = 0
|
||||
|
||||
return parselength
|
||||
}
|
||||
|
||||
// DwarfEndian determines the endianness of the DWARF by using the version number field in the debug_info section
|
||||
// Trick borrowed from "debug/dwarf".New()
|
||||
func DwarfEndian(infoSec []byte) binary.ByteOrder {
|
||||
if len(infoSec) < 6 {
|
||||
return binary.BigEndian
|
||||
}
|
||||
x, y := infoSec[4], infoSec[5]
|
||||
switch {
|
||||
case x == 0 && y == 0:
|
||||
return binary.BigEndian
|
||||
case x == 0:
|
||||
return binary.BigEndian
|
||||
case y == 0:
|
||||
return binary.LittleEndian
|
||||
default:
|
||||
return binary.BigEndian
|
||||
}
|
||||
}
|
429
vendor/github.com/derekparker/delve/dwarf/frame/table.go
generated
vendored
Normal file
429
vendor/github.com/derekparker/delve/dwarf/frame/table.go
generated
vendored
Normal file
@ -0,0 +1,429 @@
|
||||
package frame
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
||||
"github.com/derekparker/delve/dwarf/util"
|
||||
)
|
||||
|
||||
type CurrentFrameAddress struct {
|
||||
register uint64
|
||||
offset int64
|
||||
expression []byte
|
||||
rule byte
|
||||
}
|
||||
|
||||
type DWRule struct {
|
||||
rule byte
|
||||
offset int64
|
||||
newreg uint64
|
||||
expression []byte
|
||||
}
|
||||
|
||||
type FrameContext struct {
|
||||
loc uint64
|
||||
order binary.ByteOrder
|
||||
address uint64
|
||||
cfa CurrentFrameAddress
|
||||
regs map[uint64]DWRule
|
||||
initialRegs map[uint64]DWRule
|
||||
prevRegs map[uint64]DWRule
|
||||
buf *bytes.Buffer
|
||||
cie *CommonInformationEntry
|
||||
codeAlignment uint64
|
||||
dataAlignment int64
|
||||
}
|
||||
|
||||
func (fctx *FrameContext) CFAOffset() int64 {
|
||||
return fctx.cfa.offset
|
||||
}
|
||||
|
||||
// Instructions used to recreate the table from the .debug_frame data.
|
||||
const (
|
||||
DW_CFA_nop = 0x0 // No ops
|
||||
DW_CFA_set_loc = 0x01 // op1: address
|
||||
DW_CFA_advance_loc1 = iota // op1: 1-bytes delta
|
||||
DW_CFA_advance_loc2 // op1: 2-byte delta
|
||||
DW_CFA_advance_loc4 // op1: 4-byte delta
|
||||
DW_CFA_offset_extended // op1: ULEB128 register, op2: ULEB128 offset
|
||||
DW_CFA_restore_extended // op1: ULEB128 register
|
||||
DW_CFA_undefined // op1: ULEB128 register
|
||||
DW_CFA_same_value // op1: ULEB128 register
|
||||
DW_CFA_register // op1: ULEB128 register, op2: ULEB128 register
|
||||
DW_CFA_remember_state // No ops
|
||||
DW_CFA_restore_state // No ops
|
||||
DW_CFA_def_cfa // op1: ULEB128 register, op2: ULEB128 offset
|
||||
DW_CFA_def_cfa_register // op1: ULEB128 register
|
||||
DW_CFA_def_cfa_offset // op1: ULEB128 offset
|
||||
DW_CFA_def_cfa_expression // op1: BLOCK
|
||||
DW_CFA_expression // op1: ULEB128 register, op2: BLOCK
|
||||
DW_CFA_offset_extended_sf // op1: ULEB128 register, op2: SLEB128 BLOCK
|
||||
DW_CFA_def_cfa_sf // op1: ULEB128 register, op2: SLEB128 offset
|
||||
DW_CFA_def_cfa_offset_sf // op1: SLEB128 offset
|
||||
DW_CFA_val_offset // op1: ULEB128, op2: ULEB128
|
||||
DW_CFA_val_offset_sf // op1: ULEB128, op2: SLEB128
|
||||
DW_CFA_val_expression // op1: ULEB128, op2: BLOCK
|
||||
DW_CFA_lo_user = 0x1c // op1: BLOCK
|
||||
DW_CFA_hi_user = 0x3f // op1: ULEB128 register, op2: BLOCK
|
||||
DW_CFA_advance_loc = (0x1 << 6) // High 2 bits: 0x1, low 6: delta
|
||||
DW_CFA_offset = (0x2 << 6) // High 2 bits: 0x2, low 6: register
|
||||
DW_CFA_restore = (0x3 << 6) // High 2 bits: 0x3, low 6: register
|
||||
)
|
||||
|
||||
// Rules defined for register values.
|
||||
const (
|
||||
rule_undefined = iota
|
||||
rule_sameval
|
||||
rule_offset
|
||||
rule_valoffset
|
||||
rule_register
|
||||
rule_expression
|
||||
rule_valexpression
|
||||
rule_architectural
|
||||
)
|
||||
|
||||
const low_6_offset = 0x3f
|
||||
|
||||
type instruction func(frame *FrameContext)
|
||||
|
||||
// // Mapping from DWARF opcode to function.
|
||||
var fnlookup = map[byte]instruction{
|
||||
DW_CFA_advance_loc: advanceloc,
|
||||
DW_CFA_offset: offset,
|
||||
DW_CFA_restore: restore,
|
||||
DW_CFA_set_loc: setloc,
|
||||
DW_CFA_advance_loc1: advanceloc1,
|
||||
DW_CFA_advance_loc2: advanceloc2,
|
||||
DW_CFA_advance_loc4: advanceloc4,
|
||||
DW_CFA_offset_extended: offsetextended,
|
||||
DW_CFA_restore_extended: restoreextended,
|
||||
DW_CFA_undefined: undefined,
|
||||
DW_CFA_same_value: samevalue,
|
||||
DW_CFA_register: register,
|
||||
DW_CFA_remember_state: rememberstate,
|
||||
DW_CFA_restore_state: restorestate,
|
||||
DW_CFA_def_cfa: defcfa,
|
||||
DW_CFA_def_cfa_register: defcfaregister,
|
||||
DW_CFA_def_cfa_offset: defcfaoffset,
|
||||
DW_CFA_def_cfa_expression: defcfaexpression,
|
||||
DW_CFA_expression: expression,
|
||||
DW_CFA_offset_extended_sf: offsetextendedsf,
|
||||
DW_CFA_def_cfa_sf: defcfasf,
|
||||
DW_CFA_def_cfa_offset_sf: defcfaoffsetsf,
|
||||
DW_CFA_val_offset: valoffset,
|
||||
DW_CFA_val_offset_sf: valoffsetsf,
|
||||
DW_CFA_val_expression: valexpression,
|
||||
DW_CFA_lo_user: louser,
|
||||
DW_CFA_hi_user: hiuser,
|
||||
}
|
||||
|
||||
func executeCIEInstructions(cie *CommonInformationEntry) *FrameContext {
|
||||
initialInstructions := make([]byte, len(cie.InitialInstructions))
|
||||
copy(initialInstructions, cie.InitialInstructions)
|
||||
frame := &FrameContext{
|
||||
cie: cie,
|
||||
regs: make(map[uint64]DWRule),
|
||||
initialRegs: make(map[uint64]DWRule),
|
||||
prevRegs: make(map[uint64]DWRule),
|
||||
codeAlignment: cie.CodeAlignmentFactor,
|
||||
dataAlignment: cie.DataAlignmentFactor,
|
||||
buf: bytes.NewBuffer(initialInstructions),
|
||||
}
|
||||
|
||||
frame.ExecuteDwarfProgram()
|
||||
return frame
|
||||
}
|
||||
|
||||
// Unwind the stack to find the return address register.
|
||||
func executeDwarfProgramUntilPC(fde *FrameDescriptionEntry, pc uint64) *FrameContext {
|
||||
frame := executeCIEInstructions(fde.CIE)
|
||||
frame.order = fde.order
|
||||
frame.loc = fde.Begin()
|
||||
frame.address = pc
|
||||
fdeInstructions := make([]byte, len(fde.Instructions))
|
||||
copy(fdeInstructions, fde.Instructions)
|
||||
frame.ExecuteUntilPC(fdeInstructions)
|
||||
|
||||
return frame
|
||||
}
|
||||
|
||||
func (frame *FrameContext) ExecuteDwarfProgram() {
|
||||
for frame.buf.Len() > 0 {
|
||||
executeDwarfInstruction(frame)
|
||||
}
|
||||
}
|
||||
|
||||
// Execute dwarf instructions.
|
||||
func (frame *FrameContext) ExecuteUntilPC(instructions []byte) {
|
||||
frame.buf.Truncate(0)
|
||||
frame.buf.Write(instructions)
|
||||
|
||||
// We only need to execute the instructions until
|
||||
// ctx.loc > ctx.addess (which is the address we
|
||||
// are currently at in the traced process).
|
||||
for frame.address >= frame.loc && frame.buf.Len() > 0 {
|
||||
executeDwarfInstruction(frame)
|
||||
}
|
||||
}
|
||||
|
||||
func executeDwarfInstruction(frame *FrameContext) {
|
||||
instruction, err := frame.buf.ReadByte()
|
||||
if err != nil {
|
||||
panic("Could not read from instruction buffer")
|
||||
}
|
||||
|
||||
if instruction == DW_CFA_nop {
|
||||
return
|
||||
}
|
||||
|
||||
fn := lookupFunc(instruction, frame.buf)
|
||||
|
||||
fn(frame)
|
||||
}
|
||||
|
||||
func lookupFunc(instruction byte, buf *bytes.Buffer) instruction {
|
||||
const high_2_bits = 0xc0
|
||||
var restore bool
|
||||
|
||||
// Special case the 3 opcodes that have their argument encoded in the opcode itself.
|
||||
switch instruction & high_2_bits {
|
||||
case DW_CFA_advance_loc:
|
||||
instruction = DW_CFA_advance_loc
|
||||
restore = true
|
||||
|
||||
case DW_CFA_offset:
|
||||
instruction = DW_CFA_offset
|
||||
restore = true
|
||||
|
||||
case DW_CFA_restore:
|
||||
instruction = DW_CFA_restore
|
||||
restore = true
|
||||
}
|
||||
|
||||
if restore {
|
||||
// Restore the last byte as it actually contains the argument for the opcode.
|
||||
err := buf.UnreadByte()
|
||||
if err != nil {
|
||||
panic("Could not unread byte")
|
||||
}
|
||||
}
|
||||
|
||||
fn, ok := fnlookup[instruction]
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("Encountered an unexpected DWARF CFA opcode: %#v", instruction))
|
||||
}
|
||||
|
||||
return fn
|
||||
}
|
||||
|
||||
func advanceloc(frame *FrameContext) {
|
||||
b, err := frame.buf.ReadByte()
|
||||
if err != nil {
|
||||
panic("Could not read byte")
|
||||
}
|
||||
|
||||
delta := b & low_6_offset
|
||||
frame.loc += uint64(delta) * frame.codeAlignment
|
||||
}
|
||||
|
||||
func advanceloc1(frame *FrameContext) {
|
||||
delta, err := frame.buf.ReadByte()
|
||||
if err != nil {
|
||||
panic("Could not read byte")
|
||||
}
|
||||
|
||||
frame.loc += uint64(delta) * frame.codeAlignment
|
||||
}
|
||||
|
||||
func advanceloc2(frame *FrameContext) {
|
||||
var delta uint16
|
||||
binary.Read(frame.buf, frame.order, &delta)
|
||||
|
||||
frame.loc += uint64(delta) * frame.codeAlignment
|
||||
}
|
||||
|
||||
func advanceloc4(frame *FrameContext) {
|
||||
var delta uint32
|
||||
binary.Read(frame.buf, frame.order, &delta)
|
||||
|
||||
frame.loc += uint64(delta) * frame.codeAlignment
|
||||
}
|
||||
|
||||
func offset(frame *FrameContext) {
|
||||
b, err := frame.buf.ReadByte()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
var (
|
||||
reg = b & low_6_offset
|
||||
offset, _ = util.DecodeULEB128(frame.buf)
|
||||
)
|
||||
|
||||
frame.regs[uint64(reg)] = DWRule{offset: int64(offset) * frame.dataAlignment, rule: rule_offset}
|
||||
}
|
||||
|
||||
func restore(frame *FrameContext) {
|
||||
b, err := frame.buf.ReadByte()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
reg := uint64(b & low_6_offset)
|
||||
oldrule, ok := frame.initialRegs[reg]
|
||||
if ok {
|
||||
frame.regs[reg] = DWRule{offset: oldrule.offset, rule: rule_offset}
|
||||
} else {
|
||||
frame.regs[reg] = DWRule{rule: rule_undefined}
|
||||
}
|
||||
}
|
||||
|
||||
func setloc(frame *FrameContext) {
|
||||
var loc uint64
|
||||
binary.Read(frame.buf, frame.order, &loc)
|
||||
|
||||
frame.loc = loc
|
||||
}
|
||||
|
||||
func offsetextended(frame *FrameContext) {
|
||||
var (
|
||||
reg, _ = util.DecodeULEB128(frame.buf)
|
||||
offset, _ = util.DecodeULEB128(frame.buf)
|
||||
)
|
||||
|
||||
frame.regs[reg] = DWRule{offset: int64(offset) * frame.dataAlignment, rule: rule_offset}
|
||||
}
|
||||
|
||||
func undefined(frame *FrameContext) {
|
||||
reg, _ := util.DecodeULEB128(frame.buf)
|
||||
frame.regs[reg] = DWRule{rule: rule_undefined}
|
||||
}
|
||||
|
||||
func samevalue(frame *FrameContext) {
|
||||
reg, _ := util.DecodeULEB128(frame.buf)
|
||||
frame.regs[reg] = DWRule{rule: rule_sameval}
|
||||
}
|
||||
|
||||
func register(frame *FrameContext) {
|
||||
reg1, _ := util.DecodeULEB128(frame.buf)
|
||||
reg2, _ := util.DecodeULEB128(frame.buf)
|
||||
frame.regs[reg1] = DWRule{newreg: reg2, rule: rule_register}
|
||||
}
|
||||
|
||||
func rememberstate(frame *FrameContext) {
|
||||
frame.prevRegs = frame.regs
|
||||
}
|
||||
|
||||
func restorestate(frame *FrameContext) {
|
||||
frame.regs = frame.prevRegs
|
||||
}
|
||||
|
||||
func restoreextended(frame *FrameContext) {
|
||||
reg, _ := util.DecodeULEB128(frame.buf)
|
||||
|
||||
oldrule, ok := frame.initialRegs[reg]
|
||||
if ok {
|
||||
frame.regs[reg] = DWRule{offset: oldrule.offset, rule: rule_offset}
|
||||
} else {
|
||||
frame.regs[reg] = DWRule{rule: rule_undefined}
|
||||
}
|
||||
}
|
||||
|
||||
func defcfa(frame *FrameContext) {
|
||||
reg, _ := util.DecodeULEB128(frame.buf)
|
||||
offset, _ := util.DecodeULEB128(frame.buf)
|
||||
|
||||
frame.cfa.register = reg
|
||||
frame.cfa.offset = int64(offset)
|
||||
}
|
||||
|
||||
func defcfaregister(frame *FrameContext) {
|
||||
reg, _ := util.DecodeULEB128(frame.buf)
|
||||
frame.cfa.register = reg
|
||||
}
|
||||
|
||||
func defcfaoffset(frame *FrameContext) {
|
||||
offset, _ := util.DecodeULEB128(frame.buf)
|
||||
frame.cfa.offset = int64(offset)
|
||||
}
|
||||
|
||||
func defcfasf(frame *FrameContext) {
|
||||
reg, _ := util.DecodeULEB128(frame.buf)
|
||||
offset, _ := util.DecodeSLEB128(frame.buf)
|
||||
|
||||
frame.cfa.register = reg
|
||||
frame.cfa.offset = offset * frame.dataAlignment
|
||||
}
|
||||
|
||||
func defcfaoffsetsf(frame *FrameContext) {
|
||||
offset, _ := util.DecodeSLEB128(frame.buf)
|
||||
offset *= frame.dataAlignment
|
||||
frame.cfa.offset = offset
|
||||
}
|
||||
|
||||
func defcfaexpression(frame *FrameContext) {
|
||||
var (
|
||||
l, _ = util.DecodeULEB128(frame.buf)
|
||||
expr = frame.buf.Next(int(l))
|
||||
)
|
||||
|
||||
frame.cfa.expression = expr
|
||||
frame.cfa.rule = rule_expression
|
||||
}
|
||||
|
||||
func expression(frame *FrameContext) {
|
||||
var (
|
||||
reg, _ = util.DecodeULEB128(frame.buf)
|
||||
l, _ = util.DecodeULEB128(frame.buf)
|
||||
expr = frame.buf.Next(int(l))
|
||||
)
|
||||
|
||||
frame.regs[reg] = DWRule{rule: rule_expression, expression: expr}
|
||||
}
|
||||
|
||||
func offsetextendedsf(frame *FrameContext) {
|
||||
var (
|
||||
reg, _ = util.DecodeULEB128(frame.buf)
|
||||
offset, _ = util.DecodeSLEB128(frame.buf)
|
||||
)
|
||||
|
||||
frame.regs[reg] = DWRule{offset: offset * frame.dataAlignment, rule: rule_offset}
|
||||
}
|
||||
|
||||
func valoffset(frame *FrameContext) {
|
||||
var (
|
||||
reg, _ = util.DecodeULEB128(frame.buf)
|
||||
offset, _ = util.DecodeULEB128(frame.buf)
|
||||
)
|
||||
|
||||
frame.regs[reg] = DWRule{offset: int64(offset), rule: rule_valoffset}
|
||||
}
|
||||
|
||||
func valoffsetsf(frame *FrameContext) {
|
||||
var (
|
||||
reg, _ = util.DecodeULEB128(frame.buf)
|
||||
offset, _ = util.DecodeSLEB128(frame.buf)
|
||||
)
|
||||
|
||||
frame.regs[reg] = DWRule{offset: offset * frame.dataAlignment, rule: rule_valoffset}
|
||||
}
|
||||
|
||||
func valexpression(frame *FrameContext) {
|
||||
var (
|
||||
reg, _ = util.DecodeULEB128(frame.buf)
|
||||
l, _ = util.DecodeULEB128(frame.buf)
|
||||
expr = frame.buf.Next(int(l))
|
||||
)
|
||||
|
||||
frame.regs[reg] = DWRule{rule: rule_valexpression, expression: expr}
|
||||
}
|
||||
|
||||
func louser(frame *FrameContext) {
|
||||
frame.buf.Next(1)
|
||||
}
|
||||
|
||||
func hiuser(frame *FrameContext) {
|
||||
frame.buf.Next(1)
|
||||
}
|
122
vendor/github.com/derekparker/delve/dwarf/line/line_parser.go
generated
vendored
Normal file
122
vendor/github.com/derekparker/delve/dwarf/line/line_parser.go
generated
vendored
Normal file
@ -0,0 +1,122 @@
|
||||
package line
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/derekparker/delve/dwarf/util"
|
||||
)
|
||||
|
||||
type DebugLinePrologue struct {
|
||||
UnitLength uint32
|
||||
Version uint16
|
||||
Length uint32
|
||||
MinInstrLength uint8
|
||||
InitialIsStmt uint8
|
||||
LineBase int8
|
||||
LineRange uint8
|
||||
OpcodeBase uint8
|
||||
StdOpLengths []uint8
|
||||
}
|
||||
|
||||
type DebugLineInfo struct {
|
||||
Prologue *DebugLinePrologue
|
||||
IncludeDirs []string
|
||||
FileNames []*FileEntry
|
||||
Instructions []byte
|
||||
Lookup map[string]*FileEntry
|
||||
}
|
||||
|
||||
type FileEntry struct {
|
||||
Name string
|
||||
DirIdx uint64
|
||||
LastModTime uint64
|
||||
Length uint64
|
||||
}
|
||||
|
||||
type DebugLines []*DebugLineInfo
|
||||
|
||||
func (d *DebugLines) GetLineInfo(name string) *DebugLineInfo {
|
||||
// Find in which table file exists and return it.
|
||||
for _, l := range *d {
|
||||
if _, ok := l.Lookup[name]; ok {
|
||||
return l
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Parse(data []byte) DebugLines {
|
||||
var (
|
||||
lines = make(DebugLines, 0)
|
||||
buf = bytes.NewBuffer(data)
|
||||
)
|
||||
|
||||
// We have to parse multiple file name tables here.
|
||||
for buf.Len() > 0 {
|
||||
dbl := new(DebugLineInfo)
|
||||
dbl.Lookup = make(map[string]*FileEntry)
|
||||
|
||||
parseDebugLinePrologue(dbl, buf)
|
||||
parseIncludeDirs(dbl, buf)
|
||||
parseFileEntries(dbl, buf)
|
||||
|
||||
// Instructions size calculation breakdown:
|
||||
// - dbl.Prologue.UnitLength is the length of the entire unit, not including the 4 bytes to represent that length.
|
||||
// - dbl.Prologue.Length is the length of the prologue not including unit length, version or prologue length itself.
|
||||
// - So you have UnitLength - PrologueLength - (version_length_bytes(2) + prologue_length_bytes(4)).
|
||||
dbl.Instructions = buf.Next(int(dbl.Prologue.UnitLength - dbl.Prologue.Length - 6))
|
||||
|
||||
lines = append(lines, dbl)
|
||||
}
|
||||
|
||||
return lines
|
||||
}
|
||||
|
||||
func parseDebugLinePrologue(dbl *DebugLineInfo, buf *bytes.Buffer) {
|
||||
p := new(DebugLinePrologue)
|
||||
|
||||
p.UnitLength = binary.LittleEndian.Uint32(buf.Next(4))
|
||||
p.Version = binary.LittleEndian.Uint16(buf.Next(2))
|
||||
p.Length = binary.LittleEndian.Uint32(buf.Next(4))
|
||||
p.MinInstrLength = uint8(buf.Next(1)[0])
|
||||
p.InitialIsStmt = uint8(buf.Next(1)[0])
|
||||
p.LineBase = int8(buf.Next(1)[0])
|
||||
p.LineRange = uint8(buf.Next(1)[0])
|
||||
p.OpcodeBase = uint8(buf.Next(1)[0])
|
||||
|
||||
p.StdOpLengths = make([]uint8, p.OpcodeBase-1)
|
||||
binary.Read(buf, binary.LittleEndian, &p.StdOpLengths)
|
||||
|
||||
dbl.Prologue = p
|
||||
}
|
||||
|
||||
func parseIncludeDirs(info *DebugLineInfo, buf *bytes.Buffer) {
|
||||
for {
|
||||
str, _ := util.ParseString(buf)
|
||||
if str == "" {
|
||||
break
|
||||
}
|
||||
|
||||
info.IncludeDirs = append(info.IncludeDirs, str)
|
||||
}
|
||||
}
|
||||
|
||||
func parseFileEntries(info *DebugLineInfo, buf *bytes.Buffer) {
|
||||
for {
|
||||
entry := new(FileEntry)
|
||||
|
||||
name, _ := util.ParseString(buf)
|
||||
if name == "" {
|
||||
break
|
||||
}
|
||||
|
||||
entry.Name = name
|
||||
entry.DirIdx, _ = util.DecodeULEB128(buf)
|
||||
entry.LastModTime, _ = util.DecodeULEB128(buf)
|
||||
entry.Length, _ = util.DecodeULEB128(buf)
|
||||
|
||||
info.FileNames = append(info.FileNames, entry)
|
||||
info.Lookup[name] = entry
|
||||
}
|
||||
}
|
252
vendor/github.com/derekparker/delve/dwarf/line/state_machine.go
generated
vendored
Normal file
252
vendor/github.com/derekparker/delve/dwarf/line/state_machine.go
generated
vendored
Normal file
@ -0,0 +1,252 @@
|
||||
package line
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/derekparker/delve/dwarf/util"
|
||||
)
|
||||
|
||||
type Location struct {
|
||||
File string
|
||||
Line int
|
||||
Address uint64
|
||||
Delta int
|
||||
}
|
||||
|
||||
type StateMachine struct {
|
||||
dbl *DebugLineInfo
|
||||
file string
|
||||
line int
|
||||
address uint64
|
||||
column uint
|
||||
isStmt bool
|
||||
basicBlock bool
|
||||
endSeq bool
|
||||
lastWasStandard bool
|
||||
lastDelta int
|
||||
}
|
||||
|
||||
type opcodefn func(*StateMachine, *bytes.Buffer)
|
||||
|
||||
// Special opcodes
|
||||
const (
|
||||
DW_LNS_copy = 1
|
||||
DW_LNS_advance_pc = 2
|
||||
DW_LNS_advance_line = 3
|
||||
DW_LNS_set_file = 4
|
||||
DW_LNS_set_column = 5
|
||||
DW_LNS_negate_stmt = 6
|
||||
DW_LNS_set_basic_block = 7
|
||||
DW_LNS_const_add_pc = 8
|
||||
DW_LNS_fixed_advance_pc = 9
|
||||
)
|
||||
|
||||
// Extended opcodes
|
||||
const (
|
||||
DW_LINE_end_sequence = 1
|
||||
DW_LINE_set_address = 2
|
||||
DW_LINE_define_file = 3
|
||||
)
|
||||
|
||||
var standardopcodes = map[byte]opcodefn{
|
||||
DW_LNS_copy: copyfn,
|
||||
DW_LNS_advance_pc: advancepc,
|
||||
DW_LNS_advance_line: advanceline,
|
||||
DW_LNS_set_file: setfile,
|
||||
DW_LNS_set_column: setcolumn,
|
||||
DW_LNS_negate_stmt: negatestmt,
|
||||
DW_LNS_set_basic_block: setbasicblock,
|
||||
DW_LNS_const_add_pc: constaddpc,
|
||||
DW_LNS_fixed_advance_pc: fixedadvancepc,
|
||||
}
|
||||
|
||||
var extendedopcodes = map[byte]opcodefn{
|
||||
DW_LINE_end_sequence: endsequence,
|
||||
DW_LINE_set_address: setaddress,
|
||||
DW_LINE_define_file: definefile,
|
||||
}
|
||||
|
||||
func newStateMachine(dbl *DebugLineInfo) *StateMachine {
|
||||
return &StateMachine{dbl: dbl, file: dbl.FileNames[0].Name, line: 1}
|
||||
}
|
||||
|
||||
// Returns all PCs for a given file/line. Useful for loops where the 'for' line
|
||||
// could be split amongst 2 PCs.
|
||||
func (dbl *DebugLines) AllPCsForFileLine(f string, l int) (pcs []uint64) {
|
||||
var (
|
||||
foundFile bool
|
||||
lastAddr uint64
|
||||
lineInfo = dbl.GetLineInfo(f)
|
||||
sm = newStateMachine(lineInfo)
|
||||
buf = bytes.NewBuffer(lineInfo.Instructions)
|
||||
)
|
||||
|
||||
for b, err := buf.ReadByte(); err == nil; b, err = buf.ReadByte() {
|
||||
findAndExecOpcode(sm, buf, b)
|
||||
if foundFile && sm.file != f {
|
||||
return
|
||||
}
|
||||
if sm.line == l && sm.file == f && sm.address != lastAddr {
|
||||
foundFile = true
|
||||
pcs = append(pcs, sm.address)
|
||||
line := sm.line
|
||||
// Keep going until we're on a different line. We only care about
|
||||
// when a line comes back around (i.e. for loop) so get to next line,
|
||||
// and try to find the line we care about again.
|
||||
for b, err := buf.ReadByte(); err == nil; b, err = buf.ReadByte() {
|
||||
findAndExecOpcode(sm, buf, b)
|
||||
if line < sm.line {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var NoSourceError = errors.New("no source available")
|
||||
|
||||
func (dbl *DebugLines) AllPCsBetween(begin, end uint64, filename string) ([]uint64, error) {
|
||||
lineInfo := dbl.GetLineInfo(filename)
|
||||
if lineInfo == nil {
|
||||
return nil, NoSourceError
|
||||
}
|
||||
var (
|
||||
pcs []uint64
|
||||
lastaddr uint64
|
||||
sm = newStateMachine(lineInfo)
|
||||
buf = bytes.NewBuffer(lineInfo.Instructions)
|
||||
)
|
||||
|
||||
for b, err := buf.ReadByte(); err == nil; b, err = buf.ReadByte() {
|
||||
findAndExecOpcode(sm, buf, b)
|
||||
if sm.address > end {
|
||||
break
|
||||
}
|
||||
if sm.address >= begin && sm.address > lastaddr {
|
||||
lastaddr = sm.address
|
||||
pcs = append(pcs, sm.address)
|
||||
}
|
||||
}
|
||||
return pcs, nil
|
||||
}
|
||||
|
||||
func findAndExecOpcode(sm *StateMachine, buf *bytes.Buffer, b byte) {
|
||||
switch {
|
||||
case b == 0:
|
||||
execExtendedOpcode(sm, b, buf)
|
||||
case b < sm.dbl.Prologue.OpcodeBase:
|
||||
execStandardOpcode(sm, b, buf)
|
||||
default:
|
||||
execSpecialOpcode(sm, b)
|
||||
}
|
||||
}
|
||||
|
||||
func execSpecialOpcode(sm *StateMachine, instr byte) {
|
||||
var (
|
||||
opcode = uint8(instr)
|
||||
decoded = opcode - sm.dbl.Prologue.OpcodeBase
|
||||
)
|
||||
|
||||
if sm.dbl.Prologue.InitialIsStmt == uint8(1) {
|
||||
sm.isStmt = true
|
||||
}
|
||||
|
||||
sm.lastDelta = int(sm.dbl.Prologue.LineBase + int8(decoded%sm.dbl.Prologue.LineRange))
|
||||
sm.line += sm.lastDelta
|
||||
sm.address += uint64(decoded / sm.dbl.Prologue.LineRange)
|
||||
sm.basicBlock = false
|
||||
sm.lastWasStandard = false
|
||||
}
|
||||
|
||||
func execExtendedOpcode(sm *StateMachine, instr byte, buf *bytes.Buffer) {
|
||||
_, _ = util.DecodeULEB128(buf)
|
||||
b, _ := buf.ReadByte()
|
||||
fn, ok := extendedopcodes[b]
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("Encountered unknown extended opcode %#v\n", b))
|
||||
}
|
||||
sm.lastWasStandard = false
|
||||
|
||||
fn(sm, buf)
|
||||
}
|
||||
|
||||
func execStandardOpcode(sm *StateMachine, instr byte, buf *bytes.Buffer) {
|
||||
fn, ok := standardopcodes[instr]
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("Encountered unknown standard opcode %#v\n", instr))
|
||||
}
|
||||
sm.lastWasStandard = true
|
||||
|
||||
fn(sm, buf)
|
||||
}
|
||||
|
||||
func copyfn(sm *StateMachine, buf *bytes.Buffer) {
|
||||
sm.basicBlock = false
|
||||
}
|
||||
|
||||
func advancepc(sm *StateMachine, buf *bytes.Buffer) {
|
||||
addr, _ := util.DecodeULEB128(buf)
|
||||
sm.address += addr * uint64(sm.dbl.Prologue.MinInstrLength)
|
||||
}
|
||||
|
||||
func advanceline(sm *StateMachine, buf *bytes.Buffer) {
|
||||
line, _ := util.DecodeSLEB128(buf)
|
||||
sm.line += int(line)
|
||||
sm.lastDelta = int(line)
|
||||
}
|
||||
|
||||
func setfile(sm *StateMachine, buf *bytes.Buffer) {
|
||||
i, _ := util.DecodeULEB128(buf)
|
||||
sm.file = sm.dbl.FileNames[i-1].Name
|
||||
}
|
||||
|
||||
func setcolumn(sm *StateMachine, buf *bytes.Buffer) {
|
||||
c, _ := util.DecodeULEB128(buf)
|
||||
sm.column = uint(c)
|
||||
}
|
||||
|
||||
func negatestmt(sm *StateMachine, buf *bytes.Buffer) {
|
||||
sm.isStmt = !sm.isStmt
|
||||
}
|
||||
|
||||
func setbasicblock(sm *StateMachine, buf *bytes.Buffer) {
|
||||
sm.basicBlock = true
|
||||
}
|
||||
|
||||
func constaddpc(sm *StateMachine, buf *bytes.Buffer) {
|
||||
sm.address += (255 / uint64(sm.dbl.Prologue.LineRange))
|
||||
}
|
||||
|
||||
func fixedadvancepc(sm *StateMachine, buf *bytes.Buffer) {
|
||||
var operand uint16
|
||||
binary.Read(buf, binary.LittleEndian, &operand)
|
||||
|
||||
sm.address += uint64(operand)
|
||||
}
|
||||
|
||||
func endsequence(sm *StateMachine, buf *bytes.Buffer) {
|
||||
sm.endSeq = true
|
||||
}
|
||||
|
||||
func setaddress(sm *StateMachine, buf *bytes.Buffer) {
|
||||
var addr uint64
|
||||
|
||||
binary.Read(buf, binary.LittleEndian, &addr)
|
||||
|
||||
sm.address = addr
|
||||
}
|
||||
|
||||
func definefile(sm *StateMachine, buf *bytes.Buffer) {
|
||||
var (
|
||||
_, _ = util.ParseString(buf)
|
||||
_, _ = util.DecodeULEB128(buf)
|
||||
_, _ = util.DecodeULEB128(buf)
|
||||
_, _ = util.DecodeULEB128(buf)
|
||||
)
|
||||
|
||||
// Don't do anything here yet.
|
||||
}
|
84
vendor/github.com/derekparker/delve/dwarf/op/op.go
generated
vendored
Normal file
84
vendor/github.com/derekparker/delve/dwarf/op/op.go
generated
vendored
Normal file
@ -0,0 +1,84 @@
|
||||
package op
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/derekparker/delve/dwarf/util"
|
||||
)
|
||||
|
||||
const (
|
||||
DW_OP_addr = 0x3
|
||||
DW_OP_call_frame_cfa = 0x9c
|
||||
DW_OP_plus = 0x22
|
||||
DW_OP_consts = 0x11
|
||||
DW_OP_plus_uconsts = 0x23
|
||||
)
|
||||
|
||||
type stackfn func(*bytes.Buffer, []int64, int64) ([]int64, error)
|
||||
|
||||
var oplut = map[byte]stackfn{
|
||||
DW_OP_call_frame_cfa: callframecfa,
|
||||
DW_OP_plus: plus,
|
||||
DW_OP_consts: consts,
|
||||
DW_OP_addr: addr,
|
||||
DW_OP_plus_uconsts: plusuconsts,
|
||||
}
|
||||
|
||||
func ExecuteStackProgram(cfa int64, instructions []byte) (int64, error) {
|
||||
stack := make([]int64, 0, 3)
|
||||
buf := bytes.NewBuffer(instructions)
|
||||
|
||||
for opcode, err := buf.ReadByte(); err == nil; opcode, err = buf.ReadByte() {
|
||||
fn, ok := oplut[opcode]
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("invalid instruction %#v", opcode)
|
||||
}
|
||||
|
||||
stack, err = fn(buf, stack, cfa)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
if len(stack) == 0 {
|
||||
return 0, errors.New("empty OP stack")
|
||||
}
|
||||
|
||||
return stack[len(stack)-1], nil
|
||||
}
|
||||
|
||||
func callframecfa(buf *bytes.Buffer, stack []int64, cfa int64) ([]int64, error) {
|
||||
if cfa == 0 {
|
||||
return stack, fmt.Errorf("Could not retrieve CFA for current PC")
|
||||
}
|
||||
return append(stack, int64(cfa)), nil
|
||||
}
|
||||
|
||||
func addr(buf *bytes.Buffer, stack []int64, cfa int64) ([]int64, error) {
|
||||
return append(stack, int64(binary.LittleEndian.Uint64(buf.Next(8)))), nil
|
||||
}
|
||||
|
||||
func plus(buf *bytes.Buffer, stack []int64, cfa int64) ([]int64, error) {
|
||||
var (
|
||||
slen = len(stack)
|
||||
digits = stack[slen-2 : slen]
|
||||
st = stack[:slen-2]
|
||||
)
|
||||
|
||||
return append(st, digits[0]+digits[1]), nil
|
||||
}
|
||||
|
||||
func plusuconsts(buf *bytes.Buffer, stack []int64, cfa int64) ([]int64, error) {
|
||||
slen := len(stack)
|
||||
num, _ := util.DecodeULEB128(buf)
|
||||
stack[slen-1] = stack[slen-1] + int64(num)
|
||||
return stack, nil
|
||||
}
|
||||
|
||||
func consts(buf *bytes.Buffer, stack []int64, cfa int64) ([]int64, error) {
|
||||
num, _ := util.DecodeSLEB128(buf)
|
||||
return append(stack, num), nil
|
||||
}
|
345
vendor/github.com/derekparker/delve/dwarf/reader/reader.go
generated
vendored
Executable file
345
vendor/github.com/derekparker/delve/dwarf/reader/reader.go
generated
vendored
Executable file
@ -0,0 +1,345 @@
|
||||
package reader
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/debug/dwarf"
|
||||
"github.com/derekparker/delve/dwarf/op"
|
||||
)
|
||||
|
||||
type Reader struct {
|
||||
*dwarf.Reader
|
||||
depth int
|
||||
}
|
||||
|
||||
// New returns a reader for the specified dwarf data.
|
||||
func New(data *dwarf.Data) *Reader {
|
||||
return &Reader{data.Reader(), 0}
|
||||
}
|
||||
|
||||
// Seek moves the reader to an arbitrary offset.
|
||||
func (reader *Reader) Seek(off dwarf.Offset) {
|
||||
reader.depth = 0
|
||||
reader.Reader.Seek(off)
|
||||
}
|
||||
|
||||
// SeekToEntry moves the reader to an arbitrary entry.
|
||||
func (reader *Reader) SeekToEntry(entry *dwarf.Entry) error {
|
||||
reader.Seek(entry.Offset)
|
||||
// Consume the current entry so .Next works as intended
|
||||
_, err := reader.Next()
|
||||
return err
|
||||
}
|
||||
|
||||
// SeekToFunctionEntry moves the reader to the function that includes the
|
||||
// specified program counter.
|
||||
func (reader *Reader) SeekToFunction(pc uint64) (*dwarf.Entry, error) {
|
||||
reader.Seek(0)
|
||||
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if entry.Tag != dwarf.TagSubprogram {
|
||||
continue
|
||||
}
|
||||
|
||||
lowpc, ok := entry.Val(dwarf.AttrLowpc).(uint64)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
highpc, ok := entry.Val(dwarf.AttrHighpc).(uint64)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if lowpc <= pc && highpc > pc {
|
||||
return entry, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("unable to find function context")
|
||||
}
|
||||
|
||||
// Returns the address for the named entry.
|
||||
func (reader *Reader) AddrFor(name string) (uint64, error) {
|
||||
entry, err := reader.FindEntryNamed(name, false)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
instructions, ok := entry.Val(dwarf.AttrLocation).([]byte)
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("type assertion failed")
|
||||
}
|
||||
addr, err := op.ExecuteStackProgram(0, instructions)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uint64(addr), nil
|
||||
}
|
||||
|
||||
// Returns the address for the named struct member. Expects the reader to be at the parent entry
|
||||
// or one of the parents children, thus does not seek to parent by itself.
|
||||
func (reader *Reader) AddrForMember(member string, initialInstructions []byte) (uint64, error) {
|
||||
for {
|
||||
entry, err := reader.NextMemberVariable()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if entry == nil {
|
||||
return 0, fmt.Errorf("nil entry for member named %s", member)
|
||||
}
|
||||
name, ok := entry.Val(dwarf.AttrName).(string)
|
||||
if !ok || name != member {
|
||||
continue
|
||||
}
|
||||
instructions, ok := entry.Val(dwarf.AttrDataMemberLoc).([]byte)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
addr, err := op.ExecuteStackProgram(0, append(initialInstructions, instructions...))
|
||||
return uint64(addr), err
|
||||
}
|
||||
}
|
||||
|
||||
var TypeNotFoundErr = errors.New("no type entry found, use 'types' for a list of valid types")
|
||||
|
||||
// SeekToType moves the reader to the type specified by the entry,
|
||||
// optionally resolving typedefs and pointer types. If the reader is set
|
||||
// to a struct type the NextMemberVariable call can be used to walk all member data.
|
||||
func (reader *Reader) SeekToType(entry *dwarf.Entry, resolveTypedefs bool, resolvePointerTypes bool) (*dwarf.Entry, error) {
|
||||
offset, ok := entry.Val(dwarf.AttrType).(dwarf.Offset)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("entry does not have a type attribute")
|
||||
}
|
||||
|
||||
// Seek to the first type offset
|
||||
reader.Seek(offset)
|
||||
|
||||
// Walk the types to the base
|
||||
for typeEntry, err := reader.Next(); typeEntry != nil; typeEntry, err = reader.Next() {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if typeEntry.Tag == dwarf.TagTypedef && !resolveTypedefs {
|
||||
return typeEntry, nil
|
||||
}
|
||||
|
||||
if typeEntry.Tag == dwarf.TagPointerType && !resolvePointerTypes {
|
||||
return typeEntry, nil
|
||||
}
|
||||
|
||||
offset, ok = typeEntry.Val(dwarf.AttrType).(dwarf.Offset)
|
||||
if !ok {
|
||||
return typeEntry, nil
|
||||
}
|
||||
|
||||
reader.Seek(offset)
|
||||
}
|
||||
|
||||
return nil, TypeNotFoundErr
|
||||
}
|
||||
|
||||
func (reader *Reader) NextType() (*dwarf.Entry, error) {
|
||||
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch entry.Tag {
|
||||
case dwarf.TagArrayType, dwarf.TagBaseType, dwarf.TagClassType, dwarf.TagStructType, dwarf.TagUnionType, dwarf.TagConstType, dwarf.TagVolatileType, dwarf.TagRestrictType, dwarf.TagEnumerationType, dwarf.TagPointerType, dwarf.TagSubroutineType, dwarf.TagTypedef, dwarf.TagUnspecifiedType:
|
||||
return entry, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// SeekToTypeNamed moves the reader to the type specified by the name.
|
||||
// If the reader is set to a struct type the NextMemberVariable call
|
||||
// can be used to walk all member data.
|
||||
func (reader *Reader) SeekToTypeNamed(name string) (*dwarf.Entry, error) {
|
||||
// Walk the types to the base
|
||||
for entry, err := reader.NextType(); entry != nil; entry, err = reader.NextType() {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
n, ok := entry.Val(dwarf.AttrName).(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if n == name {
|
||||
return entry, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, TypeNotFoundErr
|
||||
}
|
||||
|
||||
// Finds the entry for 'name'.
|
||||
func (reader *Reader) FindEntryNamed(name string, member bool) (*dwarf.Entry, error) {
|
||||
depth := 1
|
||||
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if entry.Children {
|
||||
depth++
|
||||
}
|
||||
|
||||
if entry.Tag == 0 {
|
||||
depth--
|
||||
if depth <= 0 {
|
||||
return nil, fmt.Errorf("could not find symbol value for %s", name)
|
||||
}
|
||||
}
|
||||
|
||||
if member {
|
||||
if entry.Tag != dwarf.TagMember {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
if entry.Tag != dwarf.TagVariable && entry.Tag != dwarf.TagFormalParameter && entry.Tag != dwarf.TagStructType {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
n, ok := entry.Val(dwarf.AttrName).(string)
|
||||
if !ok || n != name {
|
||||
continue
|
||||
}
|
||||
return entry, nil
|
||||
}
|
||||
return nil, fmt.Errorf("could not find symbol value for %s", name)
|
||||
}
|
||||
|
||||
func (reader *Reader) InstructionsForEntryNamed(name string, member bool) ([]byte, error) {
|
||||
entry, err := reader.FindEntryNamed(name, member)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var attr dwarf.Attr
|
||||
if member {
|
||||
attr = dwarf.AttrDataMemberLoc
|
||||
} else {
|
||||
attr = dwarf.AttrLocation
|
||||
}
|
||||
instr, ok := entry.Val(attr).([]byte)
|
||||
if !ok {
|
||||
return nil, errors.New("invalid typecast for Dwarf instructions")
|
||||
}
|
||||
return instr, nil
|
||||
}
|
||||
|
||||
func (reader *Reader) InstructionsForEntry(entry *dwarf.Entry) ([]byte, error) {
|
||||
if entry.Tag == dwarf.TagMember {
|
||||
instructions, ok := entry.Val(dwarf.AttrDataMemberLoc).([]byte)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("member data has no data member location attribute")
|
||||
}
|
||||
// clone slice to prevent stomping on the dwarf data
|
||||
return append([]byte{}, instructions...), nil
|
||||
}
|
||||
|
||||
// non-member
|
||||
instructions, ok := entry.Val(dwarf.AttrLocation).([]byte)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("entry has no location attribute")
|
||||
}
|
||||
|
||||
// clone slice to prevent stomping on the dwarf data
|
||||
return append([]byte{}, instructions...), nil
|
||||
}
|
||||
|
||||
// NextScopeVariable moves the reader to the next debug entry that describes a local variable and returns the entry.
|
||||
func (reader *Reader) NextScopeVariable() (*dwarf.Entry, error) {
|
||||
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// All scope variables will be at the same depth
|
||||
reader.SkipChildren()
|
||||
|
||||
// End of the current depth
|
||||
if entry.Tag == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
if entry.Tag == dwarf.TagVariable || entry.Tag == dwarf.TagFormalParameter {
|
||||
return entry, nil
|
||||
}
|
||||
}
|
||||
|
||||
// No more items
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// NextMememberVariable moves the reader to the next debug entry that describes a member variable and returns the entry.
|
||||
func (reader *Reader) NextMemberVariable() (*dwarf.Entry, error) {
|
||||
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// All member variables will be at the same depth
|
||||
reader.SkipChildren()
|
||||
|
||||
// End of the current depth
|
||||
if entry.Tag == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
if entry.Tag == dwarf.TagMember {
|
||||
return entry, nil
|
||||
}
|
||||
}
|
||||
|
||||
// No more items
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// NextPackageVariable moves the reader to the next debug entry that describes a package variable.
|
||||
// Any TagVariable entry that is not inside a sub prgram entry and is marked external is considered a package variable.
|
||||
func (reader *Reader) NextPackageVariable() (*dwarf.Entry, error) {
|
||||
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if entry.Tag == dwarf.TagVariable {
|
||||
ext, ok := entry.Val(dwarf.AttrExternal).(bool)
|
||||
if ok && ext {
|
||||
return entry, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore everything inside sub programs
|
||||
if entry.Tag == dwarf.TagSubprogram {
|
||||
reader.SkipChildren()
|
||||
}
|
||||
}
|
||||
|
||||
// No more items
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (reader *Reader) NextCompileUnit() (*dwarf.Entry, error) {
|
||||
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if entry.Tag == dwarf.TagCompileUnit {
|
||||
return entry, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
81
vendor/github.com/derekparker/delve/dwarf/util/util.go
generated
vendored
Normal file
81
vendor/github.com/derekparker/delve/dwarf/util/util.go
generated
vendored
Normal file
@ -0,0 +1,81 @@
|
||||
package util
|
||||
|
||||
import "bytes"
|
||||
|
||||
// DecodeULEB128 decodes an unsigned Little Endian Base 128
|
||||
// represented number.
|
||||
func DecodeULEB128(buf *bytes.Buffer) (uint64, uint32) {
|
||||
var (
|
||||
result uint64
|
||||
shift uint64
|
||||
length uint32
|
||||
)
|
||||
|
||||
if buf.Len() == 0 {
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
for {
|
||||
b, err := buf.ReadByte()
|
||||
if err != nil {
|
||||
panic("Could not parse ULEB128 value")
|
||||
}
|
||||
length++
|
||||
|
||||
result |= uint64((uint(b) & 0x7f) << shift)
|
||||
|
||||
// If high order bit is 1.
|
||||
if b&0x80 == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
shift += 7
|
||||
}
|
||||
|
||||
return result, length
|
||||
}
|
||||
|
||||
// DecodeSLEB128 decodes a signed Little Endian Base 128
|
||||
// represented number.
|
||||
func DecodeSLEB128(buf *bytes.Buffer) (int64, uint32) {
|
||||
var (
|
||||
b byte
|
||||
err error
|
||||
result int64
|
||||
shift uint64
|
||||
length uint32
|
||||
)
|
||||
|
||||
if buf.Len() == 0 {
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
for {
|
||||
b, err = buf.ReadByte()
|
||||
if err != nil {
|
||||
panic("Could not parse SLEB128 value")
|
||||
}
|
||||
length++
|
||||
|
||||
result |= int64((int64(b) & 0x7f) << shift)
|
||||
shift += 7
|
||||
if b&0x80 == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (shift < 8*uint64(length)) && (b&0x40 > 0) {
|
||||
result |= -(1 << shift)
|
||||
}
|
||||
|
||||
return result, length
|
||||
}
|
||||
|
||||
func ParseString(data *bytes.Buffer) (string, uint32) {
|
||||
str, err := data.ReadString(0x0)
|
||||
if err != nil {
|
||||
panic("Could not parse string")
|
||||
}
|
||||
|
||||
return str[:len(str)-1], uint32(len(str))
|
||||
}
|
Reference in New Issue
Block a user