src/arm/decoder.c (view raw)
1/* Copyright (c) 2013-2014 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include "decoder.h"
7
8#include "decoder-inlines.h"
9
10#define ADVANCE(AMOUNT) \
11 if (AMOUNT > blen) { \
12 buffer[blen - 1] = '\0'; \
13 return total; \
14 } \
15 total += AMOUNT; \
16 buffer += AMOUNT; \
17 blen -= AMOUNT;
18
19static int _decodeRegister(int reg, char* buffer, int blen);
20static int _decodeRegisterList(int list, char* buffer, int blen);
21static int _decodePCRelative(uint32_t address, uint32_t pc, char* buffer, int blen);
22static int _decodeMemory(struct ARMMemoryAccess memory, int pc, char* buffer, int blen);
23static int _decodeShift(union ARMOperand operand, bool reg, char* buffer, int blen);
24
25static const char* _armConditions[] = {
26 "eq",
27 "ne",
28 "cs",
29 "cc",
30 "mi",
31 "pl",
32 "vs",
33 "vc",
34 "hi",
35 "ls",
36 "ge",
37 "lt",
38 "gt",
39 "le",
40 "al",
41 "nv"
42};
43
44static int _decodeRegister(int reg, char* buffer, int blen) {
45 switch (reg) {
46 case ARM_SP:
47 strncpy(buffer, "sp", blen - 1);
48 return 2;
49 case ARM_LR:
50 strncpy(buffer, "lr", blen - 1);
51 return 2;
52 case ARM_PC:
53 strncpy(buffer, "pc", blen - 1);
54 return 2;
55 case ARM_CPSR:
56 strncpy(buffer, "cpsr", blen - 1);
57 return 4;
58 case ARM_SPSR:
59 strncpy(buffer, "spsr", blen - 1);
60 return 4;
61 default:
62 return snprintf(buffer, blen - 1, "r%i", reg);
63 }
64}
65
66static int _decodeRegisterList(int list, char* buffer, int blen) {
67 if (blen <= 0) {
68 return 0;
69 }
70 int total = 0;
71 strncpy(buffer, "{", blen - 1);
72 ADVANCE(1);
73 int i;
74 int start = -1;
75 int end = -1;
76 int written;
77 for (i = 0; i <= ARM_PC; ++i) {
78 if (list & 1) {
79 if (start < 0) {
80 start = i;
81 end = i;
82 } else if (end + 1 == i) {
83 end = i;
84 } else {
85 if (end > start) {
86 written = _decodeRegister(start, buffer, blen);
87 ADVANCE(written);
88 strncpy(buffer, "-", blen - 1);
89 ADVANCE(1);
90 }
91 written = _decodeRegister(end, buffer, blen);
92 ADVANCE(written);
93 strncpy(buffer, ",", blen - 1);
94 ADVANCE(1);
95 start = i;
96 end = i;
97 }
98 }
99 list >>= 1;
100 }
101 if (start >= 0) {
102 if (end > start) {
103 written = _decodeRegister(start, buffer, blen);
104 ADVANCE(written);
105 strncpy(buffer, "-", blen - 1);
106 ADVANCE(1);
107 }
108 written = _decodeRegister(end, buffer, blen);
109 ADVANCE(written);
110 }
111 strncpy(buffer, "}", blen - 1);
112 ADVANCE(1);
113 return total;
114}
115
116static int _decodePCRelative(uint32_t address, uint32_t pc, char* buffer, int blen) {
117 return snprintf(buffer, blen - 1, "$%08X", address + pc);
118}
119
120static int _decodeMemory(struct ARMMemoryAccess memory, int pc, char* buffer, int blen) {
121 if (blen <= 1) {
122 return 0;
123 }
124 int total = 0;
125 strncpy(buffer, "[", blen - 1);
126 ADVANCE(1);
127 int written;
128 if (memory.format & ARM_MEMORY_REGISTER_BASE) {
129 if (memory.baseReg == ARM_PC && memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) {
130 written = _decodePCRelative(memory.offset.immediate, pc, buffer, blen);
131 ADVANCE(written);
132 } else {
133 written = _decodeRegister(memory.baseReg, buffer, blen);
134 ADVANCE(written);
135 if (memory.format & (ARM_MEMORY_REGISTER_OFFSET | ARM_MEMORY_IMMEDIATE_OFFSET) && !(memory.format & ARM_MEMORY_POST_INCREMENT)) {
136 strncpy(buffer, ", ", blen - 1);
137 ADVANCE(2);
138 }
139 }
140 }
141 if (memory.format & ARM_MEMORY_POST_INCREMENT) {
142 strncpy(buffer, "], ", blen - 1);
143 ADVANCE(3);
144 }
145 if (memory.format & ARM_MEMORY_IMMEDIATE_OFFSET && memory.baseReg != ARM_PC) {
146 if (memory.format & ARM_MEMORY_OFFSET_SUBTRACT) {
147 written = snprintf(buffer, blen - 1, "#-%i", memory.offset.immediate);
148 ADVANCE(written);
149 } else {
150 written = snprintf(buffer, blen - 1, "#%i", memory.offset.immediate);
151 ADVANCE(written);
152 }
153 } else if (memory.format & ARM_MEMORY_REGISTER_OFFSET) {
154 if (memory.format & ARM_MEMORY_OFFSET_SUBTRACT) {
155 strncpy(buffer, "-", blen - 1);
156 ADVANCE(1);
157 }
158 written = _decodeRegister(memory.offset.reg, buffer, blen);
159 ADVANCE(written);
160 }
161 if (memory.format & ARM_MEMORY_SHIFTED_OFFSET) {
162 written = _decodeShift(memory.offset, false, buffer, blen);
163 ADVANCE(written);
164 }
165
166 if (!(memory.format & ARM_MEMORY_POST_INCREMENT)) {
167 strncpy(buffer, "]", blen - 1);
168 ADVANCE(1);
169 }
170 if ((memory.format & (ARM_MEMORY_PRE_INCREMENT | ARM_MEMORY_WRITEBACK)) == (ARM_MEMORY_PRE_INCREMENT | ARM_MEMORY_WRITEBACK)) {
171 strncpy(buffer, "!", blen - 1);
172 ADVANCE(1);
173 }
174 return total;
175}
176
177static int _decodeShift(union ARMOperand op, bool reg, char* buffer, int blen) {
178 if (blen <= 1) {
179 return 0;
180 }
181 int total = 0;
182 strncpy(buffer, ", ", blen - 1);
183 ADVANCE(2);
184 int written;
185 switch (op.shifterOp) {
186 case ARM_SHIFT_LSL:
187 strncpy(buffer, "lsl ", blen - 1);
188 ADVANCE(4);
189 break;
190 case ARM_SHIFT_LSR:
191 strncpy(buffer, "lsr ", blen - 1);
192 ADVANCE(4);
193 break;
194 case ARM_SHIFT_ASR:
195 strncpy(buffer, "asr ", blen - 1);
196 ADVANCE(4);
197 break;
198 case ARM_SHIFT_ROR:
199 strncpy(buffer, "ror ", blen - 1);
200 ADVANCE(4);
201 break;
202 case ARM_SHIFT_RRX:
203 strncpy(buffer, "rrx", blen - 1);
204 ADVANCE(3);
205 return total;
206 }
207 if (!reg) {
208 written = snprintf(buffer, blen - 1, "#%i", op.shifterImm);
209 } else {
210 written = _decodeRegister(op.shifterReg, buffer, blen);
211 }
212 ADVANCE(written);
213 return total;
214}
215
216static const char* _armMnemonicStrings[] = {
217 "ill",
218 "adc",
219 "add",
220 "and",
221 "asr",
222 "b",
223 "bic",
224 "bkpt",
225 "bl",
226 "blh",
227 "bx",
228 "cmn",
229 "cmp",
230 "eor",
231 "ldm",
232 "ldr",
233 "lsl",
234 "lsr",
235 "mla",
236 "mov",
237 "mrs",
238 "msr",
239 "mul",
240 "mvn",
241 "neg",
242 "orr",
243 "ror",
244 "rsb",
245 "rsc",
246 "sbc",
247 "smlal",
248 "smull",
249 "stm",
250 "str",
251 "sub",
252 "swi",
253 "swp",
254 "teq",
255 "tst",
256 "umlal",
257 "umull",
258
259 "ill"
260};
261
262static const char* _armDirectionStrings[] = {
263 "da",
264 "ia",
265 "db",
266 "ib"
267};
268
269static const char* _armAccessTypeStrings[] = {
270 "",
271 "b",
272 "h",
273 "",
274 "",
275 "",
276 "",
277 "",
278
279 "",
280 "sb",
281 "sh",
282 "",
283 "",
284 "",
285 "",
286 "",
287
288 "",
289 "bt",
290 "",
291 "",
292 "t",
293 "",
294 "",
295 ""
296};
297
298int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, int blen) {
299 const char* mnemonic = _armMnemonicStrings[info->mnemonic];
300 int written;
301 int total = 0;
302 const char* cond = "";
303 if (info->condition != ARM_CONDITION_AL && info->condition < ARM_CONDITION_NV) {
304 cond = _armConditions[info->condition];
305 }
306 const char* flags = "";
307 switch (info->mnemonic) {
308 case ARM_MN_LDM:
309 case ARM_MN_STM:
310 flags = _armDirectionStrings[MEMORY_FORMAT_TO_DIRECTION(info->memory.format)];
311 break;
312 case ARM_MN_LDR:
313 case ARM_MN_STR:
314 case ARM_MN_SWP:
315 flags = _armAccessTypeStrings[info->memory.width];
316 break;
317 case ARM_MN_ADD:
318 case ARM_MN_ADC:
319 case ARM_MN_AND:
320 case ARM_MN_BIC:
321 case ARM_MN_EOR:
322 case ARM_MN_MOV:
323 case ARM_MN_MVN:
324 case ARM_MN_ORR:
325 case ARM_MN_RSB:
326 case ARM_MN_RSC:
327 case ARM_MN_SBC:
328 case ARM_MN_SUB:
329 if (info->affectsCPSR && info->execMode == MODE_ARM) {
330 flags = "s";
331 }
332 break;
333 default:
334 break;
335 }
336 written = snprintf(buffer, blen - 1, "%s%s%s ", mnemonic, cond, flags);
337 ADVANCE(written);
338
339 switch (info->mnemonic) {
340 case ARM_MN_LDM:
341 case ARM_MN_STM:
342 written = _decodeRegister(info->memory.baseReg, buffer, blen);
343 ADVANCE(written);
344 if (info->memory.format & ARM_MEMORY_WRITEBACK) {
345 strncpy(buffer, "!", blen - 1);
346 ADVANCE(1);
347 }
348 strncpy(buffer, ", ", blen - 1);
349 ADVANCE(2);
350 written = _decodeRegisterList(info->op1.immediate, buffer, blen);
351 ADVANCE(written);
352 if (info->memory.format & ARM_MEMORY_SPSR_SWAP) {
353 strncpy(buffer, "^", blen - 1);
354 ADVANCE(1);
355 }
356 break;
357 case ARM_MN_B:
358 written = _decodePCRelative(info->op1.immediate, pc, buffer, blen);
359 ADVANCE(written);
360 break;
361 default:
362 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) {
363 written = snprintf(buffer, blen - 1, "#%i", info->op1.immediate);
364 ADVANCE(written);
365 } else if (info->operandFormat & ARM_OPERAND_MEMORY_1) {
366 written = _decodeMemory(info->memory, pc, buffer, blen);
367 ADVANCE(written);
368 } else if (info->operandFormat & ARM_OPERAND_REGISTER_1) {
369 written = _decodeRegister(info->op1.reg, buffer, blen);
370 ADVANCE(written);
371 }
372 if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_1) {
373 written = _decodeShift(info->op1, true, buffer, blen);
374 ADVANCE(written);
375 } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_1) {
376 written = _decodeShift(info->op1, false, buffer, blen);
377 ADVANCE(written);
378 }
379 if (info->operandFormat & ARM_OPERAND_2) {
380 strncpy(buffer, ", ", blen);
381 ADVANCE(2);
382 }
383 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_2) {
384 written = snprintf(buffer, blen - 1, "#%i", info->op2.immediate);
385 ADVANCE(written);
386 } else if (info->operandFormat & ARM_OPERAND_MEMORY_2) {
387 written = _decodeMemory(info->memory, pc, buffer, blen);
388 ADVANCE(written);
389 } else if (info->operandFormat & ARM_OPERAND_REGISTER_2) {
390 written = _decodeRegister(info->op2.reg, buffer, blen);
391 ADVANCE(written);
392 }
393 if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_2) {
394 written = _decodeShift(info->op2, true, buffer, blen);
395 ADVANCE(written);
396 } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_2) {
397 written = _decodeShift(info->op2, false, buffer, blen);
398 ADVANCE(written);
399 }
400 if (info->operandFormat & ARM_OPERAND_3) {
401 strncpy(buffer, ", ", blen - 1);
402 ADVANCE(2);
403 }
404 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_3) {
405 written = snprintf(buffer, blen - 1, "#%i", info->op3.immediate);
406 ADVANCE(written);
407 } else if (info->operandFormat & ARM_OPERAND_MEMORY_3) {
408 written = _decodeMemory(info->memory, pc, buffer, blen);
409 ADVANCE(written);
410 } else if (info->operandFormat & ARM_OPERAND_REGISTER_3) {
411 written = _decodeRegister(info->op3.reg, buffer, blen);
412 ADVANCE(written);
413 }
414 if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_3) {
415 written = _decodeShift(info->op3, true, buffer, blen);
416 ADVANCE(written);
417 } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_3) {
418 written = _decodeShift(info->op3, false, buffer, blen);
419 ADVANCE(written);
420 }
421 if (info->operandFormat & ARM_OPERAND_4) {
422 strncpy(buffer, ", ", blen - 1);
423 ADVANCE(2);
424 }
425 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_4) {
426 written = snprintf(buffer, blen - 1, "#%i", info->op4.immediate);
427 ADVANCE(written);
428 } else if (info->operandFormat & ARM_OPERAND_MEMORY_4) {
429 written = _decodeMemory(info->memory, pc, buffer, blen);
430 ADVANCE(written);
431 } else if (info->operandFormat & ARM_OPERAND_REGISTER_4) {
432 written = _decodeRegister(info->op4.reg, buffer, blen);
433 ADVANCE(written);
434 }
435 if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_4) {
436 written = _decodeShift(info->op4, true, buffer, blen);
437 ADVANCE(written);
438 } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_4) {
439 written = _decodeShift(info->op4, false, buffer, blen);
440 ADVANCE(written);
441 }
442 break;
443 }
444 buffer[blen - 1] = '\0';
445 return total;
446}