264 lines
7.6 KiB
C++
264 lines
7.6 KiB
C++
// $Id: emu.cpp,v 1.6 2000/11/06 22:11:16 jeremy Exp $
|
|
//
|
|
// Copyright (c) 2000 Jeremy Cooper. All rights reserved.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions
|
|
// are met:
|
|
//
|
|
// 1. Redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
// 2. Redistributions in binary form must reproduce the above copyright
|
|
// notice, this list of conditions and the following disclaimer in the
|
|
// documentation and/or other materials provided with the distribution.
|
|
// 3. All advertising materials mentioning features or use of this software
|
|
// must display the following acknowledgement:
|
|
// This product includes software developed by Jeremy Cooper.
|
|
// 4. The name of the author may not be used to endorse or promote products
|
|
// derived from this software without specific prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
//
|
|
// TMS320C1X Processor module
|
|
// Instruction emulation.
|
|
//
|
|
#include "../idaidp.hpp"
|
|
#include <segregs.hpp>
|
|
|
|
#include "tms320c1.hpp"
|
|
#include "ins.hpp"
|
|
#include "reg.hpp"
|
|
|
|
int tms320c1_t::emu(const insn_t &insn) const
|
|
{
|
|
//
|
|
// Determine the current instruction's features.
|
|
//
|
|
int features = insn.get_canon_feature(ph);
|
|
bool flow = (features & CF_STOP) == 0;
|
|
|
|
//
|
|
// Examine each operand and determine what effect, if any,
|
|
// it makes on the environment.
|
|
//
|
|
// Operands that are read
|
|
if ( features & CF_USE1 )
|
|
flow &= handle_operand(insn, insn.Op1, hop_READ);
|
|
if ( features & CF_USE2 )
|
|
flow &= handle_operand(insn, insn.Op2, hop_READ);
|
|
if ( features & CF_USE3 )
|
|
flow &= handle_operand(insn, insn.Op3, hop_READ);
|
|
// Operands that are written
|
|
if ( features & CF_CHG1 )
|
|
flow &= handle_operand(insn, insn.Op1, hop_WRITE);
|
|
if ( features & CF_CHG2 )
|
|
flow &= handle_operand(insn, insn.Op2, hop_WRITE);
|
|
if ( features & CF_CHG3 )
|
|
flow &= handle_operand(insn, insn.Op3, hop_WRITE);
|
|
|
|
//
|
|
// Determine whether the instruction stops the execution flow.
|
|
//
|
|
if ( flow )
|
|
{
|
|
//
|
|
// This instruction doesn't stop execution flow.
|
|
// Add a cross reference to the next instrction.
|
|
//
|
|
add_cref(insn.ea, insn.ea+insn.size, fl_F);
|
|
}
|
|
|
|
//
|
|
// If the instruction makes a branch, let the IDA kernel
|
|
// know.
|
|
//
|
|
if ( features & CF_JUMP )
|
|
remember_problem(PR_JUMP, insn.ea);
|
|
|
|
return 1;
|
|
}
|
|
|
|
bool tms320c1_t::handle_operand(const insn_t &insn, const op_t &op, opRefType ref_type) const
|
|
{
|
|
ea_t ea;
|
|
sel_t data_selector;
|
|
bool flow = true;
|
|
|
|
switch ( op.type )
|
|
{
|
|
case o_reg:
|
|
//
|
|
// Register operand.
|
|
//
|
|
//
|
|
// Nothing needs to be calculated or examined for this
|
|
// operand.
|
|
//
|
|
break;
|
|
case o_imm:
|
|
//
|
|
// Immediate operand.
|
|
//
|
|
// Make sure that this operand reference isn't a write reference.
|
|
// (Writing to an immediate value is not allowed and is a sure
|
|
// sign of a badly decoded instruction).
|
|
//
|
|
if ( ref_type == hop_WRITE )
|
|
{
|
|
//
|
|
// Attempt to write to an immediate value.
|
|
// Error.
|
|
//
|
|
warning("%a: %s,%d: bad optype %d", insn.ea, insn.get_canon_mnem(ph), op.n, op.type);
|
|
break;
|
|
}
|
|
//
|
|
// SPECIAL INSTRUCTION CASE:
|
|
//
|
|
// The LDPK instruction is decoded by ana() to have an immediate
|
|
// value as an operand. However, this immediate value is to be
|
|
// the new data page pointer, which we must track for proper
|
|
// memory referencing.
|
|
//
|
|
if ( insn.itype == I_LDPK )
|
|
{
|
|
//
|
|
// This is an LDPK instruction. Let the kernel know that
|
|
// we are changing the current data page pointer. We track
|
|
// this bit as though it were a virtual segment register named
|
|
// I_VDS, although it is not a true register in the CPU.
|
|
//
|
|
// Determine into which data page the instruction is attempting
|
|
// to point.
|
|
//
|
|
if ( op.value == 0 )
|
|
{
|
|
//
|
|
// Data page 0 is being loaded.
|
|
//
|
|
data_selector = tms320c1x_dpage0;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Data page 1 is being loaded.
|
|
//
|
|
data_selector = tms320c1x_dpage1;
|
|
}
|
|
//
|
|
// Notify the IDA kernel of the change.
|
|
//
|
|
split_sreg_range(
|
|
insn.ea, // The current instruction's address
|
|
IREG_VDS, // The segment register being modified
|
|
data_selector, // The new selector value being loaded
|
|
SR_auto); // How the new value was determined
|
|
}
|
|
//
|
|
// Let the kernel know that the instruction's address should
|
|
// be marked with a 'has immediate value' flag.
|
|
// (Useful during search?)
|
|
//
|
|
set_immd(insn.ea);
|
|
break;
|
|
case o_phrase:
|
|
//
|
|
// Processor-specific phrase.
|
|
//
|
|
// These operands have no currently trackable side effect.
|
|
//
|
|
break;
|
|
case o_mem:
|
|
//
|
|
// Direct memory reference.
|
|
//
|
|
|
|
//
|
|
// Ask the IDA kernel for the current data page pointer selector.
|
|
//
|
|
data_selector = get_sreg(insn.ea, IREG_VDS);
|
|
|
|
//
|
|
// Is it known?
|
|
//
|
|
if ( data_selector == BADSEL )
|
|
{
|
|
//
|
|
// The current data page pointer is unknown.
|
|
// There is nothing to do.
|
|
//
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The current data page pointer is known.
|
|
// Calculate the full effective address being referenced
|
|
// by this operand.
|
|
//
|
|
ea = sel2ea(data_selector) + op.addr;
|
|
|
|
//
|
|
// Generate a data cross reference from this instruction
|
|
// to the target address.
|
|
//
|
|
insn.add_dref(ea, op.offb, ref_type == hop_READ ? dr_R : dr_W);
|
|
}
|
|
|
|
//
|
|
// TODO: DMOV, ...
|
|
// These instructions read from the address in their operands
|
|
// and write to the address ADJACENT to it.
|
|
//
|
|
break;
|
|
case o_near:
|
|
//
|
|
// Code reference in current segment.
|
|
//
|
|
//
|
|
// Determine the effective address of the reference.
|
|
//
|
|
ea = to_ea(insn.cs, op.addr);
|
|
|
|
//
|
|
// Is this a 'CALL' type reference, or a branch type reference?
|
|
//
|
|
if ( has_insn_feature(insn.itype, CF_CALL) )
|
|
{
|
|
//
|
|
// This is a CALL type reference. Make a cross reference
|
|
// that notes it.
|
|
//
|
|
insn.add_cref(ea, op.offb, fl_CN);
|
|
if ( !func_does_return(ea) )
|
|
flow = false;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This is a branch type reference. Make a cross reference
|
|
// that notes it.
|
|
//
|
|
insn.add_cref(ea, op.offb, fl_JN);
|
|
}
|
|
break;
|
|
default:
|
|
//
|
|
// Unhandled operand type.
|
|
// Error.
|
|
//
|
|
warning("%a: %s,%d: bad optype %d", insn.ea, insn.get_canon_mnem(ph), op.n, op.type);
|
|
break;
|
|
}
|
|
return flow;
|
|
}
|