You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
520 lines
16 KiB
520 lines
16 KiB
// 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
|