2161 lines
56 KiB
C++
2161 lines
56 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 "oututil.hpp"
|
|
#include "npooluti.hpp"
|
|
//lint -esym(666,qnumber) expression with side effects
|
|
|
|
// support for jasmin reserved word's
|
|
#define QS(f) (fmt_t)(f | FMT_ENC_RESERVED)
|
|
|
|
DECLARE_OUT_FUNCS(out_java_t)
|
|
|
|
//----------------------------------------------------------------------
|
|
bool out_java_t::out_sm_end(void)
|
|
{
|
|
return block_close(4, "stack");
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
bool out_java_t::out_deprecated(uchar pos)
|
|
{
|
|
return flush_buf(COLSTR(".deprecated", SCOLOR_KEYWORD), pos);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
//lint -e719 too many arguments for format
|
|
// no idea why lint complains, everything looks corrrect
|
|
bool out_java_t::out_sm_start(int same)
|
|
{
|
|
char samestr[80];
|
|
|
|
samestr[0] = 0;
|
|
if ( same >= 0 )
|
|
{
|
|
char tmp[32];
|
|
tmp[0] = '\0';
|
|
if ( same )
|
|
qsnprintf(tmp, sizeof(tmp), COLSTR(" %d", SCOLOR_NUMBER), same);
|
|
qsnprintf(samestr, sizeof(samestr), " use%s locals", tmp);
|
|
}
|
|
|
|
if ( jasmin() )
|
|
return gen_printf(4, COLSTR(".stack%s", SCOLOR_KEYWORD), samestr);
|
|
|
|
return gen_printf(4,
|
|
COLSTR("%s %s StackMap%s", SCOLOR_AUTOCMT),
|
|
COLSTR("{", SCOLOR_SYMBOL),
|
|
ash.cmnt, samestr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
bool out_java_t::out_stackmap(const SMinfo *pinf)
|
|
{
|
|
static char const *const verif[ITEM_BADOBJECT] =
|
|
{
|
|
"Top", "Integer", "Float", "Double", "Long", "Null", "UninitializedThis",
|
|
"Object ", "Unititialized "
|
|
};
|
|
static char const *const kwd[3] = { "locals", "stack", NULL };
|
|
|
|
union
|
|
{
|
|
const uchar *p1;
|
|
const ushort *p2;
|
|
};
|
|
|
|
char const *const *stage;
|
|
uchar rectype;
|
|
uint vcnt;
|
|
|
|
p1 = pinf->pb;
|
|
rectype = SMT_FULL_FRAME;
|
|
if ( pm().SMF_mode )
|
|
rectype = *p1++; // >=JDK6
|
|
if ( rectype >= SMT_SAME_FRM_S1 )
|
|
++p2; // skip offset
|
|
if ( (rectype < SMT_SAME_FRM_S1 && rectype > SMT_SAME_FRM_S1_max) )
|
|
goto BADIDB;
|
|
if ( p1 > pinf->pe )
|
|
goto BADIDB;
|
|
|
|
{
|
|
int hdr = -1;
|
|
|
|
if ( rectype != SMT_FULL_FRAME )
|
|
{
|
|
++hdr; // 0 -- without args
|
|
if ( rectype >= SMT_CHOP_FRM_S0_min && rectype <= SMT_CHOP_FRM_S0_max )
|
|
{
|
|
hdr = SMT_SAME_FRM_S0 - rectype;
|
|
if ( (uint)hdr > pinf->fcnt )
|
|
goto BADIDB;
|
|
hdr = pinf->fcnt - hdr;
|
|
if ( hdr == 0 )
|
|
--hdr; // nocopy
|
|
}
|
|
}
|
|
if ( out_sm_start(hdr) )
|
|
goto STOP_NOW;
|
|
}
|
|
|
|
if ( pinf->ea != insn.ea )
|
|
if ( gen_printf(6, COLSTR("%s %u", SCOLOR_ERROR),
|
|
COLSTR("offset", SCOLOR_KEYWORD),
|
|
(uint)(pinf->ea - pm().curSeg.start_ea)) )
|
|
goto STOP_NOW;
|
|
|
|
|
|
if ( rectype <= SMT_SAME_FRM_S0_max )
|
|
goto done_block;
|
|
stage = &kwd[1];
|
|
vcnt = 1;
|
|
if ( rectype > SMT_SAME_FRM_S1 )
|
|
{
|
|
if ( rectype <= SMT_SAME_FRM_S0 )
|
|
goto done_block;
|
|
--stage;
|
|
if ( rectype != SMT_FULL_FRAME )
|
|
{
|
|
vcnt = rectype - SMT_SAME_FRM_S0;
|
|
}
|
|
else
|
|
{
|
|
repeat_stage:
|
|
vcnt = *p2++;
|
|
if ( p1 > pinf->pe )
|
|
goto BADIDB;
|
|
}
|
|
}
|
|
if ( vcnt != 0 )
|
|
{
|
|
do
|
|
{
|
|
uchar tag = *p1++;
|
|
if ( p1 > pinf->pe || tag > ITEM_CURCLASS )
|
|
goto BADIDB;
|
|
pm().curpos = 6;
|
|
out_tagon(COLOR_KEYWORD);
|
|
size_t inplen = outbuf.length();
|
|
out_printf("%s %s", *stage,
|
|
verif[tag < ITEM_BADOBJECT ? tag : ITEM_Object]);
|
|
pm().outcnt = outbuf.length() - inplen;
|
|
out_tagoff(COLOR_KEYWORD);
|
|
CASSERT((ITEM_Object+1) == ITEM_Uninitialized
|
|
&& (ITEM_Uninitialized+1) == ITEM_BADOBJECT
|
|
&& (ITEM_BADOBJECT+1) == ITEM_CURCLASS);
|
|
if ( tag >= ITEM_Object )
|
|
{
|
|
ushort var = *p2++;
|
|
if ( p1 > pinf->pe )
|
|
goto BADIDB;
|
|
switch ( tag )
|
|
{
|
|
case ITEM_BADOBJECT:
|
|
if ( putShort(var) )
|
|
goto STOP_NOW;
|
|
break;
|
|
case ITEM_CURCLASS:
|
|
case ITEM_Object:
|
|
if ( OutUtf8(var,
|
|
QS(fmt_fullname),
|
|
tag == ITEM_Object ? COLOR_IMPNAME : COLOR_DNAME) )
|
|
goto STOP_NOW;
|
|
break;
|
|
case ITEM_Uninitialized:
|
|
if ( outOffName(var) )
|
|
goto STOP_NOW;
|
|
break;
|
|
}
|
|
}
|
|
if ( change_line() )
|
|
goto STOP_NOW;
|
|
}
|
|
while ( --vcnt );
|
|
}
|
|
if ( rectype == SMT_FULL_FRAME && *++stage )
|
|
goto repeat_stage;
|
|
done_block:
|
|
if ( p1 == pinf->pe )
|
|
return out_sm_end();
|
|
BADIDB:
|
|
DESTROYED("out_stackmap");
|
|
STOP_NOW:
|
|
return true;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
uchar out_java_t::OutModes(uint32 mode)
|
|
#define OA_THIS 0
|
|
#define OA_FIELD 1
|
|
#define OA_METHOD 2
|
|
#define OA_NEST 4 // in this case low BYTE == OA_NEST, hi word == access
|
|
{
|
|
static const TXS fn[] =
|
|
{
|
|
TXS_DECLARE("public "),
|
|
TXS_DECLARE("private "),
|
|
TXS_DECLARE("protected "),
|
|
TXS_DECLARE("static "),
|
|
TXS_DECLARE("final "),
|
|
TXS_DECLARE("synchronized "), // "super " (file)
|
|
TXS_DECLARE("volatile "), // "bridge " (method)
|
|
TXS_DECLARE("transient "), // "varargs " (method)
|
|
TXS_DECLARE("native "),
|
|
TXS_EMPTY(), // "interface " // special output mode
|
|
TXS_DECLARE("abstract "),
|
|
TXS_DECLARE("fpstrict "), // float-ing-point FP-stricted
|
|
TXS_DECLARE("synthetic "), // create by compiler (not present in source)
|
|
TXS_DECLARE("annotation "),
|
|
TXS_DECLARE("enum ") // class or it superclass is enum
|
|
};
|
|
|
|
static const TXS ex[2] =
|
|
{
|
|
TXS_DECLARE("bridge "),
|
|
TXS_DECLARE("varargs ")
|
|
};
|
|
|
|
static const TXS kwd[4] =
|
|
{
|
|
TXS_DECLARE(".class "),
|
|
TXS_DECLARE(".field "),
|
|
TXS_DECLARE(".method "),
|
|
TXS_DECLARE(".interface ")
|
|
};
|
|
|
|
ushort access_mode;
|
|
uchar off = 2, flg;
|
|
int kwdo;
|
|
|
|
switch ( mode )
|
|
{
|
|
case OA_FIELD:
|
|
flg = pm().curField.id.extflg;
|
|
access_mode = pm().curField.id.access & ACC_FIELD_MASK;
|
|
break;
|
|
case OA_METHOD:
|
|
flg = pm().curSeg.id.extflg;
|
|
access_mode = pm().curSeg.id.access & ACC_METHOD_MASK;
|
|
break;
|
|
case OA_THIS:
|
|
flg = pm().curClass.extflg;
|
|
access_mode = pm().curClass.AccessFlag & ACC_THIS_MASK;
|
|
off = 0;
|
|
break;
|
|
default: // OA_NEST
|
|
flg = 0;
|
|
access_mode = (ushort)(mode >> 16);
|
|
break;
|
|
}
|
|
|
|
kwdo = mode & 3;
|
|
if ( kwdo == 0 && (access_mode & ACC_INTERFACE) )
|
|
kwdo += 3;
|
|
|
|
if ( !jasmin() && (flg & XFL_DEPRECATED) )
|
|
{
|
|
out_commented("@Deprecated", COLOR_AUTOCMT);
|
|
if ( change_line() )
|
|
{
|
|
BADIDB:
|
|
return 1;
|
|
}
|
|
pm().curpos = off;
|
|
}
|
|
|
|
if ( mode >= OA_NEST && !jasmin() )
|
|
{
|
|
pm().outcnt += out_commented("{Inner}: ");
|
|
}
|
|
else
|
|
{
|
|
out_tagon(COLOR_KEYWORD);
|
|
uint rc = 0;
|
|
if ( jasmin() )
|
|
{
|
|
if ( mode >= OA_NEST )
|
|
{
|
|
OUT_STR(".inner ");
|
|
++rc;
|
|
}
|
|
outLine(&kwd[kwdo].str[rc], kwd[kwdo].size-rc);
|
|
}
|
|
}
|
|
for ( uint m, v = access_mode & ((1 << qnumber(fn)) - 1), i = 0;
|
|
(m = (1<<i)) <= v;
|
|
i++ ) //lint !e440 for clause irregularity
|
|
{
|
|
if ( (v & m) == 0 )
|
|
continue;
|
|
|
|
const TXS *pfn = &fn[i];
|
|
|
|
switch ( m )
|
|
{
|
|
case ACC_SUPER:
|
|
if ( !(mode & 3) )
|
|
continue; // OA_THIS, OA_NEST: 'super' is deprecated;
|
|
default:
|
|
break;
|
|
case ACC_BRIDGE:
|
|
case ACC_VARARGS:
|
|
if ( (uchar)mode == OA_METHOD )
|
|
pfn = &ex[m == ACC_VARARGS];
|
|
break;
|
|
}
|
|
if ( !pfn->size )
|
|
continue; // special case
|
|
if ( chkOutLine(pfn->str, pfn->size) )
|
|
goto BADIDB;
|
|
}
|
|
switch ( mode )
|
|
{
|
|
default: // OA_NEST, OA_THIS
|
|
if ( !jasmin()
|
|
&& chkOutLine(&kwd[kwdo].str[1], kwd[kwdo].size-1) )
|
|
{
|
|
goto BADIDB;
|
|
}
|
|
if ( (uchar)mode != OA_THIS && !jasmin() )
|
|
break;
|
|
// no break
|
|
case OA_FIELD:
|
|
case OA_METHOD:
|
|
out_tagoff(COLOR_KEYWORD);
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
uchar out_java_t::sign_out(ushort utsign, char mode)
|
|
{
|
|
fmt_t fmt = fmt_string;
|
|
|
|
if ( !jasmin() )
|
|
{
|
|
out_tagon(COLOR_AUTOCMT);
|
|
pm().outcnt += out_commented("User type: ");
|
|
fmt = fmt_FieldDescriptor_nospace; // for field/locvar
|
|
if ( mode )
|
|
{
|
|
fmt = fmt_method_FormalTypeParameters;
|
|
if ( mode > 0 )
|
|
fmt = fmt_ClassSignature; // defer for check ONLY
|
|
}
|
|
}
|
|
else
|
|
{
|
|
static const TXS sgn = TXS_DECLARE(".signature ");
|
|
out_tagon(COLOR_KEYWORD);
|
|
if ( chkOutLine(sgn.str + !mode, sgn.size - !mode) )
|
|
goto BADIDB;
|
|
}
|
|
if ( OutUtf8(utsign, fmt) )
|
|
{
|
|
BADIDB:
|
|
return 1;
|
|
}
|
|
if ( fmt == fmt_method_FormalTypeParameters )
|
|
{
|
|
if ( OutUtf8(utsign, fmt_method_ReturnType)
|
|
|| chkOutSpace()
|
|
|| OutUtf8(utsign, fmt_method_TypeSignature)
|
|
|| OutUtf8(utsign, fmt_method_ThrowsSignature) )
|
|
{
|
|
goto BADIDB;
|
|
}
|
|
}
|
|
out_tagoff(jasmin() ? COLOR_KEYWORD : COLOR_AUTOCMT);
|
|
if ( mode || !jasmin() )
|
|
return change_line();
|
|
return chkOutSpace();
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void out_java_t::out_switch(void)
|
|
{
|
|
op_t x;
|
|
x.n = 0;
|
|
x.flags = OF_SHOW;
|
|
x.dtype = dt_dword;
|
|
x.type = o_imm;
|
|
|
|
if ( !jasmin() && block_begin(4) )
|
|
return;
|
|
|
|
uchar nwarns = 0;
|
|
uval_t count;
|
|
ea_t addr;
|
|
for ( addr = insn.Op2.addr, count = insn.Op3.value; count; addr += 4, count-- )
|
|
{
|
|
pm().curpos = 8;
|
|
if ( insn.itype == j_lookupswitch )
|
|
{
|
|
x.value = get_dword(pm().curSeg.start_ea + addr); // pairs
|
|
addr += 4;
|
|
if ( !putVal(x, OOFW_IMM | OOF_NUMBER | OOF_SIGNED | OOFW_32, 0)
|
|
|| chkOutSpace()
|
|
|| chkOutSymSpace(':') )
|
|
{
|
|
return;
|
|
}
|
|
if ( !checkLine(1 + 8 - ((pm().outcnt + 1) % 8)) )
|
|
return;
|
|
int idx = pm().outcnt & 7;
|
|
if ( idx != 0 )
|
|
{
|
|
static const char seven_spaces[] = " ";
|
|
out_line(&seven_spaces[idx-1]);
|
|
}
|
|
}
|
|
x.value = insn.ip + get_dword(pm().curSeg.start_ea + addr);
|
|
if ( x.value >= pm().curSeg.CodeSize )
|
|
{
|
|
++nwarns;
|
|
}
|
|
else
|
|
{
|
|
if ( outName(pm().curSeg.start_ea + addr, x.n, pm().curSeg.start_ea, x.value, &nwarns) )
|
|
goto doneswitch;
|
|
if ( nwarns )
|
|
return;
|
|
}
|
|
if ( !putVal(x, OOFW_IMM | OOF_NUMBER | OOFS_NOSIGN | OOFW_32, nwarns) )
|
|
return;
|
|
doneswitch:
|
|
if ( change_line() )
|
|
return;
|
|
}
|
|
pm().curpos = 6;
|
|
OUT_KEYWORD("default ");
|
|
if ( chkOutSymSpace(':') || !out_operand(insn.Op3) || change_line() )
|
|
return;
|
|
if ( !jasmin() )
|
|
block_end(4);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void out_java_t::out_proc_mnem(void)
|
|
{
|
|
static const char *const addonce[] = { "", "_w", "_quick", "2_quick", "_quick_w" };
|
|
out_mnem(2, addonce[uchar(insn.wid)]);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void out_java_t::out_insn(void)
|
|
{
|
|
pm().getMySeg(insn.ea); // set curSeg (for special strings)
|
|
set_gen_xrefs(false);
|
|
|
|
if ( pm().curSeg.smNode && !(pm().idpflags & IDF_HIDESM) )
|
|
{
|
|
SMinfo smi;
|
|
smi.ea = BADADDR;
|
|
if ( pm().sm_getinfo(insn, &smi) )
|
|
{
|
|
init_prompted_output(4);
|
|
do
|
|
if ( out_stackmap(&smi) )
|
|
goto STOP_NOW;
|
|
while ( pm().sm_getinfo(insn, &smi) );
|
|
}
|
|
}
|
|
|
|
init_prompted_output(4);
|
|
out_mnemonic();
|
|
pm().outcnt = tag_strlen(outbuf.c_str());
|
|
|
|
if ( insn.Op1.type != o_void )
|
|
{
|
|
if ( !out_one_operand(0) )
|
|
goto STOP_NOW;
|
|
}
|
|
else
|
|
{
|
|
if ( (char)insn.Op1.ref > 0 )
|
|
{
|
|
qstring nbuf;
|
|
if ( get_visible_name(&nbuf, insn.Op1.addr) > 0 )
|
|
pm().outcnt += out_commented(nbuf.begin(), COLOR_REGCMT);
|
|
}
|
|
}
|
|
|
|
if ( insn.Op2.type != o_void )
|
|
{
|
|
if ( chkOutSpace() )
|
|
goto STOP_NOW;
|
|
if ( insn.itype == j_tableswitch && !jasmin() )
|
|
{
|
|
if ( CHK_OUT_KEYWORD("to ") )
|
|
goto STOP_NOW;
|
|
}
|
|
if ( !out_one_operand(1) )
|
|
goto STOP_NOW;
|
|
}
|
|
|
|
if ( insn.Op3.type != o_void && !insn.swit ) // ! lookupswitch/tablesswitch
|
|
{
|
|
if ( chkOutSpace() || !out_one_operand(2) )
|
|
goto STOP_NOW;
|
|
}
|
|
|
|
set_gen_xrefs(true);
|
|
set_gen_cmt(true);
|
|
if ( !change_line(true) )
|
|
{
|
|
if ( insn.swit & 2 )
|
|
out_switch(); // normal tableswitch/lookupswitch
|
|
}
|
|
STOP_NOW:
|
|
term_prompted_output();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
bool out_java_t::close_annotation(uint32 pos)
|
|
{
|
|
return block_close(pos, "annotation");
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
const ushort *out_java_t::annotation(const ushort *p, uint *plen, uint pos)
|
|
{
|
|
if ( *plen < sizeof(ushort) )
|
|
return NULL;
|
|
*plen -= sizeof(ushort);
|
|
uint pairs = *p++;
|
|
if ( pairs != 0 )
|
|
{
|
|
do
|
|
{
|
|
pm().curpos = pos;
|
|
if ( *plen < sizeof(ushort) )
|
|
return NULL;
|
|
*plen -= sizeof(ushort);
|
|
p = annotation_element(p+1, plen, pos, *p);
|
|
if ( p == NULL )
|
|
break;
|
|
if ( change_line() )
|
|
goto STOP_NOW;
|
|
}
|
|
while ( --pairs );
|
|
}
|
|
return p;
|
|
|
|
STOP_NOW:
|
|
*plen = (uint)-1;
|
|
return NULL;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
const ushort *out_java_t::annotation_element(
|
|
const ushort *p,
|
|
uint *plen,
|
|
uint pos,
|
|
ushort name)
|
|
{
|
|
uchar tag = 0, type = 0;
|
|
ushort val, prev = 0;
|
|
int alev = 0;
|
|
color_t ecol = COLOR_IMPNAME;
|
|
const TXS *pt;
|
|
const_desc_t co;
|
|
|
|
op_t x;
|
|
x.flags = 0; // output flags, will be used by out_value()
|
|
x.n = 0; // operand number, will be used by out_value()
|
|
do // array-values-loop
|
|
{
|
|
arentry:
|
|
if ( *plen < sizeof(uchar)+sizeof(ushort) )
|
|
goto BADIDB;
|
|
*plen -= sizeof(uchar)+sizeof(ushort);
|
|
if ( alev > 0 && tag != *(uchar*)p )
|
|
goto BADIDB;
|
|
tag = *(uchar *)p;
|
|
p = (ushort*)((uchar*)p+1);
|
|
val = *p++;
|
|
if ( tag == j_array )
|
|
{
|
|
if ( !*plen || (alev= val) == 0 || (tag= *(uchar*)p) == j_array )
|
|
goto BADIDB;
|
|
alev = -alev;
|
|
goto arentry;
|
|
}
|
|
|
|
if ( alev > 0 ) // not first array element
|
|
{
|
|
switch ( tag )
|
|
{
|
|
case j_enumconst:
|
|
case j_annotation:
|
|
if ( prev != val )
|
|
goto BADIDB;
|
|
default:
|
|
break;
|
|
}
|
|
if ( !jasmin() )
|
|
{
|
|
if ( chkOutSymSpace(',') )
|
|
goto STOP_NOW;
|
|
}
|
|
else if ( tag != j_annotation )
|
|
{
|
|
if ( chkOutSpace() )
|
|
goto STOP_NOW;
|
|
}
|
|
else
|
|
{
|
|
if ( change_line() )
|
|
goto STOP_NOW;
|
|
pm().curpos = pos;
|
|
}
|
|
goto do_value;
|
|
}
|
|
|
|
switch ( tag )
|
|
{
|
|
default:
|
|
goto BADIDB;
|
|
|
|
case j_annotation:
|
|
case j_enumconst:
|
|
if ( val == pm().curClass.This.Dscr )
|
|
ecol = COLOR_DNAME;
|
|
prev = val;
|
|
// no break
|
|
case j_class_ret:
|
|
case j_string:
|
|
break;
|
|
|
|
case j_float:
|
|
type = CONSTANT_Float;
|
|
x.dtype = dt_float;
|
|
break;
|
|
case j_long:
|
|
type = CONSTANT_Long;
|
|
x.dtype = dt_qword;
|
|
break;
|
|
case j_double:
|
|
type = CONSTANT_Double;
|
|
x.dtype = dt_double;
|
|
break;
|
|
case j_bool:
|
|
case j_byte:
|
|
case j_char:
|
|
x.dtype = dt_byte;
|
|
goto do_int;
|
|
case j_short:
|
|
x.dtype = dt_word;
|
|
goto do_int;
|
|
case j_int:
|
|
x.dtype = dt_dword;
|
|
do_int:
|
|
type = CONSTANT_Integer;
|
|
break;
|
|
}
|
|
|
|
if ( jasmin() )
|
|
{
|
|
if ( name )
|
|
{
|
|
if ( OutUtf8(name, fmt_UnqualifiedName, COLOR_DNAME) || chkOutSpace() )
|
|
goto STOP_NOW;
|
|
}
|
|
out_tagon(COLOR_KEYWORD);
|
|
if ( alev )
|
|
{
|
|
if ( !checkLine(2) )
|
|
goto STOP_NOW;
|
|
out_char(j_array);
|
|
}
|
|
if ( chkOutChar(tag) )
|
|
goto STOP_NOW;
|
|
out_tagoff(COLOR_KEYWORD);
|
|
switch ( tag )
|
|
{
|
|
case j_enumconst:
|
|
case j_annotation:
|
|
if ( chkOutSpace() || OutUtf8(val, fmt_FieldDescriptor_nospace, ecol) )
|
|
goto STOP_NOW;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{ // jasmin
|
|
static const TXS doptype[] =
|
|
{
|
|
TXS_DECLARE("String"),
|
|
TXS_DECLARE("Enum"),
|
|
TXS_DECLARE("Class"),
|
|
TXS_DECLARE("Annotation")
|
|
};
|
|
pt = doptype;
|
|
switch ( tag )
|
|
{
|
|
case j_annotation:
|
|
++pt;
|
|
// no break
|
|
case j_class_ret:
|
|
++pt;
|
|
// no break
|
|
case j_enumconst:
|
|
++pt;
|
|
// no break
|
|
case j_string:
|
|
break;
|
|
|
|
default:
|
|
pt = get_base_typename(tag);
|
|
if ( pt == NULL )
|
|
goto BADIDB;
|
|
break;
|
|
}
|
|
if ( chkOutKeyword(pt->str, pt->size) )
|
|
goto STOP_NOW;
|
|
switch ( tag )
|
|
{
|
|
case j_enumconst:
|
|
case j_annotation:
|
|
if ( chkOutSpace() || OutUtf8(val, fmt_FieldDescriptor_nospace, ecol) )
|
|
goto STOP_NOW;
|
|
default:
|
|
break;
|
|
}
|
|
if ( alev && CHK_OUT_KEYWORD("[]") )
|
|
goto STOP_NOW;
|
|
if ( name != 0 )
|
|
{
|
|
if ( chkOutSpace() || OutUtf8(name, fmt_UnqualifiedName, COLOR_DNAME) )
|
|
goto STOP_NOW;
|
|
}
|
|
} // jasmin
|
|
alev = -alev; // 0 = 0
|
|
/*
|
|
if ( chkOutSpace(insn) )
|
|
goto STOP_NOW;
|
|
if ( (name || jasmin()) && chkOutSymSpace(insn, '=') )
|
|
goto STOP_NOW;
|
|
*/
|
|
if ( chkOutSpace() || chkOutSymSpace('=') )
|
|
goto STOP_NOW;
|
|
do_value:
|
|
switch ( tag )
|
|
{
|
|
case j_annotation:
|
|
if ( jasmin() )
|
|
{
|
|
if ( CHK_OUT_KEYWORD(".annotation") )
|
|
goto STOP_NOW;
|
|
}
|
|
else
|
|
{
|
|
if ( chkOutSymbol('{') )
|
|
goto STOP_NOW;
|
|
}
|
|
if ( change_line() )
|
|
goto STOP_NOW;
|
|
p = annotation(p, plen, pos+2);
|
|
if ( p == NULL )
|
|
goto done;
|
|
pm().curpos = pos;
|
|
if ( jasmin() )
|
|
{
|
|
out_line(COLSTR(".end annotation", SCOLOR_KEYWORD));
|
|
}
|
|
else
|
|
{
|
|
out_symbol('}');
|
|
++pm().outcnt;
|
|
}
|
|
continue;
|
|
|
|
case j_class_ret:
|
|
if ( !OutUtf8(val, fmt_FieldDescriptor_nospace, // without space
|
|
val == pm().curClass.This.Dscr ? COLOR_DNAME : COLOR_IMPNAME) )
|
|
continue;
|
|
STOP_NOW:
|
|
*plen = (uint)-1;
|
|
BADIDB:
|
|
return NULL;
|
|
|
|
case j_enumconst:
|
|
if ( *plen < sizeof(ushort) )
|
|
goto BADIDB;
|
|
*plen -= sizeof(ushort);
|
|
if ( OutUtf8(*p++, fmt_UnqualifiedName, ecol) )
|
|
goto STOP_NOW;
|
|
continue;
|
|
|
|
case j_string:
|
|
if ( OutUtf8(val, fmt_string, COLOR_STRING) )
|
|
goto STOP_NOW;
|
|
continue;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
if ( !pm().LoadOpis(lm_normal, val, type, &co) )
|
|
goto BADIDB;
|
|
if ( !jasmin() )
|
|
{
|
|
switch ( tag )
|
|
{
|
|
case j_bool:
|
|
{
|
|
static const TXS bt[2] =
|
|
{
|
|
TXS_DECLARE("true"),
|
|
TXS_DECLARE("false")
|
|
};
|
|
pt = &bt[!co.value];
|
|
if ( chkOutKeyword(pt->str, pt->size) )
|
|
goto STOP_NOW;
|
|
}
|
|
continue;
|
|
|
|
case j_char:
|
|
if ( co.value < ' ' || co.value >= 0x80 )
|
|
break;
|
|
if ( !checkLine(3) )
|
|
goto STOP_NOW;
|
|
out_printf(COLSTR("'%c'", SCOLOR_CHAR), char(co.value));
|
|
pm().outcnt += 3;
|
|
continue;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
copy_const_to_opnd(x, co);
|
|
if ( !putVal(x, OOF_NUMBER | OOF_SIGNED | OOFW_IMM, 0) )
|
|
goto STOP_NOW;
|
|
}
|
|
while ( alev && --alev );
|
|
done:
|
|
return p;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
uchar out_java_t::annotation_loop(const uval_t *pnodes, uint nodecnt)
|
|
{
|
|
uchar result = 1;
|
|
uint32 pos = pm().curpos;
|
|
|
|
if ( gen_empty_line() )
|
|
goto STOP_NOW;
|
|
|
|
for ( uint n = 0; n < nodecnt; n++ )
|
|
{
|
|
if ( pnodes[n] )
|
|
{
|
|
static char const *const jnames[5] =
|
|
{
|
|
"visible", "invisible", "default", "visibleparam", "invisibleparam"
|
|
};
|
|
static char const *const lnames[5] =
|
|
{
|
|
"RuntimeVisible", "RuntimeInvisible",
|
|
"Default",
|
|
"RuntimeVisibleParameter", "RuntimeInvisibleParameter"
|
|
};
|
|
char hdr[MAXSTR];
|
|
uint hdrpos, hdrlen, len;
|
|
const ushort *p = (ushort*)pm().get_annotation(pnodes[n], &len);
|
|
if ( p == NULL )
|
|
goto BADIDB;
|
|
|
|
if ( jasmin() )
|
|
{
|
|
hdrpos = qsnprintf(hdr, sizeof(hdr),
|
|
COLSTR(".annotation %s", SCOLOR_KEYWORD),
|
|
jnames[n]);
|
|
}
|
|
else
|
|
{
|
|
hdrpos = qsnprintf(hdr, sizeof(hdr),
|
|
COLSTR("%sAnnotation", SCOLOR_KEYWORD),
|
|
lnames[n]);
|
|
}
|
|
|
|
if ( n == 2 ) // defalut
|
|
{
|
|
if ( !jasmin() )
|
|
qstrncpy(&hdr[hdrpos], COLSTR(" {", SCOLOR_SYMBOL), sizeof(hdr)-hdrpos);
|
|
if ( flush_buf(hdr, pos) )
|
|
goto STOP_NOW;
|
|
pm().curpos = pos + 2;
|
|
p = annotation_element(p, &len, pos+2, 0);
|
|
if ( p == NULL )
|
|
{
|
|
checkans:
|
|
if ( len == (uint)-1 )
|
|
goto STOP_NOW;
|
|
goto BADIDB;
|
|
}
|
|
if ( len )
|
|
goto BADIDB;
|
|
if ( change_line() || close_annotation(pos) )
|
|
goto STOP_NOW;
|
|
continue;
|
|
}
|
|
int nump = 0, ip = 1;
|
|
uchar present = 0;
|
|
if ( n > 2 ) // parameters
|
|
{
|
|
--len;
|
|
nump = *(uchar*)p;
|
|
if ( nump == 0 )
|
|
goto BADIDB;
|
|
p = (ushort*)((uchar*)p+1);
|
|
if ( !jasmin() )
|
|
hdrpos += qsnprintf(&hdr[hdrpos], sizeof(hdr)-hdrpos,
|
|
COLSTR(" for parameter", SCOLOR_KEYWORD));
|
|
}
|
|
hdr[hdrpos++] = ' ';
|
|
hdr[hdrpos] = '\0';
|
|
do // parameters loop
|
|
{
|
|
if ( len < sizeof(ushort) )
|
|
goto BADIDB;
|
|
len -= sizeof(ushort);
|
|
uint cnt = *p++;
|
|
if ( !cnt )
|
|
{
|
|
if ( !nump )
|
|
goto BADIDB;
|
|
continue;
|
|
}
|
|
if ( nump )
|
|
qsnprintf(&hdr[hdrpos], sizeof(hdr) - hdrpos, COLSTR("%d ", SCOLOR_NUMBER), ip);
|
|
present = 1;
|
|
hdrlen = (uint32)tag_strlen(hdr);
|
|
do // annotations loop
|
|
{
|
|
if ( len < sizeof(ushort) )
|
|
goto BADIDB;
|
|
len -= sizeof(ushort);
|
|
pm().curpos = pos;
|
|
out_line(hdr);
|
|
pm().outcnt = hdrlen;
|
|
if ( OutUtf8(*p, jasmin() ? fmt_FieldDescriptor_nospace : fmt_FieldDescriptor) )
|
|
goto STOP_NOW;
|
|
if ( !jasmin() )
|
|
out_symbol('{');
|
|
if ( change_line() )
|
|
goto STOP_NOW;
|
|
p = annotation(p+1, &len, pos+2);
|
|
if ( p == NULL )
|
|
goto checkans;
|
|
if ( close_annotation(pos) )
|
|
goto STOP_NOW;
|
|
}
|
|
while ( --cnt );
|
|
}
|
|
while ( ++ip <= nump );
|
|
if ( nump && !present )
|
|
goto BADIDB;
|
|
if ( len )
|
|
goto BADIDB;
|
|
}
|
|
} // loop of annotation types
|
|
result = 0;
|
|
STOP_NOW:
|
|
return result;
|
|
|
|
BADIDB:
|
|
DESTROYED("annotation");
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
void out_java_t::java_header(void)
|
|
{
|
|
char str[MAXSTR*2];
|
|
|
|
if ( !jasmin() )
|
|
flush_buf(COLSTR("/*", SCOLOR_AUTOCMT), 0);
|
|
const char *prefix = jasmin() ? ash.cmnt : "";
|
|
|
|
#ifdef __debug__
|
|
gen_printf(0, COLSTR("%sDisassembler mode: %s", SCOLOR_AUTOCMT),
|
|
prefix, debugmode ? "DEBUG" : "Normal");
|
|
#endif
|
|
gen_printf(0,
|
|
COLSTR("%sJava Virtual Machine (JDK 1.%u)", SCOLOR_AUTOCMT),
|
|
prefix, pm().curClass.JDKsubver);
|
|
{
|
|
char sv = inf_get_indent();
|
|
inf_set_indent(0);
|
|
if ( !jasmin() )
|
|
{
|
|
gen_printf(-1,
|
|
COLSTR("%sClassFile version: %u.%u", SCOLOR_AUTOCMT),
|
|
prefix, pm().curClass.MajVers, pm().curClass.MinVers);
|
|
}
|
|
else
|
|
{
|
|
if ( out_problems(str, prefix) )
|
|
return;
|
|
gen_empty_line();
|
|
gen_printf(-1, COLSTR("%s %u.%u", SCOLOR_NUMBER),
|
|
COLSTR(".bytecode", SCOLOR_KEYWORD),
|
|
pm().curClass.MajVers, pm().curClass.MinVers);
|
|
}
|
|
inf_set_indent(sv);
|
|
}
|
|
|
|
if ( pm().curClass.SourceName )
|
|
{
|
|
init_prompted_output();
|
|
if ( jasmin() )
|
|
{
|
|
OUT_KEYWORD(".source ");
|
|
out_tagon(COLOR_STRING);
|
|
}
|
|
else
|
|
{
|
|
out_tagon(COLOR_AUTOCMT);
|
|
OUT_STR("Source File : ");
|
|
}
|
|
uchar stp;
|
|
{
|
|
uint32 save = pm().idpflags;
|
|
pm().idpflags = (pm().idpflags & ~IDF_AUTOSTR) | IDF_ENCODING; // PARANOYA
|
|
stp = OutUtf8(pm().curClass.SourceName, fmt_string);
|
|
pm().idpflags = save;
|
|
}
|
|
if ( !stp )
|
|
out_tagoff(jasmin() ? COLOR_STRING : COLOR_AUTOCMT);
|
|
if ( stp || flush_outbuf(0) )
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
gen_empty_line();
|
|
}
|
|
|
|
//
|
|
{
|
|
nodeidx_t bmnidx = bootstrap_methods_get_node(/*assert=*/ false, /*can_create=*/ true);
|
|
if ( bmnidx != BADNODE )
|
|
{
|
|
const nodeidx_t bmcnt = bootstrap_methods_get_count();
|
|
if ( bmcnt > 0 )
|
|
{
|
|
gen_printf(0, COLSTR("%sBootstrapMethods : %u", SCOLOR_AUTOCMT),
|
|
prefix, uint(bmcnt));
|
|
for ( nodeidx_t bmidx = 0; bmidx < bmcnt; ++bmidx )
|
|
{
|
|
bootstrap_method_def_t bmd;
|
|
const char *bmerr = "error retrieving data";
|
|
bool bmok = bootstrap_methods_get_method(&bmd, bmidx);
|
|
if ( bmok )
|
|
{
|
|
bmok = bmd.method_ref != 0 && bmd.method_ref <= pm().curClass.maxCPindex;
|
|
if ( bmok )
|
|
{
|
|
const_desc_t tmp;
|
|
bmok = pm().ConstantNode.supval(bmd.method_ref, &tmp, sizeof(tmp)) == sizeof(tmp);
|
|
if ( bmok )
|
|
{
|
|
bmok = tmp.type == CONSTANT_MethodHandle;
|
|
if ( bmok )
|
|
{
|
|
const_desc_t method_handle;
|
|
bmok = pm().ConstantNode.supval(bmd.method_ref, &method_handle, sizeof(method_handle)) == sizeof(method_handle);
|
|
if ( bmok )
|
|
{
|
|
// qstring buf;
|
|
// buf.sprnt("MethodHandle{kind=%u, index=%u}",
|
|
// method_handle._mhr_kind, method_handle._mhr_index);
|
|
// flush_buf(buf.c_str());
|
|
switch ( method_handle._mhr_kind )
|
|
{
|
|
case JVM_REF_getField:
|
|
case JVM_REF_getStatic:
|
|
case JVM_REF_putField:
|
|
case JVM_REF_putStatic:
|
|
// points at CONSTANT_Fieldref
|
|
// (fallthrough)
|
|
case JVM_REF_invokeVirtual:
|
|
case JVM_REF_invokeStatic:
|
|
case JVM_REF_invokeSpecial:
|
|
case JVM_REF_newInvokeSpecial:
|
|
// points at CONSTANT_Methodref
|
|
{
|
|
qstrvec_t lines;
|
|
print_constant(&lines, method_handle, bmd.method_ref);
|
|
if ( lines.empty() )
|
|
lines.push_back("<failed printing method handle>");
|
|
for ( ssize_t lidx = 0; lidx < lines.size(); ++lidx )
|
|
gen_printf(0, "%s", lines[lidx].c_str());
|
|
flush_outbuf();
|
|
for ( size_t argidx = 0, argcnt = bmd.args.size(); argidx < argcnt; ++argidx )
|
|
{
|
|
const_desc_t arg;
|
|
const ushort argcid = bmd.args[argidx];
|
|
if ( pm().ConstantNode.supval(argcid, &arg, sizeof(arg)) == sizeof(arg) )
|
|
{
|
|
lines.qclear();
|
|
print_constant(&lines, arg, argcid, /*strip_tags=*/ true);
|
|
if ( lines.empty() )
|
|
lines.push_back("<failed printing constant>");
|
|
for ( size_t lidx = 0; lidx < lines.size(); ++lidx )
|
|
gen_printf(0, "Argument #%" FMT_Z ": %s", argidx, lines[lidx].c_str());
|
|
}
|
|
else
|
|
{
|
|
gen_printf(0, COLSTR("Error retrieving argument #%" FMT_Z, SCOLOR_ERROR), argidx);
|
|
}
|
|
flush_outbuf();
|
|
}
|
|
}
|
|
break;
|
|
case JVM_REF_invokeInterface:
|
|
// points at CONSTANT_InterfaceMethodref
|
|
bmok = false;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bmerr = "Couldn't retrieve method handle";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bmerr = "Bad constant type";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bmerr = "Corrupted data";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bmerr = "Bad constant pool index";
|
|
}
|
|
}
|
|
if ( !bmok )
|
|
gen_printf(0, COLSTR("Error retrieving bootstrap method %u (%s)", SCOLOR_ERROR),
|
|
uint(bmcnt), bmerr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !jasmin() )
|
|
{
|
|
if ( out_problems(str, prefix) )
|
|
return;
|
|
close_comment();
|
|
}
|
|
myBorder();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
void idaapi java_header(outctx_t &ctx)
|
|
{
|
|
out_java_t *pctx = (out_java_t *)&ctx;
|
|
pctx->java_header();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
uchar out_java_t::enclose_out(void)
|
|
{
|
|
if ( !jasmin() )
|
|
{
|
|
out_tagon(COLOR_AUTOCMT);
|
|
size_t inplen = outbuf.length();
|
|
out_printf("%sEnclosing %s: ", ash.cmnt,
|
|
pm().curClass.encMethod ? "method" : "class");
|
|
pm().outcnt += outbuf.length() - inplen;
|
|
}
|
|
else
|
|
{
|
|
OUT_KEYWORD(".enclosing method ");
|
|
}
|
|
if ( !pm().curClass.encMethod )
|
|
{
|
|
if ( OutUtf8(pm().curClass.encClass, QS(fmt_fullname)) )
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
const_desc_t op;
|
|
|
|
if ( !pm().LoadOpis(lm_normal, pm().curClass.encMethod, CONSTANT_NameAndType, &op) )
|
|
DESTROYED("out::enclose");
|
|
if ( (!jasmin() && OutUtf8(op._name, fmt_method_ReturnType))
|
|
|| OutUtf8(pm().curClass.encClass, fmt_fullname)
|
|
|| chkOutChar(jasmin() ? '/' : '.')
|
|
|| OutUtf8(op._class, fmt_UnqualifiedName)
|
|
|| OutUtf8(op._name, jasmin() ? fmt_FieldDescriptor : fmt_method_TypeSignature) )
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
if ( !jasmin() )
|
|
out_tagoff(COLOR_AUTOCMT);
|
|
pm().curpos = 0;
|
|
return change_line();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// output the method return type
|
|
uchar out_java_t::out_seg_type(fmt_t fmt)
|
|
{
|
|
return out_index(pm().curSeg.id.dscr,
|
|
fmt,
|
|
COLOR_KEYWORD,
|
|
pm().curSeg.id.extflg & EFL_TYPE);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// output the field type
|
|
uchar out_java_t::out_field_type(void)
|
|
{
|
|
return out_index(pm().curField.id.dscr,
|
|
fmt_FieldDescriptor,
|
|
COLOR_KEYWORD,
|
|
pm().curField.id.extflg & EFL_TYPE);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
uchar out_java_t::out_includes(uval_t node, uchar pos)
|
|
{
|
|
netnode temp(node);
|
|
uint32 len, vid, cnt = (uint32)temp.altval(0);
|
|
color_t color = jasmin() ? COLOR_KEYWORD : COLOR_AUTOCMT;
|
|
char fnm[qmin(QMAXPATH,MAXSPECSIZE)+4];
|
|
|
|
if ( !cnt )
|
|
goto BADIDB;
|
|
fnm[0] = '"';
|
|
do
|
|
{
|
|
pm().curpos = pos;
|
|
|
|
len = (uint32)temp.supstr(cnt, &fnm[1], sizeof(fnm)-3);
|
|
if ( !len )
|
|
goto BADIDB;
|
|
fnm[++len] = '"';
|
|
fnm[++len] = '\0';
|
|
char *pf = fnm;
|
|
if ( pm().idpflags & IDF_NOPATH )
|
|
{
|
|
pf = strrchr(pf, '/');
|
|
if ( pf != NULL )
|
|
{
|
|
++pf;
|
|
}
|
|
else
|
|
{
|
|
#ifndef __UNIX__
|
|
pf = &fnm[1+1];
|
|
if ( *pf != ':' )
|
|
--pf;
|
|
#else
|
|
pf = &fnm[1];
|
|
#endif
|
|
}
|
|
*--pf = '"';
|
|
len -= uint32(pf - fnm);
|
|
}
|
|
vid = (uint32)temp.altval(cnt);
|
|
if ( vid == 0 || vid > pm().curClass.maxCPindex )
|
|
goto BADIDB;
|
|
out_tagon(color);
|
|
if ( jasmin() )
|
|
OUT_STR(".attribute ");
|
|
else
|
|
pm().outcnt = out_commented("GenericAttribute ");
|
|
if ( OutUtf8((ushort)vid, fmt_UnqualifiedName)
|
|
|| chkOutSpace()
|
|
|| chkOutLine(pf, len) )
|
|
{
|
|
goto STOP_NOW;
|
|
}
|
|
out_tagoff(color);
|
|
if ( change_line() )
|
|
goto STOP_NOW;
|
|
}
|
|
while ( --cnt );
|
|
return 0;
|
|
|
|
BADIDB:
|
|
DESTROYED("out_includes");
|
|
STOP_NOW:
|
|
return 1;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void out_java_t::java_segstart(segment_t *)
|
|
{
|
|
ea_t ea = insn_ea;
|
|
|
|
init_prompted_output(2);
|
|
|
|
set_gen_cmt(true);
|
|
switch ( pm().getMySeg(ea)->type ) // also set curSeg
|
|
{
|
|
case SEG_CODE:
|
|
{
|
|
func_t *pfn = get_func(ea);
|
|
if ( pfn != NULL )
|
|
{
|
|
qstring qbuf;
|
|
if ( get_func_cmt(&qbuf, pfn, false) > 0
|
|
|| get_func_cmt(&qbuf, pfn, true) > 0 )
|
|
{
|
|
if ( gen_block_cmt(qbuf.c_str(), COLOR_REGCMT) )
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
pm().no_prim = true;
|
|
if ( OutModes(OA_METHOD) )
|
|
break;
|
|
if ( !(pm().curSeg.id.extflg & EFL_TYPE)
|
|
&& !jasmin()
|
|
&& out_seg_type(fmt_method_ReturnType) )
|
|
{
|
|
break;
|
|
}
|
|
if ( out_index(pm().curSeg.id.name, fmt_UnqualifiedName, COLOR_CNAME, // Method Name
|
|
pm().curSeg.id.extflg & EFL_NAME) )
|
|
break;
|
|
if ( pm().curSeg.id.extflg & EFL_TYPE )
|
|
{
|
|
if ( chkOutSpace() )
|
|
break;
|
|
goto do_dscid;
|
|
}
|
|
if ( jasmin() )
|
|
{
|
|
do_dscid:
|
|
if ( out_seg_type(fmt_FieldDescriptor) )
|
|
break;
|
|
}
|
|
else if ( OutUtf8(pm().curSeg.id.dscr, fmt_method_TypeSignature, COLOR_KEYWORD) )
|
|
{
|
|
break;
|
|
}
|
|
if ( pm().curSeg.thrNode )
|
|
{
|
|
const char *p = ".throws ";
|
|
if ( !jasmin() )
|
|
{
|
|
if ( CHK_OUT_KEYWORD(" throws ") )
|
|
break;
|
|
p = NULL;
|
|
}
|
|
if ( !out_nodelist(pm().curSeg.thrNode, 2, p) )
|
|
break;
|
|
}
|
|
if ( change_line() )
|
|
break;
|
|
if ( pm().curSeg.id.utsign )
|
|
{
|
|
pm().curpos = 2;
|
|
if ( sign_out(pm().curSeg.id.utsign, -1) )
|
|
break;
|
|
}
|
|
if ( jasmin() && (pm().curSeg.id.extflg & XFL_DEPRECATED) )
|
|
{
|
|
if ( out_deprecated(2) )
|
|
break;
|
|
}
|
|
if ( pm().curSeg.genNodes[0] && out_includes(pm().curSeg.genNodes[0], 2) )
|
|
break;
|
|
|
|
if ( pm().curSeg.stacks )
|
|
{
|
|
int over = gen_printf(2,
|
|
jasmin() ? COLSTR(".limit stack %u", SCOLOR_ASMDIR) :
|
|
COLSTR("max_stack %u", SCOLOR_ASMDIR),
|
|
pm().curSeg.stacks);
|
|
if ( over )
|
|
break;
|
|
}
|
|
|
|
if ( pm().curSeg.DataSize )
|
|
{
|
|
int over = gen_printf(2,
|
|
jasmin() ? COLSTR(".limit locals %u", SCOLOR_ASMDIR) :
|
|
COLSTR("max_locals %u", SCOLOR_ASMDIR),
|
|
pm().curSeg.DataSize);
|
|
if ( over )
|
|
break;
|
|
}
|
|
if ( (pm().curSeg.id.extflg & XFL_M_EMPTYSM) && (out_sm_start(-1) || out_sm_end()) )
|
|
break;
|
|
|
|
if ( pm().curSeg.id.extflg & XFL_M_LABSTART )
|
|
out_method_label(0);
|
|
if ( !jasmin() )
|
|
block_begin(2);
|
|
break;
|
|
|
|
case SEG_IMP:
|
|
pm().curpos = 0;
|
|
if ( OutModes(OA_THIS) )
|
|
break;
|
|
if ( out_index(pm().curClass.This.Name, QS(fmt_fullname), COLOR_DNAME,
|
|
(uchar)!pm().curClass.This.Dscr) )
|
|
break;
|
|
|
|
if ( jasmin() )
|
|
{
|
|
if ( !pm().curClass.super.Ref )
|
|
goto nosuper;
|
|
if ( change_line(true) )
|
|
break;
|
|
OUT_KEYWORD(".super ");
|
|
}
|
|
else
|
|
{
|
|
uchar sskip = 0;
|
|
if ( !pm().curClass.super.Ref )
|
|
goto check_imps;
|
|
if ( (pm().curClass.AccessFlag & ACC_INTERFACE)
|
|
&& (pm().curClass.extflg & XFL_C_SUPEROBJ) )
|
|
{
|
|
check_imps:
|
|
if ( !pm().curClass.impNode )
|
|
goto noparents;
|
|
sskip = 1;
|
|
}
|
|
|
|
if ( CHK_OUT_KEYWORD(" extends ") )
|
|
break;
|
|
if ( sskip )
|
|
goto nosuper;
|
|
}
|
|
if ( out_alt_ind(pm().curClass.super.Ref) )
|
|
break;
|
|
nosuper:
|
|
if ( pm().curClass.impNode )
|
|
{
|
|
const char *p = ".implements ";
|
|
if ( !jasmin() )
|
|
{
|
|
if ( pm().curClass.AccessFlag & ACC_INTERFACE )
|
|
{
|
|
if ( pm().curClass.super.Ref
|
|
&& !(pm().curClass.extflg&XFL_C_SUPEROBJ)
|
|
&& chkOutSymSpace(',') )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else if ( CHK_OUT_KEYWORD(" implements ") )
|
|
{
|
|
break;
|
|
}
|
|
p = NULL;
|
|
}
|
|
if ( !out_nodelist(pm().curClass.impNode, 0, p) )
|
|
break;
|
|
}
|
|
noparents:
|
|
if ( change_line(!jasmin()) )
|
|
break;
|
|
if ( pm().curClass.utsign && sign_out(pm().curClass.utsign, 1) )
|
|
break;
|
|
if ( pm().curClass.encClass && enclose_out() )
|
|
break;
|
|
if ( jasmin() && (pm().curClass.extflg & XFL_DEPRECATED) )
|
|
{
|
|
if ( out_deprecated(0) )
|
|
break;
|
|
}
|
|
if ( pm().curClass.genNode != 0 && out_includes(pm().curClass.genNode, 0) )
|
|
break;
|
|
struct ida_local lambda_t
|
|
{
|
|
static size_t call_debLine(java_t &pm, out_java_t *oj)
|
|
{
|
|
return oj->debLine(pm);
|
|
}
|
|
};
|
|
if ( (pm().curClass.extflg & XFL_C_DEBEXT)
|
|
&& fmtString(pm(), (ushort)-1, putDeb(0), fmt_debug, lambda_t::call_debLine) >= 0 )
|
|
{
|
|
out_tagoff(COLOR_STRING);
|
|
change_line();
|
|
}
|
|
break;
|
|
|
|
case SEG_XTRN:
|
|
case SEG_BSS:
|
|
if ( !jasmin() )
|
|
flush_buf(COLSTR("/*", SCOLOR_AUTOCMT), 0);
|
|
default:
|
|
break;
|
|
}
|
|
term_prompted_output();
|
|
pm().no_prim = false;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void idaapi java_segstart(outctx_t &ctx, segment_t *seg)
|
|
{
|
|
out_java_t *pctx = (out_java_t *)&ctx;
|
|
pctx->java_segstart(seg);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
void out_java_t::java_segend(segment_t *seg)
|
|
{
|
|
init_prompted_output(4);
|
|
uchar t = pm().getMySeg(BADADDR, seg)->type; // also set curSeg
|
|
switch ( t )
|
|
{
|
|
case SEG_CODE:
|
|
clr_gen_label(); // for empty method's
|
|
if ( pm().curSeg.id.extflg & XFL_M_LABEND )
|
|
out_method_label(1);
|
|
if ( pm().curSeg.excNode )
|
|
{
|
|
netnode enode(pm().curSeg.excNode);
|
|
uint j = (uint32)enode.altval(0);
|
|
if ( j == 0 )
|
|
DESTROYED("out::segend");
|
|
|
|
if ( !jasmin() )
|
|
flush_buf(COLSTR("/*", SCOLOR_AUTOCMT), 0); /*"*/// makedep BUG!!!
|
|
else
|
|
gen_empty_line();
|
|
uint i = 0;
|
|
do
|
|
{
|
|
Exception ex;
|
|
if ( enode.supval(++i, &ex, sizeof(ex)) != sizeof(ex) )
|
|
DESTROYED("out::except");
|
|
|
|
pm().curpos = 4; // for loop with large lines
|
|
if ( !jasmin() )
|
|
{
|
|
OUT_KEYWORD("try");
|
|
}
|
|
else
|
|
{
|
|
OUT_KEYWORD(".catch ");
|
|
CASSERT(offsetof(Exception, filter.Ref) == offsetof(Exception, filter.Name)
|
|
&& offsetof(Exception, filter.Dscr) == offsetof(Exception, filter.Name) + 2);
|
|
if ( !ex.filter.Ref )
|
|
OUT_KEYWORD("all");
|
|
else if ( out_alt_ind(ex.filter.Ref) )
|
|
goto STOP_NOW;
|
|
}
|
|
{
|
|
static const TXS kw[3] =
|
|
{
|
|
TXS_DECLARE(" from "),
|
|
TXS_DECLARE(" to "),
|
|
TXS_DECLARE(" using ")
|
|
};
|
|
int n = 0;
|
|
do
|
|
{
|
|
if ( n == 2 && !jasmin() )
|
|
{
|
|
if ( ex.filter.Ref )
|
|
{
|
|
if ( CHK_OUT_KEYWORD(" catch")
|
|
|| chkOutSymbol('(')
|
|
|| out_alt_ind(ex.filter.Ref)
|
|
|| chkOutSymbol(')') )
|
|
{
|
|
goto STOP_NOW;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( CHK_OUT_KEYWORD(" finally") )
|
|
goto STOP_NOW;
|
|
}
|
|
if ( CHK_OUT_KEYWORD(" handler ") )
|
|
goto STOP_NOW;
|
|
}
|
|
else
|
|
{
|
|
if ( chkOutKeyword(kw[n].str, kw[n].size) )
|
|
goto STOP_NOW;
|
|
}
|
|
CASSERT(offsetof(Exception,end_pc)-offsetof(Exception,start_pc) == sizeof(ushort)
|
|
&& offsetof(Exception,handler_pc)-offsetof(Exception,end_pc) == sizeof(ushort));
|
|
ushort off = 0;
|
|
switch ( n )
|
|
{
|
|
case 0: off = ex.start_pc; break;
|
|
case 1: off = ex.end_pc; break;
|
|
case 2: off = ex.handler_pc; break;
|
|
}
|
|
if ( outOffName(off) )
|
|
goto STOP_NOW;
|
|
}
|
|
while ( ++n < 3 );
|
|
}
|
|
if ( change_line() )
|
|
goto STOP_NOW;
|
|
}
|
|
while ( i < j );
|
|
if ( !jasmin() )
|
|
close_comment();
|
|
else
|
|
gen_empty_line();
|
|
}
|
|
if ( pm().curSeg.genNodes[1] && out_includes(pm().curSeg.genNodes[1], 2) )
|
|
goto STOP_NOW;
|
|
if ( pm().curSeg.DataSize )
|
|
goto STOP_NOW;
|
|
close_method:
|
|
for ( int i = 0; i < qnumber(pm().curSeg.annNodes); i++ )
|
|
{
|
|
if ( pm().curSeg.annNodes[i] )
|
|
{
|
|
if ( annotation_loop(pm().curSeg.annNodes, qnumber(pm().curSeg.annNodes)) )
|
|
goto STOP_NOW;
|
|
gen_empty_line();
|
|
break;
|
|
}
|
|
}
|
|
block_close(2, "method");
|
|
break;
|
|
|
|
// case SEG_IMP:
|
|
default: // PARANOYA
|
|
break;
|
|
|
|
case SEG_XTRN:
|
|
case SEG_BSS:
|
|
if ( !jasmin() )
|
|
close_comment();
|
|
if ( t == SEG_BSS )
|
|
goto close_method;
|
|
break;
|
|
}
|
|
myBorder();
|
|
STOP_NOW:
|
|
term_prompted_output();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
void idaapi java_segend(outctx_t &ctx, segment_t *seg)
|
|
{
|
|
out_java_t *pctx = (out_java_t *)&ctx;
|
|
pctx->java_segend(seg);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
static void check_float_const(ea_t ea, void *m, char len)
|
|
{
|
|
if ( !has_cmt(get_flags(ea)) && j_realcvt(m, NULL, (uchar)len) != REAL_ERROR_OK )
|
|
{
|
|
char cmt[2+5*5+2], *p = cmt;
|
|
|
|
*p++ = '0';
|
|
*p++ = 'x';
|
|
do
|
|
p += qsnprintf(p, 5, "%04X", ((ushort *)m)[uchar(len)]);
|
|
while ( --len >= 0 );
|
|
remember_problem(PR_ATTN, ea);
|
|
append_cmt(ea, cmt, false);
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
void out_java_t::java_data(bool /*analyze_only*/)
|
|
{
|
|
char nbuf[MAXSTR];
|
|
qstring name;
|
|
op_t x;
|
|
uint32 off;
|
|
uint32 lvc;
|
|
ea_t ea = insn_ea;
|
|
|
|
init_prompted_output();
|
|
char stype = pm().getMySeg(ea)->type; // also set curSeg
|
|
ea_t ip = ea - pm().curSeg.start_ea;
|
|
asize_t sz = get_item_size(ea) - 1;
|
|
switch ( stype )
|
|
{
|
|
case SEG_CODE:
|
|
if ( ip >= pm().curSeg.CodeSize )
|
|
goto STOP_NOW;
|
|
if ( get_name(NULL, ea) > 0 )
|
|
flush_buf(" "); // for string delimeter
|
|
if ( sz != 0 )
|
|
{
|
|
illcall:
|
|
out_line(COLSTR("!!!_UNSUPPORTED_OUTPUT_MODE_!!!", SCOLOR_ERROR));
|
|
}
|
|
else
|
|
{
|
|
pm().curpos = 2;
|
|
uchar c = get_byte(ea);
|
|
out_printf(COLSTR("%3u %s 0x%02X", SCOLOR_ERROR),
|
|
c, ash.cmnt, c);
|
|
}
|
|
default:
|
|
break;
|
|
|
|
case SEG_BSS:
|
|
if ( is_align(F) )
|
|
{
|
|
clr_gen_label();
|
|
set_gen_cmt(false);
|
|
set_gen_xrefs(false);
|
|
goto STOP_NOW;
|
|
}
|
|
lvc = 0; // unification
|
|
off = uint32(ea - pm().curSeg.DataBase);
|
|
if ( (uint32)off >= (uint32)pm().curSeg.DataSize )
|
|
{
|
|
off = (uint32)-1;
|
|
}
|
|
else if ( pm().curSeg.varNode
|
|
&& (lvc = (uint32)netnode(pm().curSeg.varNode).altval(off)) != 0 )
|
|
{
|
|
if ( (int32)lvc < 0 )
|
|
{
|
|
lvc = -(int32)lvc;
|
|
if ( sz ) // can be byte for 'overloaded' variables :(
|
|
{
|
|
if ( --sz )
|
|
goto BADIDB; // must be word
|
|
}
|
|
}
|
|
if ( (lvc % sizeof(LocVar)) || lvc >= sizeof(nbuf) )
|
|
goto BADIDB;
|
|
}
|
|
if ( jasmin() )
|
|
out_line(ash.cmnt, COLOR_AUTOCMT);
|
|
clr_gen_label();
|
|
if ( off == (uint32)-1 )
|
|
goto STOP_NOW;
|
|
if ( sz )
|
|
goto illcall;
|
|
if ( get_visible_name(&name, ea) > 0 )
|
|
out_printf(COLSTR("%s", SCOLOR_AUTOCMT), name.begin());
|
|
if ( lvc == 0 )
|
|
break;
|
|
set_gen_cmt(true);
|
|
set_gen_xrefs(true);
|
|
if ( change_line(true) )
|
|
goto STOP_NOW;
|
|
if ( netnode(pm().curSeg.varNode).supval(off, nbuf, lvc+1) != lvc )
|
|
goto BADIDB;
|
|
lvc /= sizeof(LocVar);
|
|
for ( LocVar *plv = (LocVar*)nbuf; ; plv++ )
|
|
{
|
|
if ( jasmin() )
|
|
{
|
|
pm().curpos = 4;
|
|
OUT_KEYWORD(".var ");
|
|
out_tagon(COLOR_NUMBER);
|
|
size_t inplen = outbuf.length();
|
|
out_printf("%u", off);
|
|
pm().outcnt += outbuf.length() - inplen;
|
|
out_tagoff(COLOR_NUMBER);
|
|
OUT_KEYWORD(" is ");
|
|
}
|
|
else
|
|
{
|
|
if ( plv->utsign && sign_out(plv->utsign, 0) )
|
|
break;
|
|
if ( OutUtf8(plv->var.Dscr, fmt_FieldDescriptor, COLOR_KEYWORD) )
|
|
break;
|
|
if ( chkOutSpace() )
|
|
break;
|
|
}
|
|
if ( OutUtf8(plv->var.Name, QS(fmt_UnqualifiedName), COLOR_DNAME) )
|
|
break;
|
|
if ( chkOutSpace() )
|
|
break;
|
|
if ( jasmin() )
|
|
{
|
|
if ( OutUtf8(plv->var.Dscr, fmt_FieldDescriptor, COLOR_KEYWORD) )
|
|
break;
|
|
if ( plv->utsign && sign_out(plv->utsign, 0) )
|
|
break;
|
|
if ( CHK_OUT_KEYWORD("from ") )
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
out_tagon(COLOR_AUTOCMT);
|
|
if ( !out_commented("Scope: ") )
|
|
break;
|
|
}
|
|
if ( putScope(plv->ScopeBeg, off) )
|
|
break;
|
|
if ( jasmin() )
|
|
{
|
|
if ( CHK_OUT_KEYWORD(" to ") )
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if ( CHK_OUT_STR(" / ") )
|
|
break;
|
|
}
|
|
if ( putScope(plv->ScopeTop, off) )
|
|
break;
|
|
if ( !jasmin() )
|
|
out_tagoff(COLOR_AUTOCMT);
|
|
if ( change_line(pm().curpos != 0) || !--lvc )
|
|
break;
|
|
}
|
|
goto STOP_NOW;
|
|
|
|
case SEG_XTRN:
|
|
if ( ip > (uint32)pm().curClass.xtrnCnt )
|
|
goto STOP_NOW;
|
|
if ( sz )
|
|
goto illcall;
|
|
if ( !ip )
|
|
{
|
|
gen_printf(0, COLSTR("%s Importing prototypes", SCOLOR_AUTOCMT),
|
|
jasmin() ? ash.cmnt : "");
|
|
break; // equivalence - gen_empty_line(); with comment
|
|
}
|
|
|
|
if ( jasmin() )
|
|
{
|
|
out_printf(COLSTR("%s", SCOLOR_AUTOCMT), ash.cmnt);
|
|
pm().outcnt = strlen(ash.cmnt);
|
|
}
|
|
clr_gen_label();
|
|
set_gen_cmt(false);
|
|
set_gen_xrefs(false);
|
|
{
|
|
const_desc_t co;
|
|
{
|
|
uint j = (uint32)pm().XtrnNode.altval(ip);
|
|
if ( j == 0 )
|
|
goto BADIDB;
|
|
if ( !pm().LoadOpis(lm_normal, (ushort)j, 0, &co) )
|
|
goto BADIDB;
|
|
}
|
|
copy_const_to_opnd(x, co); // name / class & dscr / subnam
|
|
x.ref = 0; // as flag
|
|
x.cp_type = co.type;
|
|
switch ( x.cp_type )
|
|
{
|
|
default:
|
|
goto BADIDB;
|
|
|
|
case CONSTANT_Class:
|
|
if ( !jasmin() )
|
|
{
|
|
outbuf.qclear();
|
|
pm().outcnt = 0;
|
|
}
|
|
{
|
|
static const TXS imp = TXS_DECLARE(".import ");
|
|
int of = !jasmin();
|
|
OutKeyword(imp.str+of, imp.size-of);
|
|
}
|
|
|
|
if ( !(co.flag & (HAS_TYPEDSCR | HAS_CLSNAME)) )
|
|
goto do_idx_out;
|
|
x.addr_shorts.high = (co.flag & HAS_CLSNAME) != 0
|
|
? fmt_fullname
|
|
: fmt_ClassName;
|
|
goto no_space_check;
|
|
|
|
case CONSTANT_Fieldref:
|
|
if ( (co.flag & NORM_FIELD) != NORM_FIELD )
|
|
goto do_idx;
|
|
break;
|
|
case CONSTANT_InterfaceMethodref:
|
|
case CONSTANT_Methodref:
|
|
if ( (co.flag & NORM_METOD) != NORM_METOD )
|
|
{
|
|
do_idx:
|
|
++x.ref;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if ( CHK_OUT_STR(" ") )
|
|
goto STOP_NOW;
|
|
if ( x.ref )
|
|
{
|
|
do_idx_out:
|
|
x.n = 2;
|
|
if ( !putVal(x, OOF_ADDR | OOF_NUMBER | OOFS_NOSIGN | OOFW_16, 1) )
|
|
goto STOP_NOW;
|
|
}
|
|
else
|
|
{
|
|
no_space_check:
|
|
if ( !OutConstant(x, /*include_descriptor=*/ true) )
|
|
goto STOP_NOW;
|
|
}
|
|
// if ( x.cp_type == CONSTANT_Class && !jasmin() )
|
|
// out_line(".*", COLOR_SYMBOL);
|
|
break;
|
|
|
|
case SEG_IMP:
|
|
if ( ip > (uint32)pm().curClass.FieldCnt )
|
|
goto STOP_NOW;
|
|
if ( sz )
|
|
goto illcall;
|
|
clr_gen_label();
|
|
set_gen_cmt(false);
|
|
set_gen_xrefs(false);
|
|
if ( !ip )
|
|
{
|
|
if ( pm().curClass.annNodes[0] | pm().curClass.annNodes[1] )
|
|
{
|
|
if ( annotation_loop(pm().curClass.annNodes, qnumber(pm().curClass.annNodes)) )
|
|
goto STOP_NOW;
|
|
}
|
|
if ( !jasmin() )
|
|
block_begin(0);
|
|
else
|
|
gen_empty_line();
|
|
|
|
if ( pm().curClass.innerNode )
|
|
{
|
|
netnode inode(pm().curClass.innerNode);
|
|
uint j = (uint32)inode.altval(0);
|
|
if ( j == 0 )
|
|
goto BADIDB;
|
|
color_t ci = jasmin() ? COLOR_IMPNAME : COLOR_NONE;
|
|
uint i = 0;
|
|
do
|
|
{
|
|
InnerClass ic;
|
|
if ( inode.supval(++i, &ic, sizeof(ic)) != sizeof(ic) )
|
|
goto BADIDB;
|
|
pm().curpos = 2;
|
|
if ( !jasmin() )
|
|
out_tagon(COLOR_AUTOCMT);
|
|
if ( OutModes((((uint32)ic.access) << 16) | OA_NEST) )
|
|
break;
|
|
if ( ic.name )
|
|
{
|
|
if ( OutUtf8(ic.name, fmt_UnqualifiedName, ci) )
|
|
break;
|
|
}
|
|
else if ( !jasmin() && CHK_OUT_STR("{anonymous}") )
|
|
{
|
|
break;
|
|
}
|
|
if ( ic.inner )
|
|
{
|
|
if ( jasmin() )
|
|
{
|
|
if ( CHK_OUT_KEYWORD(" inner ") )
|
|
break;
|
|
}
|
|
else if ( CHK_OUT_STR(" {is}: ") )
|
|
{
|
|
break;
|
|
}
|
|
if ( OutUtf8(ic.inner, fmt_fullname, ci) )
|
|
break;
|
|
}
|
|
if ( ic.outer )
|
|
{
|
|
if ( jasmin() )
|
|
{
|
|
if ( CHK_OUT_KEYWORD(" outer ") )
|
|
break;
|
|
}
|
|
else if ( CHK_OUT_STR(" {from}: ") )
|
|
{
|
|
break;
|
|
}
|
|
color_t co = ci;
|
|
if ( co != COLOR_NONE && ic.outer == pm().curClass.This.Name )
|
|
co = COLOR_DNAME;
|
|
if ( OutUtf8(ic.outer, fmt_fullname, co) )
|
|
break;
|
|
}
|
|
if ( !jasmin() )
|
|
out_tagoff(COLOR_AUTOCMT);
|
|
if ( change_line() )
|
|
break;
|
|
}
|
|
while ( i < j );
|
|
if ( pm().curClass.FieldCnt )
|
|
gen_empty_line();
|
|
}
|
|
goto STOP_NOW;
|
|
} // first entry (zero offset)
|
|
|
|
if ( pm().ClassNode.supval(ip, &pm().curField, sizeof(pm().curField)) != sizeof(pm().curField) )
|
|
goto BADIDB;
|
|
pm().curpos = 2;
|
|
if ( !jasmin() && pm().curField.id.utsign )
|
|
{
|
|
if ( sign_out(pm().curField.id.utsign, 0) )
|
|
goto STOP_NOW;
|
|
pm().curpos = 2;
|
|
}
|
|
if ( OutModes(OA_FIELD) )
|
|
goto STOP_NOW;
|
|
if ( !jasmin() && out_field_type() )
|
|
goto STOP_NOW;
|
|
if ( out_index(pm().curField.id.name, QS(fmt_UnqualifiedName), COLOR_DNAME, pm().curField.id.extflg & EFL_NAME) )
|
|
goto STOP_NOW;
|
|
if ( chkOutSpace() )
|
|
goto STOP_NOW;
|
|
if ( jasmin() && out_field_type() )
|
|
goto STOP_NOW;
|
|
|
|
if ( pm().curField.valNode )
|
|
{
|
|
netnode vnode(pm().curField.valNode);
|
|
|
|
uint valcnt = (uint32)vnode.altval(0);
|
|
if ( valcnt == 0 )
|
|
goto BADIDB;
|
|
x.n = 0;
|
|
x.flags = OF_SHOW;
|
|
x.type = o_imm;
|
|
|
|
if ( chkOutSymSpace('=') )
|
|
goto STOP_NOW;
|
|
for ( uint i = 1; ; i++ )
|
|
{
|
|
uchar flen;
|
|
|
|
const_desc_t co;
|
|
if ( vnode.supval(i, &co, sizeof(co)) != sizeof(co) )
|
|
{
|
|
ip = netnode(pm().curField.valNode).altval(i);
|
|
if ( ushort(ip) != 0xFFFF )
|
|
goto BADIDB;
|
|
if ( putShort(ushort(ip >> 16)) )
|
|
goto STOP_NOW;
|
|
}
|
|
else
|
|
{
|
|
switch ( co.type )
|
|
{
|
|
case CONSTANT_Long:
|
|
x.dtype = dt_qword;
|
|
copy_const_to_opnd(x, co);
|
|
flen = 3;
|
|
goto chk_flt;
|
|
case CONSTANT_Double:
|
|
x.dtype = dt_double;
|
|
check_float_const(ea, &co.value, 3);
|
|
copy_const_to_opnd(x, co);
|
|
goto one_w;
|
|
case CONSTANT_Float:
|
|
x.dtype = dt_float;
|
|
x.value = co.value;
|
|
flen = 1;
|
|
chk_flt:
|
|
check_float_const(ea, &x.value, flen);
|
|
goto one_w;
|
|
case CONSTANT_Integer:
|
|
x.dtype = dt_dword;
|
|
x.value = co.value;
|
|
one_w:
|
|
if ( !putVal(x, OOF_NUMBER | OOF_SIGNED | OOFW_IMM, 0) )
|
|
goto STOP_NOW;
|
|
break;
|
|
|
|
case CONSTANT_String:
|
|
if ( !checkLine(2) )
|
|
goto STOP_NOW;
|
|
if ( OutUtf8(co._name, fmt_string, COLOR_STRING) )
|
|
goto STOP_NOW;
|
|
break;
|
|
|
|
default:
|
|
UNCOMPAT("out::data");
|
|
}
|
|
}
|
|
|
|
if ( i >= valcnt )
|
|
break;
|
|
if ( chkOutSymSpace(',') )
|
|
goto STOP_NOW;
|
|
} // for(...) (value)
|
|
} // if ( valNode )
|
|
set_gen_cmt(true);
|
|
set_gen_xrefs(true);
|
|
if ( !change_line(pm().curpos != 0) )
|
|
{
|
|
uchar addonce = 0;
|
|
|
|
if ( jasmin() )
|
|
{
|
|
if ( pm().curField.id.utsign )
|
|
{
|
|
pm().curpos = 4;
|
|
if ( sign_out(pm().curField.id.utsign, -1) )
|
|
goto STOP_NOW;
|
|
addonce = 1;
|
|
}
|
|
if ( pm().curField.id.extflg & XFL_DEPRECATED )
|
|
{
|
|
if ( out_deprecated(4) )
|
|
goto STOP_NOW;
|
|
addonce = 1;
|
|
}
|
|
}
|
|
|
|
if ( pm().curField.genNode | pm().curField.annNodes[0] | pm().curField.annNodes[1] )
|
|
{
|
|
addonce = 1;
|
|
if ( !jasmin() )
|
|
block_begin(2);
|
|
}
|
|
|
|
if ( pm().curField.genNode && out_includes(pm().curField.genNode, 4) )
|
|
goto STOP_NOW;
|
|
|
|
if ( pm().curField.annNodes[0] | pm().curField.annNodes[1] )
|
|
{
|
|
pm().curpos = 4; // prompted output (prefer to new syntax)
|
|
if ( annotation_loop(pm().curField.annNodes, qnumber(pm().curField.annNodes)) )
|
|
goto STOP_NOW;
|
|
}
|
|
if ( addonce )
|
|
block_close(2, "field");
|
|
}
|
|
goto STOP_NOW;
|
|
}
|
|
|
|
set_gen_cmt(true);
|
|
set_gen_xrefs(true);
|
|
change_line(pm().curpos != 0);
|
|
STOP_NOW:
|
|
term_prompted_output();
|
|
return;
|
|
|
|
BADIDB:
|
|
DESTROYED("out::data");
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
void idaapi java_data(outctx_t &ctx, bool analyze_only)
|
|
{
|
|
out_java_t *pctx = (out_java_t *)&ctx;
|
|
pctx->java_data(analyze_only);
|
|
}
|