1#include "r_anal.h"
2static int hack_handle_dp_reg(ut32 insn, RAnalOp *op) {
3	const bool op0 = (insn >> 30) & 0x1;
4	const bool op1 = (insn >> 28) & 0x1;
5	const ut8 op2 = (insn >> 21) & 0xf;
6
7	// Data-processing (2 source)
8	if (!op0 && op1 && op2 == 6) {
9		const bool sf = (insn >> 31) & 0x1;
10		const bool S = (insn >> 29) & 0x1;
11		const ut8 opcode = (insn >> 10) & 0x1f;
12		if (sf) {
13			if (!S) {
14				if (opcode == 4) {
15					// irg
16					op->type = R_ANAL_OP_TYPE_MOV;
17					return op->size = 4;
18				} else if (opcode == 0) {
19					// subp
20					op->type = R_ANAL_OP_TYPE_SUB;
21					return op->size = 4;
22				} else if (opcode == 5) {
23					// gmi
24					op->type = R_ANAL_OP_TYPE_MOV;
25					return op->size = 4;
26				}
27			} else if (S && opcode == 0) {
28				// subps
29				op->type = R_ANAL_OP_TYPE_SUB;
30				return op->size = 4;
31			}
32		}
33	}
34	return -1;
35}
36
37static int hack_handle_ldst(ut32 insn, RAnalOp *op) {
38	const ut8 op0 = (insn >> 28) & 0xf;
39	const bool op1 = (insn >> 26) & 0x1;
40	ut8 op2 = (insn >> 23) & 0x3;
41	const bool op3 = (insn >> 21) & 0x1;
42
43	// Load/store memory tags
44	if (op0 == 13 && !op1 && (op2 == 2 || op2 == 3) && op3) {
45		const ut8 opc = (insn >> 22) & 0x3;
46		op2 = (insn >> 10) & 0x3;
47		if (op2 > 0) {
48			switch (opc) {
49			case 0:
50				// stg
51				op->type = R_ANAL_OP_TYPE_STORE;
52				return op->size = 4;
53			case 1:
54				// stzg
55				op->type = R_ANAL_OP_TYPE_STORE;
56				return op->size = 4;
57			case 2:
58				// st2g
59				op->type = R_ANAL_OP_TYPE_STORE;
60				return op->size = 4;
61			case 3:
62				// stz2g
63				op->type = R_ANAL_OP_TYPE_STORE;
64				return op->size = 4;
65			}
66		} else if (op2 == 0) {
67			switch (opc) {
68			case 0:
69				// stzgm
70				op->type = R_ANAL_OP_TYPE_STORE;
71				return op->size = 4;
72			case 1:
73				// ldg
74				op->type = R_ANAL_OP_TYPE_LOAD;
75				return op->size = 4;
76			case 2:
77				// stgm
78				op->type = R_ANAL_OP_TYPE_STORE;
79				return op->size = 4;
80			case 3:
81				// ldgm
82				op->type = R_ANAL_OP_TYPE_LOAD;
83				return op->size = 4;
84			}
85		}
86	// Load/store register pair
87	} else if ((op0 & 0x3) == 2) {
88		const ut8 opc = (insn >> 30) & 0x3;
89		const bool V = (insn >> 26) & 0x1;
90		const bool L = (insn >> 22) & 0x1;
91		if (opc == 1 && !V && !L) {
92			// stgp
93			op->type = R_ANAL_OP_TYPE_STORE;
94			return op->size = 4;
95		}
96	}
97	return -1;
98}
99
100static int hack_handle_dp_imm(ut32 insn, RAnalOp *op) {
101	const ut8 op0 = (insn >> 23) & 0x7;
102
103	// Add/subtract (immediate, with tags)
104	if (op0 == 3) {
105		const bool sf = (insn >> 31) & 0x1;
106		const bool op_ = (insn >> 30) & 0x1;
107		const bool S = (insn >> 29) & 0x1;
108		const bool o2 = (insn >> 22) & 0x1;
109		if (sf && !S && !o2) {
110			if (op_ ) {
111				// subg
112				op->type = R_ANAL_OP_TYPE_SUB;
113				return op->size = 4;
114			}
115			// addg
116			op->type = R_ANAL_OP_TYPE_ADD;
117			return op->size = 4;
118		}
119	}
120	return -1;
121}
122
123static int hack_handle_br_exc_sys(ut32 insn, RAnalOp *op) {
124	const ut8 op0 = (insn >> 29) & 0x7;
125	const ut16 op1 = (insn >> 12) & 0x3fff;
126	ut8 op2 = insn & 0x1f;
127
128	// Hints
129	if (op0 == 6 && op1 == 4146 && op2 == 31) {
130		const ut8 CRm = (insn >> 8) & 0xf;
131		op2 = (insn >> 5) & 0x7;
132		if (CRm == 4 && (op2 & 1) == 0) {
133			switch (op2) {
134			case 0:
135			case 2:
136			case 4:
137			case 6:
138				op->type = R_ANAL_OP_TYPE_CMP;
139				return op->size = 4;
140			}
141		}
142	}
143	return -1;
144}
145
146static inline int hackyArmAnal(RAnal *a, RAnalOp *op, const ut8 *buf, int len) {
147	int ret = -1;
148	// Hacky support for ARMv8.3 and ARMv8.5
149	if (a->bits == 64 && len >= 4) {
150		ut32 insn = r_read_ble32 (buf, a->big_endian);
151		int insn_class = (insn >> 25) & 0xf;
152		// xpaci // e#43c1da
153		if (!memcmp (buf + 1, "\x43\xc1\xda", 3)) {
154			op->type = R_ANAL_OP_TYPE_MOV;
155			return op->size = 4;
156		}
157		// retaa
158		if (!memcmp (buf, "\xff\x0b\x5f\xd6", 4)) {
159			op->type = R_ANAL_OP_TYPE_RET;
160			return op->size = 4;
161		}
162		// retab
163		if (!memcmp (buf, "\xff\x0f\x5f\xd6", 4)) {
164			op->type = R_ANAL_OP_TYPE_RET;
165			return op->size = 4;
166		}
167
168		switch (insn_class) {
169		// Data Processing -- Register
170		case 5:
171		case 13:
172			// irg, subp, gmi, subps
173			ret = hack_handle_dp_reg (insn, op);
174			break;
175		// Data Processing -- Immediate
176		case 8:
177		case 9:
178			// addg, subg
179			ret = hack_handle_dp_imm (insn, op);
180			break;
181		case 10:
182		case 11:
183			// bti
184			ret = hack_handle_br_exc_sys (insn, op);
185			break;
186		// Loads and Stores
187		case 4:
188		case 6:
189		case 12:
190		case 14:
191			// stg, stzgm, ldg, stzg, st2g, stgm, stz2g, ldgm, stgp
192			ret = hack_handle_ldst (insn, op);
193			break;
194		default:
195			break;
196		}
197
198		if (ret > 0) {
199			op->family = R_ANAL_OP_FAMILY_SECURITY;
200		}
201
202	}
203	return ret;
204}
205