2014-07-30 00:00:24 +00:00
|
|
|
package op
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2014-11-08 14:02:31 +00:00
|
|
|
"encoding/binary"
|
2015-05-07 21:55:06 +00:00
|
|
|
"errors"
|
2014-07-30 00:00:24 +00:00
|
|
|
"fmt"
|
|
|
|
|
2017-02-08 16:00:44 +00:00
|
|
|
"github.com/derekparker/delve/pkg/dwarf/util"
|
2014-07-30 00:00:24 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2014-11-08 14:02:31 +00:00
|
|
|
DW_OP_addr = 0x3
|
2014-07-30 00:00:24 +00:00
|
|
|
DW_OP_call_frame_cfa = 0x9c
|
|
|
|
DW_OP_plus = 0x22
|
|
|
|
DW_OP_consts = 0x11
|
2014-11-26 02:37:43 +00:00
|
|
|
DW_OP_plus_uconsts = 0x23
|
2014-07-30 00:00:24 +00:00
|
|
|
)
|
|
|
|
|
2017-10-05 07:26:19 +00:00
|
|
|
type stackfn func(byte, *context) error
|
|
|
|
|
|
|
|
type context struct {
|
|
|
|
buf *bytes.Buffer
|
|
|
|
stack []int64
|
|
|
|
|
|
|
|
DwarfRegisters
|
|
|
|
}
|
2014-07-30 00:00:24 +00:00
|
|
|
|
2017-08-22 14:40:01 +00:00
|
|
|
type Opcode byte
|
|
|
|
|
|
|
|
var oplut = map[Opcode]stackfn{
|
2014-07-30 00:00:24 +00:00
|
|
|
DW_OP_call_frame_cfa: callframecfa,
|
|
|
|
DW_OP_plus: plus,
|
|
|
|
DW_OP_consts: consts,
|
2014-11-08 14:02:31 +00:00
|
|
|
DW_OP_addr: addr,
|
2017-08-22 14:40:01 +00:00
|
|
|
DW_OP_plus_uconst: plusuconsts,
|
2014-07-30 00:00:24 +00:00
|
|
|
}
|
|
|
|
|
2017-10-05 07:26:19 +00:00
|
|
|
func ExecuteStackProgram(regs DwarfRegisters, instructions []byte) (int64, error) {
|
|
|
|
ctxt := &context{
|
|
|
|
buf: bytes.NewBuffer(instructions),
|
|
|
|
stack: make([]int64, 0, 3),
|
|
|
|
DwarfRegisters: regs,
|
|
|
|
}
|
2014-07-30 00:00:24 +00:00
|
|
|
|
2017-10-05 07:26:19 +00:00
|
|
|
for {
|
|
|
|
opcode, err := ctxt.buf.ReadByte()
|
|
|
|
if err != nil {
|
|
|
|
break
|
|
|
|
}
|
2015-07-23 17:08:28 +00:00
|
|
|
fn, ok := oplut[opcode]
|
2014-07-30 00:00:24 +00:00
|
|
|
if !ok {
|
2015-07-23 17:08:28 +00:00
|
|
|
return 0, fmt.Errorf("invalid instruction %#v", opcode)
|
2014-07-30 00:00:24 +00:00
|
|
|
}
|
|
|
|
|
2017-10-05 07:26:19 +00:00
|
|
|
err = fn(opcode, ctxt)
|
2014-07-30 00:00:24 +00:00
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-05 07:26:19 +00:00
|
|
|
if len(ctxt.stack) == 0 {
|
2015-05-07 21:55:06 +00:00
|
|
|
return 0, errors.New("empty OP stack")
|
|
|
|
}
|
|
|
|
|
2017-10-05 07:26:19 +00:00
|
|
|
return ctxt.stack[len(ctxt.stack)-1], nil
|
2014-07-30 00:00:24 +00:00
|
|
|
}
|
|
|
|
|
2017-10-05 07:26:19 +00:00
|
|
|
func callframecfa(opcode byte, ctxt *context) error {
|
|
|
|
if ctxt.CFA == 0 {
|
|
|
|
return fmt.Errorf("Could not retrieve call frame CFA for current PC")
|
2015-07-23 17:08:28 +00:00
|
|
|
}
|
2017-10-05 07:26:19 +00:00
|
|
|
ctxt.stack = append(ctxt.stack, int64(ctxt.CFA))
|
|
|
|
return nil
|
2014-07-30 00:00:24 +00:00
|
|
|
}
|
|
|
|
|
2017-10-05 07:26:19 +00:00
|
|
|
func addr(opcode byte, ctxt *context) error {
|
|
|
|
ctxt.stack = append(ctxt.stack, int64(binary.LittleEndian.Uint64(ctxt.buf.Next(8))))
|
|
|
|
return nil
|
2014-11-08 14:02:31 +00:00
|
|
|
}
|
|
|
|
|
2017-10-05 07:26:19 +00:00
|
|
|
func plus(opcode byte, ctxt *context) error {
|
2014-07-30 00:00:24 +00:00
|
|
|
var (
|
2017-10-05 07:26:19 +00:00
|
|
|
slen = len(ctxt.stack)
|
|
|
|
digits = ctxt.stack[slen-2 : slen]
|
|
|
|
st = ctxt.stack[:slen-2]
|
2014-07-30 00:00:24 +00:00
|
|
|
)
|
|
|
|
|
2017-10-05 07:26:19 +00:00
|
|
|
ctxt.stack = append(st, digits[0]+digits[1])
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func plusuconsts(opcode byte, ctxt *context) error {
|
|
|
|
slen := len(ctxt.stack)
|
|
|
|
num, _ := util.DecodeULEB128(ctxt.buf)
|
|
|
|
ctxt.stack[slen-1] = ctxt.stack[slen-1] + int64(num)
|
|
|
|
return nil
|
2014-07-30 00:00:24 +00:00
|
|
|
}
|
|
|
|
|
2017-10-05 07:26:19 +00:00
|
|
|
func consts(opcode byte, ctxt *context) error {
|
|
|
|
num, _ := util.DecodeSLEB128(ctxt.buf)
|
|
|
|
ctxt.stack = append(ctxt.stack, num)
|
|
|
|
return nil
|
2014-11-26 02:37:43 +00:00
|
|
|
}
|
|
|
|
|
2017-10-05 07:26:19 +00:00
|
|
|
func framebase(opcode byte, ctxt *context) error {
|
|
|
|
num, _ := util.DecodeSLEB128(ctxt.buf)
|
|
|
|
ctxt.stack = append(ctxt.stack, ctxt.FrameBase+num)
|
|
|
|
return nil
|
2014-07-30 00:00:24 +00:00
|
|
|
}
|