// $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 #include "emu.hpp" #include "ins.hpp" #include "reg.hpp" #include "idp.hpp" // // Reference type. Used between emu() and handle_operand() to // flag whether an operand is written to or read from. // enum opRefType { hop_READ, hop_WRITE, }; void handle_operand(op_t &, enum opRefType); int emu(void) { int features; // // Determine the current instruction's features. // features = Instructions[cmd.itype].feature; // // Determine whether the instruction stops the execution flow. // if (features & CF_STOP) { // // This instruction stops execution flow. // Do nothing special. // } else { // // This instruction doesn't stop execution flow. // Add a cross reference to the next instrction. // ua_add_cref(0,cmd.ea+cmd.size,fl_F); } // // Examine each operand and determine what effect, if any, // it makes on the environment. // // Operands that are read if (features & CF_USE1) handle_operand(cmd.Op1, hop_READ); if (features & CF_USE2) handle_operand(cmd.Op2, hop_READ); if (features & CF_USE3) handle_operand(cmd.Op3, hop_READ); // Operands that are written if (features & CF_CHG1) handle_operand(cmd.Op1, hop_WRITE); if (features & CF_CHG2) handle_operand(cmd.Op2, hop_WRITE); if (features & CF_CHG3) handle_operand(cmd.Op3, hop_WRITE); // // If the instruction makes a branch, let the IDA kernel // know. // if (features & CF_JUMP) QueueMark(Q_jumps, cmd.ea); return 1; } void handle_operand(op_t &op, enum opRefType ref_type) { ea_t ea; sel_t data_selector; 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( "%08lX (%s): bad optype", cmd.ea, Instructions[cmd.itype].name ); 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 (cmd.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. // splitSRarea1( cmd.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?) // doImmd(cmd.ea); // // Refresh the current address flags global cache value since // we have probably changed the instruction's flags in the previous // statement. // uFlag = getFlags(cmd.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 = getSR(cmd.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. // ua_add_dref(op.offb, ea, 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 = toEA(cmd.cs, op.addr); // // Is this a 'CALL' type reference, or a branch type reference? // if (InstrIsSet(cmd.itype, CF_CALL)) { // // This is a CALL type reference. Make a cross reference // that notes it. // ua_add_cref(op.offb, ea, fl_CN); } else { // // This is a branch type reference. Make a cross reference // that notes it. // ua_add_cref(op.offb, ea, fl_JN); } break; default: // // Unhandled operand type. // Error. // warning("%08lX (%s): bad optype", cmd.ea, Instructions[cmd.itype].name); break; } }