Files
2021-10-31 21:20:46 +02:00

331 lines
10 KiB
C++

// $Id: idp.cpp,v 1.9 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.
// IDP module entry structure
//
#include "../idaidp.hpp"
#include "tms320c1.hpp"
#include "ana.hpp"
#include "reg.hpp"
#include "out.hpp"
#include "ins.hpp"
#include "asms.hpp"
//----------------------------------------------------------------------
// This old-style callback only returns the processor module object.
static ssize_t idaapi notify(void *, int msgid, va_list)
{
if ( msgid == processor_t::ev_get_procmod )
return size_t(new tms320c1_t);
return 0;
}
//
// This function is the entry point that is called to notify the processor
// module of an important event.
//
ssize_t idaapi tms320c1_t::on_event(ssize_t msgid, va_list va)
{
int code = 1;
switch ( msgid )
{
case processor_t::ev_init:
//
// Initialize the processor module.
//
tms320c1x_Init();
break;
case processor_t::ev_newfile:
//
// Prepare for decoding of the file that has just been
// loaded.
//
tms320c1x_NewFile();
break;
case processor_t::ev_out_header:
{
outctx_t *ctx = va_arg(va, outctx_t *);
outHeader(*ctx);
return 1;
}
case processor_t::ev_out_footer:
{
outctx_t *ctx = va_arg(va, outctx_t *);
outFooter(*ctx);
return 1;
}
case processor_t::ev_out_segstart:
{
outctx_t *ctx = va_arg(va, outctx_t *);
segment_t *seg = va_arg(va, segment_t *);
outSegStart(*ctx, seg);
return 1;
}
case processor_t::ev_ana_insn:
{
insn_t *out_ins = va_arg(va, insn_t *);
return ana(out_ins);
}
case processor_t::ev_emu_insn:
{
const insn_t *insn = va_arg(va, const insn_t *);
return emu(*insn) ? 1 : -1;
}
case processor_t::ev_out_insn:
{
outctx_t *ctx = va_arg(va, outctx_t *);
out_insn(*ctx);
return 1;
}
case processor_t::ev_out_operand:
{
outctx_t *ctx = va_arg(va, outctx_t *);
const op_t *op = va_arg(va, const op_t *);
return out_opnd(*ctx, *op) ? 1 : -1;
}
default:
code = 0;
break;
}
return code;
}
//
// tms320c1x_Init()
//
// Initialize the processor module.
//
// (Called from on_event()).
//
void tms320c1_t::tms320c1x_Init() const
{
//
// Have the IDA kernel interpret the data within the virtual
// address space in a big-endian manner.
//
inf_set_be(true);
}
//
// tms320c1x_NewFile()
//
// Make any preparations needed to interpret the file that has
// just been loaded.
//
// (Called from on_event()).
//
void tms320c1_t::tms320c1x_NewFile()
{
ea_t data_start;
segment_t dpage0, dpage1;
//
// There are no known executable file formats for TMS320C1X executables.
// Therefore, we will assume in this processor module that the user
// has loaded a program ROM image into IDA. This image lacks any
// definitions for data RAM, so we must create an area in IDA's virtual
// address space to represent this RAM, thus enabling us to make
// and track cross-references made to data RAM by TMS320C1X instructions.
//
// The TMS320C1X accesses data RAM in two discrete ways, the first of
// which has a major impact on the strategy we must use to represent
// data RAM.
//
// The first kind of access occurs during the execution of instructions
// with immediate address operands. The 7-bit immediate address operand
// is combined with the current data page pointer bit in the processor
// status register to give an 8-bit final address. We will simulate this
// behavior by keeping track of the data page pointer bit from instruction
// to instruction, in effect acting as though it were a segment register.
// We will then treat the 7-bit immediate address operand in each
// instruction as though it were an offset into one of two data RAM
// segments, depending on the current value of the data page pointer bit.
// To do this, we need to create and define those two data segments here.
//
// The second manner in which the TMS320C1X access data RAM is during the
// execution of instructions with indirect address operands. An indirect
// address operand is one which identifies a location in data RAM
// indirectly through the current value in one of the accumulator or
// auxiliary registers. These memory references are fully qualified
// since all three of these registers are spacious enough to hold all
// 8-bits of addressing information. Therefore, we needn't do anything
// special here to accomodate these instructions.
//
//
// Find a suitable place in IDA's virtual address space to place
// the TMS320C1X's data RAM. Make sure it is aligned on a 16 byte
// boundary.
//
data_start = free_chunk(0, TMS320C1X_DATA_RAM_SIZE, 15);
////
//// Create the first data segment, otherwise known as 'data page 0'.
////
//
// Define its start and ending virtual address.
//
dpage0.start_ea = data_start;
dpage0.end_ea = data_start + (TMS320C1X_DATA_RAM_SIZE / 2);
//
// Assign it a unique selector value.
//
dpage0.sel = allocate_selector(dpage0.start_ea >> 4);
//
// Let the kernel know that it is a DATA segment.
//
dpage0.type = SEG_DATA;
//
// Create the segment in the address space.
//
add_segm_ex(&dpage0, "dp0", NULL, ADDSEG_OR_DIE);
////
//// Create the second data segment, otherwise known as 'data page 1'.
////
//
// Define its start and ending virtual address.
//
dpage1.start_ea = data_start + (TMS320C1X_DATA_RAM_SIZE / 2);
dpage1.end_ea = data_start + TMS320C1X_DATA_RAM_SIZE;
//
// Assign it a unique selector value.
//
dpage1.sel = allocate_selector(dpage1.start_ea >> 4);
//
// Let the kernel know that it is a DATA segment.
//
dpage1.type = SEG_DATA;
//
// Create the segment in the address space.
//
add_segm_ex(&dpage1, "dp1", NULL, ADDSEG_OR_DIE);
//
// Store the selectors of these two data segments in the global
// variables tms320c1x_dpage0 and tms320c1x_dpage1.
//
tms320c1x_dpage0 = dpage0.sel;
tms320c1x_dpage1 = dpage1.sel;
}
//
// Short supported processor names.
//
// [ This array is named in our processor_t.psnames member ]
//
static const char *const shnames[] =
{
"tms320c1x",
NULL
};
//
// Descriptive supported processor names.
//
// [ This array is named in our processor_t.plnames member ]
//
#define FAMILY "TMS320C1X Series:"
static const char *const lnames[] =
{
FAMILY"Texas Instruments TMS320C1X DSP",
NULL
};
//
// Array of opcode streams that represent a function return
// instruction.
//
// [ This array is named in our processor_t.retcodes member ]
//
const bytes_t tms320c1x_retCodes[] =
{
{ 0, 0 }
};
//////////////////////////////////////////////////////////////////////////////
// PROCESSOR MODULE DEFINITION
//////////////////////////////////////////////////////////////////////////////
processor_t LPH =
{
IDP_INTERFACE_VERSION,// version
PLFM_TMS320C1X, // id
// flag
//
// processor module capablilty flags:
//
PR_RNAMESOK // A register name can be used to name a location
| PR_BINMEM // The module creates segments for binary files
| PR_SEGS, // We'd like to use the segment register tracking
// features of IDA.
// flag2
0,
//
16, // Bits in a byte for code segments
16, // Bits in a byte for other segments
shnames, // Array of short processor names
// the short names are used to specify the processor
// with the -p command line switch)
lnames, // array of long processor names
// the long names are used to build the processor
// selection menu type
tms320c1x_Assemblers, // array of target assemblers
notify, // Callback function for kernel event notification
registerNames, // Regsiter names
nregisterNames, // Number of registers
IREG_VCS, // First segment-register number
IREG_VDS, // Last segment-register number
1, // size of a segment register
IREG_VCS, // CS segment-register number
IREG_VDS, // DS segment-register number
NULL, // Known code start sequences
tms320c1x_retCodes, // Known return opcodes
I__FIRST, // First instruction number
I__LAST, // Last instruction number
Instructions, // instruc
};