diff --git a/cmd/run.go b/cmd/run.go
index 5fdca4c4f140c29b46f0ec60413169eee2314f01..ba4844efbdb82a7d988452e733f6a705364f3d85 100644
--- a/cmd/run.go
+++ b/cmd/run.go
@@ -162,7 +162,13 @@ func (p *ProcessPreimageOracle) Close() error {
 	}
 	_ = p.cmd.Process.Signal(os.Interrupt)
 	p.cmd.WaitDelay = time.Second * 10
-	return p.cmd.Wait()
+	err := p.cmd.Wait()
+	if err, ok := err.(*exec.ExitError); ok {
+		if err.Success() {
+			return nil
+		}
+	}
+	return err
 }
 
 type StepFn func(proof bool) (*mipsevm.StepWitness, error)
@@ -248,6 +254,10 @@ func Run(ctx *cli.Context) error {
 	startStep := state.Step
 
 	for !state.Exited {
+		if err := ctx.Context.Err(); err != nil {
+			return err
+		}
+
 		step := state.Step
 
 		name := meta.LookupSymbol(state.PC)
diff --git a/main.go b/main.go
index 000dcef239519b04098228e1879a9d88b3071828..e8704fe090b9ff6c7770f9adfb75d9b61c065a23 100644
--- a/main.go
+++ b/main.go
@@ -1,8 +1,12 @@
 package main
 
 import (
+	"context"
+	"errors"
 	"fmt"
 	"os"
+	"os/signal"
+	"syscall"
 
 	"github.com/urfave/cli/v2"
 
@@ -18,9 +22,26 @@ func main() {
 		cmd.LoadELFCommand,
 		cmd.RunCommand,
 	}
-	err := app.Run(os.Args)
+	ctx, cancel := context.WithCancel(context.Background())
+
+	c := make(chan os.Signal, 1)
+	signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
+	go func() {
+		for {
+			<-c
+			cancel()
+			fmt.Println("\r\nExiting...")
+		}
+	}()
+
+	err := app.RunContext(ctx, os.Args)
 	if err != nil {
-		_, _ = fmt.Fprintf(os.Stderr, "error: %v", err)
-		os.Exit(1)
+		if errors.Is(err, ctx.Err()) {
+			_, _ = fmt.Fprintf(os.Stderr, "command interrupted")
+			os.Exit(130)
+		} else {
+			_, _ = fmt.Fprintf(os.Stderr, "error: %v", err)
+			os.Exit(1)
+		}
 	}
 }
diff --git a/mipsevm/mips.go b/mipsevm/mips.go
index f1c60e06d11a501187b00489958677f8e598182d..84b24f69a9d4a301ff609bba9f4821fc2e20d332 100644
--- a/mipsevm/mips.go
+++ b/mipsevm/mips.go
@@ -41,7 +41,7 @@ func (m *InstrumentedState) handleSyscall() error {
 	a1 := m.state.Registers[5]
 	a2 := m.state.Registers[6]
 
-	fmt.Printf("syscall: %d\n", syscallNum)
+	//fmt.Printf("syscall: %d\n", syscallNum)
 	switch syscallNum {
 	case 4090: // mmap
 		sz := a1
@@ -50,11 +50,11 @@ func (m *InstrumentedState) handleSyscall() error {
 		}
 		if a0 == 0 {
 			v0 = m.state.Heap
-			fmt.Printf("mmap heap 0x%x size 0x%x\n", v0, sz)
+			//fmt.Printf("mmap heap 0x%x size 0x%x\n", v0, sz)
 			m.state.Heap += sz
 		} else {
 			v0 = a0
-			fmt.Printf("mmap hint 0x%x size 0x%x\n", v0, sz)
+			//fmt.Printf("mmap hint 0x%x size 0x%x\n", v0, sz)
 		}
 		// Go does this thing where it first gets memory with PROT_NONE,
 		// and then mmaps with a hint with prot=3 (PROT_READ|WRITE).
@@ -84,7 +84,7 @@ func (m *InstrumentedState) handleSyscall() error {
 			m.trackMemAccess(effAddr)
 			mem := m.state.Memory.GetMemory(effAddr)
 			dat, datLen := m.readPreimage(m.state.PreimageKey, m.state.PreimageOffset)
-			fmt.Printf("reading pre-image data: addr: %08x, offset: %d, datLen: %d, data: %x, key: %s  count: %d\n", a1, m.state.PreimageOffset, datLen, dat[:datLen], m.state.PreimageKey, a2)
+			//fmt.Printf("reading pre-image data: addr: %08x, offset: %d, datLen: %d, data: %x, key: %s  count: %d\n", a1, m.state.PreimageOffset, datLen, dat[:datLen], m.state.PreimageKey, a2)
 			alignment := a1 & 3
 			space := 4 - alignment
 			if space < datLen {
@@ -99,7 +99,7 @@ func (m *InstrumentedState) handleSyscall() error {
 			m.state.Memory.SetMemory(effAddr, binary.BigEndian.Uint32(outMem[:]))
 			m.state.PreimageOffset += datLen
 			v0 = datLen
-			fmt.Printf("read %d pre-image bytes, new offset: %d, eff addr: %08x mem: %08x\n", datLen, m.state.PreimageOffset, effAddr, outMem)
+			//fmt.Printf("read %d pre-image bytes, new offset: %d, eff addr: %08x mem: %08x\n", datLen, m.state.PreimageOffset, effAddr, outMem)
 		case fdHintRead: // hint response
 			// don't actually read into memory, just say we read it all, we ignore the result anyway
 			v0 = a2
@@ -147,7 +147,7 @@ func (m *InstrumentedState) handleSyscall() error {
 			copy(key[32-a2:], tmp[:])
 			m.state.PreimageKey = key
 			m.state.PreimageOffset = 0
-			fmt.Printf("updating pre-image key: %s\n", m.state.PreimageKey)
+			//fmt.Printf("updating pre-image key: %s\n", m.state.PreimageKey)
 			v0 = a2
 		default:
 			v0 = 0xFFffFFff