History

Added basic handling of all the Dis file sections.

David Boddie committed 9 years ago

Commit d264bdd1 parent a07a3ba1 file · +213 −37Browse files

Unified · Split

dis.py+213−37
@@ -28,12 +28,11 @@ def _read(f, format): · 27 unmodified lines
2828 return unpack(format, f.read(size))[0]
2929
3030 def read_B(f):
31−
31+ # byte, 8-bit unsigned
3232 return unpack(">B", f.read(1))[0]
3333
3434 def read_OP(f):
3535
36− at = f.tell()
3736 s = f.read(1)
3837 v = unpack(">B", s)[0]
3938
@@ -62,24 +61,44 @@ def read_OP(f): · 22 unmodified lines
6261 return v
6362
6463 def read_W(f):
65−
66− return unpack(">i", f.read(4))
64+ # 32-bit word
65+ return unpack(">i", f.read(4))[0]
6766
6867 def read_F(f):
69−
70− return unpack(">d", f.read(8))
68+ # 64-bit float
69+ return unpack(">d", f.read(8))[0]
70+
71+def read_L(f):
72+ # 64-bit big integer
73+ # Signed or unsigned? Assume signed for now.
74+ return unpack(">q", f.read(8))[0]
75+
76+def read_P(f):
77+ # 32-bit pointer
78+ return unpack(">I", f.read(4))[0]
79+
80+def read_C(f):
81+ # UTF-8 encoded string
82+ s = ""
83+ while True:
84+ c = f.read(1)
85+ if c == "\x00":
86+ break
87+ s += c
88+
89+ return s
7190
7291 def read_SO(f):
7392
74− return unpack(">H", f.read(2))
93+ return unpack(">H", f.read(2))[0]
7594
7695 def read_SI(f):
7796
78− return unpack(">h", f.read(2))
97+ return unpack(">h", f.read(2))[0]
7998
8099 def read_LO(f):
81100
82− return unpack(">i", f.read(4))
101+ return unpack(">i", f.read(4))[0]
83102
84103
85104 class DisError(Exception):
@@ -130,16 +149,61 @@ class Dis: · 44 unmodified lines
130149 self.entry_type = read_OP(f)
131150
132151 self.read_code(f)
152+ self.read_types(f)
153+ self.read_data(f)
154+
155+ self.module_name = read_C(f)
156+
157+ self.read_link(f)
133158
134159 def read_code(self, f):
135160
136161 self.code = []
137−
138162 i = 0
139− while i < self.code_size:
140163
164+ while i < self.code_size:
141165 self.code.append(Instruction(f))
142166 i += 1
167+
168+ def read_types(self, f):
169+
170+ self.types = []
171+ i = 0
172+
173+ while i < self.type_size:
174+ self.types.append(Type(f))
175+ i += 1
176+
177+ def read_data(self, f):
178+
179+ self.data = []
180+
181+ while True:
182+
183+ at = f.tell()
184+
185+ code = read_B(f)
186+ if code == 0:
187+ break
188+
189+ array_type = code >> 4
190+ if not 1 <= array_type <= 8:
191+ raise self.error("Unknown type in data item at 0x%x" % at)
192+
193+ self.data.append(Data(f, code, array_type))
194+
195+ def read_link(self, f):
196+
197+ self.link = []
198+ i = 0
199+
200+ while i < self.link_size:
201+ self.link.append(Link(f))
202+ i += 1
203+
204+ def list(self):
205+
206+ print "\n".join(map(str, self.code))
143207
144208
145209 class RuntimeFlag:
@@ -165,19 +229,7 @@ class Instruction: · 19 unmodified lines
165229 self.address_mode = read_B(f)
166230
167231 middle = self.address_mode & 0xc0
168−
169− if middle == 0x40:
170− self.middle = read_OP(f)
171− self.middle_type = "$SI"
172− elif middle == 0x80:
173− self.middle = read_OP(f)
174− self.middle_type = "SO(FP)"
175− elif middle == 0xc0:
176− self.middle = read_OP(f)
177− self.middle_type = "SO(MP)"
178− else:
179− self.middle = None
180− self.middle_type = None
232+ self.middle, self.middle_type = self.read_middle_operand(middle, f)
181233
182234 source = (self.address_mode & 0x38) >> 3
183235 self.source, self.source_type = self.read_operand(source, f)
@@ -187,6 +239,9 @@ class Instruction: · 3 unmodified lines
187239
188240 def read_operand(self, operand, f):
189241
242+ # Since we shift the address flags for the source operand, we can
243+ # check both source and destination operands using the same values.
244+
190245 if operand == 0x00:
191246 operand = read_OP(f)
192247 operand_type = "LO(MP)"
@@ -208,6 +263,25 @@ class Instruction: · 15 unmodified lines
208263
209264 return operand, operand_type
210265
266+ def read_middle_operand(self, operand, f):
267+
268+ # The middle operand bits are not shifted.
269+
270+ if operand == 0x40:
271+ operand = read_OP(f)
272+ operand_type = "$SI"
273+ elif operand == 0x80:
274+ operand = read_OP(f)
275+ operand_type = "SO(FP)"
276+ elif operand == 0xc0:
277+ operand = read_OP(f)
278+ operand_type = "SO(MP)"
279+ else:
280+ operand = None
281+ operand_type = None
282+
283+ return operand, operand_type
284+
211285 def __repr__(self):
212286
213287 try:
@@ -222,17 +296,119 @@ class Instruction: · 8 unmodified lines
222296 (self.middle, self.middle_type), \
223297 (self.destination, self.destination_type):
224298
225− if optype in ["$SI", "SO(FP)", "SO(MP)"]:
226− operands.append(op)
227− comments.append(optype)
228− elif optype in ["LO(MP)", "LO(FP)", "$OP"]:
229− operands.append(op)
230− comments.append(optype)
231− elif optype in ["SO(SO(MP))", "SO(SO(FP))"]:
232− operands += list(op)
233− comments.append(optype)
234−
235− if comments:
236− return name + " " + ", ".join(map(hex, operands)) + " ; " + ", ".join(comments)
299+ if optype == "$SI":
300+ operands.append("$%s" % op)
301+ elif optype == "SO(FP)":
302+ operands.append("%i(fp)" % op)
303+ elif optype == "SO(MP)":
304+ operands.append("%i(mp)" % op)
305+ elif optype == "LO(MP)":
306+ operands.append("%i(mp)" % op)
307+ elif optype == "LO(FP)":
308+ operands.append("%i(fp)" % op)
309+ elif optype == "$OP":
310+ operands.append("$%s" % op)
311+ elif optype == "SO(SO(MP))":
312+ operands.append("%i(%i(mp))" % op)
313+ elif optype == "SO(SO(FP))":
314+ operands.append("%i(%i(fp))" % op)
315+
316+ return name + " " + ", ".join(operands)
317+
318+
319+class Type:
320+
321+ def __init__(self, f):
322+
323+ self.desc_number = read_OP(f)
324+ self.size = read_OP(f)
325+ self.number_ptrs = read_OP(f)
326+ self.array = f.read(self.number_ptrs)
327+
328+ def is_pointer(self, address):
329+
330+ # Convert the address of a word to a bit offset in the array.
331+ bit = address / 4
332+ # Extract the byte containing the bit we want to check.
333+ byte = self.array[bit / 8]
334+ # Check whether the bit is 1 or 0, returning True for 1 and False for 0.
335+ mask = 1 << (bit % 8)
336+ return (ord(byte) & mask) != 0
337+
338+
339+class Data:
340+
341+ array_types = ["Invalid", "8-bit byte", "32-bit word",
342+ "UTF-8 encoded string", "64-bit float", "Array",
343+ "Set array address", "Restore load address"]
344+
345+ def __init__(self, f, code, array_type):
346+
347+ self.code = code
348+ self.count = code & 0x0f
349+
350+ if self.count == 0:
351+ self.count = read_OP(f)
352+
353+ self.offset = read_OP(f)
354+ self.array_type = array_type
355+
356+ self.array = []
357+ base = 0
358+ i = 0
359+ while i < self.count:
360+
361+ if array_type == 1:
362+ # 8-bit byte
363+ self.array.append(read_B(f))
364+ elif array_type == 2:
365+ # 32-bit word
366+ self.array.append(read_W(f))
367+ elif array_type == 3:
368+ # UTF-8 encoded string (each item is a character)
369+ self.array.append(f.read(1))
370+ elif array_type == 4:
371+ # 64-bit float
372+ self.array.append(read_F(f))
373+ elif array_type == 5:
374+ # Array
375+ index = _read(f, ">I")
376+ length = _read(f, ">I")
377+ print "Array", index, length, self.count
378+ #self.array.append(read_F(f))
379+ elif array_type == 6:
380+ # Set array address
381+ index = _read(f, ">I")
382+ print "Set array address", index, self.count
383+ #self.array.append(read_F(f))
384+ elif array_type == 7:
385+ # Restore load address
386+ print "Restore load address"
387+ #self.array.append(read_F(f))
388+ elif array_type == 8:
389+ # 64-bit integer
390+ self.array.append(read_L(f))
391+
392+ i += 1
393+
394+ def data(self):
395+
396+ if self.array_type == 3:
397+ return "".join(self.array)
237398 else:
238− return name + " " + ", ".join(map(hex, operands))
399+ return self.array
400+
401+ def __repr__(self):
402+
403+ return "<%s.%s (%s) %s>" % (self.__module__, self.__class__.__name__,
404+ self.array_types[self.array_type], repr(self.data()))
405+
406+
407+class Link:
408+
409+ def __init__(self, f):
410+
411+ self.pc = read_OP(f)
412+ self.desc_number = read_OP(f)
413+ self.sig = read_W(f)
414+ self.name = read_C(f)