diff --git a/examples/ex2/main.go b/examples/ex2/main.go index a95ce63..7ec0404 100644 --- a/examples/ex2/main.go +++ b/examples/ex2/main.go @@ -22,6 +22,7 @@ import ( "github.com/cilium/ebpf" "github.com/safchain/baloum/pkg/baloum" + "github.com/safchain/baloum/pkg/baloum/debugger" "go.uber.org/zap" ) @@ -48,7 +49,7 @@ func main() { }, } - debugger := baloum.NewDebugger(true, nil) + debugger := debugger.NewDebugger(true, nil) defer debugger.Close() vm := baloum.NewVM(spec, baloum.Opts{Fncs: fncs, Observer: debugger}) diff --git a/pkg/baloum/debugger.go b/pkg/baloum/debugger/debugger.go similarity index 87% rename from pkg/baloum/debugger.go rename to pkg/baloum/debugger/debugger.go index b7f8fab..86a72f5 100644 --- a/pkg/baloum/debugger.go +++ b/pkg/baloum/debugger/debugger.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package baloum +package debugger import ( "fmt" @@ -24,6 +24,7 @@ import ( "github.com/cilium/ebpf/asm" "github.com/peterh/liner" + "github.com/safchain/baloum/pkg/baloum" ) type DebugCommand string @@ -64,8 +65,8 @@ func NewDebugger(enabled bool, variableReaders map[string]VariableReader) *Debug } } -func (d *Debugger) dumpRegister(vm *VM) { - for i, v := range vm.regs { +func (d *Debugger) dumpRegister(vm *baloum.VM) { + for i, v := range vm.Regs() { if i > 0 { fmt.Printf(", ") } @@ -89,17 +90,17 @@ func (d *Debugger) dumpBytes(bytes []byte) { fmt.Println() } -func (d *Debugger) dumpStack(vm *VM) { - d.dumpBytes(vm.stack) +func (d *Debugger) dumpStack(vm *baloum.VM) { + d.dumpBytes(vm.Stack()) } -func (d *Debugger) printMap(vm *VM, args ...string) { +func (d *Debugger) printMap(vm *baloum.VM, args ...string) { if len(args) != 1 { fmt.Fprintf(os.Stderr, "syntax error: pm \n") return } - _map := vm.maps.GetMapByName(args[0]) + _map := vm.GetMapByName(args[0]) if _map == nil { fmt.Fprintf(os.Stderr, "map not found") return @@ -125,7 +126,7 @@ func (d *Debugger) printMap(vm *VM, args ...string) { } } -func (d *Debugger) printVariable(vm *VM, args ...string) { +func (d *Debugger) printVariable(vm *baloum.VM, args ...string) { if len(args) != 2 { fmt.Fprintf(os.Stderr, "syntax error: pr \n") return @@ -140,13 +141,15 @@ func (d *Debugger) printVariable(vm *VM, args ...string) { var ptr uint64 + regs := vm.Regs() + if addr[0] == 'R' || addr[0] == 'r' { reg, err := strconv.Atoi(addr[1:]) - if err != nil || reg >= len(vm.regs) { + if err != nil || reg >= len(regs) { fmt.Fprintf(os.Stderr, "register unknown\n") return } - ptr = vm.regs[reg] + ptr = regs[reg] } else { value, err := strconv.Atoi(addr) if err != nil { @@ -156,7 +159,7 @@ func (d *Debugger) printVariable(vm *VM, args ...string) { ptr = uint64(value) } - bytes, err := vm.getBytes(ptr, reader.Size) + bytes, err := vm.GetBytes(ptr, reader.Size) if err != nil { fmt.Fprintf(os.Stderr, "address incorrect\n") return @@ -165,7 +168,7 @@ func (d *Debugger) printVariable(vm *VM, args ...string) { fmt.Printf(">> %v\n", reader.Read(bytes)) } -func (d *Debugger) printBacktrace(vm *VM) { +func (d *Debugger) printBacktrace(vm *baloum.VM) { for _, bt := range d.backtrace { fmt.Printf("%d: %v\n", bt.PC, bt.Inst) } @@ -177,7 +180,7 @@ func (d *Debugger) Close() { } } -func (d *Debugger) ObserveInst(vm *VM, pc int, inst *asm.Instruction) { +func (d *Debugger) ObserveInst(vm *baloum.VM, pc int, inst *asm.Instruction) { d.backtrace = append(d.backtrace, BTInst{PC: pc, Inst: *inst}) if d.state == nil { diff --git a/pkg/baloum/fncs.go b/pkg/baloum/fncs.go index 3525d9f..8098878 100644 --- a/pkg/baloum/fncs.go +++ b/pkg/baloum/fncs.go @@ -84,7 +84,7 @@ func FnMallocImpl(vm *VM, inst *asm.Instruction) error { } func FnCallImpl(vm *VM, inst *asm.Instruction) error { - data, err := vm.getBytes(vm.regs[asm.R1], 0) + data, err := vm.GetBytes(vm.regs[asm.R1], 0) if err != nil { return err } @@ -93,7 +93,7 @@ func FnCallImpl(vm *VM, inst *asm.Instruction) error { return err } - section, err := vm.getString(vm.regs[asm.R2]) + section, err := vm.GetString(vm.regs[asm.R2]) if err != nil { return err } @@ -113,12 +113,12 @@ func FnStrCmpImpl(vm *VM, inst *asm.Instruction) error { code := ErrorCode vm.regs[asm.R0] = uint64(code) - s1, err := vm.getString(vm.regs[asm.R1]) + s1, err := vm.GetString(vm.regs[asm.R1]) if err != nil { return err } - s2, err := vm.getString(vm.regs[asm.R2]) + s2, err := vm.GetString(vm.regs[asm.R2]) if err != nil { return err } @@ -135,12 +135,12 @@ func FnMemCmpImpl(vm *VM, inst *asm.Instruction) error { size := vm.regs[asm.R3] - b1, err := vm.getBytes(vm.regs[asm.R1], uint64(size)) + b1, err := vm.GetBytes(vm.regs[asm.R1], uint64(size)) if err != nil { return err } - b2, err := vm.getBytes(vm.regs[asm.R2], uint64(size)) + b2, err := vm.GetBytes(vm.regs[asm.R2], uint64(size)) if err != nil { return err } @@ -157,12 +157,12 @@ func FnMemCpyImpl(vm *VM, inst *asm.Instruction) error { size := vm.regs[asm.R3] - srcBytes, err := vm.getBytes(vm.regs[asm.R2], size) + srcBytes, err := vm.GetBytes(vm.regs[asm.R2], size) if err != nil { return err } - return vm.setBytes(vm.regs[asm.R1], srcBytes, size) + return vm.SetBytes(vm.regs[asm.R1], srcBytes, size) } var ( @@ -170,7 +170,7 @@ var ( ) func FnTracePrintkImpl(vm *VM, inst *asm.Instruction) error { - format, err := vm.getString(vm.regs[asm.R1]) + format, err := vm.GetString(vm.regs[asm.R1]) if err != nil { return err } @@ -200,7 +200,7 @@ func FnTracePrintkImpl(vm *VM, inst *asm.Instruction) error { var value interface{} if ph == "%s" { - value, err = vm.getString(vm.regs[reg]) + value, err = vm.GetString(vm.regs[reg]) if err != nil { return err } @@ -221,12 +221,12 @@ func FnTracePrintkImpl(vm *VM, inst *asm.Instruction) error { func FnProbeReadImpl(vm *VM, inst *asm.Instruction) error { size := vm.regs[asm.R2] - srcBytes, err := vm.getBytes(vm.regs[asm.R3], size) + srcBytes, err := vm.GetBytes(vm.regs[asm.R3], size) if err != nil { return err } - dstBytes, err := vm.getBytes(vm.regs[asm.R1], size) + dstBytes, err := vm.GetBytes(vm.regs[asm.R1], size) if err != nil { return err } @@ -239,12 +239,12 @@ func FnProbeReadImpl(vm *VM, inst *asm.Instruction) error { func FnProbeReadStrImpl(vm *VM, inst *asm.Instruction) error { size := vm.regs[asm.R2] - src, err := vm.getString(vm.regs[asm.R3]) + src, err := vm.GetString(vm.regs[asm.R3]) if err != nil { return err } - dstBytes, err := vm.getBytes(vm.regs[asm.R1], size) + dstBytes, err := vm.GetBytes(vm.regs[asm.R1], size) if err != nil { return err } @@ -292,7 +292,7 @@ func FnMapLookupElemImpl(vm *VM, inst *asm.Instruction) error { } keyAddr := vm.regs[asm.R2] - key, err := vm.getBytes(keyAddr, uint64(_map.KeySize())) + key, err := vm.GetBytes(keyAddr, uint64(_map.KeySize())) if err != nil { return err } @@ -313,13 +313,13 @@ func FnMapUpdateElemImpl(vm *VM, inst *asm.Instruction) error { } keyAddr := vm.regs[asm.R2] - key, err := vm.getBytes(keyAddr, uint64(_map.KeySize())) + key, err := vm.GetBytes(keyAddr, uint64(_map.KeySize())) if err != nil { return err } valueAddr := vm.regs[asm.R3] - value, err := vm.getBytes(valueAddr, uint64(_map.ValueSize())) + value, err := vm.GetBytes(valueAddr, uint64(_map.ValueSize())) if err != nil { return err } @@ -342,7 +342,7 @@ func FnMapDeleteElemImpl(vm *VM, inst *asm.Instruction) error { } keyAddr := vm.regs[asm.R2] - key, err := vm.getBytes(keyAddr, uint64(_map.KeySize())) + key, err := vm.GetBytes(keyAddr, uint64(_map.KeySize())) if err != nil { return err } @@ -369,7 +369,7 @@ func FnPerfEventOutputImpl(vm *VM, inst *asm.Instruction) error { size := vm.regs[asm.R5] eventAddr := vm.regs[asm.R4] - data, err := vm.getBytes(eventAddr, size) + data, err := vm.GetBytes(eventAddr, size) if err != nil { return err } diff --git a/pkg/baloum/vm.go b/pkg/baloum/vm.go index 702bfc9..53a91fd 100644 --- a/pkg/baloum/vm.go +++ b/pkg/baloum/vm.go @@ -107,7 +107,7 @@ func (vm *VM) getMem(addr uint64) ([]byte, uint64, error) { return vm.heap.GetMem(addr) } -func (vm *VM) getBytes(addr uint64, size uint64) ([]byte, error) { +func (vm *VM) GetBytes(addr uint64, size uint64) ([]byte, error) { bytes, addr, err := vm.getMem(addr) if err != nil { return nil, err @@ -124,8 +124,8 @@ func (vm *VM) getBytes(addr uint64, size uint64) ([]byte, error) { return bytes[addr : addr+size], nil } -func (vm *VM) getUint64(addr uint64) (uint64, error) { - bytes, err := vm.getBytes(addr, 8) +func (vm *VM) GetUint64(addr uint64) (uint64, error) { + bytes, err := vm.GetBytes(addr, 8) if err != nil { return 0, err } @@ -133,8 +133,8 @@ func (vm *VM) getUint64(addr uint64) (uint64, error) { return ByteOrder.Uint64(bytes), nil } -func (vm *VM) getUint32(addr uint64) (uint32, error) { - bytes, err := vm.getBytes(addr, 4) +func (vm *VM) GetUint32(addr uint64) (uint32, error) { + bytes, err := vm.GetBytes(addr, 4) if err != nil { return 0, err } @@ -142,8 +142,8 @@ func (vm *VM) getUint32(addr uint64) (uint32, error) { return ByteOrder.Uint32(bytes), nil } -func (vm *VM) getUint16(addr uint64) (uint16, error) { - bytes, err := vm.getBytes(addr, 2) +func (vm *VM) GetUint16(addr uint64) (uint16, error) { + bytes, err := vm.GetBytes(addr, 2) if err != nil { return 0, err } @@ -151,8 +151,8 @@ func (vm *VM) getUint16(addr uint64) (uint16, error) { return ByteOrder.Uint16(bytes), nil } -func (vm *VM) getUint8(addr uint64) (uint8, error) { - bytes, err := vm.getBytes(addr, 1) +func (vm *VM) GetUint8(addr uint64) (uint8, error) { + bytes, err := vm.GetBytes(addr, 1) if err != nil { return 0, err } @@ -160,7 +160,7 @@ func (vm *VM) getUint8(addr uint64) (uint8, error) { return uint8(bytes[0]), nil } -func (vm *VM) getString(addr uint64) (string, error) { +func (vm *VM) GetString(addr uint64) (string, error) { data, addr, err := vm.getMem(addr) if err != nil { return "", err @@ -169,8 +169,8 @@ func (vm *VM) getString(addr uint64) (string, error) { return Bytes2String(data[addr:]), nil } -func (vm *VM) setUint64(addr uint64, value uint64) error { - bytes, err := vm.getBytes(addr, 8) +func (vm *VM) SetUint64(addr uint64, value uint64) error { + bytes, err := vm.GetBytes(addr, 8) if err != nil { return err } @@ -179,8 +179,8 @@ func (vm *VM) setUint64(addr uint64, value uint64) error { return nil } -func (vm *VM) setUint32(addr uint64, value uint32) error { - bytes, err := vm.getBytes(addr, 4) +func (vm *VM) SetUint32(addr uint64, value uint32) error { + bytes, err := vm.GetBytes(addr, 4) if err != nil { return err } @@ -189,8 +189,8 @@ func (vm *VM) setUint32(addr uint64, value uint32) error { return nil } -func (vm *VM) setUint16(addr uint64, value uint16) error { - bytes, err := vm.getBytes(addr, 2) +func (vm *VM) SetUint16(addr uint64, value uint16) error { + bytes, err := vm.GetBytes(addr, 2) if err != nil { return err } @@ -200,8 +200,8 @@ func (vm *VM) setUint16(addr uint64, value uint16) error { return nil } -func (vm *VM) setUint8(addr uint64, value uint8) error { - bytes, err := vm.getBytes(addr, 1) +func (vm *VM) SetUint8(addr uint64, value uint8) error { + bytes, err := vm.GetBytes(addr, 1) if err != nil { return err } @@ -211,8 +211,8 @@ func (vm *VM) setUint8(addr uint64, value uint8) error { return nil } -func (vm *VM) setBytes(addr uint64, value []byte, size uint64) error { - bytes, err := vm.getBytes(addr, size) +func (vm *VM) SetBytes(addr uint64, value []byte, size uint64) error { + bytes, err := vm.GetBytes(addr, size) if err != nil { return err } @@ -227,7 +227,7 @@ func (vm *VM) setBytes(addr uint64, value []byte, size uint64) error { } func (vm *VM) atomicUint64(addr uint64, inc uint64, imm int64) (uint64, bool, error) { - value, err := vm.getUint64(addr) + value, err := vm.GetUint64(addr) if err != nil { return 0, false, err } @@ -245,7 +245,7 @@ func (vm *VM) atomicUint64(addr uint64, inc uint64, imm int64) (uint64, bool, er res = inc case 0xf0: // CMPXCHG if value == vm.regs[asm.R0] { - if err := vm.setUint64(addr, inc); err != nil { + if err := vm.SetUint64(addr, inc); err != nil { return 0, false, err } } @@ -253,11 +253,11 @@ func (vm *VM) atomicUint64(addr uint64, inc uint64, imm int64) (uint64, bool, er default: return 0, false, fmt.Errorf("unknown atomic operand: %d", imm) } - return value, false, vm.setUint64(addr, res) + return value, false, vm.SetUint64(addr, res) } func (vm *VM) atomicUint32(addr uint64, inc uint32, imm int64) (uint32, bool, error) { - value, err := vm.getUint32(addr) + value, err := vm.GetUint32(addr) if err != nil { return 0, false, err } @@ -275,7 +275,7 @@ func (vm *VM) atomicUint32(addr uint64, inc uint32, imm int64) (uint32, bool, er res = inc case 0xf0: // CMPXCHG if value == uint32(vm.regs[asm.R0]) { - if err := vm.setUint32(addr, inc); err != nil { + if err := vm.SetUint32(addr, inc); err != nil { return 0, false, err } } @@ -283,7 +283,7 @@ func (vm *VM) atomicUint32(addr uint64, inc uint32, imm int64) (uint32, bool, er default: return 0, false, fmt.Errorf("unknown atomic operand: %d", imm) } - return value, false, vm.setUint32(addr, res) + return value, false, vm.SetUint32(addr, res) } func isStrSection(name string) bool { @@ -403,6 +403,21 @@ func normalizeInsts(insts []asm.Instruction) []asm.Instruction { return normInsts } +// Regs returns vm registers +func (vm *VM) Regs() Regs { + return vm.regs +} + +// Stack returns the stack +func (vm *VM) Stack() []byte { + return vm.stack +} + +// GetMapByName returns the map +func (vm *VM) GetMapByName(name string) *Map { + return vm.maps.GetMapByName(name) +} + func (vm *VM) RunInstructions(ctx Context, insts []asm.Instruction) (int64, error) { // prepare the instruction insts = resolveSymbolReferences(insts) @@ -435,28 +450,28 @@ func (vm *VM) RunInstructions(ctx Context, insts []asm.Instruction) (int64, erro // case asm.LoadMemOp(asm.DWord): srcAddr := vm.regs[inst.Src] + uint64(inst.Offset) - value, err := vm.getUint64(srcAddr) + value, err := vm.GetUint64(srcAddr) if err != nil { return ErrorCode, err } vm.regs[inst.Dst] = value case asm.LoadMemOp(asm.Word): srcAddr := vm.regs[inst.Src] + uint64(inst.Offset) - value, err := vm.getUint32(srcAddr) + value, err := vm.GetUint32(srcAddr) if err != nil { return ErrorCode, err } vm.regs[inst.Dst] = uint64(value) case asm.LoadMemOp(asm.Half): srcAddr := vm.regs[inst.Src] + uint64(inst.Offset) - value, err := vm.getUint16(srcAddr) + value, err := vm.GetUint16(srcAddr) if err != nil { return ErrorCode, err } vm.regs[inst.Dst] = uint64(value) case asm.LoadMemOp(asm.Byte): srcAddr := vm.regs[inst.Src] + uint64(inst.Offset) - value, err := vm.getUint8(srcAddr) + value, err := vm.GetUint8(srcAddr) if err != nil { return ErrorCode, err } @@ -520,43 +535,43 @@ func (vm *VM) RunInstructions(ctx Context, insts []asm.Instruction) (int64, erro // case asm.StoreMemOp(asm.DWord): dstAddr := vm.regs[inst.Dst] + uint64(inst.Offset) - if err := vm.setUint64(dstAddr, vm.regs[inst.Src]); err != nil { + if err := vm.SetUint64(dstAddr, vm.regs[inst.Src]); err != nil { return ErrorCode, err } case asm.StoreMemOp(asm.Word): dstAddr := vm.regs[inst.Dst] + uint64(inst.Offset) - if err := vm.setUint32(dstAddr, uint32(vm.regs[inst.Src])); err != nil { + if err := vm.SetUint32(dstAddr, uint32(vm.regs[inst.Src])); err != nil { return ErrorCode, err } case asm.StoreMemOp(asm.Half): dstAddr := vm.regs[inst.Dst] + uint64(inst.Offset) - if err := vm.setUint16(dstAddr, uint16(vm.regs[inst.Src])); err != nil { + if err := vm.SetUint16(dstAddr, uint16(vm.regs[inst.Src])); err != nil { return ErrorCode, err } case asm.StoreMemOp(asm.Byte): dstAddr := vm.regs[inst.Dst] + uint64(inst.Offset) - if err := vm.setUint8(dstAddr, uint8(vm.regs[inst.Src])); err != nil { + if err := vm.SetUint8(dstAddr, uint8(vm.regs[inst.Src])); err != nil { return ErrorCode, err } case asm.StoreImmOp(asm.DWord): dstAddr := vm.regs[inst.Dst] + uint64(inst.Offset) - if err := vm.setUint64(dstAddr, uint64(inst.Constant)); err != nil { + if err := vm.SetUint64(dstAddr, uint64(inst.Constant)); err != nil { return ErrorCode, err } case asm.StoreImmOp(asm.Word): dstAddr := vm.regs[inst.Dst] + uint64(inst.Offset) - if err := vm.setUint32(dstAddr, uint32(inst.Constant)); err != nil { + if err := vm.SetUint32(dstAddr, uint32(inst.Constant)); err != nil { return ErrorCode, err } case asm.StoreImmOp(asm.Half): dstAddr := vm.regs[inst.Dst] + uint64(inst.Offset) - if err := vm.setUint16(dstAddr, uint16(inst.Constant)); err != nil { + if err := vm.SetUint16(dstAddr, uint16(inst.Constant)); err != nil { return ErrorCode, err } case asm.StoreImmOp(asm.Byte): dstAddr := vm.regs[inst.Dst] + uint64(inst.Offset) - if err := vm.setUint8(dstAddr, uint8(inst.Constant)); err != nil { + if err := vm.SetUint8(dstAddr, uint8(inst.Constant)); err != nil { return ErrorCode, err }