| /* Copyright (C) 2021-2024 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; | |
| } | |
| dbe_stat_t 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 (), | |
| (long long) (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; | |
| } |