src/arm/decoder.c (view raw)
1#include "decoder.h"
2
3#include "decoder-inlines.h"
4
5#define ADVANCE(AMOUNT) \
6 if (AMOUNT > blen) { \
7 buffer[blen - 1] = '\0'; \
8 return total; \
9 } \
10 total += AMOUNT; \
11 buffer += AMOUNT; \
12 blen -= AMOUNT;
13
14static int _decodeRegister(int reg, char* buffer, int blen);
15static int _decodeRegisterList(int list, char* buffer, int blen);
16static int _decodePCRelative(uint32_t address, uint32_t pc, char* buffer, int blen);
17static int _decodeMemory(struct ARMMemoryAccess memory, int pc, char* buffer, int blen);
18
19static const char* _armConditions[] = {
20 "eq",
21 "ne",
22 "cs",
23 "cc",
24 "mi",
25 "pl",
26 "vs",
27 "vc",
28 "hi",
29 "ls",
30 "ge",
31 "lt",
32 "gt",
33 "le",
34 "al",
35 "nv"
36};
37
38static int _decodeRegister(int reg, char* buffer, int blen) {
39 switch (reg) {
40 case ARM_SP:
41 strncpy(buffer, "sp", blen - 1);
42 return 2;
43 case ARM_LR:
44 strncpy(buffer, "lr", blen - 1);
45 return 2;
46 case ARM_PC:
47 strncpy(buffer, "pc", blen - 1);
48 return 2;
49 default:
50 return snprintf(buffer, blen - 1, "r%i", reg);
51 }
52}
53
54static int _decodeRegisterList(int list, char* buffer, int blen) {
55 if (blen <= 0) {
56 return 0;
57 }
58 int total = 0;
59 strncpy(buffer, "{", blen - 1);
60 ADVANCE(1);
61 int i;
62 int start = -1;
63 int end = -1;
64 int written;
65 for (i = 0; i <= ARM_PC; ++i) {
66 if (list & 1) {
67 if (start < 0) {
68 start = i;
69 end = i;
70 } else if (end + 1 == i) {
71 end = i;
72 } else {
73 if (end > start) {
74 written = _decodeRegister(start, buffer, blen);
75 ADVANCE(written);
76 strncpy(buffer, "-", blen - 1);
77 ADVANCE(1);
78 }
79 written = _decodeRegister(end, buffer, blen);
80 ADVANCE(written);
81 strncpy(buffer, ",", blen - 1);
82 ADVANCE(1);
83 start = i;
84 end = i;
85 }
86 }
87 list >>= 1;
88 }
89 if (start >= 0) {
90 if (end > start) {
91 written = _decodeRegister(start, buffer, blen);
92 ADVANCE(written);
93 strncpy(buffer, "-", blen - 1);
94 ADVANCE(1);
95 }
96 written = _decodeRegister(end, buffer, blen);
97 ADVANCE(written);
98 }
99 strncpy(buffer, "}", blen - 1);
100 ADVANCE(1);
101 return total;
102}
103
104static int _decodePCRelative(uint32_t address, uint32_t pc, char* buffer, int blen) {
105 return snprintf(buffer, blen - 1, "$%08X", address + pc);
106}
107
108static int _decodeMemory(struct ARMMemoryAccess memory, int pc, char* buffer, int blen) {
109 if (blen <= 1) {
110 return 0;
111 }
112 int total = 0;
113 strncpy(buffer, "[", blen - 1);
114 ADVANCE(1);
115 int written;
116 if (memory.format & ARM_MEMORY_REGISTER_BASE) {
117 if (memory.baseReg == ARM_PC && memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) {
118 written = _decodePCRelative(memory.offset.immediate, pc, buffer, blen);
119 ADVANCE(written);
120 } else {
121 written = _decodeRegister(memory.baseReg, buffer, blen);
122 ADVANCE(written);
123 if (memory.format & (ARM_MEMORY_REGISTER_OFFSET | ARM_MEMORY_IMMEDIATE_OFFSET) && !(memory.format & ARM_MEMORY_POST_INCREMENT)) {
124 strncpy(buffer, ", ", blen - 1);
125 ADVANCE(2);
126 }
127 }
128 }
129 if (memory.format & ARM_MEMORY_POST_INCREMENT) {
130 strncpy(buffer, "], ", blen - 1);
131 ADVANCE(3);
132 }
133 if (memory.format & ARM_MEMORY_IMMEDIATE_OFFSET && memory.baseReg != ARM_PC) {
134 if (memory.format & ARM_MEMORY_OFFSET_SUBTRACT) {
135 written = snprintf(buffer, blen - 1, "#-%i", memory.offset.immediate);
136 ADVANCE(written);
137 } else {
138 written = snprintf(buffer, blen - 1, "#%i", memory.offset.immediate);
139 ADVANCE(written);
140 }
141 } else if (memory.format & ARM_MEMORY_REGISTER_OFFSET) {
142 if (memory.format & ARM_MEMORY_OFFSET_SUBTRACT) {
143 strncpy(buffer, "-", blen - 1);
144 ADVANCE(1);
145 }
146 written = _decodeRegister(memory.offset.reg, buffer, blen);
147 ADVANCE(written);
148 }
149 // TODO: shifted registers
150
151 if (!(memory.format & ARM_MEMORY_POST_INCREMENT)) {
152 strncpy(buffer, "]", blen - 1);
153 ADVANCE(1);
154 }
155 if ((memory.format & (ARM_MEMORY_PRE_INCREMENT | ARM_MEMORY_WRITEBACK)) == (ARM_MEMORY_PRE_INCREMENT | ARM_MEMORY_WRITEBACK)) {
156 strncpy(buffer, "!", blen - 1);
157 ADVANCE(1);
158 }
159 return total;
160}
161
162static const char* _armMnemonicStrings[] = {
163 "ill",
164 "adc",
165 "add",
166 "and",
167 "asr",
168 "b",
169 "bic",
170 "bkpt",
171 "bl",
172 "blh",
173 "bx",
174 "cmn",
175 "cmp",
176 "eor",
177 "ldm",
178 "ldr",
179 "lsl",
180 "lsr",
181 "mla",
182 "mov",
183 "mrs",
184 "msr",
185 "mul",
186 "mvn",
187 "neg",
188 "orr",
189 "ror",
190 "rsb",
191 "rsc",
192 "sbc",
193 "smlal",
194 "smull",
195 "stm",
196 "str",
197 "sub",
198 "swi",
199 "swp",
200 "teq",
201 "tst",
202 "umlal",
203 "umull",
204
205 "ill"
206};
207
208static const char* _armDirectionStrings[] = {
209 "da",
210 "ia",
211 "db",
212 "da"
213};
214
215static const char* _armAccessTypeStrings[] = {
216 "",
217 "b",
218 "h",
219 "",
220 "",
221 "",
222 "",
223 "",
224 "",
225 "sb",
226 "sh",
227 ""
228 ""
229};
230
231int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, int blen) {
232 const char* mnemonic = _armMnemonicStrings[info->mnemonic];
233 int written;
234 int total = 0;
235 const char* cond = "";
236 if (info->condition != ARM_CONDITION_AL && info->condition < ARM_CONDITION_NV) {
237 cond = _armConditions[info->condition];
238 }
239 const char* flags = "";
240 switch (info->mnemonic) {
241 case ARM_MN_LDM:
242 case ARM_MN_STM:
243 flags = _armDirectionStrings[MEMORY_FORMAT_TO_DIRECTION(info->memory.format)];
244 break;
245 case ARM_MN_LDR:
246 case ARM_MN_STR:
247 case ARM_MN_SWP:
248 flags = _armAccessTypeStrings[info->memory.width];
249 break;
250 default:
251 break;
252 }
253 written = snprintf(buffer, blen - 1, "%s%s%s ", mnemonic, cond, flags);
254 ADVANCE(written);
255
256 switch (info->mnemonic) {
257 case ARM_MN_LDM:
258 case ARM_MN_STM:
259 written = _decodeRegister(info->memory.baseReg, buffer, blen);
260 ADVANCE(written);
261 if (info->memory.format & ARM_MEMORY_WRITEBACK) {
262 strncpy(buffer, "!", blen - 1);
263 ADVANCE(1);
264 }
265 strncpy(buffer, ", ", blen - 1);
266 ADVANCE(2);
267 written = _decodeRegisterList(info->op1.immediate, buffer, blen);
268 ADVANCE(written);
269 break;
270 case ARM_MN_B:
271 written = _decodePCRelative(info->op1.immediate, pc, buffer, blen);
272 ADVANCE(written);
273 break;
274 default:
275 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) {
276 written = snprintf(buffer, blen - 1, "#%i", info->op1.immediate);
277 ADVANCE(written);
278 } else if (info->operandFormat & ARM_OPERAND_MEMORY_1) {
279 written = _decodeMemory(info->memory, pc, buffer, blen);
280 ADVANCE(written);
281 } else if (info->operandFormat & ARM_OPERAND_REGISTER_1) {
282 written = _decodeRegister(info->op1.reg, buffer, blen);
283 ADVANCE(written);
284 }
285 if (info->operandFormat & ARM_OPERAND_2) {
286 strncpy(buffer, ", ", blen);
287 ADVANCE(2);
288 }
289 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_2) {
290 written = snprintf(buffer, blen - 1, "#%i", info->op2.immediate);
291 ADVANCE(written);
292 } else if (info->operandFormat & ARM_OPERAND_MEMORY_2) {
293 written = _decodeMemory(info->memory, pc, buffer, blen);
294 ADVANCE(written);
295 } else if (info->operandFormat & ARM_OPERAND_REGISTER_2) {
296 written = _decodeRegister(info->op2.reg, buffer, blen);
297 ADVANCE(written);
298 }
299 if (info->operandFormat & ARM_OPERAND_3) {
300 strncpy(buffer, ", ", blen - 1);
301 ADVANCE(2);
302 }
303 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_3) {
304 written = snprintf(buffer, blen - 1, "#%i", info->op3.immediate);
305 ADVANCE(written);
306 } else if (info->operandFormat & ARM_OPERAND_MEMORY_3) {
307 written = _decodeMemory(info->memory, pc, buffer, blen);
308 ADVANCE(written);
309 } else if (info->operandFormat & ARM_OPERAND_REGISTER_3) {
310 written = _decodeRegister(info->op3.reg, buffer, blen);
311 ADVANCE(written);
312 }
313 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_4) {
314 written = snprintf(buffer, blen - 1, "#%i", info->op4.immediate);
315 ADVANCE(written);
316 } else if (info->operandFormat & ARM_OPERAND_MEMORY_4) {
317 written = _decodeMemory(info->memory, pc, buffer, blen);
318 ADVANCE(written);
319 } else if (info->operandFormat & ARM_OPERAND_REGISTER_4) {
320 written = _decodeRegister(info->op4.reg, buffer, blen);
321 ADVANCE(written);
322 }
323 break;
324 }
325 buffer[blen - 1] = '\0';
326 return total;
327}