/* * Copyright (C) 2008 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. */ /* * Dalvik instruction utility functions. */ #ifndef LIBDEX_INSTRUTILS_H_ #define LIBDEX_INSTRUTILS_H_ #include "DexFile.h" #include "DexOpcodes.h" /* * Possible instruction formats associated with Dalvik opcodes. * * See the file opcode-gen/README.txt for information about updating * opcodes and instruction formats. */ enum InstructionFormat { kFmt00x = 0, // unknown format (also used for "breakpoint" opcode) kFmt10x, // op kFmt12x, // op vA, vB kFmt11n, // op vA, #+B kFmt11x, // op vAA kFmt10t, // op +AA kFmt20bc, // [opt] op AA, thing@BBBB kFmt20t, // op +AAAA kFmt22x, // op vAA, vBBBB kFmt21t, // op vAA, +BBBB kFmt21s, // op vAA, #+BBBB kFmt21h, // op vAA, #+BBBB00000[00000000] kFmt21c, // op vAA, thing@BBBB kFmt23x, // op vAA, vBB, vCC kFmt22b, // op vAA, vBB, #+CC kFmt22t, // op vA, vB, +CCCC kFmt22s, // op vA, vB, #+CCCC kFmt22c, // op vA, vB, thing@CCCC kFmt22cs, // [opt] op vA, vB, field offset CCCC kFmt30t, // op +AAAAAAAA kFmt32x, // op vAAAA, vBBBB kFmt31i, // op vAA, #+BBBBBBBB kFmt31t, // op vAA, +BBBBBBBB kFmt31c, // op vAA, string@BBBBBBBB kFmt35c, // op {vC,vD,vE,vF,vG}, thing@BBBB kFmt35ms, // [opt] invoke-virtual+super kFmt3rc, // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB kFmt3rms, // [opt] invoke-virtual+super/range kFmt51l, // op vAA, #+BBBBBBBBBBBBBBBB kFmt35mi, // [opt] inline invoke kFmt3rmi, // [opt] inline invoke/range kFmt33x, // exop vAA, vBB, vCCCC kFmt32s, // exop vAA, vBB, #+CCCC kFmt40sc, // [opt] exop AAAA, thing@BBBBBBBB kFmt41c, // exop vAAAA, thing@BBBBBBBB kFmt52c, // exop vAAAA, vBBBB, thing@CCCCCCCC kFmt5rc, // exop {vCCCC .. v(CCCC+AAAA-1)}, thing@BBBBBBBB }; /* * Types of indexed reference that are associated with opcodes whose * formats include such an indexed reference (e.g., 21c and 35c). */ enum InstructionIndexType { kIndexUnknown = 0, kIndexNone, // has no index kIndexVaries, // "It depends." Used for throw-verification-error kIndexTypeRef, // type reference index kIndexStringRef, // string reference index kIndexMethodRef, // method reference index kIndexFieldRef, // field reference index kIndexInlineMethod, // inline method index (for inline linked methods) kIndexVtableOffset, // vtable offset (for static linked methods) kIndexFieldOffset // field offset (for static linked fields) }; /* * Instruction width implied by an opcode's format; a value in the * range 0 to 5. Note that there are special "pseudo-instructions" * which are used to encode switch and data tables, and these don't * have a fixed width. See dexGetWidthFromInstruction(), below. */ typedef u1 InstructionWidth; /* * Opcode control flow flags, used by the verifier and JIT. */ typedef u1 OpcodeFlags; enum OpcodeFlagsBits { kInstrCanBranch = 1, // conditional or unconditional branch kInstrCanContinue = 1 << 1, // flow can continue to next statement kInstrCanSwitch = 1 << 2, // switch statement kInstrCanThrow = 1 << 3, // could cause an exception to be thrown kInstrCanReturn = 1 << 4, // returns, no additional statements kInstrInvoke = 1 << 5, // a flavor of invoke }; /* * Struct that includes a pointer to each of the opcode information * tables. * * Note: We use "u1*" here instead of the names of the enumerated * types to guarantee that elements don't use much space. We hold out * hope for a standard way to indicate the size of an enumerated type * that works for both C and C++, but in the mean time, this will * suffice. */ struct InstructionInfoTables { u1* formats; /* InstructionFormat elements */ u1* indexTypes; /* InstructionIndexType elements */ OpcodeFlags* flags; InstructionWidth* widths; }; /* * Global InstructionInfoTables struct. */ extern InstructionInfoTables gDexOpcodeInfo; /* * Holds the contents of a decoded instruction. */ struct DecodedInstruction { u4 vA; u4 vB; u8 vB_wide; /* for kFmt51l */ u4 vC; u4 arg[5]; /* vC/D/E/F/G in invoke or filled-new-array */ Opcode opcode; InstructionIndexType indexType; }; /* * Return the instruction width of the specified opcode, or 0 if not defined. */ DEX_INLINE size_t dexGetWidthFromOpcode(Opcode opcode) { assert((u4) opcode < kNumPackedOpcodes); return gDexOpcodeInfo.widths[opcode]; } /* * Return the width of the specified instruction, or 0 if not defined. Also * works for special OP_NOP entries, including switch statement data tables * and array data. */ size_t dexGetWidthFromInstruction(const u2* insns); /* * Returns the flags for the specified opcode. */ DEX_INLINE OpcodeFlags dexGetFlagsFromOpcode(Opcode opcode) { assert((u4) opcode < kNumPackedOpcodes); return gDexOpcodeInfo.flags[opcode]; } /* * Returns true if the given flags represent a goto (unconditional branch). */ DEX_INLINE bool dexIsGoto(OpcodeFlags flags) { return (flags & (kInstrCanBranch | kInstrCanContinue)) == kInstrCanBranch; } /* * Return the instruction format for the specified opcode. */ DEX_INLINE InstructionFormat dexGetFormatFromOpcode(Opcode opcode) { assert((u4) opcode < kNumPackedOpcodes); return (InstructionFormat) gDexOpcodeInfo.formats[opcode]; } /* * Return the instruction index type for the specified opcode. */ DEX_INLINE InstructionIndexType dexGetIndexTypeFromOpcode(Opcode opcode) { assert((u4) opcode < kNumPackedOpcodes); return (InstructionIndexType) gDexOpcodeInfo.indexTypes[opcode]; } /* * Decode the instruction pointed to by "insns". */ void dexDecodeInstruction(const u2* insns, DecodedInstruction* pDec); #endif // LIBDEX_INSTRUTILS_H_