/* radare2 - MIT - Copyright 2024 - NowSecure, Inc. */

#ifndef DALVIK_DALVIK_H
#define DALVIK_DALVIK_H

#include <r_types.h>
#include <r_util/r_buf.h>

// Generated from: https://cs.android.com/android/platform/superproject/main/+/main:art/libdexfile/dex/dex_instruction_list.h;l=21;drc=efb735f4d5a2f04550e33e8aa9485f906018fe4e
//
// const fs = require("fs");
// const buf = fs.readFileSync(process.argv[2]).toString();
// for (let line of buf.split("\n")) {
//     line = line.replace(/\\/g, "").trim();
//     if (line === "") continue;
//     const es = line.split(",");
//     const opcode = es[1].trim();
//     console.log(`DALVIK_OP_${opcode},`)
// }
enum dalvik_op {
	DALVIK_OP_NOP,
	DALVIK_OP_MOVE,
	DALVIK_OP_MOVE_FROM16,
	DALVIK_OP_MOVE_16,
	DALVIK_OP_MOVE_WIDE,
	DALVIK_OP_MOVE_WIDE_FROM16,
	DALVIK_OP_MOVE_WIDE_16,
	DALVIK_OP_MOVE_OBJECT,
	DALVIK_OP_MOVE_OBJECT_FROM16,
	DALVIK_OP_MOVE_OBJECT_16,
	DALVIK_OP_MOVE_RESULT,
	DALVIK_OP_MOVE_RESULT_WIDE,
	DALVIK_OP_MOVE_RESULT_OBJECT,
	DALVIK_OP_MOVE_EXCEPTION,
	DALVIK_OP_RETURN_VOID,
	DALVIK_OP_RETURN,
	DALVIK_OP_RETURN_WIDE,
	DALVIK_OP_RETURN_OBJECT,
	DALVIK_OP_CONST_4,
	DALVIK_OP_CONST_16,
	DALVIK_OP_CONST,
	DALVIK_OP_CONST_HIGH16,
	DALVIK_OP_CONST_WIDE_16,
	DALVIK_OP_CONST_WIDE_32,
	DALVIK_OP_CONST_WIDE,
	DALVIK_OP_CONST_WIDE_HIGH16,
	DALVIK_OP_CONST_STRING,
	DALVIK_OP_CONST_STRING_JUMBO,
	DALVIK_OP_CONST_CLASS,
	DALVIK_OP_MONITOR_ENTER,
	DALVIK_OP_MONITOR_EXIT,
	DALVIK_OP_CHECK_CAST,
	DALVIK_OP_INSTANCE_OF,
	DALVIK_OP_ARRAY_LENGTH,
	DALVIK_OP_NEW_INSTANCE,
	DALVIK_OP_NEW_ARRAY,
	DALVIK_OP_FILLED_NEW_ARRAY,
	DALVIK_OP_FILLED_NEW_ARRAY_RANGE,
	DALVIK_OP_FILL_ARRAY_DATA,
	DALVIK_OP_THROW,
	DALVIK_OP_GOTO,
	DALVIK_OP_GOTO_16,
	DALVIK_OP_GOTO_32,
	DALVIK_OP_PACKED_SWITCH,
	DALVIK_OP_SPARSE_SWITCH,
	DALVIK_OP_CMPL_FLOAT,
	DALVIK_OP_CMPG_FLOAT,
	DALVIK_OP_CMPL_DOUBLE,
	DALVIK_OP_CMPG_DOUBLE,
	DALVIK_OP_CMP_LONG,
	DALVIK_OP_IF_EQ,
	DALVIK_OP_IF_NE,
	DALVIK_OP_IF_LT,
	DALVIK_OP_IF_GE,
	DALVIK_OP_IF_GT,
	DALVIK_OP_IF_LE,
	DALVIK_OP_IF_EQZ,
	DALVIK_OP_IF_NEZ,
	DALVIK_OP_IF_LTZ,
	DALVIK_OP_IF_GEZ,
	DALVIK_OP_IF_GTZ,
	DALVIK_OP_IF_LEZ,
	DALVIK_OP_UNUSED_3E,
	DALVIK_OP_UNUSED_3F,
	DALVIK_OP_UNUSED_40,
	DALVIK_OP_UNUSED_41,
	DALVIK_OP_UNUSED_42,
	DALVIK_OP_UNUSED_43,
	DALVIK_OP_AGET,
	DALVIK_OP_AGET_WIDE,
	DALVIK_OP_AGET_OBJECT,
	DALVIK_OP_AGET_BOOLEAN,
	DALVIK_OP_AGET_BYTE,
	DALVIK_OP_AGET_CHAR,
	DALVIK_OP_AGET_SHORT,
	DALVIK_OP_APUT,
	DALVIK_OP_APUT_WIDE,
	DALVIK_OP_APUT_OBJECT,
	DALVIK_OP_APUT_BOOLEAN,
	DALVIK_OP_APUT_BYTE,
	DALVIK_OP_APUT_CHAR,
	DALVIK_OP_APUT_SHORT,
	DALVIK_OP_IGET,
	DALVIK_OP_IGET_WIDE,
	DALVIK_OP_IGET_OBJECT,
	DALVIK_OP_IGET_BOOLEAN,
	DALVIK_OP_IGET_BYTE,
	DALVIK_OP_IGET_CHAR,
	DALVIK_OP_IGET_SHORT,
	DALVIK_OP_IPUT,
	DALVIK_OP_IPUT_WIDE,
	DALVIK_OP_IPUT_OBJECT,
	DALVIK_OP_IPUT_BOOLEAN,
	DALVIK_OP_IPUT_BYTE,
	DALVIK_OP_IPUT_CHAR,
	DALVIK_OP_IPUT_SHORT,
	DALVIK_OP_SGET,
	DALVIK_OP_SGET_WIDE,
	DALVIK_OP_SGET_OBJECT,
	DALVIK_OP_SGET_BOOLEAN,
	DALVIK_OP_SGET_BYTE,
	DALVIK_OP_SGET_CHAR,
	DALVIK_OP_SGET_SHORT,
	DALVIK_OP_SPUT,
	DALVIK_OP_SPUT_WIDE,
	DALVIK_OP_SPUT_OBJECT,
	DALVIK_OP_SPUT_BOOLEAN,
	DALVIK_OP_SPUT_BYTE,
	DALVIK_OP_SPUT_CHAR,
	DALVIK_OP_SPUT_SHORT,
	DALVIK_OP_INVOKE_VIRTUAL,
	DALVIK_OP_INVOKE_SUPER,
	DALVIK_OP_INVOKE_DIRECT,
	DALVIK_OP_INVOKE_STATIC,
	DALVIK_OP_INVOKE_INTERFACE,
	DALVIK_OP_UNUSED_73,
	DALVIK_OP_INVOKE_VIRTUAL_RANGE,
	DALVIK_OP_INVOKE_SUPER_RANGE,
	DALVIK_OP_INVOKE_DIRECT_RANGE,
	DALVIK_OP_INVOKE_STATIC_RANGE,
	DALVIK_OP_INVOKE_INTERFACE_RANGE,
	DALVIK_OP_UNUSED_79,
	DALVIK_OP_UNUSED_7A,
	DALVIK_OP_NEG_INT,
	DALVIK_OP_NOT_INT,
	DALVIK_OP_NEG_LONG,
	DALVIK_OP_NOT_LONG,
	DALVIK_OP_NEG_FLOAT,
	DALVIK_OP_NEG_DOUBLE,
	DALVIK_OP_INT_TO_LONG,
	DALVIK_OP_INT_TO_FLOAT,
	DALVIK_OP_INT_TO_DOUBLE,
	DALVIK_OP_LONG_TO_INT,
	DALVIK_OP_LONG_TO_FLOAT,
	DALVIK_OP_LONG_TO_DOUBLE,
	DALVIK_OP_FLOAT_TO_INT,
	DALVIK_OP_FLOAT_TO_LONG,
	DALVIK_OP_FLOAT_TO_DOUBLE,
	DALVIK_OP_DOUBLE_TO_INT,
	DALVIK_OP_DOUBLE_TO_LONG,
	DALVIK_OP_DOUBLE_TO_FLOAT,
	DALVIK_OP_INT_TO_BYTE,
	DALVIK_OP_INT_TO_CHAR,
	DALVIK_OP_INT_TO_SHORT,
	DALVIK_OP_ADD_INT,
	DALVIK_OP_SUB_INT,
	DALVIK_OP_MUL_INT,
	DALVIK_OP_DIV_INT,
	DALVIK_OP_REM_INT,
	DALVIK_OP_AND_INT,
	DALVIK_OP_OR_INT,
	DALVIK_OP_XOR_INT,
	DALVIK_OP_SHL_INT,
	DALVIK_OP_SHR_INT,
	DALVIK_OP_USHR_INT,
	DALVIK_OP_ADD_LONG,
	DALVIK_OP_SUB_LONG,
	DALVIK_OP_MUL_LONG,
	DALVIK_OP_DIV_LONG,
	DALVIK_OP_REM_LONG,
	DALVIK_OP_AND_LONG,
	DALVIK_OP_OR_LONG,
	DALVIK_OP_XOR_LONG,
	DALVIK_OP_SHL_LONG,
	DALVIK_OP_SHR_LONG,
	DALVIK_OP_USHR_LONG,
	DALVIK_OP_ADD_FLOAT,
	DALVIK_OP_SUB_FLOAT,
	DALVIK_OP_MUL_FLOAT,
	DALVIK_OP_DIV_FLOAT,
	DALVIK_OP_REM_FLOAT,
	DALVIK_OP_ADD_DOUBLE,
	DALVIK_OP_SUB_DOUBLE,
	DALVIK_OP_MUL_DOUBLE,
	DALVIK_OP_DIV_DOUBLE,
	DALVIK_OP_REM_DOUBLE,
	DALVIK_OP_ADD_INT_2ADDR,
	DALVIK_OP_SUB_INT_2ADDR,
	DALVIK_OP_MUL_INT_2ADDR,
	DALVIK_OP_DIV_INT_2ADDR,
	DALVIK_OP_REM_INT_2ADDR,
	DALVIK_OP_AND_INT_2ADDR,
	DALVIK_OP_OR_INT_2ADDR,
	DALVIK_OP_XOR_INT_2ADDR,
	DALVIK_OP_SHL_INT_2ADDR,
	DALVIK_OP_SHR_INT_2ADDR,
	DALVIK_OP_USHR_INT_2ADDR,
	DALVIK_OP_ADD_LONG_2ADDR,
	DALVIK_OP_SUB_LONG_2ADDR,
	DALVIK_OP_MUL_LONG_2ADDR,
	DALVIK_OP_DIV_LONG_2ADDR,
	DALVIK_OP_REM_LONG_2ADDR,
	DALVIK_OP_AND_LONG_2ADDR,
	DALVIK_OP_OR_LONG_2ADDR,
	DALVIK_OP_XOR_LONG_2ADDR,
	DALVIK_OP_SHL_LONG_2ADDR,
	DALVIK_OP_SHR_LONG_2ADDR,
	DALVIK_OP_USHR_LONG_2ADDR,
	DALVIK_OP_ADD_FLOAT_2ADDR,
	DALVIK_OP_SUB_FLOAT_2ADDR,
	DALVIK_OP_MUL_FLOAT_2ADDR,
	DALVIK_OP_DIV_FLOAT_2ADDR,
	DALVIK_OP_REM_FLOAT_2ADDR,
	DALVIK_OP_ADD_DOUBLE_2ADDR,
	DALVIK_OP_SUB_DOUBLE_2ADDR,
	DALVIK_OP_MUL_DOUBLE_2ADDR,
	DALVIK_OP_DIV_DOUBLE_2ADDR,
	DALVIK_OP_REM_DOUBLE_2ADDR,
	DALVIK_OP_ADD_INT_LIT16,
	DALVIK_OP_RSUB_INT,
	DALVIK_OP_MUL_INT_LIT16,
	DALVIK_OP_DIV_INT_LIT16,
	DALVIK_OP_REM_INT_LIT16,
	DALVIK_OP_AND_INT_LIT16,
	DALVIK_OP_OR_INT_LIT16,
	DALVIK_OP_XOR_INT_LIT16,
	DALVIK_OP_ADD_INT_LIT8,
	DALVIK_OP_RSUB_INT_LIT8,
	DALVIK_OP_MUL_INT_LIT8,
	DALVIK_OP_DIV_INT_LIT8,
	DALVIK_OP_REM_INT_LIT8,
	DALVIK_OP_AND_INT_LIT8,
	DALVIK_OP_OR_INT_LIT8,
	DALVIK_OP_XOR_INT_LIT8,
	DALVIK_OP_SHL_INT_LIT8,
	DALVIK_OP_SHR_INT_LIT8,
	DALVIK_OP_USHR_INT_LIT8,
	DALVIK_OP_UNUSED_E3,
	DALVIK_OP_UNUSED_E4,
	DALVIK_OP_UNUSED_E5,
	DALVIK_OP_UNUSED_E6,
	DALVIK_OP_UNUSED_E7,
	DALVIK_OP_UNUSED_E8,
	DALVIK_OP_UNUSED_E9,
	DALVIK_OP_UNUSED_EA,
	DALVIK_OP_UNUSED_EB,
	DALVIK_OP_UNUSED_EC,
	DALVIK_OP_UNUSED_ED,
	DALVIK_OP_UNUSED_EE,
	DALVIK_OP_UNUSED_EF,
	DALVIK_OP_UNUSED_F0,
	DALVIK_OP_UNUSED_F1,
	DALVIK_OP_UNUSED_F2,
	DALVIK_OP_UNUSED_F3,
	DALVIK_OP_UNUSED_F4,
	DALVIK_OP_UNUSED_F5,
	DALVIK_OP_UNUSED_F6,
	DALVIK_OP_UNUSED_F7,
	DALVIK_OP_UNUSED_F8,
	DALVIK_OP_UNUSED_F9,
	DALVIK_OP_INVOKE_POLYMORPHIC,
	DALVIK_OP_INVOKE_POLYMORPHIC_RANGE,
	DALVIK_OP_INVOKE_CUSTOM,
	DALVIK_OP_INVOKE_CUSTOM_RANGE,
	DALVIK_OP_CONST_METHOD_HANDLE,
	DALVIK_OP_CONST_METHOD_TYPE,
	DALVIK_OP_MAX,
};

enum dalvik_pseudo_op {
	DALVIK_PSEUDO_OP_PACKED_SWITCH_PAYLOAD = 1,
	DALVIK_PSEUDO_OP_SPARSE_SWITCH_PAYLOAD,
	DALVIK_PSEUDO_OP_FILL_ARRAY_DATA_PAYLOAD,
};

struct dalvik_payload {
	enum dalvik_pseudo_op op;
	union {
		struct {
			ut16 len;
			st32 first_key;
			st32 *targets;
		} packed_switch;
		struct {
			ut16 len;
			st32 *keys;
			st32 *targets;
		} sparse_switch;
		struct {
			ut16 element_width;
			ut32 len;
			ut8 *data;
		} fill_array_data;
	};
};

enum dalvik_fmt {
	DALVIK_FMT_10X,
	DALVIK_FMT_12X,
	DALVIK_FMT_11N,
	DALVIK_FMT_11X,
	DALVIK_FMT_10T,
	DALVIK_FMT_20T,
	DALVIK_FMT_22X,
	DALVIK_FMT_21T,
	DALVIK_FMT_21S,
	DALVIK_FMT_21H,
	DALVIK_FMT_21C,
	DALVIK_FMT_23X,
	DALVIK_FMT_22B,
	DALVIK_FMT_22T,
	DALVIK_FMT_22S,
	DALVIK_FMT_22C,
	DALVIK_FMT_32X,
	DALVIK_FMT_30T,
	DALVIK_FMT_31T,
	DALVIK_FMT_31I,
	DALVIK_FMT_31C,
	DALVIK_FMT_35C,
	DALVIK_FMT_3RC,
	DALVIK_FMT_45CC,
	DALVIK_FMT_4RCC,
	DALVIK_FMT_51L,
	DALVIK_FMT_MAX,
};

struct dalvik_op_detail {
	const char *name;
	enum dalvik_fmt fmt;
};

struct dalvik_instr {
	enum dalvik_op op;
	union {
		struct {
			ut8 a;
		} f10x;
		struct {
			ut8 a : 4;
			ut8 b : 4;
		} f12x;
		struct {
			ut8 a;
		} f11x;
		struct {
			ut16 a;
		} f20t;
		struct {
			ut8 a;
			ut16 b;
		} f22x;
		struct {
			ut8 a;
			ut8 c;
			ut8 b;
		} f23x;
		struct {
			ut8 a : 4;
			ut8 b : 4;
			ut16 c;
		} f22t;
		struct {
			ut16 a;
			ut16 b;
		} f32x;
		struct {
			ut32 a;
		} f30t;
		struct {
			ut8 a;
			ut32 b;
		} f31i;
		struct {
			ut8 a : 4;
			ut8 g : 4;
			ut16 b;
			ut8 f : 4;
			ut8 e : 4;
			ut8 d : 4;
			ut8 c : 4;
		} f35c;
		struct {
			ut8 a;
			ut16 b;
			ut16 c;
		} f3rc;
		struct {
			ut8 a : 4;
			ut8 g : 4;
			ut16 b;
			ut8 f : 4;
			ut8 e : 4;
			ut8 d : 4;
			ut8 c : 4;
			ut16 h;
		} f45cc;
		struct {
			ut8 a;
			ut16 b;
			ut16 c;
			ut16 h;
		} f4rcc;
		struct {
			ut8 a;
			ut64 b;
		} f51l;
	};
};

static bool dalvik_read_instr(RBuffer *buf, struct dalvik_instr *instr);
static bool dalvik_read_payload(RBuffer *buf, const struct dalvik_instr *instr, struct dalvik_payload *payload);
static void dalvik_payload_fini(struct dalvik_payload *payload);

static const struct dalvik_op_detail dalvik_opcodes[DALVIK_OP_MAX];

#endif /* DALVIK_DALVIK_H */
