317 lines
7.9 KiB
C++
317 lines
7.9 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"
|
|
|
|
static const char badlocvar[] = "Invalid local variable number";
|
|
|
|
//----------------------------------------------------------------------
|
|
uval_t java_t::SearchFM(ushort name, ushort dscr, char *naprN)
|
|
{
|
|
char buf[(qmax(sizeof(FieldInfo), sizeof(SegInfo))+1+3)&~3];
|
|
sval_t pos = curClass.FieldCnt;
|
|
uint32 csz = sizeof(FieldInfo);
|
|
sval_t napr = *naprN;
|
|
|
|
if ( napr != 1 )
|
|
{
|
|
if ( napr != -1 )
|
|
INTERNAL("SearchFM");
|
|
pos = -(uval_t)curClass.MethodCnt;
|
|
csz = sizeof(SegInfo);
|
|
}
|
|
void *p = buf;
|
|
for ( ; pos; pos -= napr )
|
|
{
|
|
if ( ClassNode.supval(pos, p, sizeof(buf)) != csz )
|
|
DESTROYED("SearchFM");
|
|
if ( ((_FMid_ *)p)->extflg & EFL_NAMETYPE
|
|
|| CmpString(name, ((_FMid_ *)p)->name)
|
|
|| CmpString(dscr, ((_FMid_ *)p)->dscr) )
|
|
{
|
|
continue;
|
|
}
|
|
if ( napr >= 0 )
|
|
return curClass.start_ea + ((FieldInfo *)p)->id.Number;
|
|
if ( ((SegInfo *)p)->CodeSize )
|
|
*naprN = 0;
|
|
return ((SegInfo *)p)->start_ea;
|
|
}
|
|
return BADADDR;
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void java_t::mark_and_comment(ea_t ea, const char *cmt) const
|
|
{
|
|
remember_problem(PR_ATTN, ea);
|
|
if ( *cmt && (!has_cmt(get_flags(ea)) || ea == curClass.start_ea) )
|
|
append_cmt(ea, cmt, false);
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void java_t::TouchArg(const insn_t &insn, const op_t &x, bool isload)
|
|
{
|
|
const char *p;
|
|
|
|
switch ( x.type )
|
|
{
|
|
case o_void: // not operand
|
|
break;
|
|
|
|
case o_cpool: // ConstantPool reference (index)
|
|
if ( x.ref )
|
|
{
|
|
p = x.ref == 1
|
|
? "Invalid string in constant pool"
|
|
: "Invalid index in constant pool";
|
|
goto mark;
|
|
}
|
|
if ( x.cp_ind )
|
|
{
|
|
ea_t ea;
|
|
char npr = -1;
|
|
|
|
switch ( (uchar)x.cp_type )
|
|
{
|
|
case CONSTANT_Fieldref:
|
|
npr = 1;
|
|
// fallthrough
|
|
case CONSTANT_InterfaceMethodref:
|
|
case CONSTANT_Methodref:
|
|
if ( !(x._subnam | x._name | x._class) )
|
|
break;
|
|
if ( x._class == curClass.This.Dscr )
|
|
{
|
|
ea = SearchFM(x._subnam, x._dscr, &npr);
|
|
if ( ea == BADADDR )
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if ( !insn.xtrn_ip )
|
|
break;
|
|
ea = insn.xtrn_ip == 0xFFFF
|
|
? curClass.start_ea
|
|
: curClass.xtrnEA + insn.xtrn_ip;
|
|
if ( npr < 0 )
|
|
npr = 0;
|
|
}
|
|
if ( npr <= 0 )
|
|
{
|
|
insn.add_cref(ea, x.offb, fl_CF);
|
|
if ( !npr )
|
|
auto_cancel(ea, ea+1);
|
|
}
|
|
else
|
|
{
|
|
dref_t type = insn.itype == j_putstatic || insn.itype == j_putfield
|
|
? dr_W
|
|
: dr_R;
|
|
insn.add_dref(ea, x.offb, type);
|
|
}
|
|
break;
|
|
|
|
case CONSTANT_Class:
|
|
if ( insn.xtrn_ip )
|
|
{
|
|
ea_t target = insn.xtrn_ip == 0xFFFF
|
|
? curClass.start_ea
|
|
: curClass.xtrnEA + insn.xtrn_ip;
|
|
insn.add_dref(target, x.offb, dr_I);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case o_array: // type!
|
|
if ( x.ref )
|
|
{
|
|
p = "Invalid array type";
|
|
goto mark;
|
|
}
|
|
break;
|
|
|
|
case o_imm: // const (& #data)
|
|
if ( x.ref < 2 )
|
|
set_immd(insn.ea);
|
|
break;
|
|
|
|
case o_mem: // local data pool
|
|
if ( x.ref )
|
|
{
|
|
p = badlocvar;
|
|
mark:
|
|
mark_and_comment(insn.ea, p);
|
|
}
|
|
else
|
|
{
|
|
dref_t ref = isload ? dr_R : dr_W;
|
|
ea_t adr = curSeg.DataBase + x.addr;
|
|
insn.add_dref(adr, x.offb, ref);
|
|
if ( (x.dtype == dt_qword || x.dtype == dt_double)
|
|
&& get_item_size(adr) <= 1 )
|
|
{
|
|
insn.add_dref(adr + 1, x.offb, ref);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case o_near:
|
|
if ( x.ref )
|
|
{
|
|
p = "Invalid jump address";
|
|
goto mark;
|
|
}
|
|
insn.add_cref(
|
|
curSeg.start_ea + x.addr,
|
|
x.offb,
|
|
(Feature & CF_CALL) != 0 ? fl_CN : fl_JN);
|
|
break;
|
|
|
|
default:
|
|
warning("%a: %s,%d: bad optype %d", insn.ea, insn.get_canon_mnem(ph), x.n,
|
|
x.type);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
int java_t::emu(const insn_t &insn)
|
|
{
|
|
Feature = insn.get_canon_feature(ph);
|
|
|
|
if ( insn.wid > 1 )
|
|
mark_and_comment(insn.ea, "Limited usage instruction");
|
|
|
|
if ( insn.itype >= j_a_software )
|
|
mark_and_comment(insn.ea, "Undocumented instruction");
|
|
|
|
if ( insn.Op1.type == o_void && insn.Op1.ref )
|
|
{
|
|
if ( (char)insn.Op1.ref < 0 )
|
|
{
|
|
mark_and_comment(insn.ea, badlocvar);
|
|
}
|
|
else
|
|
{
|
|
dref_t ref = (insn.itype >= j_istore_0) ? dr_W : dr_R;
|
|
insn.add_dref(insn.Op1.addr, 0, ref);
|
|
if ( (insn.Op1.ref & 2) && get_item_size(insn.Op1.addr) <= 1 )
|
|
insn.add_dref(insn.Op1.addr + 1, 0, ref);
|
|
}
|
|
}
|
|
|
|
if ( Feature & CF_USE1 )
|
|
TouchArg(insn, insn.Op1, true);
|
|
if ( Feature & CF_USE2 )
|
|
TouchArg(insn, insn.Op2, true);
|
|
if ( Feature & CF_USE3 )
|
|
TouchArg(insn, insn.Op3, true);
|
|
|
|
if ( Feature & CF_CHG1 )
|
|
TouchArg(insn, insn.Op1, false);
|
|
|
|
if ( insn.swit ) // tableswitch OR lookupswitch
|
|
{
|
|
uval_t count, addr, rnum;
|
|
|
|
if ( insn.swit & 0200 )
|
|
mark_and_comment(insn.ea, badlocvar);
|
|
if ( insn.swit & 0100 )
|
|
mark_and_comment(insn.ea, "Nonzero filler (warning)");
|
|
|
|
rnum = insn.Op2.value - 1; // for lookupswtitch
|
|
for ( addr=insn.Op2.addr, count=insn.Op3.value; count; addr +=4, count-- )
|
|
{
|
|
uval_t refa;
|
|
|
|
if ( insn.itype != j_lookupswitch )
|
|
{
|
|
++rnum;
|
|
}
|
|
else
|
|
{
|
|
rnum = get_dword(curSeg.start_ea + addr); // skip pairs
|
|
addr += 4;
|
|
}
|
|
refa = insn.ip + get_dword(curSeg.start_ea + addr);
|
|
|
|
if ( refa < curSeg.CodeSize )
|
|
{
|
|
add_cref(insn.ea, (refa += curSeg.start_ea), fl_JN);
|
|
if ( !has_cmt(get_flags(refa)) )
|
|
{
|
|
char str[32];
|
|
qsnprintf(str, sizeof(str), "case %" FMT_EA "u", rnum);
|
|
set_cmt(refa, str, false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !(Feature&CF_STOP) && (!(Feature&CF_CALL) || func_does_return(insn.ea)) )
|
|
add_cref(insn.ea, insn.ea + insn.size, fl_F);
|
|
|
|
return 1;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
size_t java_t::make_locvar_cmt(qstring *buf, const insn_t &insn)
|
|
{
|
|
LocVar lv;
|
|
|
|
if ( curSeg.varNode )
|
|
{
|
|
const char *p = NULL;
|
|
uval_t idx = insn.Op1.addr;
|
|
|
|
if ( insn.Op1.type == o_mem )
|
|
{
|
|
if ( !insn.Op1.ref )
|
|
{
|
|
switch ( insn.itype )
|
|
{
|
|
case j_ret:
|
|
p = "Return";
|
|
break;
|
|
case j_iinc:
|
|
p = "Add 8-bit signed const to";
|
|
break;
|
|
default:
|
|
p = "Push";
|
|
if ( insn.get_canon_feature(ph) & CF_CHG1 )
|
|
p = "Pop";
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if ( insn.Op1.type == o_void
|
|
&& (char)insn.Op1.ref >= 0
|
|
&& (int32)(idx -= curSeg.DataBase) >= 0 )
|
|
{
|
|
p = "Push";
|
|
if ( insn.itype >= j_istore_0 )
|
|
p = "Pop";
|
|
}
|
|
|
|
if ( p != NULL && netnode(curSeg.varNode).supval(idx,&lv,sizeof(lv)) == sizeof(lv) )
|
|
{
|
|
if ( fmtName(lv.var.Name, tmp_name, sizeof(tmp_name), fmt_UnqualifiedName) )
|
|
return buf->sprnt("%s %s", p, tmp_name).length();
|
|
}
|
|
}
|
|
return 0;
|
|
}
|