mirror of
https://github.com/LSPosed/DexBuilder.git
synced 2024-11-22 06:06:28 +00:00
217 lines
7.0 KiB
C++
217 lines
7.0 KiB
C++
/*
|
|
* Copyright (C) 2017 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "dex_format.h"
|
|
|
|
#include <stddef.h>
|
|
|
|
// .dex bytecode definitions and helpers:
|
|
// https://source.android.com/devices/tech/dalvik/dalvik-bytecode.html
|
|
|
|
namespace dex {
|
|
|
|
// The number of Dalvik opcodes
|
|
constexpr size_t kNumPackedOpcodes = 0x100;
|
|
|
|
// Switch table and array data signatures are a code unit consisting
|
|
// of "NOP" (0x00) in the low-order byte and a non-zero identifying
|
|
// code in the high-order byte. (A true NOP is 0x0000.)
|
|
constexpr u2 kPackedSwitchSignature = 0x0100;
|
|
constexpr u2 kSparseSwitchSignature = 0x0200;
|
|
constexpr u2 kArrayDataSignature = 0x0300;
|
|
|
|
// Enumeration of all Dalvik opcodes
|
|
enum Opcode : u1 {
|
|
#define INSTRUCTION_ENUM(opcode, cname, ...) OP_##cname = (opcode),
|
|
#include "dex_instruction_list.h"
|
|
DEX_INSTRUCTION_LIST(INSTRUCTION_ENUM)
|
|
#undef DEX_INSTRUCTION_LIST
|
|
#undef INSTRUCTION_ENUM
|
|
};
|
|
|
|
// Instruction formats associated with Dalvik opcodes
|
|
enum InstructionFormat : u1 {
|
|
k10x, // op
|
|
k12x, // op vA, vB
|
|
k11n, // op vA, #+B
|
|
k11x, // op vAA
|
|
k10t, // op +AA
|
|
k20t, // op +AAAA
|
|
k20bc, // [opt] op AA, thing@BBBB
|
|
k22x, // op vAA, vBBBB
|
|
k21t, // op vAA, +BBBB
|
|
k21s, // op vAA, #+BBBB
|
|
k21h, // op vAA, #+BBBB00000[00000000]
|
|
k21c, // op vAA, thing@BBBB
|
|
k23x, // op vAA, vBB, vCC
|
|
k22b, // op vAA, vBB, #+CC
|
|
k22t, // op vA, vB, +CCCC
|
|
k22s, // op vA, vB, #+CCCC
|
|
k22c, // op vA, vB, thing@CCCC
|
|
k22cs, // [opt] op vA, vB, field offset CCCC
|
|
k30t, // op +AAAAAAAA
|
|
k32x, // op vAAAA, vBBBB
|
|
k31i, // op vAA, #+BBBBBBBB
|
|
k31t, // op vAA, +BBBBBBBB
|
|
k31c, // op vAA, string@BBBBBBBB
|
|
k35c, // op {vC,vD,vE,vF,vG}, thing@BBBB
|
|
k35ms, // [opt] invoke-virtual+super
|
|
k3rc, // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB
|
|
k3rms, // [opt] invoke-virtual+super/range
|
|
k35mi, // [opt] inline invoke
|
|
k3rmi, // [opt] inline invoke/range
|
|
k45cc, // op {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH
|
|
k4rcc, // op {VCCCC .. v(CCCC+AA-1)}, meth@BBBB, proto@HHHH
|
|
k51l, // op vAA, #+BBBBBBBBBBBBBBBB
|
|
};
|
|
|
|
using OpcodeFlags = u1;
|
|
enum : OpcodeFlags {
|
|
kBranch = 0x01, // conditional or unconditional branch
|
|
kContinue = 0x02, // flow can continue to next statement
|
|
kSwitch = 0x04, // switch statement
|
|
kThrow = 0x08, // could cause an exception to be thrown
|
|
kReturn = 0x10, // returns, no additional statements
|
|
kInvoke = 0x20, // a flavor of invoke
|
|
kUnconditional = 0x40, // unconditional branch
|
|
kExperimental = 0x80, // is an experimental opcode
|
|
};
|
|
|
|
using VerifyFlags = u4;
|
|
enum : VerifyFlags {
|
|
kVerifyNothing = 0x0000000,
|
|
kVerifyRegA = 0x0000001,
|
|
kVerifyRegAWide = 0x0000002,
|
|
kVerifyRegB = 0x0000004,
|
|
kVerifyRegBField = 0x0000008,
|
|
kVerifyRegBMethod = 0x0000010,
|
|
kVerifyRegBNewInstance = 0x0000020,
|
|
kVerifyRegBString = 0x0000040,
|
|
kVerifyRegBType = 0x0000080,
|
|
kVerifyRegBWide = 0x0000100,
|
|
kVerifyRegC = 0x0000200,
|
|
kVerifyRegCField = 0x0000400,
|
|
kVerifyRegCNewArray = 0x0000800,
|
|
kVerifyRegCType = 0x0001000,
|
|
kVerifyRegCWide = 0x0002000,
|
|
kVerifyArrayData = 0x0004000,
|
|
kVerifyBranchTarget = 0x0008000,
|
|
kVerifySwitchTargets = 0x0010000,
|
|
kVerifyVarArg = 0x0020000,
|
|
kVerifyVarArgNonZero = 0x0040000,
|
|
kVerifyVarArgRange = 0x0080000,
|
|
kVerifyVarArgRangeNonZero = 0x0100000,
|
|
kVerifyRuntimeOnly = 0x0200000,
|
|
kVerifyError = 0x0400000,
|
|
kVerifyRegHPrototype = 0x0800000,
|
|
kVerifyRegBCallSite = 0x1000000,
|
|
kVerifyRegBMethodHandle = 0x2000000,
|
|
kVerifyRegBPrototype = 0x4000000,
|
|
};
|
|
|
|
// Types of indexed reference that are associated with opcodes whose
|
|
// formats include such an indexed reference (e.g., 21c and 35c).
|
|
enum InstructionIndexType : u1 {
|
|
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)
|
|
kIndexMethodAndProtoRef, // method index and proto index
|
|
kIndexCallSiteRef, // call site index
|
|
kIndexMethodHandleRef, // constant method handle reference index
|
|
kIndexProtoRef, // constant prototype reference index
|
|
};
|
|
|
|
// Holds the contents of a decoded instruction.
|
|
struct Instruction {
|
|
u4 vA; // the A field of the instruction
|
|
u4 vB; // the B field of the instruction
|
|
u8 vB_wide; // 64bit version of the B field (for k51l)
|
|
u4 vC; // the C field of the instruction
|
|
u4 arg[5]; // vC/D/E/F/G in invoke or filled-new-array
|
|
Opcode opcode; // instruction opcode
|
|
};
|
|
|
|
// "packed-switch-payload" format
|
|
struct PackedSwitchPayload {
|
|
u2 ident;
|
|
u2 size;
|
|
s4 first_key;
|
|
s4 targets[];
|
|
};
|
|
|
|
// "sparse-switch-payload" format
|
|
struct SparseSwitchPayload {
|
|
u2 ident;
|
|
u2 size;
|
|
s4 data[];
|
|
};
|
|
|
|
// "fill-array-data-payload" format
|
|
struct ArrayData {
|
|
u2 ident;
|
|
u2 element_width;
|
|
u4 size;
|
|
u1 data[];
|
|
};
|
|
|
|
// Collect the enums in a struct for better locality.
|
|
struct InstructionDescriptor {
|
|
u4 verify_flags; // Set of VerifyFlag.
|
|
InstructionFormat format;
|
|
InstructionIndexType index_type;
|
|
u1 flags; // Set of Flags.
|
|
};
|
|
|
|
// Extracts the opcode from a Dalvik code unit (bytecode)
|
|
Opcode OpcodeFromBytecode(u2 bytecode);
|
|
|
|
// Returns the name of an opcode
|
|
const char* GetOpcodeName(Opcode opcode);
|
|
|
|
// Returns the index type associated with the specified opcode
|
|
InstructionIndexType GetIndexTypeFromOpcode(Opcode opcode);
|
|
|
|
// Returns the format associated with the specified opcode
|
|
InstructionFormat GetFormatFromOpcode(Opcode opcode);
|
|
|
|
// Returns the flags for the specified opcode
|
|
OpcodeFlags GetFlagsFromOpcode(Opcode opcode);
|
|
|
|
// Returns the verify flags for the specified opcode
|
|
VerifyFlags GetVerifyFlagsFromOpcode(Opcode opcode);
|
|
|
|
// Returns the instruction width for the specified opcode format
|
|
size_t GetWidthFromFormat(InstructionFormat format);
|
|
|
|
// 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 GetWidthFromBytecode(const u2* bytecode);
|
|
|
|
// Decode a .dex bytecode
|
|
Instruction DecodeInstruction(const u2* bytecode);
|
|
|
|
} // namespace dex
|