mirror of
https://github.com/autc04/Retro68.git
synced 2024-06-01 15:41:39 +00:00
1640 lines
42 KiB
C++
1640 lines
42 KiB
C++
/* Copyright (C) 2021 Free Software Foundation, Inc.
|
|
Contributed by Oracle.
|
|
|
|
This file is part of GNU Binutils.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3, or (at your option)
|
|
any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, 51 Franklin Street - Fifth Floor, Boston,
|
|
MA 02110-1301, USA. */
|
|
|
|
#include "config.h"
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include "util.h"
|
|
#include "DbeSession.h"
|
|
#include "ClassFile.h"
|
|
#include "Function.h"
|
|
#include "StringBuilder.h"
|
|
#include "DbeFile.h"
|
|
|
|
class ByteCodeInfo
|
|
{
|
|
public:
|
|
|
|
ByteCodeInfo (JMethod *_func, int _bci, int _lno)
|
|
{
|
|
func = _func;
|
|
bci = _bci;
|
|
lno = _lno;
|
|
};
|
|
|
|
JMethod *func;
|
|
int bci;
|
|
int lno;
|
|
};
|
|
|
|
typedef unsigned char u1;
|
|
typedef unsigned short u2;
|
|
typedef unsigned int u4;
|
|
|
|
// Class File Constants
|
|
#define JAVA_MAGIC 0xcafebabe
|
|
|
|
enum {
|
|
// First argument in access_flags_to_str()
|
|
ClassAccess = 1,
|
|
FieldAccess,
|
|
MethodAccess,
|
|
NestedClassAccess,
|
|
|
|
// jdk/src/share/classes/sun/tools/java/RuntimeConstants.java
|
|
// Type codes
|
|
T_CLASS = 0x00000002,
|
|
T_BOOLEAN = 0x00000004,
|
|
T_CHAR = 0x00000005,
|
|
T_FLOAT = 0x00000006,
|
|
T_DOUBLE = 0x00000007,
|
|
T_BYTE = 0x00000008,
|
|
T_SHORT = 0x00000009,
|
|
T_INT = 0x0000000a,
|
|
T_LONG = 0x0000000b,
|
|
|
|
// Access and modifier flags
|
|
ACC_PUBLIC = 0x00000001,
|
|
ACC_PRIVATE = 0x00000002,
|
|
ACC_PROTECTED = 0x00000004,
|
|
ACC_STATIC = 0x00000008,
|
|
ACC_FINAL = 0x00000010,
|
|
ACC_SYNCHRONIZED = 0x00000020,
|
|
ACC_VOLATILE = 0x00000040,
|
|
ACC_TRANSIENT = 0x00000080,
|
|
ACC_NATIVE = 0x00000100,
|
|
ACC_INTERFACE = 0x00000200,
|
|
ACC_ABSTRACT = 0x00000400,
|
|
ACC_STRICT = 0x00000800,
|
|
ACC_SYNTHETIC = 0x00001000,
|
|
ACC_ANNOTATION = 0x00002000,
|
|
ACC_ENUM = 0x00004000,
|
|
|
|
ACC_SUPER = 0x00000020,
|
|
ACC_BRIDGE = 0x00000040,
|
|
ACC_VARARGS = 0x00000080,
|
|
|
|
// Opcodes
|
|
opc_try = -3,
|
|
opc_dead = -2,
|
|
opc_label = -1,
|
|
opc_nop = 0,
|
|
opc_aconst_null = 1,
|
|
opc_iconst_m1 = 2,
|
|
opc_iconst_0 = 3,
|
|
opc_iconst_1 = 4,
|
|
opc_iconst_2 = 5,
|
|
opc_iconst_3 = 6,
|
|
opc_iconst_4 = 7,
|
|
opc_iconst_5 = 8,
|
|
opc_lconst_0 = 9,
|
|
opc_lconst_1 = 10,
|
|
opc_fconst_0 = 11,
|
|
opc_fconst_1 = 12,
|
|
opc_fconst_2 = 13,
|
|
opc_dconst_0 = 14,
|
|
opc_dconst_1 = 15,
|
|
opc_bipush = 16,
|
|
opc_sipush = 17,
|
|
opc_ldc = 18,
|
|
opc_ldc_w = 19,
|
|
opc_ldc2_w = 20,
|
|
opc_iload = 21,
|
|
opc_lload = 22,
|
|
opc_fload = 23,
|
|
opc_dload = 24,
|
|
opc_aload = 25,
|
|
opc_iload_0 = 26,
|
|
opc_iload_1 = 27,
|
|
opc_iload_2 = 28,
|
|
opc_iload_3 = 29,
|
|
opc_lload_0 = 30,
|
|
opc_lload_1 = 31,
|
|
opc_lload_2 = 32,
|
|
opc_lload_3 = 33,
|
|
opc_fload_0 = 34,
|
|
opc_fload_1 = 35,
|
|
opc_fload_2 = 36,
|
|
opc_fload_3 = 37,
|
|
opc_dload_0 = 38,
|
|
opc_dload_1 = 39,
|
|
opc_dload_2 = 40,
|
|
opc_dload_3 = 41,
|
|
opc_aload_0 = 42,
|
|
opc_aload_1 = 43,
|
|
opc_aload_2 = 44,
|
|
opc_aload_3 = 45,
|
|
opc_iaload = 46,
|
|
opc_laload = 47,
|
|
opc_faload = 48,
|
|
opc_daload = 49,
|
|
opc_aaload = 50,
|
|
opc_baload = 51,
|
|
opc_caload = 52,
|
|
opc_saload = 53,
|
|
opc_istore = 54,
|
|
opc_lstore = 55,
|
|
opc_fstore = 56,
|
|
opc_dstore = 57,
|
|
opc_astore = 58,
|
|
opc_istore_0 = 59,
|
|
opc_istore_1 = 60,
|
|
opc_istore_2 = 61,
|
|
opc_istore_3 = 62,
|
|
opc_lstore_0 = 63,
|
|
opc_lstore_1 = 64,
|
|
opc_lstore_2 = 65,
|
|
opc_lstore_3 = 66,
|
|
opc_fstore_0 = 67,
|
|
opc_fstore_1 = 68,
|
|
opc_fstore_2 = 69,
|
|
opc_fstore_3 = 70,
|
|
opc_dstore_0 = 71,
|
|
opc_dstore_1 = 72,
|
|
opc_dstore_2 = 73,
|
|
opc_dstore_3 = 74,
|
|
opc_astore_0 = 75,
|
|
opc_astore_1 = 76,
|
|
opc_astore_2 = 77,
|
|
opc_astore_3 = 78,
|
|
opc_iastore = 79,
|
|
opc_lastore = 80,
|
|
opc_fastore = 81,
|
|
opc_dastore = 82,
|
|
opc_aastore = 83,
|
|
opc_bastore = 84,
|
|
opc_castore = 85,
|
|
opc_sastore = 86,
|
|
opc_pop = 87,
|
|
opc_pop2 = 88,
|
|
opc_dup = 89,
|
|
opc_dup_x1 = 90,
|
|
opc_dup_x2 = 91,
|
|
opc_dup2 = 92,
|
|
opc_dup2_x1 = 93,
|
|
opc_dup2_x2 = 94,
|
|
opc_swap = 95,
|
|
opc_iadd = 96,
|
|
opc_ladd = 97,
|
|
opc_fadd = 98,
|
|
opc_dadd = 99,
|
|
opc_isub = 100,
|
|
opc_lsub = 101,
|
|
opc_fsub = 102,
|
|
opc_dsub = 103,
|
|
opc_imul = 104,
|
|
opc_lmul = 105,
|
|
opc_fmul = 106,
|
|
opc_dmul = 107,
|
|
opc_idiv = 108,
|
|
opc_ldiv = 109,
|
|
opc_fdiv = 110,
|
|
opc_ddiv = 111,
|
|
opc_irem = 112,
|
|
opc_lrem = 113,
|
|
opc_frem = 114,
|
|
opc_drem = 115,
|
|
opc_ineg = 116,
|
|
opc_lneg = 117,
|
|
opc_fneg = 118,
|
|
opc_dneg = 119,
|
|
opc_ishl = 120,
|
|
opc_lshl = 121,
|
|
opc_ishr = 122,
|
|
opc_lshr = 123,
|
|
opc_iushr = 124,
|
|
opc_lushr = 125,
|
|
opc_iand = 126,
|
|
opc_land = 127,
|
|
opc_ior = 128,
|
|
opc_lor = 129,
|
|
opc_ixor = 130,
|
|
opc_lxor = 131,
|
|
opc_iinc = 132,
|
|
opc_i2l = 133,
|
|
opc_i2f = 134,
|
|
opc_i2d = 135,
|
|
opc_l2i = 136,
|
|
opc_l2f = 137,
|
|
opc_l2d = 138,
|
|
opc_f2i = 139,
|
|
opc_f2l = 140,
|
|
opc_f2d = 141,
|
|
opc_d2i = 142,
|
|
opc_d2l = 143,
|
|
opc_d2f = 144,
|
|
opc_i2b = 145,
|
|
opc_i2c = 146,
|
|
opc_i2s = 147,
|
|
opc_lcmp = 148,
|
|
opc_fcmpl = 149,
|
|
opc_fcmpg = 150,
|
|
opc_dcmpl = 151,
|
|
opc_dcmpg = 152,
|
|
opc_ifeq = 153,
|
|
opc_ifne = 154,
|
|
opc_iflt = 155,
|
|
opc_ifge = 156,
|
|
opc_ifgt = 157,
|
|
opc_ifle = 158,
|
|
opc_if_icmpeq = 159,
|
|
opc_if_icmpne = 160,
|
|
opc_if_icmplt = 161,
|
|
opc_if_icmpge = 162,
|
|
opc_if_icmpgt = 163,
|
|
opc_if_icmple = 164,
|
|
opc_if_acmpeq = 165,
|
|
opc_if_acmpne = 166,
|
|
opc_goto = 167,
|
|
opc_jsr = 168,
|
|
opc_ret = 169,
|
|
opc_tableswitch = 170,
|
|
opc_lookupswitch = 171,
|
|
opc_ireturn = 172,
|
|
opc_lreturn = 173,
|
|
opc_freturn = 174,
|
|
opc_dreturn = 175,
|
|
opc_areturn = 176,
|
|
opc_return = 177,
|
|
opc_getstatic = 178,
|
|
opc_putstatic = 179,
|
|
opc_getfield = 180,
|
|
opc_putfield = 181,
|
|
opc_invokevirtual = 182,
|
|
opc_invokespecial = 183,
|
|
opc_invokestatic = 184,
|
|
opc_invokeinterface = 185,
|
|
opc_invokedynamic = 186,
|
|
opc_new = 187,
|
|
opc_newarray = 188,
|
|
opc_anewarray = 189,
|
|
opc_arraylength = 190,
|
|
opc_athrow = 191,
|
|
opc_checkcast = 192,
|
|
opc_instanceof = 193,
|
|
opc_monitorenter = 194,
|
|
opc_monitorexit = 195,
|
|
opc_wide = 196,
|
|
opc_multianewarray = 197,
|
|
opc_ifnull = 198,
|
|
opc_ifnonnull = 199,
|
|
opc_goto_w = 200,
|
|
opc_jsr_w = 201,
|
|
opc_breakpoint = 202,
|
|
|
|
// Constant table
|
|
CONSTANT_UTF8 = 1,
|
|
CONSTANT_UNICODE = 2,
|
|
CONSTANT_INTEGER = 3,
|
|
CONSTANT_FLOAT = 4,
|
|
CONSTANT_LONG = 5,
|
|
CONSTANT_DOUBLE = 6,
|
|
CONSTANT_CLASS = 7,
|
|
CONSTANT_STRING = 8,
|
|
CONSTANT_FIELD = 9,
|
|
CONSTANT_METHOD = 10,
|
|
CONSTANT_INTERFACEMETHOD = 11,
|
|
CONSTANT_NAMEANDTYPE = 12,
|
|
CONSTANT_METHODHANDLE = 15,
|
|
CONSTANT_METHODTYPE = 16,
|
|
CONSTANT_INVOKEDYNAMIC = 18
|
|
};
|
|
|
|
static char *opcNames[] = {
|
|
NTXT ("nop"),
|
|
NTXT ("aconst_null"),
|
|
NTXT ("iconst_m1"),
|
|
NTXT ("iconst_0"),
|
|
NTXT ("iconst_1"),
|
|
NTXT ("iconst_2"),
|
|
NTXT ("iconst_3"),
|
|
NTXT ("iconst_4"),
|
|
NTXT ("iconst_5"),
|
|
NTXT ("lconst_0"),
|
|
NTXT ("lconst_1"),
|
|
NTXT ("fconst_0"),
|
|
NTXT ("fconst_1"),
|
|
NTXT ("fconst_2"),
|
|
NTXT ("dconst_0"),
|
|
NTXT ("dconst_1"),
|
|
NTXT ("bipush"),
|
|
NTXT ("sipush"),
|
|
NTXT ("ldc"),
|
|
NTXT ("ldc_w"),
|
|
NTXT ("ldc2_w"),
|
|
NTXT ("iload"),
|
|
NTXT ("lload"),
|
|
NTXT ("fload"),
|
|
NTXT ("dload"),
|
|
NTXT ("aload"),
|
|
NTXT ("iload_0"),
|
|
NTXT ("iload_1"),
|
|
NTXT ("iload_2"),
|
|
NTXT ("iload_3"),
|
|
NTXT ("lload_0"),
|
|
NTXT ("lload_1"),
|
|
NTXT ("lload_2"),
|
|
NTXT ("lload_3"),
|
|
NTXT ("fload_0"),
|
|
NTXT ("fload_1"),
|
|
NTXT ("fload_2"),
|
|
NTXT ("fload_3"),
|
|
NTXT ("dload_0"),
|
|
NTXT ("dload_1"),
|
|
NTXT ("dload_2"),
|
|
NTXT ("dload_3"),
|
|
NTXT ("aload_0"),
|
|
NTXT ("aload_1"),
|
|
NTXT ("aload_2"),
|
|
NTXT ("aload_3"),
|
|
NTXT ("iaload"),
|
|
NTXT ("laload"),
|
|
NTXT ("faload"),
|
|
NTXT ("daload"),
|
|
NTXT ("aaload"),
|
|
NTXT ("baload"),
|
|
NTXT ("caload"),
|
|
NTXT ("saload"),
|
|
NTXT ("istore"),
|
|
NTXT ("lstore"),
|
|
NTXT ("fstore"),
|
|
NTXT ("dstore"),
|
|
NTXT ("astore"),
|
|
NTXT ("istore_0"),
|
|
NTXT ("istore_1"),
|
|
NTXT ("istore_2"),
|
|
NTXT ("istore_3"),
|
|
NTXT ("lstore_0"),
|
|
NTXT ("lstore_1"),
|
|
NTXT ("lstore_2"),
|
|
NTXT ("lstore_3"),
|
|
NTXT ("fstore_0"),
|
|
NTXT ("fstore_1"),
|
|
NTXT ("fstore_2"),
|
|
NTXT ("fstore_3"),
|
|
NTXT ("dstore_0"),
|
|
NTXT ("dstore_1"),
|
|
NTXT ("dstore_2"),
|
|
NTXT ("dstore_3"),
|
|
NTXT ("astore_0"),
|
|
NTXT ("astore_1"),
|
|
NTXT ("astore_2"),
|
|
NTXT ("astore_3"),
|
|
NTXT ("iastore"),
|
|
NTXT ("lastore"),
|
|
NTXT ("fastore"),
|
|
NTXT ("dastore"),
|
|
NTXT ("aastore"),
|
|
NTXT ("bastore"),
|
|
NTXT ("castore"),
|
|
NTXT ("sastore"),
|
|
NTXT ("pop"),
|
|
NTXT ("pop2"),
|
|
NTXT ("dup"),
|
|
NTXT ("dup_x1"),
|
|
NTXT ("dup_x2"),
|
|
NTXT ("dup2"),
|
|
NTXT ("dup2_x1"),
|
|
NTXT ("dup2_x2"),
|
|
NTXT ("swap"),
|
|
NTXT ("iadd"),
|
|
NTXT ("ladd"),
|
|
NTXT ("fadd"),
|
|
NTXT ("dadd"),
|
|
NTXT ("isub"),
|
|
NTXT ("lsub"),
|
|
NTXT ("fsub"),
|
|
NTXT ("dsub"),
|
|
NTXT ("imul"),
|
|
NTXT ("lmul"),
|
|
NTXT ("fmul"),
|
|
NTXT ("dmul"),
|
|
NTXT ("idiv"),
|
|
NTXT ("ldiv"),
|
|
NTXT ("fdiv"),
|
|
NTXT ("ddiv"),
|
|
NTXT ("irem"),
|
|
NTXT ("lrem"),
|
|
NTXT ("frem"),
|
|
NTXT ("drem"),
|
|
NTXT ("ineg"),
|
|
NTXT ("lneg"),
|
|
NTXT ("fneg"),
|
|
NTXT ("dneg"),
|
|
NTXT ("ishl"),
|
|
NTXT ("lshl"),
|
|
NTXT ("ishr"),
|
|
NTXT ("lshr"),
|
|
NTXT ("iushr"),
|
|
NTXT ("lushr"),
|
|
NTXT ("iand"),
|
|
NTXT ("land"),
|
|
NTXT ("ior"),
|
|
NTXT ("lor"),
|
|
NTXT ("ixor"),
|
|
NTXT ("lxor"),
|
|
NTXT ("iinc"),
|
|
NTXT ("i2l"),
|
|
NTXT ("i2f"),
|
|
NTXT ("i2d"),
|
|
NTXT ("l2i"),
|
|
NTXT ("l2f"),
|
|
NTXT ("l2d"),
|
|
NTXT ("f2i"),
|
|
NTXT ("f2l"),
|
|
NTXT ("f2d"),
|
|
NTXT ("d2i"),
|
|
NTXT ("d2l"),
|
|
NTXT ("d2f"),
|
|
NTXT ("i2b"),
|
|
NTXT ("i2c"),
|
|
NTXT ("i2s"),
|
|
NTXT ("lcmp"),
|
|
NTXT ("fcmpl"),
|
|
NTXT ("fcmpg"),
|
|
NTXT ("dcmpl"),
|
|
NTXT ("dcmpg"),
|
|
NTXT ("ifeq"),
|
|
NTXT ("ifne"),
|
|
NTXT ("iflt"),
|
|
NTXT ("ifge"),
|
|
NTXT ("ifgt"),
|
|
NTXT ("ifle"),
|
|
NTXT ("if_icmpeq"),
|
|
NTXT ("if_icmpne"),
|
|
NTXT ("if_icmplt"),
|
|
NTXT ("if_icmpge"),
|
|
NTXT ("if_icmpgt"),
|
|
NTXT ("if_icmple"),
|
|
NTXT ("if_acmpeq"),
|
|
NTXT ("if_acmpne"),
|
|
NTXT ("goto"),
|
|
NTXT ("jsr"),
|
|
NTXT ("ret"),
|
|
NTXT ("tableswitch"),
|
|
NTXT ("lookupswitch"),
|
|
NTXT ("ireturn"),
|
|
NTXT ("lreturn"),
|
|
NTXT ("freturn"),
|
|
NTXT ("dreturn"),
|
|
NTXT ("areturn"),
|
|
NTXT ("return"),
|
|
NTXT ("getstatic"),
|
|
NTXT ("putstatic"),
|
|
NTXT ("getfield"),
|
|
NTXT ("putfield"),
|
|
NTXT ("invokevirtual"),
|
|
NTXT ("invokespecial"),
|
|
NTXT ("invokestatic"),
|
|
NTXT ("invokeinterface"),
|
|
NTXT ("invokedynamic"),
|
|
NTXT ("new"),
|
|
NTXT ("newarray"),
|
|
NTXT ("anewarray"),
|
|
NTXT ("arraylength"),
|
|
NTXT ("athrow"),
|
|
NTXT ("checkcast"),
|
|
NTXT ("instanceof"),
|
|
NTXT ("monitorenter"),
|
|
NTXT ("monitorexit"),
|
|
NTXT ("wide"),
|
|
NTXT ("multianewarray"),
|
|
NTXT ("ifnull"),
|
|
NTXT ("ifnonnull"),
|
|
NTXT ("goto_w"),
|
|
NTXT ("jsr_w"),
|
|
NTXT ("breakpoint")
|
|
};
|
|
|
|
|
|
#define APPEND_FLAG(len, buf, flag, x) \
|
|
if (((x) & (flag)) != 0) \
|
|
{ \
|
|
flag &= ~(x); \
|
|
AppendString(len, buf, NTXT("%s%s"), delimiter, #x); \
|
|
delimiter = NTXT("|"); \
|
|
}
|
|
|
|
static char *
|
|
access_flags_to_str (int kind, int flag)
|
|
{
|
|
static char buf[256];
|
|
size_t len = 0;
|
|
buf[0] = 0;
|
|
if (flag == 0)
|
|
{
|
|
AppendString (len, buf, NTXT ("0x%x"), (unsigned int) flag);
|
|
return buf;
|
|
}
|
|
const char *delimiter = "";
|
|
if (kind == ClassAccess)
|
|
{
|
|
APPEND_FLAG (len, buf, flag, ACC_FINAL);
|
|
APPEND_FLAG (len, buf, flag, ACC_SUPER);
|
|
APPEND_FLAG (len, buf, flag, ACC_INTERFACE);
|
|
APPEND_FLAG (len, buf, flag, ACC_ABSTRACT);
|
|
APPEND_FLAG (len, buf, flag, ACC_SYNTHETIC);
|
|
APPEND_FLAG (len, buf, flag, ACC_ANNOTATION);
|
|
APPEND_FLAG (len, buf, flag, ACC_ENUM);
|
|
if (flag)
|
|
AppendString (len, buf, "%s0x%x", delimiter, (unsigned int) (flag));
|
|
}
|
|
else if (kind == FieldAccess)
|
|
{
|
|
APPEND_FLAG (len, buf, flag, ACC_PUBLIC);
|
|
APPEND_FLAG (len, buf, flag, ACC_PRIVATE);
|
|
APPEND_FLAG (len, buf, flag, ACC_PROTECTED);
|
|
APPEND_FLAG (len, buf, flag, ACC_STATIC);
|
|
APPEND_FLAG (len, buf, flag, ACC_FINAL);
|
|
APPEND_FLAG (len, buf, flag, ACC_VOLATILE);
|
|
APPEND_FLAG (len, buf, flag, ACC_TRANSIENT);
|
|
APPEND_FLAG (len, buf, flag, ACC_SYNTHETIC);
|
|
APPEND_FLAG (len, buf, flag, ACC_ENUM);
|
|
if (flag)
|
|
AppendString (len, buf, "%s0x%x", delimiter, (unsigned int) (flag));
|
|
}
|
|
else if (kind == MethodAccess)
|
|
{
|
|
APPEND_FLAG (len, buf, flag, ACC_PUBLIC);
|
|
APPEND_FLAG (len, buf, flag, ACC_PRIVATE);
|
|
APPEND_FLAG (len, buf, flag, ACC_PROTECTED);
|
|
APPEND_FLAG (len, buf, flag, ACC_STATIC);
|
|
APPEND_FLAG (len, buf, flag, ACC_FINAL);
|
|
APPEND_FLAG (len, buf, flag, ACC_SYNCHRONIZED);
|
|
APPEND_FLAG (len, buf, flag, ACC_BRIDGE);
|
|
APPEND_FLAG (len, buf, flag, ACC_VARARGS);
|
|
APPEND_FLAG (len, buf, flag, ACC_NATIVE);
|
|
APPEND_FLAG (len, buf, flag, ACC_ABSTRACT);
|
|
APPEND_FLAG (len, buf, flag, ACC_STRICT);
|
|
APPEND_FLAG (len, buf, flag, ACC_SYNTHETIC);
|
|
if (flag)
|
|
AppendString (len, buf, "%s0x%x", delimiter, (unsigned int) (flag));
|
|
}
|
|
else if (kind == NestedClassAccess)
|
|
{
|
|
APPEND_FLAG (len, buf, flag, ACC_PUBLIC);
|
|
APPEND_FLAG (len, buf, flag, ACC_PRIVATE);
|
|
APPEND_FLAG (len, buf, flag, ACC_PROTECTED);
|
|
APPEND_FLAG (len, buf, flag, ACC_STATIC);
|
|
APPEND_FLAG (len, buf, flag, ACC_FINAL);
|
|
APPEND_FLAG (len, buf, flag, ACC_INTERFACE);
|
|
APPEND_FLAG (len, buf, flag, ACC_ABSTRACT);
|
|
APPEND_FLAG (len, buf, flag, ACC_SYNTHETIC);
|
|
APPEND_FLAG (len, buf, flag, ACC_ANNOTATION);
|
|
APPEND_FLAG (len, buf, flag, ACC_ENUM);
|
|
if (flag)
|
|
AppendString (len, buf, "%s0x%x", delimiter, (unsigned int) (flag));
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
class DataReadException
|
|
{
|
|
public:
|
|
|
|
DataReadException (char *s)
|
|
{
|
|
str_err = s;
|
|
}
|
|
|
|
~DataReadException ()
|
|
{
|
|
free (str_err);
|
|
}
|
|
|
|
char *
|
|
toString ()
|
|
{
|
|
return str_err;
|
|
}
|
|
|
|
private:
|
|
char *str_err;
|
|
};
|
|
|
|
class DataInputStream
|
|
{
|
|
public:
|
|
|
|
DataInputStream (const unsigned char *bytes, int64_t sz)
|
|
{
|
|
bp = bp_orig = bytes;
|
|
bp_last = bp_orig + sz;
|
|
}
|
|
|
|
DataInputStream (DataInputStream *in)
|
|
{
|
|
bp = bp_orig = in->bp_orig;
|
|
bp_last = in->bp_last;
|
|
}
|
|
|
|
u1
|
|
readByte ()
|
|
{
|
|
check (1);
|
|
u1 val = *bp;
|
|
bp++;
|
|
return val;
|
|
}
|
|
|
|
u2
|
|
readUnsignedShort ()
|
|
{
|
|
check (2);
|
|
u2 val = (bp[0] << 8) | bp[1];
|
|
bp += 2;
|
|
return val;
|
|
}
|
|
|
|
u4
|
|
readUnsigned ()
|
|
{
|
|
check (4);
|
|
u4 val = (bp[0] << 24) | (bp[1] << 16) | (bp[2] << 8) | bp[3];
|
|
bp += 4;
|
|
return val;
|
|
}
|
|
|
|
const u1 *
|
|
getptr ()
|
|
{
|
|
return bp;
|
|
}
|
|
|
|
const size_t
|
|
get_offset ()
|
|
{
|
|
return bp - bp_orig;
|
|
}
|
|
|
|
void
|
|
skip (int n)
|
|
{
|
|
check (n);
|
|
bp += n;
|
|
}
|
|
|
|
void
|
|
reset ()
|
|
{
|
|
bp = bp_orig;
|
|
}
|
|
|
|
void
|
|
copy_bytes (char *buf, int64_t len)
|
|
{
|
|
check (len);
|
|
memcpy (buf, bp, len);
|
|
buf[len] = '\0';
|
|
}
|
|
|
|
private:
|
|
|
|
void
|
|
check (int64_t sz)
|
|
{
|
|
if (sz < 0 || bp + sz > bp_last)
|
|
{
|
|
DataReadException *e1 = new DataReadException (
|
|
dbe_sprintf (GTXT ("(Cannot read %lld byte(s) offset=0x%llx)\n"),
|
|
(long long) sz, (long long) get_offset ()));
|
|
throw (e1);
|
|
}
|
|
};
|
|
|
|
const unsigned char *bp_last;
|
|
const unsigned char *bp_orig;
|
|
const unsigned char *bp;
|
|
};
|
|
|
|
class BinaryConstantPool
|
|
{
|
|
public:
|
|
BinaryConstantPool (DataInputStream &in);
|
|
~BinaryConstantPool ();
|
|
|
|
u1
|
|
getType (int n)
|
|
{
|
|
return (n < nconst && n > 0) ? types[n] : 0;
|
|
};
|
|
char *getString (int index);
|
|
|
|
private:
|
|
static char *getTypeName (int ty);
|
|
static char *type_name_to_str (int ty);
|
|
static char *offset_to_str (long long offset);
|
|
int nconst;
|
|
u1 *types;
|
|
int64_t *offsets;
|
|
char **strings;
|
|
DataInputStream *input;
|
|
};
|
|
|
|
char *
|
|
BinaryConstantPool::type_name_to_str (int ty)
|
|
{
|
|
static char buf[128];
|
|
char *tyName = getTypeName (ty);
|
|
snprintf (buf, sizeof (buf), NTXT ("%s(%d)"), tyName, ty);
|
|
return buf;
|
|
}
|
|
|
|
char *
|
|
BinaryConstantPool::offset_to_str (long long offset)
|
|
{
|
|
static char buf[128];
|
|
snprintf (buf, sizeof (buf), NTXT ("offset=0x%06llx (%llu)"), offset, offset);
|
|
return buf;
|
|
}
|
|
|
|
BinaryConstantPool::BinaryConstantPool (DataInputStream &in)
|
|
{
|
|
nconst = 0;
|
|
types = NULL;
|
|
offsets = NULL;
|
|
strings = NULL;
|
|
input = new DataInputStream (in);
|
|
int cntConst = in.readUnsignedShort ();
|
|
if (cntConst > 0)
|
|
{
|
|
types = new u1[cntConst];
|
|
types[0] = 0;
|
|
offsets = new int64_t [cntConst];
|
|
strings = new char * [cntConst];
|
|
strings[0] = NULL;
|
|
}
|
|
Dprintf (DUMP_JAVA_CLASS, NTXT ("# BinaryConstantPool: %d\n"), (int) nconst);
|
|
for (int i = 1; i < cntConst; i++)
|
|
{
|
|
nconst = i + 1;
|
|
strings[i] = NULL;
|
|
types[i] = in.readByte ();
|
|
offsets[i] = in.get_offset ();
|
|
Dprintf (DUMP_JAVA_CLASS, NTXT (" %3d %-25s %-25s"), i, offset_to_str (offsets[i]), type_name_to_str (types[i]));
|
|
switch (types[i])
|
|
{
|
|
case CONSTANT_UTF8:
|
|
{
|
|
u2 length = in.readUnsignedShort ();
|
|
in.skip (length);
|
|
Dprintf (DUMP_JAVA_CLASS, " length=%u\n", (unsigned int) length);
|
|
break;
|
|
}
|
|
case CONSTANT_INTEGER:
|
|
{
|
|
u4 bytes = in.readUnsigned ();
|
|
Dprintf (DUMP_JAVA_CLASS, " bytes=0x%08x\n", (unsigned int) bytes);
|
|
break;
|
|
}
|
|
case CONSTANT_FLOAT:
|
|
{
|
|
u4 bytes = in.readUnsigned ();
|
|
Dprintf (DUMP_JAVA_CLASS, " bytes=0x%08x\n", (unsigned int) bytes);
|
|
break;
|
|
}
|
|
case CONSTANT_LONG:
|
|
case CONSTANT_DOUBLE:
|
|
{
|
|
// JVM 4.4.5: all 8-byte constants take up
|
|
// two entries in the constant_pool table.
|
|
i++;
|
|
nconst++;
|
|
offsets[i] = 0;
|
|
strings[i] = NULL;
|
|
u4 high_bytes = in.readUnsigned ();
|
|
u4 low_bytes = in.readUnsigned ();
|
|
Dprintf (DUMP_JAVA_CLASS, NTXT (" high_bytes=0x%08x low_bytes=0x%08x\n"),
|
|
(unsigned int) high_bytes, (unsigned int) low_bytes);
|
|
break;
|
|
}
|
|
case CONSTANT_CLASS:
|
|
{
|
|
u2 name_index = in.readUnsignedShort ();
|
|
Dprintf (DUMP_JAVA_CLASS, NTXT (" name_index=%6u\n"), (unsigned int) name_index);
|
|
break;
|
|
}
|
|
case CONSTANT_STRING:
|
|
{
|
|
u2 string_index = in.readUnsignedShort ();
|
|
Dprintf (DUMP_JAVA_CLASS, NTXT (" string_index=%4u\n"), (unsigned int) string_index);
|
|
break;
|
|
}
|
|
case CONSTANT_FIELD:
|
|
case CONSTANT_METHOD:
|
|
case CONSTANT_INTERFACEMETHOD:
|
|
{
|
|
u2 class_index = in.readUnsignedShort ();
|
|
u2 name_and_type_index = in.readUnsignedShort ();
|
|
Dprintf (DUMP_JAVA_CLASS, NTXT (" class_index=%5u name_and_type_index=%u\n"),
|
|
(unsigned int) class_index, (unsigned int) name_and_type_index);
|
|
break;
|
|
}
|
|
case CONSTANT_NAMEANDTYPE:
|
|
{
|
|
u2 name_index = in.readUnsignedShort ();
|
|
u2 descriptor_index = in.readUnsignedShort ();
|
|
Dprintf (DUMP_JAVA_CLASS, " name_index=%6u descriptor_index=%u\n",
|
|
(unsigned int) name_index, (unsigned int) descriptor_index);
|
|
break;
|
|
}
|
|
case CONSTANT_METHODHANDLE:
|
|
{
|
|
u1 reference_kind = in.readByte ();
|
|
u2 reference_index = in.readUnsignedShort ();
|
|
Dprintf (DUMP_JAVA_CLASS, " reference_kind=%u reference_index=%u\n",
|
|
(unsigned int) reference_kind, (unsigned int) reference_index);
|
|
break;
|
|
}
|
|
case CONSTANT_METHODTYPE:
|
|
{
|
|
u2 descriptor_index = in.readUnsignedShort ();
|
|
Dprintf (DUMP_JAVA_CLASS, NTXT (" descriptor_index=%u\n"),
|
|
(unsigned int) descriptor_index);
|
|
break;
|
|
}
|
|
case CONSTANT_INVOKEDYNAMIC:
|
|
{
|
|
u2 bootstrap_method_attr_index = in.readUnsignedShort ();
|
|
u2 name_and_type_index = in.readUnsignedShort ();
|
|
Dprintf (DUMP_JAVA_CLASS, NTXT (" bootstrap_method_attr_index=%5u name_and_type_index=%u\n"),
|
|
(unsigned int) bootstrap_method_attr_index,
|
|
(unsigned int) name_and_type_index);
|
|
break;
|
|
}
|
|
default:
|
|
Dprintf (DUMP_JAVA_CLASS, NTXT ("\n"));
|
|
DataReadException *e1 = new DataReadException (
|
|
dbe_sprintf (GTXT ("BinaryConstantPool[%d]: bad tag %d %s\n"),
|
|
i, types[i], offset_to_str (offsets[i])));
|
|
throw (e1);
|
|
}
|
|
}
|
|
}
|
|
|
|
BinaryConstantPool::~BinaryConstantPool ()
|
|
{
|
|
delete[] types;
|
|
delete[] offsets;
|
|
delete input;
|
|
if (strings)
|
|
{
|
|
for (int i = 0; i < nconst; i++)
|
|
free (strings[i]);
|
|
delete[] strings;
|
|
}
|
|
}
|
|
|
|
#define CASE_S(x) case x: return (char *) #x
|
|
|
|
char *
|
|
BinaryConstantPool::getTypeName (int ty)
|
|
{
|
|
switch (ty)
|
|
{
|
|
CASE_S (CONSTANT_UTF8);
|
|
CASE_S (CONSTANT_INTEGER);
|
|
CASE_S (CONSTANT_FLOAT);
|
|
CASE_S (CONSTANT_LONG);
|
|
CASE_S (CONSTANT_DOUBLE);
|
|
CASE_S (CONSTANT_CLASS);
|
|
CASE_S (CONSTANT_STRING);
|
|
CASE_S (CONSTANT_FIELD);
|
|
CASE_S (CONSTANT_METHOD);
|
|
CASE_S (CONSTANT_INTERFACEMETHOD);
|
|
CASE_S (CONSTANT_NAMEANDTYPE);
|
|
CASE_S (CONSTANT_METHODHANDLE);
|
|
CASE_S (CONSTANT_METHODTYPE);
|
|
CASE_S (CONSTANT_INVOKEDYNAMIC);
|
|
default: return NTXT ("UNKNOWN_TYPE");
|
|
}
|
|
}
|
|
|
|
char *
|
|
BinaryConstantPool::getString (int index)
|
|
{
|
|
if (index >= nconst || index <= 0)
|
|
return NULL;
|
|
if (strings[index])
|
|
return strings[index];
|
|
input->reset ();
|
|
input->skip (offsets[index]);
|
|
switch (types[index])
|
|
{
|
|
case CONSTANT_CLASS:
|
|
case CONSTANT_STRING:
|
|
case CONSTANT_NAMEANDTYPE:
|
|
strings[index] = dbe_strdup (getString (input->readUnsignedShort ()));
|
|
return strings[index];
|
|
case CONSTANT_METHOD:
|
|
input->readUnsignedShort (); // cl_inx
|
|
strings[index] = dbe_strdup (getString (input->readUnsignedShort ()));
|
|
return strings[index];
|
|
case CONSTANT_UTF8:
|
|
break;
|
|
default:
|
|
return NULL;
|
|
}
|
|
u2 len = input->readUnsignedShort ();
|
|
strings[index] = (char *) malloc (len + 1);
|
|
input->copy_bytes (strings[index], len);
|
|
return strings[index];
|
|
}
|
|
|
|
ClassFile::ClassFile () : Module ()
|
|
{
|
|
input = NULL;
|
|
bcpool = NULL;
|
|
cf_buf = NULL;
|
|
cur_jmthd = NULL;
|
|
blanksCnt = 0;
|
|
cf_bufsz = 0;
|
|
lang_code = Sp_lang_java;
|
|
class_name = NULL;
|
|
class_filename = NULL;
|
|
source_name = NULL;
|
|
byteCodeInfo = NULL;
|
|
}
|
|
|
|
char *
|
|
ClassFile::get_opc_name (int op)
|
|
{
|
|
if (op >= 0 && ((size_t) op) < sizeof (opcNames) / sizeof (char*))
|
|
return opcNames[op];
|
|
switch (op)
|
|
{
|
|
case opc_try:
|
|
return NTXT ("try");
|
|
case opc_dead:
|
|
return NTXT ("dead");
|
|
case opc_label:
|
|
return NTXT ("label");
|
|
default:
|
|
return NTXT ("Unknown op code");
|
|
}
|
|
}
|
|
|
|
void
|
|
ClassFile::openFile (const char *fname)
|
|
{
|
|
if (fname == NULL)
|
|
return;
|
|
int fd = open64 (fname, O_RDONLY);
|
|
if (fd == -1)
|
|
{
|
|
append_msg (CMSG_ERROR, GTXT ("Cannot open file %s"), fname);
|
|
return;
|
|
}
|
|
struct stat64 stat_buf;
|
|
if ((fstat64 (fd, &stat_buf) == -1) || (stat_buf.st_size == 0))
|
|
{
|
|
close (fd);
|
|
append_msg (CMSG_ERROR, GTXT ("Cannot read file %s"), fname);
|
|
return;
|
|
}
|
|
cf_bufsz = stat_buf.st_size;
|
|
cf_buf = (unsigned char *) malloc (cf_bufsz);
|
|
if (cf_bufsz != read_from_file (fd, cf_buf, cf_bufsz))
|
|
{
|
|
free (cf_buf);
|
|
cf_buf = NULL;
|
|
close (fd);
|
|
append_msg (CMSG_ERROR, GTXT ("Cannot read file %s"), fname);
|
|
return;
|
|
}
|
|
close (fd);
|
|
|
|
input = new DataInputStream (cf_buf, cf_bufsz);
|
|
u4 c_magic = input->readUnsigned ();
|
|
if (c_magic != JAVA_MAGIC)
|
|
{
|
|
append_msg (CMSG_ERROR, GTXT ("Not a class file: %s"), fname);
|
|
return;
|
|
}
|
|
/* u2 minor = */ input->readUnsignedShort ();
|
|
/* u2 major = */ input->readUnsignedShort ();
|
|
status = AE_OK;
|
|
}
|
|
|
|
ClassFile::~ClassFile ()
|
|
{
|
|
free (cf_buf);
|
|
free (class_name);
|
|
free (class_filename);
|
|
free (source_name);
|
|
delete bcpool;
|
|
delete input;
|
|
}
|
|
|
|
static void
|
|
convertName (char *s)
|
|
{
|
|
while (*s)
|
|
{
|
|
if (*s == '/')
|
|
*s = '.';
|
|
s++;
|
|
}
|
|
}
|
|
|
|
void
|
|
ClassFile::printConstant (StringBuilder *sb, int index)
|
|
{
|
|
u1 type = bcpool->getType (index);
|
|
switch (type)
|
|
{
|
|
case CONSTANT_METHOD:
|
|
{
|
|
char *str = bcpool->getString (index);
|
|
if (str)
|
|
{
|
|
convertName (str);
|
|
sb->append (str);
|
|
sb->append (NTXT ("()"));
|
|
}
|
|
break;
|
|
}
|
|
case CONSTANT_CLASS:
|
|
{
|
|
char *str = bcpool->getString (index);
|
|
if (str)
|
|
{
|
|
convertName (str);
|
|
sb->append (str);
|
|
}
|
|
break;
|
|
}
|
|
case CONSTANT_UTF8:
|
|
{
|
|
char *str = bcpool->getString (index);
|
|
if (str)
|
|
sb->append (str);
|
|
break;
|
|
}
|
|
case CONSTANT_STRING:
|
|
{
|
|
char *str = bcpool->getString (index);
|
|
if (str)
|
|
{
|
|
sb->append ('"');
|
|
sb->append (str);
|
|
sb->append ('"');
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
sb->append ('#');
|
|
sb->append ((int) index);
|
|
break;
|
|
}
|
|
}
|
|
|
|
long long
|
|
ClassFile::printCodeSequence (StringBuilder *sb, uint64_t addr, DataInputStream *in)
|
|
{
|
|
int64_t offset = in->get_offset ();
|
|
sb->appendf (NTXT ("%08llx: "), (long long) addr);
|
|
int opcode = in->readByte ();
|
|
if (opcode == opc_wide)
|
|
{
|
|
opcode = in->readByte ();
|
|
sb->append (get_opc_name (opcode));
|
|
sb->append (NTXT ("_w "));
|
|
int arg = in->readUnsignedShort ();
|
|
switch (opcode)
|
|
{
|
|
case opc_aload: case opc_astore:
|
|
case opc_fload: case opc_fstore:
|
|
case opc_iload: case opc_istore:
|
|
case opc_lload: case opc_lstore:
|
|
case opc_dload: case opc_dstore:
|
|
case opc_ret:
|
|
sb->append (arg);
|
|
break;
|
|
case opc_iinc:
|
|
sb->append (arg);
|
|
sb->append (' ');
|
|
sb->append (in->readUnsignedShort ());
|
|
break;
|
|
default:
|
|
sb->append (GTXT ("Invalid opcode"));
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sb->append (get_opc_name (opcode));
|
|
sb->append (' ');
|
|
switch (opcode)
|
|
{
|
|
case opc_aload: case opc_astore:
|
|
case opc_fload: case opc_fstore:
|
|
case opc_iload: case opc_istore:
|
|
case opc_lload: case opc_lstore:
|
|
case opc_dload: case opc_dstore:
|
|
case opc_ret:
|
|
sb->append (in->readByte ());
|
|
break;
|
|
case opc_iinc:
|
|
sb->append (in->readByte ());
|
|
sb->append (' ');
|
|
sb->append (in->readByte ());
|
|
break;
|
|
case opc_tableswitch:
|
|
{
|
|
int align = (addr + 1) % 4; // 1 byte is a length of opc_lookupswitch
|
|
if (align != 0)
|
|
{
|
|
in->skip (4 - align); // four byte boundry
|
|
}
|
|
long default_skip = in->readUnsigned ();
|
|
long low = in->readUnsigned ();
|
|
long high = in->readUnsigned ();
|
|
sb->appendf (GTXT ("%ld to %ld: default=0x%llx"),
|
|
(long) low, (long) high, (long long) (addr + default_skip));
|
|
for (long i = low; i <= high; ++i)
|
|
/* u4 i1 = */ in->readUnsigned ();
|
|
break;
|
|
}
|
|
case opc_lookupswitch:
|
|
{
|
|
int align = (addr + 1) % 4; // 1 byte is a length of opc_lookupswitch
|
|
if (align != 0)
|
|
in->skip (4 - align); // four byte boundry
|
|
u4 default_skip = in->readUnsigned ();
|
|
u4 npairs = in->readUnsigned ();
|
|
sb->appendf (GTXT ("%d: default=0x%llx"), npairs,
|
|
(long long) (addr + default_skip));
|
|
for (int i = 0, nints = npairs * 2; i < nints; i += 2)
|
|
{
|
|
/* u4 i1 = */ in->readUnsigned ();
|
|
/* u4 i2 = */ in->readUnsigned ();
|
|
}
|
|
break;
|
|
}
|
|
case opc_newarray:
|
|
switch (in->readByte ())
|
|
{
|
|
case T_INT:
|
|
sb->append (GTXT ("int"));
|
|
break;
|
|
case T_LONG:
|
|
sb->append (GTXT ("long"));
|
|
break;
|
|
case T_FLOAT:
|
|
sb->append (GTXT ("float"));
|
|
break;
|
|
case T_DOUBLE:
|
|
sb->append (GTXT ("double"));
|
|
break;
|
|
case T_CHAR:
|
|
sb->append (GTXT ("char"));
|
|
break;
|
|
case T_SHORT:
|
|
sb->append (GTXT ("short"));
|
|
break;
|
|
case T_BYTE:
|
|
sb->append (GTXT ("byte"));
|
|
break;
|
|
case T_BOOLEAN:
|
|
sb->append (GTXT ("boolean"));
|
|
break;
|
|
default:
|
|
sb->append (GTXT ("BOGUS TYPE"));
|
|
break;
|
|
}
|
|
break;
|
|
case opc_anewarray:
|
|
sb->append (GTXT ("class "));
|
|
printConstant (sb, in->readUnsignedShort ());
|
|
break;
|
|
case opc_sipush:
|
|
sb->append (in->readUnsignedShort ());
|
|
break;
|
|
case opc_bipush:
|
|
sb->append (in->readByte ());
|
|
break;
|
|
case opc_ldc:
|
|
printConstant (sb, in->readByte ());
|
|
break;
|
|
case opc_ldc_w: case opc_ldc2_w:
|
|
case opc_instanceof: case opc_checkcast:
|
|
case opc_new:
|
|
case opc_putstatic: case opc_getstatic:
|
|
case opc_putfield: case opc_getfield:
|
|
case opc_invokevirtual:
|
|
case opc_invokespecial:
|
|
case opc_invokestatic:
|
|
printConstant (sb, in->readUnsignedShort ());
|
|
break;
|
|
case opc_invokeinterface:
|
|
{
|
|
u2 index = in->readUnsignedShort ();
|
|
u1 count = in->readByte ();
|
|
/* u1 zero = */ in->readByte ();
|
|
sb->appendf (" #%u, %u) ", (unsigned int) index, (unsigned int) count);
|
|
printConstant (sb, index);
|
|
break;
|
|
}
|
|
case opc_multianewarray:
|
|
{
|
|
u2 index = in->readUnsignedShort ();
|
|
printConstant (sb, index);
|
|
sb->appendf (GTXT (" dim #%d "), index);
|
|
break;
|
|
}
|
|
case opc_jsr: case opc_goto:
|
|
case opc_ifeq: case opc_ifge: case opc_ifgt:
|
|
case opc_ifle: case opc_iflt: case opc_ifne:
|
|
case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmpge:
|
|
case opc_if_icmpgt: case opc_if_icmple: case opc_if_icmplt:
|
|
case opc_if_acmpeq: case opc_if_acmpne:
|
|
case opc_ifnull: case opc_ifnonnull:
|
|
sb->appendf (NTXT ("0x%llx"), (long long) (addr + (short) in->readUnsignedShort ()));
|
|
break;
|
|
case opc_jsr_w:
|
|
case opc_goto_w:
|
|
sb->append (addr + (int) in->readUnsigned ());
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return in->get_offset () - offset;
|
|
}
|
|
|
|
void
|
|
ClassFile::readAttributes (int count)
|
|
{
|
|
blanksCnt += 4;
|
|
for (int ax = 0; ax < count; ax++)
|
|
{
|
|
u2 attribute_name_index = input->readUnsignedShort ();
|
|
u4 attribute_length = input->readUnsigned ();
|
|
char *attribute_name = bcpool->getString (attribute_name_index);
|
|
if (!attribute_name)
|
|
{
|
|
Dprintf (DUMP_JAVA_CLASS, NTXT ("%*c %2d: attr_name=%3d %-15s len=%4d\n"),
|
|
(int) blanksCnt, ' ', (int) (ax + 1),
|
|
(int) attribute_name_index, STR (attribute_name), (int) attribute_length);
|
|
input->skip (attribute_length);
|
|
continue;
|
|
}
|
|
|
|
if (strcmp (attribute_name, NTXT ("SourceFile")) == 0)
|
|
{
|
|
u2 sourcefile_index = input->readUnsignedShort ();
|
|
source_name = dbe_strdup (bcpool->getString (sourcefile_index));
|
|
Dprintf (DUMP_JAVA_CLASS, NTXT ("%*c %2d: attr_name=%3d %-15s len=%4d file_name=%d %s\n"),
|
|
(int) blanksCnt, ' ', (int) (ax + 1),
|
|
(int) attribute_name_index, STR (attribute_name), (int) attribute_length,
|
|
(int) sourcefile_index, STR (source_name));
|
|
}
|
|
else if (strcmp (attribute_name, NTXT ("InnerClasses")) == 0)
|
|
{
|
|
int niclasses = input->readUnsignedShort ();
|
|
for (int ix = 0; ix < niclasses; ix++)
|
|
{
|
|
u2 inner_class_info_index = input->readUnsignedShort ();
|
|
u2 outer_class_info_index = input->readUnsignedShort ();
|
|
u2 inner_name_index = input->readUnsignedShort ();
|
|
u2 inner_class_access_flags = input->readUnsignedShort ();
|
|
Dprintf (DUMP_JAVA_CLASS,
|
|
NTXT ("%*c %2d: attr_name=%3d %-15s len=%4d name=%d '%s'\n"
|
|
"%*cinner_class_info_index=%d outer_class_info_index=%d flags=%s\n"),
|
|
(int) blanksCnt, ' ', (int) (ax + 1),
|
|
(int) attribute_name_index, STR (attribute_name), (int) attribute_length,
|
|
(int) inner_name_index, STR (bcpool->getString (inner_name_index)),
|
|
(int) (blanksCnt + 10), ' ',
|
|
(int) inner_class_info_index, (int) outer_class_info_index,
|
|
access_flags_to_str (NestedClassAccess, inner_class_access_flags));
|
|
}
|
|
}
|
|
else if (strcmp (attribute_name, NTXT ("Code")) == 0)
|
|
{
|
|
u2 max_stack = input->readUnsignedShort ();
|
|
u2 max_locals = input->readUnsignedShort ();
|
|
u4 code_length = input->readUnsigned ();
|
|
if (cur_jmthd)
|
|
{
|
|
cur_jmthd->size = code_length;
|
|
cur_jmthd->img_fname = dbeFile->get_location ();
|
|
cur_jmthd->img_offset = input->get_offset ();
|
|
}
|
|
input->skip (code_length);
|
|
u2 exception_table_length = input->readUnsignedShort ();
|
|
input->skip (exception_table_length * (2 + 2 + 2 + 2));
|
|
Dprintf (DUMP_JAVA_CLASS,
|
|
NTXT ("%*c %2d: attr_name=%3d %-15s len=%4d max_stack=%d max_locals=%d code_length=%d exception_table_length=%d\n"),
|
|
(int) blanksCnt, ' ', (int) (ax + 1),
|
|
(int) attribute_name_index, STR (attribute_name), (int) attribute_length,
|
|
(int) max_stack, (int) max_locals, (int) code_length, (int) exception_table_length);
|
|
readAttributes (input->readUnsignedShort ());
|
|
}
|
|
else if (strcmp (attribute_name, NTXT ("LineNumberTable")) == 0)
|
|
{
|
|
int nlines = input->readUnsignedShort ();
|
|
Dprintf (DUMP_JAVA_CLASS, NTXT ("%*c %2d: attr_name=%3d %-15s len=%4d nlines=%d\n"),
|
|
(int) blanksCnt, ' ', (int) (ax + 1),
|
|
(int) attribute_name_index, STR (attribute_name), (int) attribute_length,
|
|
(int) nlines);
|
|
for (int lx = 0; lx < nlines; lx++)
|
|
{
|
|
int bci = input->readUnsignedShort ();
|
|
int lno = input->readUnsignedShort ();
|
|
Dprintf (DUMP_JAVA_CLASS, NTXT ("%*c %3d: pc=%4d (0x%04x) line=%d\n"),
|
|
(int) (blanksCnt + 5), ' ', (int) (lx + 1), (int) bci, (int) bci, (int) lno);
|
|
if (cur_jmthd)
|
|
byteCodeInfo->append (new ByteCodeInfo (cur_jmthd, bci, lno));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Dprintf (DUMP_JAVA_CLASS, NTXT ("%*c %2d: attr_name=%3d %-15s len=%4d\n"),
|
|
(int) blanksCnt, ' ', (int) (ax + 1),
|
|
(int) attribute_name_index, STR (attribute_name),
|
|
(int) attribute_length);
|
|
input->skip (attribute_length);
|
|
}
|
|
}
|
|
blanksCnt -= 4;
|
|
}
|
|
|
|
int
|
|
ClassFile::readFile ()
|
|
{
|
|
if (status != AE_NOTREAD)
|
|
return status;
|
|
status = AE_OTHER;
|
|
|
|
// The ClassFile Structure http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html
|
|
try
|
|
{
|
|
blanksCnt = 4;
|
|
cur_jmthd = NULL;
|
|
char *fname = dbeFile->get_location ();
|
|
openFile (fname);
|
|
Dprintf (DUMP_JAVA_CLASS, NTXT ("\nClassFile::readFile status=%d %s location=%s\n"),
|
|
(unsigned int) status, STR (get_name ()), STR (fname));
|
|
if (status != AE_OK)
|
|
return status;
|
|
byteCodeInfo = new Vector<ByteCodeInfo *>(512);
|
|
bcpool = new BinaryConstantPool (*input);
|
|
u2 access_flags = input->readUnsignedShort ();
|
|
Dprintf (DUMP_JAVA_CLASS, NTXT ("\naccess_flags=%s; %s\n"),
|
|
access_flags_to_str (ClassAccess, access_flags),
|
|
STR (dbeFile->get_name ()));
|
|
u2 classNameInd = input->readUnsignedShort ();
|
|
class_filename = dbe_strdup (bcpool->getString (classNameInd));
|
|
if (class_filename)
|
|
{
|
|
class_name = strdup (class_filename);
|
|
convertName (class_name);
|
|
}
|
|
|
|
// Get superclass name
|
|
u2 superClassInd = input->readUnsignedShort ();
|
|
//char *str = bcpool->getString(superClassInd);
|
|
//super_name = str ? convertName( str ) : NULL;
|
|
|
|
// Read interfaces
|
|
int interfaces_count = input->readUnsignedShort ();
|
|
Dprintf (DUMP_JAVA_CLASS,
|
|
NTXT (" class_name=%3d %-20s superClass=%3d %s interfaces_count=%d\n"),
|
|
(int) classNameInd, STR (class_name),
|
|
(int) superClassInd, STR (bcpool->getString (superClassInd)),
|
|
(int) interfaces_count);
|
|
for (int i = 0; i < interfaces_count; i++)
|
|
{
|
|
u2 index = input->readUnsignedShort ();
|
|
Dprintf (DUMP_JAVA_CLASS, NTXT (" %6lld%s"), (long long) index,
|
|
(i % 8 == 7) || (i + 1 == interfaces_count) ? "\n" : "");
|
|
}
|
|
|
|
// Read fields
|
|
int fields_count = input->readUnsignedShort ();
|
|
Dprintf (DUMP_JAVA_CLASS, NTXT (" fields_count=%d\n"), fields_count);
|
|
for (int i = 0; i < fields_count; i++)
|
|
{
|
|
u2 fld_access_flags = input->readUnsignedShort ();
|
|
u2 name_index = input->readUnsignedShort ();
|
|
u2 descriptor_index = input->readUnsignedShort ();
|
|
u2 attributes_count = input->readUnsignedShort ();
|
|
Dprintf (DUMP_JAVA_CLASS,
|
|
NTXT (" %2d: name=%3d %-20s flags=%s; desc_ind=%d attr_count=%d\n"),
|
|
i, (int) name_index, STR (bcpool->getString (name_index)),
|
|
access_flags_to_str (FieldAccess, fld_access_flags),
|
|
(int) descriptor_index, (int) attributes_count);
|
|
readAttributes (attributes_count);
|
|
}
|
|
|
|
// Read methods
|
|
int methods_count = input->readUnsignedShort ();
|
|
Dprintf (DUMP_JAVA_CLASS, NTXT ("\n methods_count=%d\n"), (int) methods_count);
|
|
int func_cnt = functions->size ();
|
|
for (int i = 0; i < methods_count; i++)
|
|
{
|
|
u2 mthd_access_flags = input->readUnsignedShort ();
|
|
u2 name_index = input->readUnsignedShort ();
|
|
u2 descriptor_index = input->readUnsignedShort ();
|
|
char *mname = bcpool->getString (name_index);
|
|
if (mname == NULL)
|
|
{
|
|
DataReadException *e1 = new DataReadException (dbe_sprintf (GTXT ("method name[%d] is NULL\n"), i));
|
|
throw (e1);
|
|
}
|
|
char *msign = bcpool->getString (descriptor_index);
|
|
if (msign == NULL)
|
|
{
|
|
DataReadException *e1 = new DataReadException (dbe_sprintf (GTXT ("method signature[%d] is NULL\n"), i));
|
|
throw (e1);
|
|
}
|
|
size_t len = strlen (class_name);
|
|
cur_jmthd = NULL;
|
|
for (int idx = 0; idx < func_cnt; idx++)
|
|
{
|
|
JMethod *jmthd = (JMethod*) functions->fetch (idx);
|
|
char *jmt_name = jmthd->get_name (Histable::SHORT);
|
|
if (strncmp (jmt_name, class_name, len) == 0)
|
|
{
|
|
if (strcmp (jmt_name + len + 1, mname) == 0 &&
|
|
strcmp (jmthd->get_signature (), msign) == 0)
|
|
{
|
|
cur_jmthd = jmthd;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (cur_jmthd == NULL)
|
|
{
|
|
cur_jmthd = dbeSession->createJMethod ();
|
|
cur_jmthd->module = this;
|
|
cur_jmthd->set_signature (dbe_strdup (msign));
|
|
char *nm = dbe_sprintf (NTXT ("%s.%s"), class_name, mname);
|
|
cur_jmthd->set_name (nm);
|
|
free (nm);
|
|
functions->append (cur_jmthd);
|
|
}
|
|
if ((mthd_access_flags & ACC_NATIVE) != 0)
|
|
{
|
|
cur_jmthd->flags |= FUNC_FLAG_NATIVE;
|
|
}
|
|
u2 attributes_count = input->readUnsignedShort ();
|
|
Dprintf (DUMP_JAVA_CLASS,
|
|
NTXT (" %2d: name=%d %-20s flags=%s desc_ind=%d attr_count=%d\n"),
|
|
(int) (i + 1), (int) name_index, STR (bcpool->getString (name_index)),
|
|
access_flags_to_str (MethodAccess, mthd_access_flags),
|
|
(int) descriptor_index, (int) attributes_count);
|
|
readAttributes (attributes_count);
|
|
cur_jmthd->popSrcFile ();
|
|
}
|
|
|
|
// Read global attributes
|
|
u2 global_attributes_count = input->readUnsignedShort ();
|
|
Dprintf (DUMP_JAVA_CLASS, NTXT (" global_attributes_count=%d\n"), global_attributes_count);
|
|
readAttributes (global_attributes_count);
|
|
status = AE_OK;
|
|
}
|
|
catch (DataReadException *ex)
|
|
{
|
|
append_msg (CMSG_ERROR, GTXT ("Cannot read class file %s (%s)"), get_name (), ex->toString ());
|
|
delete ex;
|
|
status = AE_OTHER;
|
|
}
|
|
|
|
char *fnm = NULL;
|
|
if (class_filename)
|
|
{
|
|
if (strcmp (class_filename, get_name ()) != 0)
|
|
set_name (strdup (class_filename));
|
|
if (source_name)
|
|
{
|
|
char *bname = strrchr (class_filename, '/');
|
|
if (bname)
|
|
fnm = dbe_sprintf (NTXT ("%.*s/%s"), (int) (bname - class_filename),
|
|
class_filename, source_name);
|
|
else
|
|
fnm = strdup (source_name);
|
|
}
|
|
else
|
|
fnm = get_java_file_name (class_filename, false);
|
|
}
|
|
else if (source_name)
|
|
fnm = strdup (source_name);
|
|
if (fnm)
|
|
{
|
|
set_file_name (fnm);
|
|
main_source = findSource (file_name, true);
|
|
main_source->dbeFile->filetype |= DbeFile::F_JAVA_SOURCE;
|
|
}
|
|
|
|
for (long i = 0, sz = VecSize (functions); i < sz; i++)
|
|
functions->get (i)->def_source = main_source;
|
|
JMethod *func = NULL;
|
|
for (long i = 0, sz = VecSize (byteCodeInfo); i < sz; i++)
|
|
{
|
|
ByteCodeInfo *p = byteCodeInfo->get (i);
|
|
if (func != p->func)
|
|
{
|
|
if (func)
|
|
func->popSrcFile ();
|
|
func = p->func;
|
|
func->line_first = p->lno;
|
|
func->pushSrcFile (main_source, 0);
|
|
}
|
|
func->line_last = p->lno;
|
|
func->add_PC_info (p->bci, p->lno, main_source);
|
|
}
|
|
if (func)
|
|
func->popSrcFile ();
|
|
Destroy (byteCodeInfo);
|
|
Dprintf (DUMP_JAVA_CLASS, NTXT ("\n status=%d class_filename=%s class_name=%s source_name=%s file_name=%s %s\n"),
|
|
(unsigned int) status, STR (class_filename), STR (class_name),
|
|
STR (source_name), STR (file_name),
|
|
STR (get_name ()));
|
|
return status;
|
|
}
|
|
|
|
#define MAX_CLASS_SIZE 65536
|
|
|
|
char *
|
|
ClassFile::get_disasm (uint64_t inst_address, uint64_t end_address,
|
|
uint64_t start_address, uint64_t f_offset, int64_t &inst_size)
|
|
{
|
|
int64_t offset = f_offset + (inst_address - start_address);
|
|
if ((cf_buf == NULL) || (inst_address >= end_address) || (offset >= cf_bufsz))
|
|
{
|
|
inst_size = 0;
|
|
return NULL;
|
|
}
|
|
|
|
// Check for an implausibly large size
|
|
if ((inst_address - start_address) > MAX_CLASS_SIZE)
|
|
{
|
|
append_msg (CMSG_ERROR, GTXT ("Cannot disassemble class file %s (%s), implausible size = %lld"),
|
|
get_name (), dbeFile->get_location (),
|
|
(end_address - start_address));
|
|
inst_size = 0;
|
|
return NULL;
|
|
}
|
|
|
|
StringBuilder sb;
|
|
DataInputStream *in = new DataInputStream (input);
|
|
try
|
|
{
|
|
in->skip (offset);
|
|
inst_size = printCodeSequence (&sb, inst_address - start_address, in);
|
|
}
|
|
catch (DataReadException *ex)
|
|
{
|
|
append_msg (CMSG_ERROR, GTXT ("Cannot disassemble class file %s (%s) %s"),
|
|
get_name (), dbeFile->get_location (), ex->toString ());
|
|
delete ex;
|
|
inst_size = 0;
|
|
}
|
|
delete in;
|
|
if (inst_size == 0)
|
|
return NULL;
|
|
return sb.toString ();
|
|
}
|
|
|
|
char *
|
|
ClassFile::get_java_file_name (char *clname, bool classSuffix)
|
|
{
|
|
size_t len = strlen (clname);
|
|
if (len > 6 && streq (clname + len - 6, NTXT (".class")))
|
|
len -= 6;
|
|
if (!classSuffix)
|
|
{ // remove $SubClassName from "ClassName$SubClassName"
|
|
char *tmp = strchr (clname, '$');
|
|
if (tmp)
|
|
len = tmp - clname;
|
|
}
|
|
char *clpath = (char *) malloc (len + 10);
|
|
for (size_t i = 0; i < len; i++)
|
|
clpath[i] = (clname[i] == '.') ? '/' : clname[i];
|
|
snprintf (clpath + len, 10, classSuffix ? NTXT (".class") : NTXT (".java"));
|
|
return clpath;
|
|
}
|