From a767188ee3c5e7206d7bd222716606934440b2e0 Mon Sep 17 00:00:00 2001 From: Wei-ju Wu Date: Sat, 8 Nov 2014 08:34:27 -0800 Subject: [PATCH] added more instructions to disassembler --- hunktools/disassemble.py | 135 +++++++++++++++++++++++++++++++-------- hunktools/hunk.py | 4 +- 2 files changed, 111 insertions(+), 28 deletions(-) diff --git a/hunktools/disassemble.py b/hunktools/disassemble.py index 74237e2..1de72a0 100644 --- a/hunktools/disassemble.py +++ b/hunktools/disassemble.py @@ -13,19 +13,43 @@ ADDR_MODES_EXT = { OPCODE_CATEGORIES = { '0000': 'bitops_movep_imm', '0001': 'move.b', '0010': 'move.l', '0011': 'move.w', - '0100': 'misc', '1101': 'add_addx' + '0100': 'misc', '1001': 'sub_subx', + '0110': 'bcc_bsr_bra', '0111': 'moveq', + '1101': 'add_addx' } -ADD_OPMODES = { - '000': ('b', 'ea+dn->dn'), '001': ('w', 'ea+dn->dn'),'010': ('l', 'ea+dn->dn'), - '100': ('b', 'dn+ea->ea'), '101': ('w', 'dn+ea->ea'),'110': ('l', 'dn+ea->ea') +ADD_SUB_OPMODES = { + '000': ('b', 'ea,dn->dn'), '001': ('w', 'ea,dn->dn'),'010': ('l', 'ea,dn->dn'), + '100': ('b', 'dn,ea->ea'), '101': ('w', 'dn,ea->ea'),'110': ('l', 'dn,ea->ea') } +SIZES = ['b', 'w', 'l'] + +CONDITION_CODES = [ + 't', 'f', 'hi', 'ls', + 'cc', 'cs', 'ne', 'eq', + 'vc', 'vs', 'pl', 'mi', + 'ge', 'lt', 'gt', 'le' +] + def is_move(category): return category in {'move.b', 'move.w', 'move.l'} +def next_word(size, data, data_offset): + if size == 'L': + value = struct.unpack('>i', data[data_offset:data_offset+4])[0] + added = 4 + elif size == 'W': + data[data_offset:data_offset+2] + value = struct.unpack('>h', data[data_offset:data_offset+2])[0] + added = 2 + else: + raise Exception('unsupported size: ', size) + return (value, added) + + def operand(size, mode_bits, reg_bits, data, offset): result = "" added = 0 @@ -36,17 +60,20 @@ def operand(size, mode_bits, reg_bits, data, offset): mode = ADDR_MODES_EXT[reg_bits] regnum = int(reg_bits, 2) if mode == '#': - data_offset = offset + 2 - if size == 'L': - imm_value = struct.unpack('>i', data[data_offset:data_offset+4])[0] - added += 4 - elif size == 'W': - data[data_offset:data_offset+2] - imm_value = struct.unpack('>h', data[data_offset:data_offset+2])[0] - added += 2 - else: - raise Exception('unsupported size: ', size) + imm_value, added = next_word(size, data, offset + 2) result = "#%d" % imm_value + elif mode in {'(xxx).L', '(xxx).W'}: # absolute + addr, added = next_word(mode[-1], data, offset + 2) + result = "%d.%s" % (addr, mode[-1]) + elif mode == '(d16,PC)': + disp16, added = next_word('W', data, offset + 2) + result = "%d(PC)" % disp16 + else: + raise Exception("unsupported ext mode: '%s'" % mode) + elif mode == '(d16,An)': + regnum = int(reg_bits, 2) + disp16, added = next_word('W', data, offset + 2) + result = "%d(A%d)" % (disp16, regnum) else: regnum = int(reg_bits, 2) result = mode.replace('n', str(regnum)) @@ -67,43 +94,97 @@ def disassemble_move(bits, data, offset): return ((category, src_op, dst_op), total_added) -def disassemble_add(bits, data, offset): +def disassemble_add_sub(name, bits, data, offset): total_added = 0 reg = "D%d" % int(bits[4:7], 2) - size, operation = ADD_OPMODES[bits[7:10]] + size, operation = ADD_SUB_OPMODES[bits[7:10]] ea, added = operand(size, bits[10:13], bits[13:16], data, offset) total_added += added - if operation == 'ea+dn->dn': + if operation == 'ea,dn->dn': src = ea dst = reg - elif operation == 'dn+ea->ea': + elif operation == 'dn,ea->ea': src = reg dst = ea else: - raise Exception('Unknown operation for add') + raise Exception('Unknown operation for %s' % name) - return (('add.%s' % size, src, dst), total_added) + return (('%s.%s' % (name, size), src, dst), total_added) +def disassemble_misc(bits, data, offset): + if bits == '0100111001110101': # rts + return (('rts', ), 0) + elif bits[7:10] == '111': # lea + regnum = int(bits[4:7], 2) + ea, added = operand('l', bits[10:13], bits[13:16], data, offset) + return (('lea', ea, 'A%d' % regnum), added) + elif bits.startswith('0100111010'): # jsr + ea, added = operand('l', bits[10:13], bits[13:16], data, offset) + return (('jsr', ea), added) + elif bits.startswith('0100111011'): # jmp + ea, added = operand('l', bits[10:13], bits[13:16], data, offset) + return (('jmp', ea), added) + elif bits.startswith('01001010'): # tst.x + size = SIZES[int(bits[8:10], 2)] + ea, added = operand('l', bits[10:13], bits[13:16], data, offset) + return (('test.%s' % size, ea), added) + else: + print("unrecognized misc: %s" % bits) + raise Exception('TODO Misc') + def disassemble(data, offset): bits = "{0:016b}".format(struct.unpack(">H", data[offset:offset+2])[0]) # first step categorize by looking at bits 15-12 opcode = bits[0:4] category = OPCODE_CATEGORIES[opcode] + added = 0 + if is_move(category): op, added = disassemble_move(bits, data, offset) - elif category == 'add_addx': - if bits[7] == 1 and bits[10:12] == '11': # addx - raise Exception('addx not supported yet') + elif category in {'add_addx', 'sub_subx'}: + if bits[7] == 1 and bits[10:12] == '11': # extended + raise Exception('addx/subx not supported yet') else: - op, added = disassemble_add(bits, data, offset) + op, added = disassemble_add_sub(category[0:3], bits, data, offset) + elif category == 'misc': + op, added = disassemble_misc(bits, data, offset) + elif category == 'moveq': + regnum = int(bits[4:7], 2) + value = int(bits[8:16], 2) + op = ('moveq', value, 'D%d' % regnum) + elif category == 'bcc_bsr_bra': + if bits[0:16] == '01100000': # bra + raise Exception('BRA TODO') + elif bits[0:16] == '01100001': # bsr + raise Exception('BSR TODO') + else: + cond = CONDITION_CODES[int(bits[4:8], 2)] + disp8 = int(bits[8:16], 2) + if disp8 == 0: + # 16 bit displacement TODO + raise Exception('16 bit branch displacement TODO') + elif disp8 == 255: + # 16 bit displacement TODO + raise Exception('16 bit branch displacement TODO') + if disp8 >= 128: + raise Exception('wrong value for signed displacement: %d', disp8) + return (('b%s' % cond, disp8), 2) else: - print("category: ", category) + print("\nUnknown instruction\nCategory: ", category, " Bits: ", bits) raise Exception('TODO') return (op, 2 + added) def print_instruction(address, op): - opcode, src, dst = op - print("$%08x:\t%8s %8s, %8s" % (address, opcode, src, dst)) + if len(op) == 3: + opcode, src, dst = op + print("$%08x:\t%8s %s,%s" % (address, opcode, src, dst)) + elif len(op) == 2: + opcode, ea = op + print("$%08x:\t%8s %s" % (address, opcode, ea)) + elif len(op) == 1: + print("$%08x:\t%8s" % (address, op[0])) + else: + raise Exception("can't print instruction with %d components" % len(op)) diff --git a/hunktools/hunk.py b/hunktools/hunk.py index 8e8036e..926123f 100755 --- a/hunktools/hunk.py +++ b/hunktools/hunk.py @@ -159,13 +159,15 @@ def parse_hunkfile(hunkfile): elif block[0] == 'BSS': print("Block %d: '%s' -> %d" % (i, block[0], block[1])) elif block[0] == 'CODE': - print("%d: '%s'" % (i, block[0])) + print("%d: '%s', size = %d" % (i, block[0], len(block[1]))) + print("----------------------------\n") code = block[1] offset = 0 while offset < len(code): op, size = disassemble(code, offset) print_instruction(offset, op) offset += size + print("\n---------------------------\n") else: print("Block %d: '%s'" % (i, block[0]))