Skip to content

Commit

Permalink
Fix compatibility with IDA 7.x and Python 3
Browse files Browse the repository at this point in the history
  • Loading branch information
leoetlino committed Jul 13, 2021
1 parent 0b90941 commit 6c3d741
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 97 deletions.
139 changes: 53 additions & 86 deletions gcdsp.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,50 +10,18 @@
repository.
"""
from idaapi import *
import os.path
from pathlib import Path

from gcdsp_opcodes import OpType
from gcdsp_generated import *

GREETINGS_STRING = """\
GC/Wii DSP processor for IDA (C) 2011 [email protected] - \
licensed under the GPLv2 license\
"""

class OpType:
"""Enumeration of the different operand encoding types which can be found
in the GC DSP ISA. From DSPTables.h in Dolphin source code."""

NONE = 0
VAL = 1
IMM = 2
MEM = 3
STR = 4
ADDR_I = 5
ADDR_D = 6

REG = 0x8000
REG04 = REG | 0x0400
REG08 = REG | 0x0800
REG18 = REG | 0x1800
REGM18 = REG18
REG19 = REG | 0x1900
REGM19 = REG19
REG1A = REG | 0x1a80
REG1C = REG | 0x1c00
ACCL = REG | 0x1c00
ACCM = REG | 0x1e00
ACCM_D = REG | 0x1e80
ACC = REG | 0x2000
ACC_D = REG | 0x2080
AX = REG | 0x2200
REGS_MASK = 0x3f80

REF = REG | 0x4000
PRG = REF | REG


# Get autogenerated parts from another file
execfile(os.path.join(os.path.dirname(__file__), 'gcdsp_generated.py'))

class Operand(object):

class Operand:
def __init__(self, type, size, loc, rshift, mask):
self.type = type
self.size = size
Expand Down Expand Up @@ -115,7 +83,7 @@ def parse(self, res, byte1, byte2):
else:
raise ValueError("unhandled type: %04X" % type)

class Instr(object):
class Instr:
def __init__(self, name, opcode, mask, size, operands=[], ext_operands=[],
stops=False, calls=False, jumps=False, shifts=False,
hll=False):
Expand Down Expand Up @@ -170,7 +138,7 @@ class GCDSPProcessor(processor_t):
instruc_start = 0

assembler = {
"flag" : ASH_HEXF3 | ASD_DECF0 | ASO_OCTF1 | ASB_BINF3 | AS_NOTAB
"flag" : ASH_HEXF3 | ASD_DECF0 | ASO_OCTF1 | ASB_BINF3
| AS_ASCIIC | AS_ASCIIZ,
"uflag": 0,
"name": "GNU assembler",
Expand Down Expand Up @@ -291,40 +259,41 @@ def _init_registers(self):
self.reg_ids[reg] = i

# Simulate fake segment registers
self.regFirstSreg = self.regCodeSreg = self.reg_ids["$CS"]
self.regLastSreg = self.regDataSreg = self.reg_ids["$DS"]
self.reg_first_sreg = self.reg_code_sreg = self.reg_ids["$CS"]
self.reg_last_sreg = self.reg_data_sreg = self.reg_ids["$DS"]


def notify_init(self, idp_file):
"""Called at module initialization."""
cvar.inf.mf = True # set to big endian... wtf
cvar.inf.wide_high_byte_first = True # big endian for 16b bytes too
cvar.inf.set_be(True)
cvar.inf.lflags |= LFLG_WIDE_HBF # big endian for 16b bytes too
return True

def notify_endbinary(self, ok):
"""Called when the binary finished loading."""
if ok:
print GREETINGS_STRING
print(GREETINGS_STRING)

def _read_cmd_byte(self):
ea = self.cmd.ea + self.cmd.size
byte = get_full_byte(ea)
self.cmd.size += 1
def _read_cmd_byte(self, cmd):
ea = cmd.ea + cmd.size
byte = get_wide_byte(ea)
cmd.size += 1
return byte

def ana(self):
"""Analyze one instruction and fill the "cmd" instance member."""
cmd = self.cmd
byte1 = self._read_cmd_byte()
def notify_ana(self, cmd):
"""Analyze one instruction and fill "cmd"."""
self.cmd = cmd
byte1 = self._read_cmd_byte(cmd)
instr = self.instrs_opcode[byte1]
if instr is None:
return 0

if instr.size == 2:
byte2 = self._read_cmd_byte()
byte2 = self._read_cmd_byte(cmd)
else:
byte2 = 0

operands = [cmd[i] for i in xrange(6)]
operands = [cmd[i] for i in range(6)]
for to_fill in operands:
to_fill.type = o_void

Expand All @@ -334,80 +303,78 @@ def ana(self):
cmd.itype = instr.id
return cmd.size

def _emu_operand(self, op):
def _emu_operand(self, cmd, op):
"""Emulated using one operand from the instruction."""
if op.type == o_mem:
ua_dodata2(0, op.addr, op.dtyp)
ua_add_dref(0, op.addr, dr_R) # TODO: dr_W ?
cmd.create_op_data(op.addr, 0, op.dtype)
cmd.add_dref(op.addr, 0, dr_R)
elif op.type == o_near:
if self.cmd.get_canon_feature() & CF_CALL:
if cmd.get_canon_feature() & CF_CALL:
fl = fl_CN
else:
fl = fl_JN
ua_add_cref(0, op.addr, fl)
cmd.add_cref(op.addr, 0, fl)

def emu(self):
def notify_emu(self, cmd):
"""Emulate instruction behavior and create x-refs, interpret operand
values, etc."""
instr = self.instrs_list[self.cmd.itype]
instr = self.instrs_list[cmd.itype]

for i in xrange(len(instr.all_operands)):
self._emu_operand(self.cmd[i])
for i in range(len(instr.all_operands)):
self._emu_operand(cmd, cmd[i])

if not instr.stops: # add a link to next instr if code continues
ua_add_cref(0, self.cmd.ea + self.cmd.size, fl_F)
cmd.add_cref(cmd.ea + cmd.size, 0, fl_F)

return True

def outop(self, op):
def notify_out_operand(self, ctx, op):
"""Generates text representation of an instruction operand."""
if op.type == o_reg:
out_register(self.reg_names[op.reg])
ctx.out_register(self.reg_names[op.reg])
elif op.type == o_phrase:
out_symbol('@')
out_register(self.reg_names[op.reg])
ctx.out_symbol('@')
ctx.out_register(self.reg_names[op.reg])
elif op.type == o_imm:
OutValue(op, OOFW_IMM)
ctx.out_value(op, OOFW_IMM)
elif op.type in [o_near, o_mem]:
ok = out_name_expr(op, op.addr, BADADDR)
ok = ctx.out_name_expr(op, op.addr, BADADDR)
if not ok:
out_tagon(COLOR_ERROR)
OutLong(op.addr, 16)
out_tagoff(COLOR_ERROR)
QueueMark(Q_noName, self.cmd.ea)
ctx.out_tagon(COLOR_ERROR)
ctx.out_long(op.addr, 16)
ctx.out_tagoff(COLOR_ERROR)
QueueMark(PR_NONAME, self.cmd.ea)
else:
return False
return True

def out(self):
def notify_out_insn(self, ctx):
"""Generates text representation of an instruction in the "cmd" inst
member."""
cmd = self.cmd

buf = init_output_buffer(1024)
OutMnem(15) # max width = 15
ctx.out_mnem(15) # max width = 15

instr = self.instrs_list[cmd.itype]

in_extended = False
for i in xrange(0, 6):
for i in range(0, 6):
if cmd[i].type == o_void:
break

if i != 0:
if not in_extended and i >= len(instr.operands):
in_extended = True
OutChar(' ')
out_symbol(':')
ctx.out_char(' ')
ctx.out_symbol(':')
else:
out_symbol(',')
OutChar(' ')
ctx.out_symbol(',')
ctx.out_char(' ')

out_one_operand(i)
ctx.out_one_operand(i)

term_output_buffer()
cvar.gl_comm = 1 # allow comments at end of line
MakeLine(buf)
ctx.flush_outbuf()

def PROCESSOR_ENTRY():
return GCDSPProcessor()
2 changes: 2 additions & 0 deletions gcdsp_generated.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#### THIS CODE WAS AUTO-GENERATED BY gen_from_tables.py ####
from gcdsp_opcodes import OpType

opcodes = [
["NOP",0x0000,0xfffc,1,0,[],False,False],
["DAR",0x0004,0xfffc,1,1,[[OpType.REG,1,0,0,0x0003]],False,False],
Expand Down
31 changes: 31 additions & 0 deletions gcdsp_opcodes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
class OpType:
"""Enumeration of the different operand encoding types which can be found
in the GC DSP ISA. From DSPTables.h in Dolphin source code."""

NONE = 0
VAL = 1
IMM = 2
MEM = 3
STR = 4
ADDR_I = 5
ADDR_D = 6

REG = 0x8000
REG04 = REG | 0x0400
REG08 = REG | 0x0800
REG18 = REG | 0x1800
REGM18 = REG18
REG19 = REG | 0x1900
REGM19 = REG19
REG1A = REG | 0x1a80
REG1C = REG | 0x1c00
ACCL = REG | 0x1c00
ACCM = REG | 0x1e00
ACCM_D = REG | 0x1e80
ACC = REG | 0x2000
ACC_D = REG | 0x2080
AX = REG | 0x2200
REGS_MASK = 0x3f80

REF = REG | 0x4000
PRG = REF | REG
23 changes: 12 additions & 11 deletions gen_from_tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def gen_from_text(text):
else:
fields = line.replace('{', '[').replace('}', ']').split(',')
fields = fields[0:3] + fields[5:-5] + [fields[-4]]
fields = map(str.strip, fields)
fields = list(map(str.strip, fields))
fields = ','.join(fields) + ']'
fields = fields.replace('true', 'True')
fields = fields.replace('false', 'False')
Expand All @@ -60,21 +60,22 @@ def gen_from_text(text):
else:
opcodes_ext.append(fields)

print 'opcodes = ['
print ' ' + ',\n '.join(opcodes)
print ']'
print
print 'opcodes_ext = ['
print ' ' + ',\n '.join(opcodes_ext)
print ']'
print('opcodes = [')
print(' ' + ',\n '.join(opcodes))
print(']')
print()
print('opcodes_ext = [')
print(' ' + ',\n '.join(opcodes_ext))
print(']')

if __name__ == '__main__':
if len(sys.argv) != 2:
print 'usage: %s /path/to/DSPTables.cpp' % sys.argv[0]
print('usage: %s /path/to/DSPTables.cpp' % sys.argv[0])
sys.exit(1)

text = open(sys.argv[1]).read()

print "#### THIS CODE WAS AUTO-GENERATED BY gen_from_tables.py ####"
print("#### THIS CODE WAS AUTO-GENERATED BY gen_from_tables.py ####")
print("from gcdsp_opcodes import OpType")
gen_from_text(text)
print "#### END AUTO-GENERATED CODE ####"
print("#### END AUTO-GENERATED CODE ####")

0 comments on commit 6c3d741

Please sign in to comment.