823 lines
22 KiB
C++
823 lines
22 KiB
C++
/*
|
|
* Interactive disassembler (IDA)
|
|
* Copyright (c) 1990-98 by Ilfak Guilfanov.
|
|
* E-mail: ig@datarescue.com
|
|
* JVM module.
|
|
* Copyright (c) 1995-2006 by Iouri Kharon.
|
|
* E-mail: yjh@styx.cabel.net
|
|
*
|
|
* ALL RIGHTS RESERVED.
|
|
*
|
|
*/
|
|
|
|
#include "java.hpp"
|
|
#include <diskio.hpp>
|
|
#include <ieee.h>
|
|
#include "npooluti.hpp"
|
|
#include "notify_codes.hpp"
|
|
int data_id;
|
|
|
|
//-----------------------------------------------------------------------
|
|
#ifdef __debug__
|
|
NORETURN void _destroyed(const char *from)
|
|
{
|
|
error("Database is corrupted! [at: %s]", from);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
NORETURN void _faterr(uchar mode, const char *from)
|
|
{
|
|
error("Internal error (%s) [at: %s]",
|
|
mode ? "compatibility" : "idp",
|
|
from);
|
|
}
|
|
#else
|
|
//-----------------------------------------------------------------------
|
|
NORETURN void _destroyed(void)
|
|
{
|
|
error("Database is corrupted!");
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
NORETURN void _faterr(uchar mode)
|
|
{
|
|
error("Internal error (%s)", mode ? "compatibility" : "idp");
|
|
}
|
|
#endif
|
|
|
|
//-----------------------------------------------------------------------
|
|
void java_t::sm_validate(const SegInfo *si)
|
|
{
|
|
ea_t segTopEA = si->start_ea + si->CodeSize;
|
|
netnode temp(si->smNode);
|
|
nodeidx_t nid = temp.supfirst();
|
|
|
|
if ( (ea_t)nid < si->start_ea )
|
|
goto destroyed;
|
|
|
|
do
|
|
{
|
|
if ( (ea_t)nid >= segTopEA )
|
|
goto destroyed;
|
|
if ( temp.supval(nid, NULL, 0) != sizeof(sm_info_t) )
|
|
goto destroyed;
|
|
if ( !is_head(get_flags((ea_t)nid)) )
|
|
{
|
|
remember_problem(PR_HEAD, (ea_t)nid);
|
|
if ( !displayed_nl )
|
|
{
|
|
displayed_nl = true;
|
|
msg("\n");
|
|
}
|
|
msg("StackMap refers to nonHead offset %X in Method#%u\n",
|
|
(uint32)((ea_t)nid - si->start_ea), si->id.Number);
|
|
}
|
|
nid = temp.supnext(nid);
|
|
}
|
|
while ( nid != BADNODE );
|
|
return;
|
|
|
|
destroyed:
|
|
DESTROYED("sm_validate");
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// visble for upgrade ONLY
|
|
void java_t::coagulate_unused_data(const SegInfo *ps)
|
|
{
|
|
uint size = 0;
|
|
ea_t ea = ps->DataBase;
|
|
ea_t top = ea + ps->DataSize;
|
|
for ( ; ea < top; ea++ )
|
|
{
|
|
if ( is_head(get_flags(ea))
|
|
&& get_first_dref_to(ea) == BADADDR )
|
|
{
|
|
ConstantNode.chardel(ea, UR_TAG); // unicode renaming support
|
|
del_global_name(ea);
|
|
del_items(ea, DELIT_SIMPLE);
|
|
++size;
|
|
ea_t to;
|
|
while ( (to=get_first_dref_from(ea)) != BADADDR )
|
|
del_dref(ea, to);
|
|
}
|
|
else if ( size )
|
|
{
|
|
create_data(ea-size, align_flag(), size, BADNODE);
|
|
size = 0;
|
|
}
|
|
}
|
|
if ( size )
|
|
create_data(ea-size, align_flag(), size, BADNODE);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
//--------------------------------------------------------------------------
|
|
static int idaapi out_asm_file(
|
|
FILE *fp,
|
|
const qstring &line,
|
|
bgcolor_t,
|
|
bgcolor_t)
|
|
{
|
|
qstring qbuf;
|
|
tag_remove(&qbuf, line);
|
|
size_t len = qbuf.length();
|
|
size_t chk = len;
|
|
|
|
if ( qbuf.last() == '\\' )
|
|
--len;
|
|
if ( qfwrite(fp, qbuf.c_str(), len) != len )
|
|
return 0;
|
|
if ( chk == len && qfputc('\n', fp) == EOF )
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
static void idaapi func_header(outctx_t &ctx, func_t *) { ctx.ctxflags |= CTXF_LABEL_OK; }
|
|
static void idaapi func_footer(outctx_t &, func_t *) {}
|
|
static bool idaapi java_specseg(outctx_t &ctx, uchar) { java_data(ctx, false); return false; }
|
|
|
|
//----------------------------------------------------------------------
|
|
// floating point conversion
|
|
fpvalue_error_t idaapi j_realcvt(void *m, fpvalue_t *e, ushort swt)
|
|
{
|
|
return ieee_realcvt(m, e, swt | 0x80);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// Set IDP options. Either from the configuration file either allow the user
|
|
// to specify them in a dialog box.
|
|
const char *java_t::set_idp_options(
|
|
const char *keyword,
|
|
int value_type,
|
|
const void * value,
|
|
bool idb_loaded)
|
|
{
|
|
static const char form[] =
|
|
"HELP\n"
|
|
"JAVA specific options\n"
|
|
"\n"
|
|
" Multiline .debug\n"
|
|
"\n"
|
|
" If this option is on, IDA forces new .debug directive at every\n"
|
|
" LR ('\\n') in the input string\n"
|
|
"\n"
|
|
" Hide StackMap(s)\n"
|
|
"\n"
|
|
" If this option is on, IDA hides .stack verification declarations\n"
|
|
"\n"
|
|
" Auto strings\n"
|
|
"\n"
|
|
" If this option is on, IDA makes 'prompt-string' after every CR in\n"
|
|
" the quoted-string operand\n"
|
|
"\n"
|
|
" Save to jasmin\n"
|
|
"\n"
|
|
" If this option is on, IDA creates asm-file in the jasmin-\n"
|
|
" compatibe form: concatenates 'prompted' string, reserved names\n"
|
|
" will be enclosed in quotes.\n"
|
|
" Also when this option is on IDA changes unicode-to-oem encoding to\n"
|
|
" unicode-to-ansi encoding because jasmin expects ansi encoding.\n"
|
|
"\n"
|
|
" Enable encoding\n"
|
|
"\n"
|
|
" If this option is on, IDA converts unicode characters which\n"
|
|
" can't be represented in current locale to ascii characters.\n"
|
|
"\n"
|
|
" Nopath .attribute\n"
|
|
" If this option is on, IDA prints filename in '.attribute'\n"
|
|
" directives without the path part.\n"
|
|
"\n"
|
|
"\n"
|
|
" Bad index as string\n"
|
|
" If this option is on, IDA will show invalid name/type references\n"
|
|
" as a quoted string.\n"
|
|
"ENDHELP\n"
|
|
"JAVA specific options\n"
|
|
"\n"
|
|
" <~M~ultilne .debug :C>\n"
|
|
" <~H~ide StackMap(s) :C>\n"
|
|
" <~A~uto strings :C>\n"
|
|
" <~S~ave to jasmin :C>\n"
|
|
" <~E~nable encoding :C>\n"
|
|
" <~N~opath .attribute :C>>\n"
|
|
"\n"
|
|
" <~B~ad index as string :C>>\n"
|
|
"\n"
|
|
"\n";
|
|
|
|
if ( !keyword )
|
|
{
|
|
ushort tmp = (idpflags >> 16) & IDM__REQMASK;
|
|
ushort flags = idpflags;
|
|
if ( ask_form(form, &flags, &tmp) )
|
|
{
|
|
int32 old = idpflags;
|
|
idpflags = (flags & ~(IDM__REQMASK << 16)) | (tmp << 16);
|
|
if ( (idpflags ^ old) & IDF_ENCODING )
|
|
rename_uninames(-1);
|
|
}
|
|
goto SAVE;
|
|
}
|
|
|
|
if ( value_type != IDPOPT_BIT )
|
|
return IDPOPT_BADTYPE;
|
|
|
|
struct keyword_info_t
|
|
{
|
|
const char *name;
|
|
int bit;
|
|
};
|
|
static const keyword_info_t keywords[] =
|
|
{
|
|
{ "JAVA_MULTILINE_DEBUG", IDF_MULTDEB },
|
|
{ "JAVA_HIDE_STACKMAP", IDF_HIDESM },
|
|
{ "JAVA_AUTO_STRING", IDF_AUTOSTR },
|
|
{ "JAVA_ASMFILE_CONVERT", IDF_CONVERT },
|
|
{ "JAVA_ENABLE_ENCODING", IDF_ENCODING },
|
|
{ "JAVA_NOPATH_ATTRIBUTE", IDF_NOPATH },
|
|
{ "JAVA_UNKATTR_REQUEST", IDM_REQUNK },
|
|
{ "JAVA_UNKATTR_WARNING", IDM_WARNUNK },
|
|
};
|
|
|
|
for ( int i=0; i < qnumber(keywords); i++ )
|
|
{
|
|
if ( strcmp(keywords[i].name, keyword) == 0 )
|
|
{
|
|
setflag(idpflags, keywords[i].bit, *(int*)value != 0);
|
|
goto SAVE;
|
|
}
|
|
}
|
|
|
|
if ( streq(keyword, "JAVA_STARTASM_LIST") )
|
|
{
|
|
start_asm_list = *(int*)value;
|
|
return IDPOPT_OK;
|
|
}
|
|
else
|
|
{
|
|
return IDPOPT_BADKEY;
|
|
}
|
|
SAVE:
|
|
if ( idb_loaded )
|
|
ConstantNode.altset(CNA_IDPFLAGS, (ushort)idpflags);
|
|
return IDPOPT_OK;
|
|
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
static const asm_t jasmin_asm =
|
|
{
|
|
AS_COLON | ASH_HEXF3 | ASO_OCTF1 | ASD_DECF0 | AS_ONEDUP | ASB_BINF3,
|
|
UAS_JASMIN,
|
|
"Jasmin assembler",
|
|
0, // no help screen
|
|
NULL, // header
|
|
NULL, // origin
|
|
NULL, // end of file
|
|
|
|
";", // comment string
|
|
'"', // string delimiter
|
|
'\'', // char delimiter
|
|
"\"'\\", // special symbols in char and string constants
|
|
|
|
"", // ascii string directive
|
|
"", // byte directive
|
|
NULL, // word directive
|
|
NULL, // double words
|
|
NULL, // qwords
|
|
NULL, // oword (16 bytes)
|
|
NULL, // float
|
|
NULL, // double
|
|
NULL, // no tbytes
|
|
NULL, // no packreal
|
|
NULL, // arrays:
|
|
// #h - header(.byte,.word)
|
|
// #d - size of array
|
|
// #v - value of array elements
|
|
NULL, //".reserv %s", // uninited data (reserve space)
|
|
" = ", // equ
|
|
NULL, // seg prefix
|
|
NULL, // a_curip
|
|
func_header, // func header
|
|
func_footer, // func footer
|
|
"", // public (disable ouput)
|
|
NULL, // weak
|
|
NULL, // extrn
|
|
NULL, // comm
|
|
NULL, // get_type_name
|
|
NULL, // align
|
|
'(', ')', // lbrace, rbrace
|
|
NULL, // mod
|
|
"&", // and
|
|
"|", // or
|
|
"^", // xor
|
|
"!", // not
|
|
"<<", // shl
|
|
">>", // shr
|
|
NULL, // sizeof
|
|
0, // flag2
|
|
NULL, // cmnt2
|
|
NULL, // low8
|
|
NULL, // high8
|
|
NULL, // low16
|
|
NULL, // high16
|
|
NULL, // a_include_fmt
|
|
NULL, // a_vstruc_fmt
|
|
NULL, // a_rva
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
static const asm_t list_asm =
|
|
{
|
|
AS_COLON | ASH_HEXF3 | ASO_OCTF1 | ASD_DECF0 | AS_ONEDUP | ASB_BINF3,
|
|
0,
|
|
"User friendly listing",
|
|
0, // no help screen
|
|
NULL, // header
|
|
NULL, // origin
|
|
NULL, // end of file
|
|
|
|
"//", // comment string
|
|
'"', // string delimiter
|
|
'\'', // char delimiter
|
|
"\"'\\", // special symbols in char and string constants
|
|
|
|
"", // ascii string directive
|
|
"", // byte directive
|
|
NULL, // word directive
|
|
NULL, // double words
|
|
NULL, // qwords
|
|
NULL, // oword (16 bytes)
|
|
NULL, // float
|
|
NULL, // double
|
|
NULL, // no tbytes
|
|
NULL, // no packreal
|
|
NULL, // arrays:
|
|
// #h - header(.byte,.word)
|
|
// #d - size of array
|
|
// #v - value of array elements
|
|
NULL, //".reserv %s", // uninited data (reserve space)
|
|
" = ", // equ
|
|
NULL, // seg prefix
|
|
NULL, // a_curip
|
|
func_header, // func header
|
|
func_footer, // func footer
|
|
"", // public (disable ouput)
|
|
NULL, // weak
|
|
NULL, // extrn
|
|
NULL, // comm
|
|
NULL, // get_type_name
|
|
NULL, // align
|
|
'(', ')', // lbrace, rbrace
|
|
NULL, // mod
|
|
"&", // and
|
|
"|", // or
|
|
"^", // xor
|
|
"!", // not
|
|
"<<", // shl
|
|
">>", // shr
|
|
NULL, // sizeof
|
|
0, // flag2
|
|
NULL, // cmnt2
|
|
NULL, // low8
|
|
NULL, // high8
|
|
NULL, // low16
|
|
NULL, // high16
|
|
NULL, // a_include_fmt
|
|
NULL, // a_vstruc_fmt
|
|
NULL, // a_rva
|
|
};
|
|
|
|
//-----------------------------------------------------------------------
|
|
static const asm_t *const asms[] = { &jasmin_asm, &list_asm, NULL };
|
|
|
|
static const char *const RegNames[] = { "vars", "optop", "frame", "cs", "ds" };
|
|
|
|
#define FAMILY "Java Virtual Machine:"
|
|
|
|
static const char *const shnames[] =
|
|
{
|
|
"java",
|
|
#ifdef __debug__
|
|
"_javaPC",
|
|
#endif
|
|
NULL
|
|
};
|
|
|
|
static const char *const lnames[] =
|
|
{
|
|
FAMILY"Java",
|
|
#ifdef __debug__
|
|
"Java full (IBM PC, debug mode)",
|
|
#endif
|
|
NULL
|
|
};
|
|
|
|
//--------------------------------------------------------------------------
|
|
static const uchar retcode_0[] = { j_ret };
|
|
static const uchar retcode_1[] = { j_ireturn };
|
|
static const uchar retcode_2[] = { j_lreturn };
|
|
static const uchar retcode_3[] = { j_freturn };
|
|
static const uchar retcode_4[] = { j_dreturn };
|
|
static const uchar retcode_5[] = { j_areturn };
|
|
static const uchar retcode_6[] = { j_return };
|
|
static const uchar retcode_7[] = { j_wide, j_ret };
|
|
|
|
static const bytes_t retcodes[] =
|
|
{
|
|
{ sizeof(retcode_0), retcode_0 },
|
|
{ sizeof(retcode_1), retcode_1 },
|
|
{ sizeof(retcode_2), retcode_2 },
|
|
{ sizeof(retcode_3), retcode_3 },
|
|
{ sizeof(retcode_4), retcode_4 },
|
|
{ sizeof(retcode_5), retcode_5 },
|
|
{ sizeof(retcode_6), retcode_6 },
|
|
{ sizeof(retcode_7), retcode_7 },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
//--------------------------------------------------------------------------
|
|
ssize_t idaapi idb_listener_t::on_event(ssize_t code, va_list)
|
|
{
|
|
switch ( code )
|
|
{
|
|
case idb_event::closebase:
|
|
memset(&pm.curClass, 0, sizeof(pm.curClass));
|
|
// no break
|
|
case idb_event::savebase:
|
|
pm.ConstantNode.altset(CNA_IDPFLAGS, (ushort)pm.idpflags);
|
|
break;
|
|
|
|
case idb_event::auto_empty:
|
|
if ( !(pm.curClass.extflg & XFL_C_DONE) ) // kernel BUGs
|
|
{
|
|
pm.curClass.extflg |= XFL_C_DONE;
|
|
msg("JavaLoader finalization stage...");
|
|
for ( int n = pm.curClass.MethodCnt; n; n-- )
|
|
{
|
|
SegInfo si;
|
|
if ( pm.ClassNode.supval(-n, &si, sizeof(si)) != sizeof(si) )
|
|
DESTROYED("postprocess");
|
|
if ( si.smNode || si.DataSize )
|
|
{
|
|
show_addr(si.start_ea);
|
|
if ( si.smNode )
|
|
pm.sm_validate(&si);
|
|
if ( si.DataSize )
|
|
pm.coagulate_unused_data(&si);
|
|
}
|
|
}
|
|
pm.ConstantNode.supset(CNS_CLASS, &pm.curClass, sizeof(pm.curClass)); // all chgs
|
|
pm.sm_node = smn_ok;
|
|
msg("OK\n");
|
|
}
|
|
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(SET_MODULE_DATA(java_t));
|
|
return 0;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
ssize_t idaapi java_t::on_event(ssize_t msgid, va_list va)
|
|
{
|
|
int retcode = 0;
|
|
switch ( msgid )
|
|
{
|
|
case processor_t::ev_init:
|
|
hook_event_listener(HT_IDB, &idb_listener, &LPH);
|
|
inf_set_be(true); // reverse byte!
|
|
break;
|
|
|
|
case processor_t::ev_rename:
|
|
va_arg(va, ea_t);
|
|
for ( char const *pn, *p = va_arg(va, const char *);
|
|
(pn = strchr(p, '\\')) != NULL;
|
|
p = pn+1 )
|
|
{
|
|
if ( *++pn != 'u' )
|
|
{
|
|
inv_name:
|
|
--retcode; // 0
|
|
warning("Backslash is accepted only as a unicode escape sequence in names");
|
|
break;
|
|
}
|
|
for ( int i = 0; i < 4; i++ )
|
|
if ( !qisxdigit((uchar)*++pn) )
|
|
goto inv_name;
|
|
}
|
|
break;
|
|
|
|
case processor_t::ev_newfile:
|
|
if ( inf_get_filetype() != f_LOADER )
|
|
{
|
|
set_database_flag(DBFL_KILL); // clean up the database files
|
|
error("The input file does not have a supported Java file format");
|
|
}
|
|
database_loaded (va_arg(va, char *));
|
|
inf_set_lowoff(BADADDR);
|
|
inf_set_highoff(BADADDR);
|
|
break;
|
|
|
|
case processor_t::ev_ending_undo:
|
|
case processor_t::ev_oldfile:
|
|
database_loaded(NULL);
|
|
break;
|
|
|
|
case processor_t::ev_term:
|
|
unhook_event_listener(HT_IDB, &idb_listener);
|
|
qfree(tsPtr);
|
|
qfree(smBuf);
|
|
qfree(annBuf);
|
|
clr_module_data(data_id);
|
|
break;
|
|
|
|
#ifdef __debug__
|
|
case processor_t::ev_newprc:
|
|
{
|
|
int procnum = va_arg(va, int);
|
|
bool keep_cfg = va_argi(va, bool);
|
|
if ( procnum == 1 ) // debug mode
|
|
{
|
|
ph.flag &= ~(PR_DEFNUM | PR_NOCHANGE);
|
|
ph.flag |= PRN_HEX;
|
|
if ( inf_get_margin() == 77 && !inf.bin_prefix_size && !inf.show_line_pref() )
|
|
{
|
|
if ( !keep_cfg )
|
|
inf_set_show_line_pref(true);
|
|
--debugmode;
|
|
}
|
|
else
|
|
{
|
|
++debugmode;
|
|
}
|
|
}
|
|
else // normal node
|
|
{
|
|
ph.flag &= ~PR_DEFNUM;
|
|
ph.flag |= PRN_DEC;
|
|
if ( debugmode == -1
|
|
&& inf.show_line_pref()
|
|
&& !inf.bin_prefix_size
|
|
&& inf_get_margin() == 77
|
|
&& !keep_cfg )
|
|
{
|
|
inf.show_line_pref(false);
|
|
}
|
|
debugmode = 0;
|
|
}
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
case java_module_t::ev_load_file:
|
|
{
|
|
linput_t *li = va_arg(va, linput_t *);
|
|
FILE *f = qlfile(li);
|
|
QASSERT(10082, f != NULL);
|
|
bool manual = va_argi(va, bool);
|
|
loader(f, manual);
|
|
retcode = 0;
|
|
}
|
|
if ( start_asm_list )
|
|
set_target_assembler(1);
|
|
break;
|
|
|
|
case processor_t::ev_gen_src_file_lnnum:
|
|
if ( jasmin() )
|
|
{
|
|
outctx_t *ctx = va_arg(va, outctx_t *);
|
|
va_arg(va, const char *); // skip file name
|
|
size_t lineno = va_arg(va, size_t);
|
|
ctx->gen_printf(2, COLSTR(".line %" FMT_Z, SCOLOR_ASMDIR), lineno);
|
|
retcode = 1;
|
|
}
|
|
break;
|
|
|
|
case processor_t::ev_gen_asm_or_lst:
|
|
{
|
|
if ( va_argi(va, bool) ) // starting (else end of generation )
|
|
{
|
|
va_arg(va, FILE *); // output file (skip)
|
|
bool isasm = va_argi(va, bool); // assembler-true, listing-false
|
|
if ( isasm && (idpflags & IDF_CONVERT) )
|
|
{
|
|
va_arg(va, int); // flags of gen_file() (skip)
|
|
*va_arg(va, gen_outline_t**) = out_asm_file;
|
|
idpflags |= IDM_OUTASM;
|
|
}
|
|
if ( isasm == jasmin() )
|
|
break; // need change mode?
|
|
}
|
|
else // end of generation.
|
|
{
|
|
idpflags &= ~IDM_OUTASM;
|
|
if ( !mode_changed )
|
|
break; // mode changed?
|
|
}
|
|
mode_changed = !mode_changed;
|
|
set_target_assembler(!inf_get_asmtype());
|
|
}
|
|
break;
|
|
|
|
case processor_t::ev_get_autocmt:
|
|
{
|
|
qstring *buf = va_arg(va, qstring *);
|
|
const insn_t *insn = va_arg(va, insn_t *);
|
|
if ( make_locvar_cmt(buf, *insn) )
|
|
retcode = 1;
|
|
}
|
|
break;
|
|
|
|
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 *);
|
|
java_header(*ctx);
|
|
return 1;
|
|
}
|
|
|
|
case processor_t::ev_out_footer:
|
|
{
|
|
outctx_t *ctx = va_arg(va, outctx_t *);
|
|
java_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 *);
|
|
java_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 *);
|
|
java_segend(*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);
|
|
java_data(*ctx, analyze_only);
|
|
return 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_realcvt:
|
|
{
|
|
void *m = va_arg(va, void *);
|
|
fpvalue_t *e = va_arg(va, fpvalue_t *);
|
|
uint16 swt = va_argi(va, uint16);
|
|
fpvalue_error_t code = j_realcvt(m, e, swt);
|
|
return code == REAL_ERROR_OK ? 1 : code;
|
|
}
|
|
|
|
case processor_t::ev_gen_map_file:
|
|
{
|
|
int *nlines = va_arg(va, int *);
|
|
FILE *fp = va_arg(va, FILE *);
|
|
int code = gen_map_file(fp);
|
|
if ( code == -1 )
|
|
return -1;
|
|
*nlines = code;
|
|
return 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 = get_ref_addr(screen_ea, str, pos);
|
|
if ( ea == BADADDR )
|
|
return -1;
|
|
if ( ea == (BADADDR-1) )
|
|
return 0;
|
|
*out_ea = ea;
|
|
return 1;
|
|
}
|
|
|
|
case processor_t::ev_out_special_item:
|
|
{
|
|
outctx_t *ctx = va_arg(va, outctx_t *);
|
|
uchar seg_type = va_argi(va, uchar);
|
|
java_specseg(*ctx, seg_type);
|
|
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 retcode;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
// Processor Definition
|
|
//-----------------------------------------------------------------------
|
|
processor_t LPH =
|
|
{
|
|
IDP_INTERFACE_VERSION, // version
|
|
PLFM_JAVA, // id
|
|
// flag
|
|
PRN_DEC
|
|
| PR_RNAMESOK
|
|
| PR_NO_SEGMOVE,
|
|
// flag2
|
|
PR2_REALCVT // the module has 'realcvt' event implementation
|
|
| 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,
|
|
|
|
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,j_last,
|
|
Instructions, // instruc
|
|
0, // size of tbyte
|
|
{0,7,15,0}, // real width
|
|
j_ret, // icode_return
|
|
NULL, // Micro virtual machine description
|
|
};
|