FreeCalypso > hg > freecalypso-reveng
comparison leo-obj/tool/thumbdis.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/thumbdis.c@ca82528ec84d |
children | daeaa5950d10 |
comparison
equal
deleted
inserted
replaced
129:597143ba1c37 | 130:87b82398a08b |
---|---|
1 /* | |
2 * Thumb 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 void | |
19 format_1_2(word) | |
20 unsigned word; | |
21 { | |
22 unsigned op, imm; | |
23 | |
24 op = (word >> 11) & 3; | |
25 if (op != 3) { | |
26 /* format 1 */ | |
27 imm = (word >> 6) & 0x1F; | |
28 if (op != 0 && imm == 0) | |
29 imm = 32; | |
30 printf("%s\t%s, %s, #%u\n", shift_types[op], regnames[word&7], | |
31 regnames[(word>>3)&7], imm); | |
32 return; | |
33 } | |
34 /* format 2 */ | |
35 printf("%s\t%s, %s, ", word&0x200 ? "sub" : "add", regnames[word&7], | |
36 regnames[(word>>3)&7]); | |
37 if (word & 0x400) | |
38 printf("#%u\n", (word >> 6) & 7); | |
39 else | |
40 printf("%s\n", regnames[(word >> 6) & 7]); | |
41 } | |
42 | |
43 static void | |
44 format_3(word) | |
45 unsigned word; | |
46 { | |
47 static char *opctab[4] = {"mov", "cmp", "add", "sub"}; | |
48 unsigned imm; | |
49 | |
50 imm = word & 0xFF; | |
51 printf("%s\t%s, #%u", opctab[(word>>11)&3], regnames[(word>>8)&7], imm); | |
52 if (imm > 9) | |
53 printf("\t; 0x%x", imm); | |
54 putchar('\n'); | |
55 } | |
56 | |
57 static void | |
58 format_4(word) | |
59 unsigned word; | |
60 { | |
61 static char *opc[16] = {"and", "eor", "lsl", "lsr", | |
62 "asr", "adc", "sbc", "ror", | |
63 "tst", "neg", "cmp", "cmn", | |
64 "orr", "mul", "bic", "mvn"}; | |
65 | |
66 printf("%s\t%s, %s\n", opc[(word>>6)&0xF], regnames[word&7], | |
67 regnames[(word>>3)&7]); | |
68 } | |
69 | |
70 static void | |
71 format_5_bx(word) | |
72 unsigned word; | |
73 { | |
74 if (word & 0x80) | |
75 printf("<invalid: blx instead of bx>\n"); | |
76 else | |
77 printf("bx\t%s\n", regnames[(word>>3)&0xF]); | |
78 } | |
79 | |
80 static void | |
81 format_5_hiops(word) | |
82 unsigned word; | |
83 { | |
84 static char *opctab[3] = {"add", "cmp", "mov"}; | |
85 int reg1, reg2, op; | |
86 | |
87 if (word & 0xC0) { | |
88 reg1 = word & 7; | |
89 if (word & 0x80) | |
90 reg1 += 8; | |
91 reg2 = (word >> 3) & 0xF; | |
92 op = (word >> 8) & 3; | |
93 if (op == 2 && reg1 == reg2 && reg1 != 15) | |
94 printf("nop\t\t\t(mov %s, %s)\n", | |
95 regnames[reg1], regnames[reg2]); | |
96 else | |
97 printf("%s\t%s, %s\n", opctab[op], | |
98 regnames[reg1], regnames[reg2]); | |
99 } else | |
100 printf("<invalid: hi-reg format with both low regs>\n"); | |
101 } | |
102 | |
103 static void | |
104 format_5(word) | |
105 unsigned word; | |
106 { | |
107 if ((word & 0x300) == 0x300) | |
108 format_5_bx(word); | |
109 else | |
110 format_5_hiops(word); | |
111 } | |
112 | |
113 static void | |
114 format_6(sec, off, word) | |
115 struct internal_scnhdr *sec; | |
116 unsigned off, word; | |
117 { | |
118 unsigned loff, litoff, datum; | |
119 struct internal_reloc *rel; | |
120 | |
121 loff = (word & 0xFF) << 2; | |
122 off &= ~3; | |
123 off += 4; | |
124 litoff = off + loff; | |
125 if (litoff+4 <= sec->size) { | |
126 rel = find_word32_reloc(sec, litoff); | |
127 datum = get_u32(filemap + sec->data_offset + litoff); | |
128 printf("ldr\t%s, =", regnames[(word>>8)&7]); | |
129 if (rel) | |
130 disasm_reloc_target(sec, rel, datum); | |
131 else | |
132 printf("0x%x", datum); | |
133 printf("\t; via 0x%x\n", litoff); | |
134 } else | |
135 printf("ldr\t%s, [pc, #%u]\t(0x%x)\n", regnames[(word>>8)&7], | |
136 loff, litoff); | |
137 } | |
138 | |
139 static void | |
140 format_7(word) | |
141 unsigned word; | |
142 { | |
143 printf("%s%s\t%s, [%s, %s]\n", word&0x800 ? "ldr" : "str", | |
144 word&0x400 ? "b" : "", regnames[word&7], | |
145 regnames[(word>>3)&7], regnames[(word>>6)&7]); | |
146 } | |
147 | |
148 static void | |
149 format_8(word) | |
150 unsigned word; | |
151 { | |
152 static char *opc[4] = {"strh", "ldrsb", "ldrh", "ldrsh"}; | |
153 | |
154 printf("%s\t%s, [%s, %s]\n", opc[(word>>10)&3], regnames[word&7], | |
155 regnames[(word>>3)&7], regnames[(word>>6)&7]); | |
156 } | |
157 | |
158 static void | |
159 format_9(word) | |
160 unsigned word; | |
161 { | |
162 unsigned loff; | |
163 | |
164 loff = (word >> 6) & 0x1F; | |
165 if (!(word & 0x1000)) | |
166 loff <<= 2; | |
167 printf("%s%s\t%s, [%s, #%u]", word&0x800 ? "ldr" : "str", | |
168 word&0x1000 ? "b" : "", regnames[word&7], | |
169 regnames[(word>>3)&7], loff); | |
170 if (loff >= 10) | |
171 printf("\t; 0x%x", loff); | |
172 putchar('\n'); | |
173 } | |
174 | |
175 static void | |
176 format_10(word) | |
177 unsigned word; | |
178 { | |
179 unsigned loff; | |
180 | |
181 loff = (word >> 6) & 0x1F; | |
182 loff <<= 1; | |
183 printf("%sh\t%s, [%s, #%u]", word&0x800 ? "ldr" : "str", | |
184 regnames[word&7], regnames[(word>>3)&7], loff); | |
185 if (loff >= 10) | |
186 printf("\t; 0x%x", loff); | |
187 putchar('\n'); | |
188 } | |
189 | |
190 static void | |
191 format_11(word) | |
192 unsigned word; | |
193 { | |
194 unsigned loff; | |
195 | |
196 loff = (word & 0xFF) << 2; | |
197 printf("%s\t%s, [sp, #%u]", word&0x800 ? "ldr" : "str", | |
198 regnames[(word>>8)&7], loff); | |
199 if (loff >= 10) | |
200 printf("\t; 0x%x", loff); | |
201 putchar('\n'); | |
202 } | |
203 | |
204 static void | |
205 format_12(off, word) | |
206 unsigned off, word; | |
207 { | |
208 unsigned loff; | |
209 | |
210 loff = (word & 0xFF) << 2; | |
211 printf("add\t%s, ", regnames[(word>>8)&7]); | |
212 if (word & 0x800) { | |
213 printf("sp, #%u", loff); | |
214 if (loff >= 10) | |
215 printf("\t; 0x%x", loff); | |
216 putchar('\n'); | |
217 } else { | |
218 off &= ~3; | |
219 printf("pc, #%u\t; 0x%x\n", loff, off + 4 + loff); | |
220 } | |
221 } | |
222 | |
223 static void | |
224 format_13(word) | |
225 unsigned word; | |
226 { | |
227 unsigned loff; | |
228 | |
229 if ((word & 0xFF00) != 0xB000) { | |
230 printf("<invalid format 13>\n"); | |
231 return; | |
232 } | |
233 loff = (word & 0x7F) << 2; | |
234 printf("%s\tsp, #%u", word&0x80 ? "sub" : "add", loff); | |
235 if (loff >= 10) | |
236 printf("\t; 0x%x", loff); | |
237 putchar('\n'); | |
238 } | |
239 | |
240 static void | |
241 format_14(word) | |
242 unsigned word; | |
243 { | |
244 int r, flag; | |
245 | |
246 if ((word & 0xF600) != 0xB400) { | |
247 printf("<invalid format 14>\n"); | |
248 return; | |
249 } | |
250 printf("%s\t{", word&0x800 ? "pop" : "push"); | |
251 flag = 0; | |
252 for (r = 0; r < 9; r++) | |
253 if (word & (1 << r)) { | |
254 if (flag) | |
255 fputs(", ", stdout); | |
256 if (r == 8) | |
257 fputs(word&0x800 ? "pc" : "lr", stdout); | |
258 else | |
259 fputs(regnames[r], stdout); | |
260 flag = 1; | |
261 } | |
262 putchar('}'); | |
263 putchar('\n'); | |
264 } | |
265 | |
266 static void | |
267 format_15(word) | |
268 unsigned word; | |
269 { | |
270 int r, flag; | |
271 | |
272 printf("%sia\t%s!, {", word&0x800 ? "ldm" : "stm", | |
273 regnames[(word>>8)&7]); | |
274 flag = 0; | |
275 for (r = 0; r < 8; r++) | |
276 if (word & (1 << r)) { | |
277 if (flag) | |
278 fputs(", ", stdout); | |
279 fputs(regnames[r], stdout); | |
280 flag = 1; | |
281 } | |
282 putchar('}'); | |
283 putchar('\n'); | |
284 } | |
285 | |
286 static void | |
287 format_16_17(off, word) | |
288 unsigned off, word; | |
289 { | |
290 unsigned cond; | |
291 unsigned dest; | |
292 | |
293 cond = (word >> 8) & 0xF; | |
294 switch (cond) { | |
295 case 0xE: | |
296 printf("<invalid: bal>\n"); | |
297 return; | |
298 case 0xF: | |
299 printf("swi\t0x%x\n", word & 0xFF); | |
300 return; | |
301 } | |
302 dest = (word & 0xFF) << 1; | |
303 if (dest & 0x00000100) | |
304 dest |= 0xFFFFFE00; | |
305 dest += off + 4; | |
306 printf("b%s\t0x%x\n", condition_decode[cond], dest); | |
307 } | |
308 | |
309 static void | |
310 format_18(off, word) | |
311 unsigned off, word; | |
312 { | |
313 unsigned dest; | |
314 | |
315 if (word & 0x800) { | |
316 printf("<invalid format 18>\n"); | |
317 return; | |
318 } | |
319 dest = (word & 0x7FF) << 1; | |
320 if (dest & 0x00000800) | |
321 dest |= 0xFFFFF000; | |
322 dest += off + 4; | |
323 printf("b\t0x%x\n", dest); | |
324 } | |
325 | |
326 void | |
327 thumb_disasm_line(sec, off) | |
328 struct internal_scnhdr *sec; | |
329 unsigned off; | |
330 { | |
331 unsigned word; | |
332 | |
333 word = get_u16(filemap + sec->data_offset + off); | |
334 printf("%04x\t\t", word); | |
335 switch (word >> 12) { | |
336 case 0: | |
337 case 1: | |
338 format_1_2(word); | |
339 return; | |
340 case 2: | |
341 case 3: | |
342 format_3(word); | |
343 return; | |
344 case 4: | |
345 if (word & 0x800) | |
346 format_6(sec, off, word); | |
347 else if (word & 0x400) | |
348 format_5(word); | |
349 else | |
350 format_4(word); | |
351 return; | |
352 case 5: | |
353 if (word & 0x200) | |
354 format_8(word); | |
355 else | |
356 format_7(word); | |
357 return; | |
358 case 6: | |
359 case 7: | |
360 format_9(word); | |
361 return; | |
362 case 8: | |
363 format_10(word); | |
364 return; | |
365 case 9: | |
366 format_11(word); | |
367 return; | |
368 case 0xA: | |
369 format_12(off, word); | |
370 return; | |
371 case 0xB: | |
372 if (word & 0x400) | |
373 format_14(word); | |
374 else | |
375 format_13(word); | |
376 return; | |
377 case 0xC: | |
378 format_15(word); | |
379 return; | |
380 case 0xD: | |
381 format_16_17(off, word); | |
382 return; | |
383 case 0xE: | |
384 format_18(off, word); | |
385 return; | |
386 case 0xF: | |
387 printf("<half-bl>\n"); | |
388 return; | |
389 } | |
390 } | |
391 | |
392 thumb_check_bl(sec, off) | |
393 struct internal_scnhdr *sec; | |
394 unsigned off; | |
395 { | |
396 unsigned ins1, ins2; | |
397 unsigned dest; | |
398 | |
399 ins1 = get_u16(filemap + sec->data_offset + off); | |
400 if ((ins1 & 0xF800) != 0xF000) | |
401 return(0); | |
402 ins2 = get_u16(filemap + sec->data_offset + off + 2); | |
403 if ((ins2 & 0xF800) != 0xF800) | |
404 return(0); | |
405 /* match */ | |
406 dest = ((ins1 & 0x7FF) << 12) | ((ins2 & 0x7FF) << 1); | |
407 if (dest & 0x00400000) | |
408 dest |= 0xFF800000; | |
409 dest += off + 4; | |
410 printf("%04x %04x\tbl\t0x%x\n", ins1, ins2, dest); | |
411 return(1); | |
412 } | |
413 | |
414 void | |
415 thumb_bl_reloc(sec, rel) | |
416 struct internal_scnhdr *sec; | |
417 struct internal_reloc *rel; | |
418 { | |
419 unsigned ins1, ins2; | |
420 unsigned dest; | |
421 | |
422 ins1 = get_u16(filemap + sec->data_offset + rel->location); | |
423 ins2 = get_u16(filemap + sec->data_offset + rel->location + 2); | |
424 printf("%04x %04x R\t", ins1, ins2); | |
425 if ((ins1 & 0xF800) != 0xF000 || (ins2 & 0xF800) != 0xF800) { | |
426 printf("<invalid Thumb_BL reloc: opcode not BL>\n"); | |
427 return; | |
428 } | |
429 dest = ((ins1 & 0x7FF) << 12) | ((ins2 & 0x7FF) << 1); | |
430 if (dest & 0x00400000) | |
431 dest |= 0xFF800000; | |
432 dest += rel->location + 4; | |
433 fputs("bl\t", stdout); | |
434 disasm_reloc_target(sec, rel, dest); | |
435 putchar('\n'); | |
436 } |