392 lines
10 KiB
C++
392 lines
10 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 "upgrade.hpp"
|
|
#include "oututil.hpp"
|
|
|
|
//----------------------------------------------------------------------
|
|
#define _TO_VERSION IDP_JDK16
|
|
|
|
//----------------------------------------------------------------------
|
|
void java_t::make_new_name(ushort name, ushort subnam, uchar mode, uint ip)
|
|
{
|
|
out_java_t *pctx = (out_java_t *)create_outctx(BADADDR);
|
|
if ( pctx->fmtString(*this, name, MAXNAMELEN-2, fmt_fullname) )
|
|
{
|
|
trunc:
|
|
pctx->trunc_name(ip, mode & 4);
|
|
}
|
|
else if ( (char)mode > 0 )
|
|
{
|
|
size_t len = pctx->outbuf.length();
|
|
if ( len >= (MAXNAMELEN-3) )
|
|
goto trunc;
|
|
pctx->out_char(' ');
|
|
if ( pctx->fmtString(*this, subnam, (MAXNAMELEN-2) - len, fmt_UnqualifiedName) )
|
|
goto trunc;
|
|
}
|
|
force_name(ip, convert_clsname(pctx->outbuf.begin()));
|
|
delete pctx;
|
|
hide_name(ip);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
int java_t::upgrade_db_format(int ver, netnode constnode)
|
|
{
|
|
if ( ask_yn(ASKBTN_YES,
|
|
"AUTOHIDE REGISTRY\nHIDECANCEL\n"
|
|
"The database has an old java data format.\n"
|
|
"Do you want to upgrade it?") <= ASKBTN_NO )
|
|
{
|
|
qexit(1);
|
|
}
|
|
|
|
switch ( ver )
|
|
{
|
|
default:
|
|
INTERNAL("upgrade::ver");
|
|
case IDP_JDK12:
|
|
break;
|
|
}
|
|
|
|
// change format: jdk-version
|
|
if ( curClass.MinVers > 0x8000u )
|
|
{
|
|
BADIDB:
|
|
return 0;
|
|
}
|
|
|
|
curClass.MajVers = JDK_MIN_MAJOR;
|
|
if ( curClass.MinVers >= 0x8000 )
|
|
{
|
|
curClass.MinVers &= ~0;
|
|
++curClass.MajVers;
|
|
curClass.JDKsubver = 2;
|
|
}
|
|
else if ( curClass.MinVers >= JDK_1_1_MINOR )
|
|
{
|
|
++curClass.JDKsubver;
|
|
}
|
|
|
|
// change format: This
|
|
CASSERT(offsetof(ClassInfo, This.Ref) == offsetof(ClassInfo, This.Name)
|
|
&& offsetof(ClassInfo, This.Dscr) == offsetof(ClassInfo, This.Name) + 2);
|
|
|
|
curClass.This.Ref = (curClass.This.Ref << 16) | curClass.This.Dscr;
|
|
if ( !curClass.This.Name )
|
|
goto BADIDB;
|
|
|
|
// change format: Super
|
|
CASSERT(offsetof(ClassInfo, super.Ref) == offsetof(ClassInfo, super.Name)
|
|
&& offsetof(ClassInfo, super.Dscr) == offsetof(ClassInfo, super.Name) + 2);
|
|
switch ( curClass.super.Name )
|
|
{
|
|
case 0: // absent
|
|
curClass.super.Ref &= 0;
|
|
break;
|
|
case 0xFFFF: // bad index
|
|
++curClass.super.Name;
|
|
break;
|
|
default: // reverse order
|
|
curClass.super.Ref = (curClass.super.Ref << 16) | curClass.super.Dscr;
|
|
break;
|
|
}
|
|
|
|
// validate: impNode
|
|
if ( curClass.impNode && !netnode(curClass.impNode).altval(0) )
|
|
goto BADIDB;
|
|
|
|
// change variable 'errload' in previous version
|
|
if ( curClass.maxSMsize )
|
|
{
|
|
curClass.extflg |= XFL_C_ERRLOAD;
|
|
curClass.maxSMsize &= 0;
|
|
}
|
|
|
|
// set segments type type for special segments
|
|
segment_t *S = getseg(curClass.start_ea);
|
|
if ( S == NULL )
|
|
goto BADIDB;
|
|
S->set_hidden_segtype(true);
|
|
S->update();
|
|
if ( curClass.xtrnCnt )
|
|
{
|
|
S = getseg(curClass.xtrnEA);
|
|
if ( S == NULL )
|
|
goto BADIDB;
|
|
S->set_hidden_segtype(true);
|
|
S->update();
|
|
}
|
|
|
|
curClass.extflg |= XFL_C_DONE; // do not repeat datalabel destroyer :)
|
|
// change: method/fields format
|
|
#define SGEXPSZ (sizeof(SegInfo) - offsetof(SegInfo, varNode))
|
|
#define FMEXPSZ (sizeof(_FMid_) - offsetof(_FMid_, _UNUSED_ALING))
|
|
#define FLEXPSZ (sizeof(FieldInfo) - offsetof(FieldInfo, annNodes))
|
|
uval_t oldsize = sizeof(SegInfo) - FMEXPSZ - SGEXPSZ;
|
|
|
|
for ( int pos = -(int)curClass.MethodCnt; pos <= (int)curClass.FieldCnt; pos++ )
|
|
{
|
|
union
|
|
{
|
|
SegInfo s;
|
|
FieldInfo f;
|
|
_FMid_ id;
|
|
uchar _space[qmax(sizeof(SegInfo), sizeof(FieldInfo)) + 1]; //lint !e754 not referenced
|
|
} u;
|
|
|
|
if ( !pos ) // class node
|
|
{
|
|
oldsize += (sizeof(FieldInfo) - FLEXPSZ) - (sizeof(SegInfo) - SGEXPSZ);
|
|
continue;
|
|
}
|
|
|
|
if ( ClassNode.supval(pos, &u, sizeof(u)) != oldsize )
|
|
goto BADIDB;
|
|
|
|
memmove((uchar *)&u.id + sizeof(u.id), &u.id._UNUSED_ALING,
|
|
(size_t)oldsize - offsetof(_FMid_, _UNUSED_ALING));
|
|
u.id._UNUSED_ALING = 0;
|
|
u.id.utsign = 0;
|
|
|
|
if ( u.id.extflg & ~EFL__MASK )
|
|
goto BADIDB;
|
|
u.id.extflg &= (EFL_NAMETYPE);
|
|
|
|
if ( pos > 0 ) // fields
|
|
{
|
|
memset(u.f.annNodes, 0, sizeof(u.f)-offsetof(FieldInfo, annNodes));
|
|
ClassNode.supset(pos, &u.f, sizeof(u.f));
|
|
continue;
|
|
}
|
|
|
|
// segments
|
|
memset(&u.s.varNode, 0, sizeof(u.s) - offsetof(SegInfo, varNode));
|
|
if ( u.s.thrNode && !netnode(u.s.thrNode).altval(0) )
|
|
{
|
|
netnode(u.s.thrNode).kill(); // empty node (old format)
|
|
u.s.thrNode = 0;
|
|
}
|
|
|
|
// have locvars?
|
|
if ( u.s.DataSize )
|
|
{
|
|
S = getseg(u.s.DataBase);
|
|
if ( S == NULL )
|
|
goto BADIDB;
|
|
S->type = SEG_BSS;
|
|
S->set_hidden_segtype(true);
|
|
S->update();
|
|
}
|
|
|
|
// change: Exception format
|
|
if ( u.s.excNode )
|
|
{
|
|
netnode enode(u.s.excNode);
|
|
ushort j = (ushort)enode.altval(0);
|
|
if ( j == 0 )
|
|
goto BADIDB;
|
|
ea_t ea = u.s.start_ea + u.s.CodeSize;
|
|
ushort i = 1;
|
|
do
|
|
{
|
|
Exception exc;
|
|
|
|
if ( enode.supval(i, &exc, sizeof(exc)) != sizeof(exc) )
|
|
goto BADIDB;
|
|
|
|
CASSERT(offsetof(Exception, filter.Ref) == offsetof(Exception, filter.Name)
|
|
&& offsetof(Exception, filter.Dscr) == offsetof(Exception, filter.Name) + 2);
|
|
if ( !exc.filter.Name != !exc.filter.Dscr )
|
|
goto BADIDB;
|
|
exc.filter.Ref = (exc.filter.Ref << 16) | exc.filter.Dscr; // was reverse order
|
|
if ( exc.filter.Name == 0xFFFF )
|
|
++exc.filter.Name;
|
|
enode.supset(i, &exc, sizeof(exc));
|
|
set_exception_xref(&u.s, exc, ea);
|
|
}
|
|
while ( ++i <= j );
|
|
}
|
|
ClassNode.supset(pos, &u.s, sizeof(u.s));
|
|
// rename local variables (for references)
|
|
if ( u.s.DataSize )
|
|
{
|
|
int i = u.s.DataSize;
|
|
ea_t ea = u.s.DataBase + i;
|
|
do
|
|
{
|
|
char str[MAXNAMELEN];
|
|
qsnprintf(str, sizeof(str), "met%03u_slot%03d", u.s.id.Number, --i);
|
|
--ea;
|
|
if ( force_name(ea, str) )
|
|
make_name_auto(ea);
|
|
else
|
|
hide_name(ea);
|
|
}
|
|
while ( i > 0 );
|
|
coagulate_unused_data(&u.s);
|
|
}
|
|
} // for
|
|
|
|
// change format of string presentation in constant pool
|
|
FOR_EACH_CONSTANT_POOL_INDEX(pos)
|
|
{
|
|
const_desc_t co;
|
|
if ( constnode.supval(pos, &co, sizeof(co)) != sizeof(co) )
|
|
goto BADIDB;
|
|
switch ( co.type )
|
|
{
|
|
default:
|
|
continue;
|
|
|
|
case CONSTANT_Unicode:
|
|
error("Base contain CONSTANT_Unicode, but it is removed from "
|
|
"the standard in 1996 year and never normal loaded in IDA");
|
|
|
|
case CONSTANT_Utf8:
|
|
break;
|
|
}
|
|
uint32 v, i = pos << 16;
|
|
uint32 n = (uint32)constnode.altval(i);
|
|
if ( (n & UPG12_BADMASK) != 0 || (v = n & ~UPG12_CLRMASK) == 0 )
|
|
goto BADIDB;
|
|
if ( n & UPG12_EXTMASK )
|
|
v |= UPG12_EXTSET;
|
|
n = ushort(v);
|
|
if ( n != 0 )
|
|
{
|
|
uchar *po = (uchar*)append_tmp_buffer(v);
|
|
n *= sizeof(ushort);
|
|
uint32 idx = 0;
|
|
do
|
|
{
|
|
uint32 sz = n - idx;
|
|
if ( sz > MAXSPECSIZE )
|
|
sz = MAXSPECSIZE;
|
|
if ( constnode.supval(++i, &po[idx], sz) != sz )
|
|
goto BADIDB;
|
|
constnode.supdel(i);
|
|
idx += sz;
|
|
}
|
|
while ( idx < n );
|
|
constnode.setblob(po, n, i & ~0xFFFF, BLOB_TAG);
|
|
if ( !(v & UPG12_EXTSET) )
|
|
{
|
|
do
|
|
{
|
|
CASSERT((sizeof(ushort) % 2) == 0 && (MAXSPECSIZE % 2) == 0);
|
|
ushort cw = *(ushort *)&po[idx];
|
|
if ( cw >= CHP_MAX )
|
|
{
|
|
if ( !javaIdent(cw) )
|
|
goto extchar;
|
|
}
|
|
else if ( (uchar)cw <= CHP_MIN )
|
|
{
|
|
extchar:
|
|
v |= UPG12_EXTSET;
|
|
break;
|
|
}
|
|
}
|
|
while ( (idx -= sizeof(ushort)) != 0 );
|
|
}
|
|
v = upgrade_ResW(v);
|
|
}
|
|
constnode.altset(i, v);
|
|
co._Sopstr = v; // my be not needed? (next also)
|
|
constnode.supset(pos, &co, sizeof(co));
|
|
}
|
|
|
|
// rename 'import' variables for refernces
|
|
for ( uint ip = 1; (ushort)ip <= curClass.xtrnCnt; ip++ )
|
|
{
|
|
const_desc_t co;
|
|
{
|
|
uint j = (uint)XtrnNode.altval(ip);
|
|
if ( j == 0 || !LoadOpis(lm_lenient, (ushort)j, 0, &co) )
|
|
goto BADIDB;
|
|
}
|
|
switch ( co.type )
|
|
{
|
|
default:
|
|
goto BADIDB;
|
|
|
|
case CONSTANT_Class:
|
|
if ( !(co.flag & HAS_CLSNAME) )
|
|
continue;
|
|
break;
|
|
case CONSTANT_InterfaceMethodref:
|
|
case CONSTANT_Methodref:
|
|
if ( (co.flag & NORM_METOD) != NORM_METOD )
|
|
continue;
|
|
break;
|
|
case CONSTANT_Fieldref:
|
|
if ( (co.flag & NORM_FIELD) != NORM_FIELD )
|
|
continue;
|
|
break;
|
|
}
|
|
make_new_name(co._name, co._subnam, co.type != CONSTANT_Class, ip);
|
|
}
|
|
|
|
if ( curClass.This.Dscr )
|
|
make_new_name(curClass.This.Name, 0, (uchar)-1, (uint)curClass.start_ea);
|
|
|
|
return _TO_VERSION;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
//----------------------------------------------------------------------
|
|
// some utilities (size of npool)
|
|
//----------------------------------------------------------------------
|
|
// visible for converter only
|
|
char *java_t::convert_clsname(char *buf) const
|
|
{
|
|
if ( jasmin() )
|
|
for ( char *p = buf; (p = strchr(p, j_clspath_dlm)) != NULL; p++ )
|
|
*p = j_field_dlm;
|
|
|
|
return buf;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
// visible for converter only
|
|
uchar set_exception_xref(SegInfo *ps, Exception const & exc, ea_t ea)
|
|
{
|
|
uchar ans = 0;
|
|
|
|
if ( exc.start_pc >= ps->CodeSize )
|
|
{
|
|
ans = 1;
|
|
}
|
|
else
|
|
{
|
|
if ( !exc.start_pc )
|
|
ps->id.extflg |= XFL_M_LABSTART; // special label at entry
|
|
add_dref(ea, ps->start_ea + exc.start_pc, dr_I);
|
|
}
|
|
if ( exc.end_pc > ps->CodeSize )
|
|
{
|
|
ans = 1;
|
|
}
|
|
else
|
|
{
|
|
if ( exc.end_pc == ps->CodeSize )
|
|
ps->id.extflg |= XFL_M_LABEND; // special label at end
|
|
add_dref(ea, ps->start_ea + exc.end_pc, dr_I);
|
|
}
|
|
if ( exc.handler_pc >= ps->CodeSize )
|
|
return 1;
|
|
add_dref(ea, ps->start_ea + exc.handler_pc, dr_I);
|
|
return ans;
|
|
}
|