/* * 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<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(""); 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(""); 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); }