This commit is contained in:
olari
2021-06-05 21:10:25 +03:00
parent 807cffd9de
commit e0e0f2be99
923 changed files with 911857 additions and 15 deletions

1083
idasdk75/module/i51/ana.cpp Normal file

File diff suppressed because it is too large Load Diff

255
idasdk75/module/i51/emu.cpp Normal file
View File

@@ -0,0 +1,255 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-98 by Ilfak Guilfanov.
* ALL RIGHTS RESERVED.
* E-mail: ig@estar.msk.su, ig@datarescue.com
* FIDO: 2:5020/209
*
*/
#include "i51.hpp"
#include <frame.hpp>
//------------------------------------------------------------------------
// Handle an operand with an immediate value:
// - mark it with FF_IMMD flag
// - for bit logical instructions specify the operand type as a number
// because such an operand is likely a plain number rather than
// an offset or of another type.
static flags_t set_immd_bit(const insn_t &insn, flags_t F)
{
if ( !has_immd(F) )
{
set_immd(insn.ea);
F = get_flags(insn.ea);
}
switch ( insn.itype )
{
case I51_anl:
case I51_orl:
case I51_xrl:
if ( !is_defarg1(F) )
{
op_num(insn.ea, 1);
F = get_flags(insn.ea);
}
break;
}
return F;
}
//----------------------------------------------------------------------
void i51_t::attach_bit_comment(const insn_t &insn, ea_t addr, int bit)
{
const ioport_bit_t *predef = find_bit(addr, bit);
if ( predef != NULL && get_cmt(NULL, insn.ea, false) <= 0 )
set_cmt(insn.ea, predef->cmt.c_str(), false);
}
//----------------------------------------------------------------------
// Calculate the target data address
ea_t i51_t::i51_map_data_ea(const insn_t &insn, ea_t addr, int opnum) const
{
if ( is_off(get_flags(insn.ea), opnum) )
return get_offbase(insn.ea, opnum) >> 4;
return ((addr >= 0x80 && addr < 0x100) ? sfrmem : intmem) + addr;
}
//----------------------------------------------------------------------
// Handle an operand. What this function usually does:
// - creates cross-references from the operand
// (the kernel deletes all xrefs before calling emu())
// - creates permanent comments
// - if possible, specifies the operand type (for example, it may
// create stack variables)
// - anything else you might need to emulate or trace
void i51_t::handle_operand(const insn_t &insn, const op_t &x, bool loading)
{
ea_t addr = x.addr;
flags_t F = get_flags(insn.ea);
switch ( x.type )
{
case o_phrase: // no special hanlding for these types
case o_reg:
break;
case o_imm: // an immediate number as an operand
if ( !loading )
goto BAD_LOGIC; // this can't happen!
F = set_immd_bit(insn, F); // handle immediate number
// if the value was converted to an offset, then create a data xref:
if ( op_adds_xrefs(F, x.n) )
insn.add_off_drefs(x, dr_O, OOFS_IFSIGN);
break;
case o_displ:
F = set_immd_bit(insn, F); // handle immediate number
// if the value was converted to an offset, then create a data xref:
if ( op_adds_xrefs(F, x.n) )
insn.add_off_drefs(x, loading?dr_R:dr_W, OOFS_IFSIGN|OOF_ADDR);
break;
case o_bit: // 8051 specific operand types - bits
case o_bitnot:
addr = (x.reg & 0xF8);
if ( (addr & 0x80) == 0 )
addr = addr/8 + 0x20;
attach_bit_comment(insn, addr, x.reg & 7); // attach a comment if necessary
goto MEM_XREF;
case o_bit251:
attach_bit_comment(insn, addr, x.b251_bit);
/* no break */
case o_mem: // an ordinary memory data reference
MEM_XREF:
{
ea_t dea = i51_map_data_ea(insn, addr, x.n);
insn.create_op_data(dea, x);
insn.add_dref(dea, x.offb, loading ? dr_R : dr_W);
}
break;
case o_near: // a code reference
{
ea_t ea = map_code_ea(insn, x);
int iscall = has_insn_feature(insn.itype, CF_CALL);
insn.add_cref(ea, x.offb, iscall ? fl_CN : fl_JN);
if ( flow && iscall )
flow = func_does_return(ea);
}
break;
default:
BAD_LOGIC:
warning("%a: %s,%d: bad optype %d", insn.ea, insn.get_canon_mnem(ph), x.n, x.type);
break;
}
}
//----------------------------------------------------------------------
static void add_stkpnt(const insn_t &insn, sval_t v)
{
if ( !may_trace_sp() )
return;
func_t *pfn = get_func(insn.ea);
if ( pfn == NULL )
return;
add_auto_stkpnt(pfn, insn.ea+insn.size, v);
}
//----------------------------------------------------------------------
// Emulate an instruction
// This function should:
// - create all xrefs from the instruction
// - perform any additional analysis of the instruction/program
// and convert the instruction operands, create comments, etc.
// - create stack variables
// - analyze the delayed branches and similar constructs
// The kernel calls ana() before calling emu(), so you may be sure that
// the 'cmd' structure contains a valid and up-to-date information.
// You are not allowed to modify the 'cmd' structure.
// Upon entering this function, the 'uFlag' variable contains the flags of
// insn.ea. If you change the characteristics of the current instruction, you
// are required to refresh 'uFlag'.
// Usually the kernel calls emu() with consecutive addresses in insn.ea but
// you can't rely on this - for example, if the user asks to analyze an
// instruction at arbirary address, his request will be handled immediately,
// thus breaking the normal sequence of emulation.
// If you need to analyze the surroundings of the current instruction, you
// are allowed to save the contents of the 'cmd' structure and call ana().
// For example, this is a very common pattern:
// {
// insn_t saved = cmd;
// if ( decode_prev_insn(&cmd, insn.ea) != BADADDR )
// {
// ....
// }
// cmd = saved;
// }
//
// This sample emu() function is a very simple emulation engine.
int i51_t::emu(const insn_t &insn)
{
flags_t F = get_flags(insn.ea);
uint32 Feature = insn.get_canon_feature(ph);
flow = ((Feature & CF_STOP) == 0);
// you may emulate selected instructions with a greater care:
switch ( insn.itype )
{
case I51_mov:
if ( insn.Op1.type == o_mem && insn.Op1.addr == 0x81 ) // mov SP, #num
{
if ( insn.Op2.type == o_imm && !is_defarg(F,1) )
{
ea_t base = intmem;
if ( base == BADADDR )
base = calc_offset_base(insn.ea, 1);
if ( base != BADADDR )
op_plain_offset(insn.ea, 1, base); // convert it to an offset
}
}
break;
case I51_trap:
add_cref(insn.ea, 0x7B, fl_CN);
break;
case I51_pop:
add_stkpnt(insn, 1);
break;
case I51_push:
add_stkpnt(insn, -1);
break;
}
if ( Feature & CF_USE1 ) handle_operand(insn, insn.Op1, true);
if ( Feature & CF_USE2 ) handle_operand(insn, insn.Op2, true);
if ( Feature & CF_USE3 ) handle_operand(insn, insn.Op3, true);
if ( Feature & CF_JUMP )
remember_problem(PR_JUMP, insn.ea);
if ( Feature & CF_CHG1 ) handle_operand(insn, insn.Op1, false);
if ( Feature & CF_CHG2 ) handle_operand(insn, insn.Op2, false);
if ( Feature & CF_CHG3 ) handle_operand(insn, insn.Op3, false);
// if the execution flow is not stopped here, then create
// a xref to the next instruction.
// Thus we plan to analyze the next instruction.
if ( flow )
add_cref(insn.ea, insn.ea+insn.size, fl_F);
return 1; // actually the return value is unimportant, but let's it be so
}
//-------------------------------------------------------------------------
// reason meaning:
// 1: the instruction has no code refs to it.
// ida just tries to convert unexplored bytes
// to an instruction (but there is no other
// reason to convert them into an instruction)
// 0: the instruction is created because
// of some coderef, user request or another
// weighty reason.
bool is_sane_insn(const insn_t &insn, int reason)
{
if ( reason != 0 )
{
switch ( insn.itype )
{
case I51_mov:
if ( get_byte(insn.ea) == 0xFF )
return false;
break;
}
}
return true;
}

17356
idasdk75/module/i51/i51.cfg Normal file

File diff suppressed because it is too large Load Diff

160
idasdk75/module/i51/i51.hpp Normal file
View File

@@ -0,0 +1,160 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-98 by Ilfak Guilfanov.
* ALL RIGHTS RESERVED.
* E-mail: ig@estar.msk.su, ig@datarescue.com
* FIDO: 2:5020/209
*
*/
#ifndef _I51_HPP
#define _I51_HPP
#include "../idaidp.hpp"
#include "ins.hpp"
#include <diskio.hpp>
#include "../iohandler.hpp"
//------------------------------------------------------------------
enum processor_subtype_t
{
// odd types are binary mode
// even types are source modes
prc_51 = 0, // plain 8051
prc_251_bin, // 80251 in binary mode
prc_251 = prc_251_bin, // the same... (a shortcut)
prc_251_src, // 80251 in source mode
prc_930_bin, // 8x930 in source mode
prc_930 = prc_930_bin, // the same... (a shortcut)
prc_930_src, // 8x930 in source mode
prc_51mx,
};
//------------------------------------------------------------------------
// customization of the 'cmd' structure:
// 8051 bit references:
#define o_bit o_idpspec0
#define o_bitnot o_idpspec1
// fRi indirect register number (for o_phrase):
#define indreg specflag1
// displacement is an immediate number (print #) (for o_displ):
#define imm_disp specflag1
// 80251 bit references (bit address in x.addr):
#define o_bit251 o_idpspec2
#define b251_bit specflag1 // bit number
#define b251_bitneg specflag2 // negate?
// cmd.auxpref bits:
#define aux_0ext 0x0001 // high bit 0-extension immediate value
#define aux_1ext 0x0002 // high bit 1-extension immediate value
// ash.uflag bit meanings:
#define UAS_PSAM 0x0001 // PseudoSam: use funny form of
// equ for intmem
#define UAS_SECT 0x0002 // Segments are named .SECTION
#define UAS_NOSEG 0x0004 // No 'segment' directives
#define UAS_NOBIT 0x0008 // No bit.# names, use bit_#
#define UAS_SELSG 0x0010 // Segment should be selected by its name
#define UAS_EQCLN 0x0020 // ':' in EQU directives
#define UAS_AUBIT 0x0040 // Don't use BIT directives -
// assembler generates bit names itself
#define UAS_CDSEG 0x0080 // Only DSEG,CSEG,XSEG
#define UAS_NODS 0x0100 // No .DS directives in Code segment
#define UAS_NOENS 0x0200 // don't specify start addr in the .end directive
#define UAS_PBIT 0x0400 // assembler knows about predefined bits
#define UAS_PBYTNODEF 0x0800 // do not define predefined byte names
//------------------------------------------------------------------------
// Registers
enum i51_registers
{
rAcc, rAB, rB,
rR0, rR1, rR2, rR3, rR4, rR5, rR6, rR7,
rR8, rR9, r10, r11, rR12, rR13, rR14, rR15,
rWR0, rWR2, rWR4, rWR6, rWR8, rWR10, rWR12, rWR14,
rWR16, rWR18, rWR20, rWR22, rWR24, rWR26, rWR28, rWR30,
rDR0, rDR4, rDR8, rDR12, rDR16, rDR20, rDR24, rDR28,
rDR32, rDR36, rDR40, rDR44, rDR48, rDR52, rDR56, rDR60,
rDptr, rC, rPC,
rEptr, rPR0, rPR1, // 51mx registers
rVcs, rVds // these 2 registers are required by the IDA kernel
};
// Indirect addressing modes without a displacement:
enum i51_phrases
{
fR0, // @R0
fR1, // @R1
fDptr, // @DPTR
fAdptr, // @A+DPTR
fApc, // @A+PC
fRi, // @WRj or @DRj, reg number in indreg
fEptr, // @EPTR
fAeptr, // @A+EPTR
fPr0, // @PR0
fPr1, // @PR1
};
//------------------------------------------------------------------------
bool is_sane_insn(const insn_t &insn, int reason);
//------------------------------------------------------------------
struct i51_iohandler_t : public iohandler_t
{
struct i51_t &pm;
i51_iohandler_t(i51_t &_pm, netnode &nn) : iohandler_t(nn), pm(_pm) {}
virtual void apply_io_port(ea_t ea, const char *name, const char *cmt) override;
virtual void get_cfg_filename(char *buf, size_t bufsize) override;
virtual bool segment_created(ea_t /*start*/, ea_t /*end*/, const char * /*name*/, const char * /*aclass*/) override;
};
DECLARE_PROC_LISTENER(idb_listener_t, struct i51_t);
struct i51_t : public procmod_t
{
netnode helper;
i51_iohandler_t ioh = i51_iohandler_t(*this, helper);
idb_listener_t idb_listener = idb_listener_t(*this);
processor_subtype_t ptype = prc_51;
ea_t intmem = 0; // address of the internal memory
ea_t sfrmem = 0; // address of SFR memory
bool flow = false;
bool first_time = true;
virtual ssize_t idaapi on_event(ssize_t msgid, va_list va) override;
const char *set_idp_options(
const char *keyword,
int /*value_type*/,
const void * /*value*/,
bool /*idb_loaded*/);
const ioport_bit_t *find_bit(ea_t address, int bit);
bool IsPredefined(const char *name);
ea_t AdditionalSegment(size_t size, size_t offset, const char *name) const;
uint32 truncate(uval_t addr) const;
int ana_extended(insn_t &insn);
void attach_bit_comment(const insn_t &insn, ea_t addr, int bit);
void setup_data_segment_pointers(void);
void i51_header(outctx_t &ctx);
int out_equ(outctx_t &ctx);
void i51_data(outctx_t &ctx, bool analyze_only);
ea_t i51_map_data_ea(const insn_t &insn, ea_t addr, int opnum) const;
void handle_operand(const insn_t &insn, const op_t &x, bool loading);
int emu(const insn_t &insn);
int ana_basic(insn_t &insn);
int ana(insn_t *_insn);
void i51_segstart(outctx_t &ctx, segment_t *Sarea) const;
void i51_footer(outctx_t &ctx) const;
void do_out_equ(outctx_t &ctx, const char *name, const char *equ, uchar off) const;
};
#endif

View File

@@ -0,0 +1,89 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-98 by Ilfak Guilfanov.
* ALL RIGHTS RESERVED.
* E-mail: ig@estar.msk.su, ig@datarescue.com
* FIDO: 2:5020/209
*
*/
#include "i51.hpp"
const instruc_t Instructions[] =
{
{ "", 0 }, // Unknown Operation
{ "acall", CF_USE1|CF_CALL }, // Absolute Call
{ "add", CF_USE1|CF_USE2|CF_CHG1 }, // Add Second Operand to Acc
{ "addc", CF_USE1|CF_USE2|CF_CHG1 }, // Add Second Operand to Acc with carry
{ "ajmp", CF_USE1|CF_STOP }, // Absolute Jump
{ "anl", CF_USE1|CF_USE2|CF_CHG1 }, // Logical AND (op1 &= op2)
{ "cjne", CF_USE1|CF_USE2|CF_USE3 }, // Compare Operands and JNE
{ "clr", CF_CHG1 }, // Clear Operand (0)
{ "cpl", CF_USE1|CF_CHG1 }, // Complement Operand
{ "da", CF_USE1|CF_CHG1 }, // Decimal Adjust Accumulator
{ "dec", CF_USE1|CF_CHG1 }, // Decrement Operand
{ "div", CF_USE1|CF_CHG1 }, // Divide Acc by B
{ "djnz", CF_USE1|CF_CHG1|CF_USE2 }, // Decrement Operand and JNZ
{ "inc", CF_USE1|CF_CHG1 }, // Increment Operand
{ "jb", CF_USE1|CF_USE2 }, // Jump if Bit is set
{ "jbc", CF_USE1|CF_USE2 }, // Jump if Bit is set & clear Bit
{ "jc", CF_USE1 }, // Jump if Carry is set
{ "jmp", CF_USE1|CF_STOP|CF_JUMP }, // Jump indirect relative to Data Pointer
{ "jnb", CF_USE1|CF_USE2 }, // Jump if Bit is clear
{ "jnc", CF_USE1 }, // Jump if Carry is clear
{ "jnz", CF_USE1 }, // Jump if Acc is not zero
{ "jz", CF_USE1 }, // Jump if Acc is zero
{ "lcall", CF_USE1|CF_CALL }, // Long Subroutine Call
{ "ljmp", CF_USE1|CF_STOP }, // Long Jump
{ "mov", CF_CHG1|CF_USE2 }, // Move (Op1 <- Op2)
{ "movc", CF_CHG1|CF_USE2 }, // Move code byte relative to second op to Acc
{ "movx", CF_CHG1|CF_USE2 }, // Move from/to external RAM
{ "mul", CF_USE1|CF_CHG1 }, // Multiply Acc by B
{ "nop", 0 }, // No operation
{ "orl", CF_USE1|CF_USE2|CF_CHG1 }, // Logical OR (op1 |= op2)
{ "pop", CF_CHG1 }, // Pop from Stack and put in Direct RAM
{ "push", CF_USE1 }, // Push from Direct RAM to Stack
{ "ret", CF_STOP }, // Return from subroutine
{ "reti", CF_STOP }, // Return from Interrupt
{ "rl", CF_USE1|CF_CHG1 }, // Rotate Acc left
{ "rlc", CF_USE1|CF_CHG1 }, // Rotate Acc left through Carry
{ "rr", CF_USE1|CF_CHG1 }, // Rotate Acc right
{ "rrc", CF_USE1|CF_CHG1 }, // Rotate Acc right through Carry
{ "setb", CF_CHG1 }, // Set Direct Bit
{ "sjmp", CF_USE1|CF_STOP }, // Short jump
{ "subb", CF_USE1|CF_USE2|CF_CHG1 }, // Subtract Second Operand from Acc with Borrow
{ "swap", CF_USE1|CF_CHG1 }, // Swap nibbles of Acc
{ "xch", CF_USE1|CF_CHG1|CF_USE2|CF_CHG2 }, // Exchange Operands
{ "xchd", CF_USE1|CF_CHG1|CF_USE2|CF_CHG2 }, // Exchange Digit in Acc with Indirect RAM
{ "xrl", CF_USE1|CF_USE2|CF_CHG1 }, // Exclusive OR (op1 ^= op2)
// 80251 instructions
{ "jsle", CF_USE1 }, // Jump if less than or equal (signed)
{ "jsg", CF_USE1 }, // Jump if greater than (signed)
{ "jle", CF_USE1 }, // Jump if less than or equal
{ "jg", CF_USE1 }, // Jump if greater than
{ "jsl", CF_USE1 }, // Jump if less than (signed)
{ "jsge", CF_USE1 }, // Jump if greater than or equal (signed)
{ "je", CF_USE1 }, // Jump if equal
{ "jne", CF_USE1 }, // Jump if not equal
{ "trap", 0 }, // Trap
{ "ejmp", CF_USE1|CF_STOP }, // Extended jump
{ "ecall", CF_USE1|CF_CALL }, // Extended call
{ "eret", CF_STOP }, // Extended return
{ "movh", CF_CHG1|CF_USE2 }, // Move immediate 16-bit data to the high word of a dword (double-word) register
{ "movz", CF_CHG1|CF_USE2 }, // Move 8-bit register to 16-bit register with zero extension
{ "movs", CF_CHG1|CF_USE2 }, // Move 8-bit register to 16-bit register with sign extension
{ "srl", CF_CHG1 }, // Shift logical right by 1 bit
{ "sra", CF_CHG1 }, // Shift arithmetic right by 1 bit
{ "sll", CF_CHG1 }, // Shift logical left by 1 bit
{ "sub", CF_CHG1|CF_USE2 }, // Subtract
{ "cmp", CF_USE1|CF_USE2 }, // Compare
// 51mx instructions
{ "emov", CF_CHG1|CF_USE2 }, // Move (Op1 <- Op2)
};
CASSERT(qnumber(Instructions) == I51_last);

View File

@@ -0,0 +1,92 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2020 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef __INSTRS_HPP
#define __INSTRS_HPP
extern const instruc_t Instructions[];
enum nameNum ENUM_SIZE(uint8)
{
I51_null = 0, // Unknown Operation
I51_acall, // Absolute Call
I51_add, // Add Second Operand to Acc
I51_addc, // Add Second Operand to Acc with carry
I51_ajmp, // Absolute Jump
I51_anl, // Logical AND (op1 &= op2)
I51_cjne, // Compare Operands and JNE
I51_clr, // Clear Operand (0)
I51_cpl, // Complement Operand
I51_da, // Decimal Adjust Accumulator
I51_dec, // Decrement Operand
I51_div, // Divide Acc by B
I51_djnz, // Decrement Operand and JNZ
I51_inc, // Increment Operand
I51_jb, // Jump if Bit is set
I51_jbc, // Jump if Bit is set & clear Bit
I51_jc, // Jump if Carry is set
I51_jmp, // Jump indirect relative to Data Pointer
I51_jnb, // Jump if Bit is clear
I51_jnc, // Jump if Carry is clear
I51_jnz, // Jump if Acc is not zero
I51_jz, // Jump if Acc is zero
I51_lcall, // Long Subroutine Call
I51_ljmp, // Long Jump
I51_mov, // Move (Op1 <- Op2)
I51_movc, // Move code byte relative to second op to Acc
I51_movx, // Move from/to external RAM
I51_mul, // Multiply Acc by B
I51_nop, // No operation
I51_orl, // Logical OR (op1 |= op2)
I51_pop, // Pop from Stack and put in Direct RAM
I51_push, // Push from Direct RAM to Stack
I51_ret, // Return from subroutine
I51_reti, // Return from Interrupt
I51_rl, // Rotate Acc left
I51_rlc, // Rotate Acc left through Carry
I51_rr, // Rotate Acc right
I51_rrc, // Rotate Acc right through Carry
I51_setb, // Set Direct Bit
I51_sjmp, // Short jump
I51_subb, // Subtract Second Operand from Acc with Borrow
I51_swap, // Swap nibbles of Acc
I51_xch, // Exchange Operands
I51_xchd, // Exchange Digit in Acc with Indirect RAM
I51_xrl, // Exclusive OR (op1 ^= op2)
// 80251 instructions
I51_jsle, // Jump if less than or equal (signed)
I51_jsg, // Jump if greater than (signed)
I51_jle, // Jump if less than or equal
I51_jg, // Jump if greater than
I51_jsl, // Jump if less than (signed)
I51_jsge, // Jump if greater than or equal (signed)
I51_je, // Jump if equal
I51_jne, // Jump if not equal
I51_trap, // Trap
I51_ejmp, // Extended jump
I51_ecall, // Extended call
I51_eret, // Extended return
I51_movh, // Move immediate 16-bit data to the high word of a dword (double-word) register
I51_movz, // Move 8-bit register to 16-bit register with zero extension
I51_movs, // Move 8-bit register to 16-bit register with sign extension
I51_srl, // Shift logical right by 1 bit
I51_sra, // Shift arithmetic right by 1 bit
I51_sll, // Shift logical left by 1 bit
I51_sub, // Subtract
I51_cmp, // Compare
// 51mx instructions
I51_emov, // Move (A <- @PRi+disp) or (@PRi+disp <- A)
I51_last,
};
#endif

View File

@@ -0,0 +1,46 @@
PROC=i51
CONFIGS=i51.cfg
include ../module.mak
# MAKEDEP dependency list ------------------
$(F)ana$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp $(I)fpro.h \
$(I)funcs.hpp $(I)ida.hpp $(I)idp.hpp $(I)kernwin.hpp \
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
$(I)name.hpp $(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
$(I)problems.hpp $(I)range.hpp $(I)segment.hpp \
$(I)ua.hpp $(I)xref.hpp ../idaidp.hpp ../iohandler.hpp \
ana.cpp i51.hpp ins.hpp
$(F)emu$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp $(I)fpro.h \
$(I)frame.hpp $(I)funcs.hpp $(I)ida.hpp $(I)idp.hpp \
$(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
$(I)loader.hpp $(I)nalt.hpp $(I)name.hpp $(I)netnode.hpp \
$(I)offset.hpp $(I)pro.h $(I)problems.hpp $(I)range.hpp \
$(I)segment.hpp $(I)ua.hpp $(I)xref.hpp ../idaidp.hpp \
../iohandler.hpp emu.cpp i51.hpp ins.hpp
$(F)ins$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp $(I)fpro.h \
$(I)funcs.hpp $(I)ida.hpp $(I)idp.hpp $(I)kernwin.hpp \
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
$(I)name.hpp $(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
$(I)problems.hpp $(I)range.hpp $(I)segment.hpp \
$(I)ua.hpp $(I)xref.hpp ../idaidp.hpp ../iohandler.hpp \
i51.hpp ins.cpp ins.hpp
$(F)out$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp $(I)fpro.h \
$(I)funcs.hpp $(I)ida.hpp $(I)idp.hpp $(I)kernwin.hpp \
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
$(I)name.hpp $(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
$(I)problems.hpp $(I)range.hpp $(I)segment.hpp \
$(I)ua.hpp $(I)xref.hpp ../idaidp.hpp ../iohandler.hpp \
i51.hpp ins.hpp out.cpp
$(F)reg$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp $(I)fpro.h \
$(I)funcs.hpp $(I)ida.hpp $(I)idp.hpp $(I)kernwin.hpp \
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
$(I)name.hpp $(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
$(I)problems.hpp $(I)range.hpp $(I)segment.hpp \
$(I)segregs.hpp $(I)ua.hpp $(I)xref.hpp ../idaidp.hpp \
../iohandler.hpp i51.hpp ins.hpp reg.cpp

415
idasdk75/module/i51/out.cpp Normal file
View File

@@ -0,0 +1,415 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-98 by Ilfak Guilfanov.
* ALL RIGHTS RESERVED.
* E-mail: ig@estar.msk.su, ig@datarescue.com
* FIDO: 2:5020/209
*
*/
#include "i51.hpp"
#include <fpro.h>
#include <diskio.hpp>
//----------------------------------------------------------------------
AS_PRINTF(1, 0) static void vlog(const char *format, va_list va)
{
static FILE *fp = NULL;
if ( fp == NULL )
fp = fopenWT("debug_log");
qvfprintf(fp, format, va);
qflush(fp);
}
//----------------------------------------------------------------------
AS_PRINTF(1, 2) inline void log(const char *format, ...)
{
va_list va;
va_start(va, format);
vlog(format, va);
va_end(va);
}
#define AT COLSTR("@", SCOLOR_SYMBOL)
#define PLUS COLSTR("+", SCOLOR_SYMBOL)
static const char *const phrases[] =
{
AT COLSTR("R0", SCOLOR_REG),
AT COLSTR("R1", SCOLOR_REG),
AT COLSTR("DPTR", SCOLOR_REG),
AT COLSTR("A", SCOLOR_REG) PLUS COLSTR("DPTR", SCOLOR_REG),
AT COLSTR("A", SCOLOR_REG) PLUS COLSTR("PC", SCOLOR_REG),
AT COLSTR("WR", SCOLOR_REG),
AT COLSTR("EPTR", SCOLOR_REG),
AT COLSTR("A", SCOLOR_REG) PLUS COLSTR("EPTR", SCOLOR_REG),
AT COLSTR("PR0", SCOLOR_REG),
AT COLSTR("PR1", SCOLOR_REG),
};
//----------------------------------------------------------------------
class out_i51_t : public outctx_t
{
out_i51_t(void) = delete; // not used
public:
void OutReg(int rgnum) { out_register(ph.reg_names[rgnum]); }
bool out_operand(const op_t &x);
void out_insn(void);
};
CASSERT(sizeof(out_i51_t) == sizeof(outctx_t));
DECLARE_OUT_FUNCS_WITHOUT_OUTMNEM(out_i51_t)
//----------------------------------------------------------------------
// generate the text representation of an operand
bool out_i51_t::out_operand(const op_t &x)
{
i51_t &pm = *static_cast<i51_t *>(procmod);
uval_t v;
int dir, bit;
qstring qbuf;
switch ( x.type )
{
case o_reg:
OutReg(x.reg);
break;
case o_phrase:
if ( x.reg == fRi )
{
out_symbol('@');
OutReg(x.indreg);
}
else
{
out_colored_register_line(phrases[x.phrase]);
}
if ( x.imm_disp )
{
out_symbol('+');
out_symbol('#');
out_value(x, OOFS_IFSIGN | OOFW_IMM);
}
break;
case o_displ:
out_symbol('@');
OutReg(x.reg);
out_symbol('+');
out_value(x, OOF_ADDR | OOFS_IFSIGN | OOFW_16);
break;
case o_imm:
out_symbol('#');
if ( insn.auxpref & aux_0ext )
out_symbol('0');
if ( insn.auxpref & aux_1ext )
out_symbol('1');
out_value(x, OOFS_IFSIGN | OOFW_IMM);
break;
case o_mem:
case o_near:
v = x.type == o_near
? map_code_ea(insn, x)
: pm.i51_map_data_ea(insn, x.addr, x.n);
if ( get_name_expr(&qbuf, insn.ea+x.offb, x.n, v, x.addr) <= 0 )
{
/* int nbit;
if ( insn.itype == I51_ecall || insn.itype == I51_ejmp )
nbit = OOFW_32;
else
nbit = OOFW_16;*/
out_value(x, OOF_ADDR | OOF_NUMBER | OOFS_NOSIGN | OOFW_32);
remember_problem(PR_NONAME, insn.ea);
break;
}
// we want to output SFR register names always in COLOR_REG,
// so remove the color tags and output it manually:
if ( x.type == o_mem && x.addr >= 0x80 )
{
tag_remove(&qbuf);
out_register(qbuf.begin());
break;
}
out_line(qbuf.begin());
break;
case o_void:
return false;
case o_bit251:
if ( x.b251_bitneg )
out_symbol('/');
dir = (int)x.addr;
bit = x.b251_bit;
goto OUTBIT;
case o_bitnot:
out_symbol('/');
// fallthrough
case o_bit:
dir = (x.reg & 0xF8);
bit = x.reg & 7;
if ( (dir & 0x80) == 0 )
dir = dir/8 + 0x20;
OUTBIT:
v = pm.i51_map_data_ea(insn, dir, x.n);
out_addr_tag(v);
if ( ash.uflag & UAS_PBIT )
{
const ioport_bit_t *predef = pm.find_bit(dir, bit);
if ( predef != NULL )
{
out_line(predef->name.c_str(), COLOR_REG);
break;
}
}
{
ssize_t len = get_name_expr(&qbuf, insn.ea+x.offb, x.n, v, dir);
if ( len > 0 && strchr(qbuf.begin(), '+') == NULL )
{
// we want to output the bit names always in COLOR_REG,
// so remove the color tags and output it manually:
if ( dir < 0x80 )
{
out_line(qbuf.begin());
}
else
{
tag_remove(&qbuf);
out_register(qbuf.begin());
}
}
else
{
out_long(dir, 16);
}
out_symbol(ash.uflag & UAS_NOBIT ? '_' : '.');
out_symbol(char('0'+bit));
}
break;
default:
warning("out: %a: bad optype %d",insn.ea,x.type);
break;
}
return true;
}
//----------------------------------------------------------------------
// generate a text representation of an instruction
// the information about the instruction is in the 'cmd' structure
void out_i51_t::out_insn(void)
{
out_mnemonic();
out_one_operand(0); // output the first operand
if ( insn.Op2.type != o_void )
{
out_symbol(',');
out_char(' ');
out_one_operand(1); // output the second operand
}
if ( insn.Op3.type != o_void )
{
out_symbol(',');
out_char(' ');
out_one_operand(2); // output the third operand
}
// output a character representation of the immediate values
// embedded in the instruction as comments
out_immchar_cmts();
flush_outbuf();
}
//--------------------------------------------------------------------------
// generate start of the disassembly
void i51_t::i51_header(outctx_t &ctx)
{
ctx.gen_header(GH_PRINT_ALL, ioh.device.c_str(), ioh.deviceparams.c_str());
}
//--------------------------------------------------------------------------
// generate start of a segment
//lint -esym(1764, ctx) could be made const
//lint -esym(818, Sarea) could be made const
void i51_t::i51_segstart(outctx_t &ctx, segment_t *Sarea) const
{
char buf[MAXSTR];
qstring name;
get_visible_segm_name(&name, Sarea);
if ( ash.uflag & UAS_SECT )
{
if ( Sarea->type == SEG_IMEM )
ctx.flush_buf(".RSECT", DEFAULT_INDENT);
else
ctx.gen_printf(0, COLSTR("%s: .section", SCOLOR_ASMDIR), name.c_str());
}
else
{
if ( ash.uflag & UAS_NOSEG )
ctx.gen_printf(DEFAULT_INDENT, COLSTR("%s.segment %s", SCOLOR_AUTOCMT), ash.cmnt, name.c_str());
else
ctx.gen_printf(DEFAULT_INDENT, COLSTR("segment %s",SCOLOR_ASMDIR), name.c_str());
if ( ash.uflag & UAS_SELSG )
ctx.flush_buf(name.c_str(), DEFAULT_INDENT);
if ( ash.uflag & UAS_CDSEG )
ctx.flush_buf(Sarea->type == SEG_IMEM
? COLSTR("DSEG", SCOLOR_ASMDIR)
: COLSTR("CSEG", SCOLOR_ASMDIR),
DEFAULT_INDENT);
// XSEG - eXternal memory
}
if ( (inf_get_outflags() & OFLG_GEN_ORG) != 0 )
{
adiff_t org = ctx.insn_ea - get_segm_base(Sarea);
if ( org != 0 )
{
btoa(buf, sizeof(buf), org);
ctx.gen_cmt_line("%s %s", ash.origin, buf);
}
}
}
//--------------------------------------------------------------------------
// generate end of the disassembly
void i51_t::i51_footer(outctx_t &ctx) const
{
if ( ash.end != NULL )
{
ctx.gen_empty_line();
ctx.out_line(ash.end, COLOR_ASMDIR);
qstring name;
if ( get_colored_name(&name, inf_get_start_ea()) > 0 )
{
ctx.out_char(' ');
if ( ash.uflag & UAS_NOENS )
ctx.out_line(ash.cmnt);
ctx.out_line(name.begin());
}
ctx.flush_outbuf(DEFAULT_INDENT);
}
else
{
ctx.gen_cmt_line("end of file");
}
}
//--------------------------------------------------------------------------
// output one "equ" directive
void i51_t::do_out_equ(outctx_t &ctx, const char *name, const char *equ, uchar off) const
{
if ( ash.uflag & UAS_PSAM )
{
ctx.out_line(equ, COLOR_KEYWORD);
ctx.out_char(' ');
ctx.out_line(name);
ctx.out_symbol(',');
}
else
{
ctx.out_line(name);
if ( ash.uflag & UAS_EQCLN )
ctx.out_symbol(':');
ctx.out_char(' ');
ctx.out_line(equ, COLOR_KEYWORD);
ctx.out_char(' ');
}
ctx.out_long(off, 16);
ctx.clr_gen_label();
ctx.flush_outbuf(0x80000000);
}
//--------------------------------------------------------------------------
int i51_t::out_equ(outctx_t &ctx)
{
ea_t ea = ctx.insn_ea;
segment_t *s = getseg(ea);
if ( s != NULL && s->type == SEG_IMEM && ash.a_equ != NULL )
{
qstring name = get_visible_name(ea);
if ( !name.empty()
&& ((ash.uflag & UAS_PBYTNODEF) == 0 || !IsPredefined(name.begin())) )
{
get_colored_name(&name, ea);
uchar off = uchar(ea - get_segm_base(s));
do_out_equ(ctx, name.begin(), ash.a_equ, off);
if ( (ash.uflag & UAS_AUBIT) == 0 && (off & 0xF8) == off )
{
ctx.out_tagon(COLOR_SYMBOL);
ctx.out_char(ash.uflag & UAS_NOBIT ? '_' : '.');
qstring pfx = ctx.outbuf;
for ( int i=0; i < 8; i++ )
{
ctx.outbuf = pfx;
const ioport_bit_t *b = find_bit(off, i);
if ( b == NULL || b->name.empty() )
ctx.out_char('0' + i);
else
ctx.out_line(b->name.c_str(), COLOR_HIDNAME);
ctx.out_tagoff(COLOR_SYMBOL);
qstring full = name + ctx.outbuf;
ctx.outbuf.qclear();
do_out_equ(ctx, full.begin(), ash.a_equ, uchar(off+i));
}
ctx.gen_empty_line();
}
}
else
{
ctx.clr_gen_label();
ctx.flush_buf("");
}
return 1;
}
if ( (ash.uflag & UAS_NODS) != 0 )
{
if ( s != NULL && !is_loaded(ea) && s->type == SEG_CODE )
{
char buf[MAX_NUMBUF];
adiff_t org = ea - get_segm_base(s) + get_item_size(ea);
btoa(buf, sizeof(buf), org);
ctx.gen_printf(DEFAULT_INDENT, COLSTR("%s %s", SCOLOR_ASMDIR), ash.origin, buf);
return 1;
}
}
return 0;
}
//--------------------------------------------------------------------------
// generate a data representation
// usually all the job is handled by the kernel's standard procedure,
// out_data()
// But 8051 has its own quirks (namely, "equ" directives) and out_data()
// can't handle them. So we output "equ" ourselves and pass everything
// else to out_data()
// Again, let's repeat: usually the data items are output by the kernel
// function out_data(). You have to override it only if the processor
// has special features and the data items should be displayed in a
// special way.
void i51_t::i51_data(outctx_t &ctx, bool analyze_only)
{
// the kernel's standard routine which outputs the data knows nothing
// about "equ" directives. So we do the following:
// - try to output an "equ" directive
// - if we succeed, then ok
// - otherwise let the standard data output routine, out_data()
// do all the job
if ( !out_equ(ctx) )
ctx.out_data(analyze_only);
}

891
idasdk75/module/i51/reg.cpp Normal file
View File

@@ -0,0 +1,891 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-98 by Ilfak Guilfanov.
* ALL RIGHTS RESERVED.
* E-mail: ig@estar.msk.su, ig@datarescue.com
* FIDO: 2:50620/209
*
*/
#include "i51.hpp"
#include <entry.hpp>
#include <segregs.hpp>
//--------------------------------------------------------------------------
static const char *const RegNames[] =
{
"A", "AB", "B",
"R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
"R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15",
"WR0", "WR2", "WR4", "WR6", "WR8", "WR10", "WR12", "WR14",
"WR16", "WR18", "WR20", "WR22", "WR24", "WR26", "WR28", "WR30",
"DR0", "DR4", "DR8", "DR12", "DR16", "DR20", "DR24", "DR28",
"DR32", "DR36", "DR40", "DR44", "DR48", "DR52", "DPX", "SPX",
"DPTR","C", "PC",
"EPTR", "PR0", "PR1",
"cs","ds"
};
//----------------------------------------------------------------------
static const char cfgname[] = "i51.cfg";
void i51_iohandler_t::get_cfg_filename(char *buf, size_t bufsize)
{
qstrncpy(buf, cfgname, bufsize);
}
void i51_iohandler_t::apply_io_port(ea_t ea, const char *name, const char *cmt)
{
if ( ea >= 0x80 && ea < 0x100 )
{
// specail mapping alg for i51 FSR regs
segment_t *s = get_segm_by_name("FSR");
if ( s != NULL )
{
ea_t map = ea + s->start_ea - 0x80;
if ( is_mapped(map) )
ea = map;
}
}
set_name(ea, name, SN_NODUMMY);
set_cmt(ea, cmt, true);
}
bool i51_iohandler_t::segment_created(ea_t start, ea_t end, const char *word, const char *)
{
if ( stristr(word, "FSR") != NULL || stristr(word, "RAM") != NULL )
{
pm.AdditionalSegment(end-start, start, word);
return true;
}
return false;
}
//------------------------------------------------------------------
const char *i51_t::set_idp_options(
const char *keyword,
int /*value_type*/,
const void * /*value*/,
bool /*idb_loaded*/)
{
if ( keyword != NULL )
return IDPOPT_BADKEY;
iohandler_t::parse_area_line0_t cb(ioh);
if ( choose_ioport_device2(&ioh.device, cfgname, &cb) )
ioh.set_device_name(ioh.device.c_str(), IORESP_PORT|IORESP_INT);
return IDPOPT_OK;
}
//------------------------------------------------------------------
const ioport_bit_t *i51_t::find_bit(ea_t address, int bit)
{
return find_ioport_bit(ioh.ports, address, bit);
}
//----------------------------------------------------------------------
bool i51_t::IsPredefined(const char *name)
{
for ( int i=0; i < ioh.ports.size(); i++ )
{
const ioport_t &p = ioh.ports[i];
if ( p.name == name )
return true;
for ( int j=0; j < p.bits.size(); j++ )
if ( p.bits[j].name == name )
return true;
}
return false;
}
//----------------------------------------------------------------------
struct entry_t
{
char proc;
char off;
const char *name; //lint !e958 padding is required to align members
const char *cmt;
};
static const entry_t entries[] =
{
{ prc_51, 0x03, "extint0", "External interrupt 0 (INT0 / EX0)" },
{ prc_51, 0x0B, "timint0", "Timer interrupt 0 (TIM0)" },
{ prc_51, 0x13, "extint1", "External interrupt 1 (INT1 / EX1)" },
{ prc_51, 0x1B, "timint1", "Timer interrupt 1 (TIM1)" },
{ prc_51, 0x23, "serint", "Serial port interrupt (SERIAL)" },
{ prc_51, 0x2B, "timint2", "Timer interrupt 2 (TIM2) (52 or higher)" },
{ prc_51, 0x33, "pcaint", "PCA (programmable counter array) interrupt\n(only 51f or higher)" },
{ prc_930, 0x43, "usbhub", "USB Hub/SOF (isochronous end point) (only 930)" },
{ prc_930, 0x4B, "usbfun", "USB Function (non-isochronous end point) (only 930)" },
{ prc_930, 0x53, "usbglb", "USB Global Suspend/Resume and USB Reset (only 930)" },
{ prc_251, 0x7B, "trapint", "TRAP (program interrupt) (only 251 or 930)" }
};
//----------------------------------------------------------------------
// Get linear address of a special segment
// sel - selector of the segment
static ea_t specialSeg(segment_t *s)
{
if ( s->type != SEG_IMEM ) // is the segment type correct? - no
{
s->type = SEG_IMEM; // fix it
s->update();
}
return s->start_ea;
}
//----------------------------------------------------------------------
ea_t i51_t::AdditionalSegment(size_t size, size_t offset, const char *name) const
{
segment_t s;
s.start_ea = (ptype > prc_51)
? (inf_get_max_ea() + 0xF) & ~0xF
: free_chunk(0, size, 0xF);
s.end_ea = s.start_ea + size;
s.sel = allocate_selector((s.start_ea-offset) >> 4);
s.type = SEG_IMEM; // internal memory
add_segm_ex(&s, name, NULL, ADDSEG_NOSREG|ADDSEG_OR_DIE);
return s.start_ea - offset;
}
//----------------------------------------------------------------------
void i51_t::setup_data_segment_pointers(void)
{
segment_t *s = get_segm_by_name("INTMEM");
if ( s == NULL )
s = get_segm_by_name("RAM");
if ( s != NULL )
intmem = specialSeg(s);
s = get_segm_by_name("SFR");
if ( s == NULL )
s = get_segm_by_name("FSR");
if ( s != NULL )
sfrmem = specialSeg(s) - 0x80;
}
//--------------------------------------------------------------------------
ssize_t idaapi idb_listener_t::on_event(ssize_t code, va_list)
{
switch ( code )
{
case idb_event::segm_moved: // A segment is moved
// Fix processor dependent address sensitive information
{
// ea_t from = va_arg(va, ea_t);
// ea_t to = va_arg(va, ea_t);
// asize_t size = va_arg(va, asize_t);
// bool changed_netmap = va_argi(va, bool);
// Add commands to adjust your internal variables here
// Most of the time this callback will be empty
//
// If you keep information in a netnode's altval array, you can use
// node.altshift(from, s->start_ea, s->end_ea - s->start_ea);
//
// If you have a variables pointing to somewhere in the disassembled program memory,
// you can adjust it like this:
//
// if ( var >= from && var < from+size )
// var += to - from;
}
break;
}
return 0;
}
//----------------------------------------------------------------------
// 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 i51_t);
return 0;
}
ssize_t idaapi i51_t::on_event(ssize_t msgid, va_list va)
{
int code = 0;
switch ( msgid )
{
case processor_t::ev_init:
hook_event_listener(HT_IDB, &idb_listener, &LPH);
helper.create("$ intel 8051");
inf_set_be(true); // Set a big endian mode of the IDA kernel
break;
case processor_t::ev_term:
ioh.ports.clear();
unhook_event_listener(HT_IDB, &idb_listener);
break;
case processor_t::ev_newfile:
{
segment_t *sptr = get_first_seg();
if ( sptr != NULL )
{
if ( sptr->start_ea-get_segm_base(sptr) == 0 )
{
inf_set_start_ea(sptr->start_ea);
inf_set_start_ip(0);
for ( int i=0; i < qnumber(entries); i++ )
{
if ( entries[i].proc > ptype )
continue;
ea_t ea = inf_get_start_ea()+entries[i].off;
if ( is_mapped(ea) && get_byte(ea) != 0xFF )
{
add_entry(ea, ea, entries[i].name, 1);
set_cmt(ea, entries[i].cmt, 1);
}
}
}
}
segment_t *scode = get_first_seg();
set_segm_class(scode, "CODE");
if ( ptype > prc_51 )
{
AdditionalSegment(0x10000-256-128, 256+128, "RAM");
if ( scode != NULL )
{
ea_t align = (scode->end_ea + 0xFFF) & ~0xFFF;
if ( getseg(align-7) == scode ) // the code segment size is
{ // multiple of 4K or near it
uchar b0 = get_byte(align-8);
// 251:
// 0 : 1-source, 0-binary mode
// 6,7: must be 1s
// 82930:
// 0 : 1-source, 0-binary mode
// 7 : must be 1s
// uchar b1 = get_byte(align-7);
// 251
// 0: eprommap 0 - FE2000..FE4000 is mapped into 00E000..100000
// 1 - .............. is not mapped ...............
// 1: must be 1
// 3:
// 2: must be 1
// 4: intr 1 - upon interrupt PC,PSW are pushed into stack
// 0 - upon interrupt only PC is pushed into stack
// 5: must be 1
// 6: must be 1
// 7: must be 1
// 82930:
// 3: must be 1
// 5: must be 1
// 6: must be 1
// 7: must be 1
// msg("b0=%x b1=%x\n", b0, b1);
// if ( (b0 & 0x80) == 0x80 && (b1 & 0xEA) == 0xEA )
{ // the init bits are correct
char pname[IDAINFO_PROCNAME_SIZE];
inf_get_procname(pname, sizeof(pname));
char ntype = (b0 & 1) ? 's' : 'b';
char *ptr = tail(pname)-1;
if ( ntype != *ptr
&& ask_yn(ASKBTN_YES,
"HIDECANCEL\n"
"The input file seems to be for the %s mode of the processor.\n"
"Do you want to change the current processor type?",
ntype == 's' ? "source" : "binary") > 0 )
{
*ptr = ntype;
first_time = true;
set_processor_type(pname, SETPROC_USER);
}
}
}
}
}
// the default data segment will be INTMEM
{
segment_t *s = getseg(intmem);
if ( s != NULL )
set_default_dataseg(s->sel);
}
iohandler_t::parse_area_line0_t cb(ioh);
if ( choose_ioport_device2(&ioh.device, cfgname, &cb) )
ioh.set_device_name(ioh.device.c_str(), IORESP_ALL);
if ( get_segm_by_name("RAM") == NULL )
AdditionalSegment(256, 0, "RAM");
if ( get_segm_by_name("FSR") == NULL )
AdditionalSegment(128, 128, "FSR");
setup_data_segment_pointers();
}
break;
case processor_t::ev_ending_undo:
// restore ptype
ptype = processor_subtype_t(ph.get_proc_index());
//fall through
case processor_t::ev_oldfile:
setup_data_segment_pointers();
break;
case processor_t::ev_creating_segm:
// make the default DS point to INTMEM
// (8051 specific issue)
{
segment_t *newseg = va_arg(va, segment_t *);
segment_t *intseg = getseg(intmem);
if ( intseg != NULL )
newseg->defsr[rVds-ph.reg_first_sreg] = intseg->sel;
}
break;
case processor_t::ev_newprc:
{
processor_subtype_t prcnum = processor_subtype_t(va_arg(va, int));
// bool keep_cfg = va_argi(va, bool);
if ( !first_time && prcnum != ptype )
{
warning("Sorry, it is not possible to change" // (this is 8051 specific)
" the processor mode on the fly."
" Please reload the input file"
" if you want to change the processor.");
code = -1;
break;
}
first_time = false;
ptype = prcnum;
}
break;
case processor_t::ev_newasm: // new assembler type
ioh.restore_device();
break;
case processor_t::ev_is_sane_insn:
// is the instruction sane for the current file type?
// arg: int no_crefs
// 1: the instruction has no code refs to it.
// ida just tries to convert unexplored bytes
// to an instruction (but there is no other
// reason to convert them into an instruction)
// -1: the instruction is created because
// of some coderef, user request or another
// weighty reason.
// The instruction is in 'cmd'
// returns: 1-ok, <=0-no, the instruction isn't
// likely to appear in the program
{
const insn_t *insn = va_arg(va, insn_t *);
int reason = va_arg(va, int);
return is_sane_insn(*insn, reason) == 1 ? 1 : -1;
}
case processor_t::ev_out_header:
{
outctx_t *ctx = va_arg(va, outctx_t *);
i51_header(*ctx);
return 1;
}
case processor_t::ev_out_footer:
{
outctx_t *ctx = va_arg(va, outctx_t *);
i51_footer(*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 *);
i51_segstart(*ctx, seg);
return 1;
}
case processor_t::ev_ana_insn:
{
insn_t *out = va_arg(va, insn_t *);
return ana(out);
}
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;
}
case processor_t::ev_out_data:
{
outctx_t *ctx = va_arg(va, outctx_t *);
bool analyze_only = va_argi(va, bool);
i51_data(*ctx, analyze_only);
return 1;
}
case processor_t::ev_set_idp_options:
{
const char *keyword = va_arg(va, const char *);
int value_type = va_arg(va, int);
const char *value = va_arg(va, const char *);
const char **errmsg = va_arg(va, const char **);
bool idb_loaded = va_argi(va, bool);
const char *ret = set_idp_options(keyword, value_type, value, idb_loaded);
if ( ret == IDPOPT_OK )
return 1;
if ( errmsg != NULL )
*errmsg = ret;
return -1;
}
default:
break;
}
return code;
}
//-----------------------------------------------------------------------
// ASMI
//-----------------------------------------------------------------------
static const asm_t asmi =
{
AS_COLON | ASH_HEXF3 | AS_1TEXT | AS_NCHRE | ASO_OCTF1 | AS_RELSUP,
UAS_PSAM | UAS_NOSEG | UAS_AUBIT | UAS_PBIT | UAS_NOENS,
"ASMI",
0,
NULL, // no headers
".equ $, ",
".end",
";", // comment string
'"', // string delimiter
'\'', // char delimiter
"\\\"'", // special symbols in char and string constants
".text", // ascii string directive
".byte", // byte directive
".word", // word directive
NULL, // dword (4 bytes)
NULL, // qword (8 bytes)
NULL, // oword (16 bytes)
NULL, // float (4 bytes)
NULL, // double (8 bytes)
NULL, // tbyte (10/12 bytes)
NULL, // packed decimal real
NULL, // arrays (#h,#d,#v,#s(...)
".byte 0xFF;(array %s)", // uninited arrays
".equ", // equ
NULL, // seg prefix
"$", // curip
NULL, // func_header
NULL, // func_footer
NULL, // public
NULL, // weak
NULL, // extrn
NULL, // comm
NULL, // get_type_name
NULL, // align
'(', ')', // lbrace, rbrace
"%", // mod
"&", // and
"|", // or
"^", // xor
"!", // not
"<<", // shl
">>", // shr
NULL, // sizeof
};
//-----------------------------------------------------------------------
// 8051 Macro Assembler - Version 4.02a
// Copyright (C) 1985 by 2500 A.D. Software, Inc.
//-----------------------------------------------------------------------
static const asm_t adasm =
{
AS_COLON | ASH_HEXF0,
UAS_PBIT | UAS_SECT,
"8051 Macro Assembler by 2500 A.D. Software",
0,
NULL, // no headers
"org",
"end",
";", // comment string
'"', // string delimiter
'\'', // char delimiter
"\\\"'", // special symbols in char and string constants
"db", // ascii string directive
"db", // byte directive
"dw", // word directive
"long", // dword (4 bytes)
NULL, // qword (8 bytes)
NULL, // oword (16 bytes)
NULL, // float (4 bytes)
NULL, // double (8 bytes)
NULL, // tbyte (10/12 bytes)
NULL, // packed decimal real
NULL, // arrays (#h,#d,#v,#s(...)
"ds %s", // uninited arrays
"reg", // equ
NULL, // seg prefix
"$", // curip
NULL, // func_header
NULL, // func_footer
NULL, // public
NULL, // weak
NULL, // extrn
NULL, // comm
NULL, // get_type_name
NULL, // align
'(', ')', // lbrace, rbrace
NULL, // mod
NULL, // and
NULL, // or
NULL, // xor
NULL, // not
NULL, // shl
NULL, // shr
NULL, // sizeof
0, // flag2
NULL, // close comment
COLSTR("<", SCOLOR_SYMBOL) "%s", // low8
COLSTR(">", SCOLOR_SYMBOL) "%s", // high8
NULL, // low16
NULL, // high16
};
//-----------------------------------------------------------------------
// PseudoSam
//-----------------------------------------------------------------------
static const char *const ps_headers[] =
{
".code",
NULL
};
static const asm_t pseudosam =
{
AS_COLON | ASH_HEXF1 | AS_N2CHR,
UAS_PBIT | UAS_PSAM | UAS_SELSG,
"PseudoSam by PseudoCode",
0,
ps_headers,
".org",
".end",
";", // comment string
'"', // string delimiter
'\'', // char delimiter
"\\\"'", // special symbols in char and string constants
".db", // ascii string directive
".db", // byte directive
".dw", // word directive
NULL, // dword (4 bytes)
NULL, // qword (8 bytes)
NULL, // oword (16 bytes)
NULL, // float (4 bytes)
NULL, // double (8 bytes)
NULL, // tbyte (10/12 bytes)
NULL, // packed decimal real
NULL, // arrays (#h,#d,#v,#s(...)
".rs %s", // uninited arrays
".equ", // equ
NULL, // seg prefix
"$", // curip
NULL, // func_header
NULL, // func_footer
NULL, // public
NULL, // weak
NULL, // extrn
NULL, // comm
NULL, // get_type_name
NULL, // align
'(', ')', // lbrace, rbrace
NULL, // mod
NULL, // and
NULL, // or
NULL, // xor
NULL, // not
NULL, // shl
NULL, // shr
NULL, // sizeof
};
//-----------------------------------------------------------------------
// Cross-16 assembler definiton
//-----------------------------------------------------------------------
static const char *const cross16_headers[] =
{
"cpu \"8051.tbl\"",
NULL
};
static const asm_t cross16 =
{
AS_COLON | ASH_HEXF0 | AS_NHIAS,
UAS_PBIT | UAS_NOSEG | UAS_NOBIT | UAS_EQCLN,
"Cross-16 by Universal Cross-Assemblers",
0,
cross16_headers,
"org",
"end",
";", // comment string
'"', // string delimiter
'\0', // char delimiter (no char consts)
"\\\"'", // special symbols in char and string constants
"dfb", // ascii string directive
"dfb", // byte directive
"dwm", // word directive
NULL, // dword (4 bytes)
NULL, // qword (8 bytes)
NULL, // oword (16 bytes)
NULL, // float (4 bytes)
NULL, // double (8 bytes)
NULL, // tbyte (10/12 bytes)
NULL, // packed decimal real
NULL, // arrays (#h,#d,#v,#s(...)
"dfs %s", // uninited arrays
"equ", // Equ
NULL, // seg prefix
"$", // curip
NULL, // func_header
NULL, // func_footer
NULL, // public
NULL, // weak
NULL, // extrn
NULL, // comm
NULL, // get_type_name
NULL, // align
'(', ')', // lbrace, rbrace
NULL, // mod
NULL, // and
NULL, // or
NULL, // xor
NULL, // not
NULL, // shl
NULL, // shr
NULL, // sizeof
};
//-----------------------------------------------------------------------
// 8051 Cross-Assembler by MetaLink Corporation
//-----------------------------------------------------------------------
static const asm_t mcross =
{
AS_COLON | ASH_HEXF0 | AS_NHIAS,
UAS_NOSEG | UAS_CDSEG | UAS_AUBIT | UAS_NODS | UAS_NOENS,
"8051 Cross-Assembler by MetaLink Corporation",
0,
NULL,
"org",
"end",
";", // comment string
'\'', // string delimiter
'\0', // char delimiter (no char consts)
"\\\"'", // special symbols in char and string constants
"db", // ascii string directive
"db", // byte directive
"dw", // word directive
NULL, // dword (4 bytes)
NULL, // qword (8 bytes)
NULL, // oword (16 bytes)
NULL, // float (4 bytes)
NULL, // double (8 bytes)
NULL, // tbyte (10/12 bytes)
NULL, // packed decimal real
NULL, // arrays (#h,#d,#v,#s(...)
"ds %s", // uninited arrays
"equ", // Equ
NULL, // seg prefix
"$", // curip
NULL, // func_header
NULL, // func_footer
NULL, // public
NULL, // weak
NULL, // extrn
NULL, // comm
NULL, // get_type_name
NULL, // align
'(', ')', // lbrace, rbrace
NULL, // mod
NULL, // and
NULL, // or
NULL, // xor
NULL, // not
NULL, // shl
NULL, // shr
NULL, // sizeof
};
//-----------------------------------------------------------------------
// TASM assembler definiton
//-----------------------------------------------------------------------
static const char *const tasm_headers[] =
{
".msfirst",
NULL
};
static const asm_t tasm =
{
AS_COLON | AS_N2CHR | AS_1TEXT,
UAS_PBIT | UAS_NOENS | UAS_EQCLN | UAS_NOSEG,
"Table Driven Assembler (TASM) by Speech Technology Inc.",
0,
tasm_headers,
".org",
".end",
";", // comment string
'"', // string delimiter
'\'', // char delimiter
"\\\"'", // special symbols in char and string constants
".text", // ascii string directive
".db", // byte directive
".dw", // word directive
NULL, // dword (4 bytes)
NULL, // qword (8 bytes)
NULL, // oword (16 bytes)
NULL, // float (4 bytes)
NULL, // double (8 bytes)
NULL, // tbyte (10/12 bytes)
NULL, // packed decimal real
NULL, // arrays (#h,#d,#v,#s(...)
".block %s", // uninited arrays
".equ",
NULL, // seg prefix
"$", // curip
NULL, // func_header
NULL, // func_footer
NULL, // public
NULL, // weak
NULL, // extrn
NULL, // comm
NULL, // get_type_name
NULL, // align
'(', ')', // lbrace, rbrace
NULL, // mod
"and", // and
"or", // or
NULL, // xor
"not", // not
NULL, // shl
NULL, // shr
NULL, // sizeof
};
static const asm_t *const asms[] =
{
&asmi, &adasm, &pseudosam, &cross16, &mcross, &tasm, NULL
};
//-----------------------------------------------------------------------
// The short and long names of the supported processors
#define FAMILY "Intel 51 series:"
static const char *const shnames[] =
{
"8051",
"80251b",
"80251s",
"80930b",
"80930s",
"8051mx",
NULL
};
static const char *const lnames[] =
{
FAMILY"Intel 8051",
"Intel 80251 in binary mode",
"Intel 80251 in source mode",
"Intel 80930 in binary mode",
"Intel 80930 in source mode",
"Intel 8051MX",
NULL
};
//--------------------------------------------------------------------------
// Opcodes of "return" instructions. This information will be used in 2 ways:
// - if an instruction has the "return" opcode, its autogenerated label
// will be "locret" rather than "loc".
// - IDA will use the first "return" opcode to create empty subroutines.
static const uchar retcode_1[] = { 0x22 };
static const uchar retcode_2[] = { 0x32 };
static const bytes_t retcodes[] =
{
{ sizeof(retcode_1), retcode_1 },
{ sizeof(retcode_2), retcode_2 },
{ 0, NULL } // NULL terminated array
};
//-----------------------------------------------------------------------
// Processor Definition
//-----------------------------------------------------------------------
processor_t LPH =
{
IDP_INTERFACE_VERSION, // version
PLFM_8051, // id
// flag
PR_RNAMESOK // can use register names for byte names
| PR_SEGTRANS // segment translation is supported (map_code_ea)
| PR_BINMEM, // The module creates RAM/ROM segments for binary files
// (the kernel shouldn't ask the user about their sizes and addresses)
// flag2
PR2_IDP_OPTS, // the module has processor-specific configuration options
8, // 8 bits in a byte for code segments
8, // 8 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 type
// selection menu
asms, // array of target assemblers
notify, // the kernel event notification callback
RegNames, // Regsiter names
qnumber(RegNames), // Number of registers
rVcs,rVds,
0, // size of a segment register
rVcs,rVds,
NULL, // No known code start sequences
retcodes,
0,I51_last,
Instructions, // instruc
0, // int tbyte_size; -- doesn't exist
{ 0, 7, 15, 0 }, // char real_width[4];
// number of symbols after decimal point
// 2byte float (0-does not exist)
// normal float
// normal double
// long double
I51_ret, // Icode of return instruction. It is ok to give any of possible return instructions
};