class JumpInstruction(Instruction): def __init__(self, name, target, cond, addr, reads, writes): super(JumpInstruction, self).__init__(name, addr) self._reads = reads self._writes = writes self.cond = cond if hasattr(target, 'getAddress'): self.targetAddr = target.getAddress() self.target = target elif target.value is not None: self.targetAddr = address.fromVirtualAndCurrent(target.value, addr) self.target = ProcAddress(self.targetAddr) else: self.targetAddr = None self.target = target def optimizedWithContext(self, ctx): return JumpInstruction(self.name, self.target.optimizedWithContext(ctx), self.cond, self.addr, self._reads, self._writes) def getDependencies(self, needed): return (needed - self._writes) | self._reads def getDependencySet(self): return DependencySet(self._reads, self._writes) def hasContinue(self): try: return not self.cond.alwaysTrue() except AttributeError: return True def jumps(self): if self.targetAddr and not self.targetAddr.isAmbiguous(): return set([self.targetAddr]) else: return set() def allJumps(self): if self.targetAddr: return [self.targetAddr] else: return [] def operands(self): if not self.cond.alwaysTrue(): return [self.target, self.cond] else: return [self.target]
class CallInstruction(Instruction): def __init__(self, proj, name, target, cond, addr): super(CallInstruction, self).__init__(name, addr) # XXX: IDIOM [CALL HL] if hasattr(target, 'value') and target.value == 0x00A0: target = placeholders.HL # XXX: IDIOM [CALL BC] if hasattr(target, 'value') and target.value == 0x0CDA: target = placeholders.BC # XXX: IDIOM [CALL LONG E:HL] if hasattr(target, 'value') and target.value == 0x008A: target = ComputedProcAddress(placeholders.E, placeholders.HL) self.cond = cond if hasattr(target, 'getAddress'): self.targetAddr = target.getAddress() self.target = ProcAddress(self.targetAddr) elif hasattr(target, 'value') and target.value is not None: self.targetAddr = address.fromVirtualAndCurrent(target.value, addr) self.target = ProcAddress(self.targetAddr) else: self.targetAddr = address.fromVirtual(0x4000) # XXX: ambiguous address self.target = target self.target_depset = proj.database.procInfo(self.targetAddr).depset self.returns_used = ALL_REGS self.constant_params = dict() def getDependencies(self, needed): #return flow.getProcDeps(self.targetAddr, needed) deps = self.getDependencySet() return (needed - deps.writes) | deps.reads def getDependencySet(self): reads = set(self.target_depset.reads) for r in joinRegisters(reads): if r in self.constant_params: reads -= splitRegister(r) return DependencySet(reads, self.target_depset.writes) def optimizeDependencies(self, needed): self.returns_used = needed & self.getDependencySet().writes return self def optimizedWithContext(self, ctx): self.target = self.target.optimizedWithContext(ctx) if hasattr(self.target, 'getAddress'): self.targetAddr = self.target.getAddress() elif hasattr(self.target, 'value') and self.target.value is not None: self.targetAddr = address.fromVirtualAndCurrent(self.target.value, self.addr) self.target = ProcAddress(self.targetAddr) else: pass # XXX deps = self.getDependencySet() ins = joinRegisters(deps.reads - set(['mem'])) for param in ins: if ctx.hasConstantValue(param): self.constant_params[param] = ctx.getValue(param) for w in deps.writes: ctx.setValueComplex(w) # TODO: XXX if self.targetAddr.virtual() == 0x07B9: if 'A' in self.constant_params: ctx.setValue('ROMBANK', self.constant_params['A']) return self def calls(self): if self.targetAddr.inPhysicalMem() and not self.targetAddr.isAmbiguous(): return set([self.targetAddr]) else: return set([]) def operands(self): if not self.cond.alwaysTrue(): return [self.target, self.cond] else: return [self.target] def fillParamIfKnown(self, param): if param in self.constant_params: return param + '=' + str(self.constant_params[param]) else: return param def signature(self): x = '' if not self.cond.alwaysTrue(): x = 'CONDITIONAL' depset = self.getDependencySet().onlyRegisters() ins = joinRegisters(depset.reads - set(['mem'])) outs = joinRegisters(self.returns_used - set(['mem'])) ins |= set(param+'='+str(self.constant_params[param]) for param in self.constant_params) ins = ', '.join(sorted(ins)) outs = ', '.join(sorted(outs)) if ins: ins = ' @ (' + ins + ')' if not outs: outs = 'void' return x + ins + ' -> ' + outs