History

Added basic writing support. Removed the string representations of instructions and changed instruction reading to ensure that an instance of a specific class is created for each instruction. Fixed the definition of the frame instruction.

David Boddie committed 9 years ago

Commit 9bbb0591 parent b2622162 files · +245 −57Browse files

Unified · Split

2 files
  1. dis.py +187 −13
  2. opcodes.py +58 −44
dis.py+187−13
@@ -19,7 +19,9 @@ from struct import calcsize, pack, unpack · 18 unmodified lines
1919
2020 import opcodes
2121 from utils import _read, read_B, read_C, read_OP, read_F, read_L, read_P, \
22− read_W
22+ read_W, \
23+ _write, write_B, write_C, write_OP, write_F, write_L, \
24+ write_P, write_W
2325
2426 XMAGIC = 0x0c8030
2527 SMAGIC = 0x0e1722
@@ -72,6 +74,7 @@ class Dis: · 46 unmodified lines
7274 self.entry_pc = read_OP(f)
7375 self.entry_type = read_OP(f)
7476
77+ # Read the other sections.
7578 self.read_code(f)
7679 self.read_types(f)
7780 self.read_data(f)
@@ -114,6 +117,7 @@ class Dis: · 36 unmodified lines
114117 # Use a list as a load address stack with an initial base address of 0.
115118 addresses = []
116119 base = 0
120+ type_ = None
117121
118122 while True:
119123
@@ -139,20 +143,26 @@ class Dis: · 19 unmodified lines
139143 type_index = _read(f, ">I")
140144 length = _read(f, ">I")
141145 type_ = self.types[type_index]
142− #print "Array", type_, type_.size, length
146+ #print "Array", offset
147+
143148 elif array_type == 6:
144− # Set array address
149+ # Set array index
145150 index = _read(f, ">I")
146− #print "Set array address", index, "(offset=%i)" % offset
151+ # Store the current base first.
147152 addresses.append(base)
153+ #print "Set", base, offset, index
148154 base = offset + index
155+
149156 elif array_type == 7:
150157 # Restore load address
151− #print "Restore load address"
152158 base = addresses.pop()
159+ type_ = None
160+ #print "Restore", base, offset
161+
153162 else:
163+ #print "Data", offset
154164 address = base + offset
155− item = Data(f, code, count, address, array_type)
165+ item = Data(f, code, count, offset, base, array_type, type_)
156166 self.data_items.append(item)
157167 if address in self.data:
158168 print "Overwriting existing data item at %x." % address
@@ -183,11 +193,109 @@ class Dis: · 24 unmodified lines
183193 if value == 0:
184194 break
185195
196+ sequence = []
197+
186198 i = 0
187199 while i < value:
188200
189− self.ldt.append(LDT(f))
201+ sequence.append(LDT(f))
190202 i += 1
203+
204+ self.ldt.append(sequence)
205+
206+ def write(self, f):
207+
208+ # Write the header.
209+ self.code_size = len(self.code)
210+
211+ # Only unsigned files are currently supported.
212+ write_OP(f, XMAGIC)
213+
214+ self.runtime_flag.write(f)
215+ write_OP(f, self.stack_extent)
216+ write_OP(f, self.code_size)
217+ write_OP(f, self.data_size)
218+ write_OP(f, self.type_size)
219+ write_OP(f, self.link_size)
220+ write_OP(f, self.entry_pc)
221+ write_OP(f, self.entry_type)
222+
223+ # Write the other sections.
224+ self.write_code(f)
225+ self.write_types(f)
226+ self.write_data(f)
227+
228+ write_C(f, self.module_name)
229+
230+ self.write_link(f)
231+
232+ if self.runtime_flag.contains(RuntimeFlag.HASLDT):
233+ self.write_ldt(f)
234+
235+ write_C(f, self.path)
236+
237+ def write_code(self, f):
238+
239+ for ins in self.code:
240+ ins.write(f)
241+
242+ def write_types(self, f):
243+
244+ for type_ in self.types:
245+ type_.write(f)
246+
247+ def write_data(self, f):
248+
249+ # Sort the dictionary items by address.
250+ items = self.data.items()
251+ items.sort()
252+
253+ addresses = []
254+ base = 0
255+
256+ for address, item in items:
257+
258+ if item.base != base:
259+
260+ # Array
261+ write_B(f, 0x51) # use count=1 to save a word
262+ write_OP(f, item.base - base) # offset
263+ _write(f, ">I", self.types.index(item.type_))
264+ _write(f, ">I", len(item.data))
265+
266+ # Set array address
267+ write_B(f, 0x61) # use count=1 to save a word
268+ write_OP(f, item.base - base) # offset
269+ _write(f, ">I", 0) # index
270+
271+ item.write(f)
272+
273+ if item.base != base:
274+
275+ # Restore load address
276+ write_B(f, 0x71) # use count=1 to save a word
277+ write_OP(f, 0) # offset
278+ base = addresses.pop()
279+
280+ write_OP(f, 0)
281+
282+ def write_link(self, f):
283+
284+ for link in self.link:
285+ link.write(f)
286+
287+ def write_ldt(self, f):
288+
289+ write_OP(f, self.initialised_globals)
290+
291+ for sequence in self.ldt:
292+
293+ write_OP(f, len(sequence))
294+
295+ for ldt in sequence:
296+ ldt.write(f)
297+
298+ write_OP(f, 0)
191299
192300 def list(self):
193301
@@ -213,6 +321,9 @@ class RuntimeFlag: · 19 unmodified lines
213321 def contains(self, flags):
214322
215323 return self.value & flags != 0
324+
325+ def write(self, f):
326+ write_OP(f, self.value)
216327
217328
218329 class Type:
@@ -224,6 +335,11 @@ class Type: · 5 unmodified lines
224335 self.number_ptrs = read_OP(f)
225336 self.array = f.read(self.number_ptrs)
226337
338+ def __repr__(self):
339+
340+ return "Type(desc=%i, size=%i, ptrs=%i)" % (self.desc_number,
341+ self.size, self.number_ptrs)
342+
227343 def is_pointer(self, address):
228344
229345 # Each bit in the array represents a word in the type. If the bit is 1
@@ -236,6 +352,13 @@ class Type: · 6 unmodified lines
236352 # Check whether the bit is 1 or 0, returning True for 1 and False for 0.
237353 mask = 1 << (bit % 8)
238354 return (ord(byte) & mask) != 0
355+
356+ def write(self, f):
357+
358+ write_OP(f, self.desc_number)
359+ write_OP(f, self.size)
360+ write_OP(f, self.number_ptrs)
361+ f.write(self.array)
239362
240363
241364 class Data:
@@ -244,12 +367,14 @@ class Data: · 2 unmodified lines
244367 "UTF-8 encoded string", "64-bit float", "Array",
245368 "Set array address", "Restore load address"]
246369
247− def __init__(self, f, code, count, address, array_type):
370+ def __init__(self, f, code, count, offset, base, array_type, type_):
248371
249372 self.code = code
250373 self.count = count
251− self.address = address
374+ self.offset = offset
375+ self.base = base
252376 self.array_type = array_type
377+ self.type_ = type_
253378
254379 self.array = []
255380 base = 0
@@ -276,8 +401,14 @@ class Data: · 20 unmodified lines
276401
277402 def __repr__(self):
278403
279− return "<%s.%s (%s) %s>" % (self.__module__, self.__class__.__name__,
280− self.array_types[self.array_type], repr(self.data()))
404+ if self.type_:
405+ return "Data(base=%i offset=%i raw='%s' type=%s data=%s>" % (
406+ self.base, self.offset, self.array_types[self.array_type],
407+ self.type_, repr(self.data()))
408+ else:
409+ return "Data(base=%i offset=%i raw='%s' data=%s>" % (
410+ self.base, self.offset, self.array_types[self.array_type],
411+ repr(self.data()))
281412
282413 def data(self):
283414
@@ -288,8 +419,8 @@ class Data: · 4 unmodified lines
288419
289420 def encoded(self):
290421
291− """Returns the contents of the array in the form they would take in the
292− module area on a big-endian system."""
422+ """Returns the contents of the array in the form they would take if
423+ serialised on a big-endian system."""
293424
294425 data = ""
295426
@@ -307,6 +438,28 @@ class Data: · 11 unmodified lines
307438 data += pack(">q", item)
308439
309440 return data
441+
442+ def write(self, f):
443+
444+ write_B(f, self.code)
445+
446+ if self.count >= 16:
447+ write_OP(f, self.count)
448+
449+ write_OP(f, self.offset)
450+
451+ for item in self.array:
452+
453+ if self.array_type == 1:
454+ write_B(f, item)
455+ elif self.array_type == 2:
456+ write_W(f, item)
457+ elif self.array_type == 3:
458+ f.write(item)
459+ elif self.array_type == 4:
460+ write_F(f, item)
461+ elif self.array_type == 8:
462+ write_L(f, item)
310463
311464
312465 class Link:
@@ -317,6 +470,18 @@ class Link: · 4 unmodified lines
317470 self.desc_number = read_OP(f)
318471 self.sig = read_W(f) # unsigned for hashes
319472 self.name = read_C(f)
473+
474+ def __repr__(self):
475+
476+ return "Link(pc=%s, desc=%i, sig=%s, name='%s')" % (
477+ hex(self.pc), self.desc_number, hex(self.sig), self.name)
478+
479+ def write(self, f):
480+
481+ write_OP(f, self.pc)
482+ write_OP(f, self.desc_number)
483+ write_W(f, self.sig)
484+ write_C(f, self.name)
320485
321486
322487 class LDT:
@@ -325,3 +490,12 @@ class LDT: · 2 unmodified lines
325490
326491 self.sig = _read(f, ">I") # unsigned for hashes
327492 self.name = read_C(f)
493+
494+ def __repr__(self):
495+
496+ return "LDT(sig=0x%x, name='%s')" % (self.sig, self.name)
497+
498+ def write(self, f):
499+
500+ _write(f, ">I", self.sig)
501+ write_C(f, self.name)
opcodes.py+58−44
@@ -21,34 +21,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. · 20 unmodified lines
2121
2222 from utils import read_B, read_OP, write_B, write_OP
2323
24−# Define string representations of the opcodes.
25−
26−instruction_names = [
27− "nop", "alt", "nbalt", "goto", "call", "frame", "spawn", "runt",
28− "load", "mcall", "mspawn", "mframe", "ret", "jmp", "case", "exit",
29− "new", "newa", "newcb", "newcw", "newcf", "newcp", "newcm", "newcmp",
30− "send", "recv", "consb", "consw", "consp", "consf", "consm", "consmp",
31− "headb", "headw", "headp", "headf", "headm", "headmp", "tail", "lea",
32− "indx", "movp", "movm", "movmp", "movb", "movw", "movf", "cvtbw",
33− "cvtwb", "cvtfw", "cvtwf", "cvtca", "cvtac", "cvtwc", "cvtcw", "cvtfc",
34− "cvtcf", "addb", "addw", "addf", "subb", "subw", "subf", "mulb",
35− "mulw", "mulf", "divb", "divw", "divf", "modw", "modb", "andb",
36− "andw", "orb", "orw", "xorb", "xorw", "shlb", "shlw", "shrb",
37− "shrw", "insc", "indc", "addc", "lenc", "lena", "lenl", "beqb",
38− "bneb", "bltb", "bleb", "bgtb", "bgeb", "beqw", "bnew", "bltw",
39− "blew", "bgtw", "bgew", "beqf", "bnef", "bltf", "blef", "bgtf",
40− "bgef", "beqc", "bnec", "bltc", "blec", "bgtc", "bgec", "slicea",
41− "slicela", "slicec", "indw", "indf", "indb", "negf", "movl", "addl",
42− "subl", "divl", "modl", "mull", "andl", "orl", "xorl", "shll",
43− "shrl", "bnel", "bltl", "blel", "bgtl", "bgel", "beql", "cvtlf",
44− "cvtfl", "cvtlw", "cvtwl", "cvtlc", "cvtcl", "headl", "consl", "newcl",
45− "casec", "indl", "movpc", "tcmp", "mnewz", "cvtrf", "cvtfr", "cvtws",
46− "cvtsw", "lsrw", "lsrl", "eclr", "newz", "newaz", "raise", "casel",
47− "mulx", "divx", "cvtxx", "mulx0", "divx0", "cvtxx0", "mulx1", "divx1",
48− "cvtxx1", "cvtfx", "cvtxf", "expw", "expl", "expf", "self"
49− ]
50−
51−
5224 class Instruction:
5325
5426 def __init__(self):
@@ -60,19 +32,34 @@ class Instruction: · 5 unmodified lines
6032
6133 def read(self, f):
6234
63− self.opcode = read_B(f)
64− self.address_mode = read_B(f)
35+ opcode = read_B(f)
36+ class_ = instructions[opcode]
37+
38+ address_mode = read_B(f)
6539
66− middle = self.address_mode & 0xc0
67− self.middle = self.read_middle_operand(middle, f)
40+ middle = address_mode & 0xc0
41+ middle = self.read_middle_operand(middle, f)
6842
69− source = (self.address_mode & 0x38) >> 3
70− self.source = self.read_operand(source, f)
43+ source = (address_mode & 0x38) >> 3
44+ source = self.read_operand(source, f)
7145
72− destination = self.address_mode & 0x07
73− self.destination = self.read_operand(destination, f)
46+ destination = address_mode & 0x07
47+ destination = self.read_operand(destination, f)
7448
75− return self
49+ if issubclass(class_, Src):
50+ return class_(source)
51+ elif issubclass(class_, Src_Src):
52+ return class_(source, middle)
53+ elif issubclass(class_, Src_Dst):
54+ return class_(source, destination)
55+ elif issubclass(class_, Src_Src_Dst):
56+ return class_(source, middle, destination)
57+ elif issubclass(class_, Src_Src_Src):
58+ return class_(source, middle, destination)
59+ elif issubclass(class_, Dst):
60+ return class_(destination)
61+ else:
62+ return class_()
7663
7764 def set_address_mode(self):
7865
@@ -130,7 +117,7 @@ class Instruction: · 51 unmodified lines
130117 def __repr__(self):
131118
132119 try:
133− name = instruction_names[self.opcode]
120+ name = self.__class__.__name__
134121 except IndexError:
135122 name = hex(self.opcode)
136123
@@ -203,11 +190,11 @@ class DoubleShortOffset(Operand): · 66 unmodified lines
203190 write_OP(f, self.value[0] & 0xffff)
204191 write_OP(f, self.value[1] & 0xffff)
205192
206−class DoubleShortOffsetMP(Operand):
193+class DoubleShortOffsetMP(DoubleShortOffset):
207194 str_pattern = "%i(%i(mp))"
208195 address_mode = 0x04
209196
210−class DoubleShortOffsetFP(Operand):
197+class DoubleShortOffsetFP(DoubleShortOffset):
211198 str_pattern = "%i(%i(fp))"
212199 address_mode = 0x05
213200
@@ -250,7 +237,7 @@ class Src_Src_Dst(Instruction): · 36 unmodified lines
250237 self.destination = dst
251238 self.set_address_mode()
252239
253−class Src_Src_src(Instruction):
240+class Src_Src_Src(Instruction):
254241
255242 def __init__(self, src1, src2, src3):
256243
@@ -380,7 +367,7 @@ class exit(Instruction): opcode = 0x0f · 123 unmodified lines
380367 class expf(Src_Src_Dst): opcode = 0xad # word word -> float (xec.c)
381368 class expl(Src_Src_Dst): opcode = 0xac # word long -> long (xec.c)
382369 class expw(Src_Src_Dst): opcode = 0xab # word word -> word (xec.c)
383−class frame(Src_Src): opcode = 0x05
370+class frame(Src_Dst): opcode = 0x05 # not src1, src2 as in documentation
384371 class goto(Src_Dst): opcode = 0x03
385372 class headb(headx): opcode = 0x20
386373 class headf(headx): opcode = 0x23
@@ -404,7 +391,7 @@ class lenl(Src_Dst): opcode = 0x56 · 17 unmodified lines
404391 class load(Src_Src_Dst): opcode = 0x08
405392 class lsrl(lsrx): opcode = 0x9a
406393 class lsrw(lsrx): opcode = 0x99
407−class mcall(Src_Src_src): opcode = 0x09
394+class mcall(Src_Src_Src): opcode = 0x09
408395 class mframe(Src_Src_Dst): opcode = 0x0b
409396 class mnewz(Src_Src_Dst): opcode = 0x94
410397 class modb(modx): opcode = 0x46
@@ -418,7 +405,7 @@ class movmp(Src_Src_Dst): opcode = 0x2b · 7 unmodified lines
418405 class movpc(Src_Dst): opcode = 0x92
419406 class movp(Src_Dst): opcode = 0x29
420407 class movw(movx): opcode = 0x2d
421−class mspawn(Src_Src_src): opcode = 0x0a
408+class mspawn(Src_Src_Src): opcode = 0x0a
422409 class mulb(mulx_): opcode = 0x3f
423410 class mulf(mulx_): opcode = 0x41
424411 class mull(mulx_): opcode = 0x7b
@@ -468,3 +455,30 @@ class tcmp(Src_Dst): opcode = 0x93 · 43 unmodified lines
468455 class xorb(xorx): opcode = 0x4b
469456 class xorl(xorx): opcode = 0x7e
470457 class xorw(xorx): opcode = 0x4c
458+
459+# Define a list to map opcodes to instruction classes.
460+
461+instructions = [
462+ nop, alt, nbalt, goto, call, frame, spawn, runt,
463+ load, mcall, mspawn, mframe, ret, jmp, case, exit,
464+ new, newa, newcb, newcw, newcf, newcp, newcm, newcmp,
465+ send, recv, consb, consw, consp, consf, consm, consmp,
466+ headb, headw, headp, headf, headm, headmp, tail, lea,
467+ indx, movp, movm, movmp, movb, movw, movf, cvtbw,
468+ cvtwb, cvtfw, cvtwf, cvtca, cvtac, cvtwc, cvtcw, cvtfc,
469+ cvtcf, addb, addw, addf, subb, subw, subf, mulb,
470+ mulw, mulf, divb, divw, divf, modw, modb, andb,
471+ andw, orb, orw, xorb, xorw, shlb, shlw, shrb,
472+ shrw, insc, indc, addc, lenc, lena, lenl, beqb,
473+ bneb, bltb, bleb, bgtb, bgeb, beqw, bnew, bltw,
474+ blew, bgtw, bgew, beqf, bnef, bltf, blef, bgtf,
475+ bgef, beqc, bnec, bltc, blec, bgtc, bgec, slicea,
476+ slicela, slicec, indw, indf, indb, negf, movl, addl,
477+ subl, divl, modl, mull, andl, orl, xorl, shll,
478+ shrl, bnel, bltl, blel, bgtl, bgel, beql, cvtlf,
479+ cvtfl, cvtlw, cvtwl, cvtlc, cvtcl, headl, consl, newcl,
480+ casec, indl, movpc, tcmp, mnewz, cvtrf, cvtfr, cvtws,
481+ cvtsw, lsrw, lsrl, eclr, newz, newaz, raise_, casel,
482+ mulx, divx, cvtxx, mulx0, divx0, cvtxx0, mulx1, divx1,
483+ cvtxx1, cvtfx, cvtxf, expw, expl, expf, self
484+ ]