Files
sigmaker-ida/idasdk76/module/java/npooluti.cpp
2021-10-31 21:20:46 +02:00

2032 lines
57 KiB
C++

#include "java.hpp"
#include <diskio.hpp>
#include <entry.hpp>
#include "npooluti.hpp"
#include "oututil.hpp"
#ifndef NCPS
#define NCPS 0x110000
#endif
//-----------------------------------------------------------------------
NORETURN void errtrunc(void)
{
loader_failure("Premature end of file");
}
//-----------------------------------------------------------------------
GCC_DIAG_OFF(format-nonliteral);
void java_t::load_msg(const char *format, ...)
{ // this procedure prepares saving load-time message to base
char str[MAXSTR];
va_list va;
++errload;
va_start(va, format);
int cnt = qvsnprintf(str, sizeof(str), format, va);
va_end(va);
msg("%s", str);
for ( int i = cnt; i; )
{
if ( str[--i] <= ' ' ) // remove cr's
continue;
if ( ++i > MAXSPECSIZE )
{
i = MAXSPECSIZE;
memcpy(&str[MAXSPECSIZE-3], "...", 3);
}
netnode temp;
uval_t j;
if ( !curClass.msgNode )
{
temp.create();
curClass.msgNode = temp;
j = 0;
}
else
{
temp = curClass.msgNode;
j = temp.altval(0);
}
temp.supset(j, str, i);
temp.altset(0, j+1);
break;
}
}
GCC_DIAG_ON(format-nonliteral);
//-----------------------------------------------------------------------
const char *java_t::mk_diag(attr_parent_kind_t apk, char str[128]) const
{
static const char *const diag[] = { "Code in method", "Field", "Method" };
str[0] = '\0';
if ( apk < attr_parent_kind_class_file )
qsnprintf(str,
126,
" for %s#%u", diag[uchar(apk)],
apk == attr_parent_kind_field ? curField.id.Number : curSeg.id.Number);
return str;
}
//-----------------------------------------------------------------------
void java_t::BadRef(ea_t ea, const char *to, ushort id, attr_parent_kind_t apk)
{
if ( ea != BADADDR )
remember_problem(PR_DISASM, ea);
char diastr[128];
load_msg("Illegal %s reference (%u)%s\n", to, id, mk_diag(apk, diastr));
}
//-----------------------------------------------------------------------
void java_t::mark_access(ea_t ea, ushort acc) const
{
char str[60];
str[0] = 0; // for module
if ( acc )
qsnprintf(str, sizeof(str), "Illegal access bits (0x%X)", acc);
mark_and_comment(ea, str);
}
//-------------------------------------------------------------------------
static const char *_constant_strings[CONSTANT_LAST+1] =
{
// 0
"<UNKNOWN>",
"Utf8",
"Unicode",
"Integer",
"Float",
// 5
"Long",
"Double",
"Class",
"String",
"Fieldref",
// 10
"Methodref",
"InterfaceMethodref",
"NameAndType",
"<UNUSED_13>",
"<UNUSED_14>",
// 15
"MethodHandle",
"MethodType",
"<UNUSED_17>",
"InvokeDynamic",
};
const char *constant_type_to_str(uchar ctype)
{
if ( ctype > CONSTANT_LAST )
ctype = 0;
return _constant_strings[ctype];
}
//-------------------------------------------------------------------------
void print_constant(
qstrvec_t *out,
const const_desc_t &cd,
ushort index,
bool strip_tags)
{
size_t anchor = out->size();
op_t x;
memset(&x, 0, sizeof(x));
copy_const_to_opnd(x, cd);
x.ref = 0; // as flag
x.cp_type = cd.type;
x.cp_ind = index;
if ( x.cp_type == CONSTANT_Class )
x.addr_shorts.high = (cd.flag & HAS_CLSNAME) != 0 ? fmt_fullname : fmt_ClassName;
out_java_t *ctx = (out_java_t *) create_outctx(BADADDR);
ctx->init_lines_array(out, 1000);
ctx->init_prompted_output();
ctx->OutConstant(x, /*include_descriptor=*/ true);
ctx->flush_outbuf();
if ( strip_tags )
{
for ( ; anchor < out->size(); ++anchor )
tag_remove(&out->at(anchor));
}
delete ctx;
}
//-----------------------------------------------------------------------
void *myAlloc(uint size)
{
void *p = qalloc(size);
if ( p == NULL )
nomem("JavaLoader");
return p;
}
//-----------------------------------------------------------------------
uchar *java_t::sm_realloc(uint size)
{
if ( size > curClass.maxSMsize )
{
curClass.maxSMsize = size;
qfree(smBuf);
smBuf = (uchar*)myAlloc(size+1);
}
return smBuf;
}
//-----------------------------------------------------------------------
uchar *java_t::annotation_realloc(uint size)
{
if ( size > curClass.maxAnnSz )
{
curClass.maxAnnSz = size;
qfree(annBuf);
annBuf = (uchar*)myAlloc(size+1);
}
return annBuf;
}
//-----------------------------------------------------------------------
// visible for converter only
ushort *java_t::append_tmp_buffer(uint size)
{
if ( (ushort)size > curClass.maxStrSz )
{
curClass.maxStrSz = (ushort)size;
qfree(tsPtr);
tsPtr = (ushort*)myAlloc(size*sizeof(ushort)*2+sizeof(ushort));
}
return tsPtr;
}
//-----------------------------------------------------------------------
bool java_t::getblob(uval_t ind, void *p, uval_t sz)
{
if ( (ushort)sz > curClass.maxStrSz )
return false;
sz *= 2;
size_t ts = (size_t)sz + 1;
return ConstantNode.getblob(p, &ts, ind, BLOB_TAG) && (uint32)ts == sz;
}
//-------------------------------------------------------------------------
bool java_t::getstr(qstring *out, ushort index)
{
bool ok = is_valid_string_index(index);
if ( ok )
{
// || !getblob(ind2, p2 = p1 + (size_t)siz1, siz2) )
// uval_t i1 = ConstantNode.altval(ind1);
uint32 raw_idx = (uint32)index << 16;
nodeidx_t sz = ushort(ConstantNode.altval(raw_idx));
ok = sz > 0;
if ( ok )
{
qvector<ushort> raw;
raw.resize(sz, 0);
msg("Reading %u bytes\n", uint32(sz));
ok = getblob(raw_idx, raw.begin(), sz);
if ( ok )
out->append((const char *) raw.begin(), sz);
}
}
return ok;
}
//----------------------------------------------------------------------
NORETURN static void readerr(void)
{
loader_failure("Input file read error");
}
//-----------------------------------------------------------------------
ushort java_t::read2(void)
{
ushort data;
if ( FileSize < 2 )
errtrunc();
FileSize -= 2;
if ( fread2bytes(myFile, &data, 1) != 0 )
readerr();
return data;
}
//-----------------------------------------------------------------------
uint32 java_t::read4(void)
{
uint32 data;
if ( FileSize < 4 )
errtrunc();
FileSize -= 4;
if ( fread4bytes(myFile, &data, 1) != 0 )
readerr();
return data;
}
//-----------------------------------------------------------------------
uchar java_t::read1(void)
{
uchar data;
if ( !FileSize )
errtrunc();
--FileSize;
if ( qfread(myFile, &data, 1) != 1 )
readerr();
return data;
}
//-----------------------------------------------------------------------
void java_t::readData(void *data, uint32 size)
{
if ( FileSize < size )
errtrunc();
FileSize -= size;
if ( qfread(myFile, data, size) != size )
readerr();
}
//-----------------------------------------------------------------------
void java_t::skipData(uint32 size)
{
if ( FileSize < size )
errtrunc();
FileSize -= size;
qfseek(myFile, size, SEEK_CUR);
}
//-----------------------------------------------------------------------
uchar java_t::set_parent_object(void)
{
if ( curClass.super.Name )
{
static const char object[] = "java.lang.Object";
if ( fmtName(curClass.super.Name, tmpbuf, sizeof(tmpbuf), fmt_fullname)
&& memcmp(tmpbuf, object, sizeof(object)) == 0 )
{
curClass.extflg |= XFL_C_SUPEROBJ;
return 1;
}
}
return 0;
}
//-----------------------------------------------------------------------
const uchar *java_t::get_annotation(uval_t node, uint *plen)
{
netnode temp(node);
size_t len = (size_t)temp.altval(0);
if ( len && len <= curClass.maxAnnSz )
{
*plen = (uint)len;
++len;
if ( temp.getblob(annBuf, &len, 0, BLOB_TAG) && len == *plen )
return annBuf;
}
return NULL;
}
//-----------------------------------------------------------------------
bool java_t::sm_getinfo(const insn_t &insn, SMinfo *pinf)
{ // call ONLY when curSeg.smNode != 0
sm_info_t smr;
ea_t ea;
switch ( sm_node )
{
case smn_aa_not_finished:
goto noinfo;
case smn_ok:
sm_node = smn_no_use;
SMnode = curSeg.smNode;
{
size_t cnt = (size_t)SMnode.altval(-1);
if ( cnt < 2 || cnt > curClass.maxSMsize )
goto destroyed;
SMsize = (uint32)cnt;
++cnt;
if ( !SMnode.getblob(smBuf, &cnt, 0, BLOB_TAG) || cnt != SMsize )
goto destroyed;
}
default:
break;
}
ea = pinf->ea;
if ( ea == BADADDR )
ea = insn.ea - 1;
ea = SMnode.supnext(ea);
if ( ea == BADNODE )
goto noinfo;
if ( get_item_head(ea) != insn.ea )
goto noinfo;
if ( SMnode.supval(ea, &smr, sizeof(smr)) != sizeof(smr) )
goto destroyed;
if ( smr.noff >= 2 && smr.eoff > smr.noff && smr.eoff <= SMsize )
{
pinf->ea = ea;
pinf->pb = smBuf + smr.noff;
pinf->pe = smBuf + smr.eoff;
pinf->fcnt = smr.fcnt;
return true;
}
destroyed:
DESTROYED("sm_getinfo");
noinfo:
return false;
}
//-----------------------------------------------------------------------
static const char special_sym[] =
{
j_field_dlm, // classname (dot) ==> special point
j_clspath_dlm, // classname path (slash)
j_parm_list_start, j_parm_list_end, // function (for methods)
0
};
//-------------------------------------------------------------------------
void op_NameChars(namechar_op_t op)
{
switch ( op )
{
case ncop_disable:
for ( size_t i = 0; i < qnumber(special_sym); ++i )
set_cp_validity(UCDR_NAME, special_sym[i], BADCP, false);
break;
case ncop_enable:
for ( size_t i = 0; i < qnumber(special_sym); ++i )
set_cp_validity(UCDR_NAME, special_sym[i]);
break;
case ncop_enable_without_parens:
for ( size_t i = 0; i < 2; ++i )
set_cp_validity(UCDR_NAME, special_sym[i]);
break;
default: INTERR(10267);
}
}
//-----------------------------------------------------------------------
void make_NameChars(bool on_load)
{
static const char special_char[] =
{
'$', '_', // MUST present (historical/special)
j_sign, j_endsign, // special case for <init>, <clinit> :(
};
set_cp_validity(UCDR_NAME, 0, NCPS, false);
// in names accepted ONLY english chars (temporary?)
set_cp_validity(UCDR_NAME, 'A', 'Z'+1);
set_cp_validity(UCDR_NAME, 'a', 'z'+1);
set_cp_validity(UCDR_NAME, '0', '9'+1);
for ( size_t i = 0; i < qnumber(special_char); ++i )
set_cp_validity(UCDR_NAME, special_char[i]);
// fill national character's
set_cp_validity(UCDR_NAME, '\\'); // is valid for unicode escape sequnce only (special work)
// class/method path/call chars
op_NameChars(on_load ? ncop_enable : ncop_enable_without_parens); // for oldbase convertation
}
//----------------------------------------------------------------------
segment_t *java_t::getMySeg(ea_t ea, segment_t *seg)
{
segment_t *s = seg != NULL ? seg : getseg(ea);
if ( s == NULL )
goto compat_err;
if ( curSeg.start_ea != s->start_ea )
{
if ( sm_node > smn_ok )
sm_node = smn_ok;
if ( !s->orgbase )
{
if ( s->type != SEG_IMP && s->type != SEG_XTRN )
goto compat_err;
curSeg.start_ea = s->start_ea;
}
else
{
if ( ClassNode.supval(s->orgbase, &curSeg, sizeof(curSeg) ) != sizeof(curSeg) )
DESTROYED("getMySeg");
if ( -s->orgbase != curSeg.id.Number
|| s->start_ea != (s->type == SEG_BSS ? curSeg.DataBase : curSeg.start_ea) )
{
compat_err:
UNCOMPAT("getMySeg");
}
}
}
return s;
}
//-----------------------------------------------------------------------
// visible for converter only
GCC_DIAG_OFF(format-nonliteral);
void out_java_t::trunc_name(uint num, uchar type)
{
static const char fnam[] = "...(Field_%u)";
static const char metnam[] = "...(Method_%u)";
static const char locnam[] = "...(locvar_%u)";
static const char xtrn[] = "...(extern_%u)";
static const char clsnam[] = "...";
static const char *const add_nam[5] = { xtrn, fnam, metnam, locnam, clsnam };
enableExt_NameChar();
size_t s = (sizeof(metnam) - 2 + 5 + 1);
size_t inplen = outbuf.length();
outbuf.resize(inplen - s);
outbuf.cat_sprnt(add_nam[type], num);
}
GCC_DIAG_ON(format-nonliteral);
//-----------------------------------------------------------------------
int java_t::CmpString(ushort index1, ushort index2)
{
DEB_ASSERT((!index1 || !index2), "cs-ind");
if ( index1 != index2 )
{
size_t i;
uval_t ind1 = (uint32)index1 << 16;
uval_t ind2 = (uint32)index2 << 16;
uval_t sz = ConstantNode.altval(ind1);
if ( sz == 0 || (i=(size_t)ConstantNode.altval(ind2)) == 0 )
{
BADIDB:
DESTROYED("CmpString");
}
if ( sz != i )
{
diff:
return 1;
}
i = (ushort)i;
if ( i == 0 )
return -1;
sz = i;
i *= sizeof(ushort);
uchar *p1 = (uchar *)tsPtr, *p2 = p1 + i;
if ( !getblob(ind1, p1, sz) || !getblob(ind2, p2, sz) )
goto BADIDB;
if ( memcmp(p1, p2, i) != 0 )
goto diff;
}
return 0;
}
//-----------------------------------------------------------------------
int java_t::cmpDscrString(ushort index1, uchar met, ushort index2, uchar self)
{
uval_t siz1, siz2;
ushort *p1, *p2;
uval_t ind1 = (uint32)index1 << 16;
uval_t ind2 = (uint32)index2 << 16;
uval_t i1 = ConstantNode.altval(ind1);
uval_t i2 = ConstantNode.altval(ind2);
if ( i1 == 0
|| i2 == 0
|| (siz1 = (ushort)i1) == 0
|| (siz2 = (ushort)i2) == 0
|| !getblob(ind1, p1 = tsPtr, siz1)
|| !getblob(ind2, p2 = p1 + (size_t)siz1, siz2) )
{
goto int_err;
}
if ( met )
{
#define _MCR ((_OP_ONECLS | _OP_VALPOS) << 16)
if ( (i1 & _MCR) != _MCR )
goto diff;
#undef _MCR
i1 = ConstantNode.altval(ind1+1);
if ( !i1 || (int32)(siz1 -= i1) <= 0 )
goto int_err; // never signature
p1 += (size_t)i1;
}
if ( self && !(i1 & (_OP_NODSCR << 16)) )
{
while ( *p1 == j_array )
{
if ( !--siz1 )
goto int_err;
++p1;
}
}
if ( (i1 ^ i2) & (_OP_NODSCR << 16) )
{
if ( i2 & (_OP_NODSCR << 16) )
{
if ( *p1 == j_class && p1[(size_t)siz1-1] == j_endclass )
{
++p1;
if ( (int)(siz1 -= 2) <= 0 )
goto int_err;
}
}
else
{
if ( *p2 == j_class && p2[(size_t)siz2-1] == j_endclass )
{
++p2;
if ( (int)(siz2 -= 2) <= 0 )
goto int_err;
}
}
}
if ( siz1 != siz2 || memcmp(p1, p2, (size_t)siz1 * sizeof(ushort)) != 0 )
goto diff;
return 0;
int_err:
INTERNAL("cmpDscrString");
diff:
return 1;
}
//-----------------------------------------------------------------------
ushort java_t::xtrnDscrSearch(ushort name, uchar met)
{
const_desc_t cr;
if ( curClass.This.Dscr
&& !cmpDscrString(name, met, curClass.This.Name, 1) )
{
return 0xFFFF;
}
for ( ushort j = curClass.xtrnLQE; j; j = (ushort)(XtrnNode.altval(j) >> 16) )
{
if ( ConstantNode.supval(j, &cr, sizeof(cr)) != sizeof(cr)
|| cr.type != CONSTANT_Class
|| (j = cr.ref_ip) == 0 )
{
INTERNAL("xtrnDscrSearch");
}
if ( !cmpDscrString(name, met, cr._name, 0) )
return j;
}
return 0;
}
//-----------------------------------------------------------------------
void java_t::mark_strange_name(ea_t ea) const
{
mark_and_comment(ea, "Strange name");
}
//-----------------------------------------------------------------------
void java_t::xtrnSet(
uint cin,
const_desc_t *co,
uint xip,
char *str,
size_t strsize,
bool full,
uchar rmod)
{
ea_t ea = curClass.xtrnEA + xip;
if ( !(rmod & 4) )
{
co->ref_ip = (ushort)xip;
StoreOpis(cin, *co);
uval_t rfa = cin;
if ( full )
{
rfa |= ((uval_t)curClass.xtrnLQE << 16);
curClass.xtrnLQE = (ushort)cin;
}
XtrnNode.altset(xip, rfa);
create_byte(ea, 1);
}
uint js = MAXNAMELEN - 1;
out_java_t *pctx = (out_java_t *)create_outctx(BADADDR);
name_chk = 0;
if ( full ) // fmt_fullname
{
uni_chk = 0;
if ( pctx->fmtString(*this, co->_name, js, fmt_fullname) )
{
endcls = MAXNAMELEN;
trnc:
pctx->trunc_name(xip);
pctx->outbuf.resize(MAXNAMELEN-1);
}
else
{
endcls = (uint)strlen(pctx->outbuf.c_str());
}
clunic = uni_chk;
}
else
{
uni_chk = clunic;
if ( endcls >= MAXNAMELEN - 2 )
{
pctx->outbuf.resize(MAXNAMELEN-1);
name_chk = 0; // no mark here
goto trnc;
}
pctx->outbuf.resize(pctx->outbuf.length() + (endcls + 1));
pctx->outbuf[endcls] = '.';
js -= (endcls + 1);
if ( pctx->fmtString(*this, co->_subnam, js, fmt_UnqualifiedName) )
goto trnc;
}
qstrncpy(str, pctx->outbuf.c_str(), strsize);
delete pctx;
if ( rmod & 1 )
{
// enableExt_NameChar();
force_name(ea, convert_clsname(str));
hide_name(ea);
// disableExt_NameChar();
}
if ( (char)uni_chk > 0 && (rmod & 2) )
ConstantNode.charset(ea, uni_chk, UR_TAG);
uni_chk = (uchar)-1;
if ( name_chk && !(rmod & 4) )
mark_strange_name(ea);
}
//-----------------------------------------------------------------------
void java_t::SetName(ushort name, ea_t ea, ushort access_mode, uval_t number, uchar rmod)
{
uni_chk = name_chk = 0;
fmt_t fmt = number || curSeg.id.Number ? fmt_UnqualifiedName : fmt_fullname;
out_java_t *pctx = (out_java_t *)create_outctx(BADADDR);
if ( pctx->fmtString(*this, name, sizeof(tmpbuf) - 1, fmt) )
{
if ( !number )
pctx->trunc_name(curSeg.id.Number, uchar(3 + !curSeg.id.Number));
else if ( number <= (uval_t)curClass.FieldCnt )
pctx->trunc_name((uint)number, 1);
else
pctx->trunc_name((uint)number - curClass.FieldCnt, 2);
}
qstrncpy(tmpbuf, pctx->outbuf.c_str(), sizeof(tmpbuf));
delete pctx;
convert_clsname(tmpbuf);
if ( rmod & 1 )
{
switch ( access_mode & ACC_ACCESS_MASK )
{
case ACC_PUBLIC:
if ( rmod & 4 )
del_global_name(ea);
add_entry(number, ea, tmpbuf, 0);
break;
case 0:
if ( rmod & 4 )
del_global_name(ea);
add_entry(ea, ea, tmpbuf, 0);
break;
default:
force_name(ea, tmpbuf);
break;
}
}
// disableExt_NameChar();
if ( (char)uni_chk > 0 && (rmod & 2) )
ConstantNode.charset(ea, uni_chk, UR_TAG);
uni_chk = (uchar)-1;
if ( name_chk && !(rmod & 4) )
mark_strange_name(ea);
}
//-----------------------------------------------------------------------
// as procedure for rename_unichars
void java_t::set_lv_name(ushort name, ea_t ea, uchar rmod)
{
uni_chk = name_chk = 0;
if ( fmtName(name, tmpbuf, sizeof(tmpbuf), fmt_UnqualifiedName) )
{
if ( rmod & 1 )
force_name(ea, tmpbuf);
hide_name(ea);
if ( (char)uni_chk > 0 && (rmod & 2) )
ConstantNode.charset(ea, uni_chk, UR_TAG);
if ( name_chk && !(rmod & 4) )
mark_strange_name(ea);
}
uni_chk = (uchar)-1;
}
//--------------------------------------------------------------------------
void java_t::rename_uninames(int32 mode)
{
nodeidx_t id = ConstantNode.charfirst(UR_TAG);
if ( id != BADNODE )
{
char str[MAXNAMELEN]; // for imports
show_wait_box("HIDECANCEL\nRenaming labels with national characters");
ushort lcls = 0; // for imports
uchar rmod = 7; // rename+save (+renamemode)
switch ( mode )
{
case 0: // change table but renaming not needed (recreate records only)
rmod = 2; // save only
break;
case -1: // change processor flag only
rmod = 5; // rename only
// no break
default: // change table and renaming needed
break;
}
do
{
adiff_t dif;
ea_t ea = id;
uchar type = ConstantNode.charval(ea, UR_TAG);
show_addr(ea);
if ( !type || type > 3 )
goto BADIDB;
if ( !(type & 2) && mode == -1 )
continue;
switch ( getMySeg(ea)->type )
{
default:
BADIDB:
DESTROYED("rename_uninames");
case SEG_BSS:
if ( !curSeg.varNode
|| (dif = ea - curSeg.DataBase) < 0
|| dif >= curSeg.DataSize
|| is_align(get_flags(ea)) )
{
goto BADIDB;
}
{
netnode tmp(curSeg.varNode);
LocVar lv;
if ( tmp.supval((nodeidx_t)dif, &lv, sizeof(lv)) != sizeof(lv) )
goto BADIDB;
set_lv_name(lv.var.Name, ea, rmod);
}
break;
case SEG_CODE:
if ( ea != curSeg.start_ea )
goto BADIDB;
SetName(curSeg.id.name, ea, curSeg.id.access,
curClass.FieldCnt + curSeg.id.Number, rmod);
break;
case SEG_IMP: // class/fields
dif = ea - curClass.start_ea;
if ( dif < 0 )
goto BADIDB;
if ( !dif ) // class
{
ushort sv = curSeg.id.Number;
curSeg.id.Number = 0;
SetName(curClass.This.Name, ea, curClass.AccessFlag, 0, rmod);
curSeg.id.Number = sv;
break;
}
if ( dif > curClass.FieldCnt )
goto BADIDB;
if ( ClassNode.supval((nodeidx_t)dif, &curField, sizeof(curField) ) != sizeof(curField) )
goto BADIDB;
SetName(curField.id.name, ea, curField.id.access, (int)dif, rmod);
break;
case SEG_XTRN:
dif = ea - curClass.xtrnEA;
if ( dif <= 0 || dif > curClass.xtrnCnt )
goto BADIDB;
{
uchar cmod = rmod;
const_desc_t co;
{
uint j = (uint)XtrnNode.altval((nodeidx_t)dif);
if ( j == 0 )
goto BADIDB;
if ( !LoadOpis(lm_normal, (ushort)j, 0, &co) )
goto BADIDB;
}
switch ( co.type )
{
default:
goto BADIDB;
case CONSTANT_Fieldref:
case CONSTANT_InterfaceMethodref:
case CONSTANT_Methodref:
if ( co._name != lcls )
{
cmod = 4; // set internal static variables only
LCLASS:
lcls = co._name;
xtrnSet(-1, &co, (uint)dif, str, sizeof(str), true, cmod);
if ( co.type == CONSTANT_Class )
break;
}
xtrnSet(-1, &co, (uint)dif, str, sizeof(str), false, rmod);
break;
case CONSTANT_Class:
goto LCLASS;
}
}
break;
}
}
while ( (id = ConstantNode.charnext(id, UR_TAG)) != BADNODE );
hide_wait_box();
}
}
//-----------------------------------------------------------------------
void java_t::xtrnRef(ea_t ea, const const_desc_t &opis) const
{
if ( (loadMode & MLD_EXTREF) && opis.ref_ip )
{
ea_t target = opis.ref_ip == 0xFFFF
? curClass.start_ea
: curClass.xtrnEA + opis.ref_ip;
add_dref(ea, target, dr_I);
}
}
//-----------------------------------------------------------------------
void java_t::xtrnRef_dscr(ea_t ea, const_desc_t *opis, uchar met)
{
if ( !met )
{
if ( !(loadMode & MLD_VARREF) )
return;
if ( (opis->flag & (HAS_CLSNAME | HAS_TYPEDSCR)) == HAS_CLSNAME )
return;
}
else if ( !(loadMode & MLD_METHREF) )
{
return;
}
const_desc_t cr(*opis);
opis = &cr;
opis->ref_ip = xtrnDscrSearch(opis->_name, met);
xtrnRef(ea, *opis);
}
//-----------------------------------------------------------------------
void java_t::deltry(uint bg, uint ic, uint ui, const const_desc_t &pco)
{
for ( uint i = bg; (ushort)i <= curClass.xtrnCnt; i++ )
{
uint j = (uint)XtrnNode.altval(i, '0');
if ( j == 0 )
continue;
const_desc_t co;
ConstantNode.supval(j, &co, sizeof(co));
if ( co.type != pco.type
|| co.flag != pco.flag
|| co.ref_ip != (ushort)ic
|| CmpString(co._subnam, pco._subnam)
|| CmpString(co._dscr, pco._dscr) )
{
continue;
}
co.ref_ip = (ushort)ui;
StoreOpis(j, co);
XtrnNode.altdel(i, '0');
}
}
//-----------------------------------------------------------------------
GCC_DIAG_OFF(format-nonliteral);
segment_t *java_t::_add_seg(int caller)
{
static const char *const _cls[4] = { "xtrn", "met_", "_var", "head" };
static const char *const fm[4] = { "import", "met%03u", "var%03u", "_Class" };
uval_t size;
uchar type;
switch ( caller )
{
default:
INTERNAL("_add_seg");
case 1: // method
curSeg.start_ea = start_ea;
// fallthrough
case -1: // code
start_ea = curSeg.start_ea;
type = SEG_CODE;
size = curSeg.CodeSize;
break;
case 2: // data
curSeg.DataBase = start_ea;
size = curSeg.DataSize;
type = SEG_BSS;
break;
case 3: // class
curClass.start_ea = start_ea;
size = curClass.FieldCnt + 1;
type = SEG_IMP;
break;
case 0: // header
curClass.xtrnEA = start_ea = to_ea(inf_get_baseaddr(), 0);
if ( !curClass.xtrnCnt )
return NULL;
size = curClass.xtrnCnt;
type = SEG_XTRN;
break;
}
ea_t top = start_ea + size;
ea_t end = (top + (0xF + 1)) & ~0xF;
if ( top < start_ea )
loader_failure("Our of addressing space");
segment_t *S;
if ( caller < 0 )
{
S = getseg(start_ea);
if ( S == NULL || !set_segm_end(curSeg.start_ea, end, SEGMOD_KILL) )
qexit(1);
qoff64_t pos = qftell(myFile);
linput_t *li = make_linput(myFile);
file2base(li, pos, start_ea, top, FILEREG_PATCHABLE);
unmake_linput(li);
qfseek(myFile, pos + curSeg.CodeSize, SEEK_SET);
}
else
{
sel_t sel;
if ( start_ea > 0x100000 )
{
sel = cursel++;
set_selector(sel, start_ea>>4);
}
else
{
sel = (ushort)(start_ea >> 4);
}
if ( !add_segm(sel, start_ea, end, NULL, _cls[caller]) )
qexit(1);
S = getseg(start_ea);
S->orgbase = -(uval_t)curSeg.id.Number;
S->type = type;
if ( caller != 1 )
S->set_hidden_segtype(true); // no out comment of segment type
char sname[32];
qsnprintf(sname, sizeof(sname), fm[caller], curSeg.id.Number);
set_segm_name(S, sname);
if ( caller <= 1 )
goto end_create; // method/header
for ( uval_t i = 0; start_ea < top; start_ea++, i++ ) // data & class
{
create_byte(start_ea, 1);
if ( caller == 2 ) // data
{
char str[MAXNAMELEN];
qsnprintf(str, sizeof(str), "met%03u_slot%03" FMT_EA "u", curSeg.id.Number, i);
if ( force_name(start_ea, str) )
make_name_auto(start_ea);
else
hide_name(start_ea);
}
}
}
create_byte(top, end - top); // !header && !method
end_create:
start_ea = end;
return S;
}
GCC_DIAG_ON(format-nonliteral);
//-----------------------------------------------------------------------
void java_t::resizeLocVars(void) const
{
netnode temp(curSeg.varNode);
int slot = curSeg.DataSize;
for ( int32 cur, prev = 1; --slot >= 0; prev = cur )
{
cur = (int32)temp.altval(slot);
if ( cur < 0 && !prev )
{
del_items(curSeg.DataBase + slot+1, DELIT_SIMPLE);
create_word(curSeg.DataBase + slot, 2);
}
}
}
//-----------------------------------------------------------------------
const char *java_t::CopyAttrToFile(const char *astr, uint32 size, ushort id)
{
if ( FileSize < size )
errtrunc(); // here for alloc diagnostic
char fname[QMAXPATH];
qstrncpy(fname, get_path(PATH_TYPE_CMD), sizeof(fname));
char *ptr = (char *)get_file_ext(fname);
if ( ptr == NULL )
{
ptr = &fname[strlen(fname)];
*ptr++ = '.';
}
uint32 sz = uint32(ptr - fname);
uval_t *pnode = NULL;
if ( astr[0] == ' ' ) // SourceDebugExtension
{
if ( sz > sizeof(fname)-sizeof("SDE.utf8") )
{
too_long:
return "PathName too long";
}
memcpy(ptr, "SDE.utf8", sizeof("SDE.utf8"));
}
else
{
if ( sz > (sizeof(fname)-30) )
goto too_long;
switch ( (uchar)astr[0] )
{
default: // ARQ_FILE:
pnode = &curClass.genNode;
break;
case attr_parent_kind_field:
ptr += qsnprintf(ptr, 30, "fld%03u_", curField.id.Number);
pnode = &curField.genNode;
break;
case attr_parent_kind_code:
case attr_parent_kind_method:
pnode = &curSeg.genNodes[astr[0] == attr_parent_kind_code];
ptr += qsnprintf(ptr, 30, "%smet%03u.",
astr[0] == attr_parent_kind_code ? "code_" : "",
curSeg.id.Number);
break;
}
uchar err = 0;
for ( sz = 1; ptr < &fname[sizeof(fname) - sizeof(".attr")]; sz++ ) //lint !e440
{
uchar c = astr[sz];
switch ( c )
{
case 0:
goto full_copy;
default:
if ( c > CHP_MIN && c < CHP_MAX )
{
*ptr++ = c;
break;
}
// no break
case '/':
case '\\':
case '>':
case '<':
case '?':
case '*':
case '=':
err = 1;
break;
}
}
ptr[-1] = '!'; // as marker of truncated name
full_copy:
memcpy(ptr, ".attr", sizeof(".attr"));
if ( err )
msg("Convert unprintable filename for attribute '%s'\n", &astr[1]);
}
ptr = fname;
while ( (ptr=strchr(ptr, '\\')) != NULL )
*ptr = '/';
ptr = (char *)myAlloc(size + 1); // +1 for zero_size extension!
readData(ptr, size);
FILE *f = qfopen(fname, "wb");
if ( f == NULL )
{
qfree(ptr);
return "Can't create file for storing";
}
uchar err = 0;
if ( qfwrite(f, ptr, size) != size )
++err;
qfree(ptr);
if ( qfclose(f) && !err )
{
qunlink(fname);
return "Error writing";
}
if ( pnode )
{
netnode temp;
uint32 pos = 0;
if ( *pnode )
{
temp = *pnode;
}
else
{
temp.create();
*pnode = temp;
pos = (uint32)temp.altval(0);
}
++pos;
temp.altset(pos, id);
temp.supset(pos, fname, strlen(fname));
temp.altset(0, pos);
}
return NULL;
}
//-----------------------------------------------------------------------
bool java_t::fmtName(ushort index, char *buf, size_t bufsize, fmt_t fmt)
{
out_java_t *pctx = (out_java_t *)create_outctx(BADADDR);
int i = pctx->fmtString(*this, index, bufsize-1, fmt);
qstrncpy(buf, pctx->outbuf.c_str(), bufsize);
delete pctx;
return !i && buf[0];
}
//--------------------------------------------------------------------------
// Procedures for "press Enter on any name"
int java_t::is_locvar_name(const insn_t &insn, const char *name)
{
LocVar lv;
uint32 idx = (uint32)insn.Op1.addr;
if ( insn.Op1.type == o_mem )
{
if ( insn.Op1.ref )
goto bad;
}
else if ( insn.Op1.type == o_void )
{
if ( (char)insn.Op1.ref < 0 || (int32)(idx -= (uint32)curSeg.DataBase) < 0 )
goto bad;
}
if ( netnode(curSeg.varNode).supval(idx, &lv, sizeof(lv)) == sizeof(lv)
&& fmtName(lv.var.Name, tmpbuf, sizeof(tmpbuf), fmt_UnqualifiedName)
&& streq(name, tmpbuf) )
{
return idx;
}
bad:
return -1;
}
//-------------------------------------------------------------------------
static bool is_get_ref_addr_visible_cp(wchar32_t cp)
{
return cp == j_field_dlm || cp == j_clspath_dlm || is_visible_cp(cp);
}
//--------------------------------------------------------------------------
ea_t java_t::get_ref_addr(ea_t ea, const char *name, size_t pos)
{
if ( strlen(name) <= pos || getseg(ea) == NULL )
{
NOT_FOUND:
return BADADDR;
}
uchar clv = getMySeg(ea)->type;
switch ( clv ) // also set curSeg
{
case SEG_XTRN:
if ( !jasmin() )
goto NOT_FOUND; // short form. Can't search by text
// no break
default:
break;
case SEG_CODE:
if ( strstrpos(name, ash.cmnt) <= pos )
clv |= 0x80; // flag for 'modified autocomment' (see make_locvar_cmt)
break;
}
ssize_t r = pos;
if ( !is_get_ref_addr_visible_cp(uchar(name[r])) )
goto NOT_FOUND;
while ( r > 0 && is_get_ref_addr_visible_cp(uchar(name[r-1])) )
--r;
ssize_t start = r;
for ( r = pos+1; name[r]; r++ )
if ( !is_get_ref_addr_visible_cp(uchar(name[r])) )
break;
if ( name[r] == '\\' && !name[r+1] )
goto NOT_FOUND; //\\+++ not work with prompt?
char buf[MAXSTR*2];
memcpy(buf, &name[start], r);
buf[r] = '\0';
switch ( clv & ~0x80 )
{
case SEG_CODE:
case SEG_BSS:
r = check_special_label(buf, r);
if ( r >= 0 )
return curSeg.start_ea + r;
// no break
default:
break;
}
insn_t insn;
decode_insn(&insn, ea);
if ( (clv&0x80) && curSeg.varNode && (start = is_locvar_name(insn, buf)) >= 0 )
return curSeg.DataBase + start;
// append(new)
ea_t rea = get_name_ea(BADADDR, convert_clsname(buf));
if ( rea == BADADDR && jasmin() && (clv&~0x80) == SEG_CODE ) // fieldnames
{
char *p = strrchr(buf, j_field_dlm);
if ( p )
{
*p++ = '\0';
if ( get_name_ea(BADADDR, buf) == curClass.start_ea )
rea = get_name_ea(BADADDR, p);
}
}
return rea;
}
//-----------------------------------------------------------------------
// for IDF_SHOWBADSTR (index my be not string :)
bool java_t::is_valid_string_index(ushort index) const
{
return index > 0
&& index <= curClass.maxCPindex
&& ConstantNode.altval(((uint32)index) << 16);
}
//-----------------------------------------------------------------------
/* signatures encoding
*
* methodOrFieldSignature ::= type
* classSignature ::= [ typeparams ] supertype { interfacetype }
*
* type ::= ... | classtype | methodtype | typevar
* classtype ::= classsig { '.' classsig }
* classig ::= 'L' name [typeargs] ';'
* methodtype ::= [ typeparams ] '(' { type } ')' type
* typevar ::= 'T' name ';'
* typeargs ::= '<' type { type } '>'
* typeparams ::= '<' typeparam { typeparam } '>'
* typeparam ::= name ':' type
*/
//-------------------------------------------------------------------------
int out_java_t::fmtString(java_t &pm, ushort index, ssize_t size, fmt_t mode, _PRMPT_ putproc)
{
ushort *tp = NULL;
if ( size < 0 )
FMTSTR_INTERR:
INTERNAL("fmtString");
if ( !index )
BADIDB:
DESTROYED("fmtString");
uint32 strind = ((uint32)index) << 16;
uint32 ostsz = uint32(pm.ConstantNode.altval(strind));
if ( ostsz == 0 )
goto BADIDB;
CASSERT(offsetof(_STROP_, size) == 0 && sizeof(((_STROP_ *)0)->size) == sizeof(ushort));
if ( !(pm.uni_chk & 1) && (ostsz & (_OP_UNICHARS<<16)) )
++pm.uni_chk; // rename unicode
if ( ostsz & (_OP_BADFIRST<<16) )
pm.name_chk = 1;
if ( mode & FMT_ENC_RESERVED ) // support jasmin reserved words
{
CASSERT((fmt_fullname+1) == fmt_UnqualifiedName && (fmt_UnqualifiedName+1 ) == fmt__ENDENUM);
mode = (fmt_t)(mode ^ FMT_ENC_RESERVED);
if ( mode < fmt_fullname )
goto FMTSTR_INTERR;
if ( (ostsz & (_OP_JSMRES_ << 16)) && (pm.idpflags & IDM_OUTASM) )
mode = fmt_string_single_quotes;
}
ostsz = (ushort)ostsz;
if ( ostsz != 0 && !pm.getblob(strind, tp = pm.tsPtr, ostsz) )
goto BADIDB;
uint32 off_ReturnType = 0;
uint32 off_ThrowsSignature_and_TypeSignature = 0;
if ( fmt_expects_call_descriptor(mode) ) // method part out
{
off_ReturnType = (uint32)pm.ConstantNode.altval(strind+1); // offset to return type
off_ThrowsSignature_and_TypeSignature = (uint32)pm.ConstantNode.altval(strind+2); // lng of <...:...> + throw off
}
return pm.format_utf16_string(tp, ostsz, off_ReturnType, off_ThrowsSignature_and_TypeSignature, size, mode, this, putproc);
}
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
// this function is called only from the loader
uchar java_t::LoadUtf8(ushort index, const_desc_t *co)
{
_STROP_ _opstr;
uint32 Flags = 0;
uint32 ind = ((uint32)index) << 16;
uchar result = 0, is_sde = 0, unicode = 0;
uint size;
if ( index == (ushort)-1 ) // SourceDebugExtension
{
CASSERT(offsetof(_STROP_, size) == 0 && sizeof(_opstr.size) == sizeof(ushort));
*(uint32*)&_opstr = (ushort)(size_t)co;
co = NULL;
is_sde = 1;
}
else
{
_opstr.flags = _OP_UTF8_;
_opstr.size = read2();
}
size = _opstr.size;
if ( size != 0 )
{
ushort *po = append_tmp_buffer(size);
union
{
ushort cw;
uchar cs;
};
uchar c;
do
{
--size;
cw = (uchar)read1();
if ( cw == 0 || cs >= 0xf0 )
goto errcoding;
if ( (char)cs < 0 )
{
if ( !size )
goto errchar;
--size;
--_opstr.size;
c = cs;
cs &= 0x1F;
cw <<= 6;
{
uchar c2 = read1();
if ( (c2 & 0xC0) != 0x80 )
goto errchar;
cs |= (c2 & 0x3F);
}
if ( (c & 0xE0) != 0xC0 )
{
if ( !size
|| (c & 0xF0) != 0xE0
|| ((c = read1()) & 0xC0) != 0x80 )
{
errchar:
if ( is_sde )
goto done;
loader_failure("Illegal byte in CONSTANT_Utf8 (%u)", index);
}
--size;
--_opstr.size;
cw <<= 6;
cs |= (c & 0x3F);
if ( cw < 0x800 )
goto errcoding;
}
else if ( cw < 0x80 && cs )
{
errcoding:
if ( is_sde )
goto done;
loader_failure("Illegal symbol encoding in CONSTANT_Utf8 (%u)", index);
}
} // end encoding
*po++ = cw;
if ( !is_sde )
{
if ( cw >= CHP_MAX )
{
if ( !javaIdent(cw) )
goto extchar;
unicode = 1;
}
else if ( cs <= CHP_MIN )
{
extchar:
Flags |= _OP_EXTSYM_;
unicode = (uchar)-1;
}
}
}
while ( size );
if ( !is_sde
&& _opstr.size == 1
&& (loadMode & MLD_STRIP)
&& (cw >= 0x80 || get_base_typename(cs) == NULL) )
{
// Symantec error (strip) #3
char str[16];
uchar *ps = (uchar *)str;
_opstr.size = (ushort)qsnprintf(str, sizeof(str), "_?_%04X", cw);
po = append_tmp_buffer(_opstr.size);
do
*po++ = *ps++;
while ( *ps );
Flags |= _OP_NODSCR | _OP_NOSIGN;
co->flag = HAS_CLSNAME | HAS_FLDNAME;
unicode = 0; // PARANOYA
}
result = !Flags;
ConstantNode.setblob(tsPtr, (uchar *)po - (uchar *)tsPtr, ind, BLOB_TAG);
}
if ( !is_sde )
{
if ( unicode == 1 )
Flags |= _OP_UNICHARS;
_opstr.flags |= (ushort)Flags;
co->_Sopstr = *(int32 *)&_opstr;
}
ConstantNode.altset(ind, *(uint32 *)&_opstr);
done:
return result;
}
//-----------------------------------------------------------------------
void java_t::parse_const_desc(ushort index, const_desc_t *co)
{
// all nexts used only here (for parsing)
#define _op_PARAM_ 0x00010000 // start paramlist '('
#define _op_PAREND_ 0x00020000 // last char is end of paramlist ')'
#define _op_RETTYPE_ 0x00040000 // have valid position for call return type
#define _op_FRSPRM_ 0x00080000 // not first descriptor (parameter)
#define _op_CLSBEG_ 0x00100000 // begin 'L...;' detected
#define _op_TYPBEG_ 0x00200000 // begin 'T...;' (signtype) detected
#define _op_NAME_ 0x00400000 // non empty class/typeref-name
#define _op_ARRAY_ 0x00800000 // previous char is '['
// next needed for 'complex' classnames
#define _op_ISARRAY_ 0x01000000 // have any '[' in name
#define _op_PRIMSIG_ 0x02000000 // <...:...> signature presnt
#define _op_INPRSIG_ 0x04000000 // currently parse <...:...> signature
#define _op_MUSTNAM_ 0x08000000 // part must be name (before ':')
#define _op_isTAG_ (_op_CLSBEG_ | _op_NAME_ | _op_TYPBEG_)
uint Flags = 0;
uint size = co->_Ssize;
uint32 off_ReturnType = 0;
uint32 off_ThrowsSignature_and_TypeSignature = 0;
ushort *po = tsPtr; // ATT: call ONLY after LoadUtf8, size!=0
uchar sgnlev = 0, prim = 0, *pprim = NULL;
uchar cs; // for prev
if ( *po == j_sign ) // check <...:...> signature and <init>/<clinit>
{
while ( ++off_ReturnType < size )
{
if ( !javaIdent(po[off_ReturnType]) )
{
if ( off_ReturnType != 1 )
{
size -= off_ReturnType+1; // +1 => balance for while, or align for <init>
switch ( po[off_ReturnType] )
{
case j_tag:
if ( size < 7 )
break; // Lx;>Lx; or Lx;>( )V => only_string
Flags |= _OP_FULLNM | _OP_NOFNM | _OP_NODSCR
| _op_PRIMSIG_ | _op_INPRSIG_;
po += off_ReturnType;
off_ReturnType &= 0;
++sgnlev;
goto accept_tag;
case j_endsign:
if ( !size ) // <init>/<clinit>
{
Flags |= _OP_NODSCR | _OP_NOSIGN;
goto SET_FLAGS;
}
// no break
default:
break; // only_string
} // switch
} // off_ReturnType != 1
break;
} // special_char
}
goto only_string;
} // first '<'
if ( *po == j_parm_list_start ) // check method descriptor/signature
{
to_func:
if ( --size < 2 )
goto only_string; // )V
++po;
Flags |= _op_PARAM_;
}
else
{
pprim = &prim;
}
do
{
--size;
cs = 0; // as flag (for wide characters)
CASSERT(CHP_MAX < 0x100);
if ( *po < CHP_MAX )
cs = (uchar)*po; // for 'L', 'T'...
if ( javaIdent(*po, pprim) ) // letter/digit/$_
{
if ( pprim )
{
if ( !prim )
Flags |= _OP_BADFIRST;
pprim = NULL;
}
goto norm_char;
}
pprim = NULL; // for speed
if ( cs <= CHP_MIN )
goto only_string; // also >= CHP_MAX
if ( Flags & _op_MUSTNAM_ ) // only in <...:...> signature (formal name)
{
if ( cs != j_tag )
goto only_string;
Flags &= ~_op_MUSTNAM_;
if ( size < 7 )
goto only_string; // Lx;>Lx; or Lx;>()V
accept_tag:
if ( po[1] == j_tag )
{ // iface
--size;
++po;
}
goto only_tag;
}
switch ( cs ) // validate special chars
{
case j_parm_list_end: // always can be present in in name
if ( sgnlev )
goto only_string;
if ( (Flags & (_op_PARAM_ | _op_ARRAY_ | _op_isTAG_)) != _op_PARAM_ )
goto only_string;
Flags ^= (_op_PARAM_ | _op_PAREND_);
continue;
case j_array: // class name can be full qualified array :(
if ( !sgnlev && !(Flags & (_op_isTAG_ | _OP_NOSIGN)) )
{
Flags |= _OP_FULLNM;
break;
}
// no break
default:
goto only_string;
case j_clspath_dlm: // '/'
case j_field_dlm: // '.'
Flags |= _OP_FULLNM;
continue;
case j_sign:
if ( size < 3 // *>;
|| (Flags & (_op_NAME_ | _OP_NOSIGN)) != _op_NAME_
|| ++sgnlev >= 30 )
{
goto only_string;
}
CASSERT((int32)(2 << 30) < 0); // "fmtString check method"
Flags |= _OP_FULLNM | _OP_NOFNM | _OP_NODSCR;
Flags &= ~_op_isTAG_;
--size;
switch ( *++po )
{
case j_wild:
if ( *++po != j_endsign )
goto only_string;
--size;
goto end_signW;
case j_wild_s:
case j_wild_e:
goto only_tag;
default:
goto skipped_only_tag;
}
case j_endsign:
if ( !size || !sgnlev )
goto only_string;
end_signW:
// end of <...:...> signature must resolve in endclass
if ( !--sgnlev && (Flags & _op_INPRSIG_) )
goto only_string;
if ( *++po != j_endclass )
goto only_string;
--size;
Flags |= _op_NAME_; // restore
// no break
case j_endclass:
if ( (Flags & (_op_NAME_ | _op_PAREND_ | _op_ARRAY_)) != _op_NAME_ )
goto only_string;
if ( !size && (Flags & (_op_CLSBEG_ | _OP_NOSIGN)) == _op_CLSBEG_ )
Flags |= _OP_ONECLS;
Flags &= ~_op_isTAG_;
if ( sgnlev == 1 && (Flags & _op_INPRSIG_) ) // parse <...:...>
{
if ( size < 4 )
goto only_string; // >Lx; or >( )V
switch ( po[1] )
{
default:
Flags |= _op_MUSTNAM_; // next substitution
continue;
case j_tag:
goto only_string;
case j_endsign: // end of <...:...>
break;
}
++po; // skip ';'
--size; // balance next '>'
sgnlev = 0;
Flags &= ~_op_INPRSIG_;
if ( po[1] != j_parm_list_start )
goto only_tag; // superclass{ifaces}
++po; // skip '>' (go=> before do-while)
off_ThrowsSignature_and_TypeSignature = (uint32)(po - tsPtr);
goto to_func;
} // end resolve end of <...:...>
if ( sgnlev )
{
if ( po[1] == j_endsign )
continue;
if ( size > 2 )
goto only_tag; // Lx;
goto only_string;
}
Flags |= _OP_FULLNM;
// class name can be full qualified array :(
if ( (Flags&(_op_ISARRAY_|_op_PARAM_|_op_RETTYPE_)) != _op_ISARRAY_ )
{
if ( Flags & _OP_NOSIGN )
goto only_string; // speed only
Flags |= _OP_NOFNM;
}
if ( Flags & (_op_RETTYPE_ | _op_PRIMSIG_) )
{
Flags &= ~_op_FRSPRM_;
if ( Flags & _op_RETTYPE_ )
goto check_throw;
}
continue;
} // switch ( specchar ) FULLNM
norm_char:
if ( Flags & (_OP_NOSIGN | _op_MUSTNAM_ | _op_NAME_) )
continue;
if ( Flags & _op_isTAG_ )
{
Flags |= _op_NAME_;
continue;
}
if ( sgnlev )
continue;
if ( Flags & _op_PAREND_ )
{
off_ReturnType = (uint32)(po - tsPtr);
Flags &= ~(_op_PAREND_ | _op_FRSPRM_);
Flags |= _op_RETTYPE_;
if ( cs == j_void_ret )
goto check_throw;
}
// chkdscr
if ( (Flags & (_op_PARAM_ | _op_FRSPRM_)) == _op_FRSPRM_ )
goto nodscsg;
if ( cs == j_array )
{
Flags |= _op_ARRAY_ | _op_ISARRAY_;
continue;
}
Flags = (Flags & ~_op_ARRAY_) | _op_FRSPRM_;
switch ( cs )
{
case j_class: // 'L'
Flags |= _op_CLSBEG_;
continue;
case j_typeref: // 'T'
Flags |= _op_TYPBEG_;
continue;
default:
break;
}
if ( !cs || get_base_typename(cs) == NULL )
{
nodscsg:
if ( Flags & (_OP_FULLNM | _op_RETTYPE_) )
goto only_string;
Flags |= _OP_NODSCR | _OP_NOSIGN;
}
else if ( Flags & _op_RETTYPE_ )
{
check_throw:
if ( !size )
break;
if ( size < 4 || po[1] != j_throw )
goto only_string; // ^Lx;
Flags |= _OP_FULLNM | _OP_NOFNM | _OP_NODSCR;
++po; // skip rettype/previous-';'
--size;
if ( off_ThrowsSignature_and_TypeSignature < 0x10000 )
off_ThrowsSignature_and_TypeSignature |= ((uint32)(po - tsPtr) << 16);
only_tag:
--size;
++po;
skipped_only_tag:
switch ( *po )
{
default:
goto only_string;
case j_class: // never set CLSBEG (no ONECLS)
case j_typeref:
Flags |= _op_TYPBEG_;
break;
}
}
}
while ( ++po, size );
if ( (Flags & (_op_PARAM_ | _op_PAREND_ | _op_ARRAY_)) || sgnlev )
{
only_string:
Flags |= (_OP_NODSCR | _OP_NOSIGN | _OP_NOFNM | _OP_FULLNM);
}
else
{
if ( Flags & (_op_CLSBEG_ | _op_TYPBEG_) )
{
Flags |= _OP_NODSCR | _OP_NOSIGN;
}
else if ( !(Flags & _OP_NOSIGN) )
{
if ( off_ReturnType )
{
Flags |= _OP_VALPOS;
if ( off_ThrowsSignature_and_TypeSignature )
Flags |= _OP_METSIGN;
}
else if ( off_ThrowsSignature_and_TypeSignature )
{
Flags |= _OP_CLSSIGN;
}
}
// check for reserved words
if ( !(Flags & _OP_NOWORD) )
ResW_validate((uint32 *)&Flags, po);
}
if ( (ushort)Flags )
{
SET_FLAGS: // <init>/<cinit>/V nor reserved :)
uint32 ind = ((uint32)index) << 16;
co->_Sflags |= (ushort)Flags;
ConstantNode.altset(ind, co->_Sopstr);
CASSERT(_OP_VALPOS < 0x10000u);
if ( Flags & _OP_VALPOS )
{
ConstantNode.altset(ind+1, off_ReturnType);
if ( Flags & _OP_METSIGN )
ConstantNode.altset(ind+2, off_ThrowsSignature_and_TypeSignature);
if ( !(Flags & _OP_NODSCR) )
co->flag |= HAS_CALLDSCR;
return;
}
}
cs = 0;
if ( !(Flags & _OP_NODSCR) )
cs |= HAS_TYPEDSCR;
if ( !(Flags & _OP_NOFNM) )
cs |= HAS_CLSNAME;
if ( !(Flags & _OP_FULLNM) )
cs |= HAS_FLDNAME;
co->flag |= cs;
}
//--------------------------------------------------------------------------
//---------------------------------------------------------------------------
// generated by JDK1.5 (checked with beta of 1.6) -- previously version have
// some 'skipped' letters(?). See 'addonces\jvunigen.cpp' (and move headers)
uchar javaIdent(ushort v, uchar *isStart)
{
static const uchar cpchtb[256] =
{
2, 3, 4, 5, 6, 7, 8, 9, 0, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 3, 22, 23, 24, 25, 0, 0, 0, 26, 27, 28,
29, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
31, 32, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 33, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 34,
3, 3, 3, 3, 35, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 36, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 37, 38, 3, 39, 40, 41 };
static const uchar idxtb[42][32] =
{
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
{ 0, 0, 0, 0, 1, 0,192,215, 38, 26, 26, 49, 38, 26, 26, 86,
0, 0, 0, 0, 2, 3,111, 3, 26, 26,110, 26, 26, 26,110, 26 },
{ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26 },
{ 26, 26, 26, 26, 26, 26,110, 0, 0, 0, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 28, 26, 37, 0, 40, 83, 0, 0 },
{ 192,192,192,192,192,192,192,192,192,192,192,222,192,192, 0, 3,
83, 4, 26, 26, 65, 26, 26, 26, 26,110, 26, 26, 26, 26, 71, 55 },
{ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
155, 5, 26, 26, 26, 26, 26, 26, 26,110, 26, 26, 26, 26, 96, 37 },
{ 26, 26, 0, 0, 0, 0, 38, 26, 26, 26,110, 97, 38, 26, 26, 26,
26, 0,217,192,193,192,192,194,195, 0, 26, 26, 26, 86, 86, 0 },
{ 0, 0,224, 0, 38, 26, 26, 86, 26,154,192,228,192,156,157, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26,158,196,159,160,192,191 },
{ 0, 0,190, 26, 26, 26,192,192,192,163, 0, 0, 0, 0, 0, 0,
26, 26, 26, 26,164,192,165, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 166, 26, 26, 26, 26, 26, 26,189,192,224,168, 26,169,192, 0, 0,
170, 63, 6, 26, 26, 32, 7,189,196,197,237, 8,169,192, 55, 0 },
{ 170, 49, 6, 26, 26, 32, 9,171,198,197, 0, 10,216,192,172, 0,
170, 71, 65, 26, 26, 32, 11,189,199,200,100, 0,169,192, 97, 0 },
{ 170, 63, 6, 26, 26, 32, 11,189,201,197,216, 8,173,192, 97, 0,
188, 74, 75, 12,108, 74, 71,173,202,203,237, 0,237,192, 0, 97 },
{ 170, 76, 32, 26, 26, 32, 30,173,204,203,219, 0,173,192, 0, 0,
175, 76, 32, 26, 26, 32, 30,189,204,203,219, 83,173,192, 0, 0 },
{ 175, 76, 32, 26, 26, 32, 26,173,205,203,237, 0,173,192, 0, 0,
175, 26,110, 5, 26, 26, 65, 90,110,206,207,192, 0, 0,208, 0 },
{ 38, 26, 26, 26, 26, 26,187,177,178,238,192,215, 0, 0, 0, 0,
13, 14, 98, 38, 15, 47,187,179, 79,224,192,186, 0, 0, 0, 0 },
{ 100, 0, 0,215,192,215,221,209, 26, 38, 26, 26, 26, 86,217,192,
204, 55,192,217,192,192,192,210,211, 0, 0, 0, 0, 0, 0, 0 },
{ 26, 26, 26, 26, 65,185,202,215,192,215,164,215, 0, 0, 0, 0,
0, 0, 0, 0, 26, 26, 26, 26, 96, 0, 26, 26, 26, 26, 26,100 },
{ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 16, 26, 26, 26, 26,
26, 26, 26, 26, 86, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 37 },
{ 110, 26, 26, 26, 26, 26, 26, 26,110, 75,110, 75, 26, 26, 26, 26,
110, 75, 26, 26, 26,110, 75,110, 75,110,110, 26, 26,110, 26, 26 },
{ 26,110, 75,110, 26, 26, 26, 26,110, 26, 26, 86, 0,217,215, 0,
0, 0, 0, 0, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 40, 0 },
{ 38, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26 },
{ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 63,110, 0,
38, 26, 26, 86, 26, 26, 26, 26, 26, 26, 26, 26, 26, 74,100, 0 },
{ 26, 76,182, 0, 26, 26,182, 0, 26, 26,183, 0, 26, 76,184, 0,
26, 26, 26, 26, 26, 26,181,192,192,192,180,176,192,215, 0, 0 },
{ 0,212,192,215, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0,
26, 26, 26, 26, 26,174, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 26, 26, 26, 40,192,241,192,241,216,192, 26, 26, 26, 96, 40, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 55, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 55, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 37 },
{ 26, 26, 96, 96, 26, 26, 26, 26, 96, 96, 26, 17, 26, 26, 26, 96,
26, 26, 26, 26, 26, 26, 76, 79, 18, 40, 41, 55, 26, 40, 18, 40 },
{ 0, 0, 0, 0, 0, 0, 0,109,100, 0, 1, 0, 0, 0, 97,109,
0, 0, 0, 0, 26, 26, 37, 0, 0, 0,192,210,213,214, 0, 0 },
{ 78, 5, 90, 19, 20, 21, 65, 22, 33, 37, 0, 0, 26, 26, 26, 26,
55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 33, 0, 0, 0, 38,167, 19, 40, 38, 26, 26, 26, 26, 26, 26, 26,
26, 26,110,162, 38, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26 },
{ 33, 26, 26, 26, 26, 40, 38, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26,110, 0, 0, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 26, 26 },
{ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 26, 26, 26, 26, 26, 96, 26, 26, 26, 26, 26, 26, 26, 86, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 110, 0, 23,161, 26, 32,110, 79, 24, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 37, 0, 0, 0, 23, 26, 26, 26, 26, 26 },
{ 26, 26, 26, 26, 26, 26, 26, 96, 0, 0, 26, 26, 26, 26, 26, 26,
26, 26, 5, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 26, 40 },
{ 192,192, 0, 0,241, 0,108, 0, 0, 33, 0, 0, 0, 97, 76, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 40 },
{ 1, 0,192,215, 38, 26, 26, 49, 38, 26, 26, 86, 33, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26,110, 5, 5, 5,104, 25, 0, 0, 0 }
};
static const uchar bittb[124] =
{
0x00, 0x10, 0x3C, 0x04, 0xD7, 0xFC, 0xF9, 0xC5, 0xB0, 0x6D, 0x5E, 0xED,
0xD6, 0x96, 0x25, 0xAE, 0x83, 0xAA, 0xDC, 0x3E, 0x50, 0xBD, 0xE3, 0xF8,
0xDB, 0x63, 0xFF, 0x7B, 0xC3, 0xFF, 0xEF, 0xFF, 0xFD, 0xE0, 0xE6, 0xE7,
0xFF, 0x03, 0xFE, 0xFF, 0x1F, 0xCF, 0xEE, 0xD3, 0x1F, 0xC3, 0x03, 0xEC,
0x38, 0x87, 0xFF, 0x3B, 0x8F, 0xCF, 0x1F, 0x0F, 0x0D, 0xF6, 0x33, 0xFF,
0xEC, 0xF3, 0xFF, 0x9F, 0xFF, 0xFB, 0xBB, 0x16, 0x9F, 0x39, 0x87, 0xBF,
0x3B, 0x8F, 0xC7, 0x3D, 0xDF, 0xCF, 0x84, 0x5F, 0x0C, 0xC2, 0x1F, 0x40,
0x38, 0xE2, 0x07, 0x03, 0xC0, 0xFE, 0x2F, 0x60, 0xC0, 0xA0, 0xE0, 0xE0,
0x3F, 0x02, 0xF0, 0x03, 0x01, 0x03, 0xE0, 0x03, 0x1C, 0x03, 0x01, 0xE0,
0x18, 0x80, 0x7F, 0x20, 0x80, 0x0F, 0x03, 0x03, 0x01, 0x06, 0x30, 0x0D,
0xE8, 0x23, 0xFD, 0x9C
};
uint ind = idxtb[cpchtb[v >> 8]][(((uchar)v) >> 3) & 31];
uchar bit = uchar(1 << (v & 7));
if ( !(bittb[ind & 0x7F] & bit) )
return 0;
if ( isStart )
*isStart = (!(ind & 0x80)
|| (!(ind & 0x40) && (bittb[ind - 68] & bit)));
return 1;
}