gruesome 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -33,236 +33,305 @@ require_relative 'header'
33
33
  # will specify an exact number.
34
34
 
35
35
  module Gruesome
36
- module Z
37
-
38
- # This class holds the memory for the virtual machine
39
- class Memory
40
- attr_accessor :program_counter
41
- attr_reader :num_locals
42
-
43
- def initialize(contents)
44
- @call_stack = []
45
- @stack = []
46
- @memory = contents
47
- @num_locals = 0
48
-
49
- # Get the header information
50
- @header = Header.new(@memory)
51
- @program_counter = @header.entry
52
-
53
- # With the header info, discover the bounds of each memory region
54
- @dyn_base = 0x0
55
- @dyn_limit = @header.static_mem_base
56
-
57
- # Cannot Write to Static Memory
58
- @static_base = @header.static_mem_base
59
- @static_limit = @memory.length
60
-
61
- # Cannot Access High Memory
62
- @high_base = @header.high_mem_base
63
- @high_limit = @memory.length
64
-
65
- # Error if high memory overlaps dynamic memory
66
- if @high_base < @dyn_limit
67
- # XXX: ERROR
68
- end
69
-
70
- # Check machine endianess
71
- @endian = [1].pack('S')[0] == 1 ? 'little' : 'big'
72
- end
73
-
74
- def packed_address_to_byte_address(address)
75
- if @header.version <=3
76
- address * 2
77
- else
78
- end
79
- end
80
-
81
- # Sets up the environment for a new routine
82
- def push_routine(return_addr, num_locals, destination)
83
- # pushes the stack onto the call stack
84
- @call_stack.push @num_locals
85
- @call_stack.push destination
86
- @call_stack.push @stack
87
-
88
- # empties the current stack
89
- @stack = Array.new()
90
-
91
- # pushes the return address onto the stack
92
- @stack.push(return_addr)
93
-
94
- # push locals
95
- num_locals.times do
96
- @stack.push 0
97
- end
98
-
99
- @num_locals = num_locals
100
- end
101
-
102
- # Tears down the environment for the current routine
103
- def pop_routine()
104
- # return the return address
105
- return_addr = @stack[0]
106
- @stack = @call_stack.pop
107
- destination = @call_stack.pop
108
- @num_locals = @call_stack.pop
109
-
110
- {:destination => destination, :return_address => return_addr}
111
- end
112
-
113
- def readb(address)
114
- if address < @high_base
115
- force_readb(address)
116
- else
117
- # XXX: Access violation
118
- raise "Access Violation accessing $" + sprintf("%04x", address)
119
- nil
120
- end
121
- end
122
-
123
- def readw(address)
124
- if (address + 1) < @high_base
125
- force_readw(address)
126
- else
127
- # XXX: Access violation
128
- raise "Access Violation accessing $" + sprintf("%04x", address)
129
- nil
130
- end
131
- end
132
-
133
- def writeb(address, value)
134
- if address < @static_base
135
- force_writeb(address, value)
136
- else
137
- # XXX: Access violation
138
- raise "Access Violation (W) accessing $" + sprintf("%04x", address)
139
- nil
140
- end
141
- end
142
-
143
- def writew(address, value)
144
- if (address + 1) < @static_base
145
- force_writew(address, value)
146
- else
147
- # XXX: Access violation
148
- raise "Access Violation (W) accessing $" + sprintf("%04x", address)
149
- nil
150
- end
151
- end
152
-
153
- def force_readb(address)
154
- if address < @memory.size
155
- @memory.getbyte(address)
156
- else
157
- # XXX: Access Violation
158
- raise "Major Access Violation accessing $" + sprintf("%04x", address)
159
- nil
160
- end
161
- end
162
-
163
- def force_readw(address)
164
- if (address + 1) < @memory.size
165
- if @endian == 'little'
166
- (@memory.getbyte(address+1) << 8) | @memory.getbyte(address)
167
- else
168
- (@memory.getbyte(address) << 8) | @memory.getbyte(address+1)
169
- end
170
- else
171
- # XXX: Access Violation
172
- raise "Major Access Violation accessing $" + sprintf("%04x", address)
173
- nil
174
- end
175
- end
176
-
177
- def force_writeb(address, value)
178
- if address < @memory.size
179
- @memory.setbyte(address, (value & 255))
180
- else
181
- # XXX: Access Violation
182
- raise "Major Access (W) Violation accessing $" + sprintf("%04x", address)
183
- nil
184
- end
185
- end
186
-
187
- def force_writew(address, value)
188
- if (address + 1) < @memory.size
189
- low_byte = value & 255
190
- high_byte = (value >> 8) & 255
191
-
192
- if @endian == 'little'
193
- tmp = high_byte
194
- high_byte = low_byte
195
- low_byte = tmp
196
- end
197
-
198
- @memory.setbyte(address, high_byte)
199
- @memory.setbyte(address+1, low_byte)
200
- else
201
- # XXX: Access Violation
202
- raise "Major Access (W) Violation accessing $" + sprintf("%04x", address)
203
- nil
204
- end
205
- end
206
-
207
- def contents
208
- @memory
209
- end
210
-
211
- # Read from variable number index
212
- def readv(index)
213
- if index == 0
214
- # pop from stack
215
- @stack.pop
216
- elsif index >= 16
217
- index -= 16
218
- readw(@header.global_var_addr + (index*2))
219
- elsif index <= @num_locals
220
- @stack[index]
221
- else
222
- # XXX: Error
223
- end
224
- end
225
-
226
- # Write value to variable number index
227
- def writev(index, value)
228
- value &= 65535
229
- if index == 0
230
- # push to stack
231
- @stack.push value
232
- elsif index >= 16
233
- index -= 16
234
- writew(@header.global_var_addr + (index*2), value)
235
- elsif index <= @num_locals
236
- @stack[index] = value
237
- else
238
- # XXX: Error
239
- end
240
- end
241
-
242
- def force_readzstr(index, max_len = -1)
243
- chrs = []
244
- continue = true
245
- orig_index = index
246
-
247
- until continue == false do
248
- if max_len != -1 and (index + 2 - orig_index) > max_len
249
- break
250
- end
251
-
252
- byte1 = force_readb(index)
253
- byte2 = force_readb(index+1)
254
-
255
- index += 2
256
-
257
- chrs << ((byte1 >> 2) & 0b11111)
258
- chrs << (((byte1 & 0b11) << 3) | (byte2 >> 5))
259
- chrs << (byte2 & 0b11111)
260
-
261
- continue = (byte1 & 0b10000000) == 0
262
- end
263
-
264
- return [index - orig_index, chrs]
265
- end
266
- end
267
- end
36
+ module Z
37
+
38
+ # This class holds the memory for the virtual machine
39
+ class Memory
40
+ attr_accessor :program_counter
41
+ attr_reader :num_locals
42
+
43
+ def initialize(contents, save_file_name)
44
+ @call_stack = []
45
+ @save_file_name = save_file_name
46
+ @stack = []
47
+ @memory = contents
48
+ @num_locals = 0
49
+
50
+ # Get the header information
51
+ @header = Header.new(@memory)
52
+ @program_counter = @header.entry
53
+
54
+ # With the header info, discover the bounds of each memory region
55
+ @dyn_base = 0x0
56
+ @dyn_limit = @header.static_mem_base
57
+
58
+ # Cannot Write to Static Memory
59
+ @static_base = @header.static_mem_base
60
+ @static_limit = @memory.length
61
+
62
+ # Cannot Access High Memory
63
+ @high_base = @header.high_mem_base
64
+ @high_limit = @memory.length
65
+
66
+ # Error if high memory overlaps dynamic memory
67
+ if @high_base < @dyn_limit
68
+ # XXX: ERROR
69
+ end
70
+
71
+ # Check machine endianess
72
+ @endian = [1].pack('S')[0] == 1 ? 'little' : 'big'
73
+ end
74
+
75
+ def packed_address_to_byte_address(address)
76
+ if @header.version <=3
77
+ address * 2
78
+ else
79
+ end
80
+ end
81
+
82
+ # Sets up the environment for a new routine
83
+ def push_routine(return_addr, num_locals, destination)
84
+ # pushes the stack onto the call stack
85
+ @call_stack.push @num_locals
86
+ @call_stack.push destination
87
+ @call_stack.push @stack
88
+
89
+ # empties the current stack
90
+ @stack = Array.new()
91
+
92
+ # pushes the return address onto the stack
93
+ @stack.push(return_addr)
94
+
95
+ # push locals
96
+ num_locals.times do
97
+ @stack.push 0
98
+ end
99
+
100
+ @num_locals = num_locals
101
+ end
102
+
103
+ # Tears down the environment for the current routine
104
+ def pop_routine()
105
+ # return the return address
106
+ return_addr = @stack[0]
107
+ @stack = @call_stack.pop
108
+ destination = @call_stack.pop
109
+ @num_locals = @call_stack.pop
110
+
111
+ {:destination => destination, :return_address => return_addr}
112
+ end
113
+
114
+ def readb(address)
115
+ if address < @high_base
116
+ force_readb(address)
117
+ else
118
+ # XXX: Access violation
119
+ raise "Access Violation accessing $" + sprintf("%04x", address)
120
+ nil
121
+ end
122
+ end
123
+
124
+ def readw(address)
125
+ if (address + 1) < @high_base
126
+ force_readw(address)
127
+ else
128
+ # XXX: Access violation
129
+ raise "Access Violation accessing $" + sprintf("%04x", address)
130
+ nil
131
+ end
132
+ end
133
+
134
+ def writeb(address, value)
135
+ if address < @static_base
136
+ force_writeb(address, value)
137
+ else
138
+ # XXX: Access violation
139
+ raise "Access Violation (W) accessing $" + sprintf("%04x", address)
140
+ nil
141
+ end
142
+ end
143
+
144
+ def writew(address, value)
145
+ if (address + 1) < @static_base
146
+ force_writew(address, value)
147
+ else
148
+ # XXX: Access violation
149
+ raise "Access Violation (W) accessing $" + sprintf("%04x", address)
150
+ nil
151
+ end
152
+ end
153
+
154
+ def force_readb(address)
155
+ if address < @memory.size
156
+ @memory.getbyte(address)
157
+ else
158
+ # XXX: Access Violation
159
+ raise "Major Access Violation accessing $" + sprintf("%04x", address)
160
+ nil
161
+ end
162
+ end
163
+
164
+ def force_readw(address)
165
+ if (address + 1) < @memory.size
166
+ if @endian == 'little'
167
+ (@memory.getbyte(address+1) << 8) | @memory.getbyte(address)
168
+ else
169
+ (@memory.getbyte(address) << 8) | @memory.getbyte(address+1)
170
+ end
171
+ else
172
+ # XXX: Access Violation
173
+ raise "Major Access Violation accessing $" + sprintf("%04x", address)
174
+ nil
175
+ end
176
+ end
177
+
178
+ def force_writeb(address, value)
179
+ if address < @memory.size
180
+ @memory.setbyte(address, (value & 255))
181
+ else
182
+ # XXX: Access Violation
183
+ raise "Major Access (W) Violation accessing $" + sprintf("%04x", address)
184
+ nil
185
+ end
186
+ end
187
+
188
+ def force_writew(address, value)
189
+ if (address + 1) < @memory.size
190
+ low_byte = value & 255
191
+ high_byte = (value >> 8) & 255
192
+
193
+ if @endian == 'little'
194
+ tmp = high_byte
195
+ high_byte = low_byte
196
+ low_byte = tmp
197
+ end
198
+
199
+ @memory.setbyte(address, high_byte)
200
+ @memory.setbyte(address+1, low_byte)
201
+ else
202
+ # XXX: Access Violation
203
+ raise "Major Access (W) Violation accessing $" + sprintf("%04x", address)
204
+ nil
205
+ end
206
+ end
207
+
208
+ def contents
209
+ @memory
210
+ end
211
+
212
+ # Read from variable number index
213
+ def readv(index)
214
+ if index == 0
215
+ # pop from stack
216
+ @stack.pop
217
+ elsif index >= 16
218
+ index -= 16
219
+ readw(@header.global_var_addr + (index*2))
220
+ elsif index <= @num_locals
221
+ @stack[index]
222
+ else
223
+ # XXX: Error
224
+ end
225
+ end
226
+
227
+ # Write value to variable number index
228
+ def writev(index, value)
229
+ value &= 65535
230
+ if index == 0
231
+ # push to stack
232
+ @stack.push value
233
+ elsif index >= 16
234
+ index -= 16
235
+ writew(@header.global_var_addr + (index*2), value)
236
+ elsif index <= @num_locals
237
+ @stack[index] = value
238
+ else
239
+ # XXX: Error
240
+ end
241
+ end
242
+
243
+ def force_readzstr(index, max_len = -1)
244
+ chrs = []
245
+ continue = true
246
+ orig_index = index
247
+
248
+ until continue == false do
249
+ if max_len != -1 and (index + 2 - orig_index) > max_len
250
+ break
251
+ end
252
+
253
+ byte1 = force_readb(index)
254
+ byte2 = force_readb(index+1)
255
+
256
+ index += 2
257
+
258
+ chrs << ((byte1 >> 2) & 0b11111)
259
+ chrs << (((byte1 & 0b11) << 3) | (byte2 >> 5))
260
+ chrs << (byte2 & 0b11111)
261
+
262
+ continue = (byte1 & 0b10000000) == 0
263
+ end
264
+
265
+ return [index - orig_index, chrs]
266
+ end
267
+
268
+ def save
269
+ # Save contents of dynamic memory to disk
270
+ File.open(@save_file_name, "wb+") do |f|
271
+ f.puts @program_counter
272
+ f.puts (@call_stack.size / 3)
273
+ @call_stack.each_with_index do |call_stack, i|
274
+ if (i % 3) == 0 or (i % 3) == 1
275
+ f.puts call_stack
276
+ else
277
+ # this is stack
278
+ stack = call_stack
279
+ f.puts stack.size
280
+ stack.each do |stack_entry|
281
+ f.puts stack_entry
282
+ end
283
+ end
284
+ end
285
+ f.puts @num_locals
286
+ f.puts @stack.size
287
+ @stack.each do |stack_entry|
288
+ f.puts stack_entry
289
+ end
290
+
291
+ @dyn_limit.times do |i|
292
+ f.write force_readb(i).chr
293
+ end
294
+ end
295
+ end
296
+
297
+ def restore
298
+ # Restore, if it can, the contents of memory from disk
299
+ File.open(@save_file_name, "rb") do |f|
300
+ @call_stack = []
301
+
302
+ @program_counter = f.readline.to_i
303
+ call_stack_size = f.readline.to_i
304
+
305
+ call_stack_size.times do
306
+ num_locals = f.readline.to_i
307
+ destination = f.readline.to_i
308
+ stack_size = f.readline.to_i
309
+
310
+ stack = []
311
+ stack_size.times do |i|
312
+ stack.push f.readline.to_i
313
+ end
314
+
315
+ @call_stack.push num_locals
316
+ @call_stack.push destination
317
+ @call_stack.push stack
318
+ end
319
+
320
+ @num_locals = f.readline.to_i
321
+ stack_size = f.readline.to_i
322
+
323
+ @stack = []
324
+ stack_size.times do |i|
325
+ @stack.push f.readline.to_i
326
+ end
327
+
328
+ i = 0
329
+ f.read.each_byte do |b|
330
+ force_writeb(i, b)
331
+ i += 1
332
+ end
333
+ end
334
+ end
335
+ end
336
+ end
268
337
  end