// $Id: out.cpp,v 1.7 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. // // IDA TMS320C1X processor module. // Instruction display routines // #include "../idaidp.hpp" #include #include "ins.hpp" #include "out.hpp" #include "reg.hpp" // // outSegStart() // // [ This function is named in our processor_t.segstart member ] // // Generate assembly text before the start of a segment. // void idaapi outSegStart(outctx_t &ctx, segment_t *) { ctx.gen_cmt_line("A segment starts here."); } // // outSegEnd() // // [ This function is named in our processor_t.segend member ] // // Generate assembly text after the end of a segment. // void idaapi outSegEnd(outctx_t &ctx, segment_t *) { ctx.gen_cmt_line("A segment ends here."); } // // outHeader() // // [ This function is named in our processor_t.header member ] // // Generate an assembly header for the top of the file. // void idaapi outHeader(outctx_t &ctx) { ctx.gen_header(GH_PRINT_PROC_AND_ASM); } // // outFooter() // // [ This function is named in our processor_t.footer member ] // // Generate an assembly footer for the bottom of the file. // void idaapi outFooter(outctx_t &ctx) { ctx.gen_cmt_line("End of file"); } //////////////////////////////////////////////////////////////////////////// // // DISASSEMBLY OPERAND HELPER FUNCTIONS // //////////////////////////////////////////////////////////////////////////// DECLARE_OUT_FUNCS_WITHOUT_OUTMNEM(out_tms320c1_t) // // outPhrase(phrase) // Output a TMS320C1X-specific operand phrase. // void out_tms320c1_t::outPhrase(int phrase) { // // Complex phrase operand. // (Processor specific) // switch ( phrase ) { case IPH_AR: // // Current address register, indirect. // out_symbol('*'); break; case IPH_AR_INCR: // // Current address register, indirect, post-increment. // out_symbol('*'); out_symbol('+'); break; case IPH_AR_DECR: // // Current address register, indirect, post-decrement. // out_symbol('*'); out_symbol('-'); break; } } // // outNear(operand) // // Display an operand that is known to reference another piece of // of code. // void out_tms320c1_t::outNear(const op_t &op) { // // Calculate the effective address of this code reference. // ea_t ea = to_ea(insn.cs, op.addr); // // Find or create a name for the code address that this operand // references so that we can output that name in the operand's // place. // if ( !out_name_expr(op, ea, op.addr) ) // // The code address didn't have a name. Default to // displaying the address as a number. // out_value(op, OOF_ADDR | OOF_NUMBER | OOFS_NOSIGN); // // Let the user know that he or she should look at this // instruction and attempt to name the address that it // references. // remember_problem(PR_NONAME, insn.ea); } // // outNear(operand) // // Display an operand that is known to reference data RAM. // void out_tms320c1_t::outMem(const op_t &op) { // // Ask the IDA kernel for the value of the current data page // pointer for execution of this instruction. // sel_t data_selector = get_sreg(insn.ea, IREG_VDS); // // Is it known? // if ( data_selector == BADSEL ) { // // The current data page pointer is not known. // // // Display the current operand as a regular number and // return. // out_value(op, OOF_ADDR); return; } // // The current data page pointer is known. Use it to calculate the // effective address of the memory being referenced by this // operand. // ea_t ea = sel2ea(data_selector) + op.addr; // // Find or create a name for the data address that this operand // references so that we can output that name in the operand's // place. // if ( !out_name_expr(op, ea, op.addr) ) { // // No name was found and no name was created. // Display the current operand as a regular number. // out_value(op, OOF_ADDR); // // Let the user know that he or she should look at this // instruction and attempt to name the address that it // references. // remember_problem(PR_NONAME, insn.ea); } } bool out_tms320c1_t::out_operand(const op_t &op) { switch ( op.type ) { case o_reg: // // Register operand. // outreg(op.reg); break; case o_phrase: // // Complex phrase. // (Processor specific) // outPhrase(op.phrase); break; case o_imm: // // Immediate value. // out_value(op, 0); break; case o_near: // // Code reference. // outNear(op); break; case o_mem: // // Data memory reference. // outMem(op); break; default: break; } return 1; } void out_tms320c1_t::out_insn() { // // An unseen parameter to this function is the 'insn' structure // which holds all the information about the instruction that we // are being asked to display. // // This call to out_mnemonic() is a helper function in the IDA kernel that // displays an instruction mnemonic for the current instruction. // It does so by taking the integer value in insn.itype and using it // as an index into the array that we named in this processor module's // processor_t.instruc member. From this indexed element comes the // instruction mnemonic to be displayed. // out_mnemonic(); // // If the current instruction has a non-empty first operand, // then display it. // if ( insn.Op1.type != o_void ) { // // This call to out_one_operand() is another IDA kernel function that // is mandatory for a properly behaved processor module. // // Normally, this helper function turns around and calls the function // named in our processor_t.u_outop member with a reference to // the current instruction's operand numbered in the first argument. // However, if through the course of interacting with the // disassembly the user chooses to manually override the specified // operand in this instruction, the IDA kernel will forego the call // to u_outop() -- instead calling an internal IDA routine to // display the user's manually entered operand. // out_one_operand(0); } // // Display the second operand, if non-empty. // if ( insn.Op2.type != o_void ) { // // This call to out_symbol() is another helper function in the // IDA kernel. It writes the specified character to the current // buffer, using the user-configurable 'symbol' color. // out_symbol(','); out_char(' '); out_one_operand(1); } // // Finally, display the third operand, if non-empty. // if ( insn.Op3.type != o_void ) { out_symbol(','); out_char(' '); out_one_operand(2); } // // Tell IDA to display our constructed line. // flush_outbuf(); }