libredex/DexOpcode.cpp (469 lines of code) (raw):

/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #include "DexOpcode.h" #include "Debug.h" #include "Show.h" namespace dex_opcode { // clang-format off OpcodeFormat format(DexOpcode opcode) { switch (opcode) { #define OP(op, code, fmt, ...) \ case code: \ return FMT_##fmt; DOPS #undef OP case FOPCODE_PACKED_SWITCH : return FMT_fopcode; case FOPCODE_SPARSE_SWITCH: return FMT_fopcode; case FOPCODE_FILLED_ARRAY: return FMT_fopcode; #define OP(op, code, fmt, ...) \ case code: \ not_reached_log("Unexpected quick opcode 0x%x", opcode); QDOPS #undef OP } not_reached_log("Unexpected opcode 0x%x", opcode); } // clang-format on bool dest_is_src(DexOpcode op) { return format(op) == FMT_f12x_2; } bool has_literal(DexOpcode op) { auto fmt = format(op); switch (fmt) { case FMT_f11n: case FMT_f21s: case FMT_f21h: case FMT_f22b: case FMT_f22s: case FMT_f31i: case FMT_f51l: return true; default: return false; } not_reached(); } bool has_offset(DexOpcode op) { switch (format(op)) { case FMT_f10t: case FMT_f20t: case FMT_f21t: case FMT_f22t: case FMT_f30t: case FMT_f31t: return true; default: return false; } not_reached(); } bool has_range(DexOpcode op) { auto fmt = format(op); return fmt == FMT_f3rc || fmt == FMT_f5rc; } bool is_commutative(DexOpcode op) { return op == DOPCODE_ADD_INT || op == DOPCODE_MUL_INT || (op >= DOPCODE_AND_INT && op <= DOPCODE_XOR_INT) || op == DOPCODE_ADD_LONG || op == DOPCODE_MUL_LONG || (op >= DOPCODE_AND_LONG && op <= DOPCODE_XOR_LONG) || op == DOPCODE_ADD_FLOAT || op == DOPCODE_MUL_FLOAT || op == DOPCODE_ADD_DOUBLE || op == DOPCODE_MUL_DOUBLE; } bool is_branch(DexOpcode op) { switch (op) { case DOPCODE_PACKED_SWITCH: case DOPCODE_SPARSE_SWITCH: case DOPCODE_GOTO_32: case DOPCODE_IF_EQ: case DOPCODE_IF_NE: case DOPCODE_IF_LT: case DOPCODE_IF_GE: case DOPCODE_IF_GT: case DOPCODE_IF_LE: case DOPCODE_IF_EQZ: case DOPCODE_IF_NEZ: case DOPCODE_IF_LTZ: case DOPCODE_IF_GEZ: case DOPCODE_IF_GTZ: case DOPCODE_IF_LEZ: case DOPCODE_GOTO_16: case DOPCODE_GOTO: return true; default: return false; } } bool is_conditional_branch(DexOpcode op) { switch (op) { case DOPCODE_IF_EQ: case DOPCODE_IF_NE: case DOPCODE_IF_LT: case DOPCODE_IF_GE: case DOPCODE_IF_GT: case DOPCODE_IF_LE: case DOPCODE_IF_EQZ: case DOPCODE_IF_NEZ: case DOPCODE_IF_LTZ: case DOPCODE_IF_GEZ: case DOPCODE_IF_GTZ: case DOPCODE_IF_LEZ: return true; default: return false; } } bool is_goto(DexOpcode op) { switch (op) { case DOPCODE_GOTO_32: case DOPCODE_GOTO_16: case DOPCODE_GOTO: return true; default: return false; } } bool is_move(DexOpcode op) { return op >= DOPCODE_MOVE && op <= DOPCODE_MOVE_OBJECT_16; } DexOpcode invert_conditional_branch(DexOpcode op) { switch (op) { case DOPCODE_IF_EQ: return DOPCODE_IF_NE; case DOPCODE_IF_NE: return DOPCODE_IF_EQ; case DOPCODE_IF_LT: return DOPCODE_IF_GE; case DOPCODE_IF_GE: return DOPCODE_IF_LT; case DOPCODE_IF_GT: return DOPCODE_IF_LE; case DOPCODE_IF_LE: return DOPCODE_IF_GT; case DOPCODE_IF_EQZ: return DOPCODE_IF_NEZ; case DOPCODE_IF_NEZ: return DOPCODE_IF_EQZ; case DOPCODE_IF_LTZ: return DOPCODE_IF_GEZ; case DOPCODE_IF_GEZ: return DOPCODE_IF_LTZ; case DOPCODE_IF_GTZ: return DOPCODE_IF_LEZ; case DOPCODE_IF_LEZ: return DOPCODE_IF_GTZ; default: not_reached_log("Invalid conditional opcode %s", SHOW(op)); } } bit_width_t src_bit_width(DexOpcode op, uint16_t i) { switch (dex_opcode::format(op)) { case FMT_f00x: not_reached(); case FMT_f10x: not_reached(); case FMT_f12x: redex_assert(i == 0); return 4; case FMT_f12x_2: redex_assert(i <= 1); return 4; case FMT_f11n: not_reached(); case FMT_f11x_d: not_reached(); case FMT_f11x_s: redex_assert(i == 0); return 8; case FMT_f10t: not_reached(); case FMT_f20t: not_reached(); case FMT_f20bc: not_reached(); case FMT_f22x: redex_assert(i == 0); return 16; case FMT_f21t: redex_assert(i == 0); return 8; case FMT_f21s: not_reached(); case FMT_f21h: not_reached(); case FMT_f21c_d: not_reached(); case FMT_f21c_s: redex_assert(i == 0); return 8; case FMT_f23x_d: redex_assert(i <= 1); return 8; case FMT_f23x_s: redex_assert(i <= 2); return 8; case FMT_f22b: redex_assert(i == 0); return 8; case FMT_f22t: redex_assert(i <= 1); return 4; case FMT_f22s: redex_assert(i == 0); return 4; case FMT_f22c_d: redex_assert(i == 0); return 4; case FMT_f22c_s: redex_assert(i <= 1); return 4; case FMT_f22cs: not_reached(); case FMT_f30t: not_reached(); case FMT_f32x: redex_assert(i == 0); return 16; case FMT_f31i: not_reached(); case FMT_f31t: redex_assert(i == 0); return 8; case FMT_f31c: not_reached(); case FMT_f35c: redex_assert(i <= 4); return 4; case FMT_f3rc: redex_assert(i == 0); return 16; case FMT_f41c_d: not_reached(); case FMT_f41c_s: redex_assert(i == 0); return 16; case FMT_f45cc: redex_assert(i <= 4); return 4; case FMT_f4rcc: redex_assert(i == 0); return 16; case FMT_f52c_d: redex_assert(i == 0); return 16; case FMT_f52c_s: redex_assert(i <= 1); return 16; case FMT_f5rc: redex_assert(i == 0); return 16; case FMT_f57c: redex_assert(i <= 6); return 4; case FMT_f35ms: case FMT_f35mi: case FMT_f3rms: case FMT_f3rmi: case FMT_f51l: case FMT_fopcode: case FMT_iopcode: not_reached(); } not_reached(); } bit_width_t dest_bit_width(DexOpcode op) { switch (dex_opcode::format(op)) { case FMT_f00x: not_reached(); case FMT_f10x: not_reached(); case FMT_f12x: return 4; case FMT_f12x_2: return 4; case FMT_f11n: return 4; case FMT_f11x_d: return 8; case FMT_f11x_s: not_reached(); case FMT_f10t: not_reached(); case FMT_f20t: not_reached(); case FMT_f20bc: not_reached(); case FMT_f22x: return 8; case FMT_f21t: not_reached(); case FMT_f21s: return 8; case FMT_f21h: return 8; case FMT_f21c_d: return 8; case FMT_f21c_s: not_reached(); case FMT_f23x_d: return 8; case FMT_f23x_s: not_reached(); case FMT_f22b: return 8; case FMT_f22t: not_reached(); case FMT_f22s: return 4; case FMT_f22c_d: return 4; case FMT_f22c_s: not_reached(); case FMT_f22cs: not_reached(); case FMT_f30t: not_reached(); case FMT_f32x: return 16; case FMT_f31i: return 8; case FMT_f31t: not_reached(); case FMT_f31c: return 8; case FMT_f35c: not_reached(); case FMT_f35ms: case FMT_f35mi: case FMT_f3rc: case FMT_f3rms: case FMT_f3rmi: not_reached(); case FMT_f51l: return 8; case FMT_f41c_d: return 16; case FMT_f41c_s: case FMT_f45cc: case FMT_f4rcc: not_reached(); case FMT_f52c_d: return 16; case FMT_f52c_s: not_reached(); case FMT_f5rc: not_reached(); case FMT_f57c: not_reached(); case FMT_fopcode: not_reached(); case FMT_iopcode: return 16; } not_reached(); } bool has_dest(DexOpcode op) { switch (dex_opcode::format(op)) { case FMT_f00x: case FMT_f10x: case FMT_f11x_s: case FMT_f10t: case FMT_f20t: case FMT_f21t: case FMT_f21c_s: case FMT_f23x_s: case FMT_f22t: case FMT_f22c_s: case FMT_f30t: case FMT_f31t: case FMT_f35c: case FMT_f3rc: case FMT_f41c_s: case FMT_f45cc: case FMT_f4rcc: case FMT_f52c_s: case FMT_f5rc: case FMT_f57c: case FMT_fopcode: return false; case FMT_f12x: case FMT_f12x_2: case FMT_f11n: case FMT_f11x_d: case FMT_f22x: case FMT_f21s: case FMT_f21h: case FMT_f21c_d: case FMT_f23x_d: case FMT_f22b: case FMT_f22s: case FMT_f22c_d: case FMT_f32x: case FMT_f31i: case FMT_f31c: case FMT_f51l: case FMT_f41c_d: case FMT_f52c_d: case FMT_iopcode: return true; case FMT_f20bc: case FMT_f22cs: case FMT_f35ms: case FMT_f35mi: case FMT_f3rms: case FMT_f3rmi: not_reached_log("Unimplemented opcode `%s'", SHOW(op)); } } unsigned min_srcs_size(DexOpcode op) { switch (dex_opcode::format(op)) { case FMT_f00x: case FMT_f10x: case FMT_f11n: case FMT_f11x_d: case FMT_f10t: case FMT_f20t: case FMT_f21s: case FMT_f21h: case FMT_f21c_d: case FMT_f30t: case FMT_f31i: case FMT_f31c: case FMT_f3rc: case FMT_f51l: case FMT_f5rc: case FMT_f41c_d: case FMT_f4rcc: case FMT_fopcode: case FMT_iopcode: return 0; case FMT_f12x: case FMT_f11x_s: case FMT_f22x: case FMT_f21t: case FMT_f21c_s: case FMT_f22b: case FMT_f22s: case FMT_f22c_d: case FMT_f32x: case FMT_f31t: case FMT_f41c_s: case FMT_f52c_d: return 1; case FMT_f12x_2: case FMT_f23x_d: case FMT_f22t: case FMT_f22c_s: case FMT_f52c_s: return 2; case FMT_f23x_s: return 3; case FMT_f35c: case FMT_f45cc: case FMT_f57c: return 0; case FMT_f20bc: case FMT_f22cs: case FMT_f35ms: case FMT_f35mi: case FMT_f3rms: case FMT_f3rmi: not_reached_log("Unimplemented opcode `%s'", SHOW(op)); } } } // namespace dex_opcode