-
Notifications
You must be signed in to change notification settings - Fork 67
/
UnicornSimulator.class.st
159 lines (122 loc) · 4.27 KB
/
UnicornSimulator.class.st
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
Class {
#name : #UnicornSimulator,
#superclass : #ProcessorSimulator,
#instVars : [
'stopReason',
'invalidAccessHandler'
],
#category : #'VMMakerTests-Unicorn'
}
{ #category : #'instance creation' }
UnicornSimulator class >> supportsISA: isa [
^ #( #ARMv5 #ARMv8 #IA32 #X64 #aarch64 #riscv64 ) includes: isa
]
{ #category : #accessing }
UnicornSimulator >> argument1RegisterValue: anInteger [
self subclassResponsibility
]
{ #category : #initialization }
UnicornSimulator >> createUnicorn [
self subclassResponsibility
]
{ #category : #executing }
UnicornSimulator >> doStartAt: startAddress until: until timeout: timeout count: count [
| result error startTime currentTime remainingTimeout remainingCount |
self instructionPointerRegisterValue: startAddress.
startTime := Time millisecondClockValue.
remainingTimeout := timeout.
remainingCount := count.
[ true ]
whileTrue: [
[result := simulator
startAt: self instructionPointerRegisterValue
until: until
timeout: remainingTimeout
count: remainingCount.
stopReason ifNotNil: [
error := stopReason.
stopReason := nil.
error signal ].
"If execution did not stop because of a stop reason, verify the error code"
simulator verifyErrorCode: result]
on: UnicornInvalidMemoryAccess do: [ :invalidAccess |
self instructionPointerRegisterValue = until ifTrue: [ ^ 0 ].
(self handleInvalidAccess: invalidAccess)
ifFalse: [ ^ result ]].
stopReason ifNotNil: [ ^ result ].
count ~= 0 ifTrue: [ | lastCount |
lastCount := simulator lastInstructionCount.
remainingCount := remainingCount - lastCount.
remainingCount <= 0 ifTrue: [ ^ result ]].
timeout ~= 0 ifTrue: [
currentTime := Time millisecondClockValue.
remainingTimeout := remainingTimeout - (currentTime - startTime).
remainingTimeout <= 0
ifTrue: [
UnicornTimeout new
target: until;
signal ]].
self instructionPointerRegisterValue = until
ifTrue: [ ^ result ]]
]
{ #category : #'stack-access' }
UnicornSimulator >> finishMappingMemory [
"Do nothing in the case of Unicorn, is useful if the simulator used has to map memory by hand"
]
{ #category : #'handling invalid accesses' }
UnicornSimulator >> handleInvalidAccess: invalidAccess [
| previousInstructionPointer hasToContinue |
previousInstructionPointer := self instructionPointerRegisterValue.
"If the called handler want to resume execution but it has not set a next instruction pointer to execute I will calculate it"
(hasToContinue := invalidAccessHandler value: invalidAccess)
ifTrue: [ previousInstructionPointer = self instructionPointerRegisterValue
ifTrue: [
self instructionPointerRegisterValue:
self lastExecutedInstructionAddress + self lastExecutedInstructionSize
] ].
^ hasToContinue
]
{ #category : #initialization }
UnicornSimulator >> initialize [
super initialize.
simulator := self createUnicorn.
self initializeUnicorn.
registerAliases := Dictionary new.
self initializeRegisterAliases.
invalidAccessHandler := [ :invalidAccess |
self cogit handleSimulationTrap: (UnicornSimulationTrap simulator: self error: invalidAccess).
true]
]
{ #category : #initialization }
UnicornSimulator >> initializeUnicorn [
simulator
registerInvalidMemoryAccessHook: UcHookType invalidMemoryAccess value
doing: [ :type :address :size :value |
simulator stop.
stopReason := UnicornInvalidMemoryAccess new
type: type;
address: address;
size: size;
value: value;
yourself.
false ]
]
{ #category : #'handling invalid accesses' }
UnicornSimulator >> invalidAccessHandler: aFullBlockClosure [
invalidAccessHandler := aFullBlockClosure
]
{ #category : #initialization }
UnicornSimulator >> registerHook: aBlock atAddress: anAddress [
simulator
registerInvalidMemoryAccessHook: UcHookType fetchingAccess value
doing: [ :type :address :size :value |
address = anAddress ifTrue: [ aBlock value ] ]
]
{ #category : #executing }
UnicornSimulator >> startAt: begin until: until timeout: timeout count: count [
self instructionPointerRegisterValue: begin.
"If we are asked to finish right away,
then don't call the simulation and same some cycles"
begin = until ifTrue: [ ^ self ].
^ self doStartAt: begin until: until timeout: timeout count: count.
]