forked from ethereum-optimism/optimism
-
Notifications
You must be signed in to change notification settings - Fork 40
/
Copy pathmips.go
138 lines (123 loc) · 4.1 KB
/
mips.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package mipsevm
import (
"encoding/binary"
"fmt"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
)
type MemTracker func(addr uint32)
func (m *InstrumentedState) readPreimage(key [32]byte, offset uint32) (dat [32]byte, datLen uint32) {
preimage := m.lastPreimage
if key != m.lastPreimageKey {
m.lastPreimageKey = key
data := m.preimageOracle.GetPreimage(key)
// add the length prefix
preimage = make([]byte, 0, 8+len(data))
preimage = binary.BigEndian.AppendUint64(preimage, uint64(len(data)))
preimage = append(preimage, data...)
m.lastPreimage = preimage
}
m.lastPreimageOffset = offset
datLen = uint32(copy(dat[:], preimage[offset:]))
return
}
func (m *InstrumentedState) trackMemAccess(effAddr uint32) {
if m.memProofEnabled && m.lastMemAccess != effAddr {
if m.lastMemAccess != ^uint32(0) {
panic(fmt.Errorf("unexpected different mem access at %08x, already have access at %08x buffered", effAddr, m.lastMemAccess))
}
m.lastMemAccess = effAddr
m.memProof = m.state.Memory.MerkleProof(effAddr)
}
}
func (m *InstrumentedState) handleSyscall() error {
syscallNum, a0, a1, a2 := getSyscallArgs(&m.state.Registers)
v0 := uint32(0)
v1 := uint32(0)
//fmt.Printf("syscall: %d\n", syscallNum)
switch syscallNum {
case sysMmap:
var newHeap uint32
v0, v1, newHeap = handleSysMmap(a0, a1, m.state.Heap)
m.state.Heap = newHeap
case sysBrk:
v0 = 0x40000000
case sysClone: // clone (not supported)
v0 = 1
case sysExitGroup:
m.state.Exited = true
m.state.ExitCode = uint8(a0)
return nil
case sysRead:
var newPreimageOffset uint32
v0, v1, newPreimageOffset = handleSysRead(a0, a1, a2, m.state.PreimageKey, m.state.PreimageOffset, m.readPreimage, m.state.Memory, m.trackMemAccess)
m.state.PreimageOffset = newPreimageOffset
case sysWrite:
var newLastHint hexutil.Bytes
var newPreimageKey common.Hash
var newPreimageOffset uint32
v0, v1, newLastHint, newPreimageKey, newPreimageOffset = handleSysWrite(a0, a1, a2, m.state.LastHint, m.state.PreimageKey, m.state.PreimageOffset, m.preimageOracle, m.state.Memory, m.trackMemAccess, m.stdOut, m.stdErr)
m.state.LastHint = newLastHint
m.state.PreimageKey = newPreimageKey
m.state.PreimageOffset = newPreimageOffset
case sysFcntl:
v0, v1 = handleSysFcntl(a0, a1)
}
handleSyscallUpdates(&m.state.Cpu, &m.state.Registers, v0, v1)
return nil
}
func (m *InstrumentedState) pushStack(target uint32) {
if !m.debugEnabled {
return
}
m.debug.stack = append(m.debug.stack, target)
m.debug.caller = append(m.debug.caller, m.state.Cpu.PC)
}
func (m *InstrumentedState) popStack() {
if !m.debugEnabled {
return
}
if len(m.debug.stack) != 0 {
fn := m.debug.meta.LookupSymbol(m.state.Cpu.PC)
topFn := m.debug.meta.LookupSymbol(m.debug.stack[len(m.debug.stack)-1])
if fn != topFn {
// most likely the function was inlined. Snap back to the last return.
i := len(m.debug.stack) - 1
for ; i >= 0; i-- {
if m.debug.meta.LookupSymbol(m.debug.stack[i]) == fn {
m.debug.stack = m.debug.stack[:i]
m.debug.caller = m.debug.caller[:i]
break
}
}
} else {
m.debug.stack = m.debug.stack[:len(m.debug.stack)-1]
m.debug.caller = m.debug.caller[:len(m.debug.caller)-1]
}
} else {
fmt.Printf("ERROR: stack underflow at pc=%x. step=%d\n", m.state.Cpu.PC, m.state.Step)
}
}
func (m *InstrumentedState) Traceback() {
fmt.Printf("traceback at pc=%x. step=%d\n", m.state.Cpu.PC, m.state.Step)
for i := len(m.debug.stack) - 1; i >= 0; i-- {
s := m.debug.stack[i]
idx := len(m.debug.stack) - i - 1
fmt.Printf("\t%d %x in %s caller=%08x\n", idx, s, m.debug.meta.LookupSymbol(s), m.debug.caller[i])
}
}
func (m *InstrumentedState) mipsStep() error {
if m.state.Exited {
return nil
}
m.state.Step += 1
// instruction fetch
insn, opcode, fun := getInstructionDetails(m.state.Cpu.PC, m.state.Memory)
// Handle syscall separately
// syscall (can read and write)
if opcode == 0 && fun == 0xC {
return m.handleSyscall()
}
// Exec the rest of the step logic
return execMipsCoreStepLogic(&m.state.Cpu, &m.state.Registers, m.state.Memory, insn, opcode, fun, m.trackMemAccess, m)
}