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

475 lines
13 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"
//----------------------------------------------------------------------
int32 java_t::print_loader_messages(char str[MAXSTR], const char *cmt, outctx_t *ctx)
{
netnode temp(curClass.msgNode);
ssize_t i = 0;
ssize_t j = (ssize_t)temp.altval(i);
if ( j == 0 )
BADIDB:
DESTROYED("loader_message");
do
{
ssize_t len = temp.supstr(i, str, MAXSTR);
if ( len <= 0 )
goto BADIDB;
if ( cmt )
{
QASSERT(10264, ctx != NULL);
if ( ctx->gen_printf(0, "%s%s", cmt, str) )
return -1;
}
else
{
qfwrite(myFile, str, len);
if ( qfputc('\n', myFile) == EOF )
return -1;
}
}
while ( ++i < j );
return i;
}
//----------------------------------------------------------------------
bool out_java_t::print_newline(void)
{
if ( ferror(pm().myFile) )
return false;
if ( qfputc('\n', pm().myFile) == EOF )
return false;
qfprintf(pm().myFile, "%*c", int(pm().curpos), ' ');
return true;
}
//----------------------------------------------------------------------
//lint -esym(818,write_utf) could be made const
static size_t write_utf(java_t &pm, out_java_t *oj)
{
qfprintf(pm.myFile, "%s", oj->outbuf.c_str());
if ( !oj->print_newline() )
return 0;
return pm.maxpos - 1;
}
//----------------------------------------------------------------------
static int utfstr(java_t &pm, ushort index, const const_desc_t &)
{
out_java_t *pctx = (out_java_t *)create_outctx(BADADDR);
int i = pctx->fmtString(pm, index, pm.maxpos -= pm.curpos, fmt_string, write_utf);
pm.maxpos += pm.curpos;
if ( i >= 0 )
qfprintf(pm.myFile, "%s\n", pctx->outbuf.c_str());
delete pctx;
return i < 0 ? 0 : ++i;
}
//----------------------------------------------------------------------
static int outnum(java_t &pm, ushort /*type*/, const const_desc_t &co)
{
op_t x;
copy_const_to_opnd(x, co);
qfprintf(pm.myFile, "value = %" FMT_EA "u\n", x.value);
return 1;
}
//----------------------------------------------------------------------
GCC_DIAG_OFF(format-nonliteral);
static int outref(java_t &pm, ushort count, const const_desc_t &co)
{
static const char typ[] = " Descriptor", nam[] = " Name";
switch ( count )
{
case 3:
qfprintf(pm.myFile, pm.ind_fmt, "Class", co._class);
qfprintf(pm.myFile, pm.ind_fmt, " ref", co._name);
qfprintf(pm.myFile, pm.ind_fmt, typ, co._dscr);
qfprintf(pm.myFile, pm.ind_fmt, nam, co._subnam);
break;
case 2:
qfprintf(pm.myFile, pm.ind_fmt, &typ[1], co._name);
qfprintf(pm.myFile, pm.ind_fmt, nam, co._class);
break;
case 1:
qfprintf(pm.myFile, pm.ind_fmt, "Index", co._name);
break;
}
qfputc('\n', pm.myFile);
return 1;
}
//----------------------------------------------------------------------
int java_t::refput(ushort index)
{
if ( !LoadOpis(lm_normal, index, CONSTANT_Utf8, NULL) )
return 0;
qfprintf(myFile, rfmt, index);
return utfstr(*this, index, const_desc_t());
}
GCC_DIAG_ON(format-nonliteral);
//----------------------------------------------------------------------
GCC_DIAG_OFF(format-nonliteral);
int32 java_t::gen_map_file(FILE *fp)
{
static const char form[] =
"Map format\n\n"
"<~W~idth:D::::> [72-%D], 0 - unlimited \n"
" Printing\n"
"<~A~ll:R> Included constant types\n"
"<~U~nused :R>> <Utf~8~:C>\n"
" Sorting by<~C~lass:C>\n"
"<~T~ype:R><~R~eferences:C>\n"
"<U~n~sorted:R>><Na~m~eAndType :C>\n"
" Number in pool<Num~b~ers:C>\n"
"<~D~ecimal :R><~S~tring:C>>\n"
"<~H~ex:R>>\n\n"
"<~O~ut Utf8 string without encoding :C>\n"
"<~I~nclude loader problem messages :C>>\n\n";
static const struct
{
int (*proc)(java_t &pm, ushort index, const const_desc_t &);
ushort mask;
ushort skip;
char name[8];
ushort arg;
} defr[MAX_CONSTANT_TYPE] =
{
{ utfstr, 0x01, 0, "Utf8 ", 0 },
{ NULL, 0x00, 0, "", 0 }, // unicode
{ outnum, 0x10, 4, "Integer", 3 + dt_dword },
{ outnum, 0x10, 4, "Float ", 3 + dt_float },
{ outnum, 0x10, 8, "Long ", 3 + dt_qword },
{ outnum, 0x10, 8, "Double ", 3 + dt_double },
{ outref, 0x02, 2, "Class ", 1 },
{ outref, 0x20, 2, "String ", 1 },
{ outref, 0x04, 4, "Fld_ref", 3 },
{ outref, 0x04, 4, "Met_ref", 3 },
{ outref, 0x04, 4, "Int_ref", 3 },
{ outref, 0x08, 4, "nam&typ", 2 }
};
#define STR_MIN_RESERVED 32
char str[MAXSTR];
uchar tflag;
sval_t width;
sval_t pos;
int32 numstr = 0;
uint32 save_flags = idpflags;
ushort curbit = 1;
short unus = 1, unsort = 1, hexnum = 0, typemask = 0x3F, encinc = 2;
const_desc_t opis;
ushort j;
if ( !(idpflags & IDF_ENCODING) )
++encinc; // |= 1
width = 80;
if ( !ask_form(form, &width, &pos, &unus, &unsort, &typemask, &hexnum, &encinc) )
return 0;
if ( encinc & 2 )
unus = 0; // from error - all
idpflags &= ~IDF_ENCODING;
if ( !(encinc & 1) )
idpflags |= IDF_ENCODING;
CASSERT(MAXSTR - STR_MIN_RESERVED > 72);
if ( width < 72 )
{
if ( width != 0 )
{
width = 72;
}
else
{
set_max:
width = sizeof(str) - STR_MIN_RESERVED;
}
}
else if ( width > MAXSTR-STR_MIN_RESERVED )
{
goto set_max;
}
if ( !typemask )
typemask = 0x3F;
if ( hexnum )
{
lft_fmt[7] = ind_fmt[5] = rfmt[17] = '4';
lft_fmt[8] = ind_fmt[6] = rfmt[18] = 'X';
curpos = 8 + 1 + 4 + 1 + 1 + 0 + 1;
}
else
{
lft_fmt[7] = ind_fmt[5] = rfmt[17] = '5';
lft_fmt[8] = ind_fmt[6] = rfmt[18] = 'u';
curpos = 8 + 1 + 5 + 1 + 1 + 0 + 1;
}
if ( unsort )
{
curpos += 7;
curbit = typemask;
}
maxpos = width;
myFile = fp;
do
{
while ( !(typemask & curbit) )
curbit <<= 1;
tflag = (uchar)unsort;
pos = 10;
FOR_EACH_CONSTANT_POOL_INDEX(i)
{
if ( !LoadOpis(lm_normal, i, 0, &opis) || opis.type == CONSTANT_Unicode )
DESTROYED("map::CP");
j = opis.type - 1;
DEB_ASSERT((j >= MAX_CONSTANT_TYPE), "map:type");
if ( (!unus || !opis.is_referenced()) && (curbit & defr[j].mask) )
{
if ( !numstr )
{
static const char fmh[]= "This file generated by IDA";
for ( int k = (maxpos - sizeof(fmh)) / 2; k; k-- )
qfputc(' ', fp);
char dname[MAXSTR];
if ( ConstantNode.supstr(CNS_SOURCE, dname, sizeof(dname)) < 0 )
DESTROYED("map:srcname");
qfprintf(fp, "%s\n\n"
" Constant Pool for \"%s\"\n\n"
" offset #(%s)\n",
fmh, dname, hexnum ? "hex" : "dec");
numstr = 5;
}
if ( !tflag )
{
qfprintf(fp,
"\n-----CONSTANT-%s-----\n",
(defr[j].arg < 3) ? defr[j].name
: ((defr[j].arg == 3) ? "(program references)" : "(numeric values)"));
++tflag;
numstr += 2;
}
qfprintf(fp, lft_fmt, int32(pos), i,
opis.is_referenced() ? ' ' : '*',
(unsort || defr[j].arg >= 3) ? defr[j].name : "");
{
int n = defr[j].proc(*this, defr[j].arg ? defr[j].arg : i, opis);
if ( n <= 0 )
goto do_eof;
numstr += n;
}
if ( unus && unsort && opis.type >= CONSTANT_Class )
{
numstr += refput(opis._name);
if ( opis.type > CONSTANT_String )
{
if ( opis.type == CONSTANT_NameAndType )
{
numstr += refput(opis._class);
}
else
{
numstr += refput(opis._subnam);
numstr += refput(opis._dscr);
}
}
}
if ( feof(fp) || ferror(fp) )
goto do_eof;
}
++pos;
j = defr[j].skip;
switch ( j )
{
case 0: // Utf8 / Unicode
pos += opis._Ssize + 2;
break;
case 8: // Long / Double
DEB_ASSERT((i == curClass.maxCPindex), "map:CPend");
++i;
// fallthrough
default:
pos += j;
break;
}
}
typemask ^= curbit;
}
while ( typemask != 0 );
if ( numstr ) // if error print before - header problems!
{
qfprintf(fp, "\nEnd of map\n");
numstr += 2;
if ( (encinc & 2) && curClass.msgNode )
{
qfprintf(fp, "\nLoader problem messages\n\n");
int32 slen = print_loader_messages(str, NULL, NULL);
if ( slen == -1 )
goto do_eof;
numstr += slen + 5;
qfprintf(fp, "\nEnd of messages\n");
}
if ( feof(fp) || ferror(fp) )
{
do_eof:
numstr = EOF;
}
}
myFile = NULL;
idpflags = save_flags;
return numstr;
}
GCC_DIAG_ON(format-nonliteral);
//----------------------------------------------------------------------
uchar java_t::loadDialog(bool manual)
{
static const char fmt[] =
"HELP\n"
"Java-VM class file loading options\n"
"\n"
"Do not create 'import' segment with external-references\n"
"\n"
" Prohibits the creation of a segment with external names, classes, and\n"
" methods.\n"
"\n"
"\n"
"Create 'import' segment with with references from commands\n"
"\n"
" Only regular references to the import segment will be collected.\n"
" If this option is off, then all references (including simple text\n"
" references) will be collected.\n"
"\n"
"\n"
"Field/variable declarations are included in references\n"
"\n"
" Cross references from field declarations are collected in the import\n"
" segment. For example, a field declaration\n"
"\n"
" Field borland.ui.AboutDialog about\n"
"\n"
" creates a reference to class borland.ui.AboutDialog\n"
"\n"
"\n"
"Method return types are included in references\n"
"\n"
" Cross references from the return type and arguments of method\n"
" declarations are collected in the import segment.\n"
" NOTE: The import segment does not contain classes that appear only in\n"
" the arguments of the method declarations.\n"
"\n"
"Store unknown attributes to external files\n"
"\n"
" This option allows to extract non-standard attributes (if present)\n"
" and store them to a set of files in the current directory.\n"
" Filenames will have <classname>.<tagname>.<attributename> form\n"
"\n"
"\n"
"Rename local (slot) variables (if information is available)\n"
"\n"
" This option allows to use names from variable declarations to\n"
" rename local variables if the input file has this information.\n"
"\n"
"\n"
"Create visible representation of stripped names\n"
"\n"
" Some java classes have their local\n"
" names stripped. This option allows IDA to recreate such local names.\n"
" NOTE: If this option is selected then all one-character names with\n"
" the character code >= 0x80 will be ignored.\n"
"\n"
"\n"
"Continue loading after errors in additional attributes\n"
"\n"
" Normally all errors in the classfile structure are fatal.\n"
" If this option is on, errors in the additional attributes\n"
" produce only warnings and the loading process continues.\n"
"\n"
"ENDHELP\n"
"Java loading options\n"
"\n"
" Class File version %D.%D (JDK1.%D%A)\n"
"\n"
"\n"
"<~D~o not create 'import' segment with external-references :R>\n"
"<~C~reate 'import' segment with references from commands :R>\n"
"<~F~ield/variable declarations are included in references :R>\n"
"<~M~ethod return types are included in references :R>>\n"
"\n"
"<~S~tore unknown attributes to external files :C>\n"
"<~R~ename local (slot) variables (if info is available) :C>\n"
"<Create ~v~isible representation of stripped names :C>\n"
"<Continue ~l~oading after errors in additional attributes :C>>\n"
"\n"
"\n";
CASSERT(((MLD__DEFAULT & MLD_METHREF) == 0 || (MLD__DEFAULT & MLD_VARREF) != 0)); //-V590
CASSERT(((MLD__DEFAULT & MLD_VARREF) == 0 || (MLD__DEFAULT & MLD_EXTREF) != 0)); //-V590
if ( !manual )
return MLD__DEFAULT;
short rtyp =
#if MLD__DEFAULT & MLD_METHREF
3;
#elif MLD__DEFAULT & MLD_VARREF
2;
#elif MLD__DEFAULT & MLD_EXTREF
1;
#else
0;
#endif
short mod = (MLD__DEFAULT & (MLD_EXTATR | MLD_LOCVAR | MLD_STRIP | MLD_FORCE)) >> 3; //lint !e572 Excessive shift value (precision 1 shifted right by 3)
CASSERT((MLD_EXTATR >> 3) == 1
&& (MLD_LOCVAR >> 3 ) == 2
&& (MLD_STRIP >> 3) == 4
&& (MLD_FORCE >> 3) == 8);
{
uval_t maxv = curClass.MajVers;
uval_t minv = curClass.MinVers;
uval_t jdk = curClass.JDKsubver;
if ( !ask_form(fmt, &maxv, &minv, &jdk,
jdk == 3 ? "/CLDC" : "",
&rtyp, &mod) )
qexit(1);
}
idpflags &= ~IDM_REQUNK; // do not use 'request mode' when 'manual options'
uchar ans = 0;
CASSERT(MLD_EXTATR == (1<<3)
&& MLD_LOCVAR == (2<<3)
&& MLD_STRIP == (4<<3)
&& MLD_FORCE == (8<<3));
ans |= ((uchar)mod) << 3;
CASSERT(MLD_EXTREF == 1 && MLD_VARREF == 2 && MLD_METHREF == 4);
ans |= (uchar)((1 << rtyp) - 1);
return ans;
}