pkg/proc, pkg/dwarf/op: support DW_OP_piece, DW_OP_regX, DW_OP_fbreg
These are emitted by C compilers but also by the current development version of the go compiler with the dwarflocationlists flag.
This commit is contained in:
parent
f098915192
commit
99cad1044b
@ -34,7 +34,7 @@ func New() *Builder {
|
||||
}
|
||||
|
||||
// Build closes b and returns all the dwarf sections.
|
||||
func (b *Builder) Build() (abbrev, aranges, frame, info, line, pubnames, ranges, str []byte, err error) {
|
||||
func (b *Builder) Build() (abbrev, aranges, frame, info, line, pubnames, ranges, str, loc []byte, err error) {
|
||||
b.TagClose()
|
||||
|
||||
if len(b.tagStack) > 0 {
|
||||
@ -45,6 +45,7 @@ func (b *Builder) Build() (abbrev, aranges, frame, info, line, pubnames, ranges,
|
||||
abbrev = b.makeAbbrevTable()
|
||||
info = b.info.Bytes()
|
||||
binary.LittleEndian.PutUint32(info, uint32(len(info)-4))
|
||||
loc = b.loc.Bytes()
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -9,34 +9,33 @@ import (
|
||||
"github.com/derekparker/delve/pkg/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 Opcode byte
|
||||
|
||||
type stackfn func(byte, *context) error
|
||||
//go:generate go run ../../../scripts/gen-opcodes.go opcodes.table opcodes.go
|
||||
|
||||
type stackfn func(Opcode, *context) error
|
||||
|
||||
type context struct {
|
||||
buf *bytes.Buffer
|
||||
stack []int64
|
||||
buf *bytes.Buffer
|
||||
stack []int64
|
||||
pieces []Piece
|
||||
reg bool
|
||||
|
||||
DwarfRegisters
|
||||
}
|
||||
|
||||
type Opcode byte
|
||||
|
||||
var oplut = map[Opcode]stackfn{
|
||||
DW_OP_call_frame_cfa: callframecfa,
|
||||
DW_OP_plus: plus,
|
||||
DW_OP_consts: consts,
|
||||
DW_OP_addr: addr,
|
||||
DW_OP_plus_uconst: plusuconsts,
|
||||
// Piece is a piece of memory stored either at an addres or in a register.
|
||||
type Piece struct {
|
||||
Size int
|
||||
Addr int64
|
||||
RegNum uint64
|
||||
IsRegister bool
|
||||
}
|
||||
|
||||
func ExecuteStackProgram(regs DwarfRegisters, instructions []byte) (int64, error) {
|
||||
// ExecuteStackProgram executes a DWARF location expression and returns
|
||||
// either an address (int64), or a slice of Pieces for location expressions
|
||||
// that don't evaluate to an address (such as register and composite expressions).
|
||||
func ExecuteStackProgram(regs DwarfRegisters, instructions []byte) (int64, []Piece, error) {
|
||||
ctxt := &context{
|
||||
buf: bytes.NewBuffer(instructions),
|
||||
stack: make([]int64, 0, 3),
|
||||
@ -44,42 +43,50 @@ func ExecuteStackProgram(regs DwarfRegisters, instructions []byte) (int64, error
|
||||
}
|
||||
|
||||
for {
|
||||
opcode, err := ctxt.buf.ReadByte()
|
||||
opcodeByte, err := ctxt.buf.ReadByte()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
opcode := Opcode(opcodeByte)
|
||||
if ctxt.reg && opcode != DW_OP_piece {
|
||||
break
|
||||
}
|
||||
fn, ok := oplut[opcode]
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("invalid instruction %#v", opcode)
|
||||
return 0, nil, fmt.Errorf("invalid instruction %#v", opcode)
|
||||
}
|
||||
|
||||
err = fn(opcode, ctxt)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
return 0, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if len(ctxt.stack) == 0 {
|
||||
return 0, errors.New("empty OP stack")
|
||||
if ctxt.pieces != nil {
|
||||
return 0, ctxt.pieces, nil
|
||||
}
|
||||
|
||||
return ctxt.stack[len(ctxt.stack)-1], nil
|
||||
if len(ctxt.stack) == 0 {
|
||||
return 0, nil, errors.New("empty OP stack")
|
||||
}
|
||||
|
||||
return ctxt.stack[len(ctxt.stack)-1], nil, nil
|
||||
}
|
||||
|
||||
func callframecfa(opcode byte, ctxt *context) error {
|
||||
func callframecfa(opcode Opcode, ctxt *context) error {
|
||||
if ctxt.CFA == 0 {
|
||||
return fmt.Errorf("Could not retrieve call frame CFA for current PC")
|
||||
return fmt.Errorf("Could not retrieve CFA for current PC")
|
||||
}
|
||||
ctxt.stack = append(ctxt.stack, int64(ctxt.CFA))
|
||||
return nil
|
||||
}
|
||||
|
||||
func addr(opcode byte, ctxt *context) error {
|
||||
func addr(opcode Opcode, ctxt *context) error {
|
||||
ctxt.stack = append(ctxt.stack, int64(binary.LittleEndian.Uint64(ctxt.buf.Next(8))))
|
||||
return nil
|
||||
}
|
||||
|
||||
func plus(opcode byte, ctxt *context) error {
|
||||
func plus(opcode Opcode, ctxt *context) error {
|
||||
var (
|
||||
slen = len(ctxt.stack)
|
||||
digits = ctxt.stack[slen-2 : slen]
|
||||
@ -90,21 +97,50 @@ func plus(opcode byte, ctxt *context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func plusuconsts(opcode byte, ctxt *context) error {
|
||||
func plusuconsts(opcode Opcode, ctxt *context) error {
|
||||
slen := len(ctxt.stack)
|
||||
num, _ := util.DecodeULEB128(ctxt.buf)
|
||||
ctxt.stack[slen-1] = ctxt.stack[slen-1] + int64(num)
|
||||
return nil
|
||||
}
|
||||
|
||||
func consts(opcode byte, ctxt *context) error {
|
||||
func consts(opcode Opcode, ctxt *context) error {
|
||||
num, _ := util.DecodeSLEB128(ctxt.buf)
|
||||
ctxt.stack = append(ctxt.stack, num)
|
||||
return nil
|
||||
}
|
||||
|
||||
func framebase(opcode byte, ctxt *context) error {
|
||||
func framebase(opcode Opcode, ctxt *context) error {
|
||||
num, _ := util.DecodeSLEB128(ctxt.buf)
|
||||
ctxt.stack = append(ctxt.stack, ctxt.FrameBase+num)
|
||||
return nil
|
||||
}
|
||||
|
||||
func register(opcode Opcode, ctxt *context) error {
|
||||
ctxt.reg = true
|
||||
if opcode == DW_OP_regx {
|
||||
n, _ := util.DecodeSLEB128(ctxt.buf)
|
||||
ctxt.pieces = append(ctxt.pieces, Piece{IsRegister: true, RegNum: uint64(n)})
|
||||
} else {
|
||||
ctxt.pieces = append(ctxt.pieces, Piece{IsRegister: true, RegNum: uint64(opcode - DW_OP_reg0)})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func piece(opcode Opcode, ctxt *context) error {
|
||||
sz, _ := util.DecodeULEB128(ctxt.buf)
|
||||
if ctxt.reg {
|
||||
ctxt.reg = false
|
||||
ctxt.pieces[len(ctxt.pieces)-1].Size = int(sz)
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(ctxt.stack) == 0 {
|
||||
return errors.New("empty OP stack")
|
||||
}
|
||||
|
||||
addr := ctxt.stack[len(ctxt.stack)-1]
|
||||
ctxt.pieces = append(ctxt.pieces, Piece{Size: int(sz), Addr: addr})
|
||||
ctxt.stack = ctxt.stack[:0]
|
||||
return nil
|
||||
}
|
||||
|
@ -1,161 +0,0 @@
|
||||
package op
|
||||
|
||||
const (
|
||||
DW_OP_addr Opcode = 0x03 // implemented
|
||||
DW_OP_deref Opcode = 0x06
|
||||
DW_OP_const1u Opcode = 0x08
|
||||
DW_OP_const1s Opcode = 0x09
|
||||
DW_OP_const2u Opcode = 0x0a
|
||||
DW_OP_const2s Opcode = 0x0b
|
||||
DW_OP_const4u Opcode = 0x0c
|
||||
DW_OP_const4s Opcode = 0x0d
|
||||
DW_OP_const8u Opcode = 0x0e
|
||||
DW_OP_const8s Opcode = 0x0f
|
||||
DW_OP_constu Opcode = 0x10
|
||||
DW_OP_consts Opcode = 0x11 // implemented
|
||||
DW_OP_dup Opcode = 0x12
|
||||
DW_OP_drop Opcode = 0x13
|
||||
DW_OP_over Opcode = 0x14
|
||||
DW_OP_pick Opcode = 0x15
|
||||
DW_OP_swap Opcode = 0x16
|
||||
DW_OP_rot Opcode = 0x17
|
||||
DW_OP_xderef Opcode = 0x18
|
||||
DW_OP_abs Opcode = 0x19
|
||||
DW_OP_and Opcode = 0x1a
|
||||
DW_OP_div Opcode = 0x1b
|
||||
DW_OP_minus Opcode = 0x1c
|
||||
DW_OP_mod Opcode = 0x1d
|
||||
DW_OP_mul Opcode = 0x1e
|
||||
DW_OP_neg Opcode = 0x1f
|
||||
DW_OP_not Opcode = 0x20
|
||||
DW_OP_or Opcode = 0x21
|
||||
DW_OP_plus Opcode = 0x22 // implemented
|
||||
DW_OP_plus_uconst Opcode = 0x23 // implemented
|
||||
DW_OP_shl Opcode = 0x24
|
||||
DW_OP_shr Opcode = 0x25
|
||||
DW_OP_shra Opcode = 0x26
|
||||
DW_OP_xor Opcode = 0x27
|
||||
DW_OP_bra Opcode = 0x28
|
||||
DW_OP_eq Opcode = 0x29
|
||||
DW_OP_ge Opcode = 0x2a
|
||||
DW_OP_gt Opcode = 0x2b
|
||||
DW_OP_le Opcode = 0x2c
|
||||
DW_OP_lt Opcode = 0x2d
|
||||
DW_OP_ne Opcode = 0x2e
|
||||
DW_OP_skip Opcode = 0x2f
|
||||
DW_OP_lit0 Opcode = 0x30
|
||||
DW_OP_lit1 Opcode = 0x31
|
||||
DW_OP_lit2 Opcode = 0x32
|
||||
DW_OP_lit3 Opcode = 0x33
|
||||
DW_OP_lit4 Opcode = 0x34
|
||||
DW_OP_lit5 Opcode = 0x35
|
||||
DW_OP_lit6 Opcode = 0x36
|
||||
DW_OP_lit7 Opcode = 0x37
|
||||
DW_OP_lit8 Opcode = 0x38
|
||||
DW_OP_lit9 Opcode = 0x39
|
||||
DW_OP_lit10 Opcode = 0x3a
|
||||
DW_OP_lit11 Opcode = 0x3b
|
||||
DW_OP_lit12 Opcode = 0x3c
|
||||
DW_OP_lit13 Opcode = 0x3d
|
||||
DW_OP_lit14 Opcode = 0x3e
|
||||
DW_OP_lit15 Opcode = 0x3f
|
||||
DW_OP_lit16 Opcode = 0x40
|
||||
DW_OP_lit17 Opcode = 0x41
|
||||
DW_OP_lit18 Opcode = 0x42
|
||||
DW_OP_lit19 Opcode = 0x43
|
||||
DW_OP_lit20 Opcode = 0x44
|
||||
DW_OP_lit21 Opcode = 0x45
|
||||
DW_OP_lit22 Opcode = 0x46
|
||||
DW_OP_lit23 Opcode = 0x47
|
||||
DW_OP_lit24 Opcode = 0x48
|
||||
DW_OP_lit25 Opcode = 0x49
|
||||
DW_OP_lit26 Opcode = 0x4a
|
||||
DW_OP_lit27 Opcode = 0x4b
|
||||
DW_OP_lit28 Opcode = 0x4c
|
||||
DW_OP_lit29 Opcode = 0x4d
|
||||
DW_OP_lit30 Opcode = 0x4e
|
||||
DW_OP_lit31 Opcode = 0x4f
|
||||
DW_OP_reg0 Opcode = 0x50
|
||||
DW_OP_reg1 Opcode = 0x51
|
||||
DW_OP_reg2 Opcode = 0x52
|
||||
DW_OP_reg3 Opcode = 0x53
|
||||
DW_OP_reg4 Opcode = 0x54
|
||||
DW_OP_reg5 Opcode = 0x55
|
||||
DW_OP_reg6 Opcode = 0x56
|
||||
DW_OP_reg7 Opcode = 0x57
|
||||
DW_OP_reg8 Opcode = 0x58
|
||||
DW_OP_reg9 Opcode = 0x59
|
||||
DW_OP_reg10 Opcode = 0x5a
|
||||
DW_OP_reg11 Opcode = 0x5b
|
||||
DW_OP_reg12 Opcode = 0x5c
|
||||
DW_OP_reg13 Opcode = 0x5d
|
||||
DW_OP_reg14 Opcode = 0x5e
|
||||
DW_OP_reg15 Opcode = 0x5f
|
||||
DW_OP_reg16 Opcode = 0x60
|
||||
DW_OP_reg17 Opcode = 0x61
|
||||
DW_OP_reg18 Opcode = 0x62
|
||||
DW_OP_reg19 Opcode = 0x63
|
||||
DW_OP_reg20 Opcode = 0x64
|
||||
DW_OP_reg21 Opcode = 0x65
|
||||
DW_OP_reg22 Opcode = 0x66
|
||||
DW_OP_reg23 Opcode = 0x67
|
||||
DW_OP_reg24 Opcode = 0x68
|
||||
DW_OP_reg25 Opcode = 0x69
|
||||
DW_OP_reg26 Opcode = 0x6a
|
||||
DW_OP_reg27 Opcode = 0x6b
|
||||
DW_OP_reg28 Opcode = 0x6c
|
||||
DW_OP_reg29 Opcode = 0x6d
|
||||
DW_OP_reg30 Opcode = 0x6e
|
||||
DW_OP_reg31 Opcode = 0x6f
|
||||
DW_OP_breg0 Opcode = 0x70
|
||||
DW_OP_breg1 Opcode = 0x71
|
||||
DW_OP_breg2 Opcode = 0x72
|
||||
DW_OP_breg3 Opcode = 0x73
|
||||
DW_OP_breg4 Opcode = 0x74
|
||||
DW_OP_breg5 Opcode = 0x75
|
||||
DW_OP_breg6 Opcode = 0x76
|
||||
DW_OP_breg7 Opcode = 0x77
|
||||
DW_OP_breg8 Opcode = 0x78
|
||||
DW_OP_breg9 Opcode = 0x79
|
||||
DW_OP_breg10 Opcode = 0x7a
|
||||
DW_OP_breg11 Opcode = 0x7b
|
||||
DW_OP_breg12 Opcode = 0x7c
|
||||
DW_OP_breg13 Opcode = 0x7d
|
||||
DW_OP_breg14 Opcode = 0x7e
|
||||
DW_OP_breg15 Opcode = 0x7f
|
||||
DW_OP_breg16 Opcode = 0x80
|
||||
DW_OP_breg17 Opcode = 0x81
|
||||
DW_OP_breg18 Opcode = 0x82
|
||||
DW_OP_breg19 Opcode = 0x83
|
||||
DW_OP_breg20 Opcode = 0x84
|
||||
DW_OP_breg21 Opcode = 0x85
|
||||
DW_OP_breg22 Opcode = 0x86
|
||||
DW_OP_breg23 Opcode = 0x87
|
||||
DW_OP_breg24 Opcode = 0x88
|
||||
DW_OP_breg25 Opcode = 0x89
|
||||
DW_OP_breg26 Opcode = 0x8a
|
||||
DW_OP_breg27 Opcode = 0x8b
|
||||
DW_OP_breg28 Opcode = 0x8c
|
||||
DW_OP_breg29 Opcode = 0x8d
|
||||
DW_OP_breg30 Opcode = 0x8e
|
||||
DW_OP_breg31 Opcode = 0x8f
|
||||
DW_OP_regx Opcode = 0x90
|
||||
DW_OP_fbreg Opcode = 0x91
|
||||
DW_OP_bregx Opcode = 0x92
|
||||
DW_OP_piece Opcode = 0x93
|
||||
DW_OP_deref_size Opcode = 0x94
|
||||
DW_OP_xderef_size Opcode = 0x95
|
||||
DW_OP_nop Opcode = 0x96
|
||||
// DWARF 3 extensions.
|
||||
DW_OP_push_object_address Opcode = 0x97
|
||||
DW_OP_call2 Opcode = 0x98
|
||||
DW_OP_call4 Opcode = 0x99
|
||||
DW_OP_call_ref Opcode = 0x9a
|
||||
DW_OP_form_tls_address Opcode = 0x9b
|
||||
DW_OP_call_frame_cfa Opcode = 0x9c // implemented
|
||||
DW_OP_bit_piece Opcode = 0x9d
|
||||
|
||||
// DWARF 4 extensions.
|
||||
DW_OP_implicit_value Opcode = 0x9e
|
||||
DW_OP_stack_value Opcode = 0x9f
|
||||
)
|
@ -4,10 +4,10 @@ import "testing"
|
||||
|
||||
func TestExecuteStackProgram(t *testing.T) {
|
||||
var (
|
||||
instructions = []byte{DW_OP_consts, 0x1c, DW_OP_consts, 0x1c, DW_OP_plus}
|
||||
instructions = []byte{byte(DW_OP_consts), 0x1c, byte(DW_OP_consts), 0x1c, byte(DW_OP_plus)}
|
||||
expected = int64(56)
|
||||
)
|
||||
actual, err := ExecuteStackProgram(DwarfRegisters{}, instructions)
|
||||
actual, _, err := ExecuteStackProgram(DwarfRegisters{}, instructions)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
515
pkg/dwarf/op/opcodes.go
Normal file
515
pkg/dwarf/op/opcodes.go
Normal file
@ -0,0 +1,515 @@
|
||||
// THIS FILE IS AUTOGENERATED, EDIT opcodes.table INSTEAD
|
||||
|
||||
package op
|
||||
|
||||
const (
|
||||
DW_OP_addr Opcode = 0x03
|
||||
DW_OP_deref Opcode = 0x06
|
||||
DW_OP_const1u Opcode = 0x08
|
||||
DW_OP_const1s Opcode = 0x09
|
||||
DW_OP_const2u Opcode = 0x0a
|
||||
DW_OP_const2s Opcode = 0x0b
|
||||
DW_OP_const4u Opcode = 0x0c
|
||||
DW_OP_const4s Opcode = 0x0d
|
||||
DW_OP_const8u Opcode = 0x0e
|
||||
DW_OP_const8s Opcode = 0x0f
|
||||
DW_OP_constu Opcode = 0x10
|
||||
DW_OP_consts Opcode = 0x11
|
||||
DW_OP_dup Opcode = 0x12
|
||||
DW_OP_drop Opcode = 0x13
|
||||
DW_OP_over Opcode = 0x14
|
||||
DW_OP_pick Opcode = 0x15
|
||||
DW_OP_swap Opcode = 0x16
|
||||
DW_OP_rot Opcode = 0x17
|
||||
DW_OP_xderef Opcode = 0x18
|
||||
DW_OP_abs Opcode = 0x19
|
||||
DW_OP_and Opcode = 0x1a
|
||||
DW_OP_div Opcode = 0x1b
|
||||
DW_OP_minus Opcode = 0x1c
|
||||
DW_OP_mod Opcode = 0x1d
|
||||
DW_OP_mul Opcode = 0x1e
|
||||
DW_OP_neg Opcode = 0x1f
|
||||
DW_OP_not Opcode = 0x20
|
||||
DW_OP_or Opcode = 0x21
|
||||
DW_OP_plus Opcode = 0x22
|
||||
DW_OP_plus_uconst Opcode = 0x23
|
||||
DW_OP_shl Opcode = 0x24
|
||||
DW_OP_shr Opcode = 0x25
|
||||
DW_OP_shra Opcode = 0x26
|
||||
DW_OP_xor Opcode = 0x27
|
||||
DW_OP_bra Opcode = 0x28
|
||||
DW_OP_eq Opcode = 0x29
|
||||
DW_OP_ge Opcode = 0x2a
|
||||
DW_OP_gt Opcode = 0x2b
|
||||
DW_OP_le Opcode = 0x2c
|
||||
DW_OP_lt Opcode = 0x2d
|
||||
DW_OP_ne Opcode = 0x2e
|
||||
DW_OP_skip Opcode = 0x2f
|
||||
DW_OP_lit0 Opcode = 0x30
|
||||
DW_OP_lit1 Opcode = 0x31
|
||||
DW_OP_lit2 Opcode = 0x32
|
||||
DW_OP_lit3 Opcode = 0x33
|
||||
DW_OP_lit4 Opcode = 0x34
|
||||
DW_OP_lit5 Opcode = 0x35
|
||||
DW_OP_lit6 Opcode = 0x36
|
||||
DW_OP_lit7 Opcode = 0x37
|
||||
DW_OP_lit8 Opcode = 0x38
|
||||
DW_OP_lit9 Opcode = 0x39
|
||||
DW_OP_lit10 Opcode = 0x3a
|
||||
DW_OP_lit11 Opcode = 0x3b
|
||||
DW_OP_lit12 Opcode = 0x3c
|
||||
DW_OP_lit13 Opcode = 0x3d
|
||||
DW_OP_lit14 Opcode = 0x3e
|
||||
DW_OP_lit15 Opcode = 0x3f
|
||||
DW_OP_lit16 Opcode = 0x40
|
||||
DW_OP_lit17 Opcode = 0x41
|
||||
DW_OP_lit18 Opcode = 0x42
|
||||
DW_OP_lit19 Opcode = 0x43
|
||||
DW_OP_lit20 Opcode = 0x44
|
||||
DW_OP_lit21 Opcode = 0x45
|
||||
DW_OP_lit22 Opcode = 0x46
|
||||
DW_OP_lit23 Opcode = 0x47
|
||||
DW_OP_lit24 Opcode = 0x48
|
||||
DW_OP_lit25 Opcode = 0x49
|
||||
DW_OP_lit26 Opcode = 0x4a
|
||||
DW_OP_lit27 Opcode = 0x4b
|
||||
DW_OP_lit28 Opcode = 0x4c
|
||||
DW_OP_lit29 Opcode = 0x4d
|
||||
DW_OP_lit30 Opcode = 0x4e
|
||||
DW_OP_lit31 Opcode = 0x4f
|
||||
DW_OP_reg0 Opcode = 0x50
|
||||
DW_OP_reg1 Opcode = 0x51
|
||||
DW_OP_reg2 Opcode = 0x52
|
||||
DW_OP_reg3 Opcode = 0x53
|
||||
DW_OP_reg4 Opcode = 0x54
|
||||
DW_OP_reg5 Opcode = 0x55
|
||||
DW_OP_reg6 Opcode = 0x56
|
||||
DW_OP_reg7 Opcode = 0x57
|
||||
DW_OP_reg8 Opcode = 0x58
|
||||
DW_OP_reg9 Opcode = 0x59
|
||||
DW_OP_reg10 Opcode = 0x5a
|
||||
DW_OP_reg11 Opcode = 0x5b
|
||||
DW_OP_reg12 Opcode = 0x5c
|
||||
DW_OP_reg13 Opcode = 0x5d
|
||||
DW_OP_reg14 Opcode = 0x5e
|
||||
DW_OP_reg15 Opcode = 0x5f
|
||||
DW_OP_reg16 Opcode = 0x60
|
||||
DW_OP_reg17 Opcode = 0x61
|
||||
DW_OP_reg18 Opcode = 0x62
|
||||
DW_OP_reg19 Opcode = 0x63
|
||||
DW_OP_reg20 Opcode = 0x64
|
||||
DW_OP_reg21 Opcode = 0x65
|
||||
DW_OP_reg22 Opcode = 0x66
|
||||
DW_OP_reg23 Opcode = 0x67
|
||||
DW_OP_reg24 Opcode = 0x68
|
||||
DW_OP_reg25 Opcode = 0x69
|
||||
DW_OP_reg26 Opcode = 0x6a
|
||||
DW_OP_reg27 Opcode = 0x6b
|
||||
DW_OP_reg28 Opcode = 0x6c
|
||||
DW_OP_reg29 Opcode = 0x6d
|
||||
DW_OP_reg30 Opcode = 0x6e
|
||||
DW_OP_reg31 Opcode = 0x6f
|
||||
DW_OP_breg0 Opcode = 0x70
|
||||
DW_OP_breg1 Opcode = 0x71
|
||||
DW_OP_breg2 Opcode = 0x72
|
||||
DW_OP_breg3 Opcode = 0x73
|
||||
DW_OP_breg4 Opcode = 0x74
|
||||
DW_OP_breg5 Opcode = 0x75
|
||||
DW_OP_breg6 Opcode = 0x76
|
||||
DW_OP_breg7 Opcode = 0x77
|
||||
DW_OP_breg8 Opcode = 0x78
|
||||
DW_OP_breg9 Opcode = 0x79
|
||||
DW_OP_breg10 Opcode = 0x7a
|
||||
DW_OP_breg11 Opcode = 0x7b
|
||||
DW_OP_breg12 Opcode = 0x7c
|
||||
DW_OP_breg13 Opcode = 0x7d
|
||||
DW_OP_breg14 Opcode = 0x7e
|
||||
DW_OP_breg15 Opcode = 0x7f
|
||||
DW_OP_breg16 Opcode = 0x80
|
||||
DW_OP_breg17 Opcode = 0x81
|
||||
DW_OP_breg18 Opcode = 0x82
|
||||
DW_OP_breg19 Opcode = 0x83
|
||||
DW_OP_breg20 Opcode = 0x84
|
||||
DW_OP_breg21 Opcode = 0x85
|
||||
DW_OP_breg22 Opcode = 0x86
|
||||
DW_OP_breg23 Opcode = 0x87
|
||||
DW_OP_breg24 Opcode = 0x88
|
||||
DW_OP_breg25 Opcode = 0x89
|
||||
DW_OP_breg26 Opcode = 0x8a
|
||||
DW_OP_breg27 Opcode = 0x8b
|
||||
DW_OP_breg28 Opcode = 0x8c
|
||||
DW_OP_breg29 Opcode = 0x8d
|
||||
DW_OP_breg30 Opcode = 0x8e
|
||||
DW_OP_breg31 Opcode = 0x8f
|
||||
DW_OP_regx Opcode = 0x90
|
||||
DW_OP_fbreg Opcode = 0x91
|
||||
DW_OP_bregx Opcode = 0x92
|
||||
DW_OP_piece Opcode = 0x93
|
||||
DW_OP_deref_size Opcode = 0x94
|
||||
DW_OP_xderef_size Opcode = 0x95
|
||||
DW_OP_nop Opcode = 0x96
|
||||
DW_OP_push_object_address Opcode = 0x97
|
||||
DW_OP_call2 Opcode = 0x98
|
||||
DW_OP_call4 Opcode = 0x99
|
||||
DW_OP_call_ref Opcode = 0x9a
|
||||
DW_OP_form_tls_address Opcode = 0x9b
|
||||
DW_OP_call_frame_cfa Opcode = 0x9c
|
||||
DW_OP_bit_piece Opcode = 0x9d
|
||||
DW_OP_implicit_value Opcode = 0x9e
|
||||
DW_OP_stack_value Opcode = 0x9f
|
||||
)
|
||||
|
||||
var opcodeName = map[Opcode]string{
|
||||
DW_OP_addr: "DW_OP_addr",
|
||||
DW_OP_deref: "DW_OP_deref",
|
||||
DW_OP_const1u: "DW_OP_const1u",
|
||||
DW_OP_const1s: "DW_OP_const1s",
|
||||
DW_OP_const2u: "DW_OP_const2u",
|
||||
DW_OP_const2s: "DW_OP_const2s",
|
||||
DW_OP_const4u: "DW_OP_const4u",
|
||||
DW_OP_const4s: "DW_OP_const4s",
|
||||
DW_OP_const8u: "DW_OP_const8u",
|
||||
DW_OP_const8s: "DW_OP_const8s",
|
||||
DW_OP_constu: "DW_OP_constu",
|
||||
DW_OP_consts: "DW_OP_consts",
|
||||
DW_OP_dup: "DW_OP_dup",
|
||||
DW_OP_drop: "DW_OP_drop",
|
||||
DW_OP_over: "DW_OP_over",
|
||||
DW_OP_pick: "DW_OP_pick",
|
||||
DW_OP_swap: "DW_OP_swap",
|
||||
DW_OP_rot: "DW_OP_rot",
|
||||
DW_OP_xderef: "DW_OP_xderef",
|
||||
DW_OP_abs: "DW_OP_abs",
|
||||
DW_OP_and: "DW_OP_and",
|
||||
DW_OP_div: "DW_OP_div",
|
||||
DW_OP_minus: "DW_OP_minus",
|
||||
DW_OP_mod: "DW_OP_mod",
|
||||
DW_OP_mul: "DW_OP_mul",
|
||||
DW_OP_neg: "DW_OP_neg",
|
||||
DW_OP_not: "DW_OP_not",
|
||||
DW_OP_or: "DW_OP_or",
|
||||
DW_OP_plus: "DW_OP_plus",
|
||||
DW_OP_plus_uconst: "DW_OP_plus_uconst",
|
||||
DW_OP_shl: "DW_OP_shl",
|
||||
DW_OP_shr: "DW_OP_shr",
|
||||
DW_OP_shra: "DW_OP_shra",
|
||||
DW_OP_xor: "DW_OP_xor",
|
||||
DW_OP_bra: "DW_OP_bra",
|
||||
DW_OP_eq: "DW_OP_eq",
|
||||
DW_OP_ge: "DW_OP_ge",
|
||||
DW_OP_gt: "DW_OP_gt",
|
||||
DW_OP_le: "DW_OP_le",
|
||||
DW_OP_lt: "DW_OP_lt",
|
||||
DW_OP_ne: "DW_OP_ne",
|
||||
DW_OP_skip: "DW_OP_skip",
|
||||
DW_OP_lit0: "DW_OP_lit0",
|
||||
DW_OP_lit1: "DW_OP_lit1",
|
||||
DW_OP_lit2: "DW_OP_lit2",
|
||||
DW_OP_lit3: "DW_OP_lit3",
|
||||
DW_OP_lit4: "DW_OP_lit4",
|
||||
DW_OP_lit5: "DW_OP_lit5",
|
||||
DW_OP_lit6: "DW_OP_lit6",
|
||||
DW_OP_lit7: "DW_OP_lit7",
|
||||
DW_OP_lit8: "DW_OP_lit8",
|
||||
DW_OP_lit9: "DW_OP_lit9",
|
||||
DW_OP_lit10: "DW_OP_lit10",
|
||||
DW_OP_lit11: "DW_OP_lit11",
|
||||
DW_OP_lit12: "DW_OP_lit12",
|
||||
DW_OP_lit13: "DW_OP_lit13",
|
||||
DW_OP_lit14: "DW_OP_lit14",
|
||||
DW_OP_lit15: "DW_OP_lit15",
|
||||
DW_OP_lit16: "DW_OP_lit16",
|
||||
DW_OP_lit17: "DW_OP_lit17",
|
||||
DW_OP_lit18: "DW_OP_lit18",
|
||||
DW_OP_lit19: "DW_OP_lit19",
|
||||
DW_OP_lit20: "DW_OP_lit20",
|
||||
DW_OP_lit21: "DW_OP_lit21",
|
||||
DW_OP_lit22: "DW_OP_lit22",
|
||||
DW_OP_lit23: "DW_OP_lit23",
|
||||
DW_OP_lit24: "DW_OP_lit24",
|
||||
DW_OP_lit25: "DW_OP_lit25",
|
||||
DW_OP_lit26: "DW_OP_lit26",
|
||||
DW_OP_lit27: "DW_OP_lit27",
|
||||
DW_OP_lit28: "DW_OP_lit28",
|
||||
DW_OP_lit29: "DW_OP_lit29",
|
||||
DW_OP_lit30: "DW_OP_lit30",
|
||||
DW_OP_lit31: "DW_OP_lit31",
|
||||
DW_OP_reg0: "DW_OP_reg0",
|
||||
DW_OP_reg1: "DW_OP_reg1",
|
||||
DW_OP_reg2: "DW_OP_reg2",
|
||||
DW_OP_reg3: "DW_OP_reg3",
|
||||
DW_OP_reg4: "DW_OP_reg4",
|
||||
DW_OP_reg5: "DW_OP_reg5",
|
||||
DW_OP_reg6: "DW_OP_reg6",
|
||||
DW_OP_reg7: "DW_OP_reg7",
|
||||
DW_OP_reg8: "DW_OP_reg8",
|
||||
DW_OP_reg9: "DW_OP_reg9",
|
||||
DW_OP_reg10: "DW_OP_reg10",
|
||||
DW_OP_reg11: "DW_OP_reg11",
|
||||
DW_OP_reg12: "DW_OP_reg12",
|
||||
DW_OP_reg13: "DW_OP_reg13",
|
||||
DW_OP_reg14: "DW_OP_reg14",
|
||||
DW_OP_reg15: "DW_OP_reg15",
|
||||
DW_OP_reg16: "DW_OP_reg16",
|
||||
DW_OP_reg17: "DW_OP_reg17",
|
||||
DW_OP_reg18: "DW_OP_reg18",
|
||||
DW_OP_reg19: "DW_OP_reg19",
|
||||
DW_OP_reg20: "DW_OP_reg20",
|
||||
DW_OP_reg21: "DW_OP_reg21",
|
||||
DW_OP_reg22: "DW_OP_reg22",
|
||||
DW_OP_reg23: "DW_OP_reg23",
|
||||
DW_OP_reg24: "DW_OP_reg24",
|
||||
DW_OP_reg25: "DW_OP_reg25",
|
||||
DW_OP_reg26: "DW_OP_reg26",
|
||||
DW_OP_reg27: "DW_OP_reg27",
|
||||
DW_OP_reg28: "DW_OP_reg28",
|
||||
DW_OP_reg29: "DW_OP_reg29",
|
||||
DW_OP_reg30: "DW_OP_reg30",
|
||||
DW_OP_reg31: "DW_OP_reg31",
|
||||
DW_OP_breg0: "DW_OP_breg0",
|
||||
DW_OP_breg1: "DW_OP_breg1",
|
||||
DW_OP_breg2: "DW_OP_breg2",
|
||||
DW_OP_breg3: "DW_OP_breg3",
|
||||
DW_OP_breg4: "DW_OP_breg4",
|
||||
DW_OP_breg5: "DW_OP_breg5",
|
||||
DW_OP_breg6: "DW_OP_breg6",
|
||||
DW_OP_breg7: "DW_OP_breg7",
|
||||
DW_OP_breg8: "DW_OP_breg8",
|
||||
DW_OP_breg9: "DW_OP_breg9",
|
||||
DW_OP_breg10: "DW_OP_breg10",
|
||||
DW_OP_breg11: "DW_OP_breg11",
|
||||
DW_OP_breg12: "DW_OP_breg12",
|
||||
DW_OP_breg13: "DW_OP_breg13",
|
||||
DW_OP_breg14: "DW_OP_breg14",
|
||||
DW_OP_breg15: "DW_OP_breg15",
|
||||
DW_OP_breg16: "DW_OP_breg16",
|
||||
DW_OP_breg17: "DW_OP_breg17",
|
||||
DW_OP_breg18: "DW_OP_breg18",
|
||||
DW_OP_breg19: "DW_OP_breg19",
|
||||
DW_OP_breg20: "DW_OP_breg20",
|
||||
DW_OP_breg21: "DW_OP_breg21",
|
||||
DW_OP_breg22: "DW_OP_breg22",
|
||||
DW_OP_breg23: "DW_OP_breg23",
|
||||
DW_OP_breg24: "DW_OP_breg24",
|
||||
DW_OP_breg25: "DW_OP_breg25",
|
||||
DW_OP_breg26: "DW_OP_breg26",
|
||||
DW_OP_breg27: "DW_OP_breg27",
|
||||
DW_OP_breg28: "DW_OP_breg28",
|
||||
DW_OP_breg29: "DW_OP_breg29",
|
||||
DW_OP_breg30: "DW_OP_breg30",
|
||||
DW_OP_breg31: "DW_OP_breg31",
|
||||
DW_OP_regx: "DW_OP_regx",
|
||||
DW_OP_fbreg: "DW_OP_fbreg",
|
||||
DW_OP_bregx: "DW_OP_bregx",
|
||||
DW_OP_piece: "DW_OP_piece",
|
||||
DW_OP_deref_size: "DW_OP_deref_size",
|
||||
DW_OP_xderef_size: "DW_OP_xderef_size",
|
||||
DW_OP_nop: "DW_OP_nop",
|
||||
DW_OP_push_object_address: "DW_OP_push_object_address",
|
||||
DW_OP_call2: "DW_OP_call2",
|
||||
DW_OP_call4: "DW_OP_call4",
|
||||
DW_OP_call_ref: "DW_OP_call_ref",
|
||||
DW_OP_form_tls_address: "DW_OP_form_tls_address",
|
||||
DW_OP_call_frame_cfa: "DW_OP_call_frame_cfa",
|
||||
DW_OP_bit_piece: "DW_OP_bit_piece",
|
||||
DW_OP_implicit_value: "DW_OP_implicit_value",
|
||||
DW_OP_stack_value: "DW_OP_stack_value",
|
||||
}
|
||||
var opcodeArgs = map[Opcode]string{
|
||||
DW_OP_addr: "8",
|
||||
DW_OP_deref: "",
|
||||
DW_OP_const1u: "1",
|
||||
DW_OP_const1s: "1",
|
||||
DW_OP_const2u: "2",
|
||||
DW_OP_const2s: "2",
|
||||
DW_OP_const4u: "4",
|
||||
DW_OP_const4s: "4",
|
||||
DW_OP_const8u: "8",
|
||||
DW_OP_const8s: "8",
|
||||
DW_OP_constu: "u",
|
||||
DW_OP_consts: "s",
|
||||
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: "u",
|
||||
DW_OP_shl: "",
|
||||
DW_OP_shr: "",
|
||||
DW_OP_shra: "",
|
||||
DW_OP_xor: "",
|
||||
DW_OP_bra: "2",
|
||||
DW_OP_eq: "",
|
||||
DW_OP_ge: "",
|
||||
DW_OP_gt: "",
|
||||
DW_OP_le: "",
|
||||
DW_OP_lt: "",
|
||||
DW_OP_ne: "",
|
||||
DW_OP_skip: "2",
|
||||
DW_OP_lit0: "",
|
||||
DW_OP_lit1: "",
|
||||
DW_OP_lit2: "",
|
||||
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: "s",
|
||||
DW_OP_breg1: "s",
|
||||
DW_OP_breg2: "s",
|
||||
DW_OP_breg3: "s",
|
||||
DW_OP_breg4: "s",
|
||||
DW_OP_breg5: "s",
|
||||
DW_OP_breg6: "s",
|
||||
DW_OP_breg7: "s",
|
||||
DW_OP_breg8: "s",
|
||||
DW_OP_breg9: "s",
|
||||
DW_OP_breg10: "s",
|
||||
DW_OP_breg11: "s",
|
||||
DW_OP_breg12: "s",
|
||||
DW_OP_breg13: "s",
|
||||
DW_OP_breg14: "s",
|
||||
DW_OP_breg15: "s",
|
||||
DW_OP_breg16: "s",
|
||||
DW_OP_breg17: "s",
|
||||
DW_OP_breg18: "s",
|
||||
DW_OP_breg19: "s",
|
||||
DW_OP_breg20: "s",
|
||||
DW_OP_breg21: "s",
|
||||
DW_OP_breg22: "s",
|
||||
DW_OP_breg23: "s",
|
||||
DW_OP_breg24: "s",
|
||||
DW_OP_breg25: "s",
|
||||
DW_OP_breg26: "s",
|
||||
DW_OP_breg27: "s",
|
||||
DW_OP_breg28: "s",
|
||||
DW_OP_breg29: "s",
|
||||
DW_OP_breg30: "s",
|
||||
DW_OP_breg31: "s",
|
||||
DW_OP_regx: "s",
|
||||
DW_OP_fbreg: "s",
|
||||
DW_OP_bregx: "us",
|
||||
DW_OP_piece: "u",
|
||||
DW_OP_deref_size: "1",
|
||||
DW_OP_xderef_size: "1",
|
||||
DW_OP_nop: "",
|
||||
DW_OP_push_object_address: "",
|
||||
DW_OP_call2: "2",
|
||||
DW_OP_call4: "4",
|
||||
DW_OP_call_ref: "4",
|
||||
DW_OP_form_tls_address: "",
|
||||
DW_OP_call_frame_cfa: "",
|
||||
DW_OP_bit_piece: "uu",
|
||||
DW_OP_implicit_value: "B",
|
||||
DW_OP_stack_value: "",
|
||||
}
|
||||
var oplut = map[Opcode]stackfn{
|
||||
DW_OP_addr: addr,
|
||||
DW_OP_consts: consts,
|
||||
DW_OP_plus: plus,
|
||||
DW_OP_plus_uconst: plusuconsts,
|
||||
DW_OP_reg0: register,
|
||||
DW_OP_reg1: register,
|
||||
DW_OP_reg2: register,
|
||||
DW_OP_reg3: register,
|
||||
DW_OP_reg4: register,
|
||||
DW_OP_reg5: register,
|
||||
DW_OP_reg6: register,
|
||||
DW_OP_reg7: register,
|
||||
DW_OP_reg8: register,
|
||||
DW_OP_reg9: register,
|
||||
DW_OP_reg10: register,
|
||||
DW_OP_reg11: register,
|
||||
DW_OP_reg12: register,
|
||||
DW_OP_reg13: register,
|
||||
DW_OP_reg14: register,
|
||||
DW_OP_reg15: register,
|
||||
DW_OP_reg16: register,
|
||||
DW_OP_reg17: register,
|
||||
DW_OP_reg18: register,
|
||||
DW_OP_reg19: register,
|
||||
DW_OP_reg20: register,
|
||||
DW_OP_reg21: register,
|
||||
DW_OP_reg22: register,
|
||||
DW_OP_reg23: register,
|
||||
DW_OP_reg24: register,
|
||||
DW_OP_reg25: register,
|
||||
DW_OP_reg26: register,
|
||||
DW_OP_reg27: register,
|
||||
DW_OP_reg28: register,
|
||||
DW_OP_reg29: register,
|
||||
DW_OP_reg30: register,
|
||||
DW_OP_reg31: register,
|
||||
DW_OP_regx: register,
|
||||
DW_OP_fbreg: framebase,
|
||||
DW_OP_piece: piece,
|
||||
DW_OP_call_frame_cfa: callframecfa,
|
||||
}
|
175
pkg/dwarf/op/opcodes.table
Normal file
175
pkg/dwarf/op/opcodes.table
Normal file
@ -0,0 +1,175 @@
|
||||
// This file is used by scripts/gen-opcodes.go to generate
|
||||
// pkg/dwarf/op/opcodes.go
|
||||
// Lines starting with // are comments and will be discarded.
|
||||
// Non empty lines contain the following tab separated fields:
|
||||
//
|
||||
// <opcode name> <opcode code> <arguments> <function name>
|
||||
//
|
||||
// With the last column, <function name>, being optional.
|
||||
//
|
||||
// The arguments field should contain a string with one character for each
|
||||
// argument of the opcode:
|
||||
//
|
||||
// s signed variable length integer
|
||||
// u unsigned variable length integer
|
||||
// 1 one byte unsigned integer
|
||||
// 2 two bytes unsigned integer
|
||||
// 4 four bytes unsigned integer
|
||||
// 8 eight bytes unsigned integer
|
||||
// B an unsigned variable length integer 'n' followed by n a block of n bytes
|
||||
|
||||
|
||||
DW_OP_addr 0x03 "8" addr
|
||||
DW_OP_deref 0x06 ""
|
||||
DW_OP_const1u 0x08 "1"
|
||||
DW_OP_const1s 0x09 "1"
|
||||
DW_OP_const2u 0x0a "2"
|
||||
DW_OP_const2s 0x0b "2"
|
||||
DW_OP_const4u 0x0c "4"
|
||||
DW_OP_const4s 0x0d "4"
|
||||
DW_OP_const8u 0x0e "8"
|
||||
DW_OP_const8s 0x0f "8"
|
||||
DW_OP_constu 0x10 "u"
|
||||
DW_OP_consts 0x11 "s" consts
|
||||
DW_OP_dup 0x12 ""
|
||||
DW_OP_drop 0x13 ""
|
||||
DW_OP_over 0x14 ""
|
||||
DW_OP_pick 0x15 ""
|
||||
DW_OP_swap 0x16 ""
|
||||
DW_OP_rot 0x17 ""
|
||||
DW_OP_xderef 0x18 ""
|
||||
DW_OP_abs 0x19 ""
|
||||
DW_OP_and 0x1a ""
|
||||
DW_OP_div 0x1b ""
|
||||
DW_OP_minus 0x1c ""
|
||||
DW_OP_mod 0x1d ""
|
||||
DW_OP_mul 0x1e ""
|
||||
DW_OP_neg 0x1f ""
|
||||
DW_OP_not 0x20 ""
|
||||
DW_OP_or 0x21 ""
|
||||
DW_OP_plus 0x22 "" plus
|
||||
DW_OP_plus_uconst 0x23 "u" plusuconsts
|
||||
DW_OP_shl 0x24 ""
|
||||
DW_OP_shr 0x25 ""
|
||||
DW_OP_shra 0x26 ""
|
||||
DW_OP_xor 0x27 ""
|
||||
DW_OP_bra 0x28 "2"
|
||||
DW_OP_eq 0x29 ""
|
||||
DW_OP_ge 0x2a ""
|
||||
DW_OP_gt 0x2b ""
|
||||
DW_OP_le 0x2c ""
|
||||
DW_OP_lt 0x2d ""
|
||||
DW_OP_ne 0x2e ""
|
||||
DW_OP_skip 0x2f "2"
|
||||
DW_OP_lit0 0x30 ""
|
||||
DW_OP_lit1 0x31 ""
|
||||
DW_OP_lit2 0x32 ""
|
||||
DW_OP_lit3 0x33 ""
|
||||
DW_OP_lit4 0x34 ""
|
||||
DW_OP_lit5 0x35 ""
|
||||
DW_OP_lit6 0x36 ""
|
||||
DW_OP_lit7 0x37 ""
|
||||
DW_OP_lit8 0x38 ""
|
||||
DW_OP_lit9 0x39 ""
|
||||
DW_OP_lit10 0x3a ""
|
||||
DW_OP_lit11 0x3b ""
|
||||
DW_OP_lit12 0x3c ""
|
||||
DW_OP_lit13 0x3d ""
|
||||
DW_OP_lit14 0x3e ""
|
||||
DW_OP_lit15 0x3f ""
|
||||
DW_OP_lit16 0x40 ""
|
||||
DW_OP_lit17 0x41 ""
|
||||
DW_OP_lit18 0x42 ""
|
||||
DW_OP_lit19 0x43 ""
|
||||
DW_OP_lit20 0x44 ""
|
||||
DW_OP_lit21 0x45 ""
|
||||
DW_OP_lit22 0x46 ""
|
||||
DW_OP_lit23 0x47 ""
|
||||
DW_OP_lit24 0x48 ""
|
||||
DW_OP_lit25 0x49 ""
|
||||
DW_OP_lit26 0x4a ""
|
||||
DW_OP_lit27 0x4b ""
|
||||
DW_OP_lit28 0x4c ""
|
||||
DW_OP_lit29 0x4d ""
|
||||
DW_OP_lit30 0x4e ""
|
||||
DW_OP_lit31 0x4f ""
|
||||
DW_OP_reg0 0x50 "" register
|
||||
DW_OP_reg1 0x51 "" register
|
||||
DW_OP_reg2 0x52 "" register
|
||||
DW_OP_reg3 0x53 "" register
|
||||
DW_OP_reg4 0x54 "" register
|
||||
DW_OP_reg5 0x55 "" register
|
||||
DW_OP_reg6 0x56 "" register
|
||||
DW_OP_reg7 0x57 "" register
|
||||
DW_OP_reg8 0x58 "" register
|
||||
DW_OP_reg9 0x59 "" register
|
||||
DW_OP_reg10 0x5a "" register
|
||||
DW_OP_reg11 0x5b "" register
|
||||
DW_OP_reg12 0x5c "" register
|
||||
DW_OP_reg13 0x5d "" register
|
||||
DW_OP_reg14 0x5e "" register
|
||||
DW_OP_reg15 0x5f "" register
|
||||
DW_OP_reg16 0x60 "" register
|
||||
DW_OP_reg17 0x61 "" register
|
||||
DW_OP_reg18 0x62 "" register
|
||||
DW_OP_reg19 0x63 "" register
|
||||
DW_OP_reg20 0x64 "" register
|
||||
DW_OP_reg21 0x65 "" register
|
||||
DW_OP_reg22 0x66 "" register
|
||||
DW_OP_reg23 0x67 "" register
|
||||
DW_OP_reg24 0x68 "" register
|
||||
DW_OP_reg25 0x69 "" register
|
||||
DW_OP_reg26 0x6a "" register
|
||||
DW_OP_reg27 0x6b "" register
|
||||
DW_OP_reg28 0x6c "" register
|
||||
DW_OP_reg29 0x6d "" register
|
||||
DW_OP_reg30 0x6e "" register
|
||||
DW_OP_reg31 0x6f "" register
|
||||
DW_OP_breg0 0x70 "s"
|
||||
DW_OP_breg1 0x71 "s"
|
||||
DW_OP_breg2 0x72 "s"
|
||||
DW_OP_breg3 0x73 "s"
|
||||
DW_OP_breg4 0x74 "s"
|
||||
DW_OP_breg5 0x75 "s"
|
||||
DW_OP_breg6 0x76 "s"
|
||||
DW_OP_breg7 0x77 "s"
|
||||
DW_OP_breg8 0x78 "s"
|
||||
DW_OP_breg9 0x79 "s"
|
||||
DW_OP_breg10 0x7a "s"
|
||||
DW_OP_breg11 0x7b "s"
|
||||
DW_OP_breg12 0x7c "s"
|
||||
DW_OP_breg13 0x7d "s"
|
||||
DW_OP_breg14 0x7e "s"
|
||||
DW_OP_breg15 0x7f "s"
|
||||
DW_OP_breg16 0x80 "s"
|
||||
DW_OP_breg17 0x81 "s"
|
||||
DW_OP_breg18 0x82 "s"
|
||||
DW_OP_breg19 0x83 "s"
|
||||
DW_OP_breg20 0x84 "s"
|
||||
DW_OP_breg21 0x85 "s"
|
||||
DW_OP_breg22 0x86 "s"
|
||||
DW_OP_breg23 0x87 "s"
|
||||
DW_OP_breg24 0x88 "s"
|
||||
DW_OP_breg25 0x89 "s"
|
||||
DW_OP_breg26 0x8a "s"
|
||||
DW_OP_breg27 0x8b "s"
|
||||
DW_OP_breg28 0x8c "s"
|
||||
DW_OP_breg29 0x8d "s"
|
||||
DW_OP_breg30 0x8e "s"
|
||||
DW_OP_breg31 0x8f "s"
|
||||
DW_OP_regx 0x90 "s" register
|
||||
DW_OP_fbreg 0x91 "s" framebase
|
||||
DW_OP_bregx 0x92 "us"
|
||||
DW_OP_piece 0x93 "u" piece
|
||||
DW_OP_deref_size 0x94 "1"
|
||||
DW_OP_xderef_size 0x95 "1"
|
||||
DW_OP_nop 0x96 ""
|
||||
DW_OP_push_object_address 0x97 ""
|
||||
DW_OP_call2 0x98 "2"
|
||||
DW_OP_call4 0x99 "4"
|
||||
DW_OP_call_ref 0x9a "4"
|
||||
DW_OP_form_tls_address 0x9b ""
|
||||
DW_OP_call_frame_cfa 0x9c "" callframecfa
|
||||
DW_OP_bit_piece 0x9d "uu"
|
||||
DW_OP_implicit_value 0x9e "B"
|
||||
DW_OP_stack_value 0x9f ""
|
@ -73,7 +73,7 @@ func (reader *Reader) AddrFor(name string) (uint64, error) {
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("type assertion failed")
|
||||
}
|
||||
addr, err := op.ExecuteStackProgram(op.DwarfRegisters{}, instructions)
|
||||
addr, _, err := op.ExecuteStackProgram(op.DwarfRegisters{}, instructions)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@ -99,7 +99,7 @@ func (reader *Reader) AddrForMember(member string, initialInstructions []byte) (
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
addr, err := op.ExecuteStackProgram(op.DwarfRegisters{}, append(initialInstructions, instructions...))
|
||||
addr, _, err := op.ExecuteStackProgram(op.DwarfRegisters{}, append(initialInstructions, instructions...))
|
||||
return uint64(addr), err
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"debug/elf"
|
||||
"debug/macho"
|
||||
"debug/pe"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@ -17,6 +18,7 @@ import (
|
||||
"github.com/derekparker/delve/pkg/dwarf/frame"
|
||||
"github.com/derekparker/delve/pkg/dwarf/godwarf"
|
||||
"github.com/derekparker/delve/pkg/dwarf/line"
|
||||
"github.com/derekparker/delve/pkg/dwarf/op"
|
||||
"github.com/derekparker/delve/pkg/dwarf/reader"
|
||||
)
|
||||
|
||||
@ -32,6 +34,7 @@ type BinaryInfo struct {
|
||||
Arch Arch
|
||||
dwarf *dwarf.Data
|
||||
frameEntries frame.FrameDescriptionEntries
|
||||
loclist loclistReader
|
||||
compileUnits []*compileUnit
|
||||
types map[string]dwarf.Offset
|
||||
packageVars map[string]dwarf.Offset
|
||||
@ -116,6 +119,65 @@ func (fn *Function) BaseName() string {
|
||||
return fn.Name
|
||||
}
|
||||
|
||||
type loclistReader struct {
|
||||
data []byte
|
||||
cur int
|
||||
ptrSz int
|
||||
}
|
||||
|
||||
func (rdr *loclistReader) Seek(off int) {
|
||||
rdr.cur = off
|
||||
}
|
||||
|
||||
func (rdr *loclistReader) read(sz int) []byte {
|
||||
r := rdr.data[rdr.cur : rdr.cur+sz]
|
||||
rdr.cur += sz
|
||||
return r
|
||||
}
|
||||
|
||||
func (rdr *loclistReader) oneAddr() uint64 {
|
||||
switch rdr.ptrSz {
|
||||
case 4:
|
||||
addr := binary.LittleEndian.Uint32(rdr.read(rdr.ptrSz))
|
||||
if addr == ^uint32(0) {
|
||||
return ^uint64(0)
|
||||
}
|
||||
return uint64(addr)
|
||||
case 8:
|
||||
addr := uint64(binary.LittleEndian.Uint64(rdr.read(rdr.ptrSz)))
|
||||
return addr
|
||||
default:
|
||||
panic("bad address size")
|
||||
}
|
||||
}
|
||||
|
||||
func (rdr *loclistReader) Next(e *loclistEntry) bool {
|
||||
e.lowpc = rdr.oneAddr()
|
||||
e.highpc = rdr.oneAddr()
|
||||
|
||||
if e.lowpc == 0 && e.highpc == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
if e.BaseAddressSelection() {
|
||||
e.instr = nil
|
||||
return true
|
||||
}
|
||||
|
||||
instrlen := binary.LittleEndian.Uint16(rdr.read(2))
|
||||
e.instr = rdr.read(int(instrlen))
|
||||
return true
|
||||
}
|
||||
|
||||
type loclistEntry struct {
|
||||
lowpc, highpc uint64
|
||||
instr []byte
|
||||
}
|
||||
|
||||
func (e *loclistEntry) BaseAddressSelection() bool {
|
||||
return e.lowpc == ^uint64(0)
|
||||
}
|
||||
|
||||
func NewBinaryInfo(goos, goarch string) BinaryInfo {
|
||||
r := BinaryInfo{GOOS: goos, nameOfRuntimeType: make(map[uintptr]nameOfRuntimeTypeEntry), typeCache: make(map[dwarf.Offset]godwarf.Type)}
|
||||
|
||||
@ -228,8 +290,9 @@ type nilCloser struct{}
|
||||
|
||||
func (c *nilCloser) Close() error { return nil }
|
||||
|
||||
// New creates a new BinaryInfo object using the specified data. Use LoadBinary instead.
|
||||
func (bi *BinaryInfo) LoadFromData(dwdata *dwarf.Data, debugFrameBytes []byte, debugLineBytes []byte) {
|
||||
// LoadFromData creates a new BinaryInfo object using the specified data.
|
||||
// This is used for debugging BinaryInfo, you should use LoadBinary instead.
|
||||
func (bi *BinaryInfo) LoadFromData(dwdata *dwarf.Data, debugFrameBytes, debugLineBytes, debugLocBytes []byte) {
|
||||
bi.closer = (*nilCloser)(nil)
|
||||
bi.dwarf = dwdata
|
||||
|
||||
@ -237,10 +300,73 @@ func (bi *BinaryInfo) LoadFromData(dwdata *dwarf.Data, debugFrameBytes []byte, d
|
||||
bi.frameEntries = frame.Parse(debugFrameBytes, frame.DwarfEndian(debugFrameBytes))
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
go bi.loadDebugInfoMaps(debugLineBytes, &wg)
|
||||
wg.Wait()
|
||||
bi.loclistInit(debugLocBytes)
|
||||
|
||||
bi.loadDebugInfoMaps(debugLineBytes, nil)
|
||||
}
|
||||
|
||||
func (bi *BinaryInfo) loclistInit(data []byte) {
|
||||
bi.loclist.data = data
|
||||
bi.loclist.ptrSz = bi.Arch.PtrSize()
|
||||
}
|
||||
|
||||
// Location returns the location described by attribute attr of entry.
|
||||
// This will either be an int64 address or a slice of Pieces for locations
|
||||
// that don't correspond to a single memory address (registers, composite
|
||||
// locations).
|
||||
func (bi *BinaryInfo) Location(entry *dwarf.Entry, attr dwarf.Attr, pc uint64, regs op.DwarfRegisters) (int64, []op.Piece, error) {
|
||||
a := entry.Val(attr)
|
||||
if a == nil {
|
||||
return 0, nil, fmt.Errorf("no location attribute %s", attr)
|
||||
}
|
||||
if instr, ok := a.([]byte); ok {
|
||||
return op.ExecuteStackProgram(regs, instr)
|
||||
}
|
||||
off, ok := a.(int64)
|
||||
if !ok {
|
||||
return 0, nil, fmt.Errorf("could not interpret location attribute %s", attr)
|
||||
}
|
||||
if bi.loclist.data == nil {
|
||||
return 0, nil, fmt.Errorf("could not find loclist entry at %#x for address %#x (no debug_loc section found)", off, pc)
|
||||
}
|
||||
instr := bi.loclistEntry(off, pc)
|
||||
if instr == nil {
|
||||
return 0, nil, fmt.Errorf("could not find loclist entry at %#x for address %#x", off, pc)
|
||||
}
|
||||
return op.ExecuteStackProgram(regs, instr)
|
||||
}
|
||||
|
||||
// loclistEntry returns the loclist entry in the loclist starting at off,
|
||||
// for address pc.
|
||||
func (bi *BinaryInfo) loclistEntry(off int64, pc uint64) []byte {
|
||||
var base uint64
|
||||
if cu := bi.findCompileUnit(pc); cu != nil {
|
||||
base = cu.LowPC
|
||||
}
|
||||
|
||||
bi.loclist.Seek(int(off))
|
||||
var e loclistEntry
|
||||
for bi.loclist.Next(&e) {
|
||||
if e.BaseAddressSelection() {
|
||||
base = e.highpc
|
||||
continue
|
||||
}
|
||||
if pc >= e.lowpc+base && pc < e.highpc+base {
|
||||
return e.instr
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// findCompileUnit returns the compile unit containing address pc.
|
||||
func (bi *BinaryInfo) findCompileUnit(pc uint64) *compileUnit {
|
||||
for _, cu := range bi.compileUnits {
|
||||
if pc >= cu.LowPC && pc < cu.HighPC {
|
||||
return cu
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ELF ///////////////////////////////////////////////////////////////
|
||||
@ -267,6 +393,7 @@ func (bi *BinaryInfo) LoadBinaryInfoElf(path string, wg *sync.WaitGroup) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
bi.loclistInit(getDebugLocElf(elfFile))
|
||||
|
||||
wg.Add(3)
|
||||
go bi.parseDebugFrameElf(elfFile, wg)
|
||||
@ -310,6 +437,14 @@ func getDebugLineInfoElf(exe *elf.File) ([]byte, error) {
|
||||
return nil, errors.New("could not find .debug_line section in binary")
|
||||
}
|
||||
|
||||
func getDebugLocElf(exe *elf.File) []byte {
|
||||
if sec := exe.Section(".debug_loc"); sec != nil {
|
||||
debugLoc, _ := exe.Section(".debug_loc").Data()
|
||||
return debugLoc
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bi *BinaryInfo) setGStructOffsetElf(exe *elf.File, wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
|
||||
@ -368,6 +503,7 @@ func (bi *BinaryInfo) LoadBinaryInfoPE(path string, wg *sync.WaitGroup) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
bi.loclistInit(getDebugLocPE(peFile))
|
||||
|
||||
wg.Add(2)
|
||||
go bi.parseDebugFramePE(peFile, wg)
|
||||
@ -505,6 +641,14 @@ func getDebugLineInfoPE(exe *pe.File) ([]byte, error) {
|
||||
return nil, errors.New("could not find .debug_line section in binary")
|
||||
}
|
||||
|
||||
func getDebugLocPE(exe *pe.File) []byte {
|
||||
if sec := exe.Section(".debug_loc"); sec != nil {
|
||||
debugLoc, _ := sec.Data()
|
||||
return debugLoc
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MACH-O ////////////////////////////////////////////////////////////
|
||||
|
||||
func (bi *BinaryInfo) LoadBinaryInfoMacho(path string, wg *sync.WaitGroup) error {
|
||||
@ -525,6 +669,7 @@ func (bi *BinaryInfo) LoadBinaryInfoMacho(path string, wg *sync.WaitGroup) error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
bi.loclistInit(getDebugLocMacho(exe))
|
||||
|
||||
wg.Add(2)
|
||||
go bi.parseDebugFrameMacho(exe, wg)
|
||||
@ -567,3 +712,11 @@ func getDebugLineInfoMacho(exe *macho.File) ([]byte, error) {
|
||||
}
|
||||
return nil, errors.New("could not find __debug_line section in binary")
|
||||
}
|
||||
|
||||
func getDebugLocMacho(exe *macho.File) []byte {
|
||||
if sec := exe.Section("__debug_loc"); sec != nil {
|
||||
debugLoc, _ := sec.Data()
|
||||
return debugLoc
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -16,18 +16,19 @@ import (
|
||||
"github.com/derekparker/delve/pkg/dwarf/godwarf"
|
||||
"github.com/derekparker/delve/pkg/dwarf/op"
|
||||
"github.com/derekparker/delve/pkg/proc"
|
||||
"github.com/derekparker/delve/pkg/proc/core"
|
||||
)
|
||||
|
||||
const defaultCFA = 0xc420051d00
|
||||
|
||||
func fakeBinaryInfo(t *testing.T, dwb *dwarfbuilder.Builder) *proc.BinaryInfo {
|
||||
abbrev, aranges, frame, info, line, pubnames, ranges, str, err := dwb.Build()
|
||||
abbrev, aranges, frame, info, line, pubnames, ranges, str, loc, err := dwb.Build()
|
||||
assertNoError(err, t, "dwarbuilder.Build")
|
||||
dwdata, err := dwarf.New(abbrev, aranges, frame, info, line, pubnames, ranges, str)
|
||||
assertNoError(err, t, "creating dwarf")
|
||||
|
||||
bi := proc.NewBinaryInfo("linux", "amd64")
|
||||
bi.LoadFromData(dwdata, frame, line)
|
||||
bi.LoadFromData(dwdata, frame, line, loc)
|
||||
|
||||
return &bi
|
||||
}
|
||||
@ -66,22 +67,6 @@ func (mem *fakeMemory) WriteMemory(uintptr, []byte) (int, error) {
|
||||
return 0, fmt.Errorf("not implemented")
|
||||
}
|
||||
|
||||
// fakeRegisters implements op.DwarfRegisters with arbitrary values for each
|
||||
// register.
|
||||
type fakeRegisters struct {
|
||||
regs [32]uint64
|
||||
}
|
||||
|
||||
func (regs *fakeRegisters) Set(i int, val uint64) {
|
||||
regs.regs[i] = val
|
||||
}
|
||||
|
||||
func (regs *fakeRegisters) Get(i int) []byte {
|
||||
var out bytes.Buffer
|
||||
binary.Write(&out, binary.LittleEndian, regs.regs[i])
|
||||
return out.Bytes()
|
||||
}
|
||||
|
||||
func uintExprCheck(t *testing.T, scope *proc.EvalScope, expr string, tgt uint64) {
|
||||
thevar, err := scope.EvalExpression(expr, normalLoadConfig)
|
||||
assertNoError(err, t, fmt.Sprintf("EvalExpression(%s)", expr))
|
||||
@ -95,7 +80,7 @@ func uintExprCheck(t *testing.T, scope *proc.EvalScope, expr string, tgt uint64)
|
||||
}
|
||||
|
||||
func dwarfExprCheck(t *testing.T, mem proc.MemoryReadWriter, regs op.DwarfRegisters, bi *proc.BinaryInfo, testCases map[string]uint16) *proc.EvalScope {
|
||||
scope := &proc.EvalScope{PC: 0x40100, CFA: defaultCFA, Mem: mem, Gvar: nil, BinInfo: bi}
|
||||
scope := &proc.EvalScope{PC: 0x40100, Regs: regs, Mem: mem, Gvar: nil, BinInfo: bi}
|
||||
for name, value := range testCases {
|
||||
uintExprCheck(t, scope, name, uint64(value))
|
||||
}
|
||||
@ -103,6 +88,14 @@ func dwarfExprCheck(t *testing.T, mem proc.MemoryReadWriter, regs op.DwarfRegist
|
||||
return scope
|
||||
}
|
||||
|
||||
func dwarfRegisters(regs *core.Registers) op.DwarfRegisters {
|
||||
a := proc.AMD64Arch("linux")
|
||||
dwarfRegs := a.RegistersToDwarfRegisters(regs)
|
||||
dwarfRegs.CFA = defaultCFA
|
||||
dwarfRegs.FrameBase = defaultCFA
|
||||
return dwarfRegs
|
||||
}
|
||||
|
||||
func TestDwarfExprRegisters(t *testing.T) {
|
||||
testCases := map[string]uint16{
|
||||
"a": 0x1234,
|
||||
@ -112,23 +105,23 @@ func TestDwarfExprRegisters(t *testing.T) {
|
||||
|
||||
dwb := dwarfbuilder.New()
|
||||
|
||||
uint16off := dwb.BaseType("uint16", dwarfbuilder.DW_ATE_unsigned, 2)
|
||||
uint16off := dwb.AddBaseType("uint16", dwarfbuilder.DW_ATE_unsigned, 2)
|
||||
|
||||
dwb.Subprogram("main.main", 0x40100, 0x41000)
|
||||
dwb.AddSubprogram("main.main", 0x40100, 0x41000)
|
||||
dwb.Attr(dwarf.AttrFrameBase, dwarfbuilder.LocationBlock(op.DW_OP_call_frame_cfa))
|
||||
dwb.Variable("a", uint16off, dwarfbuilder.LocationBlock(op.DW_OP_reg0))
|
||||
dwb.Variable("b", uint16off, dwarfbuilder.LocationBlock(op.DW_OP_fbreg, int(8)))
|
||||
dwb.Variable("c", uint16off, dwarfbuilder.LocationBlock(op.DW_OP_regx, int(1)))
|
||||
dwb.AddVariable("a", uint16off, dwarfbuilder.LocationBlock(op.DW_OP_reg0))
|
||||
dwb.AddVariable("b", uint16off, dwarfbuilder.LocationBlock(op.DW_OP_fbreg, int(8)))
|
||||
dwb.AddVariable("c", uint16off, dwarfbuilder.LocationBlock(op.DW_OP_regx, int(1)))
|
||||
dwb.TagClose()
|
||||
|
||||
bi := fakeBinaryInfo(t, dwb)
|
||||
|
||||
mem := newFakeMemory(defaultCFA, uint64(0), uint64(testCases["b"]), uint16(testCases["pair.v"]))
|
||||
var regs fakeRegisters
|
||||
regs.Set(0, uint64(testCases["a"]))
|
||||
regs.Set(1, uint64(testCases["c"]))
|
||||
regs := core.Registers{LinuxCoreRegisters: &core.LinuxCoreRegisters{}}
|
||||
regs.Rax = uint64(testCases["a"])
|
||||
regs.Rdx = uint64(testCases["c"])
|
||||
|
||||
dwarfExprCheck(t, mem, ®s, bi, testCases)
|
||||
dwarfExprCheck(t, mem, dwarfRegisters(®s), bi, testCases)
|
||||
}
|
||||
|
||||
func TestDwarfExprComposite(t *testing.T) {
|
||||
@ -141,46 +134,47 @@ func TestDwarfExprComposite(t *testing.T) {
|
||||
|
||||
dwb := dwarfbuilder.New()
|
||||
|
||||
uint16off := dwb.BaseType("uint16", dwarfbuilder.DW_ATE_unsigned, 2)
|
||||
intoff := dwb.BaseType("int", dwarfbuilder.DW_ATE_signed, 8)
|
||||
uint16off := dwb.AddBaseType("uint16", dwarfbuilder.DW_ATE_unsigned, 2)
|
||||
intoff := dwb.AddBaseType("int", dwarfbuilder.DW_ATE_signed, 8)
|
||||
|
||||
byteoff := dwb.BaseType("uint8", dwarfbuilder.DW_ATE_unsigned, 1)
|
||||
byteoff := dwb.AddBaseType("uint8", dwarfbuilder.DW_ATE_unsigned, 1)
|
||||
|
||||
byteptroff := dwb.TagOpen(dwarf.TagPointerType, "*uint8")
|
||||
dwb.Attr(godwarf.AttrGoKind, uint8(22))
|
||||
dwb.Attr(dwarf.AttrType, byteoff)
|
||||
dwb.TagClose()
|
||||
|
||||
pairoff := dwb.StructType("main.pair", 4)
|
||||
pairoff := dwb.AddStructType("main.pair", 4)
|
||||
dwb.Attr(godwarf.AttrGoKind, uint8(25))
|
||||
dwb.Member("k", uint16off, dwarfbuilder.LocationBlock(op.DW_OP_plus_uconst, uint(0)))
|
||||
dwb.Member("v", uint16off, dwarfbuilder.LocationBlock(op.DW_OP_plus_uconst, uint(2)))
|
||||
dwb.AddMember("k", uint16off, dwarfbuilder.LocationBlock(op.DW_OP_plus_uconst, uint(0)))
|
||||
dwb.AddMember("v", uint16off, dwarfbuilder.LocationBlock(op.DW_OP_plus_uconst, uint(2)))
|
||||
dwb.TagClose()
|
||||
|
||||
stringoff := dwb.StructType("string", 16)
|
||||
stringoff := dwb.AddStructType("string", 16)
|
||||
dwb.Attr(godwarf.AttrGoKind, uint8(24))
|
||||
dwb.Member("str", byteptroff, dwarfbuilder.LocationBlock(op.DW_OP_plus_uconst, uint(0)))
|
||||
dwb.Member("len", intoff, dwarfbuilder.LocationBlock(op.DW_OP_plus_uconst, uint(8)))
|
||||
dwb.AddMember("str", byteptroff, dwarfbuilder.LocationBlock(op.DW_OP_plus_uconst, uint(0)))
|
||||
dwb.AddMember("len", intoff, dwarfbuilder.LocationBlock(op.DW_OP_plus_uconst, uint(8)))
|
||||
dwb.TagClose()
|
||||
|
||||
dwb.Subprogram("main.main", 0x40100, 0x41000)
|
||||
dwb.Variable("pair", pairoff, dwarfbuilder.LocationBlock(
|
||||
dwb.AddSubprogram("main.main", 0x40100, 0x41000)
|
||||
dwb.AddVariable("pair", pairoff, dwarfbuilder.LocationBlock(
|
||||
op.DW_OP_reg2, op.DW_OP_piece, uint(2),
|
||||
op.DW_OP_call_frame_cfa, op.DW_OP_consts, int(16), op.DW_OP_plus, op.DW_OP_piece, uint(2)))
|
||||
dwb.Variable("s", stringoff, dwarfbuilder.LocationBlock(
|
||||
dwb.AddVariable("s", stringoff, dwarfbuilder.LocationBlock(
|
||||
op.DW_OP_reg1, op.DW_OP_piece, uint(8),
|
||||
op.DW_OP_reg0, op.DW_OP_piece, uint(8)))
|
||||
dwb.TagClose()
|
||||
|
||||
bi := fakeBinaryInfo(t, dwb)
|
||||
|
||||
mem := newFakeMemory(defaultCFA, uint64(0), uint64(0), uint16(testCases["pair.v"]), stringVal)
|
||||
var regs fakeRegisters
|
||||
regs.Set(0, uint64(len(stringVal)))
|
||||
regs.Set(1, defaultCFA+18)
|
||||
regs.Set(2, uint64(testCases["pair.k"]))
|
||||
mem := newFakeMemory(defaultCFA, uint64(0), uint64(0), uint16(testCases["pair.v"]), []byte(stringVal))
|
||||
var regs core.Registers
|
||||
regs.LinuxCoreRegisters = &core.LinuxCoreRegisters{}
|
||||
regs.Rax = uint64(len(stringVal))
|
||||
regs.Rdx = defaultCFA + 18
|
||||
regs.Rcx = uint64(testCases["pair.k"])
|
||||
|
||||
scope := dwarfExprCheck(t, mem, ®s, bi, testCases)
|
||||
scope := dwarfExprCheck(t, mem, dwarfRegisters(®s), bi, testCases)
|
||||
|
||||
thevar, err := scope.EvalExpression("s", normalLoadConfig)
|
||||
assertNoError(err, t, fmt.Sprintf("EvalExpression(s)", "s"))
|
||||
@ -199,10 +193,10 @@ func TestDwarfExprLoclist(t *testing.T) {
|
||||
|
||||
dwb := dwarfbuilder.New()
|
||||
|
||||
uint16off := dwb.BaseType("uint16", dwarfbuilder.DW_ATE_unsigned, 2)
|
||||
uint16off := dwb.AddBaseType("uint16", dwarfbuilder.DW_ATE_unsigned, 2)
|
||||
|
||||
dwb.Subprogram("main.main", 0x40100, 0x41000)
|
||||
dwb.Variable("a", uint16off, []dwarfbuilder.LocEntry{
|
||||
dwb.AddSubprogram("main.main", 0x40100, 0x41000)
|
||||
dwb.AddVariable("a", uint16off, []dwarfbuilder.LocEntry{
|
||||
{0x40100, 0x40700, dwarfbuilder.LocationBlock(op.DW_OP_call_frame_cfa)},
|
||||
{0x40700, 0x41000, dwarfbuilder.LocationBlock(op.DW_OP_call_frame_cfa, op.DW_OP_consts, int(2), op.DW_OP_plus)},
|
||||
})
|
||||
@ -211,8 +205,9 @@ func TestDwarfExprLoclist(t *testing.T) {
|
||||
bi := fakeBinaryInfo(t, dwb)
|
||||
|
||||
mem := newFakeMemory(defaultCFA, uint16(before), uint16(after))
|
||||
regs := core.Registers{LinuxCoreRegisters: &core.LinuxCoreRegisters{}}
|
||||
|
||||
scope := &proc.EvalScope{PC: 0x40100, CFA: defaultCFA, Mem: mem, Gvar: nil, BinInfo: bi}
|
||||
scope := &proc.EvalScope{PC: 0x40100, Regs: dwarfRegisters(®s), Mem: mem, Gvar: nil, BinInfo: bi}
|
||||
|
||||
uintExprCheck(t, scope, "a", before)
|
||||
scope.PC = 0x40800
|
||||
|
@ -87,7 +87,7 @@ func (scope *EvalScope) evalToplevelTypeCast(t ast.Expr, cfg LoadConfig) (*Varia
|
||||
return nil, converr
|
||||
}
|
||||
for i, ch := range []byte(constant.StringVal(argv.Value)) {
|
||||
e := scope.newVariable("", argv.Addr+uintptr(i), targetType.(*godwarf.SliceType).ElemType)
|
||||
e := scope.newVariable("", argv.Addr+uintptr(i), targetType.(*godwarf.SliceType).ElemType, argv.mem)
|
||||
e.loaded = true
|
||||
e.Value = constant.MakeInt64(int64(ch))
|
||||
v.Children = append(v.Children, *e)
|
||||
@ -101,7 +101,7 @@ func (scope *EvalScope) evalToplevelTypeCast(t ast.Expr, cfg LoadConfig) (*Varia
|
||||
return nil, converr
|
||||
}
|
||||
for i, ch := range constant.StringVal(argv.Value) {
|
||||
e := scope.newVariable("", argv.Addr+uintptr(i), targetType.(*godwarf.SliceType).ElemType)
|
||||
e := scope.newVariable("", argv.Addr+uintptr(i), targetType.(*godwarf.SliceType).ElemType, argv.mem)
|
||||
e.loaded = true
|
||||
e.Value = constant.MakeInt64(int64(ch))
|
||||
v.Children = append(v.Children, *e)
|
||||
@ -183,7 +183,7 @@ func (scope *EvalScope) evalAST(t ast.Expr) (*Variable, error) {
|
||||
}
|
||||
return scope.Gvar.clone(), nil
|
||||
} else if maybePkg.Name == "runtime" && node.Sel.Name == "frameoff" {
|
||||
return newConstant(constant.MakeInt64(scope.CFA-int64(scope.StackHi)), scope.Mem), nil
|
||||
return newConstant(constant.MakeInt64(scope.Regs.CFA-int64(scope.StackHi)), scope.Mem), nil
|
||||
} else if v, err := scope.packageVarAddr(maybePkg.Name + "." + node.Sel.Name); err == nil {
|
||||
return v, nil
|
||||
}
|
||||
@ -286,7 +286,7 @@ func (scope *EvalScope) evalTypeCast(node *ast.CallExpr) (*Variable, error) {
|
||||
|
||||
n, _ := constant.Int64Val(argv.Value)
|
||||
|
||||
v.Children = []Variable{*(scope.newVariable("", uintptr(n), ttyp.Type))}
|
||||
v.Children = []Variable{*(scope.newVariable("", uintptr(n), ttyp.Type, scope.Mem))}
|
||||
return v, nil
|
||||
|
||||
case *godwarf.UintType:
|
||||
@ -512,7 +512,7 @@ func complexBuiltin(args []*Variable, nodeargs []ast.Expr) (*Variable, error) {
|
||||
|
||||
typ := &godwarf.ComplexType{BasicType: godwarf.BasicType{CommonType: godwarf.CommonType{ByteSize: int64(sz / 8), Name: fmt.Sprintf("complex%d", sz)}, BitSize: sz, BitOffset: 0}}
|
||||
|
||||
r := realev.newVariable("", 0, typ)
|
||||
r := realev.newVariable("", 0, typ, nil)
|
||||
r.Value = constant.BinaryOp(realev.Value, token.ADD, constant.MakeImag(imagev.Value))
|
||||
return r, nil
|
||||
}
|
||||
@ -786,7 +786,7 @@ func (scope *EvalScope) evalAddrOf(node *ast.UnaryExpr) (*Variable, error) {
|
||||
xev.OnlyAddr = true
|
||||
|
||||
typename := "*" + xev.DwarfType.Common().Name
|
||||
rv := scope.newVariable("", 0, &godwarf.PtrType{CommonType: godwarf.CommonType{ByteSize: int64(scope.BinInfo.Arch.PtrSize()), Name: typename}, Type: xev.DwarfType})
|
||||
rv := scope.newVariable("", 0, &godwarf.PtrType{CommonType: godwarf.CommonType{ByteSize: int64(scope.BinInfo.Arch.PtrSize()), Name: typename}, Type: xev.DwarfType}, scope.Mem)
|
||||
rv.Children = []Variable{*xev}
|
||||
rv.loaded = true
|
||||
|
||||
@ -851,7 +851,7 @@ func (scope *EvalScope) evalUnary(node *ast.UnaryExpr) (*Variable, error) {
|
||||
return nil, err
|
||||
}
|
||||
if xv.DwarfType != nil {
|
||||
r := xv.newVariable("", 0, xv.DwarfType)
|
||||
r := xv.newVariable("", 0, xv.DwarfType, scope.Mem)
|
||||
r.Value = rc
|
||||
return r, nil
|
||||
}
|
||||
@ -994,7 +994,7 @@ func (scope *EvalScope) evalBinary(node *ast.BinaryExpr) (*Variable, error) {
|
||||
return newConstant(rc, xv.mem), nil
|
||||
}
|
||||
|
||||
r := xv.newVariable("", 0, typ)
|
||||
r := xv.newVariable("", 0, typ, scope.Mem)
|
||||
r.Value = rc
|
||||
if r.Kind == reflect.String {
|
||||
r.Len = xv.Len + yv.Len
|
||||
@ -1207,7 +1207,11 @@ func (v *Variable) sliceAccess(idx int) (*Variable, error) {
|
||||
if idx < 0 || int64(idx) >= v.Len {
|
||||
return nil, fmt.Errorf("index out of bounds")
|
||||
}
|
||||
return v.newVariable("", v.Base+uintptr(int64(idx)*v.stride), v.fieldType), nil
|
||||
mem := v.mem
|
||||
if v.Kind != reflect.Array {
|
||||
mem = DereferenceMemory(mem)
|
||||
}
|
||||
return v.newVariable("", v.Base+uintptr(int64(idx)*v.stride), v.fieldType, mem), nil
|
||||
}
|
||||
|
||||
func (v *Variable) mapAccess(idx *Variable) (*Variable, error) {
|
||||
@ -1261,7 +1265,12 @@ func (v *Variable) reslice(low int64, high int64) (*Variable, error) {
|
||||
typ = fakeSliceType(v.fieldType)
|
||||
}
|
||||
|
||||
r := v.newVariable("", 0, typ)
|
||||
mem := v.mem
|
||||
if v.Kind != reflect.Array {
|
||||
mem = DereferenceMemory(mem)
|
||||
}
|
||||
|
||||
r := v.newVariable("", 0, typ, mem)
|
||||
r.Cap = len
|
||||
r.Len = len
|
||||
r.Base = base
|
||||
|
@ -1,5 +1,11 @@
|
||||
package proc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/derekparker/delve/pkg/dwarf/op"
|
||||
)
|
||||
|
||||
const cacheEnabled = true
|
||||
|
||||
// MemoryReader is like io.ReaderAt, but the offset is a uintptr so that it
|
||||
@ -46,7 +52,8 @@ func cacheMemory(mem MemoryReadWriter, addr uintptr, size int) MemoryReadWriter
|
||||
if size <= 0 {
|
||||
return mem
|
||||
}
|
||||
if cacheMem, isCache := mem.(*memCache); isCache {
|
||||
switch cacheMem := mem.(type) {
|
||||
case *memCache:
|
||||
if cacheMem.contains(addr, size) {
|
||||
return mem
|
||||
} else {
|
||||
@ -57,6 +64,8 @@ func cacheMemory(mem MemoryReadWriter, addr uintptr, size int) MemoryReadWriter
|
||||
}
|
||||
return &memCache{addr, cache, mem}
|
||||
}
|
||||
case *compositeMemory:
|
||||
return mem
|
||||
}
|
||||
cache := make([]byte, size)
|
||||
_, err := mem.ReadMemory(cache, addr)
|
||||
@ -65,3 +74,62 @@ func cacheMemory(mem MemoryReadWriter, addr uintptr, size int) MemoryReadWriter
|
||||
}
|
||||
return &memCache{addr, cache, mem}
|
||||
}
|
||||
|
||||
// fakeAddress used by extractVarInfoFromEntry for variables that do not
|
||||
// have a memory address, we can't use 0 because a lot of code (likely
|
||||
// including client code) assumes that addr == 0 is nil
|
||||
const fakeAddress = 0xbeef0000
|
||||
|
||||
type compositeMemory struct {
|
||||
realmem MemoryReadWriter
|
||||
regs op.DwarfRegisters
|
||||
pieces []op.Piece
|
||||
data []byte
|
||||
}
|
||||
|
||||
func newCompositeMemory(mem MemoryReadWriter, regs op.DwarfRegisters, pieces []op.Piece) *compositeMemory {
|
||||
cmem := &compositeMemory{realmem: mem, regs: regs, pieces: pieces, data: []byte{}}
|
||||
for _, piece := range pieces {
|
||||
if piece.IsRegister {
|
||||
reg := regs.Bytes(piece.RegNum)
|
||||
sz := piece.Size
|
||||
if sz == 0 && len(pieces) == 1 {
|
||||
sz = len(reg)
|
||||
}
|
||||
cmem.data = append(cmem.data, reg[:sz]...)
|
||||
} else {
|
||||
buf := make([]byte, piece.Size)
|
||||
mem.ReadMemory(buf, uintptr(piece.Addr))
|
||||
cmem.data = append(cmem.data, buf...)
|
||||
}
|
||||
}
|
||||
return cmem
|
||||
}
|
||||
|
||||
func (mem *compositeMemory) ReadMemory(data []byte, addr uintptr) (int, error) {
|
||||
addr -= fakeAddress
|
||||
if addr >= uintptr(len(mem.data)) || addr+uintptr(len(data)) > uintptr(len(mem.data)) {
|
||||
return 0, errors.New("read out of bounds")
|
||||
}
|
||||
copy(data, mem.data[addr:addr+uintptr(len(data))])
|
||||
return len(data), nil
|
||||
}
|
||||
|
||||
func (mem *compositeMemory) WriteMemory(addr uintptr, data []byte) (int, error) {
|
||||
//TODO(aarzilli): implement
|
||||
return 0, errors.New("can't write composite memory")
|
||||
}
|
||||
|
||||
// DereferenceMemory returns a MemoryReadWriter that can read and write the
|
||||
// memory pointed to by pointers in this memory.
|
||||
// Normally mem and mem.Dereference are the same object, they are different
|
||||
// only if this MemoryReadWriter is used to access memory outside of the
|
||||
// normal address space of the inferior process (such as data contained in
|
||||
// registers, or composite memory).
|
||||
func DereferenceMemory(mem MemoryReadWriter) MemoryReadWriter {
|
||||
switch mem := mem.(type) {
|
||||
case *compositeMemory:
|
||||
return mem.realmem
|
||||
}
|
||||
return mem
|
||||
}
|
||||
|
@ -3,6 +3,8 @@ package proc
|
||||
import (
|
||||
"go/constant"
|
||||
"unsafe"
|
||||
|
||||
"github.com/derekparker/delve/pkg/dwarf/op"
|
||||
)
|
||||
|
||||
// delve counterpart to runtime.moduledata
|
||||
@ -13,7 +15,7 @@ type moduleData struct {
|
||||
|
||||
func loadModuleData(bi *BinaryInfo, mem MemoryReadWriter) (err error) {
|
||||
bi.loadModuleDataOnce.Do(func() {
|
||||
scope := &EvalScope{0, 0, mem, nil, bi, 0}
|
||||
scope := &EvalScope{0, op.DwarfRegisters{}, mem, nil, bi, 0}
|
||||
var md *Variable
|
||||
md, err = scope.packageVarAddr("runtime.firstmoduledata")
|
||||
if err != nil {
|
||||
@ -81,7 +83,7 @@ func resolveTypeOff(bi *BinaryInfo, typeAddr uintptr, off uintptr, mem MemoryRea
|
||||
}
|
||||
v.loadValue(LoadConfig{false, 1, 0, 0, -1})
|
||||
addr, _ := constant.Int64Val(v.Value)
|
||||
return v.newVariable(v.Name, uintptr(addr), rtyp), nil
|
||||
return v.newVariable(v.Name, uintptr(addr), rtyp, mem), nil
|
||||
}
|
||||
|
||||
if t, _ := md.typemapVar.mapAccess(newConstant(constant.MakeUint64(uint64(off)), mem)); t != nil {
|
||||
@ -119,7 +121,7 @@ func resolveNameOff(bi *BinaryInfo, typeAddr uintptr, off uintptr, mem MemoryRea
|
||||
}
|
||||
|
||||
func reflectOffsMapAccess(bi *BinaryInfo, off uintptr, mem MemoryReadWriter) (*Variable, error) {
|
||||
scope := &EvalScope{0, 0, mem, nil, bi, 0}
|
||||
scope := &EvalScope{0, op.DwarfRegisters{}, mem, nil, bi, 0}
|
||||
reflectOffs, err := scope.packageVarAddr("runtime.reflectOffs")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -481,12 +481,10 @@ func ConvertEvalScope(dbp Process, gid, frame int) (*EvalScope, error) {
|
||||
return nil, fmt.Errorf("Frame %d does not exist in goroutine %d", frame, gid)
|
||||
}
|
||||
|
||||
PC, CFA := locs[frame].Current.PC, locs[frame].Regs.CFA
|
||||
|
||||
return &EvalScope{PC, CFA, thread, g.variable, dbp.BinInfo(), g.stackhi}, nil
|
||||
return &EvalScope{locs[frame].Current.PC, locs[frame].Regs, thread, g.variable, dbp.BinInfo(), locs[frame].StackHi}, nil
|
||||
}
|
||||
|
||||
// FrameToScope returns a new EvalScope for this frame
|
||||
func FrameToScope(p Process, frame Stackframe) *EvalScope {
|
||||
return &EvalScope{frame.Current.PC, frame.Regs.CFA, p.CurrentThread(), nil, p.BinInfo(), frame.StackHi}
|
||||
return &EvalScope{frame.Current.PC, frame.Regs, p.CurrentThread(), nil, p.BinInfo(), frame.StackHi}
|
||||
}
|
||||
|
90
pkg/proc/registers_amd64.go
Normal file
90
pkg/proc/registers_amd64.go
Normal file
@ -0,0 +1,90 @@
|
||||
package proc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
|
||||
"golang.org/x/arch/x86/x86asm"
|
||||
)
|
||||
|
||||
var dwarfToAsm = map[int]x86asm.Reg{
|
||||
0: x86asm.RAX,
|
||||
1: x86asm.RDX,
|
||||
2: x86asm.RCX,
|
||||
3: x86asm.RBX,
|
||||
4: x86asm.RSI,
|
||||
5: x86asm.RDI,
|
||||
6: x86asm.RBP,
|
||||
7: x86asm.RSP,
|
||||
8: x86asm.R8,
|
||||
9: x86asm.R9,
|
||||
10: x86asm.R10,
|
||||
11: x86asm.R11,
|
||||
12: x86asm.R12,
|
||||
13: x86asm.R13,
|
||||
14: x86asm.R14,
|
||||
15: x86asm.R15,
|
||||
16: x86asm.RIP,
|
||||
}
|
||||
|
||||
var dwarfToName = map[int]string{
|
||||
17: "XMM0",
|
||||
18: "XMM1",
|
||||
19: "XMM2",
|
||||
20: "XMM3",
|
||||
21: "XMM4",
|
||||
22: "XMM5",
|
||||
23: "XMM6",
|
||||
24: "XMM7",
|
||||
25: "XMM8",
|
||||
26: "XMM9",
|
||||
27: "XMM10",
|
||||
28: "XMM11",
|
||||
29: "XMM12",
|
||||
30: "XMM13",
|
||||
31: "XMM14",
|
||||
32: "XMM15",
|
||||
33: "ST(0)",
|
||||
34: "ST(1)",
|
||||
35: "ST(2)",
|
||||
36: "ST(3)",
|
||||
37: "ST(4)",
|
||||
38: "ST(5)",
|
||||
39: "ST(6)",
|
||||
40: "ST(7)",
|
||||
49: "Eflags",
|
||||
50: "Es",
|
||||
51: "Cs",
|
||||
52: "Ss",
|
||||
53: "Ds",
|
||||
54: "Fs",
|
||||
55: "Gs",
|
||||
58: "Fs_base",
|
||||
59: "Gs_base",
|
||||
64: "MXCSR",
|
||||
65: "CW",
|
||||
66: "SW",
|
||||
}
|
||||
|
||||
// getDwarfRegister maps between DWARF register numbers and architecture
|
||||
// registers.
|
||||
// The mapping is specified in the System V ABI AMD64 Architecture Processor
|
||||
// Supplement page 57, figure 3.36
|
||||
// https://www.uclibc.org/docs/psABI-x86_64.pdf
|
||||
func GetDwarfRegister(regs Registers, i int) []byte {
|
||||
if asmreg, ok := dwarfToAsm[i]; ok {
|
||||
x, _ := regs.Get(int(asmreg))
|
||||
var buf bytes.Buffer
|
||||
binary.Write(&buf, binary.LittleEndian, x)
|
||||
return buf.Bytes()
|
||||
}
|
||||
if regname, ok := dwarfToName[i]; ok {
|
||||
regslice := regs.Slice()
|
||||
for _, reg := range regslice {
|
||||
if reg.Name == regname {
|
||||
return reg.Bytes
|
||||
}
|
||||
}
|
||||
}
|
||||
return []byte{}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package proc
|
||||
|
||||
import (
|
||||
"debug/dwarf"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
@ -173,6 +174,19 @@ func (it *stackIterator) Err() error {
|
||||
return it.err
|
||||
}
|
||||
|
||||
// frameBase calculates the frame base pseudo-register for DWARF for fn and
|
||||
// the current frame.
|
||||
func (it *stackIterator) frameBase(fn *Function) int64 {
|
||||
rdr := it.bi.dwarf.Reader()
|
||||
rdr.Seek(fn.offset)
|
||||
e, err := rdr.Next()
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
fb, _, _ := it.bi.Location(e, dwarf.AttrFrameBase, it.pc, it.regs)
|
||||
return fb
|
||||
}
|
||||
|
||||
func (it *stackIterator) newStackframe(ret, retaddr uint64) Stackframe {
|
||||
if retaddr == 0 {
|
||||
it.err = NullAddrError{}
|
||||
@ -182,6 +196,8 @@ func (it *stackIterator) newStackframe(ret, retaddr uint64) Stackframe {
|
||||
if fn == nil {
|
||||
f = "?"
|
||||
l = -1
|
||||
} else {
|
||||
it.regs.FrameBase = it.frameBase(fn)
|
||||
}
|
||||
r := Stackframe{Current: Location{PC: it.pc, File: f, Line: l, Fn: fn}, Regs: it.regs, Ret: ret, addrret: retaddr, StackHi: it.stackhi}
|
||||
if !it.top {
|
||||
@ -281,13 +297,13 @@ func (it *stackIterator) executeFrameRegRule(regnum uint64, rule frame.DWRule, c
|
||||
case frame.RuleRegister:
|
||||
return it.regs.Reg(rule.Reg), nil
|
||||
case frame.RuleExpression:
|
||||
v, err := op.ExecuteStackProgram(it.regs, rule.Expression)
|
||||
v, _, err := op.ExecuteStackProgram(it.regs, rule.Expression)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return it.readRegisterAt(regnum, uint64(v))
|
||||
case frame.RuleValExpression:
|
||||
v, err := op.ExecuteStackProgram(it.regs, rule.Expression)
|
||||
v, _, err := op.ExecuteStackProgram(it.regs, rule.Expression)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -379,7 +379,7 @@ func ThreadScope(thread Thread) (*EvalScope, error) {
|
||||
if len(locations) < 1 {
|
||||
return nil, errors.New("could not decode first frame")
|
||||
}
|
||||
return &EvalScope{locations[0].Current.PC, locations[0].Regs.CFA, thread, nil, thread.BinInfo(), 0}, nil
|
||||
return &EvalScope{locations[0].Current.PC, locations[0].Regs, thread, nil, thread.BinInfo(), 0}, nil
|
||||
}
|
||||
|
||||
// GoroutineScope returns an EvalScope for the goroutine running on this thread.
|
||||
@ -395,7 +395,7 @@ func GoroutineScope(thread Thread) (*EvalScope, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &EvalScope{locations[0].Current.PC, locations[0].Regs.CFA, thread, g.variable, thread.BinInfo(), g.stackhi}, nil
|
||||
return &EvalScope{locations[0].Current.PC, locations[0].Regs, thread, g.variable, thread.BinInfo(), g.stackhi}, nil
|
||||
}
|
||||
|
||||
func onRuntimeBreakpoint(thread Thread) bool {
|
||||
|
@ -170,7 +170,9 @@ func (v compileUnitsByLowpc) Less(i int, j int) bool { return v[i].LowPC < v[j].
|
||||
func (v compileUnitsByLowpc) Swap(i int, j int) { v[i], v[j] = v[j], v[i] }
|
||||
|
||||
func (bi *BinaryInfo) loadDebugInfoMaps(debugLineBytes []byte, wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
if wg != nil {
|
||||
defer wg.Done()
|
||||
}
|
||||
bi.types = make(map[string]dwarf.Offset)
|
||||
bi.packageVars = make(map[string]dwarf.Offset)
|
||||
bi.Functions = []Function{}
|
||||
@ -502,7 +504,7 @@ func nameOfFuncRuntimeType(_type *Variable, tflag int64, anonymous bool) (string
|
||||
outCount = outCount & (1<<15 - 1)
|
||||
}
|
||||
|
||||
cursortyp := _type.newVariable("", _type.Addr+uintptr(uadd), prtyp)
|
||||
cursortyp := _type.newVariable("", _type.Addr+uintptr(uadd), prtyp, _type.mem)
|
||||
var buf bytes.Buffer
|
||||
if anonymous {
|
||||
buf.WriteString("func(")
|
||||
@ -710,7 +712,7 @@ func specificRuntimeType(_type *Variable, kind int64) (*Variable, error) {
|
||||
return _type, nil
|
||||
}
|
||||
|
||||
return _type.newVariable(_type.Name, _type.Addr, typ), nil
|
||||
return _type.newVariable(_type.Name, _type.Addr, typ, _type.mem), nil
|
||||
}
|
||||
|
||||
// See reflect.(*rtype).uncommon in $GOROOT/src/reflect/type.go
|
||||
@ -724,7 +726,7 @@ func uncommon(_type *Variable, tflag int64) *Variable {
|
||||
return nil
|
||||
}
|
||||
|
||||
return _type.newVariable(_type.Name, _type.Addr+uintptr(_type.RealType.Size()), typ)
|
||||
return _type.newVariable(_type.Name, _type.Addr+uintptr(_type.RealType.Size()), typ, _type.mem)
|
||||
}
|
||||
|
||||
// typeForKind returns a *dwarf.StructType describing the specialization of
|
||||
|
@ -150,8 +150,8 @@ type G struct {
|
||||
// EvalScope is the scope for variable evaluation. Contains the thread,
|
||||
// current location (PC), and canonical frame address.
|
||||
type EvalScope struct {
|
||||
PC uint64 // Current instruction of the evaluation frame
|
||||
CFA int64 // Stack address of the evaluation frame
|
||||
PC uint64 // Current instruction of the evaluation frame
|
||||
Regs op.DwarfRegisters
|
||||
Mem MemoryReadWriter // Target's memory
|
||||
Gvar *Variable
|
||||
BinInfo *BinaryInfo
|
||||
@ -167,16 +167,16 @@ func (err *IsNilErr) Error() string {
|
||||
return fmt.Sprintf("%s is nil", err.name)
|
||||
}
|
||||
|
||||
func (scope *EvalScope) newVariable(name string, addr uintptr, dwarfType godwarf.Type) *Variable {
|
||||
return newVariable(name, addr, dwarfType, scope.BinInfo, scope.Mem)
|
||||
func (scope *EvalScope) newVariable(name string, addr uintptr, dwarfType godwarf.Type, mem MemoryReadWriter) *Variable {
|
||||
return newVariable(name, addr, dwarfType, scope.BinInfo, mem)
|
||||
}
|
||||
|
||||
func newVariableFromThread(t Thread, name string, addr uintptr, dwarfType godwarf.Type) *Variable {
|
||||
return newVariable(name, addr, dwarfType, t.BinInfo(), t)
|
||||
}
|
||||
|
||||
func (v *Variable) newVariable(name string, addr uintptr, dwarfType godwarf.Type) *Variable {
|
||||
return newVariable(name, addr, dwarfType, v.bi, v.mem)
|
||||
func (v *Variable) newVariable(name string, addr uintptr, dwarfType godwarf.Type, mem MemoryReadWriter) *Variable {
|
||||
return newVariable(name, addr, dwarfType, v.bi, mem)
|
||||
}
|
||||
|
||||
func newVariable(name string, addr uintptr, dwarfType godwarf.Type, bi *BinaryInfo, mem MemoryReadWriter) *Variable {
|
||||
@ -333,7 +333,7 @@ func (v *Variable) toField(field *godwarf.StructField) (*Variable, error) {
|
||||
name = fmt.Sprintf("%s.%s", v.Name, field.Name)
|
||||
}
|
||||
}
|
||||
return v.newVariable(name, uintptr(int64(v.Addr)+field.ByteOffset), field.Type), nil
|
||||
return v.newVariable(name, uintptr(int64(v.Addr)+field.ByteOffset), field.Type, v.mem), nil
|
||||
}
|
||||
|
||||
// DwarfReader returns the DwarfReader containing the
|
||||
@ -597,14 +597,6 @@ func (scope *EvalScope) SetVariable(name, value string) error {
|
||||
return xv.setValue(yv)
|
||||
}
|
||||
|
||||
func (scope *EvalScope) extractVariableFromEntry(entry *dwarf.Entry) (*Variable, error) {
|
||||
v, err := scope.extractVarInfoFromEntry(entry)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// LocalVariables returns all local variables from the current function scope.
|
||||
func (scope *EvalScope) LocalVariables(cfg LoadConfig) ([]*Variable, error) {
|
||||
return scope.variablesByTag(dwarf.TagVariable, &cfg)
|
||||
@ -636,7 +628,7 @@ func (scope *EvalScope) PackageVariables(cfg LoadConfig) ([]*Variable, error) {
|
||||
}
|
||||
|
||||
// Ignore errors trying to extract values
|
||||
val, err := scope.extractVariableFromEntry(entry)
|
||||
val, err := scope.extractVarInfoFromEntry(entry)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
@ -757,14 +749,14 @@ func (scope *EvalScope) extractVarInfoFromEntry(entry *dwarf.Entry) (*Variable,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
instructions, ok := entry.Val(dwarf.AttrLocation).([]byte)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("type assertion failed")
|
||||
addr, pieces, err := scope.BinInfo.Location(entry, dwarf.AttrLocation, scope.PC, scope.Regs)
|
||||
mem := scope.Mem
|
||||
if pieces != nil {
|
||||
addr = fakeAddress
|
||||
mem = newCompositeMemory(scope.Mem, scope.Regs, pieces)
|
||||
}
|
||||
|
||||
addr, err := op.ExecuteStackProgram(op.DwarfRegisters{CFA: scope.CFA}, instructions)
|
||||
|
||||
v := scope.newVariable(n, uintptr(addr), t)
|
||||
v := scope.newVariable(n, uintptr(addr), t, mem)
|
||||
if err != nil {
|
||||
v.Unreadable = err
|
||||
}
|
||||
@ -780,7 +772,7 @@ func (v *Variable) maybeDereference() *Variable {
|
||||
switch t := v.RealType.(type) {
|
||||
case *godwarf.PtrType:
|
||||
ptrval, err := readUintRaw(v.mem, uintptr(v.Addr), t.ByteSize)
|
||||
r := v.newVariable("", uintptr(ptrval), t.Type)
|
||||
r := v.newVariable("", uintptr(ptrval), t.Type, DereferenceMemory(v.mem))
|
||||
if err != nil {
|
||||
r.Unreadable = err
|
||||
}
|
||||
@ -837,7 +829,7 @@ func (v *Variable) loadValueInternal(recurseLevel int, cfg LoadConfig) {
|
||||
|
||||
case reflect.String:
|
||||
var val string
|
||||
val, v.Unreadable = readStringValue(v.mem, v.Base, v.Len, cfg)
|
||||
val, v.Unreadable = readStringValue(DereferenceMemory(v.mem), v.Base, v.Len, cfg)
|
||||
v.Value = constant.MakeString(val)
|
||||
|
||||
case reflect.Slice, reflect.Array:
|
||||
@ -1105,8 +1097,13 @@ func (v *Variable) loadArrayValues(recurseLevel int, cfg LoadConfig) {
|
||||
|
||||
errcount := 0
|
||||
|
||||
mem := v.mem
|
||||
if v.Kind != reflect.Array {
|
||||
mem = DereferenceMemory(mem)
|
||||
}
|
||||
|
||||
for i := int64(0); i < count; i++ {
|
||||
fieldvar := v.newVariable("", uintptr(int64(v.Base)+(i*v.stride)), v.fieldType)
|
||||
fieldvar := v.newVariable("", uintptr(int64(v.Base)+(i*v.stride)), v.fieldType, mem)
|
||||
fieldvar.loadValueInternal(recurseLevel+1, cfg)
|
||||
|
||||
if fieldvar.Unreadable != nil {
|
||||
@ -1134,8 +1131,8 @@ func (v *Variable) readComplex(size int64) {
|
||||
|
||||
ftyp := &godwarf.FloatType{BasicType: godwarf.BasicType{CommonType: godwarf.CommonType{ByteSize: fs, Name: fmt.Sprintf("float%d", fs)}, BitSize: fs * 8, BitOffset: 0}}
|
||||
|
||||
realvar := v.newVariable("real", v.Addr, ftyp)
|
||||
imagvar := v.newVariable("imaginary", v.Addr+uintptr(fs), ftyp)
|
||||
realvar := v.newVariable("real", v.Addr, ftyp, v.mem)
|
||||
imagvar := v.newVariable("imaginary", v.Addr+uintptr(fs), ftyp, v.mem)
|
||||
realvar.loadValue(loadSingleValue)
|
||||
imagvar.loadValue(loadSingleValue)
|
||||
v.Value = constant.BinaryOp(realvar.Value, token.ADD, constant.MakeImag(imagvar.Value))
|
||||
@ -1316,7 +1313,7 @@ func (v *Variable) loadMap(recurseLevel int, cfg LoadConfig) {
|
||||
if it.values.fieldType.Size() > 0 {
|
||||
val = it.value()
|
||||
} else {
|
||||
val = v.newVariable("", it.values.Addr, it.values.fieldType)
|
||||
val = v.newVariable("", it.values.Addr, it.values.fieldType, DereferenceMemory(v.mem))
|
||||
}
|
||||
key.loadValueInternal(recurseLevel+1, cfg)
|
||||
val.loadValueInternal(recurseLevel+1, cfg)
|
||||
@ -1710,7 +1707,7 @@ func (v *Variable) loadInterface(recurseLevel int, loadData bool, cfg LoadConfig
|
||||
}
|
||||
}
|
||||
|
||||
data = data.newVariable("data", data.Addr, typ)
|
||||
data = data.newVariable("data", data.Addr, typ, data.mem)
|
||||
if deref {
|
||||
data = data.maybeDereference()
|
||||
data.Name = "data"
|
||||
@ -1754,7 +1751,7 @@ func (scope *EvalScope) variablesByTag(tag dwarf.Tag, cfg *LoadConfig) ([]*Varia
|
||||
if entry.Tag != tag {
|
||||
continue
|
||||
}
|
||||
val, err := scope.extractVariableFromEntry(entry)
|
||||
val, err := scope.extractVarInfoFromEntry(entry)
|
||||
if err != nil {
|
||||
// skip variables that we can't parse yet
|
||||
continue
|
||||
|
95
scripts/gen-opcodes.go
Normal file
95
scripts/gen-opcodes.go
Normal file
@ -0,0 +1,95 @@
|
||||
// This script generates pkg/dwarf/op/opcodes.go from pkg/dwarf/op/opcodes.txt
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/format"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Opcode struct {
|
||||
Name string
|
||||
Code string
|
||||
Args string
|
||||
Func string
|
||||
}
|
||||
|
||||
func main() {
|
||||
fh, err := os.Open(os.Args[1])
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer fh.Close()
|
||||
|
||||
outfh := os.Stdout
|
||||
if os.Args[2] != "-" {
|
||||
outfh, err = os.Create(os.Args[2])
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer outfh.Close()
|
||||
}
|
||||
|
||||
opcodes := []Opcode{}
|
||||
s := bufio.NewScanner(fh)
|
||||
for s.Scan() {
|
||||
line := strings.TrimSpace(s.Text())
|
||||
if line == "" || strings.HasPrefix(line, "//") {
|
||||
continue
|
||||
}
|
||||
fields := strings.Split(line, "\t")
|
||||
opcode := Opcode{Name: fields[0], Code: fields[1], Args: fields[2]}
|
||||
if len(fields) > 3 {
|
||||
opcode.Func = fields[3]
|
||||
}
|
||||
opcodes = append(opcodes, opcode)
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
|
||||
fmt.Fprintf(&buf, `// THIS FILE IS AUTOGENERATED, EDIT opcodes.table INSTEAD
|
||||
|
||||
package op
|
||||
`)
|
||||
|
||||
// constants
|
||||
fmt.Fprintf(&buf, "const (\n")
|
||||
for _, opcode := range opcodes {
|
||||
fmt.Fprintf(&buf, "%s Opcode = %s\n", opcode.Name, opcode.Code)
|
||||
}
|
||||
fmt.Fprintf(&buf, ")\n\n")
|
||||
|
||||
// name map
|
||||
fmt.Fprintf(&buf, "var opcodeName = map[Opcode]string{\n")
|
||||
for _, opcode := range opcodes {
|
||||
fmt.Fprintf(&buf, "%s: %q,\n", opcode.Name, opcode.Name)
|
||||
}
|
||||
fmt.Fprintf(&buf, "}\n")
|
||||
|
||||
// arguments map
|
||||
fmt.Fprintf(&buf, "var opcodeArgs = map[Opcode]string{\n")
|
||||
for _, opcode := range opcodes {
|
||||
fmt.Fprintf(&buf, "%s: %s,\n", opcode.Name, opcode.Args)
|
||||
}
|
||||
fmt.Fprintf(&buf, "}\n")
|
||||
|
||||
// function map
|
||||
fmt.Fprintf(&buf, "var oplut = map[Opcode]stackfn{\n")
|
||||
for _, opcode := range opcodes {
|
||||
if opcode.Func != "" {
|
||||
fmt.Fprintf(&buf, "%s: %s,\n", opcode.Name, opcode.Func)
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(&buf, "}\n")
|
||||
|
||||
src, err := format.Source(buf.Bytes())
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
outfh.Write(src)
|
||||
}
|
Loading…
Reference in New Issue
Block a user