/*
* 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_