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