FreeCalypso > hg > freecalypso-reveng
comparison ticoff/armdis.c @ 111:0f94d17899b3
tiobjd: disassembly integrated, no relocs or hints yet
author | Michael Spacefalcon <msokolov@ivan.Harhan.ORG> |
---|---|
date | Thu, 03 Apr 2014 05:14:15 +0000 |
parents | |
children | d97fbe98600b |
comparison
equal
deleted
inserted
replaced
110:e650fdc743fe | 111:0f94d17899b3 |
---|---|
1 /* | |
2 * ARM state disassembly | |
3 */ | |
4 | |
5 #include <sys/types.h> | |
6 #include <stdio.h> | |
7 #include <stdlib.h> | |
8 #include <string.h> | |
9 #include <strings.h> | |
10 #include "intstruct.h" | |
11 #include "globals.h" | |
12 | |
13 extern unsigned get_u16(), get_u32(); | |
14 | |
15 extern char *regnames[16], *condition_decode[16], *shift_types[4]; | |
16 | |
17 static char *dataproc_ops[16] = {"and", "eor", "sub", "rsb", | |
18 "add", "adc", "sbc", "rsc", | |
19 "tst", "teq", "cmp", "cmn", | |
20 "orr", "mov", "bic", "mvn"}; | |
21 | |
22 static void | |
23 arm_branch(off, word) | |
24 unsigned off, word; | |
25 { | |
26 unsigned dest; | |
27 | |
28 dest = (word & 0x00FFFFFF) << 2; | |
29 if (dest & 0x02000000) | |
30 dest |= 0xFC000000; | |
31 dest += off + 8; | |
32 printf("b%s%s\t0x%x\n", word&0x1000000 ? "l" : "", | |
33 condition_decode[word>>28], dest); | |
34 } | |
35 | |
36 static void | |
37 op2_immed(word) | |
38 unsigned word; | |
39 { | |
40 unsigned low8, rot, val; | |
41 | |
42 low8 = word & 0xFF; | |
43 rot = (word & 0xF00) >> 7; | |
44 val = (low8 << (32 - rot)) | (low8 >> rot); | |
45 if (val <= 9) | |
46 printf("#%u\n", val); | |
47 else | |
48 printf("#%u\t; 0x%x\n", val, val); | |
49 } | |
50 | |
51 static void | |
52 op2_regbyconst(word) | |
53 unsigned word; | |
54 { | |
55 unsigned c, t; | |
56 | |
57 c = (word >> 7) & 0x1F; | |
58 t = (word >> 5) & 3; | |
59 if (!c) { | |
60 switch (t) { | |
61 case 0: | |
62 printf("%s", regnames[word&0xF]); | |
63 return; | |
64 case 3: | |
65 printf("%s, rrx", regnames[word&0xF]); | |
66 return; | |
67 default: | |
68 c = 32; | |
69 } | |
70 } | |
71 printf("%s, %s #%u", regnames[word&0xF], shift_types[t], c); | |
72 } | |
73 | |
74 static void | |
75 op2_regbyreg(word) | |
76 unsigned word; | |
77 { | |
78 printf("%s, %s %s", regnames[word&0xF], shift_types[(word>>5)&3], | |
79 regnames[(word>>8)&0xF]); | |
80 } | |
81 | |
82 static void | |
83 op2_regshift(word) | |
84 unsigned word; | |
85 { | |
86 if (word & 0x10) | |
87 op2_regbyreg(word); | |
88 else | |
89 op2_regbyconst(word); | |
90 putchar('\n'); | |
91 } | |
92 | |
93 static void | |
94 dataproc_op2(word) | |
95 unsigned word; | |
96 { | |
97 if (word & 0x02000000) | |
98 op2_immed(word); | |
99 else | |
100 op2_regshift(word); | |
101 } | |
102 | |
103 static void | |
104 dataproc_tstcmp_overlay(word) | |
105 unsigned word; | |
106 { | |
107 char msrmask[5], *cp; | |
108 | |
109 if ((word & 0x0FFFFFF0) == 0x012FFF10) { | |
110 printf("bx%s\t%s\n", condition_decode[word>>28], | |
111 regnames[word&0xF]); | |
112 return; | |
113 } else if ((word & 0x0FBF0FFF) == 0x010F0000) { | |
114 printf("mrs%s\t%s, %cPSR\n", condition_decode[word>>28], | |
115 regnames[(word>>12)&0xF], word&0x400000 ? 'S' : 'C'); | |
116 return; | |
117 } else if ((word & 0x0DB0F000) == 0x0120F000) { | |
118 if (!(word & 0x02000000) && (word & 0xFF0)) { | |
119 printf("<invalid MSR>\n"); | |
120 return; | |
121 } | |
122 if (word & 0xF0000) { | |
123 cp = msrmask; | |
124 if (word & 0x80000) | |
125 *cp++ = 'f'; | |
126 if (word & 0x40000) | |
127 *cp++ = 's'; | |
128 if (word & 0x20000) | |
129 *cp++ = 'x'; | |
130 if (word & 0x10000) | |
131 *cp++ = 'c'; | |
132 *cp = '\0'; | |
133 } else | |
134 strcpy(msrmask, "null"); | |
135 printf("msr%s\t%cPSR_%s, ", condition_decode[word>>28], | |
136 word&0x400000 ? 'S' : 'C', msrmask); | |
137 dataproc_op2(word); | |
138 return; | |
139 } | |
140 printf("<invalid BX/MRS/MSR>\n"); | |
141 } | |
142 | |
143 static void | |
144 dataproc(word) | |
145 unsigned word; | |
146 { | |
147 unsigned opc; | |
148 | |
149 opc = (word >> 21) & 0xF; | |
150 switch (opc) { | |
151 case 0: | |
152 case 1: | |
153 case 2: | |
154 case 3: | |
155 case 4: | |
156 case 5: | |
157 case 6: | |
158 case 7: | |
159 case 0xC: | |
160 case 0xE: | |
161 printf("%s%s%s\t%s, %s, ", dataproc_ops[opc], | |
162 condition_decode[word>>28], word&0x100000 ? "s" : "", | |
163 regnames[(word>>12)&0xF], regnames[(word>>16)&0xF]); | |
164 dataproc_op2(word); | |
165 return; | |
166 case 0xD: | |
167 case 0xF: | |
168 printf("%s%s%s\t%s, ", dataproc_ops[opc], | |
169 condition_decode[word>>28], word&0x100000 ? "s" : "", | |
170 regnames[(word>>12)&0xF]); | |
171 dataproc_op2(word); | |
172 return; | |
173 case 8: | |
174 case 9: | |
175 case 0xA: | |
176 case 0xB: | |
177 if (word & 0x100000) { | |
178 printf("%s%s\t%s, ", dataproc_ops[opc], | |
179 condition_decode[word>>28], | |
180 regnames[(word>>16)&0xF]); | |
181 dataproc_op2(word); | |
182 } else | |
183 dataproc_tstcmp_overlay(word); | |
184 return; | |
185 } | |
186 } | |
187 | |
188 static void | |
189 multiply(word) | |
190 unsigned word; | |
191 { | |
192 if ((word & 0x0FE000F0) == 0x90) | |
193 printf("mul%s%s\t%s, %s, %s\n", condition_decode[word>>28], | |
194 word&0x100000 ? "s" : "", regnames[(word>>16)&0xF], | |
195 regnames[word&0xF], regnames[(word>>8)&0xF]); | |
196 else if ((word & 0x0FE000F0) == 0x00200090) | |
197 printf("mla%s%s\t%s, %s, %s, %s\n", condition_decode[word>>28], | |
198 word&0x100000 ? "s" : "", regnames[(word>>16)&0xF], | |
199 regnames[word&0xF], regnames[(word>>8)&0xF], | |
200 regnames[(word>>12)&0xF]); | |
201 else if ((word & 0x0F8000F0) == 0x00800090) | |
202 printf("%c%sl%s%s\t%s, %s, %s, %s\n", | |
203 word&0x400000 ? 's' : 'u', | |
204 word&0x200000 ? "mla" : "mul", | |
205 condition_decode[word>>28], | |
206 word&0x100000 ? "s" : "", | |
207 regnames[(word>>12)&0xF], regnames[(word>>16)&0xF], | |
208 regnames[word&0xF], regnames[(word>>8)&0xF]); | |
209 else if ((word & 0x0FB00FF0) == 0x01000090) | |
210 printf("swp%s%s\t%s, %s, [%s]\n", condition_decode[word>>28], | |
211 word&0x400000, "b", "", regnames[(word>>12)&0xF], | |
212 regnames[word&0xF], regnames[(word>>16)&0xF]); | |
213 else | |
214 printf("<invalid multiply>\n"); | |
215 } | |
216 | |
217 static int | |
218 check_ldr_litpool(sec, off, word, loff, size) | |
219 struct internal_scnhdr *sec; | |
220 unsigned off, word, loff; | |
221 { | |
222 unsigned litoff, datum; | |
223 | |
224 /* base reg must be 15 */ | |
225 if (((word >> 16) & 0xF) != 15) | |
226 return(0); | |
227 /* must be a load */ | |
228 if (!(word & 0x100000)) | |
229 return(0); | |
230 /* no writeback allowed */ | |
231 if (word & 0x200000) | |
232 return(0); | |
233 /* alignment */ | |
234 if (loff & (size - 1)) | |
235 return(0); | |
236 /* range */ | |
237 off += 8; | |
238 if (word & 0x800000) | |
239 litoff = off + loff; | |
240 else { | |
241 if (loff > off) | |
242 return(0); | |
243 litoff = off - loff; | |
244 } | |
245 if (litoff >= sec->size) | |
246 return(0); | |
247 /* all checks passed, proceed */ | |
248 switch (size) { | |
249 case 1: | |
250 datum = filemap[sec->data_offset + litoff]; | |
251 break; | |
252 case 2: | |
253 datum = get_u16(filemap + sec->data_offset + litoff); | |
254 break; | |
255 case 4: | |
256 datum = get_u32(filemap + sec->data_offset + litoff); | |
257 break; | |
258 } | |
259 printf("=0x%x\t; via 0x%x\n", datum, litoff); | |
260 return(1); | |
261 } | |
262 | |
263 static void | |
264 ldr_str_imm_pre(sec, off, word) | |
265 struct internal_scnhdr *sec; | |
266 unsigned off, word; | |
267 { | |
268 unsigned loff = word & 0xFFF; | |
269 | |
270 printf("%s%s%s\t%s, ", word&0x100000 ? "ldr" : "str", | |
271 condition_decode[word>>28], word&0x400000 ? "b" : "", | |
272 regnames[(word>>12)&0xF]); | |
273 if (check_ldr_litpool(sec, off, word, loff, word&0x400000 ? 1 : 4)) | |
274 return; | |
275 printf("[%s", regnames[(word>>16)&0xF]); | |
276 if (loff || word&0x200000) | |
277 printf(", #%s%u", word&0x800000 ? "" : "-", loff); | |
278 putchar(']'); | |
279 if (word & 0x200000) | |
280 putchar('!'); | |
281 if (loff >= 10) | |
282 printf("\t; 0x%x", loff); | |
283 putchar('\n'); | |
284 } | |
285 | |
286 static void | |
287 ldr_str_imm_post(word) | |
288 unsigned word; | |
289 { | |
290 unsigned loff = word & 0xFFF; | |
291 | |
292 printf("%s%s%s%s\t%s, [%s], #%s%u", word&0x100000 ? "ldr" : "str", | |
293 condition_decode[word>>28], word&0x400000 ? "b" : "", | |
294 word&0x200000 ? "t" : "", | |
295 regnames[(word>>12)&0xF], regnames[(word>>16)&0xF], | |
296 word&0x800000 ? "" : "-", loff); | |
297 if (loff >= 10) | |
298 printf("\t; 0x%x", loff); | |
299 putchar('\n'); | |
300 } | |
301 | |
302 static void | |
303 ldr_str_reg_pre(word) | |
304 unsigned word; | |
305 { | |
306 if (word & 0x10) { | |
307 printf("<invalid ldr/str: offset reg shift by reg>\n"); | |
308 return; | |
309 } | |
310 printf("%s%s%s\t%s, [%s, ", word&0x100000 ? "ldr" : "str", | |
311 condition_decode[word>>28], word&0x400000 ? "b" : "", | |
312 regnames[(word>>12)&0xF], regnames[(word>>16)&0xF]); | |
313 if (!(word & 0x800000)) | |
314 putchar('-'); | |
315 op2_regbyconst(word); | |
316 putchar(']'); | |
317 if (word & 0x200000) | |
318 putchar('!'); | |
319 putchar('\n'); | |
320 } | |
321 | |
322 static void | |
323 ldr_str_reg_post(word) | |
324 unsigned word; | |
325 { | |
326 if (word & 0x10) { | |
327 printf("<invalid ldr/str: offset reg shift by reg>\n"); | |
328 return; | |
329 } | |
330 printf("%s%s%s%s\t%s, [%s], ", word&0x100000 ? "ldr" : "str", | |
331 condition_decode[word>>28], word&0x400000 ? "b" : "", | |
332 word&0x200000 ? "t" : "", | |
333 regnames[(word>>12)&0xF], regnames[(word>>16)&0xF]); | |
334 if (!(word & 0x800000)) | |
335 putchar('-'); | |
336 op2_regbyconst(word); | |
337 putchar('\n'); | |
338 } | |
339 | |
340 static void | |
341 ldr_str_ext(sec, off, word) | |
342 struct internal_scnhdr *sec; | |
343 unsigned off, word; | |
344 { | |
345 unsigned loff; | |
346 | |
347 if (!(word&0x01000000) && word&0x200000) { | |
348 printf("<invalid ldrh/strh: P=0, W=1>\n"); | |
349 return; | |
350 } | |
351 if (!(word&0x400000) && word&0xF00) { | |
352 printf("<invalid ldrh/strh: SBZ!=0>\n"); | |
353 return; | |
354 } | |
355 printf("%s%s%s%c\t%s, ", word&0x100000 ? "ldr" : "str", | |
356 condition_decode[word>>28], | |
357 word&0x40 ? "s" : "", | |
358 word&0x20 ? 'h' : 'b', | |
359 regnames[(word>>12)&0xF]); | |
360 if (word & 0x400000) | |
361 loff = ((word & 0xF00) >> 4) | (word & 0xF); | |
362 switch (word & 0x01400000) { | |
363 case 0: | |
364 /* reg post */ | |
365 printf("[%s], %s%s", regnames[(word>>16)&0xF], | |
366 word&0x800000 ? "" : "-", regnames[word&0xF]); | |
367 break; | |
368 case 0x400000: | |
369 /* imm post */ | |
370 printf("[%s], #%s%u", regnames[(word>>16)&0xF], | |
371 word&0x800000 ? "" : "-", loff); | |
372 if (loff >= 10) | |
373 printf("\t; 0x%x", loff); | |
374 break; | |
375 case 0x01000000: | |
376 /* reg pre */ | |
377 printf("[%s, %s%s]%s", regnames[(word>>16)&0xF], | |
378 word&0x800000 ? "" : "-", regnames[word&0xF], | |
379 word&0x200000 ? "!" : ""); | |
380 break; | |
381 case 0x01400000: | |
382 /* imm pre */ | |
383 if (check_ldr_litpool(sec, off, word, loff, word&0x20 ? 2 : 1)) | |
384 return; | |
385 printf("[%s", regnames[(word>>16)&0xF]); | |
386 if (loff || word&0x200000) | |
387 printf(", #%s%u", word&0x800000 ? "" : "-", loff); | |
388 putchar(']'); | |
389 if (word & 0x200000) | |
390 putchar('!'); | |
391 if (loff >= 10) | |
392 printf("\t; 0x%x", loff); | |
393 break; | |
394 } | |
395 putchar('\n'); | |
396 } | |
397 | |
398 static void | |
399 dataproc_74_overlay(sec, off, word) | |
400 struct internal_scnhdr *sec; | |
401 unsigned off, word; | |
402 { | |
403 if (word & 0x60) | |
404 ldr_str_ext(sec, off, word); | |
405 else | |
406 multiply(word); | |
407 } | |
408 | |
409 static void | |
410 ldm_stm(word) | |
411 unsigned word; | |
412 { | |
413 int r, flag; | |
414 | |
415 printf("%s%s%c%c\t%s", word&0x100000 ? "ldm" : "stm", | |
416 condition_decode[word>>28], | |
417 word&0x800000 ? 'i' : 'd', word&0x01000000 ? 'b' : 'a', | |
418 regnames[(word>>16)&0xF]); | |
419 if (word & 0x200000) | |
420 putchar('!'); | |
421 fputs(", {", stdout); | |
422 flag = 0; | |
423 for (r = 0; r < 16; r++) | |
424 if (word & (1 << r)) { | |
425 if (flag) | |
426 fputs(", ", stdout); | |
427 fputs(regnames[r], stdout); | |
428 flag = 1; | |
429 } | |
430 putchar('}'); | |
431 if (word & 0x400000) | |
432 putchar('^'); | |
433 putchar('\n'); | |
434 } | |
435 | |
436 void | |
437 arm_disasm_line(sec, off) | |
438 struct internal_scnhdr *sec; | |
439 unsigned off; | |
440 { | |
441 unsigned word; | |
442 | |
443 word = get_u32(filemap + sec->data_offset + off); | |
444 printf("%08x\t", word); | |
445 if ((word >> 28) == 0xF) { | |
446 printf("<invalid-F>\n"); | |
447 return; | |
448 } | |
449 switch ((word >> 24) & 0xF) { | |
450 case 0: | |
451 case 1: | |
452 if ((word & 0x90) == 0x90) | |
453 dataproc_74_overlay(sec, off, word); | |
454 else | |
455 dataproc(word); | |
456 return; | |
457 case 2: | |
458 case 3: | |
459 dataproc(word); | |
460 return; | |
461 case 4: | |
462 ldr_str_imm_post(word); | |
463 return; | |
464 case 5: | |
465 ldr_str_imm_pre(sec, off, word); | |
466 return; | |
467 case 6: | |
468 ldr_str_reg_post(word); | |
469 return; | |
470 case 7: | |
471 ldr_str_reg_pre(word); | |
472 return; | |
473 case 8: | |
474 case 9: | |
475 ldm_stm(word); | |
476 return; | |
477 case 0xA: | |
478 case 0xB: | |
479 arm_branch(off, word); | |
480 return; | |
481 case 0xC: | |
482 case 0xD: | |
483 case 0xE: | |
484 printf("<COPROCESSOR>\n"); | |
485 return; | |
486 case 0xF: | |
487 printf("swi%s\t0x%x\n", condition_decode[word>>28], | |
488 word & 0xFFFFFF); | |
489 return; | |
490 } | |
491 } |