def extract_procedures(code_file): result = {} procedure_pc, procedure, in_procedure = 0, [], 0 while True: opcode_str = code_file.read(4) if len(opcode_str) != 4: break # >L is for big-endian files. Use <L for little-endian files. opcode = struct.unpack('>L', opcode_str)[0] if in_procedure: pc = code_file.tell() - 4 op = mips.disassemble(pc, opcode) if isinstance(op, mips.JR) and op.s == 31: # JR $31 = return from procedure. We're about to finish! # We just need to get the delay slot, so 1 instruction is # left. procedure.append(op) in_procedure = 1 elif len(procedure) > 16384 or isinstance(op, mips.Unknown): # We are probably parsing data that happened to look like # a procedure. Just ignore it. procedure, in_procedure = [], 0 elif in_procedure == 1: # We've got the delay slot of the JR $31. We're finished! procedure.append(op) result[procedure_pc] = procedure procedure, in_procedure = [], 0 else: procedure.append(op) else: # This checks for 'ADDIU $29, $29, <negative 4-byte-aligned>'. # That's a stack adjustment. Until now we haven't parsed # opcodes because we were probably in data, but we now need to # parse them, as a procedure is starting! if opcode & 0xFFFF8003 == 0x27BD8000: procedure_pc = pc = code_file.tell() - 4 op = mips.disassemble(pc, opcode) procedure, in_procedure = [op], 2 return result
# This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. import sys, mips def simplify_notice(string): print "Simplification in %s" % (string) mips.simplify_notice = simplify_notice if __name__ == '__main__': for line in sys.stdin: if line.startswith('BLOCK '): print "-- Trace --" colon_tokens = [token.strip() for token in line[6:].split(':')] pc = int(colon_tokens[0], 16) mips_opcodes = [int(op_str, 16) for op_str in colon_tokens[1].split(' ')] mips_ops = [mips.disassemble(pc + n * 4, mips_opcode) for n, mips_opcode in enumerate(mips_opcodes)] int_state = mips.IntState() for n in xrange(len(mips_ops)): mips_op = mips_ops[n].simplify() print mips_op.as_string() mips_ops[n] = simplified_op = mips_op.update_int_state(int_state) if simplified_op is not mips_op: print "%s= %s" % (" " * 8, simplified_op.as_string(pc=False))
endian = '>L' # >L is for big-endian files, <L for little-endian files. if len(sys.argv) >= 3: if sys.argv[2] == 'little': endian = '<L' procedure, procedure_pc, in_procedure = [], 0, 0 with open(sys.argv[1], 'rb') as code_file: procedure_pc, procedure, in_procedure = 0, [], 0 while True: opcode_str = code_file.read(4) if len(opcode_str) != 4: break # >L is for big-endian files. Use <L for little-endian files. opcode = struct.unpack(endian, opcode_str)[0] if in_procedure: pc = code_file.tell() - 4 op = mips.disassemble(pc, opcode) if isinstance(op, mips.JR) and op.s == 31: # JR $31 = return from procedure. We're about to finish! # We just need to get the delay slot, so 1 instruction is # left. procedure.append(op) in_procedure = 1 elif len(procedure) > 16384 or isinstance(op, mips.Unknown): # We are probably parsing data that happened to look like # a procedure. Just ignore it. procedure, in_procedure = [], 0 elif in_procedure == 1: # We've got the delay slot of the JR $31. We're finished! procedure.append(op) is_boundary = get_block_boundaries(procedure) procedure = optimize(procedure, is_boundary)