update to ida 7.6, add builds

This commit is contained in:
2021-10-31 21:20:46 +02:00
parent e0e0f2be99
commit b1809fe2d9
1408 changed files with 279193 additions and 302468 deletions

View File

@@ -0,0 +1,650 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-99 by Ilfak Guilfanov.
* ALL RIGHTS RESERVED.
* E-mail: ig@datarescue.com
*
* Hitchi H8
*
*/
#include "h8500.hpp"
//--------------------------------------------------------------------------
#define MAP3 ushort(-3)
#define MAP4 ushort(-4)
#define MAP5 ushort(-5)
#define MAP6 ushort(-6)
static const ushort A2[] =
{
/* 00 */ H8500_nop, MAP6, H8500_ldm, H8500_pjsr, MAP5, MAP4, MAP6, MAP6,
/* 08 */ H8500_trapa, H8500_trap_vs, H8500_rte, H8500_bpt, MAP5, MAP4, H8500_bsr, H8500_unlk,
/* 10 */ H8500_jmp, MAP6, H8500_stm, H8500_pjmp, H8500_rtd, MAP4, H8500_null, H8500_link,
/* 18 */ H8500_jsr, H8500_rts, H8500_sleep, H8500_null, H8500_rtd, MAP4, H8500_bsr, H8500_link,
/* 20 */ H8500_bra, H8500_brn, H8500_bhi, H8500_bls, H8500_bcc, H8500_bcs, H8500_bne, H8500_beq,
/* 28 */ H8500_bvc, H8500_bvs, H8500_bpl, H8500_bmi, H8500_bge, H8500_blt, H8500_bgt, H8500_ble,
/* 30 */ H8500_bra, H8500_brn, H8500_bhi, H8500_bls, H8500_bcc, H8500_bcs, H8500_bne, H8500_beq,
/* 38 */ H8500_bvc, H8500_bvs, H8500_bpl, H8500_bmi, H8500_bge, H8500_blt, H8500_bgt, H8500_ble,
/* 40 */ H8500_cmp_e, H8500_cmp_e, H8500_cmp_e, H8500_cmp_e, H8500_cmp_e, H8500_cmp_e, H8500_cmp_e, H8500_cmp_e,
/* 48 */ H8500_cmp_i, H8500_cmp_i, H8500_cmp_i, H8500_cmp_i, H8500_cmp_i, H8500_cmp_i, H8500_cmp_i, H8500_cmp_i,
/* 50 */ H8500_mov_e, H8500_mov_e, H8500_mov_e, H8500_mov_e, H8500_mov_e, H8500_mov_e, H8500_mov_e, H8500_mov_e,
/* 58 */ H8500_mov_i, H8500_mov_i, H8500_mov_i, H8500_mov_i, H8500_mov_i, H8500_mov_i, H8500_mov_i, H8500_mov_i,
};
static const ushort A2tail[] =
{
/* 60 */ H8500_mov_l,
/* 70 */ H8500_mov_s,
/* 80 */ H8500_mov_f,
/* 90 */ H8500_mov_f,
/* A0 */ MAP3,
/* B0 */ MAP4,
/* C0 */ MAP4,
/* D0 */ MAP4,
/* E0 */ MAP4,
/* F0 */ MAP4,
};
static const ushort A3[] =
{
/* 00 */ MAP6, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null,
/* 08 */ H8500_add_q, H8500_add_q, H8500_null, H8500_null, H8500_add_q, H8500_add_q, H8500_null, H8500_null,
/* 10 */ H8500_swap, H8500_exts, H8500_extu, H8500_clr, H8500_neg, H8500_not, H8500_tst, H8500_tas,
/* 18 */ H8500_shal, H8500_shar, H8500_shll, H8500_shlr, H8500_rotl, H8500_rotr, H8500_rotxl, H8500_rotxr,
};
static const ushort A3tail[] =
{
/* 20 */ H8500_add_g, H8500_adds,
/* 30 */ H8500_sub, H8500_subs,
/* 40 */ H8500_or, H8500_bset,
/* 50 */ H8500_and, H8500_bclr,
/* 60 */ H8500_xor, H8500_bnot,
/* 70 */ H8500_cmp_g, H8500_btst,
/* 80 */ H8500_mov_g, H8500_ldc,
/* 90 */ H8500_xch, H8500_stc,
/* A0 */ H8500_addx, H8500_mulxu,
/* B0 */ H8500_subx, H8500_divxu,
/* C0 */ H8500_bset, H8500_bset,
/* D0 */ H8500_bclr, H8500_bclr,
/* E0 */ H8500_bnot, H8500_bnot,
/* F0 */ H8500_btst, H8500_btst,
};
static const ushort A4[] =
{
/* 00 */ MAP6, H8500_null, H8500_null, H8500_null, H8500_cmp_g, H8500_cmp_g, H8500_mov_g, H8500_mov_g,
/* 08 */ H8500_add_q, H8500_add_q, H8500_null, H8500_null, H8500_add_q, H8500_add_q, H8500_null, H8500_null,
/* 10 */ H8500_null, H8500_null, H8500_null, H8500_clr, H8500_neg, H8500_not, H8500_tst, H8500_tas,
/* 18 */ H8500_shal, H8500_shar, H8500_shll, H8500_shlr, H8500_rotl, H8500_rotr, H8500_rotxl, H8500_rotxr,
};
static const ushort A4tail[] =
{
/* 20 */ H8500_add_g, H8500_adds,
/* 30 */ H8500_sub, H8500_subs,
/* 40 */ H8500_or, H8500_bset,
/* 50 */ H8500_and, H8500_bclr,
/* 60 */ H8500_xor, H8500_bnot,
/* 70 */ H8500_cmp_g, H8500_btst,
/* 80 */ H8500_mov_g, H8500_ldc,
/* 90 */ H8500_mov_g, H8500_stc,
/* A0 */ H8500_addx, H8500_mulxu,
/* B0 */ H8500_subx, H8500_divxu,
/* C0 */ H8500_bset, H8500_bset,
/* D0 */ H8500_bclr, H8500_bclr,
/* E0 */ H8500_bnot, H8500_bnot,
/* F0 */ H8500_btst, H8500_btst,
};
static const ushort A5[] =
{
/* 00 */ H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null,
/* 08 */ H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null,
/* 10 */ H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null,
/* 18 */ H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null,
};
static const ushort A5tail[] =
{
/* 20 */ H8500_add_g, H8500_adds,
/* 30 */ H8500_sub, H8500_subs,
/* 40 */ H8500_or, H8500_orc,
/* 50 */ H8500_and, H8500_andc,
/* 60 */ H8500_xor, H8500_xorc,
/* 70 */ H8500_cmp_g, H8500_null,
/* 80 */ H8500_mov_g, H8500_ldc,
/* 90 */ H8500_null, H8500_null,
/* A0 */ H8500_addx, H8500_mulxu,
/* B0 */ H8500_subx, H8500_divxu,
/* C0 */ H8500_null, H8500_null,
/* D0 */ H8500_null, H8500_null,
/* E0 */ H8500_null, H8500_null,
/* F0 */ H8500_null, H8500_null,
};
static const ushort A6[] =
{
/* 00 */ H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null,
/* 08 */ H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null, H8500_null,
/* 10 */ H8500_null, H8500_null, H8500_null, H8500_null, H8500_prtd, H8500_null, H8500_null, H8500_null,
/* 18 */ H8500_null, H8500_prts, H8500_null, H8500_null, H8500_prtd, H8500_null, H8500_null, H8500_null,
};
static const ushort A6tail[] =
{
/* 20 */ H8500_null, H8500_null,
/* 30 */ H8500_null, H8500_null,
/* 40 */ H8500_null, H8500_null,
/* 50 */ H8500_null, H8500_null,
/* 60 */ H8500_null, H8500_null,
/* 70 */ H8500_null, H8500_null,
/* 80 */ H8500_movfpe, H8500_null,
/* 90 */ H8500_movtpe, H8500_null,
/* A0 */ H8500_dadd, H8500_null,
/* B0 */ H8500_dsub, H8500_scb,
/* C0 */ H8500_pjmp, H8500_pjsr,
/* D0 */ H8500_jmp, H8500_jsr,
/* E0 */ H8500_jmp, H8500_jsr,
/* F0 */ H8500_jmp, H8500_jsr,
};
struct tables_t
{
const ushort *head;
const ushort *tail;
};
static const tables_t tables[] =
{
{ A3, A3tail },
{ A4, A4tail },
{ A5, A5tail },
{ A6, A6tail },
};
//--------------------------------------------------------------------------
inline void immv(op_t &x, int v)
{
x.type = o_imm;
x.dtype = dt_dword;
x.value = v;
}
//--------------------------------------------------------------------------
inline void imm8(insn_t &insn, op_t &x)
{
insn.auxpref |= aux_disp8;
x.type = o_imm;
x.dtype = dt_byte;
x.value = insn.get_next_byte();
}
//--------------------------------------------------------------------------
inline void imm16(insn_t &insn, op_t &x)
{
insn.auxpref |= aux_disp16;
x.type = o_imm;
x.dtype = dt_word;
x.value = insn.get_next_word();
}
//--------------------------------------------------------------------------
inline void opreg(op_t &x, int code, char dtype)
{
x.type = o_reg;
x.dtype = dtype;
x.reg = code & 7;
}
//--------------------------------------------------------------------------
inline void aa8(insn_t &insn, op_t &x, char dtype)
{
insn.auxpref |= aux_page|aux_disp8;
x.type = o_mem;
x.dtype = dtype;
x.addr = insn.get_next_byte();
}
//--------------------------------------------------------------------------
inline void aa16(insn_t &insn, op_t &x, char dtype)
{
insn.auxpref |= aux_disp16;
x.type = o_mem;
x.dtype = dtype;
x.addr = insn.get_next_word();
}
//--------------------------------------------------------------------------
inline void ds8(insn_t &insn, op_t &x, int reg, char dtype)
{
insn.auxpref |= aux_disp8;
x.type = o_displ;
x.dtype = dtype;
x.reg = reg & 7;
x.addr = insn.get_next_byte();
}
//--------------------------------------------------------------------------
inline void ds16(insn_t &insn, op_t &x, int reg, char dtype)
{
insn.auxpref |= aux_disp16;
x.type = o_displ;
x.dtype = dtype;
x.reg = reg & 7;
x.addr = insn.get_next_word();
}
//--------------------------------------------------------------------------
inline void phrase(op_t &x, int code, uchar pht, char dtype)
{
x.type = o_phrase;
x.dtype = dtype;
x.phrase = code & 7;
x.phtype = pht;
}
//--------------------------------------------------------------------------
inline void d8(insn_t &insn, op_t &x)
{
insn.auxpref |= aux_disp8;
int32 disp = char(insn.get_next_byte());
x.type = o_near;
x.dtype = dt_code;
x.addr = insn.ip + insn.size + disp;
}
//--------------------------------------------------------------------------
int h8500_t::h8500_ana(insn_t *_insn)
{
insn_t &insn = *_insn;
uint8 code = insn.get_next_byte();
uint8 saved_code = code;
char dtype = dt_byte;
if ( code < 0x60 )
{
insn.itype = A2[code];
}
else
{
if ( code & 8 )
{
insn.auxpref |= aux_word;
dtype = dt_word;
}
else
{
insn.auxpref |= aux_byte;
dtype = dt_byte;
}
insn.itype = A2tail[(code>>4)-6];
}
if ( insn.itype == H8500_null )
return 0;
switch ( code )
{
case 0x02: // ldm.w @sp+, <reglist>
// insn.auxpref |= aux_word;
phrase(insn.Op1, SP, ph_post, dt_word);
insn.Op2.type = o_reglist;
insn.Op2.reg = insn.get_next_byte();
if ( !insn.Op2.reg )
return 0;
break;
case 0x12: // stm.w <reglist>, @-sp
// insn.auxpref |= aux_word;
insn.Op1.type = o_reglist;
insn.Op1.reg = insn.get_next_byte();
if ( !insn.Op1.reg )
return 0;
phrase(insn.Op2, SP, ph_pre, dt_word);
break;
case 0x01: // scb/f
insn.auxpref |= aux_f;
break;
case 0x06: // scb/ne
insn.auxpref |= aux_ne;
break;
case 0x07: // scb/eq
insn.auxpref |= aux_eq;
break;
case 0x08: // trapa #xx
code = insn.get_next_byte();
if ( (code & 0xF0) != 0x10 )
return 0;
insn.Op1.type = o_imm;
insn.Op1.dtype = dt_byte;
insn.Op1.value = code & 15;
break;
case 0x0F: // unlk
opreg(insn.Op1, FP, dt_word);
break;
case 0x10: // jmp @aa:16
case 0x18: // jsr @aa:16
aa16(insn, insn.Op1, dt_code);
insn.Op1.type = o_near;
insn.Op1.addr += insn.ea & ~0xFFFF;
break;
case 0x17: // link #xx:8
opreg(insn.Op1, FP, dt_word);
imm8(insn, insn.Op2);
break;
case 0x1F: // link #xx:16
opreg(insn.Op1, FP, dt_word);
imm16(insn, insn.Op2);
break;
case 0x03: // pjsr @aa:24
case 0x13: // pjmp @aa:24
{
insn.auxpref |= aux_disp24;
uint32 page = insn.get_next_byte();
insn.Op1.type = o_far;
insn.Op1.dtype = dt_code;
insn.Op1.addr = (page<<16) | insn.get_next_word();
}
break;
case 0x04: // #xx:8
insn.auxpref |= aux_byte;
// fallthrough
case 0x14: // #xx:8
imm8(insn, insn.Op1);
break;
case 0x05: // #aa:8.B
insn.auxpref |= aux_byte;
aa8(insn, insn.Op1, dt_byte);
break;
case 0x15: // #aa:16.B
insn.auxpref |= aux_byte;
aa16(insn, insn.Op1, dt_byte);
break;
case 0x0C: // #xx:16
insn.auxpref |= aux_word;
// fallthrough
case 0x1C: // #xx:16
imm16(insn, insn.Op1);
break;
case 0x0D: // #aa:8.W
insn.auxpref |= aux_word;
aa8(insn, insn.Op1, dt_word);
dtype = dt_word;
break;
case 0x1D: // #aa:16.W
insn.auxpref |= aux_word;
aa16(insn, insn.Op1, dt_word);
dtype = dt_word;
break;
case 0x0E: // bsr d:8
case 0x20: case 0x21: case 0x22: case 0x23: // d:8
case 0x24: case 0x25: case 0x26: case 0x27:
case 0x28: case 0x29: case 0x2A: case 0x2B:
case 0x2C: case 0x2D: case 0x2E: case 0x2F:
d8(insn, insn.Op1);
break;
case 0x1E: // bsr d:16
case 0x30: case 0x31: case 0x32: case 0x33: // d:16
case 0x34: case 0x35: case 0x36: case 0x37:
case 0x38: case 0x39: case 0x3A: case 0x3B:
case 0x3C: case 0x3D: case 0x3E: case 0x3F:
{
insn.auxpref |= aux_disp16;
int32 disp = short(insn.get_next_word());
insn.Op1.type = o_near;
insn.Op1.dtype = dt_code;
insn.Op1.addr = insn.ip + insn.size + disp;
}
break;
case 0x40: case 0x41: case 0x42: case 0x43: // cmp:e #xx:8, Rn
case 0x44: case 0x45: case 0x46: case 0x47:
case 0x50: case 0x51: case 0x52: case 0x53: // mov:e #xx:8, Rn
case 0x54: case 0x55: case 0x56: case 0x57:
insn.auxpref |= aux_byte;
imm8(insn, insn.Op1);
opreg(insn.Op2, code, dtype);
break;
case 0x48: case 0x49: case 0x4A: case 0x4B: // cmp:i #xx:16, Rn
case 0x4C: case 0x4D: case 0x4E: case 0x4F:
case 0x58: case 0x59: case 0x5A: case 0x5B: // mov:i #xx:16, Rn
case 0x5C: case 0x5D: case 0x5E: case 0x5F:
insn.auxpref |= aux_word;
imm16(insn, insn.Op1);
opreg(insn.Op2, code, dtype);
break;
case 0x60: case 0x61: case 0x62: case 0x63: // @aa:8, Rn
case 0x64: case 0x65: case 0x66: case 0x67:
case 0x68: case 0x69: case 0x6A: case 0x6B:
case 0x6C: case 0x6D: case 0x6E: case 0x6F:
aa8(insn, insn.Op1, dtype);
opreg(insn.Op2, code, dtype);
break;
case 0x70: case 0x71: case 0x72: case 0x73: // Rn, @aa:8
case 0x74: case 0x75: case 0x76: case 0x77:
case 0x78: case 0x79: case 0x7A: case 0x7B:
case 0x7C: case 0x7D: case 0x7E: case 0x7F:
opreg(insn.Op1, code, dtype);
aa8(insn, insn.Op2, dtype);
break;
case 0x80: case 0x81: case 0x82: case 0x83: // mov:f @(d:8, R6), Rn
case 0x84: case 0x85: case 0x86: case 0x87:
case 0x88: case 0x89: case 0x8A: case 0x8B:
case 0x8C: case 0x8D: case 0x8E: case 0x8F:
ds8(insn, insn.Op1, R6, dtype);
opreg(insn.Op2, code, dtype);
break;
case 0x90: case 0x91: case 0x92: case 0x93: // mov:f Rn, @(d:8, R6)
case 0x94: case 0x95: case 0x96: case 0x97:
case 0x98: case 0x99: case 0x9A: case 0x9B:
case 0x9C: case 0x9D: case 0x9E: case 0x9F:
opreg(insn.Op1, code, dtype);
ds8(insn, insn.Op2, R6, dtype);
break;
case 0xA0: case 0xA1: case 0xA2: case 0xA3: // Rn, Rn
case 0xA4: case 0xA5: case 0xA6: case 0xA7:
case 0xA8: case 0xA9: case 0xAA: case 0xAB:
case 0xAC: case 0xAD: case 0xAE: case 0xAF:
opreg(insn.Op1, code, dtype);
break;
case 0xB0: case 0xB1: case 0xB2: case 0xB3: // @-Rn, Rn
case 0xB4: case 0xB5: case 0xB6: case 0xB7:
case 0xB8: case 0xB9: case 0xBA: case 0xBB:
case 0xBC: case 0xBD: case 0xBE: case 0xBF:
phrase(insn.Op1, code, ph_pre, dtype);
break;
case 0xC0: case 0xC1: case 0xC2: case 0xC3: // @Rn+, Rn
case 0xC4: case 0xC5: case 0xC6: case 0xC7:
case 0xC8: case 0xC9: case 0xCA: case 0xCB:
case 0xCC: case 0xCD: case 0xCE: case 0xCF:
phrase(insn.Op1, code, ph_post, dtype);
break;
case 0xD0: case 0xD1: case 0xD2: case 0xD3: // @Rn, Rn
case 0xD4: case 0xD5: case 0xD6: case 0xD7:
case 0xD8: case 0xD9: case 0xDA: case 0xDB:
case 0xDC: case 0xDD: case 0xDE: case 0xDF:
phrase(insn.Op1, code, ph_normal, dtype);
break;
case 0xE0: case 0xE1: case 0xE2: case 0xE3: // @(d:8,Rn), Rn
case 0xE4: case 0xE5: case 0xE6: case 0xE7:
case 0xE8: case 0xE9: case 0xEA: case 0xEB:
case 0xEC: case 0xED: case 0xEE: case 0xEF:
ds8(insn, insn.Op1, code, dtype);
break;
case 0xF0: case 0xF1: case 0xF2: case 0xF3: // @(d:16,Rn), Rn
case 0xF4: case 0xF5: case 0xF6: case 0xF7:
case 0xF8: case 0xF9: case 0xFA: case 0xFB:
case 0xFC: case 0xFD: case 0xFE: case 0xFF:
ds16(insn, insn.Op1, code, dtype);
break;
}
while ( insn.itype > H8500_last ) // while MAPs are not resolved
{
int index = -(3+short(insn.itype));
if ( index < 0 || index >= qnumber(tables) )
INTERR(10089);
code = insn.get_next_byte();
if ( code < 0x20 )
{
insn.itype = tables[index].head[code];
}
else
{
insn.itype = tables[index].tail[(code>>3)-4];
opreg(insn.Op2, code, dtype);
}
if ( index == 3 ) switch ( saved_code ) // MAP6
{
case 0x01:
case 0x06:
case 0x07:
if ( insn.itype != H8500_scb )
return 0;
break;
case 0x11:
if ( insn.itype != H8500_prts
&& insn.itype != H8500_prtd
&& insn.itype != H8500_jmp
&& insn.itype != H8500_pjmp
&& insn.itype != H8500_jsr
&& insn.itype != H8500_pjsr )
{
return 0;
}
break;
default:
if ( insn.itype != H8500_movfpe
&& insn.itype != H8500_movtpe
&& insn.itype != H8500_dadd
&& insn.itype != H8500_dsub )
{
return 0;
}
}
switch ( insn.itype )
{
case H8500_null:
return 0;
case H8500_add_q:
insn.Op2 = insn.Op1;
switch ( code )
{
case 0x08: immv(insn.Op1, 1); break;
case 0x09: immv(insn.Op1, 2); break;
case 0x0C: immv(insn.Op1, -1); break;
case 0x0D: immv(insn.Op1, -2); break;
}
break;
case H8500_bset:
case H8500_bclr:
case H8500_bnot:
case H8500_btst:
insn.Op2 = insn.Op1;
if ( code < 0xC0 )
opreg(insn.Op1, code, dtype);
else
immv(insn.Op1, code & 15);
break;
case H8500_mov_g:
if ( (code & 0xF8) == 0x80 )
break;
insn.Op2 = insn.Op1;
if ( code == 0x06 )
{
if ( (insn.auxpref & aux_word) == 0 )
insn.auxpref |= aux_byte;
insn.Op1.type = o_imm;
insn.Op1.dtype = dt_byte;
insn.Op1.value = insn.get_next_byte();
}
else if ( code == 0x07 )
{
if ( (insn.auxpref & aux_byte) == 0 )
insn.auxpref |= aux_word;
insn.auxpref |= aux_mov16;
insn.Op1.type = o_imm;
insn.Op1.dtype = dt_word;
insn.Op1.value = insn.get_next_word();
}
else
opreg(insn.Op1, code, dtype);
break;
case H8500_cmp_g:
if ( code > 5 )
break;
insn.Op2 = insn.Op1;
if ( code == 0x04 )
{
insn.auxpref |= aux_byte;
insn.Op1.type = o_imm;
insn.Op1.dtype = dt_byte;
insn.Op1.value = insn.get_next_byte();
}
else
{
insn.auxpref |= aux_word;
insn.Op1.type = o_imm;
insn.Op1.dtype = dt_word;
insn.Op1.value = insn.get_next_word();
}
break;
case H8500_andc:
case H8500_orc:
case H8500_xorc:
case H8500_ldc:
case H8500_stc:
insn.Op2.reg += SR;
if ( insn.Op2.reg == RES1 || insn.Op2.reg == CP )
return 0;
if ( ((insn.auxpref & aux_word) != 0) != (insn.Op2.reg == SR) )
return 0;
if ( insn.itype != H8500_stc )
break;
// no break
case H8500_movtpe:
{
op_t x = insn.Op1;
insn.Op1 = insn.Op2;
insn.Op2 = x;
}
break;
case H8500_pjmp:
case H8500_pjsr:
case H8500_jmp:
case H8500_jsr:
insn.Op2.type = o_void;
switch ( code & 0xF0 )
{
case 0xC0:
case 0xD0: phrase(insn.Op1, code, ph_normal, dt_code); break;
case 0xE0: ds8(insn, insn.Op1, code, dt_code); break;
case 0xF0: ds16(insn, insn.Op1, code, dt_code); break;
}
break;
case H8500_rtd:
case H8500_prtd:
if ( code == 0x14 )
imm8(insn, insn.Op1);
else
imm16(insn, insn.Op1);
break;
case H8500_scb:
insn.Op1 = insn.Op2;
d8(insn, insn.Op2);
break;
case H8500_dadd:
case H8500_dsub:
if ( (insn.auxpref & aux_byte) == 0 )
return 0;
insn.auxpref &= ~aux_byte;
break;
}
}
if ( !is_mixed_size_insns() )
{
if ( (insn.auxpref & aux_word) && insn.Op1.dtype == dt_byte
|| (insn.auxpref & aux_byte) && insn.Op1.dtype == dt_word )
{
if ( insn.itype != H8500_mov_g )
return 0;
}
}
return insn.size;
}

View File

@@ -0,0 +1,514 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-99 by Ilfak Guilfanov.
* ALL RIGHTS RESERVED.
* E-mail: ig@datarescue.com
*
*
*/
#include "h8500.hpp"
#include <frame.hpp>
//------------------------------------------------------------------------
static void process_immediate_number(const insn_t &insn, int n)
{
set_immd(insn.ea);
if ( is_defarg(get_flags(insn.ea), n) )
return;
switch ( insn.itype )
{
case H8500_add_q:
case H8500_bclr:
case H8500_bnot:
case H8500_bset:
case H8500_btst:
op_dec(insn.ea, n);
break;
case H8500_and:
case H8500_or:
case H8500_xor:
case H8500_andc:
case H8500_orc:
case H8500_xorc:
op_num(insn.ea, n);
break;
}
}
//----------------------------------------------------------------------
inline bool issp(int x)
{
return x == SP;
}
inline bool isbp(int x)
{
return x == FP;
}
//----------------------------------------------------------------------
int idaapi is_sp_based(const insn_t &, const op_t &x)
{
return OP_SP_ADD
| ((x.type == o_displ || x.type == o_phrase) && issp(x.phrase)
? OP_SP_BASED
: OP_FP_BASED);
}
//----------------------------------------------------------------------
static void add_stkpnt(const insn_t &insn, sval_t value)
{
func_t *pfn = get_func(insn.ea);
if ( pfn == NULL )
return;
if ( value & 1 )
value++;
add_auto_stkpnt(pfn, insn.ea+insn.size, value);
}
//----------------------------------------------------------------------
inline bool is_mov(int itype)
{
return itype >= H8500_mov_g && itype <= H8500_mov_s;
}
//----------------------------------------------------------------------
static bool get_op_value(const insn_t &insn, const op_t &x, int *value)
{
if ( x.type == o_imm )
{
*value = (int)x.value;
return true;
}
bool ok = false;
if ( x.type == o_reg )
{
int reg = x.reg;
insn_t movi;
if ( decode_prev_insn(&movi, insn.ea) != BADADDR
&& is_mov(movi.itype)
&& movi.Op1.type == o_imm
&& movi.Op2.type == o_reg
&& movi.Op2.reg == reg )
{
*value = (int)movi.Op1.value;
ok = true;
}
}
return ok;
}
//----------------------------------------------------------------------
static int calc_reglist_count(int regs)
{
int count = 0;
for ( int i=0; i < 8; i++,regs>>=1 )
if ( regs & 1 )
count++;
return count;
}
//----------------------------------------------------------------------
// @--sp
inline bool is_sp_dec(const op_t &x)
{
return x.type == o_phrase
&& issp(x.reg)
&& x.phtype == ph_pre;
}
//----------------------------------------------------------------------
// @sp++
inline bool is_sp_inc(const op_t &x)
{
return x.type == o_phrase
&& issp(x.reg)
&& x.phtype == ph_post;
}
//----------------------------------------------------------------------
static void trace_sp(const insn_t &insn)
{
// @sp++
if ( is_sp_inc(insn.Op1) )
{
int size = 2;
if ( insn.Op2.type == o_reglist )
size *= calc_reglist_count(insn.Op2.reg);
add_stkpnt(insn, size);
return;
}
// @--sp
if ( is_sp_dec(insn.Op2) )
{
int size = 2;
if ( insn.Op1.type == o_reglist )
size *= calc_reglist_count(insn.Op1.reg);
add_stkpnt(insn, -size);
return;
}
// xxx @--sp
if ( is_sp_dec(insn.Op1) )
{
add_stkpnt(insn, -2);
return;
}
int v;
switch ( insn.itype )
{
case H8500_add_g:
case H8500_add_q:
case H8500_adds:
if ( issp(insn.Op2.reg) && get_op_value(insn, insn.Op1, &v) )
add_stkpnt(insn, v);
break;
case H8500_sub:
case H8500_subs:
if ( issp(insn.Op2.reg) && get_op_value(insn, insn.Op1, &v) )
add_stkpnt(insn, -v);
break;
}
}
//----------------------------------------------------------------------
static sval_t calc_func_call_delta(const insn_t &insn, ea_t callee)
{
sval_t delta;
func_t *pfn = get_func(callee);
if ( pfn != NULL )
{
delta = pfn->argsize;
if ( (pfn->flags & FUNC_FAR) != 0 && insn.Op1.type == o_near )
delta += 2; // function will pop the code segment
}
else
{
delta = get_ind_purged(callee);
if ( delta == -1 )
delta = 0;
}
return delta;
}
//----------------------------------------------------------------------
// trace a function call.
// adjuct the stack, determine the execution flow
// returns:
// true - the called function returns to the caller
// false - the called function doesn't return to the caller
static bool handle_function_call(const insn_t &insn, ea_t callee)
{
bool funcflow = true;
if ( !func_does_return(callee) )
funcflow = false;
if ( inf_should_trace_sp() )
{
func_t *caller = get_func(insn.ea);
if ( func_contains(caller, insn.ea+insn.size) )
{
sval_t delta = calc_func_call_delta(insn, callee);
if ( delta != 0 )
add_stkpnt(insn, delta);
}
}
return funcflow;
}
//----------------------------------------------------------------------
inline ea_t find_callee(const insn_t &insn)
{
return get_first_fcref_from(insn.ea);
}
//----------------------------------------------------------------------
void h8500_t::handle_operand(const insn_t &insn, const op_t &x, bool is_forced, bool isload)
{
switch ( x.type )
{
case o_reg:
case o_reglist:
return;
case o_imm:
QASSERT(10090, isload);
process_immediate_number(insn, x.n);
if ( op_adds_xrefs(get_flags(insn.ea), x.n) )
insn.add_off_drefs(x, dr_O, calc_opimm_flags(insn));
break;
case o_phrase:
case o_displ:
{
process_immediate_number(insn, x.n);
if ( is_forced )
break;
flags_t F = get_flags(insn.ea);
if ( op_adds_xrefs(F, x.n) )
{
ea_t ea = insn.add_off_drefs(x, isload ? dr_R : dr_W, calc_opdispl_flags(insn));
if ( ea != BADADDR )
insn.create_op_data(ea, x);
}
// create stack variables if required
if ( x.type == o_displ
&& may_create_stkvars()
&& !is_defarg(F, x.n) )
{
func_t *pfn = get_func(insn.ea);
if ( pfn != NULL
&& (issp(x.phrase)
|| isbp(x.phrase) && (pfn->flags & FUNC_FRAME) != 0) )
{
if ( insn.create_stkvar(x, x.addr, STKVAR_VALID_SIZE) )
op_stkvar(insn.ea, x.n);
}
}
}
break;
case o_near:
case o_far:
{
cref_t ftype = x.type == o_near ? fl_JN : fl_JF;
ea_t ea = calc_mem(insn, x);
if ( has_insn_feature(insn.itype, CF_CALL) )
{
if ( !func_does_return(ea) )
flow = false;
ftype = x.type == o_near ? fl_CN : fl_CF;
}
insn.add_cref(ea, x.offb, ftype);
}
break;
case o_mem:
{
ea_t ea = calc_mem(insn, x);
insn.add_dref(ea, x.offb, isload ? dr_R : dr_W);
insn.create_op_data(ea, x);
}
break;
default:
INTERR(10091);
}
}
//----------------------------------------------------------------------
inline bool is_far_ending(const insn_t &insn)
{
return insn.itype == H8500_prts
|| insn.itype == H8500_prtd;
}
//----------------------------------------------------------------------
int h8500_t::h8500_emu(const insn_t &insn)
{
uint32 Feature = insn.get_canon_feature(ph);
bool flag1 = is_forced_operand(insn.ea, 0);
bool flag2 = is_forced_operand(insn.ea, 1);
bool flag3 = is_forced_operand(insn.ea, 2);
flow = ((Feature & CF_STOP) == 0);
if ( Feature & CF_USE1 ) handle_operand(insn, insn.Op1, flag1, true);
if ( Feature & CF_USE2 ) handle_operand(insn, insn.Op2, flag2, true);
if ( Feature & CF_USE3 ) handle_operand(insn, insn.Op3, flag3, true);
if ( Feature & CF_CHG1 ) handle_operand(insn, insn.Op1, flag1, false);
if ( Feature & CF_CHG2 ) handle_operand(insn, insn.Op2, flag2, false);
if ( Feature & CF_CHG3 ) handle_operand(insn, insn.Op3, flag3, false);
//
// Determine if the next instruction should be executed
//
if ( segtype(insn.ea) == SEG_XTRN )
flow = false;
//
// Handle loads to segment registers
//
sel_t v = BADSEL;
switch ( insn.itype )
{
case H8500_andc:
if ( insn.Op1.value == 0 )
v = 0;
goto SPLIT;
case H8500_orc:
if ( insn.Op1.value == 0xFF )
v = 0xFF;
goto SPLIT;
case H8500_ldc:
if ( insn.Op1.type == o_imm )
v = insn.Op1.value;
// fallthrough
case H8500_xorc:
SPLIT:
if ( insn.Op2.reg >= BR && insn.Op2.reg <= TP )
split_sreg_range(insn.ea+insn.size, insn.Op2.reg, v, SR_auto);
break;
}
if ( (Feature & CF_CALL) != 0 )
{
ea_t callee = find_callee(insn);
if ( !handle_function_call(insn, callee) )
flow = false;
}
//
// Handle SP modifications
//
if ( may_trace_sp() )
{
func_t *pfn = get_func(insn.ea);
if ( pfn != NULL )
{
if ( (pfn->flags & FUNC_USERFAR) == 0
&& (pfn->flags & FUNC_FAR) == 0
&& is_far_ending(insn) )
{
pfn->flags |= FUNC_FAR;
update_func(pfn);
reanalyze_callers(pfn->start_ea, 0);
}
if ( !flow )
recalc_spd(insn.ea); // recalculate SP register for the next insn
else
trace_sp(insn);
}
}
if ( flow )
add_cref(insn.ea, insn.ea+insn.size, fl_F);
return 1;
}
//----------------------------------------------------------------------
int is_jump_func(const func_t * /*pfn*/, ea_t *jump_target)
{
*jump_target = BADADDR;
return 0; // means "don't know"
}
//----------------------------------------------------------------------
int may_be_func(const insn_t &)
{
// if ( insn.itype == H8_push && isbp(insn.Op1.reg) ) return 100; // push.l er6
return 0;
}
//----------------------------------------------------------------------
int is_sane_insn(const insn_t &insn, int /*nocrefs*/)
{
if ( insn.itype == H8500_nop )
{
for ( int i=0; i < 8; i++ )
if ( get_word(insn.ea-i*2) != 0 )
return 1;
return 0; // too many nops in a row
}
return 1;
}
//----------------------------------------------------------------------
int idaapi is_align_insn(ea_t ea)
{
insn_t insn;
if ( decode_insn(&insn, ea) < 1 )
return 0;
switch ( insn.itype )
{
case H8500_nop:
break;
case H8500_mov_g: // B/W Move data
case H8500_mov_e: // B Move data
case H8500_mov_i: // W Move data
case H8500_mov_f: // B/W Move data
case H8500_mov_l: // B/W Move data
case H8500_mov_s: // B/W Move data
case H8500_or:
case H8500_and:
if ( insn.Op1.type == insn.Op2.type && insn.Op1.reg == insn.Op2.reg )
break;
default:
return 0;
}
return insn.size;
}
//----------------------------------------------------------------------
int idaapi h8500_get_frame_retsize(const func_t *pfn)
{
return pfn->flags & FUNC_FAR ? 4 : 2;
}
//----------------------------------------------------------------------
static uval_t find_ret_purged(const func_t *pfn)
{
uval_t argsize = 0;
ea_t ea = pfn->start_ea;
insn_t insn;
while ( ea < pfn->end_ea )
{
decode_insn(&insn, ea);
if ( insn.itype == H8500_rtd || insn.itype == H8500_prtd )
{
argsize = insn.Op1.value;
break;
}
ea = next_that(ea, pfn->end_ea, f_is_code);
}
// could not find any ret instructions
// but the function ends with a jump
if ( ea >= pfn->end_ea
&& (insn.itype == H8500_jmp || insn.itype == H8500_pjmp) )
{
ea_t target = calc_mem(insn, insn.Op1);
pfn = get_func(target);
if ( pfn != NULL )
argsize = pfn->argsize;
}
return argsize;
}
//----------------------------------------------------------------------
static void setup_far_func(func_t *pfn)
{
if ( (pfn->flags & FUNC_FAR) == 0 )
{
ea_t ea1 = pfn->start_ea;
ea_t ea2 = pfn->end_ea;
while ( ea1 < ea2 )
{
if ( is_code(get_flags(ea1)) )
{
insn_t insn;
decode_insn(&insn, ea1);
if ( is_far_ending(insn) )
{
pfn->flags |= FUNC_FAR;
update_func(pfn);
break;
}
}
ea1 = next_head(ea1, ea2);
}
}
}
//----------------------------------------------------------------------
bool idaapi create_func_frame(func_t *pfn)
{
if ( pfn != NULL )
{
setup_far_func(pfn);
uval_t argsize = find_ret_purged(pfn);
add_frame(pfn, 0, 0, argsize);
}
return true;
}

View File

@@ -0,0 +1,122 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-99 by Ilfak Guilfanov.
* ALL RIGHTS RESERVED.
* E-mail: ig@datarescue.com
*
*
*/
#ifndef _H8500_HPP
#define _H8500_HPP
#include "../idaidp.hpp"
#include "ins.hpp"
#include <segregs.hpp>
#include <diskio.hpp>
#define PROCMOD_NAME h8500
#define PROCMOD_NODE_NAME "$ h8/500"
//---------------------------------
// Operand types:
/*
o_reg 1 Register direct Rn
x.reg
o_phrase 2 Register indirect @Rn
x.phrase contains register number
x.phtype contains phrase type (normal, post, pre)
o_displ 3 Register indirect with displacement @(d:8,Rn)/@(d:16,Rn)
x.reg, x.addr, aux_disp16, aux_disp32
o_mem 5 Absolute address @aa:8/@aa:16/@aa:24
x.page, x.addr
o_imm 6 Immediate #xx:8/#xx:16/#xx:32
x.value
o_displ 7 Program-counter relative @(d:8,PC)/@(d:16,PC)
o_reglist Register list
x.reg
*/
#define o_reglist o_idpspec0
#define phtype specflag1 // phrase type:
const int ph_normal = 0; // just simple indirection
const int ph_pre = 1; // predecrement
const int ph_post = 2; // postincrement
#define page specflag1 // o_mem, page number if aux_page
//------------------------------------------------------------------
#define aux_byte 0x0001 // .b postfix
#define aux_word 0x0002 // .w postfix
#define aux_disp8 0x0004 // 8bit displacement
#define aux_disp16 0x0008 // 16bit displacement
#define aux_disp24 0x0010 // 24bit displacement
#define aux_page 0x0020 // implicit page using BR
#define aux_f 0x0040 // /f postfix
#define aux_ne 0x0080 // /ne postfix
#define aux_eq 0x0100 // /eq postfix
#define aux_mov16 0x0200 // mov #xx:16, ...
//------------------------------------------------------------------
enum regnum_t
{
R0, R1, R2, R3, R4, R5, R6, FP=R6, R7, SP=R7,
SR, CCR, RES1, BR, EP, DP, CP, TP, // RES1 is forbidden
};
ea_t calc_mem(const insn_t &insn, const op_t &x); // map virtual to physical ea
//------------------------------------------------------------------
int calc_opimm_flags(const insn_t &insn);
int calc_opdispl_flags(const insn_t &insn);
void idaapi h8500_header(outctx_t &ctx);
void idaapi h8500_segend(outctx_t &ctx, segment_t *seg);
int idaapi is_align_insn(ea_t ea);
bool idaapi create_func_frame(func_t *pfn);
int idaapi is_sp_based(const insn_t &insn, const op_t &x);
int idaapi h8500_get_frame_retsize(const func_t *);
int is_jump_func(const func_t *pfn, ea_t *jump_target);
int is_sane_insn(const insn_t &insn, int nocrefs);
int may_be_func(const insn_t &insn); // can a function start here?
//------------------------------------------------------------------
struct h8500_t : public procmod_t
{
netnode helper;
ioports_t ports;
#define IDP_SAMESIZE 0x0001 // do not disassemble mixed size insns
ushort idpflags = 0;
bool is_mixed_size_insns() const { return (idpflags & IDP_SAMESIZE) == 0; }
bool flow = false;
char show_sizer = -1;
virtual ssize_t idaapi on_event(ssize_t msgid, va_list va) override;
void load_symbols(const char *file);
const char *find_sym(int address);
const char *set_idp_options(
const char *keyword,
int value_type,
const void * value,
bool idb_loaded);
int h8500_ana(insn_t *_insn);
void handle_operand(const insn_t &insn, const op_t &x, bool is_forced, bool isload);
int h8500_emu(const insn_t &insn);
void h8500_assume(outctx_t &ctx);
void h8500_segstart(outctx_t &ctx, segment_t *Srange) const;
void h8500_footer(outctx_t &ctx) const;
void save_idpflags() { helper.altset(-1, idpflags); }
void load_from_idb();
};
extern int data_id;
#endif // _H8500_HPP

View File

@@ -0,0 +1,127 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2000 by Ilfak Guilfanov.
* ALL RIGHTS RESERVED.
* E-mail: ig@datarescue.com
*
*
*/
#include "h8500.hpp"
const instruc_t Instructions[] =
{
{ "", 0 }, // Unknown Operation
// Data transfer
{ "mov:g", CF_USE1|CF_CHG2 }, // B/W Move data
{ "mov:e", CF_USE1|CF_CHG2 }, // B Move data
{ "mov:i", CF_USE1|CF_CHG2 }, // W Move data
{ "mov:f", CF_USE1|CF_CHG2 }, // B/W Move data
{ "mov:l", CF_USE1|CF_CHG2 }, // B/W Move data
{ "mov:s", CF_USE1|CF_CHG2 }, // B/W Move data
{ "ldm", CF_USE1|CF_CHG2 }, // W Pop data from the stack to one or more registers
{ "stm", CF_USE1|CF_CHG2 }, // W Push data from one or more registers onto the stack
{ "xch", CF_USE1|CF_USE2|CF_CHG1|CF_CHG2 }, // W Exchange data between two general registers
{ "swap", CF_USE1|CF_CHG1 }, // B Exchange the upper and lower bytes in a general register
{ "movtpe", CF_USE1|CF_CHG2 }, // B Transfer data from a general register to memory
{ "movfpe", CF_USE1|CF_CHG2 }, // B Transfer data from memory to a general register
// Arithmetic operations
{ "add:g", CF_USE1|CF_USE2|CF_CHG2 }, // B/W Addition
{ "add:q", CF_USE1|CF_USE2|CF_CHG2 }, // B/W Addition
{ "sub", CF_USE1|CF_USE2|CF_CHG2 }, // B/W Subtraction
{ "adds", CF_USE1|CF_USE2|CF_CHG2 }, // B/W Addition
{ "subs", CF_USE1|CF_USE2|CF_CHG2 }, // B/W Subtraction
{ "addx", CF_USE1|CF_USE2|CF_CHG2 }, // B/W Addition with carry
{ "subx", CF_USE1|CF_USE2|CF_CHG2 }, // B/W Subtraction with borrow
{ "dadd", CF_USE1|CF_USE2|CF_CHG2 }, // B Decimal addition
{ "dsub", CF_USE1|CF_USE2|CF_CHG2 }, // B Decimal subtraction
{ "mulxu", CF_USE1|CF_USE2|CF_CHG2 }, // B/W Unsigned multiplication
{ "divxu", CF_USE1|CF_USE2|CF_CHG2 }, // B/W Unsigned division
{ "cmp:g", CF_USE1|CF_USE2 }, // B/W Compare data
{ "cmp:e", CF_USE1|CF_USE2 }, // B Compare data
{ "cmp:i", CF_USE1|CF_USE2 }, // W Compare data
{ "exts", CF_USE1|CF_CHG1 }, // B Convert byte to word by extending the sign bit
{ "extu", CF_USE1|CF_CHG1 }, // B Convert byte to word data by padding with zero bits
{ "tst", CF_USE1 }, // B/W Compare with 0
{ "neg", CF_USE1|CF_CHG1 }, // B/W Negate
{ "clr", CF_CHG1 }, // B/W Make zero
{ "tas", CF_USE1|CF_CHG1 }, // B Test and set
// Logic Operations
{ "and", CF_USE1|CF_USE2|CF_CHG2 }, // B/W Logical AND
{ "or", CF_USE1|CF_USE2|CF_CHG2 }, // B/W Logical OR
{ "xor", CF_USE1|CF_USE2|CF_CHG2 }, // B/W Exclusive OR
{ "not", CF_USE1|CF_CHG1 }, // B/W Bitwise NOT
// Shift Operations
{ "shal", CF_USE1|CF_CHG1 }, // B/W Arithmetic shift left
{ "shar", CF_USE1|CF_CHG1 }, // B/W Arithmetic shift right
{ "shll", CF_USE1|CF_CHG1 }, // B/W Logical shift left
{ "shlr", CF_USE1|CF_CHG1 }, // B/W Logical shift right
{ "rotl", CF_USE1|CF_CHG1 }, // B/W Rotate left
{ "rotr", CF_USE1|CF_CHG1 }, // B/W Rotate right
{ "rotxl", CF_USE1|CF_CHG1 }, // B/W Rotate through carry left
{ "rotxr", CF_USE1|CF_CHG1 }, // B/W Rotate through carry right
// Bit Manipulations
{ "bset", CF_USE1|CF_USE2|CF_CHG2 }, // B/W Test bit and set
{ "bclr", CF_USE1|CF_USE2|CF_CHG2 }, // B/W Test bit and clear
{ "bnot", CF_USE1|CF_USE2|CF_CHG2 }, // B/W Test bit and invert
{ "btst", CF_USE1|CF_USE2 }, // B/W Test bit
// Branching Instructions
{ "bra", CF_USE1|CF_STOP }, // Branch Always
{ "brn", CF_USE1 }, // Branch Never
{ "bhi", CF_USE1 }, // Branch if High (C|Z = 0)
{ "bls", CF_USE1 }, // Branch if Low or Same (C|Z = 1)
{ "bcc", CF_USE1 }, // Branch if Carry Clear (C = 0)
{ "bcs", CF_USE1 }, // Branch if Carry Set (C = 1)
{ "bne", CF_USE1 }, // Branch if Not Equal (Z = 0)
{ "beq", CF_USE1 }, // Branch if Equal (Z = 1)
{ "bvc", CF_USE1 }, // Branch if Overflow Clear (V = 0)
{ "bvs", CF_USE1 }, // Branch if Overflow Set (V = 1)
{ "bpl", CF_USE1 }, // Branch if Plus (N = 0)
{ "bmi", CF_USE1 }, // Branch if Minus (N = 1)
{ "bge", CF_USE1 }, // Branch if Greater or Equal (N^V = 0)
{ "blt", CF_USE1 }, // Branch if Less Than (N^V = 1)
{ "bgt", CF_USE1 }, // Branch if Greater Than (Z|(N^V) = 0)
{ "ble", CF_USE1 }, // Branch if Less or Equal (Z|(N^V) = 1)
{ "jmp", CF_USE1|CF_STOP }, // Branch unconditionally (same page)
{ "pjmp", CF_USE1|CF_STOP }, // Branch unconditionally (specified page)
{ "bsr", CF_USE1|CF_CALL }, // Branch to subroutine (same page)
{ "jsr", CF_USE1|CF_CALL }, // Branch to subroutine (same page)
{ "pjsr", CF_USE1|CF_CALL }, // Branch to subroutine (specified page)
{ "rts", CF_STOP }, // Return from subroutine (same page)
{ "prts", CF_STOP }, // Return from subroutine (different page)
{ "rtd", CF_USE1|CF_STOP }, // Return from subroutine (same page) and adjust SP
{ "prtd", CF_USE1|CF_STOP }, // Return from subroutine (different page) and adjust SP
{ "scb", CF_USE1|CF_USE2 }, // Control loop
// System Control Instructions
{ "trapa", CF_USE1 }, // Generate trap exception
{ "trap/vs", 0 }, // Generate trap exception if the V bit is set
{ "rte", CF_STOP }, // Return from exception-handling routine
{ "link", CF_USE1|CF_USE2 }, // Create stack frame
{ "unlk", 0 }, // Deallocate stack frame
{ "sleep", 0 }, // Go to power-down state
{ "ldc", CF_USE1|CF_CHG2 }, // B/W Move to control register
{ "stc", CF_USE1|CF_CHG2 }, // B/W Move from control register
{ "andc", CF_USE1|CF_USE2|CF_CHG2 }, // B/W Logically AND control register
{ "orc", CF_USE1|CF_USE2|CF_CHG2 }, // B/W Logically OR control register
{ "xorc", CF_USE1|CF_USE2|CF_CHG2 }, // B/W Logically exclusive-OR control register
{ "nop", 0 }, // No operation
{ "bpt", 0 }, //
};
CASSERT(qnumber(Instructions) == H8500_last);

View File

@@ -0,0 +1,130 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2021 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef __INSTRS_HPP
#define __INSTRS_HPP
extern const instruc_t Instructions[];
enum nameNum
{
H8500_null = 0, // Unknown Operation
// Data transfer
H8500_mov_g, // B/W Move data
H8500_mov_e, // B Move data
H8500_mov_i, // W Move data
H8500_mov_f, // B/W Move data
H8500_mov_l, // B/W Move data
H8500_mov_s, // B/W Move data
H8500_ldm, // W Pop data from the stack to one or more registers
H8500_stm, // W Push data from one or more registers onto the stack
H8500_xch, // W Exchange data between two general registers
H8500_swap, // B Exchange the upper and lower bytes in a general register
H8500_movtpe, // B Transfer data from a general register to memory
H8500_movfpe, // B Transfer data from memory to a general register
// Arithmetic operations
H8500_add_g, // B/W Addition
H8500_add_q, // B/W Addition
H8500_sub, // B/W Subtraction
H8500_adds, // B/W Addition
H8500_subs, // B/W Subtraction
H8500_addx, // B/W Addition with carry
H8500_subx, // B/W Subtraction with borrow
H8500_dadd, // B Decimal addition
H8500_dsub, // B Decimal subtraction
H8500_mulxu, // B/W Unsigned multiplication
H8500_divxu, // B/W Unsigned division
H8500_cmp_g, // B/W Compare data
H8500_cmp_e, // B Compare data
H8500_cmp_i, // W Compare data
H8500_exts, // B Convert byte to word by extending the sign bit
H8500_extu, // B Convert byte to word data by padding with zero bits
H8500_tst, // B/W Compare with 0
H8500_neg, // B/W Negate
H8500_clr, // B/W Make zero
H8500_tas, // B Test and set
// Logic Operations
H8500_and, // B/W Logical AND
H8500_or, // B/W Logical OR
H8500_xor, // B/W Exclusive OR
H8500_not, // B/W Bitwise NOT
// Shift Operations
H8500_shal, // B/W Arithmetic shift left
H8500_shar, // B/W Arithmetic shift right
H8500_shll, // B/W Logical shift left
H8500_shlr, // B/W Logical shift right
H8500_rotl, // B/W Rotate left
H8500_rotr, // B/W Rotate right
H8500_rotxl, // B/W Rotate through carry left
H8500_rotxr, // B/W Rotate through carry right
// Bit Manipulations
H8500_bset, // B/W Test bit and set
H8500_bclr, // B/W Test bit and clear
H8500_bnot, // B/W Test bit and invert
H8500_btst, // B/W Test bit
// Branching Instructions
H8500_bra, // Branch Always
H8500_brn, // Branch Never
H8500_bhi, // Branch if High (C|Z = 0)
H8500_bls, // Branch if Low or Same (C|Z = 1)
H8500_bcc, // Branch if Carry Clear (C = 0)
H8500_bcs, // Branch if Carry Set (C = 1)
H8500_bne, // Branch if Not Equal (Z = 0)
H8500_beq, // Branch if Equal (Z = 1)
H8500_bvc, // Branch if Overflow Clear (V = 0)
H8500_bvs, // Branch if Overflow Set (V = 1)
H8500_bpl, // Branch if Plus (N = 0)
H8500_bmi, // Branch if Minus (N = 1)
H8500_bge, // Branch if Greater or Equal (N^V = 0)
H8500_blt, // Branch if Less Than (N^V = 1)
H8500_bgt, // Branch if Greater Than (Z|(N^V) = 0)
H8500_ble, // Branch if Less or Equal (Z|(N^V) = 1)
H8500_jmp, // Branch unconditionally (same page)
H8500_pjmp, // Branch unconditionally (specified page)
H8500_bsr, // Branch to subroutine (same page)
H8500_jsr, // Branch to subroutine (same page)
H8500_pjsr, // Branch to subroutine (specified page)
H8500_rts, // Return from subroutine (same page)
H8500_prts, // Return from subroutine (different page)
H8500_rtd, // Return from subroutine (same page) and adjust SP
H8500_prtd, // Return from subroutine (different page) and adjust SP
H8500_scb, // Control loop
// System Control Instructions
H8500_trapa, // Generate trap exception
H8500_trap_vs, // Generate trap exception if the V bit is set
H8500_rte, // Return from exception-handling routine
H8500_link, // Create stack frame
H8500_unlk, // Deallocate stack frame
H8500_sleep, // Go to power-down state
H8500_ldc, // B/W Move to control register
H8500_stc, // B/W Move from control register
H8500_andc, // B/W Logically AND control register
H8500_orc, // B/W Logically OR control register
H8500_xorc, // B/W Logically exclusive-OR control register
H8500_nop, // No operation
H8500_bpt, //
H8500_last,
};
#endif

View File

@@ -0,0 +1,51 @@
PROC=h8500
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)fpro.h \
$(I)funcs.hpp $(I)ida.hpp $(I)idp.hpp $(I)ieee.h \
$(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 \
ana.cpp h8500.hpp ins.hpp
$(F)emu$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)diskio.hpp $(I)fpro.h \
$(I)frame.hpp $(I)funcs.hpp $(I)ida.hpp $(I)idp.hpp \
$(I)ieee.h $(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 \
emu.cpp h8500.hpp ins.hpp
$(F)ins$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)diskio.hpp $(I)fpro.h \
$(I)funcs.hpp $(I)ida.hpp $(I)idp.hpp $(I)ieee.h \
$(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 \
h8500.hpp ins.cpp ins.hpp
$(F)out$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)diskio.hpp $(I)fpro.h \
$(I)funcs.hpp $(I)ida.hpp $(I)idp.hpp $(I)ieee.h \
$(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 \
h8500.hpp ins.hpp out.cpp
$(F)reg$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)diskio.hpp $(I)fpro.h \
$(I)funcs.hpp $(I)ida.hpp $(I)idp.hpp $(I)ieee.h \
$(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 \
h8500.hpp ins.hpp reg.cpp

View File

@@ -0,0 +1,409 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-99 by Ilfak Guilfanov.
* ALL RIGHTS RESERVED.
* E-mail: ig@datarescue.com
*
*
*/
#include "h8500.hpp"
#include <segregs.hpp>
//----------------------------------------------------------------------
class out_h8500_t : public outctx_t
{
out_h8500_t(void) = delete; // not used
public:
void outreg(int r) { out_register(ph.reg_names[r]); }
void out_bad_address(ea_t addr);
void out_sizer(const op_t &x);
void out_reglist(int reg, int cnt);
bool out_operand(const op_t &x);
void out_insn(void);
void out_proc_mnem(void);
};
CASSERT(sizeof(out_h8500_t) == sizeof(outctx_t));
DECLARE_OUT_FUNCS(out_h8500_t)
//----------------------------------------------------------------------
void out_h8500_t::out_bad_address(ea_t addr)
{
h8500_t &pm = *static_cast<h8500_t *>(procmod);
const char *name = pm.find_sym((int)addr);
if ( name != NULL && name[0] != '\0' )
{
out_line(name, COLOR_IMPNAME);
}
else
{
out_tagon(COLOR_ERROR);
out_btoa(addr, 16);
out_tagoff(COLOR_ERROR);
remember_problem(PR_NONAME, insn.ea);
}
}
//----------------------------------------------------------------------
static int calc_sizer(const insn_t &insn, const op_t &x)
{
if ( insn.itype == H8500_mov_g && x.type == o_imm )
return insn.auxpref & aux_mov16 ? 16 : 8;
// special case: cmp:g.b #x:8, @(d:16,r)
// special case: cmp:g.w #x:16, @(d:8,r)
else if ( insn.itype == H8500_cmp_g && x.type == o_imm )
return insn.auxpref & aux_word ? 16 : 8;
else
return (insn.auxpref & aux_disp24) ? 24 : (insn.auxpref & aux_disp16) ? 16 : 8;
}
//----------------------------------------------------------------------
ea_t calc_mem(const insn_t &insn, const op_t &x)
{
if ( x.type == o_near )
return to_ea(insn.cs, x.addr);
// Before this was simply to_ea, now we do it like this:
// (if someone complains, both methods should be retained)
ea_t ea = x.addr;
switch ( calc_sizer(insn, x) )
{
case 8:
if ( insn.auxpref & aux_page )
{
ea &= 0xFF;
sel_t br = get_sreg(insn.ea, BR);
if ( br != BADSEL )
ea |= br << 8;
else
ea = BADADDR;
}
break;
case 16:
ea &= 0xFFFF;
if ( x.type == o_mem )
{
sel_t dp = get_sreg(insn.ea, DP);
if ( dp != BADSEL )
ea |= dp << 16;
else
ea = BADADDR;
}
else
{
ea |= insn.ea & ~0xFFFF;
}
break;
}
return ea;
}
//----------------------------------------------------------------------
void out_h8500_t::out_sizer(const op_t &x)
{
h8500_t &pm = *static_cast<h8500_t *>(procmod);
if ( pm.show_sizer == -1 )
pm.show_sizer = !qgetenv("H8_NOSIZER");
if ( !pm.show_sizer )
return;
if ( (insn.auxpref & (aux_disp8|aux_disp16|aux_disp24)) == 0 )
return;
out_symbol(':');
// 1D 00 11 07 00 01 mov:g.w #1:16, @0x11:16
// 1D 00 11 06 01 mov:g.w #1:16, @0x11:16
// 0D 11 07 00 01 mov:g.w #1:8, @0x11:8
// 0D 11 06 01 mov:g.w #1:8, @0x11:8
// 0D 11 07 00 01 mov:g.w #1:8, @0x11:8
// 1D 00 11 07 00 01 mov:g.w #1:16, @0x11:16
// 15 00 11 06 01 mov:g.b #1:16, @0x11:16
// 05 11 06 01 mov:g.b #1:8, @0x11:8
int s = calc_sizer(insn, x);
out_long(s, 10);
}
//----------------------------------------------------------------------
void out_h8500_t::out_reglist(int reg, int cnt)
{
int bit = 1;
int delayed = -1;
int first = 1;
for ( int i=0; i <= cnt; i++,bit<<=1 )
{
if ( (reg & bit) == 0 )
{
if ( delayed >= 0 )
{
if ( !first )
out_symbol(',');
if ( delayed == (i-1) )
{
outreg(delayed);
}
else if ( delayed == (i-2) )
{
outreg(delayed);
out_symbol(',');
outreg(delayed+1);
}
else
{
outreg(delayed);
out_symbol('-');
outreg(i-1);
}
delayed = -1;
first = 0;
}
}
else
{
if ( delayed < 0 )
delayed = i;
}
}
}
//----------------------------------------------------------------------
int calc_opimm_flags(const insn_t &insn)
{
bool sign = insn.itype == H8500_add_q
|| insn.itype == H8500_adds
|| insn.itype == H8500_subs;
return OOFS_IFSIGN|OOFW_IMM|(sign ? OOF_SIGNED : 0);
}
//----------------------------------------------------------------------
int calc_opdispl_flags(const insn_t &insn)
{
bool sign = (insn.auxpref & aux_disp8) != 0;
return OOF_ADDR | OOFS_IFSIGN | (sign ? OOF_SIGNED : 0)
| (insn.auxpref & aux_disp24 ? OOFW_32
: insn.auxpref & aux_disp16 ? OOFW_16
: OOFW_8);
}
//----------------------------------------------------------------------
bool out_h8500_t::out_operand(const op_t &x)
{
switch ( x.type )
{
case o_void:
return 0;
case o_reg:
outreg(x.reg);
break;
case o_reglist:
out_symbol('(');
out_reglist(x.reg, 8);
out_symbol(')');
break;
case o_imm:
out_symbol('#');
out_value(x, calc_opimm_flags(insn));
out_sizer(x);
break;
case o_mem:
out_symbol('@');
// fallthrough
case o_near:
case o_far:
{
ea_t ea = calc_mem(insn, x);
if ( !out_name_expr(x, ea, BADADDR) )
out_bad_address(x.addr);
out_sizer(x);
}
break;
case o_phrase:
if ( x.phtype == ph_normal )
{
bool outdisp = is_off(F, x.n)
|| is_stkvar(F, x.n)
|| is_enum(F, x.n)
|| is_stroff(F, x.n);
if ( outdisp )
goto OUTDISP;
}
out_symbol('@');
if ( x.phtype == ph_pre )
out_symbol('-');
outreg(x.phrase);
if ( x.phtype == ph_post )
out_symbol('+');
break;
case o_displ:
OUTDISP:
out_symbol('@');
out_symbol('(');
out_value(x, calc_opdispl_flags(insn));
out_sizer(x);
out_symbol(',');
outreg(x.reg);
out_symbol(')');
break;
default:
INTERR(10099);
}
return 1;
}
//----------------------------------------------------------------------
void out_h8500_t::out_proc_mnem(void)
{
const char *postfix = NULL;
if ( insn.auxpref & aux_byte )
postfix = ".b";
else if ( insn.auxpref & aux_word )
postfix = ".w";
else if ( insn.auxpref & aux_f )
postfix = "/f";
else if ( insn.auxpref & aux_ne )
postfix = "/ne";
else if ( insn.auxpref & aux_eq )
postfix = "/eq";
out_mnem(8, postfix);
}
//----------------------------------------------------------------------
void out_h8500_t::out_insn(void)
{
out_mnemonic();
out_one_operand(0);
if ( insn.Op2.type != o_void )
{
out_symbol(',');
out_char(' ');
out_one_operand(1);
}
out_immchar_cmts();
flush_outbuf();
}
//--------------------------------------------------------------------------
//lint -esym(1764, ctx) could be made const
//lint -esym(818, Srange) could be made const
void h8500_t::h8500_segstart(outctx_t &ctx, segment_t *Srange) const
{
const char *predefined[] =
{
".text", // Text section
".rdata", // Read-only data section
".data", // Data sections
".lit8", // Data sections
".lit4", // Data sections
".sdata", // Small data section, addressed through register $gp
".sbss", // Small bss section, addressed through register $gp
".bss", // bss (block started by storage) section, which loads zero-initialized data
};
if ( is_spec_segm(Srange->type) )
return;
qstring sname;
qstring sclas;
get_segm_name(&sname, Srange);
get_segm_class(&sclas, Srange);
if ( !print_predefined_segname(ctx, &sname, predefined, qnumber(predefined)) )
ctx.gen_printf(DEFAULT_INDENT,
COLSTR("%s", SCOLOR_ASMDIR) "" COLSTR("%s %s", SCOLOR_AUTOCMT),
sclas == "CODE" ? ".text" :
sclas == "BSS" ? ".bss" :
".data",
ash.cmnt,
sname.c_str());
if ( Srange->orgbase != 0 )
{
char buf[MAX_NUMBUF];
btoa(buf, sizeof(buf), Srange->orgbase);
ctx.gen_printf(DEFAULT_INDENT, COLSTR("%s %s", SCOLOR_ASMDIR), ash.origin, buf);
}
}
//--------------------------------------------------------------------------
void idaapi h8500_segend(outctx_t &, segment_t *)
{
}
//--------------------------------------------------------------------------
//lint -esym(1764, ctx) could be made const
void h8500_t::h8500_assume(outctx_t &ctx)
{
ea_t ea = ctx.insn_ea;
segment_t *seg = getseg(ea);
if ( (inf_get_outflags() & OFLG_GEN_ASSUME) == 0 || seg == NULL )
return;
bool seg_started = (ea == seg->start_ea);
for ( int i=ph.reg_first_sreg; i <= ph.reg_last_sreg; i++ )
{
if ( i == ph.reg_code_sreg )
continue;
sreg_range_t sra;
if ( !get_sreg_range(&sra, ea, i) )
continue;
bool show = sra.start_ea == ea;
if ( show )
{
sreg_range_t prev_sra;
if ( get_prev_sreg_range(&prev_sra, ea, i) )
show = sra.val != prev_sra.val;
}
if ( seg_started || show )
{
if ( ctx.outbuf.empty() )
{
ctx.out_tagon(COLOR_AUTOCMT);
ctx.out_line(ash.cmnt);
ctx.out_line(" assume ");
}
else
{
ctx.out_line(", ");
}
ctx.out_line(ph.reg_names[i]);
ctx.out_char(':');
if ( sra.val == BADSEL )
ctx.out_line("nothing");
else
ctx.out_btoa(sra.val, 16);
}
}
if ( !ctx.outbuf.empty() )
{
ctx.out_tagoff(COLOR_AUTOCMT);
ctx.flush_outbuf(DEFAULT_INDENT);
}
}
//--------------------------------------------------------------------------
void idaapi h8500_header(outctx_t &ctx)
{
ctx.gen_header(GH_PRINT_ALL);
ctx.gen_empty_line();
}
//--------------------------------------------------------------------------
void h8500_t::h8500_footer(outctx_t &ctx) const
{
qstring nbuf = get_colored_name(inf_get_start_ea());
const char *name = nbuf.c_str();
const char *end = ash.end;
if ( end == NULL )
ctx.gen_printf(DEFAULT_INDENT, COLSTR("%s end %s",SCOLOR_AUTOCMT), ash.cmnt, name);
else
ctx.gen_printf(DEFAULT_INDENT,
COLSTR("%s",SCOLOR_ASMDIR) " " COLSTR("%s %s",SCOLOR_AUTOCMT),
ash.end, ash.cmnt, name);
}

View File

@@ -0,0 +1,506 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-99 by Ilfak Guilfanov.
* ALL RIGHTS RESERVED.
* E-mail: ig@datarescue.com
*
*
*/
#include "h8500.hpp"
#include <fpro.h>
#include <diskio.hpp>
#include <ieee.h>
int data_id;
//--------------------------------------------------------------------------
static const char *const register_names[] =
{
"r0", "r1", "r2", "r3", "r4", "r5", "fp", "sp",
"sr", "ccr", "?", "br", "ep", "dp", "cp", "tp",
};
//--------------------------------------------------------------------------
static const uchar retcode_0[] = { 0x56, 0x70 }; // rte
static const uchar retcode_1[] = { 0x54, 0x70 }; // rts
static const bytes_t retcodes[] =
{
{ sizeof(retcode_0), retcode_0 },
{ sizeof(retcode_1), retcode_1 },
{ 0, NULL }
};
//------------------------------------------------------------------
static void idaapi func_header(outctx_t &ctx, func_t *pfn)
{
ctx.gen_func_header(pfn);
if ( ctx.curlabel.empty() )
return;
ctx.gen_printf(0, "%s" COLSTR(":", SCOLOR_SYMBOL) " "
SCOLOR_ON SCOLOR_AUTOCMT
"%s %s"
SCOLOR_OFF SCOLOR_AUTOCMT,
ctx.curlabel.begin(),
ASH.cmnt,
(pfn->flags & FUNC_FAR) != 0 ? "far" : "near");
ctx.ctxflags |= CTXF_LABEL_OK;
}
//-----------------------------------------------------------------------
// GNU ASM
//-----------------------------------------------------------------------
static const asm_t gas =
{
AS_ASCIIC|ASH_HEXF3|ASD_DECF0|ASB_BINF3|ASO_OCTF1|AS_COLON|AS_N2CHR|AS_NCMAS|AS_ONEDUP,
0,
"GNU assembler",
0,
NULL, // header lines
".org", // org
NULL, // end
"!", // comment string
'"', // string delimiter
'"', // char delimiter
"\"", // special symbols in char and string constants
".ascii", // ascii string directive
".byte", // byte directive
".word", // word directive
".long", // double words
NULL, // qwords
NULL, // oword (16 bytes)
".float", // float (4 bytes)
NULL, // double (8 bytes)
NULL, // tbyte (10/12 bytes)
NULL, // packed decimal real
NULL, // arrays (#h,#d,#v,#s(...)
".space %s", // uninited arrays
"=", // equ
NULL, // 'seg' prefix (example: push seg seg001)
NULL, // current IP (instruction pointer)
func_header, // func_header
NULL, // func_footer
".globl", // "public" name keyword
NULL, // "weak" name keyword
".extern", // "extrn" name keyword
// .extern directive requires an explicit object size
".comm", // "comm" (communal variable)
NULL, // get_type_name
".align", // "align" keyword
'(', ')', // lbrace, rbrace
"%", // mod
"&", // and
"|", // or
"^", // xor
"~", // not
"<<", // shl
">>", // shr
NULL, // sizeof
AS2_COLONSUF, // flag2
NULL, // cmnt2
NULL, // low8
NULL, // high8
NULL, // low16
NULL, // high16
"#include \"%s\"", // a_include_fmt
};
static const asm_t *const asms[] = { &gas, NULL };
//--------------------------------------------------------------------------
void h8500_t::load_symbols(const char *file)
{
ports.clear();
// KLUDGE: read_ioports() will complain if the file is
// not present, but we don't want that.
char cfgpath[QMAXPATH];
const char *rfile = getsysfile(cfgpath, sizeof(cfgpath), file, CFG_SUBDIR);
if ( rfile != NULL )
read_ioports(&ports, NULL, file);
}
//--------------------------------------------------------------------------
const char *h8500_t::find_sym(int address)
{
const ioport_t *port = find_ioport(ports, address);
return port != NULL ? port->name.c_str() : NULL;
}
//-------------------------------------------------------------------------
void h8500_t::load_from_idb()
{
// in old databases we store 0 for the "mixed size" flag and -1 for the
// "same size" flag. Now we store 1 for the latter.
uval_t flags = helper.altval(-1);
idpflags = flags == 0 ? 0 : IDP_SAMESIZE;
}
//------------------------------------------------------------------
const char *h8500_t::set_idp_options(
const char *keyword,
int value_type,
const void * value,
bool idb_loaded)
{
static const char form[] =
"HELP\n"
"H8/500 specific analyzer options\n"
"\n"
"Disassemble mixed size instructions\n"
"\n"
" According to the documentation, instructions like\n"
"\n"
" cmp:g.b #1:16, @0x222:16\n"
"\n"
" are not allowed. The correct instruction is:\n"
"\n"
" cmp:g.b #1:8, @0x222:16\n"
"\n"
" The size of the first operand should agree with the size\n"
" of the instruction. (exception mov:g)\n"
"\n"
"ENDHELP\n"
"H8/500 specific analyzer options\n"
"\n"
// m
" <Disassemble ~m~ixed size instructions:C>>\n"
"\n"
"\n";
if ( keyword != nullptr )
{
if ( streq(keyword, "H8500_MIXED_SIZE") )
{
if ( value_type != IDPOPT_BIT )
return IDPOPT_BADTYPE;
// we store in IDPFLAGS the negation of the mixed size flag
setflag(idpflags, IDP_SAMESIZE, *(int*)value == 0);
}
else
{
return IDPOPT_BADKEY;
}
}
else
{
// we store in IDPFLAGS the negation of the mixed size flag
ushort flags = 0;
if ( is_mixed_size_insns() )
flags |= 1;
ask_form(form, &flags);
idpflags = 0;
if ( (flags & 1) == 0 )
idpflags |= IDP_SAMESIZE;
}
if ( idb_loaded )
save_idpflags();
return IDPOPT_OK;
}
//-----------------------------------------------------------------------
#define FAMILY "Hitachi H8/500:"
static const char *const shnames[] = { "h8500", NULL };
static const char *const lnames[] =
{
FAMILY"Hitachi H8/500",
NULL
};
//-----------------------------------------------------------------------
// temporary solution for v4.7
static ea_t idaapi h8_extract_address(ea_t screen_ea, const char *string, size_t x)
{
size_t len = strlen(string);
if ( len == 0 || x > len )
return BADADDR;
if ( x == len )
x--;
const char *ptr = string + x;
while ( ptr > string && qisxdigit(ptr[-1]) )
ptr--;
const char *start = ptr;
while ( qisxdigit(ptr[0]) )
ptr++;
len = ptr - start;
char buf[MAXSTR];
memcpy(buf, start, len);
buf[len] = '\0';
ea_t ea = BADADDR;
str2ea(&ea, buf, screen_ea);
return ea;
}
//------------------------------------------------------------------------
static bool idaapi can_have_type(const op_t &x) // returns 1 - operand can have
{
switch ( x.type )
{
case o_void:
case o_reg:
case o_reglist:
return false;
case o_phrase:
return x.phtype == ph_normal;
}
return true;
}
//----------------------------------------------------------------------
// 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(SET_MODULE_DATA(h8500_t));
return 0;
}
//--------------------------------------------------------------------------
ssize_t idaapi h8500_t::on_event(ssize_t msgid, va_list va)
{
int code = 0;
switch ( msgid )
{
case processor_t::ev_init:
helper.create(PROCMOD_NODE_NAME);
inf_set_be(true);
load_symbols("h8500.cfg");
break;
case processor_t::ev_term:
ports.clear();
clr_module_data(data_id);
break;
case processor_t::ev_newfile: // new file loaded
save_idpflags();
break;
case processor_t::ev_ending_undo:
case processor_t::ev_oldfile: // old file loaded
load_from_idb();
break;
case processor_t::ev_creating_segm: // new segment
{
segment_t *sptr = va_arg(va, segment_t *);
sptr->defsr[BR-ph.reg_first_sreg] = 0;
sptr->defsr[DP-ph.reg_first_sreg] = 0;
}
break;
case processor_t::ev_is_jump_func:
{
const func_t *pfn = va_arg(va, const func_t *);
ea_t *jump_target = va_arg(va, ea_t *);
return is_jump_func(pfn, jump_target);
}
case processor_t::ev_is_sane_insn:
{
const insn_t *insn = va_arg(va, insn_t *);
int no_crefs = va_arg(va, int);
return is_sane_insn(*insn, no_crefs) == 1 ? 1 : -1;
}
case processor_t::ev_may_be_func:
{
const insn_t *insn = va_arg(va, insn_t *);
return may_be_func(*insn);
}
case processor_t::ev_out_mnem:
{
outctx_t *ctx = va_arg(va, outctx_t *);
out_mnem(*ctx);
return 1;
}
case processor_t::ev_out_header:
{
outctx_t *ctx = va_arg(va, outctx_t *);
h8500_header(*ctx);
return 1;
}
case processor_t::ev_out_footer:
{
outctx_t *ctx = va_arg(va, outctx_t *);
h8500_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 *);
h8500_segstart(*ctx, seg);
return 1;
}
case processor_t::ev_out_segend:
{
outctx_t *ctx = va_arg(va, outctx_t *);
segment_t *seg = va_arg(va, segment_t *);
h8500_segend(*ctx, seg);
return 1;
}
case processor_t::ev_out_assumes:
{
outctx_t *ctx = va_arg(va, outctx_t *);
h8500_assume(*ctx);
return 1;
}
case processor_t::ev_ana_insn:
{
insn_t *out = va_arg(va, insn_t *);
return h8500_ana(out);
}
case processor_t::ev_emu_insn:
{
const insn_t *insn = va_arg(va, const insn_t *);
return h8500_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_can_have_type:
{
const op_t *op = va_arg(va, const op_t *);
return can_have_type(*op) ? 1 : -1;
}
case processor_t::ev_extract_address:
{
ea_t *out_ea = va_arg(va, ea_t *);
ea_t screen_ea = va_arg(va, ea_t);
const char *str = va_arg(va, const char *);
size_t pos = va_arg(va, size_t);
ea_t ea = h8_extract_address(screen_ea, str, pos);
if ( ea == BADADDR )
return -1;
if ( ea == (BADADDR-1) )
return 0;
*out_ea = ea;
return 1;
}
case processor_t::ev_is_sp_based:
{
int *mode = va_arg(va, int *);
const insn_t *insn = va_arg(va, const insn_t *);
const op_t *op = va_arg(va, const op_t *);
*mode = is_sp_based(*insn, *op);
return 1;
}
case processor_t::ev_create_func_frame:
{
func_t *pfn = va_arg(va, func_t *);
create_func_frame(pfn);
return 1;
}
case processor_t::ev_get_frame_retsize:
{
int *frsize = va_arg(va, int *);
const func_t *pfn = va_arg(va, const func_t *);
*frsize = h8500_get_frame_retsize(pfn);
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;
}
case processor_t::ev_is_align_insn:
{
ea_t ea = va_arg(va, ea_t);
return is_align_insn(ea);
}
default:
break;
}
return code;
}
//-----------------------------------------------------------------------
// Processor Definition
//-----------------------------------------------------------------------
processor_t LPH =
{
IDP_INTERFACE_VERSION, // version
PLFM_H8500, // id
// flag
PRN_HEX
| PR_SEGS
| PR_SGROTHER,
// 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,
lnames,
asms,
notify,
register_names, // Register names
qnumber(register_names), // Number of registers
BR, // first
TP, // last
1, // size of a segment register
CP, DP,
NULL, // No known code start sequences
retcodes,
H8500_null,
H8500_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
H8500_rts, // Icode of return instruction. It is ok to give any of possible return instructions
};