blob: e98de91fef1a80bd4a39a0b53cbbdd9214522c2e [file] [log] [blame]
/*
* 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.
*/
#include "InstrUtils.h"
#include <stdlib.h>
/*
* Generate a table that holds the width of all instructions.
*
* Unimplemented instructions have a width of zero.
*
* I'm doing it with a giant switch statement because it's easier to
* maintain and update than a static table with 256 unadorned integers,
* and if we're missing a case gcc emits a "warning: enumeration value not
* handled" message.
*
* (To save space in the binary we could generate a static table with a
* command-line utility.)
*/
InstructionWidth* dexCreateInstrWidthTable(void)
{
#ifdef __ARM_ARCH_7A__
/* hack to work around mysterious problem on emulator */
LOGD("creating instr width table\n");
#endif
InstructionWidth* instrWidth;
int i;
instrWidth = malloc(sizeof(InstructionWidth) * kNumDalvikInstructions);
if (instrWidth == NULL)
return NULL;
for (i = 0; i < kNumDalvikInstructions; i++) {
OpCode opc = (OpCode) i;
int width = 0;
switch (opc) {
case OP_NOP: /* note data for e.g. switch-* encoded "inside" a NOP */
case OP_MOVE:
case OP_MOVE_WIDE:
case OP_MOVE_OBJECT:
case OP_MOVE_RESULT:
case OP_MOVE_RESULT_WIDE:
case OP_MOVE_RESULT_OBJECT:
case OP_MOVE_EXCEPTION:
case OP_RETURN_VOID:
case OP_RETURN:
case OP_RETURN_WIDE:
case OP_RETURN_OBJECT:
case OP_CONST_4:
case OP_MONITOR_ENTER:
case OP_MONITOR_EXIT:
case OP_ARRAY_LENGTH:
case OP_THROW:
case OP_GOTO:
case OP_NEG_INT:
case OP_NOT_INT:
case OP_NEG_LONG:
case OP_NOT_LONG:
case OP_NEG_FLOAT:
case OP_NEG_DOUBLE:
case OP_INT_TO_LONG:
case OP_INT_TO_FLOAT:
case OP_INT_TO_DOUBLE:
case OP_LONG_TO_INT:
case OP_LONG_TO_FLOAT:
case OP_LONG_TO_DOUBLE:
case OP_FLOAT_TO_INT:
case OP_FLOAT_TO_LONG:
case OP_FLOAT_TO_DOUBLE:
case OP_DOUBLE_TO_INT:
case OP_DOUBLE_TO_LONG:
case OP_DOUBLE_TO_FLOAT:
case OP_INT_TO_BYTE:
case OP_INT_TO_CHAR:
case OP_INT_TO_SHORT:
case OP_ADD_INT_2ADDR:
case OP_SUB_INT_2ADDR:
case OP_MUL_INT_2ADDR:
case OP_DIV_INT_2ADDR:
case OP_REM_INT_2ADDR:
case OP_AND_INT_2ADDR:
case OP_OR_INT_2ADDR:
case OP_XOR_INT_2ADDR:
case OP_SHL_INT_2ADDR:
case OP_SHR_INT_2ADDR:
case OP_USHR_INT_2ADDR:
case OP_ADD_LONG_2ADDR:
case OP_SUB_LONG_2ADDR:
case OP_MUL_LONG_2ADDR:
case OP_DIV_LONG_2ADDR:
case OP_REM_LONG_2ADDR:
case OP_AND_LONG_2ADDR:
case OP_OR_LONG_2ADDR:
case OP_XOR_LONG_2ADDR:
case OP_SHL_LONG_2ADDR:
case OP_SHR_LONG_2ADDR:
case OP_USHR_LONG_2ADDR:
case OP_ADD_FLOAT_2ADDR:
case OP_SUB_FLOAT_2ADDR:
case OP_MUL_FLOAT_2ADDR:
case OP_DIV_FLOAT_2ADDR:
case OP_REM_FLOAT_2ADDR:
case OP_ADD_DOUBLE_2ADDR:
case OP_SUB_DOUBLE_2ADDR:
case OP_MUL_DOUBLE_2ADDR:
case OP_DIV_DOUBLE_2ADDR:
case OP_REM_DOUBLE_2ADDR:
width = 1;
break;
case OP_MOVE_FROM16:
case OP_MOVE_WIDE_FROM16:
case OP_MOVE_OBJECT_FROM16:
case OP_CONST_16:
case OP_CONST_HIGH16:
case OP_CONST_WIDE_16:
case OP_CONST_WIDE_HIGH16:
case OP_CONST_STRING:
case OP_CONST_CLASS:
case OP_CHECK_CAST:
case OP_INSTANCE_OF:
case OP_NEW_INSTANCE:
case OP_NEW_ARRAY:
case OP_CMPL_FLOAT:
case OP_CMPG_FLOAT:
case OP_CMPL_DOUBLE:
case OP_CMPG_DOUBLE:
case OP_CMP_LONG:
case OP_GOTO_16:
case OP_IF_EQ:
case OP_IF_NE:
case OP_IF_LT:
case OP_IF_GE:
case OP_IF_GT:
case OP_IF_LE:
case OP_IF_EQZ:
case OP_IF_NEZ:
case OP_IF_LTZ:
case OP_IF_GEZ:
case OP_IF_GTZ:
case OP_IF_LEZ:
case OP_AGET:
case OP_AGET_WIDE:
case OP_AGET_OBJECT:
case OP_AGET_BOOLEAN:
case OP_AGET_BYTE:
case OP_AGET_CHAR:
case OP_AGET_SHORT:
case OP_APUT:
case OP_APUT_WIDE:
case OP_APUT_OBJECT:
case OP_APUT_BOOLEAN:
case OP_APUT_BYTE:
case OP_APUT_CHAR:
case OP_APUT_SHORT:
case OP_IGET:
case OP_IGET_WIDE:
case OP_IGET_OBJECT:
case OP_IGET_BOOLEAN:
case OP_IGET_BYTE:
case OP_IGET_CHAR:
case OP_IGET_SHORT:
case OP_IPUT:
case OP_IPUT_WIDE:
case OP_IPUT_OBJECT:
case OP_IPUT_BOOLEAN:
case OP_IPUT_BYTE:
case OP_IPUT_CHAR:
case OP_IPUT_SHORT:
case OP_SGET:
case OP_SGET_WIDE:
case OP_SGET_OBJECT:
case OP_SGET_BOOLEAN:
case OP_SGET_BYTE:
case OP_SGET_CHAR:
case OP_SGET_SHORT:
case OP_SPUT:
case OP_SPUT_WIDE:
case OP_SPUT_OBJECT:
case OP_SPUT_BOOLEAN:
case OP_SPUT_BYTE:
case OP_SPUT_CHAR:
case OP_SPUT_SHORT:
case OP_ADD_INT:
case OP_SUB_INT:
case OP_MUL_INT:
case OP_DIV_INT:
case OP_REM_INT:
case OP_AND_INT:
case OP_OR_INT:
case OP_XOR_INT:
case OP_SHL_INT:
case OP_SHR_INT:
case OP_USHR_INT:
case OP_ADD_LONG:
case OP_SUB_LONG:
case OP_MUL_LONG:
case OP_DIV_LONG:
case OP_REM_LONG:
case OP_AND_LONG:
case OP_OR_LONG:
case OP_XOR_LONG:
case OP_SHL_LONG:
case OP_SHR_LONG:
case OP_USHR_LONG:
case OP_ADD_FLOAT:
case OP_SUB_FLOAT:
case OP_MUL_FLOAT:
case OP_DIV_FLOAT:
case OP_REM_FLOAT:
case OP_ADD_DOUBLE:
case OP_SUB_DOUBLE:
case OP_MUL_DOUBLE:
case OP_DIV_DOUBLE:
case OP_REM_DOUBLE:
case OP_ADD_INT_LIT16:
case OP_RSUB_INT:
case OP_MUL_INT_LIT16:
case OP_DIV_INT_LIT16:
case OP_REM_INT_LIT16:
case OP_AND_INT_LIT16:
case OP_OR_INT_LIT16:
case OP_XOR_INT_LIT16:
case OP_ADD_INT_LIT8:
case OP_RSUB_INT_LIT8:
case OP_MUL_INT_LIT8:
case OP_DIV_INT_LIT8:
case OP_REM_INT_LIT8:
case OP_AND_INT_LIT8:
case OP_OR_INT_LIT8:
case OP_XOR_INT_LIT8:
case OP_SHL_INT_LIT8:
case OP_SHR_INT_LIT8:
case OP_USHR_INT_LIT8:
width = 2;
break;
case OP_MOVE_16:
case OP_MOVE_WIDE_16:
case OP_MOVE_OBJECT_16:
case OP_CONST:
case OP_CONST_WIDE_32:
case OP_CONST_STRING_JUMBO:
case OP_GOTO_32:
case OP_FILLED_NEW_ARRAY:
case OP_FILLED_NEW_ARRAY_RANGE:
case OP_FILL_ARRAY_DATA:
case OP_PACKED_SWITCH:
case OP_SPARSE_SWITCH:
case OP_INVOKE_VIRTUAL:
case OP_INVOKE_SUPER:
case OP_INVOKE_DIRECT:
case OP_INVOKE_STATIC:
case OP_INVOKE_INTERFACE:
case OP_INVOKE_VIRTUAL_RANGE:
case OP_INVOKE_SUPER_RANGE:
case OP_INVOKE_DIRECT_RANGE:
case OP_INVOKE_STATIC_RANGE:
case OP_INVOKE_INTERFACE_RANGE:
width = 3;
break;
case OP_CONST_WIDE:
width = 5;
break;
/*
* Optimized instructions.
*/
case OP_RETURN_VOID_BARRIER:
width = 1;
break;
case OP_IGET_QUICK:
case OP_IGET_WIDE_QUICK:
case OP_IGET_OBJECT_QUICK:
case OP_IPUT_QUICK:
case OP_IPUT_WIDE_QUICK:
case OP_IPUT_OBJECT_QUICK:
case OP_IGET_VOLATILE:
case OP_IPUT_VOLATILE:
case OP_SGET_VOLATILE:
case OP_SPUT_VOLATILE:
case OP_IGET_OBJECT_VOLATILE:
case OP_IPUT_OBJECT_VOLATILE:
case OP_SGET_OBJECT_VOLATILE:
case OP_SPUT_OBJECT_VOLATILE:
case OP_IGET_WIDE_VOLATILE:
case OP_IPUT_WIDE_VOLATILE:
case OP_SGET_WIDE_VOLATILE:
case OP_SPUT_WIDE_VOLATILE:
case OP_THROW_VERIFICATION_ERROR:
width = 2;
break;
case OP_INVOKE_VIRTUAL_QUICK:
case OP_INVOKE_VIRTUAL_QUICK_RANGE:
case OP_INVOKE_SUPER_QUICK:
case OP_INVOKE_SUPER_QUICK_RANGE:
case OP_EXECUTE_INLINE:
case OP_EXECUTE_INLINE_RANGE:
case OP_INVOKE_DIRECT_EMPTY:
width = 3;
break;
/* these should never appear when scanning bytecode */
case OP_UNUSED_3E:
case OP_UNUSED_3F:
case OP_UNUSED_40:
case OP_UNUSED_41:
case OP_UNUSED_42:
case OP_UNUSED_43:
case OP_UNUSED_73:
case OP_UNUSED_79:
case OP_UNUSED_7A:
case OP_BREAKPOINT:
case OP_UNUSED_FF:
assert(width == 0);
break;
/*
* DO NOT add a "default" clause here. Without it the compiler will
* complain if an instruction is missing (which is desirable).
*/
}
instrWidth[opc] = width;
}
return instrWidth;
}
/*
* Generate a table that holds instruction flags.
*/
InstructionFlags* dexCreateInstrFlagsTable(void)
{
InstructionFlags* instrFlags;
int i;
instrFlags = malloc(sizeof(InstructionFlags) * kNumDalvikInstructions);
if (instrFlags == NULL)
return NULL;
for (i = 0; i < kNumDalvikInstructions; i++) {
OpCode opc = (OpCode) i;
InstructionFlags flags = 0;
switch (opc) {
/* these don't affect the PC and can't cause an exception */
case OP_NOP:
case OP_MOVE:
case OP_MOVE_FROM16:
case OP_MOVE_16:
case OP_MOVE_WIDE:
case OP_MOVE_WIDE_FROM16:
case OP_MOVE_WIDE_16:
case OP_MOVE_OBJECT:
case OP_MOVE_OBJECT_FROM16:
case OP_MOVE_OBJECT_16:
case OP_MOVE_RESULT:
case OP_MOVE_RESULT_WIDE:
case OP_MOVE_RESULT_OBJECT:
case OP_MOVE_EXCEPTION:
case OP_CONST_4:
case OP_CONST_16:
case OP_CONST:
case OP_CONST_HIGH16:
case OP_CONST_WIDE_16:
case OP_CONST_WIDE_32:
case OP_CONST_WIDE:
case OP_CONST_WIDE_HIGH16:
case OP_FILL_ARRAY_DATA:
case OP_CMPL_FLOAT:
case OP_CMPG_FLOAT:
case OP_CMPL_DOUBLE:
case OP_CMPG_DOUBLE:
case OP_CMP_LONG:
case OP_NEG_INT:
case OP_NOT_INT:
case OP_NEG_LONG:
case OP_NOT_LONG:
case OP_NEG_FLOAT:
case OP_NEG_DOUBLE:
case OP_INT_TO_LONG:
case OP_INT_TO_FLOAT:
case OP_INT_TO_DOUBLE:
case OP_LONG_TO_INT:
case OP_LONG_TO_FLOAT:
case OP_LONG_TO_DOUBLE:
case OP_FLOAT_TO_INT:
case OP_FLOAT_TO_LONG:
case OP_FLOAT_TO_DOUBLE:
case OP_DOUBLE_TO_INT:
case OP_DOUBLE_TO_LONG:
case OP_DOUBLE_TO_FLOAT:
case OP_INT_TO_BYTE:
case OP_INT_TO_CHAR:
case OP_INT_TO_SHORT:
case OP_ADD_INT:
case OP_SUB_INT:
case OP_MUL_INT:
case OP_AND_INT:
case OP_OR_INT:
case OP_XOR_INT:
case OP_SHL_INT:
case OP_SHR_INT:
case OP_USHR_INT:
case OP_ADD_LONG:
case OP_SUB_LONG:
case OP_MUL_LONG:
case OP_AND_LONG:
case OP_OR_LONG:
case OP_XOR_LONG:
case OP_SHL_LONG:
case OP_SHR_LONG:
case OP_USHR_LONG:
case OP_ADD_FLOAT:
case OP_SUB_FLOAT:
case OP_MUL_FLOAT:
case OP_DIV_FLOAT:
case OP_REM_FLOAT:
case OP_ADD_DOUBLE:
case OP_SUB_DOUBLE:
case OP_MUL_DOUBLE:
case OP_DIV_DOUBLE: // div by zero just returns NaN
case OP_REM_DOUBLE:
case OP_ADD_INT_2ADDR:
case OP_SUB_INT_2ADDR:
case OP_MUL_INT_2ADDR:
case OP_AND_INT_2ADDR:
case OP_OR_INT_2ADDR:
case OP_XOR_INT_2ADDR:
case OP_SHL_INT_2ADDR:
case OP_SHR_INT_2ADDR:
case OP_USHR_INT_2ADDR:
case OP_ADD_LONG_2ADDR:
case OP_SUB_LONG_2ADDR:
case OP_MUL_LONG_2ADDR:
case OP_AND_LONG_2ADDR:
case OP_OR_LONG_2ADDR:
case OP_XOR_LONG_2ADDR:
case OP_SHL_LONG_2ADDR:
case OP_SHR_LONG_2ADDR:
case OP_USHR_LONG_2ADDR:
case OP_ADD_FLOAT_2ADDR:
case OP_SUB_FLOAT_2ADDR:
case OP_MUL_FLOAT_2ADDR:
case OP_DIV_FLOAT_2ADDR:
case OP_REM_FLOAT_2ADDR:
case OP_ADD_DOUBLE_2ADDR:
case OP_SUB_DOUBLE_2ADDR:
case OP_MUL_DOUBLE_2ADDR:
case OP_DIV_DOUBLE_2ADDR:
case OP_REM_DOUBLE_2ADDR:
case OP_ADD_INT_LIT16:
case OP_RSUB_INT:
case OP_MUL_INT_LIT16:
case OP_AND_INT_LIT16:
case OP_OR_INT_LIT16:
case OP_XOR_INT_LIT16:
case OP_ADD_INT_LIT8:
case OP_RSUB_INT_LIT8:
case OP_MUL_INT_LIT8:
case OP_AND_INT_LIT8:
case OP_OR_INT_LIT8:
case OP_XOR_INT_LIT8:
case OP_SHL_INT_LIT8:
case OP_SHR_INT_LIT8:
case OP_USHR_INT_LIT8:
flags = kInstrCanContinue;
break;
/* these don't affect the PC, but can cause exceptions */
case OP_CONST_STRING:
case OP_CONST_STRING_JUMBO:
case OP_CONST_CLASS:
case OP_MONITOR_ENTER:
case OP_MONITOR_EXIT:
case OP_CHECK_CAST:
case OP_INSTANCE_OF:
case OP_ARRAY_LENGTH:
case OP_NEW_INSTANCE:
case OP_NEW_ARRAY:
case OP_FILLED_NEW_ARRAY:
case OP_FILLED_NEW_ARRAY_RANGE:
case OP_AGET:
case OP_AGET_BOOLEAN:
case OP_AGET_BYTE:
case OP_AGET_CHAR:
case OP_AGET_SHORT:
case OP_AGET_WIDE:
case OP_AGET_OBJECT:
case OP_APUT:
case OP_APUT_BOOLEAN:
case OP_APUT_BYTE:
case OP_APUT_CHAR:
case OP_APUT_SHORT:
case OP_APUT_WIDE:
case OP_APUT_OBJECT:
case OP_IGET:
case OP_IGET_BOOLEAN:
case OP_IGET_BYTE:
case OP_IGET_CHAR:
case OP_IGET_SHORT:
case OP_IGET_WIDE:
case OP_IGET_OBJECT:
case OP_IPUT:
case OP_IPUT_BOOLEAN:
case OP_IPUT_BYTE:
case OP_IPUT_CHAR:
case OP_IPUT_SHORT:
case OP_IPUT_WIDE:
case OP_IPUT_OBJECT:
case OP_SGET:
case OP_SGET_BOOLEAN:
case OP_SGET_BYTE:
case OP_SGET_CHAR:
case OP_SGET_SHORT:
case OP_SGET_WIDE:
case OP_SGET_OBJECT:
case OP_SPUT:
case OP_SPUT_BOOLEAN:
case OP_SPUT_BYTE:
case OP_SPUT_CHAR:
case OP_SPUT_SHORT:
case OP_SPUT_WIDE:
case OP_SPUT_OBJECT:
case OP_DIV_INT:
case OP_REM_INT:
case OP_DIV_LONG:
case OP_REM_LONG:
case OP_DIV_INT_2ADDR:
case OP_REM_INT_2ADDR:
case OP_DIV_LONG_2ADDR:
case OP_REM_LONG_2ADDR:
case OP_DIV_INT_LIT16:
case OP_REM_INT_LIT16:
case OP_DIV_INT_LIT8:
case OP_REM_INT_LIT8:
flags = kInstrCanContinue | kInstrCanThrow;
break;
case OP_INVOKE_VIRTUAL:
case OP_INVOKE_VIRTUAL_RANGE:
case OP_INVOKE_SUPER:
case OP_INVOKE_SUPER_RANGE:
case OP_INVOKE_DIRECT:
case OP_INVOKE_DIRECT_RANGE:
case OP_INVOKE_STATIC:
case OP_INVOKE_STATIC_RANGE:
case OP_INVOKE_INTERFACE:
case OP_INVOKE_INTERFACE_RANGE:
flags = kInstrCanContinue | kInstrCanThrow | kInstrInvoke;
break;
case OP_RETURN_VOID:
case OP_RETURN:
case OP_RETURN_WIDE:
case OP_RETURN_OBJECT:
flags = kInstrCanReturn;
break;
case OP_THROW:
flags = kInstrCanThrow;
break;
/* unconditional branches */
case OP_GOTO:
case OP_GOTO_16:
case OP_GOTO_32:
flags = kInstrCanBranch | kInstrUnconditional;
break;
/* conditional branches */
case OP_IF_EQ:
case OP_IF_NE:
case OP_IF_LT:
case OP_IF_GE:
case OP_IF_GT:
case OP_IF_LE:
case OP_IF_EQZ:
case OP_IF_NEZ:
case OP_IF_LTZ:
case OP_IF_GEZ:
case OP_IF_GTZ:
case OP_IF_LEZ:
flags = kInstrCanBranch | kInstrCanContinue;
break;
/* switch statements; if value not in switch, it continues */
case OP_PACKED_SWITCH:
case OP_SPARSE_SWITCH:
flags = kInstrCanSwitch | kInstrCanContinue;
break;
/* verifier/optimizer-generated instructions */
case OP_THROW_VERIFICATION_ERROR:
flags = kInstrCanThrow;
break;
case OP_EXECUTE_INLINE:
case OP_EXECUTE_INLINE_RANGE:
flags = kInstrCanContinue | kInstrCanThrow;
break;
case OP_IGET_QUICK:
case OP_IGET_WIDE_QUICK:
case OP_IGET_OBJECT_QUICK:
case OP_IPUT_QUICK:
case OP_IPUT_WIDE_QUICK:
case OP_IPUT_OBJECT_QUICK:
case OP_IGET_VOLATILE:
case OP_IPUT_VOLATILE:
case OP_SGET_VOLATILE:
case OP_SPUT_VOLATILE:
case OP_IGET_OBJECT_VOLATILE:
case OP_IPUT_OBJECT_VOLATILE:
case OP_SGET_OBJECT_VOLATILE:
case OP_SPUT_OBJECT_VOLATILE:
case OP_IGET_WIDE_VOLATILE:
case OP_IPUT_WIDE_VOLATILE:
case OP_SGET_WIDE_VOLATILE:
case OP_SPUT_WIDE_VOLATILE:
flags = kInstrCanContinue | kInstrCanThrow;
break;
case OP_INVOKE_VIRTUAL_QUICK:
case OP_INVOKE_VIRTUAL_QUICK_RANGE:
case OP_INVOKE_SUPER_QUICK:
case OP_INVOKE_SUPER_QUICK_RANGE:
case OP_INVOKE_DIRECT_EMPTY:
flags = kInstrCanContinue | kInstrCanThrow | kInstrInvoke;
break;
case OP_RETURN_VOID_BARRIER:
flags = kInstrCanReturn;
break;
/* these should never appear when scanning code */
case OP_UNUSED_3E:
case OP_UNUSED_3F:
case OP_UNUSED_40:
case OP_UNUSED_41:
case OP_UNUSED_42:
case OP_UNUSED_43:
case OP_UNUSED_73:
case OP_UNUSED_79:
case OP_UNUSED_7A:
case OP_BREAKPOINT:
case OP_UNUSED_FF:
break;
/*
* DO NOT add a "default" clause here. Without it the compiler will
* complain if an instruction is missing (which is desirable).
*/
}
instrFlags[opc] = flags;
}
return instrFlags;
}
/*
* Allocate and populate a 256-element array with instruction formats.
* Used in conjunction with dexDecodeInstruction.
*/
InstructionFormat* dexCreateInstrFormatTable(void)
{
InstructionFormat* instFmt;
int i;
instFmt = malloc(sizeof(InstructionFormat) * kNumDalvikInstructions);
if (instFmt == NULL)
return NULL;
for (i = 0; i < kNumDalvikInstructions; i++) {
OpCode opc = (OpCode) i;
InstructionFormat fmt = kFmtUnknown;
switch (opc) {
case OP_GOTO:
fmt = kFmt10t;
break;
case OP_NOP:
case OP_RETURN_VOID:
fmt = kFmt10x;
break;
case OP_CONST_4:
fmt = kFmt11n;
break;
case OP_CONST_HIGH16:
case OP_CONST_WIDE_HIGH16:
fmt = kFmt21h;
break;
case OP_MOVE_RESULT:
case OP_MOVE_RESULT_WIDE:
case OP_MOVE_RESULT_OBJECT:
case OP_MOVE_EXCEPTION:
case OP_RETURN:
case OP_RETURN_WIDE:
case OP_RETURN_OBJECT:
case OP_MONITOR_ENTER:
case OP_MONITOR_EXIT:
case OP_THROW:
fmt = kFmt11x;
break;
case OP_MOVE:
case OP_MOVE_WIDE:
case OP_MOVE_OBJECT:
case OP_ARRAY_LENGTH:
case OP_NEG_INT:
case OP_NOT_INT:
case OP_NEG_LONG:
case OP_NOT_LONG:
case OP_NEG_FLOAT:
case OP_NEG_DOUBLE:
case OP_INT_TO_LONG:
case OP_INT_TO_FLOAT:
case OP_INT_TO_DOUBLE:
case OP_LONG_TO_INT:
case OP_LONG_TO_FLOAT:
case OP_LONG_TO_DOUBLE:
case OP_FLOAT_TO_INT:
case OP_FLOAT_TO_LONG:
case OP_FLOAT_TO_DOUBLE:
case OP_DOUBLE_TO_INT:
case OP_DOUBLE_TO_LONG:
case OP_DOUBLE_TO_FLOAT:
case OP_INT_TO_BYTE:
case OP_INT_TO_CHAR:
case OP_INT_TO_SHORT:
case OP_ADD_INT_2ADDR:
case OP_SUB_INT_2ADDR:
case OP_MUL_INT_2ADDR:
case OP_DIV_INT_2ADDR:
case OP_REM_INT_2ADDR:
case OP_AND_INT_2ADDR:
case OP_OR_INT_2ADDR:
case OP_XOR_INT_2ADDR:
case OP_SHL_INT_2ADDR:
case OP_SHR_INT_2ADDR:
case OP_USHR_INT_2ADDR:
case OP_ADD_LONG_2ADDR:
case OP_SUB_LONG_2ADDR:
case OP_MUL_LONG_2ADDR:
case OP_DIV_LONG_2ADDR:
case OP_REM_LONG_2ADDR:
case OP_AND_LONG_2ADDR:
case OP_OR_LONG_2ADDR:
case OP_XOR_LONG_2ADDR:
case OP_SHL_LONG_2ADDR:
case OP_SHR_LONG_2ADDR:
case OP_USHR_LONG_2ADDR:
case OP_ADD_FLOAT_2ADDR:
case OP_SUB_FLOAT_2ADDR:
case OP_MUL_FLOAT_2ADDR:
case OP_DIV_FLOAT_2ADDR:
case OP_REM_FLOAT_2ADDR:
case OP_ADD_DOUBLE_2ADDR:
case OP_SUB_DOUBLE_2ADDR:
case OP_MUL_DOUBLE_2ADDR:
case OP_DIV_DOUBLE_2ADDR:
case OP_REM_DOUBLE_2ADDR:
fmt = kFmt12x;
break;
case OP_GOTO_16:
fmt = kFmt20t;
break;
case OP_GOTO_32:
fmt = kFmt30t;
break;
case OP_CONST_STRING:
case OP_CONST_CLASS:
case OP_CHECK_CAST:
case OP_NEW_INSTANCE:
case OP_SGET:
case OP_SGET_WIDE:
case OP_SGET_OBJECT:
case OP_SGET_BOOLEAN:
case OP_SGET_BYTE:
case OP_SGET_CHAR:
case OP_SGET_SHORT:
case OP_SPUT:
case OP_SPUT_WIDE:
case OP_SPUT_OBJECT:
case OP_SPUT_BOOLEAN:
case OP_SPUT_BYTE:
case OP_SPUT_CHAR:
case OP_SPUT_SHORT:
fmt = kFmt21c;
break;
case OP_CONST_16:
case OP_CONST_WIDE_16:
fmt = kFmt21s;
break;
case OP_IF_EQZ:
case OP_IF_NEZ:
case OP_IF_LTZ:
case OP_IF_GEZ:
case OP_IF_GTZ:
case OP_IF_LEZ:
fmt = kFmt21t;
break;
case OP_FILL_ARRAY_DATA:
case OP_PACKED_SWITCH:
case OP_SPARSE_SWITCH:
fmt = kFmt31t;
break;
case OP_ADD_INT_LIT8:
case OP_RSUB_INT_LIT8:
case OP_MUL_INT_LIT8:
case OP_DIV_INT_LIT8:
case OP_REM_INT_LIT8:
case OP_AND_INT_LIT8:
case OP_OR_INT_LIT8:
case OP_XOR_INT_LIT8:
case OP_SHL_INT_LIT8:
case OP_SHR_INT_LIT8:
case OP_USHR_INT_LIT8:
fmt = kFmt22b;
break;
case OP_INSTANCE_OF:
case OP_NEW_ARRAY:
case OP_IGET:
case OP_IGET_WIDE:
case OP_IGET_OBJECT:
case OP_IGET_BOOLEAN:
case OP_IGET_BYTE:
case OP_IGET_CHAR:
case OP_IGET_SHORT:
case OP_IPUT:
case OP_IPUT_WIDE:
case OP_IPUT_OBJECT:
case OP_IPUT_BOOLEAN:
case OP_IPUT_BYTE:
case OP_IPUT_CHAR:
case OP_IPUT_SHORT:
fmt = kFmt22c;
break;
case OP_ADD_INT_LIT16:
case OP_RSUB_INT:
case OP_MUL_INT_LIT16:
case OP_DIV_INT_LIT16:
case OP_REM_INT_LIT16:
case OP_AND_INT_LIT16:
case OP_OR_INT_LIT16:
case OP_XOR_INT_LIT16:
fmt = kFmt22s;
break;
case OP_IF_EQ:
case OP_IF_NE:
case OP_IF_LT:
case OP_IF_GE:
case OP_IF_GT:
case OP_IF_LE:
fmt = kFmt22t;
break;
case OP_MOVE_FROM16:
case OP_MOVE_WIDE_FROM16:
case OP_MOVE_OBJECT_FROM16:
fmt = kFmt22x;
break;
case OP_CMPL_FLOAT:
case OP_CMPG_FLOAT:
case OP_CMPL_DOUBLE:
case OP_CMPG_DOUBLE:
case OP_CMP_LONG:
case OP_AGET:
case OP_AGET_WIDE:
case OP_AGET_OBJECT:
case OP_AGET_BOOLEAN:
case OP_AGET_BYTE:
case OP_AGET_CHAR:
case OP_AGET_SHORT:
case OP_APUT:
case OP_APUT_WIDE:
case OP_APUT_OBJECT:
case OP_APUT_BOOLEAN:
case OP_APUT_BYTE:
case OP_APUT_CHAR:
case OP_APUT_SHORT:
case OP_ADD_INT:
case OP_SUB_INT:
case OP_MUL_INT:
case OP_DIV_INT:
case OP_REM_INT:
case OP_AND_INT:
case OP_OR_INT:
case OP_XOR_INT:
case OP_SHL_INT:
case OP_SHR_INT:
case OP_USHR_INT:
case OP_ADD_LONG:
case OP_SUB_LONG:
case OP_MUL_LONG:
case OP_DIV_LONG:
case OP_REM_LONG:
case OP_AND_LONG:
case OP_OR_LONG:
case OP_XOR_LONG:
case OP_SHL_LONG:
case OP_SHR_LONG:
case OP_USHR_LONG:
case OP_ADD_FLOAT:
case OP_SUB_FLOAT:
case OP_MUL_FLOAT:
case OP_DIV_FLOAT:
case OP_REM_FLOAT:
case OP_ADD_DOUBLE:
case OP_SUB_DOUBLE:
case OP_MUL_DOUBLE:
case OP_DIV_DOUBLE:
case OP_REM_DOUBLE:
fmt = kFmt23x;
break;
case OP_CONST:
case OP_CONST_WIDE_32:
fmt = kFmt31i;
break;
case OP_CONST_STRING_JUMBO:
fmt = kFmt31c;
break;
case OP_MOVE_16:
case OP_MOVE_WIDE_16:
case OP_MOVE_OBJECT_16:
fmt = kFmt32x;
break;
case OP_FILLED_NEW_ARRAY:
case OP_INVOKE_VIRTUAL:
case OP_INVOKE_SUPER:
case OP_INVOKE_DIRECT:
case OP_INVOKE_STATIC:
case OP_INVOKE_INTERFACE:
fmt = kFmt35c;
break;
case OP_FILLED_NEW_ARRAY_RANGE:
case OP_INVOKE_VIRTUAL_RANGE:
case OP_INVOKE_SUPER_RANGE:
case OP_INVOKE_DIRECT_RANGE:
case OP_INVOKE_STATIC_RANGE:
case OP_INVOKE_INTERFACE_RANGE:
fmt = kFmt3rc;
break;
case OP_CONST_WIDE:
fmt = kFmt51l;
break;
/*
* Optimized instructions.
*/
case OP_THROW_VERIFICATION_ERROR:
fmt = kFmt20bc;
break;
case OP_IGET_WIDE_VOLATILE:
case OP_IPUT_WIDE_VOLATILE:
case OP_IGET_VOLATILE:
case OP_IPUT_VOLATILE:
case OP_IGET_OBJECT_VOLATILE:
case OP_IPUT_OBJECT_VOLATILE:
fmt = kFmt22c;
break;
case OP_SGET_OBJECT_VOLATILE:
case OP_SPUT_OBJECT_VOLATILE:
case OP_SGET_VOLATILE:
case OP_SPUT_VOLATILE:
case OP_SGET_WIDE_VOLATILE:
case OP_SPUT_WIDE_VOLATILE:
fmt = kFmt21c;
break;
case OP_IGET_QUICK:
case OP_IGET_WIDE_QUICK:
case OP_IGET_OBJECT_QUICK:
case OP_IPUT_QUICK:
case OP_IPUT_WIDE_QUICK:
case OP_IPUT_OBJECT_QUICK:
fmt = kFmt22cs;
break;
case OP_INVOKE_VIRTUAL_QUICK:
case OP_INVOKE_SUPER_QUICK:
fmt = kFmt35ms;
break;
case OP_INVOKE_VIRTUAL_QUICK_RANGE:
case OP_INVOKE_SUPER_QUICK_RANGE:
fmt = kFmt3rms;
break;
case OP_EXECUTE_INLINE:
fmt = kFmt35mi;
break;
case OP_EXECUTE_INLINE_RANGE:
fmt = kFmt3rmi;
break;
case OP_INVOKE_DIRECT_EMPTY:
fmt = kFmt35c;
break;
case OP_RETURN_VOID_BARRIER:
fmt = kFmt10x;
break;
/* these should never appear when scanning code */
case OP_UNUSED_3E:
case OP_UNUSED_3F:
case OP_UNUSED_40:
case OP_UNUSED_41:
case OP_UNUSED_42:
case OP_UNUSED_43:
case OP_UNUSED_73:
case OP_UNUSED_79:
case OP_UNUSED_7A:
case OP_BREAKPOINT:
case OP_UNUSED_FF:
fmt = kFmtUnknown;
break;
/*
* DO NOT add a "default" clause here. Without it the compiler will
* complain if an instruction is missing (which is desirable).
*/
}
instFmt[opc] = fmt;
}
return instFmt;
}
/*
* Allocate and populate an array with index types for all instructions.
* Used in conjunction with dexDecodeInstruction.
*/
InstructionIndexType* dexCreateInstrIndexTypeTable(void)
{
InstructionIndexType* indexTypes;
int i;
indexTypes = malloc(sizeof(InstructionIndexType) * kNumDalvikInstructions);
if (indexTypes == NULL)
return NULL;
for (i = 0; i < kNumDalvikInstructions; i++) {
OpCode opc = (OpCode) i;
InstructionIndexType indexType = kIndexUnknown;
switch (opc) {
case OP_GOTO:
case OP_NOP:
case OP_RETURN_VOID:
case OP_CONST_4:
case OP_CONST_HIGH16:
case OP_CONST_WIDE_HIGH16:
case OP_MOVE_RESULT:
case OP_MOVE_RESULT_WIDE:
case OP_MOVE_RESULT_OBJECT:
case OP_MOVE_EXCEPTION:
case OP_RETURN:
case OP_RETURN_WIDE:
case OP_RETURN_OBJECT:
case OP_MONITOR_ENTER:
case OP_MONITOR_EXIT:
case OP_THROW:
case OP_MOVE:
case OP_MOVE_WIDE:
case OP_MOVE_OBJECT:
case OP_ARRAY_LENGTH:
case OP_NEG_INT:
case OP_NOT_INT:
case OP_NEG_LONG:
case OP_NOT_LONG:
case OP_NEG_FLOAT:
case OP_NEG_DOUBLE:
case OP_INT_TO_LONG:
case OP_INT_TO_FLOAT:
case OP_INT_TO_DOUBLE:
case OP_LONG_TO_INT:
case OP_LONG_TO_FLOAT:
case OP_LONG_TO_DOUBLE:
case OP_FLOAT_TO_INT:
case OP_FLOAT_TO_LONG:
case OP_FLOAT_TO_DOUBLE:
case OP_DOUBLE_TO_INT:
case OP_DOUBLE_TO_LONG:
case OP_DOUBLE_TO_FLOAT:
case OP_INT_TO_BYTE:
case OP_INT_TO_CHAR:
case OP_INT_TO_SHORT:
case OP_ADD_INT_2ADDR:
case OP_SUB_INT_2ADDR:
case OP_MUL_INT_2ADDR:
case OP_DIV_INT_2ADDR:
case OP_REM_INT_2ADDR:
case OP_AND_INT_2ADDR:
case OP_OR_INT_2ADDR:
case OP_XOR_INT_2ADDR:
case OP_SHL_INT_2ADDR:
case OP_SHR_INT_2ADDR:
case OP_USHR_INT_2ADDR:
case OP_ADD_LONG_2ADDR:
case OP_SUB_LONG_2ADDR:
case OP_MUL_LONG_2ADDR:
case OP_DIV_LONG_2ADDR:
case OP_REM_LONG_2ADDR:
case OP_AND_LONG_2ADDR:
case OP_OR_LONG_2ADDR:
case OP_XOR_LONG_2ADDR:
case OP_SHL_LONG_2ADDR:
case OP_SHR_LONG_2ADDR:
case OP_USHR_LONG_2ADDR:
case OP_ADD_FLOAT_2ADDR:
case OP_SUB_FLOAT_2ADDR:
case OP_MUL_FLOAT_2ADDR:
case OP_DIV_FLOAT_2ADDR:
case OP_REM_FLOAT_2ADDR:
case OP_ADD_DOUBLE_2ADDR:
case OP_SUB_DOUBLE_2ADDR:
case OP_MUL_DOUBLE_2ADDR:
case OP_DIV_DOUBLE_2ADDR:
case OP_REM_DOUBLE_2ADDR:
case OP_GOTO_16:
case OP_GOTO_32:
case OP_CONST_16:
case OP_CONST_WIDE_16:
case OP_IF_EQZ:
case OP_IF_NEZ:
case OP_IF_LTZ:
case OP_IF_GEZ:
case OP_IF_GTZ:
case OP_IF_LEZ:
case OP_FILL_ARRAY_DATA:
case OP_PACKED_SWITCH:
case OP_SPARSE_SWITCH:
case OP_ADD_INT_LIT8:
case OP_RSUB_INT_LIT8:
case OP_MUL_INT_LIT8:
case OP_DIV_INT_LIT8:
case OP_REM_INT_LIT8:
case OP_AND_INT_LIT8:
case OP_OR_INT_LIT8:
case OP_XOR_INT_LIT8:
case OP_SHL_INT_LIT8:
case OP_SHR_INT_LIT8:
case OP_USHR_INT_LIT8:
case OP_ADD_INT_LIT16:
case OP_RSUB_INT:
case OP_MUL_INT_LIT16:
case OP_DIV_INT_LIT16:
case OP_REM_INT_LIT16:
case OP_AND_INT_LIT16:
case OP_OR_INT_LIT16:
case OP_XOR_INT_LIT16:
case OP_IF_EQ:
case OP_IF_NE:
case OP_IF_LT:
case OP_IF_GE:
case OP_IF_GT:
case OP_IF_LE:
case OP_MOVE_FROM16:
case OP_MOVE_WIDE_FROM16:
case OP_MOVE_OBJECT_FROM16:
case OP_CMPL_FLOAT:
case OP_CMPG_FLOAT:
case OP_CMPL_DOUBLE:
case OP_CMPG_DOUBLE:
case OP_CMP_LONG:
case OP_AGET:
case OP_AGET_WIDE:
case OP_AGET_OBJECT:
case OP_AGET_BOOLEAN:
case OP_AGET_BYTE:
case OP_AGET_CHAR:
case OP_AGET_SHORT:
case OP_APUT:
case OP_APUT_WIDE:
case OP_APUT_OBJECT:
case OP_APUT_BOOLEAN:
case OP_APUT_BYTE:
case OP_APUT_CHAR:
case OP_APUT_SHORT:
case OP_ADD_INT:
case OP_SUB_INT:
case OP_MUL_INT:
case OP_DIV_INT:
case OP_REM_INT:
case OP_AND_INT:
case OP_OR_INT:
case OP_XOR_INT:
case OP_SHL_INT:
case OP_SHR_INT:
case OP_USHR_INT:
case OP_ADD_LONG:
case OP_SUB_LONG:
case OP_MUL_LONG:
case OP_DIV_LONG:
case OP_REM_LONG:
case OP_AND_LONG:
case OP_OR_LONG:
case OP_XOR_LONG:
case OP_SHL_LONG:
case OP_SHR_LONG:
case OP_USHR_LONG:
case OP_ADD_FLOAT:
case OP_SUB_FLOAT:
case OP_MUL_FLOAT:
case OP_DIV_FLOAT:
case OP_REM_FLOAT:
case OP_ADD_DOUBLE:
case OP_SUB_DOUBLE:
case OP_MUL_DOUBLE:
case OP_DIV_DOUBLE:
case OP_REM_DOUBLE:
case OP_CONST:
case OP_CONST_WIDE_32:
case OP_MOVE_16:
case OP_MOVE_WIDE_16:
case OP_MOVE_OBJECT_16:
case OP_CONST_WIDE:
indexType = kIndexNone;
break;
case OP_CONST_STRING:
case OP_CONST_STRING_JUMBO:
indexType = kIndexStringRef;
break;
case OP_CONST_CLASS:
case OP_CHECK_CAST:
case OP_NEW_INSTANCE:
case OP_INSTANCE_OF:
case OP_NEW_ARRAY:
case OP_FILLED_NEW_ARRAY:
case OP_FILLED_NEW_ARRAY_RANGE:
indexType = kIndexTypeRef;
break;
case OP_SGET:
case OP_SGET_WIDE:
case OP_SGET_OBJECT:
case OP_SGET_BOOLEAN:
case OP_SGET_BYTE:
case OP_SGET_CHAR:
case OP_SGET_SHORT:
case OP_SPUT:
case OP_SPUT_WIDE:
case OP_SPUT_OBJECT:
case OP_SPUT_BOOLEAN:
case OP_SPUT_BYTE:
case OP_SPUT_CHAR:
case OP_SPUT_SHORT:
case OP_IGET:
case OP_IGET_WIDE:
case OP_IGET_OBJECT:
case OP_IGET_BOOLEAN:
case OP_IGET_BYTE:
case OP_IGET_CHAR:
case OP_IGET_SHORT:
case OP_IPUT:
case OP_IPUT_WIDE:
case OP_IPUT_OBJECT:
case OP_IPUT_BOOLEAN:
case OP_IPUT_BYTE:
case OP_IPUT_CHAR:
case OP_IPUT_SHORT:
indexType = kIndexFieldRef;
break;
case OP_INVOKE_VIRTUAL:
case OP_INVOKE_SUPER:
case OP_INVOKE_DIRECT:
case OP_INVOKE_STATIC:
case OP_INVOKE_INTERFACE:
case OP_INVOKE_VIRTUAL_RANGE:
case OP_INVOKE_SUPER_RANGE:
case OP_INVOKE_DIRECT_RANGE:
case OP_INVOKE_STATIC_RANGE:
case OP_INVOKE_INTERFACE_RANGE:
indexType = kIndexMethodRef;
break;
/*
* Optimized instructions.
*/
case OP_THROW_VERIFICATION_ERROR:
indexType = kIndexVaries;
break;
case OP_IGET_WIDE_VOLATILE:
case OP_IPUT_WIDE_VOLATILE:
case OP_IGET_VOLATILE:
case OP_IPUT_VOLATILE:
case OP_IGET_OBJECT_VOLATILE:
case OP_IPUT_OBJECT_VOLATILE:
case OP_SGET_OBJECT_VOLATILE:
case OP_SPUT_OBJECT_VOLATILE:
case OP_SGET_VOLATILE:
case OP_SPUT_VOLATILE:
case OP_SGET_WIDE_VOLATILE:
case OP_SPUT_WIDE_VOLATILE:
indexType = kIndexFieldRef;
break;
case OP_IGET_QUICK:
case OP_IGET_WIDE_QUICK:
case OP_IGET_OBJECT_QUICK:
case OP_IPUT_QUICK:
case OP_IPUT_WIDE_QUICK:
case OP_IPUT_OBJECT_QUICK:
indexType = kIndexFieldOffset;
break;
case OP_INVOKE_VIRTUAL_QUICK:
case OP_INVOKE_SUPER_QUICK:
case OP_INVOKE_VIRTUAL_QUICK_RANGE:
case OP_INVOKE_SUPER_QUICK_RANGE:
indexType = kIndexVtableOffset;
break;
case OP_EXECUTE_INLINE:
case OP_EXECUTE_INLINE_RANGE:
indexType = kIndexInlineMethod;
break;
case OP_INVOKE_DIRECT_EMPTY:
indexType = kIndexMethodRef;
break;
case OP_RETURN_VOID_BARRIER:
indexType = kIndexNone;
break;
/* these should never appear when scanning code */
case OP_UNUSED_3E:
case OP_UNUSED_3F:
case OP_UNUSED_40:
case OP_UNUSED_41:
case OP_UNUSED_42:
case OP_UNUSED_43:
case OP_UNUSED_73:
case OP_UNUSED_79:
case OP_UNUSED_7A:
case OP_BREAKPOINT:
case OP_UNUSED_FF:
indexType = kIndexUnknown;
break;
/*
* DO NOT add a "default" clause here. Without it the compiler will
* complain if an instruction is missing (which is desirable).
*/
}
indexTypes[opc] = indexType;
}
return indexTypes;
}
/*
* Construct all of the instruction info tables, storing references to
* them into the given struct. This returns 0 on success or non-zero on
* failure. If this fails, then no net allocation will have occurred.
*/
int dexCreateInstructionInfoTables(InstructionInfoTables* info) {
info->formats = NULL;
info->indexTypes = NULL;
info->flags = NULL;
info->widths = NULL;
info->formats = dexCreateInstrFormatTable();
info->indexTypes = dexCreateInstrIndexTypeTable();
info->flags = dexCreateInstrFlagsTable();
info->widths = dexCreateInstrWidthTable();
if ((info->formats == NULL)
|| (info->indexTypes == NULL)
|| (info->flags == NULL)
|| (info->widths == NULL)) {
dexFreeInstructionInfoTables(info);
return 1;
}
return 0;
}
/*
* Free up the tables referred to by the given instruction info struct.
*/
void dexFreeInstructionInfoTables(InstructionInfoTables* info) {
free(info->formats);
free(info->indexTypes);
free(info->flags);
free(info->widths);
}
/*
* Handy macros for helping decode instructions.
*/
#define FETCH(_offset) (insns[(_offset)])
#define FETCH_u4(_offset) (fetch_u4_impl((_offset), insns))
#define INST_INST(_inst) ((_inst) & 0xff)
#define INST_A(_inst) (((u2)(_inst) >> 8) & 0x0f)
#define INST_B(_inst) ((u2)(_inst) >> 12)
#define INST_AA(_inst) ((_inst) >> 8)
/* Helper for FETCH_u4, above. */
static inline u4 fetch_u4_impl(u4 offset, const u2* insns) {
return insns[offset] | ((u4) insns[offset+1] << 16);
}
/*
* Decode the instruction pointed to by "insns".
*
* Fills out the pieces of "pDec" that are affected by the current
* instruction. Does not touch anything else.
*/
void dexDecodeInstruction(const InstructionInfoTables* info, const u2* insns,
DecodedInstruction* pDec)
{
u2 inst = *insns;
OpCode opCode = (OpCode) INST_INST(inst);
InstructionFormat format = dexGetInstrFormat(info->formats, opCode);
pDec->opCode = opCode;
pDec->indexType = dexGetInstrIndexType(info->indexTypes, opCode);
switch (format) {
case kFmt10x: // op
/* nothing to do; copy the AA bits out for the verifier */
pDec->vA = INST_AA(inst);
break;
case kFmt12x: // op vA, vB
pDec->vA = INST_A(inst);
pDec->vB = INST_B(inst);
break;
case kFmt11n: // op vA, #+B
pDec->vA = INST_A(inst);
pDec->vB = (s4) (INST_B(inst) << 28) >> 28; // sign extend 4-bit value
break;
case kFmt11x: // op vAA
pDec->vA = INST_AA(inst);
break;
case kFmt10t: // op +AA
pDec->vA = (s1) INST_AA(inst); // sign-extend 8-bit value
break;
case kFmt20t: // op +AAAA
pDec->vA = (s2) FETCH(1); // sign-extend 16-bit value
break;
case kFmt20bc: // [opt] op AA, thing@BBBB
case kFmt21c: // op vAA, thing@BBBB
case kFmt22x: // op vAA, vBBBB
pDec->vA = INST_AA(inst);
pDec->vB = FETCH(1);
break;
case kFmt21s: // op vAA, #+BBBB
case kFmt21t: // op vAA, +BBBB
pDec->vA = INST_AA(inst);
pDec->vB = (s2) FETCH(1); // sign-extend 16-bit value
break;
case kFmt21h: // op vAA, #+BBBB0000[00000000]
pDec->vA = INST_AA(inst);
/*
* The value should be treated as right-zero-extended, but we don't
* actually do that here. Among other things, we don't know if it's
* the top bits of a 32- or 64-bit value.
*/
pDec->vB = FETCH(1);
break;
case kFmt23x: // op vAA, vBB, vCC
pDec->vA = INST_AA(inst);
pDec->vB = FETCH(1) & 0xff;
pDec->vC = FETCH(1) >> 8;
break;
case kFmt22b: // op vAA, vBB, #+CC
pDec->vA = INST_AA(inst);
pDec->vB = FETCH(1) & 0xff;
pDec->vC = (s1) (FETCH(1) >> 8); // sign-extend 8-bit value
break;
case kFmt22s: // op vA, vB, #+CCCC
case kFmt22t: // op vA, vB, +CCCC
pDec->vA = INST_A(inst);
pDec->vB = INST_B(inst);
pDec->vC = (s2) FETCH(1); // sign-extend 16-bit value
break;
case kFmt22c: // op vA, vB, thing@CCCC
case kFmt22cs: // [opt] op vA, vB, field offset CCCC
pDec->vA = INST_A(inst);
pDec->vB = INST_B(inst);
pDec->vC = FETCH(1);
break;
case kFmt30t: // op +AAAAAAAA
pDec->vA = FETCH_u4(1); // signed 32-bit value
break;
case kFmt31t: // op vAA, +BBBBBBBB
case kFmt31c: // op vAA, string@BBBBBBBB
pDec->vA = INST_AA(inst);
pDec->vB = FETCH_u4(1); // 32-bit value
break;
case kFmt32x: // op vAAAA, vBBBB
pDec->vA = FETCH(1);
pDec->vB = FETCH(2);
break;
case kFmt31i: // op vAA, #+BBBBBBBB
pDec->vA = INST_AA(inst);
pDec->vB = FETCH_u4(1); // signed 32-bit value
break;
case kFmt35c: // op {vC, vD, vE, vF, vG}, thing@BBBB
case kFmt35ms: // [opt] invoke-virtual+super
case kFmt35mi: // [opt] inline invoke
{
/*
* Note that the fields mentioned in the spec don't appear in
* their "usual" positions here compared to most formats. This
* was done so that the field names for the argument count and
* reference index match between this format and the corresponding
* range formats (3rc and friends).
*
* Bottom line: The argument count is always in vA, and the
* method constant (or equivalent) is always in vB.
*/
u2 regList;
int i, count;
pDec->vA = INST_B(inst); // This is labeled A in the spec.
pDec->vB = FETCH(1);
regList = FETCH(2);
count = pDec->vA;
/*
* Copy the argument registers into the arg[] array, and
* also copy the first argument (if any) into vC. (The
* DecodedInstruction structure doesn't have separate
* fields for {vD, vE, vF, vG}, so there's no need to make
* copies of those.) Note that cases 5..2 fall through.
*/
switch (count) {
case 5: {
if (format == kFmt35mi) {
/* A fifth arg is verboten for inline invokes. */
LOGW("Invalid arg count in 35mi (5)\n");
goto bail;
}
/*
* Per note at the top of this format decoder, the
* fifth argument comes from the A field in the
* instruction, but it's labeled G in the spec.
*/
pDec->arg[4] = INST_A(inst);
}
case 4: pDec->arg[3] = (regList >> 12) & 0x0f;
case 3: pDec->arg[2] = (regList >> 8) & 0x0f;
case 2: pDec->arg[1] = (regList >> 4) & 0x0f;
case 1: pDec->vC = pDec->arg[0] = regList & 0x0f; break;
case 0: break; // Valid, but no need to do anything.
default:
LOGW("Invalid arg count in 35c/35ms/35mi (%d)\n", count);
goto bail;
}
}
break;
case kFmt3rc: // op {vCCCC .. v(CCCC+AA-1)}, meth@BBBB
case kFmt3rms: // [opt] invoke-virtual+super/range
case kFmt3rmi: // [opt] execute-inline/range
pDec->vA = INST_AA(inst);
pDec->vB = FETCH(1);
pDec->vC = FETCH(2);
break;
case kFmt51l: // op vAA, #+BBBBBBBBBBBBBBBB
pDec->vA = INST_AA(inst);
pDec->vB_wide = FETCH_u4(1) | ((u8) FETCH_u4(3) << 32);
break;
case kFmt33x: // exop vAA, vBB, vCCCC
pDec->vA = FETCH(1) & 0xff;
pDec->vB = FETCH(1) >> 8;
pDec->vC = FETCH(2);
break;
case kFmt32s: // exop vAA, vBB, #+CCCC
pDec->vA = FETCH(1) & 0xff;
pDec->vB = FETCH(1) >> 8;
pDec->vC = (s2) FETCH(2); // sign-extend 16-bit value
break;
case kFmt41c: // exop vAAAA, thing@BBBBBBBB
/*
* The order of fields for this format in the spec is {B, A},
* to match formats 21c and 31c.
*/
pDec->vB = FETCH_u4(1); // 32-bit value
pDec->vA = FETCH(3);
break;
case kFmt52c: // exop vAAAA, vBBBB, thing@CCCCCCCC
/*
* The order of fields for this format in the spec is {C, A, B},
* to match formats 22c and 22cs.
*/
pDec->vC = FETCH_u4(1); // 32-bit value
pDec->vA = FETCH(3);
pDec->vB = FETCH(4);
break;
case kFmt5rc: // exop {vCCCC .. v(CCCC+AAAA-1)}, meth@BBBBBBBB
/*
* The order of fields for this format in the spec is {B, A, C},
* to match formats 3rc and friends.
*/
pDec->vB = FETCH_u4(1); // 32-bit value
pDec->vA = FETCH(3);
pDec->vC = FETCH(4);
break;
default:
LOGW("Can't decode unexpected format %d (op=%d)\n", format, opCode);
assert(false);
break;
}
bail:
;
}
/*
* 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 dexGetInstrOrTableWidth(const InstructionWidth* widths,
const u2* insns)
{
size_t width;
if (*insns == kPackedSwitchSignature) {
width = 4 + insns[1] * 2;
} else if (*insns == kSparseSwitchSignature) {
width = 2 + insns[1] * 4;
} else if (*insns == kArrayDataSignature) {
u2 elemWidth = insns[1];
u4 len = insns[2] | (((u4)insns[3]) << 16);
width = 4 + (elemWidth * len + 1) / 2;
} else {
width = dexGetInstrWidth(widths, INST_INST(insns[0]));
}
return width;
}