blob: 6f497b3c0417b4142ad3771d96575ca031121a56 [file] [log] [blame]
// 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 <android-base/logging.h>
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<Bytecode::Opcode>(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<Bytecode::Opcode>(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<uint32_t>(Bytecode::Opcode::NOP) == 0, "");
static_assert(static_cast<uint32_t>(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