// Copyright (C) 2017 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #include "instruction_decoder.h" #include "dex/dex_instruction_list.h" #include namespace titrace { class ClassInstructionDecoder : public InstructionDecoder { public: size_t GetMaximumOpcode() override { return 0xff; } const char* GetName(size_t opcode) override { Bytecode::Opcode op = static_cast(opcode); return Bytecode::ToString(op); } size_t LocationToOffset(size_t j_location) override { return j_location; } private: class Bytecode { public: enum Opcode { // Java bytecode opcodes from 0x00 to 0xFF. kNop = 0x00, kAconst_null = 0x01, kIconst_m1 = 0x02, kIconst_0 = 0x03, kIconst_1 = 0x04, kIconst_2 = 0x05, kIconst_3 = 0x06, kIconst_4 = 0x07, kIconst_5 = 0x08, kLconst_0 = 0x09, kLconst_1 = 0x0a, kFconst_0 = 0x0b, kFconst_1 = 0x0c, kFconst_2 = 0x0d, kDconst_0 = 0x0e, kDconst_1 = 0x0f, kBipush = 0x10, kSipush = 0x11, kLdc = 0x12, kLdc_w = 0x13, kLdc2_w = 0x14, kIload = 0x15, kLload = 0x16, kFload = 0x17, kDload = 0x18, kAload = 0x19, kIload_0 = 0x1a, kIload_1 = 0x1b, kIload_2 = 0x1c, kIload_3 = 0x1d, kLload_0 = 0x1e, kLload_1 = 0x1f, kLload_2 = 0x20, kLload_3 = 0x21, kFload_0 = 0x22, kFload_1 = 0x23, kFload_2 = 0x24, kFload_3 = 0x25, kDload_0 = 0x26, kDload_1 = 0x27, kDload_2 = 0x28, kDload_3 = 0x29, kAload_0 = 0x2a, kAload_1 = 0x2b, kAload_2 = 0x2c, kAload_3 = 0x2d, kIaload = 0x2e, kLaload = 0x2f, kFaload = 0x30, kDaload = 0x31, kAaload = 0x32, kBaload = 0x33, kCaload = 0x34, kSaload = 0x35, kIstore = 0x36, kLstore = 0x37, kFstore = 0x38, kDstore = 0x39, kAstore = 0x3a, kIstore_0 = 0x3b, kIstore_1 = 0x3c, kIstore_2 = 0x3d, kIstore_3 = 0x3e, kLstore_0 = 0x3f, kLstore_1 = 0x40, kLstore_2 = 0x41, kLstore_3 = 0x42, kFstore_0 = 0x43, kFstore_1 = 0x44, kFstore_2 = 0x45, kFstore_3 = 0x46, kDstore_0 = 0x47, kDstore_1 = 0x48, kDstore_2 = 0x49, kDstore_3 = 0x4a, kAstore_0 = 0x4b, kAstore_1 = 0x4c, kAstore_2 = 0x4d, kAstore_3 = 0x4e, kIastore = 0x4f, kLastore = 0x50, kFastore = 0x51, kDastore = 0x52, kAastore = 0x53, kBastore = 0x54, kCastore = 0x55, kSastore = 0x56, kPop = 0x57, kPop2 = 0x58, kDup = 0x59, kDup_x1 = 0x5a, kDup_x2 = 0x5b, kDup2 = 0x5c, kDup2_x1 = 0x5d, kDup2_x2 = 0x5e, kSwap = 0x5f, kIadd = 0x60, kLadd = 0x61, kFadd = 0x62, kDadd = 0x63, kIsub = 0x64, kLsub = 0x65, kFsub = 0x66, kDsub = 0x67, kImul = 0x68, kLmul = 0x69, kFmul = 0x6a, kDmul = 0x6b, kIdiv = 0x6c, kLdiv = 0x6d, kFdiv = 0x6e, kDdiv = 0x6f, kIrem = 0x70, kLrem = 0x71, kFrem = 0x72, kDrem = 0x73, kIneg = 0x74, kLneg = 0x75, kFneg = 0x76, kDneg = 0x77, kIshl = 0x78, kLshl = 0x79, kIshr = 0x7a, kLshr = 0x7b, kIushr = 0x7c, kLushr = 0x7d, kIand = 0x7e, kLand = 0x7f, kIor = 0x80, kLor = 0x81, kIxor = 0x82, kLxor = 0x83, kIinc = 0x84, kI2l = 0x85, kI2f = 0x86, kI2d = 0x87, kL2i = 0x88, kL2f = 0x89, kL2d = 0x8a, kF2i = 0x8b, kF2l = 0x8c, kF2d = 0x8d, kD2i = 0x8e, kD2l = 0x8f, kD2f = 0x90, kI2b = 0x91, kI2c = 0x92, kI2s = 0x93, kLcmp = 0x94, kFcmpl = 0x95, kFcmpg = 0x96, kDcmpl = 0x97, kDcmpg = 0x98, kIfeq = 0x99, kIfne = 0x9a, kIflt = 0x9b, kIfge = 0x9c, kIfgt = 0x9d, kIfle = 0x9e, kIf_icmpeq = 0x9f, kIf_icmpne = 0xa0, kIf_icmplt = 0xa1, kIf_icmpge = 0xa2, kIf_icmpgt = 0xa3, kIf_icmple = 0xa4, kIf_acmpeq = 0xa5, kIf_acmpne = 0xa6, kGoto = 0xa7, kJsr = 0xa8, kRet = 0xa9, kTableswitch = 0xaa, kLookupswitch = 0xab, kIreturn = 0xac, kLreturn = 0xad, kFreturn = 0xae, kDreturn = 0xaf, kAreturn = 0xb0, kReturn = 0xb1, kGetstatic = 0xb2, kPutstatic = 0xb3, kGetfield = 0xb4, kPutfield = 0xb5, kInvokevirtual = 0xb6, kInvokespecial = 0xb7, kInvokestatic = 0xb8, kInvokeinterface = 0xb9, kInvokedynamic = 0xba, kNew = 0xbb, kNewarray = 0xbc, kAnewarray = 0xbd, kArraylength = 0xbe, kAthrow = 0xbf, kCheckcast = 0xc0, kInstanceof = 0xc1, kMonitorenter = 0xc2, kMonitorexit = 0xc3, kWide = 0xc4, kMultianewarray = 0xc5, kIfnull = 0xc6, kIfnonnull = 0xc7, kGoto_w = 0xc8, kJsr_w = 0xc9, kBreakpoint = 0xca, // Instructions 0xcb-0xfd are undefined. kImpdep1 = 0xfe, kImpdep2 = 0xff, }; static const char* ToString(Bytecode::Opcode op) { switch (op) { case kNop: return "nop"; case kAconst_null: return "aconst_null"; case kIconst_m1: return "iconst_m1"; case kIconst_0: return "iconst_0"; case kIconst_1: return "iconst_1"; case kIconst_2: return "iconst_2"; case kIconst_3: return "iconst_3"; case kIconst_4: return "iconst_4"; case kIconst_5: return "iconst_5"; case kLconst_0: return "lconst_0"; case kLconst_1: return "lconst_1"; case kFconst_0: return "fconst_0"; case kFconst_1: return "fconst_1"; case kFconst_2: return "fconst_2"; case kDconst_0: return "dconst_0"; case kDconst_1: return "dconst_1"; case kBipush: return "bipush"; case kSipush: return "sipush"; case kLdc: return "ldc"; case kLdc_w: return "ldc_w"; case kLdc2_w: return "ldc2_w"; case kIload: return "iload"; case kLload: return "lload"; case kFload: return "fload"; case kDload: return "dload"; case kAload: return "aload"; case kIload_0: return "iload_0"; case kIload_1: return "iload_1"; case kIload_2: return "iload_2"; case kIload_3: return "iload_3"; case kLload_0: return "lload_0"; case kLload_1: return "lload_1"; case kLload_2: return "lload_2"; case kLload_3: return "lload_3"; case kFload_0: return "fload_0"; case kFload_1: return "fload_1"; case kFload_2: return "fload_2"; case kFload_3: return "fload_3"; case kDload_0: return "dload_0"; case kDload_1: return "dload_1"; case kDload_2: return "dload_2"; case kDload_3: return "dload_3"; case kAload_0: return "aload_0"; case kAload_1: return "aload_1"; case kAload_2: return "aload_2"; case kAload_3: return "aload_3"; case kIaload: return "iaload"; case kLaload: return "laload"; case kFaload: return "faload"; case kDaload: return "daload"; case kAaload: return "aaload"; case kBaload: return "baload"; case kCaload: return "caload"; case kSaload: return "saload"; case kIstore: return "istore"; case kLstore: return "lstore"; case kFstore: return "fstore"; case kDstore: return "dstore"; case kAstore: return "astore"; case kIstore_0: return "istore_0"; case kIstore_1: return "istore_1"; case kIstore_2: return "istore_2"; case kIstore_3: return "istore_3"; case kLstore_0: return "lstore_0"; case kLstore_1: return "lstore_1"; case kLstore_2: return "lstore_2"; case kLstore_3: return "lstore_3"; case kFstore_0: return "fstore_0"; case kFstore_1: return "fstore_1"; case kFstore_2: return "fstore_2"; case kFstore_3: return "fstore_3"; case kDstore_0: return "dstore_0"; case kDstore_1: return "dstore_1"; case kDstore_2: return "dstore_2"; case kDstore_3: return "dstore_3"; case kAstore_0: return "astore_0"; case kAstore_1: return "astore_1"; case kAstore_2: return "astore_2"; case kAstore_3: return "astore_3"; case kIastore: return "iastore"; case kLastore: return "lastore"; case kFastore: return "fastore"; case kDastore: return "dastore"; case kAastore: return "aastore"; case kBastore: return "bastore"; case kCastore: return "castore"; case kSastore: return "sastore"; case kPop: return "pop"; case kPop2: return "pop2"; case kDup: return "dup"; case kDup_x1: return "dup_x1"; case kDup_x2: return "dup_x2"; case kDup2: return "dup2"; case kDup2_x1: return "dup2_x1"; case kDup2_x2: return "dup2_x2"; case kSwap: return "swap"; case kIadd: return "iadd"; case kLadd: return "ladd"; case kFadd: return "fadd"; case kDadd: return "dadd"; case kIsub: return "isub"; case kLsub: return "lsub"; case kFsub: return "fsub"; case kDsub: return "dsub"; case kImul: return "imul"; case kLmul: return "lmul"; case kFmul: return "fmul"; case kDmul: return "dmul"; case kIdiv: return "idiv"; case kLdiv: return "ldiv"; case kFdiv: return "fdiv"; case kDdiv: return "ddiv"; case kIrem: return "irem"; case kLrem: return "lrem"; case kFrem: return "frem"; case kDrem: return "drem"; case kIneg: return "ineg"; case kLneg: return "lneg"; case kFneg: return "fneg"; case kDneg: return "dneg"; case kIshl: return "ishl"; case kLshl: return "lshl"; case kIshr: return "ishr"; case kLshr: return "lshr"; case kIushr: return "iushr"; case kLushr: return "lushr"; case kIand: return "iand"; case kLand: return "land"; case kIor: return "ior"; case kLor: return "lor"; case kIxor: return "ixor"; case kLxor: return "lxor"; case kIinc: return "iinc"; case kI2l: return "i2l"; case kI2f: return "i2f"; case kI2d: return "i2d"; case kL2i: return "l2i"; case kL2f: return "l2f"; case kL2d: return "l2d"; case kF2i: return "f2i"; case kF2l: return "f2l"; case kF2d: return "f2d"; case kD2i: return "d2i"; case kD2l: return "d2l"; case kD2f: return "d2f"; case kI2b: return "i2b"; case kI2c: return "i2c"; case kI2s: return "i2s"; case kLcmp: return "lcmp"; case kFcmpl: return "fcmpl"; case kFcmpg: return "fcmpg"; case kDcmpl: return "dcmpl"; case kDcmpg: return "dcmpg"; case kIfeq: return "ifeq"; case kIfne: return "ifne"; case kIflt: return "iflt"; case kIfge: return "ifge"; case kIfgt: return "ifgt"; case kIfle: return "ifle"; case kIf_icmpeq: return "if_icmpeq"; case kIf_icmpne: return "if_icmpne"; case kIf_icmplt: return "if_icmplt"; case kIf_icmpge: return "if_icmpge"; case kIf_icmpgt: return "if_icmpgt"; case kIf_icmple: return "if_icmple"; case kIf_acmpeq: return "if_acmpeq"; case kIf_acmpne: return "if_acmpne"; case kGoto: return "goto"; case kJsr: return "jsr"; case kRet: return "ret"; case kTableswitch: return "tableswitch"; case kLookupswitch: return "lookupswitch"; case kIreturn: return "ireturn"; case kLreturn: return "lreturn"; case kFreturn: return "freturn"; case kDreturn: return "dreturn"; case kAreturn: return "areturn"; case kReturn: return "return"; case kGetstatic: return "getstatic"; case kPutstatic: return "putstatic"; case kGetfield: return "getfield"; case kPutfield: return "putfield"; case kInvokevirtual: return "invokevirtual"; case kInvokespecial: return "invokespecial"; case kInvokestatic: return "invokestatic"; case kInvokeinterface: return "invokeinterface"; case kInvokedynamic: return "invokedynamic"; case kNew: return "new"; case kNewarray: return "newarray"; case kAnewarray: return "anewarray"; case kArraylength: return "arraylength"; case kAthrow: return "athrow"; case kCheckcast: return "checkcast"; case kInstanceof: return "instanceof"; case kMonitorenter: return "monitorenter"; case kMonitorexit: return "monitorexit"; case kWide: return "wide"; case kMultianewarray: return "multianewarray"; case kIfnull: return "ifnull"; case kIfnonnull: return "ifnonnull"; case kGoto_w: return "goto_w"; case kJsr_w: return "jsr_w"; case kBreakpoint: return "breakpoint"; case kImpdep1: return "impdep1"; case kImpdep2: return "impdep2"; default: LOG(FATAL) << "Unknown opcode " << op; __builtin_unreachable(); } } }; }; class DexInstructionDecoder : public InstructionDecoder { public: size_t GetMaximumOpcode() override { return 0xff; } const char* GetName(size_t opcode) override { Bytecode::Opcode op = static_cast(opcode); return Bytecode::ToString(op); } size_t LocationToOffset(size_t j_location) override { // dex pc is uint16_t*, but offset needs to be in bytes. return j_location * (sizeof(uint16_t) / sizeof(uint8_t)); } private: class Bytecode { public: enum Opcode { #define MAKE_ENUM_DEFINITION(opcode, instruction_code, name, format, index, flags, extended_flags, verifier_flags) \ instruction_code = opcode, /* NOLINT */ DEX_INSTRUCTION_LIST(MAKE_ENUM_DEFINITION) #undef MAKE_ENUM_DEFINITION }; static_assert(static_cast(Bytecode::Opcode::NOP) == 0, ""); static_assert(static_cast(Bytecode::Opcode::MOVE) == 1, ""); static const char* ToString(Bytecode::Opcode op) { switch (op) { #define MAKE_ENUM_DEFINITION(opcode, instruction_code, name, format, index, flags, extended_flags, verifier_flags) \ case instruction_code: return (name); DEX_INSTRUCTION_LIST(MAKE_ENUM_DEFINITION) #undef MAKE_ENUM_DEFINITION default: LOG(FATAL) << "Unknown opcode " << op; } __builtin_unreachable(); } }; }; InstructionDecoder* InstructionDecoder::NewInstance(InstructionFileFormat file_format) { switch (file_format) { case InstructionFileFormat::kClass: return new ClassInstructionDecoder(); case InstructionFileFormat::kDex: return new DexInstructionDecoder(); default: return nullptr; } } } // namespace titrace