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 case ARM_CPSR:
50 strncpy(buffer, "cpsr", blen - 1);
51 return 4;
52 case ARM_SPSR:
53 strncpy(buffer, "spsr", blen - 1);
54 return 4;
55 default:
56 return snprintf(buffer, blen - 1, "r%i", reg);
57 }
58}
59
60static int _decodeRegisterList(int list, char* buffer, int blen) {
61 if (blen <= 0) {
62 return 0;
63 }
64 int total = 0;
65 strncpy(buffer, "{", blen - 1);
66 ADVANCE(1);
67 int i;
68 int start = -1;
69 int end = -1;
70 int written;
71 for (i = 0; i <= ARM_PC; ++i) {
72 if (list & 1) {
73 if (start < 0) {
74 start = i;
75 end = i;
76 } else if (end + 1 == i) {
77 end = i;
78 } else {
79 if (end > start) {
80 written = _decodeRegister(start, buffer, blen);
81 ADVANCE(written);
82 strncpy(buffer, "-", blen - 1);
83 ADVANCE(1);
84 }
85 written = _decodeRegister(end, buffer, blen);
86 ADVANCE(written);
87 strncpy(buffer, ",", blen - 1);
88 ADVANCE(1);
89 start = i;
90 end = i;
91 }
92 }
93 list >>= 1;
94 }
95 if (start >= 0) {
96 if (end > start) {
97 written = _decodeRegister(start, buffer, blen);
98 ADVANCE(written);
99 strncpy(buffer, "-", blen - 1);
100 ADVANCE(1);
101 }
102 written = _decodeRegister(end, buffer, blen);
103 ADVANCE(written);
104 }
105 strncpy(buffer, "}", blen - 1);
106 ADVANCE(1);
107 return total;
108}
109
110static int _decodePCRelative(uint32_t address, uint32_t pc, char* buffer, int blen) {
111 return snprintf(buffer, blen - 1, "$%08X", address + pc);
112}
113
114static int _decodeMemory(struct ARMMemoryAccess memory, int pc, char* buffer, int blen) {
115 if (blen <= 1) {
116 return 0;
117 }
118 int total = 0;
119 strncpy(buffer, "[", blen - 1);
120 ADVANCE(1);
121 int written;
122 if (memory.format & ARM_MEMORY_REGISTER_BASE) {
123 if (memory.baseReg == ARM_PC && memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) {
124 written = _decodePCRelative(memory.offset.immediate, pc, buffer, blen);
125 ADVANCE(written);
126 } else {
127 written = _decodeRegister(memory.baseReg, buffer, blen);
128 ADVANCE(written);
129 if (memory.format & (ARM_MEMORY_REGISTER_OFFSET | ARM_MEMORY_IMMEDIATE_OFFSET) && !(memory.format & ARM_MEMORY_POST_INCREMENT)) {
130 strncpy(buffer, ", ", blen - 1);
131 ADVANCE(2);
132 }
133 }
134 }
135 if (memory.format & ARM_MEMORY_POST_INCREMENT) {
136 strncpy(buffer, "], ", blen - 1);
137 ADVANCE(3);
138 }
139 if (memory.format & ARM_MEMORY_IMMEDIATE_OFFSET && memory.baseReg != ARM_PC) {
140 if (memory.format & ARM_MEMORY_OFFSET_SUBTRACT) {
141 written = snprintf(buffer, blen - 1, "#-%i", memory.offset.immediate);
142 ADVANCE(written);
143 } else {
144 written = snprintf(buffer, blen - 1, "#%i", memory.offset.immediate);
145 ADVANCE(written);
146 }
147 } else if (memory.format & ARM_MEMORY_REGISTER_OFFSET) {
148 if (memory.format & ARM_MEMORY_OFFSET_SUBTRACT) {
149 strncpy(buffer, "-", blen - 1);
150 ADVANCE(1);
151 }
152 written = _decodeRegister(memory.offset.reg, buffer, blen);
153 ADVANCE(written);
154 }
155 // TODO: shifted registers
156
157 if (!(memory.format & ARM_MEMORY_POST_INCREMENT)) {
158 strncpy(buffer, "]", blen - 1);
159 ADVANCE(1);
160 }
161 if ((memory.format & (ARM_MEMORY_PRE_INCREMENT | ARM_MEMORY_WRITEBACK)) == (ARM_MEMORY_PRE_INCREMENT | ARM_MEMORY_WRITEBACK)) {
162 strncpy(buffer, "!", blen - 1);
163 ADVANCE(1);
164 }
165 return total;
166}
167
168static const char* _armMnemonicStrings[] = {
169 "ill",
170 "adc",
171 "add",
172 "and",
173 "asr",
174 "b",
175 "bic",
176 "bkpt",
177 "bl",
178 "blh",
179 "bx",
180 "cmn",
181 "cmp",
182 "eor",
183 "ldm",
184 "ldr",
185 "lsl",
186 "lsr",
187 "mla",
188 "mov",
189 "mrs",
190 "msr",
191 "mul",
192 "mvn",
193 "neg",
194 "orr",
195 "ror",
196 "rsb",
197 "rsc",
198 "sbc",
199 "smlal",
200 "smull",
201 "stm",
202 "str",
203 "sub",
204 "swi",
205 "swp",
206 "teq",
207 "tst",
208 "umlal",
209 "umull",
210
211 "ill"
212};
213
214static const char* _armDirectionStrings[] = {
215 "da",
216 "ia",
217 "db",
218 "da"
219};
220
221static const char* _armAccessTypeStrings[] = {
222 "",
223 "b",
224 "h",
225 "",
226 "",
227 "",
228 "",
229 "",
230
231 "",
232 "sb",
233 "sh",
234 "",
235 "",
236 "",
237 "",
238 "",
239
240 "",
241 "tb",
242 "",
243 "",
244 "t",
245 "",
246 "",
247 ""
248};
249
250int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, int blen) {
251 const char* mnemonic = _armMnemonicStrings[info->mnemonic];
252 int written;
253 int total = 0;
254 const char* cond = "";
255 if (info->condition != ARM_CONDITION_AL && info->condition < ARM_CONDITION_NV) {
256 cond = _armConditions[info->condition];
257 }
258 const char* flags = "";
259 switch (info->mnemonic) {
260 case ARM_MN_LDM:
261 case ARM_MN_STM:
262 flags = _armDirectionStrings[MEMORY_FORMAT_TO_DIRECTION(info->memory.format)];
263 break;
264 case ARM_MN_LDR:
265 case ARM_MN_STR:
266 case ARM_MN_SWP:
267 flags = _armAccessTypeStrings[info->memory.width];
268 break;
269 case ARM_MN_ADD:
270 case ARM_MN_ADC:
271 case ARM_MN_AND:
272 case ARM_MN_BIC:
273 case ARM_MN_EOR:
274 case ARM_MN_MOV:
275 case ARM_MN_MVN:
276 case ARM_MN_ORR:
277 case ARM_MN_RSB:
278 case ARM_MN_RSC:
279 case ARM_MN_SBC:
280 case ARM_MN_SUB:
281 if (info->affectsCPSR && info->execMode == MODE_ARM) {
282 flags = "s";
283 }
284 break;
285 default:
286 break;
287 }
288 written = snprintf(buffer, blen - 1, "%s%s%s ", mnemonic, cond, flags);
289 ADVANCE(written);
290
291 switch (info->mnemonic) {
292 case ARM_MN_LDM:
293 case ARM_MN_STM:
294 written = _decodeRegister(info->memory.baseReg, buffer, blen);
295 ADVANCE(written);
296 if (info->memory.format & ARM_MEMORY_WRITEBACK) {
297 strncpy(buffer, "!", blen - 1);
298 ADVANCE(1);
299 }
300 strncpy(buffer, ", ", blen - 1);
301 ADVANCE(2);
302 written = _decodeRegisterList(info->op1.immediate, buffer, blen);
303 ADVANCE(written);
304 break;
305 case ARM_MN_B:
306 written = _decodePCRelative(info->op1.immediate, pc, buffer, blen);
307 ADVANCE(written);
308 break;
309 default:
310 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) {
311 written = snprintf(buffer, blen - 1, "#%i", info->op1.immediate);
312 ADVANCE(written);
313 } else if (info->operandFormat & ARM_OPERAND_MEMORY_1) {
314 written = _decodeMemory(info->memory, pc, buffer, blen);
315 ADVANCE(written);
316 } else if (info->operandFormat & ARM_OPERAND_REGISTER_1) {
317 written = _decodeRegister(info->op1.reg, buffer, blen);
318 ADVANCE(written);
319 }
320 if (info->operandFormat & ARM_OPERAND_2) {
321 strncpy(buffer, ", ", blen);
322 ADVANCE(2);
323 }
324 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_2) {
325 written = snprintf(buffer, blen - 1, "#%i", info->op2.immediate);
326 ADVANCE(written);
327 } else if (info->operandFormat & ARM_OPERAND_MEMORY_2) {
328 written = _decodeMemory(info->memory, pc, buffer, blen);
329 ADVANCE(written);
330 } else if (info->operandFormat & ARM_OPERAND_REGISTER_2) {
331 written = _decodeRegister(info->op2.reg, buffer, blen);
332 ADVANCE(written);
333 }
334 if (info->operandFormat & ARM_OPERAND_3) {
335 strncpy(buffer, ", ", blen - 1);
336 ADVANCE(2);
337 }
338 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_3) {
339 written = snprintf(buffer, blen - 1, "#%i", info->op3.immediate);
340 ADVANCE(written);
341 } else if (info->operandFormat & ARM_OPERAND_MEMORY_3) {
342 written = _decodeMemory(info->memory, pc, buffer, blen);
343 ADVANCE(written);
344 } else if (info->operandFormat & ARM_OPERAND_REGISTER_3) {
345 written = _decodeRegister(info->op3.reg, buffer, blen);
346 ADVANCE(written);
347 }
348 if (info->operandFormat & ARM_OPERAND_4) {
349 strncpy(buffer, ", ", blen - 1);
350 ADVANCE(2);
351 }
352 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_4) {
353 written = snprintf(buffer, blen - 1, "#%i", info->op4.immediate);
354 ADVANCE(written);
355 } else if (info->operandFormat & ARM_OPERAND_MEMORY_4) {
356 written = _decodeMemory(info->memory, pc, buffer, blen);
357 ADVANCE(written);
358 } else if (info->operandFormat & ARM_OPERAND_REGISTER_4) {
359 written = _decodeRegister(info->op4.reg, buffer, blen);
360 ADVANCE(written);
361 }
362 break;
363 }
364 buffer[blen - 1] = '\0';
365 return total;
366}