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
28 return unpack(format, f.read(size))[0]28 return unpack(format, f.read(size))[0]
29 29
30def read_B(f):30def read_B(f):
31 31 # byte, 8-bit unsigned
32 return unpack(">B", f.read(1))[0]32 return unpack(">B", f.read(1))[0]
33 33
34def read_OP(f):34def read_OP(f):
35 35
36 at = f.tell()
37 s = f.read(1)36 s = f.read(1)
38 v = unpack(">B", s)[0]37 v = unpack(">B", s)[0]
39 38
@@ -62,24 +61,44 @@ def read_OP(f): · 22 unmodified lines
62 return v61 return v
63 62
64def read_W(f):63def read_W(f):
65 64 # 32-bit word
66 return unpack(">i", f.read(4))65 return unpack(">i", f.read(4))[0]
67 66
68def read_F(f):67def read_F(f):
69 68 # 64-bit float
70 return unpack(">d", f.read(8))69 return unpack(">d", f.read(8))[0]
70
71def 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
76def read_P(f):
77 # 32-bit pointer
78 return unpack(">I", f.read(4))[0]
79
80def 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
71 90
72def read_SO(f):91def read_SO(f):
73 92
74 return unpack(">H", f.read(2))93 return unpack(">H", f.read(2))[0]
75 94
76def read_SI(f):95def read_SI(f):
77 96
78 return unpack(">h", f.read(2))97 return unpack(">h", f.read(2))[0]
79 98
80def read_LO(f):99def read_LO(f):
81 100
82 return unpack(">i", f.read(4))101 return unpack(">i", f.read(4))[0]
83 102
84 103
85class DisError(Exception):104class DisError(Exception):
@@ -130,16 +149,61 @@ class Dis: · 44 unmodified lines
130 self.entry_type = read_OP(f)149 self.entry_type = read_OP(f)
131 150
132 self.read_code(f)151 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)
133 158
134 def read_code(self, f):159 def read_code(self, f):
135 160
136 self.code = []161 self.code = []
137
138 i = 0162 i = 0
139 while i < self.code_size:
140 163
164 while i < self.code_size:
141 self.code.append(Instruction(f))165 self.code.append(Instruction(f))
142 i += 1166 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))
143 207
144 208
145class RuntimeFlag:209class RuntimeFlag:
@@ -165,19 +229,7 @@ class Instruction: · 19 unmodified lines
165 self.address_mode = read_B(f)229 self.address_mode = read_B(f)
166 230
167 middle = self.address_mode & 0xc0231 middle = self.address_mode & 0xc0
168 232 self.middle, self.middle_type = self.read_middle_operand(middle, f)
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
181 233
182 source = (self.address_mode & 0x38) >> 3234 source = (self.address_mode & 0x38) >> 3
183 self.source, self.source_type = self.read_operand(source, f)235 self.source, self.source_type = self.read_operand(source, f)
@@ -187,6 +239,9 @@ class Instruction: · 3 unmodified lines
187 239
188 def read_operand(self, operand, f):240 def read_operand(self, operand, f):
189 241
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
190 if operand == 0x00:245 if operand == 0x00:
191 operand = read_OP(f)246 operand = read_OP(f)
192 operand_type = "LO(MP)"247 operand_type = "LO(MP)"
@@ -208,6 +263,25 @@ class Instruction: · 15 unmodified lines
208 263
209 return operand, operand_type264 return operand, operand_type
210 265
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
211 def __repr__(self):285 def __repr__(self):
212 286
213 try:287 try:
@@ -222,17 +296,119 @@ class Instruction: · 8 unmodified lines
222 (self.middle, self.middle_type), \296 (self.middle, self.middle_type), \
223 (self.destination, self.destination_type):297 (self.destination, self.destination_type):
224 298
225 if optype in ["$SI", "SO(FP)", "SO(MP)"]:299 if optype == "$SI":
226 operands.append(op)300 operands.append("$%s" % op)
227 comments.append(optype)301 elif optype == "SO(FP)":
228 elif optype in ["LO(MP)", "LO(FP)", "$OP"]:302 operands.append("%i(fp)" % op)
229 operands.append(op)303 elif optype == "SO(MP)":
230 comments.append(optype)304 operands.append("%i(mp)" % op)
231 elif optype in ["SO(SO(MP))", "SO(SO(FP))"]:305 elif optype == "LO(MP)":
232 operands += list(op)306 operands.append("%i(mp)" % op)
233 comments.append(optype)307 elif optype == "LO(FP)":
234 308 operands.append("%i(fp)" % op)
235 if comments:309 elif optype == "$OP":
236 return name + " " + ", ".join(map(hex, operands)) + " ; " + ", ".join(comments)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
319class 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
339class 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)
237 else:398 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
407class 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)