blob: ab15c816ea3dd7d2dde29552aa59a57424472b1f [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.
*
* IMPORTANT NOTE: Much of the contents of this file are generated
* automatically by the opcode-gen tool. Any edits to the generated
* sections will get wiped out the next time the tool is run.
*/
#include "InstrUtils.h"
#include <stdlib.h>
#if 0
/* coming soon! */
/*
* Table that maps each opcode to the full width of instructions that
* use that opcode, in (16-bit) code units. Unimplemented opcodes as
* well as the "breakpoint" opcode have a width of zero.
*/
static InstructionWidth gOpcodeWidthTable[kNumDalvikInstructions] = {
// BEGIN(libdex-widths); GENERATED AUTOMATICALLY BY opcode-gen
1, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 1, 1, 1, 1, 1,
1, 1, 1, 2, 3, 2, 2, 3, 5, 2, 2, 3, 2, 1, 1, 2,
2, 1, 2, 2, 3, 3, 3, 1, 1, 2, 3, 3, 3, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0,
0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3,
3, 3, 3, 0, 3, 3, 3, 3, 3, 0, 0, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 3, 3,
3, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 0,
// END(libdex-widths)
};
/*
* Table that maps each opcode to the flags associated with that
* opcode.
*/
static InstructionFlags gOpcodeFlagsTable[kNumDalvikInstructions] = {
// BEGIN(libdex-flags); GENERATED AUTOMATICALLY BY opcode-gen
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanReturn,
kInstrCanReturn,
kInstrCanReturn,
kInstrCanReturn,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue,
kInstrCanThrow,
kInstrCanBranch,
kInstrCanBranch,
kInstrCanBranch,
kInstrCanContinue|kInstrCanSwitch,
kInstrCanContinue|kInstrCanSwitch,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue|kInstrCanBranch,
kInstrCanContinue|kInstrCanBranch,
kInstrCanContinue|kInstrCanBranch,
kInstrCanContinue|kInstrCanBranch,
kInstrCanContinue|kInstrCanBranch,
kInstrCanContinue|kInstrCanBranch,
kInstrCanContinue|kInstrCanBranch,
kInstrCanContinue|kInstrCanBranch,
kInstrCanContinue|kInstrCanBranch,
kInstrCanContinue|kInstrCanBranch,
kInstrCanContinue|kInstrCanBranch,
kInstrCanContinue|kInstrCanBranch,
0,
0,
0,
0,
0,
0,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
0,
kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
0,
0,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
0,
kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
kInstrCanReturn,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
kInstrCanContinue|kInstrCanThrow,
0,
// END(libdex-flags)
};
/*
* Table that maps each opcode to the instruction format associated
* that opcode.
*/
static InstructionFormat gOpcodeFormatTable[kNumDalvikInstructions] = {
// BEGIN(libdex-formats); GENERATED AUTOMATICALLY BY opcode-gen
kFmt10x, kFmt12x, kFmt22x, kFmt32x, kFmt12x, kFmt22x, kFmt32x,
kFmt12x, kFmt22x, kFmt32x, kFmt11x, kFmt11x, kFmt11x, kFmt11x,
kFmt10x, kFmt11x, kFmt11x, kFmt11x, kFmt11n, kFmt21s, kFmt31i,
kFmt21h, kFmt21s, kFmt31i, kFmt51l, kFmt21h, kFmt21c, kFmt31c,
kFmt21c, kFmt11x, kFmt11x, kFmt21c, kFmt22c, kFmt12x, kFmt21c,
kFmt22c, kFmt35c, kFmt3rc, kFmt31t, kFmt11x, kFmt10t, kFmt20t,
kFmt30t, kFmt31t, kFmt31t, kFmt23x, kFmt23x, kFmt23x, kFmt23x,
kFmt23x, kFmt22t, kFmt22t, kFmt22t, kFmt22t, kFmt22t, kFmt22t,
kFmt21t, kFmt21t, kFmt21t, kFmt21t, kFmt21t, kFmt21t, kFmt00x,
kFmt00x, kFmt00x, kFmt00x, kFmt00x, kFmt00x, kFmt23x, kFmt23x,
kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x,
kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt22c, kFmt22c,
kFmt22c, kFmt22c, kFmt22c, kFmt22c, kFmt22c, kFmt22c, kFmt22c,
kFmt22c, kFmt22c, kFmt22c, kFmt22c, kFmt22c, kFmt21c, kFmt21c,
kFmt21c, kFmt21c, kFmt21c, kFmt21c, kFmt21c, kFmt21c, kFmt21c,
kFmt21c, kFmt21c, kFmt21c, kFmt21c, kFmt21c, kFmt35c, kFmt35c,
kFmt35c, kFmt35c, kFmt35c, kFmt00x, kFmt3rc, kFmt3rc, kFmt3rc,
kFmt3rc, kFmt3rc, kFmt00x, kFmt00x, kFmt12x, kFmt12x, kFmt12x,
kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x,
kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x,
kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt23x, kFmt23x, kFmt23x,
kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x,
kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x,
kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x,
kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x,
kFmt23x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x,
kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x,
kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x,
kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x,
kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt22s, kFmt22s,
kFmt22s, kFmt22s, kFmt22s, kFmt22s, kFmt22s, kFmt22s, kFmt22b,
kFmt22b, kFmt22b, kFmt22b, kFmt22b, kFmt22b, kFmt22b, kFmt22b,
kFmt22b, kFmt22b, kFmt22b, kFmt22c, kFmt22c, kFmt21c, kFmt21c,
kFmt22c, kFmt22c, kFmt22c, kFmt21c, kFmt21c, kFmt00x, kFmt20bc,
kFmt35mi, kFmt3rmi, kFmt35c, kFmt10x, kFmt22cs, kFmt22cs, kFmt22cs,
kFmt22cs, kFmt22cs, kFmt22cs, kFmt35ms, kFmt3rms, kFmt35ms, kFmt3rms,
kFmt22c, kFmt21c, kFmt21c, kFmt00x,
// END(libdex-formats)
};
/*
* Table that maps each opcode to the index type implied by that
* opcode.
*/
static InstructionIndexType gOpcodeIndexTypeTable[kNumDalvikInstructions] = {
// BEGIN(libdex-index-types); GENERATED AUTOMATICALLY BY opcode-gen
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexStringRef,
kIndexStringRef, kIndexTypeRef, kIndexNone,
kIndexNone, kIndexTypeRef, kIndexTypeRef,
kIndexNone, kIndexTypeRef, kIndexTypeRef,
kIndexTypeRef, kIndexTypeRef, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexUnknown,
kIndexUnknown, kIndexUnknown, kIndexUnknown,
kIndexUnknown, kIndexUnknown, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexFieldRef, kIndexFieldRef,
kIndexFieldRef, kIndexFieldRef, kIndexFieldRef,
kIndexFieldRef, kIndexFieldRef, kIndexFieldRef,
kIndexFieldRef, kIndexFieldRef, kIndexFieldRef,
kIndexFieldRef, kIndexFieldRef, kIndexFieldRef,
kIndexFieldRef, kIndexFieldRef, kIndexFieldRef,
kIndexFieldRef, kIndexFieldRef, kIndexFieldRef,
kIndexFieldRef, kIndexFieldRef, kIndexFieldRef,
kIndexFieldRef, kIndexFieldRef, kIndexFieldRef,
kIndexFieldRef, kIndexFieldRef, kIndexMethodRef,
kIndexMethodRef, kIndexMethodRef, kIndexMethodRef,
kIndexMethodRef, kIndexUnknown, kIndexMethodRef,
kIndexMethodRef, kIndexMethodRef, kIndexMethodRef,
kIndexMethodRef, kIndexUnknown, kIndexUnknown,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexNone,
kIndexNone, kIndexNone, kIndexFieldRef,
kIndexFieldRef, kIndexFieldRef, kIndexFieldRef,
kIndexFieldRef, kIndexFieldRef, kIndexFieldRef,
kIndexFieldRef, kIndexFieldRef, kIndexUnknown,
kIndexVaries, kIndexInlineMethod, kIndexInlineMethod,
kIndexMethodRef, kIndexNone, kIndexFieldOffset,
kIndexFieldOffset, kIndexFieldOffset, kIndexFieldOffset,
kIndexFieldOffset, kIndexFieldOffset, kIndexVtableOffset,
kIndexVtableOffset, kIndexVtableOffset, kIndexVtableOffset,
kIndexFieldRef, kIndexFieldRef, kIndexFieldRef,
kIndexUnknown,
// END(libdex-index-types)
};
#endif
/*
* 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;
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 = kFmt00x;
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 = kFmt00x;
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;
}