gruesome 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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