def fmt_op(arg, mnem, op=None): '''op_ty -> str -> opt:int -> c_ast()''' insn = insns.insns[mnem] def addrof_or_deref(arg): # since addiu cannot touch memory, it must be calculating an address if mnem == 'addiu' or (insn.ty == insns.types.usefn and insn.subst == 'memcpy'): return c_ast.UnaryOp('&', arg) else: return arg if arg.ty == ida.op_ty.reg: try: slot = insn.slots[op] except IndexError: slot = None reg = fmt_reg(mnem, arg.val, slot) if insn.ty == insns.types.usefn and insn.subst == 'memcpy': return c_ast.UnaryOp('&', reg) else: return reg if mnem == 'la': # XXX the "name" type is neither suitable for a decompiler nor a # braindead static translator such as this one. i.e., in order to # translate to C, we have no choice but to deal with C's type system, # because things like "la ptr" should be translated as "reg = ptr", but # "la not_ptr" should be translated as "reg = ¬_ptr" if arg.ty in [ida.op_ty.array, ida.op_ty.ptr]: return c_ast.ID(arg.val) elif arg.ty == ida.op_ty.name: return c_ast.UnaryOp('&', c_ast.ID(arg.val)) else: # an address return c_ast.Constant('int', str(arg.val)) elif arg.ty == ida.op_ty.array: (idx, rem) = ida.item_off(arg.target) arr = c_ast.ArrayRef(c_ast.ID(arg.val), c_ast.Constant('int', str(idx))) return addrof_or_deref(arr) # retained in case we ever come across some strange pointer math. this # will generate a nonsense lvalue anyway, so we'd need to handle it some # other way # left = addrof_or_deref(arr) #return c_ast.BinaryOp('+', left, c_ast.Constant('int', str(rem))) elif arg.ty == ida.op_ty.ptr: # dereferencing of pointers is handled by the "displ" case, so just # return an address here too (_, rem) = ida.item_off(arg.target) return c_ast.ID(arg.val) # same as above # return c_ast.BinaryOp('+', # c_ast.ID(arg.val), # c_ast.Constant('int', str(rem))) elif arg.ty == ida.op_ty.name: nameval = c_ast.ID(arg.val) return addrof_or_deref(nameval) elif arg.ty == ida.op_ty.displ: r = fmt_reg(mnem, arg.val.reg, ep_ct.slot_types.u32) off = c_ast.BinaryOp('+', r, c_ast.Constant('int', str(arg.val.displ))) tyns = ['char' if insns.types.usefn and insn.subst == 'memcpy' else insn.subst] cast = ep_ct.simple_cast(ep_ct.ptr(ep_ct.simple_typename(tyns)), off) if insn.ty == insns.types.usefn and insn.subst == 'memcpy': return cast else: return c_ast.UnaryOp('*', cast) else: return c_ast.Constant('int', str(arg.val))
def do_lui(**kw): # {rt} = {op} << 16 return ep_ct.do_assign(rt=kw['rt'], op=ep_ct.simple_cast( ep_ct.slot_to_typename[kw['result']], c_ast.BinaryOp('<<', kw['op'], c_ast.Constant('int', '16'))))
def fmt_reg_for_call(reg, slot, node): '''reg -> slot_ty -> c_ast -> c_ast''' reg_ast = fmt_reg(mnem, reg, slot) return ep_ct.simple_cast(node, reg_ast)
def cast(which): return ep_ct.simple_cast(ep_ct.simple_typename([kw['subst']]), which)