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 "sb",
232 "sh",
233 ""
234 ""
235};
236
237int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, int blen) {
238 const char* mnemonic = _armMnemonicStrings[info->mnemonic];
239 int written;
240 int total = 0;
241 const char* cond = "";
242 if (info->condition != ARM_CONDITION_AL && info->condition < ARM_CONDITION_NV) {
243 cond = _armConditions[info->condition];
244 }
245 const char* flags = "";
246 switch (info->mnemonic) {
247 case ARM_MN_LDM:
248 case ARM_MN_STM:
249 flags = _armDirectionStrings[MEMORY_FORMAT_TO_DIRECTION(info->memory.format)];
250 break;
251 case ARM_MN_LDR:
252 case ARM_MN_STR:
253 case ARM_MN_SWP:
254 flags = _armAccessTypeStrings[info->memory.width];
255 break;
256 case ARM_MN_ADD:
257 case ARM_MN_ADC:
258 case ARM_MN_AND:
259 case ARM_MN_BIC:
260 case ARM_MN_EOR:
261 case ARM_MN_MOV:
262 case ARM_MN_MVN:
263 case ARM_MN_ORR:
264 case ARM_MN_RSB:
265 case ARM_MN_RSC:
266 case ARM_MN_SBC:
267 case ARM_MN_SUB:
268 if (info->affectsCPSR && info->execMode == MODE_ARM) {
269 flags = "s";
270 }
271 break;
272 default:
273 break;
274 }
275 written = snprintf(buffer, blen - 1, "%s%s%s ", mnemonic, cond, flags);
276 ADVANCE(written);
277
278 switch (info->mnemonic) {
279 case ARM_MN_LDM:
280 case ARM_MN_STM:
281 written = _decodeRegister(info->memory.baseReg, buffer, blen);
282 ADVANCE(written);
283 if (info->memory.format & ARM_MEMORY_WRITEBACK) {
284 strncpy(buffer, "!", blen - 1);
285 ADVANCE(1);
286 }
287 strncpy(buffer, ", ", blen - 1);
288 ADVANCE(2);
289 written = _decodeRegisterList(info->op1.immediate, buffer, blen);
290 ADVANCE(written);
291 break;
292 case ARM_MN_B:
293 written = _decodePCRelative(info->op1.immediate, pc, buffer, blen);
294 ADVANCE(written);
295 break;
296 default:
297 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) {
298 written = snprintf(buffer, blen - 1, "#%i", info->op1.immediate);
299 ADVANCE(written);
300 } else if (info->operandFormat & ARM_OPERAND_MEMORY_1) {
301 written = _decodeMemory(info->memory, pc, buffer, blen);
302 ADVANCE(written);
303 } else if (info->operandFormat & ARM_OPERAND_REGISTER_1) {
304 written = _decodeRegister(info->op1.reg, buffer, blen);
305 ADVANCE(written);
306 }
307 if (info->operandFormat & ARM_OPERAND_2) {
308 strncpy(buffer, ", ", blen);
309 ADVANCE(2);
310 }
311 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_2) {
312 written = snprintf(buffer, blen - 1, "#%i", info->op2.immediate);
313 ADVANCE(written);
314 } else if (info->operandFormat & ARM_OPERAND_MEMORY_2) {
315 written = _decodeMemory(info->memory, pc, buffer, blen);
316 ADVANCE(written);
317 } else if (info->operandFormat & ARM_OPERAND_REGISTER_2) {
318 written = _decodeRegister(info->op2.reg, buffer, blen);
319 ADVANCE(written);
320 }
321 if (info->operandFormat & ARM_OPERAND_3) {
322 strncpy(buffer, ", ", blen - 1);
323 ADVANCE(2);
324 }
325 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_3) {
326 written = snprintf(buffer, blen - 1, "#%i", info->op3.immediate);
327 ADVANCE(written);
328 } else if (info->operandFormat & ARM_OPERAND_MEMORY_3) {
329 written = _decodeMemory(info->memory, pc, buffer, blen);
330 ADVANCE(written);
331 } else if (info->operandFormat & ARM_OPERAND_REGISTER_3) {
332 written = _decodeRegister(info->op3.reg, buffer, blen);
333 ADVANCE(written);
334 }
335 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_4) {
336 written = snprintf(buffer, blen - 1, "#%i", info->op4.immediate);
337 ADVANCE(written);
338 } else if (info->operandFormat & ARM_OPERAND_MEMORY_4) {
339 written = _decodeMemory(info->memory, pc, buffer, blen);
340 ADVANCE(written);
341 } else if (info->operandFormat & ARM_OPERAND_REGISTER_4) {
342 written = _decodeRegister(info->op4.reg, buffer, blen);
343 ADVANCE(written);
344 }
345 break;
346 }
347 buffer[blen - 1] = '\0';
348 return total;
349}