Mercurial > vba-clojure
comparison src/gba/armdis.cpp @ 1:f9f4f1b99eed
importing src directory
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 03 Mar 2012 10:31:27 -0600 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
0:8ced16adf2e1 | 1:f9f4f1b99eed |
---|---|
1 /************************************************************************/ | |
2 /* Arm/Thumb command set disassembler */ | |
3 /************************************************************************/ | |
4 #include <cstdio> | |
5 | |
6 #include "GBAGlobals.h" | |
7 #include "armdis.h" | |
8 #include "elf.h" | |
9 | |
10 struct Opcodes | |
11 { | |
12 u32 mask; | |
13 u32 cval; | |
14 const char *mnemonic; | |
15 }; | |
16 | |
17 const char hdig[] = "0123456789abcdef"; | |
18 | |
19 const char *decVals[16] = { | |
20 "0", "1", "2", "3", "4", "5", "6", "7", "8", | |
21 "9", "10", "11", "12", "13", "14", "15" | |
22 }; | |
23 | |
24 const char *regs[16] = { | |
25 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", | |
26 "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc" | |
27 }; | |
28 | |
29 const char *conditions[16] = { | |
30 "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", | |
31 "hi", "ls", "ge", "lt", "gt", "le", "", "nv" | |
32 }; | |
33 | |
34 const char *shifts[5] = { | |
35 "lsl", "lsr", "asr", "ror", "rrx" | |
36 }; | |
37 | |
38 const char *armMultLoadStore[12] = { | |
39 // non-stack | |
40 "da", "ia", "db", "ib", | |
41 // stack store | |
42 "ed", "ea", "fd", "fa", | |
43 // stack load | |
44 "fa", "fd", "ea", "ed" | |
45 }; | |
46 | |
47 const Opcodes thumbOpcodes[] = { | |
48 // Format 1 | |
49 { 0xf800, 0x0000, "lsl %r0, %r3, %o" }, | |
50 { 0xf800, 0x0800, "lsr %r0, %r3, %o" }, | |
51 { 0xf800, 0x1000, "asr %r0, %r3, %o" }, | |
52 // Format 2 | |
53 { 0xfe00, 0x1800, "add %r0, %r3, %r6" }, | |
54 { 0xfe00, 0x1a00, "sub %r0, %r3, %r6" }, | |
55 { 0xfe00, 0x1c00, "add %r0, %r3, %i" }, | |
56 { 0xfe00, 0x1e00, "sub %r0, %r3, %i" }, | |
57 // Format 3 | |
58 { 0xf800, 0x2000, "mov %r8, %O" }, | |
59 { 0xf800, 0x2800, "cmp %r8, %O" }, | |
60 { 0xf800, 0x3000, "add %r8, %O" }, | |
61 { 0xf800, 0x3800, "sub %r8, %O" }, | |
62 // Format 4 | |
63 { 0xffc0, 0x4000, "and %r0, %r3" }, | |
64 { 0xffc0, 0x4040, "eor %r0, %r3" }, | |
65 { 0xffc0, 0x4080, "lsl %r0, %r3" }, | |
66 { 0xffc0, 0x40c0, "lsr %r0, %r3" }, | |
67 { 0xffc0, 0x4100, "asr %r0, %r3" }, | |
68 { 0xffc0, 0x4140, "adc %r0, %r3" }, | |
69 { 0xffc0, 0x4180, "sbc %r0, %r3" }, | |
70 { 0xffc0, 0x41c0, "ror %r0, %r3" }, | |
71 { 0xffc0, 0x4200, "tst %r0, %r3" }, | |
72 { 0xffc0, 0x4240, "neg %r0, %r3" }, | |
73 { 0xffc0, 0x4280, "cmp %r0, %r3" }, | |
74 { 0xffc0, 0x42c0, "cmn %r0, %r3" }, | |
75 { 0xffc0, 0x4300, "orr %r0, %r3" }, | |
76 { 0xffc0, 0x4340, "mul %r0, %r3" }, | |
77 { 0xffc0, 0x4380, "bic %r0, %r3" }, | |
78 { 0xffc0, 0x43c0, "mvn %r0, %r3" }, | |
79 // Format 5 | |
80 { 0xff80, 0x4700, "bx %h36" }, | |
81 { 0xfcc0, 0x4400, "[ ??? ]" }, | |
82 { 0xff00, 0x4400, "add %h07, %h36" }, | |
83 { 0xff00, 0x4500, "cmp %h07, %h36" }, | |
84 { 0xff00, 0x4600, "mov %h07, %h36" }, | |
85 // Format 6 | |
86 { 0xf800, 0x4800, "ldr %r8, [%I] (=%J)" }, | |
87 // Format 7 | |
88 { 0xfa00, 0x5000, "str%b %r0, [%r3, %r6]" }, | |
89 { 0xfa00, 0x5800, "ldr%b %r0, [%r3, %r6]" }, | |
90 // Format 8 | |
91 { 0xfe00, 0x5200, "strh %r0, [%r3, %r6]" }, | |
92 { 0xfe00, 0x5600, "ldsb %r0, [%r3, %r6]" }, | |
93 { 0xfe00, 0x5a00, "ldrh %r0, [%r3, %r6]" }, | |
94 { 0xfe00, 0x5e00, "ldsh %r0, [%r3, %r6]" }, | |
95 // Format 9 | |
96 { 0xe800, 0x6000, "str%B %r0, [%r3, %p]" }, | |
97 { 0xe800, 0x6800, "ldr%B %r0, [%r3, %p]" }, | |
98 // Format 10 | |
99 { 0xf800, 0x8000, "strh %r0, [%r3, %e]" }, | |
100 { 0xf800, 0x8800, "ldrh %r0, [%r3, %e]" }, | |
101 // Format 11 | |
102 { 0xf800, 0x9000, "str %r8, [sp, %w]" }, | |
103 { 0xf800, 0x9800, "ldr %r8, [sp, %w]" }, | |
104 // Format 12 | |
105 { 0xf800, 0xa000, "add %r8, pc, %w (=%K)" }, | |
106 { 0xf800, 0xa800, "add %r8, sp, %w" }, | |
107 // Format 13 | |
108 { 0xff00, 0xb000, "add sp, %s" }, | |
109 // Format 14 | |
110 { 0xffff, 0xb500, "push {lr}" }, | |
111 { 0xff00, 0xb400, "push {%l}" }, | |
112 { 0xff00, 0xb500, "push {%l,lr}" }, | |
113 { 0xffff, 0xbd00, "pop {pc}" }, | |
114 { 0xff00, 0xbd00, "pop {%l,pc}" }, | |
115 { 0xff00, 0xbc00, "pop {%l}" }, | |
116 // Format 15 | |
117 { 0xf800, 0xc000, "stmia %r8!, {%l}" }, | |
118 { 0xf800, 0xc800, "ldmia %r8!, {%l}" }, | |
119 // Format 17 | |
120 { 0xff00, 0xdf00, "swi %m" }, | |
121 // Format 16 | |
122 { 0xf000, 0xd000, "b%c %W" }, | |
123 // Format 18 | |
124 { 0xf800, 0xe000, "b %a" }, | |
125 // Format 19 | |
126 { 0xf800, 0xf000, "bl %A" }, | |
127 { 0xf800, 0xf800, "blh %Z" }, | |
128 { 0xff00, 0xbe00, "bkpt %O" }, | |
129 // Unknown | |
130 { 0x0000, 0x0000, "[ ??? ]" } | |
131 }; | |
132 | |
133 const Opcodes armOpcodes[] = { | |
134 // Undefined | |
135 { 0x0e000010, 0x06000010, "[ undefined ]" }, | |
136 // Branch instructions | |
137 { 0x0ff000f0, 0x01200010, "bx%c %r0" }, | |
138 { 0x0f000000, 0x0a000000, "b%c %o" }, | |
139 { 0x0f000000, 0x0b000000, "bl%c %o" }, | |
140 { 0x0f000000, 0x0f000000, "swi%c %q" }, | |
141 // PSR transfer | |
142 { 0x0fbf0fff, 0x010f0000, "mrs%c %r3, %p" }, | |
143 { 0x0db0f000, 0x0120f000, "msr%c %p, %i" }, | |
144 // Multiply instructions | |
145 { 0x0fe000f0, 0x00000090, "mul%c%s %r4, %r0, %r2" }, | |
146 { 0x0fe000f0, 0x00200090, "mla%c%s %r4, %r0, %r2, %r3" }, | |
147 { 0x0fa000f0, 0x00800090, "%umull%c%s %r3, %r4, %r0, %r2" }, | |
148 { 0x0fa000f0, 0x00a00090, "%umlal%c%s %r3, %r4, %r0, %r2" }, | |
149 // Load/Store instructions | |
150 { 0x0fb00ff0, 0x01000090, "swp%c%b %r3, %r0, [%r4]" }, | |
151 { 0x0fb000f0, 0x01000090, "[ ??? ]" }, | |
152 { 0x0c100000, 0x04000000, "str%c%b%t %r3, %a" }, | |
153 { 0x0c100000, 0x04100000, "ldr%c%b%t %r3, %a" }, | |
154 { 0x0e100090, 0x00000090, "str%c%h %r3, %a" }, | |
155 { 0x0e100090, 0x00100090, "ldr%c%h %r3, %a" }, | |
156 { 0x0e100000, 0x08000000, "stm%c%m %r4%l" }, | |
157 { 0x0e100000, 0x08100000, "ldm%c%m %r4%l" }, | |
158 // Data processing | |
159 { 0x0de00000, 0x00000000, "and%c%s %r3, %r4, %i" }, | |
160 { 0x0de00000, 0x00200000, "eor%c%s %r3, %r4, %i" }, | |
161 { 0x0de00000, 0x00400000, "sub%c%s %r3, %r4, %i" }, | |
162 { 0x0de00000, 0x00600000, "rsb%c%s %r3, %r4, %i" }, | |
163 { 0x0de00000, 0x00800000, "add%c%s %r3, %r4, %i" }, | |
164 { 0x0de00000, 0x00a00000, "adc%c%s %r3, %r4, %i" }, | |
165 { 0x0de00000, 0x00c00000, "sbc%c%s %r3, %r4, %i" }, | |
166 { 0x0de00000, 0x00e00000, "rsc%c%s %r3, %r4, %i" }, | |
167 { 0x0de00000, 0x01000000, "tst%c%s %r4, %i" }, | |
168 { 0x0de00000, 0x01200000, "teq%c%s %r4, %i" }, | |
169 { 0x0de00000, 0x01400000, "cmp%c%s %r4, %i" }, | |
170 { 0x0de00000, 0x01600000, "cmn%c%s %r4, %i" }, | |
171 { 0x0de00000, 0x01800000, "orr%c%s %r3, %r4, %i" }, | |
172 { 0x0de00000, 0x01a00000, "mov%c%s %r3, %i" }, | |
173 { 0x0de00000, 0x01c00000, "bic%c%s %r3, %r4, %i" }, | |
174 { 0x0de00000, 0x01e00000, "mvn%c%s %r3, %i" }, | |
175 // Coprocessor operations | |
176 { 0x0f000010, 0x0e000000, "cdp%c %P, %N, %r3, %R4, %R0%V" }, | |
177 { 0x0e100000, 0x0c000000, "stc%c%L %P, %r3, %A" }, | |
178 { 0x0f100010, 0x0e000010, "mcr%c %P, %N, %r3, %R4, %R0%V" }, | |
179 { 0x0f100010, 0x0e100010, "mrc%c %P, %N, %r3, %R4, %R0%V" }, | |
180 // Unknown | |
181 { 0x00000000, 0x00000000, "[ ??? ]" } | |
182 }; | |
183 | |
184 char *addStr(char *dest, const char *src) | |
185 { | |
186 while (*src) | |
187 { | |
188 *dest++ = *src++; | |
189 } | |
190 return dest; | |
191 } | |
192 | |
193 char *addHex(char *dest, int siz, u32 val) | |
194 { | |
195 if (siz == 0) | |
196 { | |
197 siz = 28; | |
198 while ((((val >> siz) & 15) == 0) && (siz >= 4)) | |
199 siz -= 4; | |
200 siz += 4; | |
201 } | |
202 while (siz > 0) | |
203 { | |
204 siz -= 4; | |
205 *dest++ = hdig[(val >> siz) & 15]; | |
206 } | |
207 return dest; | |
208 } | |
209 | |
210 int disArm(u32 offset, char *dest, int flags) | |
211 { | |
212 u32 opcode = debuggerReadMemory(offset); | |
213 | |
214 const Opcodes *sp = armOpcodes; | |
215 while (sp->cval != (opcode & sp->mask)) | |
216 sp++; | |
217 | |
218 if (flags & DIS_VIEW_ADDRESS) | |
219 { | |
220 dest = addHex(dest, 32, offset); | |
221 *dest++ = ' '; | |
222 } | |
223 if (flags & DIS_VIEW_CODE) | |
224 { | |
225 dest = addHex(dest, 32, opcode); | |
226 *dest++ = ' '; | |
227 } | |
228 | |
229 const char *src = sp->mnemonic; | |
230 while (*src) | |
231 { | |
232 if (*src != '%') | |
233 *dest++ = *src++; | |
234 else | |
235 { | |
236 src++; | |
237 switch (*src) | |
238 { | |
239 case 'c': | |
240 dest = addStr(dest, conditions[opcode >> 28]); | |
241 break; | |
242 case 'r': | |
243 dest = addStr(dest, regs[(opcode >> ((*(++src) - '0') * 4)) & 15]); | |
244 break; | |
245 case 'o': | |
246 { | |
247 *dest++ = '$'; | |
248 int off = opcode & 0xffffff; | |
249 if (off & 0x800000) | |
250 off |= 0xff000000; | |
251 off <<= 2; | |
252 dest = addHex(dest, 32, offset + 8 + off); | |
253 } | |
254 break; | |
255 case 'i': | |
256 if (opcode & (1 << 25)) | |
257 { | |
258 dest = addStr(dest, "#0x"); | |
259 int imm = opcode & 0xff; | |
260 int rot = (opcode & 0xf00) >> 7; | |
261 int val = (imm << (32 - rot)) | (imm >> rot); | |
262 dest = addHex(dest, 0, val); | |
263 } | |
264 else | |
265 { | |
266 dest = addStr(dest, regs[opcode & 0x0f]); | |
267 int shi = (opcode >> 5) & 3; | |
268 int sdw = (opcode >> 7) & 0x1f; | |
269 if ((sdw == 0) && (shi == 3)) | |
270 shi = 4; | |
271 if ((sdw) || (opcode & 0x10) || (shi)) | |
272 { | |
273 dest = addStr(dest, ", "); | |
274 dest = addStr(dest, shifts[shi]); | |
275 if (opcode & 0x10) | |
276 { | |
277 *dest++ = ' '; | |
278 dest = addStr(dest, regs[(opcode >> 8) & 15]); | |
279 } | |
280 else | |
281 { | |
282 if (sdw == 0 && ((shi == 1) || (shi == 2))) | |
283 sdw = 32; | |
284 if (shi != 4) | |
285 { | |
286 dest = addStr(dest, " #0x"); | |
287 dest = addHex(dest, 8, sdw); | |
288 } | |
289 } | |
290 } | |
291 } | |
292 break; | |
293 case 'p': | |
294 if (opcode & (1 << 22)) | |
295 dest = addStr(dest, "spsr"); | |
296 else | |
297 dest = addStr(dest, "cpsr"); | |
298 if (opcode & 0x00F00000) | |
299 { | |
300 *dest++ = '_'; | |
301 if (opcode & 0x00080000) | |
302 *dest++ = 'f'; | |
303 if (opcode & 0x00040000) | |
304 *dest++ = 's'; | |
305 if (opcode & 0x00020000) | |
306 *dest++ = 'x'; | |
307 if (opcode & 0x00010000) | |
308 *dest++ = 'c'; | |
309 } | |
310 break; | |
311 case 's': | |
312 if (opcode & (1 << 20)) | |
313 *dest++ = 's'; | |
314 break; | |
315 case 'S': | |
316 if (opcode & (1 << 22)) | |
317 *dest++ = 's'; | |
318 break; | |
319 case 'u': | |
320 if (opcode & (1 << 22)) | |
321 *dest++ = 's'; | |
322 else | |
323 *dest++ = 'u'; | |
324 break; | |
325 case 'b': | |
326 if (opcode & (1 << 22)) | |
327 *dest++ = 'b'; | |
328 break; | |
329 case 'a': | |
330 if ((opcode & 0x076f0000) == 0x004f0000) | |
331 { | |
332 *dest++ = '['; | |
333 *dest++ = '$'; | |
334 int adr = offset + 8; | |
335 int add = (opcode & 15) | ((opcode >> 8) & 0xf0); | |
336 if (opcode & (1 << 23)) | |
337 adr += add; | |
338 else | |
339 adr -= add; | |
340 dest = addHex(dest, 32, adr); | |
341 *dest++ = ']'; | |
342 dest = addStr(dest, " (="); | |
343 *dest++ = '$'; | |
344 dest = addHex(dest, 32, debuggerReadMemory(adr)); | |
345 *dest++ = ')'; | |
346 } | |
347 if ((opcode & 0x072f0000) == 0x050f0000) | |
348 { | |
349 *dest++ = '['; | |
350 *dest++ = '$'; | |
351 int adr = offset + 8; | |
352 if (opcode & (1 << 23)) | |
353 adr += opcode & 0xfff; | |
354 else | |
355 adr -= opcode & 0xfff; | |
356 dest = addHex(dest, 32, adr); | |
357 *dest++ = ']'; | |
358 dest = addStr(dest, " (="); | |
359 *dest++ = '$'; | |
360 dest = addHex(dest, 32, debuggerReadMemory(adr)); | |
361 *dest++ = ')'; | |
362 } | |
363 else | |
364 { | |
365 int reg = (opcode >> 16) & 15; | |
366 *dest++ = '['; | |
367 dest = addStr(dest, regs[reg]); | |
368 if (!(opcode & (1 << 24))) | |
369 *dest++ = ']'; | |
370 if (((opcode & (1 << 25)) && (opcode & (1 << 26))) || (!(opcode & (1 << 22)) && !(opcode & (1 << 26)))) | |
371 { | |
372 dest = addStr(dest, ", "); | |
373 if (!(opcode & (1 << 23))) | |
374 *dest++ = '-'; | |
375 dest = addStr(dest, regs[opcode & 0x0f]); | |
376 int shi = (opcode >> 5) & 3; | |
377 if (opcode & (1 << 26)) | |
378 { | |
379 if (((opcode >> 7) & 0x1f) || (opcode & 0x10) || (shi == 1) || (shi == 2)) | |
380 { | |
381 dest = addStr(dest, ", "); | |
382 dest = addStr(dest, shifts[shi]); | |
383 if (opcode & 0x10) | |
384 { | |
385 *dest++ = ' '; | |
386 dest = addStr(dest, regs[(opcode >> 8) & 15]); | |
387 } | |
388 else | |
389 { | |
390 int sdw = (opcode >> 7) & 0x1f; | |
391 if (sdw == 0 && ((shi == 1) || (shi == 2))) | |
392 sdw = 32; | |
393 dest = addStr(dest, " #0x"); | |
394 dest = addHex(dest, 8, sdw); | |
395 } | |
396 } | |
397 } | |
398 } | |
399 else | |
400 { | |
401 int off; | |
402 if (opcode & (1 << 26)) | |
403 off = opcode & 0xfff; | |
404 else | |
405 off = (opcode & 15) | ((opcode >> 4) & 0xf0); | |
406 if (off) | |
407 { | |
408 dest = addStr(dest, ", "); | |
409 if (!(opcode & (1 << 23))) | |
410 *dest++ = '-'; | |
411 dest = addStr(dest, "#0x"); | |
412 dest = addHex(dest, 0, off); | |
413 } | |
414 } | |
415 if (opcode & (1 << 24)) | |
416 { | |
417 *dest++ = ']'; | |
418 if (opcode & (1 << 21)) | |
419 *dest++ = '!'; | |
420 } | |
421 } | |
422 break; | |
423 case 't': | |
424 if ((opcode & 0x01200000) == 0x01200000) | |
425 *dest++ = 't'; | |
426 break; | |
427 case 'h': | |
428 if (opcode & (1 << 6)) | |
429 *dest++ = 's'; | |
430 if (opcode & (1 << 5)) | |
431 *dest++ = 'h'; | |
432 else | |
433 *dest++ = 'b'; | |
434 break; | |
435 case 'm': | |
436 if (((opcode >> 16) & 15) == 13) | |
437 { | |
438 if (opcode & 0x00100000) | |
439 dest = addStr(dest, armMultLoadStore[8 + ((opcode >> 23) & 3)]); | |
440 else | |
441 dest = addStr(dest, armMultLoadStore[4 + ((opcode >> 23) & 3)]); | |
442 } | |
443 else | |
444 dest = addStr(dest, armMultLoadStore[(opcode >> 23) & 3]); | |
445 break; | |
446 case 'l': | |
447 if (opcode & (1 << 21)) | |
448 *dest++ = '!'; | |
449 dest = addStr(dest, ", {"); | |
450 { | |
451 int rlst = opcode & 0xffff; | |
452 int msk = 0; | |
453 int not_first = 0; | |
454 while (msk < 16) | |
455 { | |
456 if (rlst & (1 << msk)) | |
457 { | |
458 int fr = msk; | |
459 while (rlst & (1 << msk)) | |
460 msk++; | |
461 int to = msk - 1; | |
462 if (not_first) | |
463 //dest = addStr(dest, ", "); | |
464 *dest++ = ','; | |
465 dest = addStr(dest, regs[fr]); | |
466 if (fr != to) | |
467 { | |
468 if (fr == to - 1) | |
469 //dest = addStr(", "); | |
470 *dest++ = ','; | |
471 else | |
472 *dest++ = '-'; | |
473 dest = addStr(dest, regs[to]); | |
474 } | |
475 not_first = 1; | |
476 } | |
477 else | |
478 msk++; | |
479 } | |
480 *dest++ = '}'; | |
481 if (opcode & (1 << 22)) | |
482 *dest++ = '^'; | |
483 } | |
484 break; | |
485 case 'q': | |
486 *dest++ = '$'; | |
487 dest = addHex(dest, 24, opcode & 0xffffff); | |
488 break; | |
489 case 'P': | |
490 *dest++ = 'p'; | |
491 dest = addStr(dest, decVals[(opcode >> 8) & 15]); | |
492 break; | |
493 case 'N': | |
494 if (opcode & 0x10) | |
495 dest = addStr(dest, decVals[(opcode >> 21) & 7]); | |
496 else | |
497 dest = addStr(dest, decVals[(opcode >> 20) & 15]); | |
498 break; | |
499 case 'R': | |
500 { | |
501 src++; | |
502 int reg = 4 * (*src - '0'); | |
503 *dest++ = 'c'; | |
504 dest = addStr(dest, decVals[(opcode >> reg) & 15]); | |
505 } | |
506 break; | |
507 case 'V': | |
508 { | |
509 int val = (opcode >> 5) & 7; | |
510 if (val) | |
511 { | |
512 dest = addStr(dest, ", "); | |
513 dest = addStr(dest, decVals[val]); | |
514 } | |
515 } | |
516 break; | |
517 case 'L': | |
518 if (opcode & (1 << 22)) | |
519 *dest++ = 'l'; | |
520 break; | |
521 case 'A': | |
522 if ((opcode & 0x012f0000) == 0x010f0000) | |
523 { | |
524 int adr = offset + 8; | |
525 int add = (opcode & 0xff) << 2; | |
526 if (opcode & (1 << 23)) | |
527 adr += add; | |
528 else | |
529 adr -= add; | |
530 *dest++ = '$'; | |
531 addHex(dest, 32, adr); | |
532 } | |
533 else | |
534 { | |
535 *dest++ = '['; | |
536 dest = addStr(dest, regs[(opcode >> 16) & 15]); | |
537 if (!(opcode & (1 << 24))) | |
538 *dest++ = ']'; | |
539 int off = (opcode & 0xff) << 2; | |
540 if (off) | |
541 { | |
542 dest = addStr(dest, ", "); | |
543 if (!(opcode & (1 << 23))) | |
544 *dest++ = '-'; | |
545 dest = addStr(dest, "#0x"); | |
546 dest = addHex(dest, 0, off); | |
547 } | |
548 if (opcode & (1 << 24)) | |
549 { | |
550 *dest++ = ']'; | |
551 if (opcode & (1 << 21)) | |
552 *dest++ = '!'; | |
553 } | |
554 } | |
555 break; | |
556 } | |
557 src++; | |
558 } | |
559 } | |
560 *dest++ = 0; | |
561 | |
562 return 4; | |
563 } | |
564 | |
565 int disThumb(u32 offset, char *dest, int flags) | |
566 { | |
567 u32 opcode = debuggerReadHalfWord(offset); | |
568 | |
569 const Opcodes *sp = thumbOpcodes; | |
570 int ret = 2; | |
571 while (sp->cval != (opcode & sp->mask)) | |
572 sp++; | |
573 | |
574 if (flags & DIS_VIEW_ADDRESS) | |
575 { | |
576 dest = addHex(dest, 32, offset); | |
577 *dest++ = ' '; | |
578 } | |
579 if (flags & DIS_VIEW_CODE) | |
580 { | |
581 dest = addHex(dest, 16, opcode); | |
582 *dest++ = ' '; | |
583 } | |
584 | |
585 const char *src = sp->mnemonic; | |
586 while (*src) | |
587 { | |
588 if (*src != '%') | |
589 *dest++ = *src++; | |
590 else | |
591 { | |
592 src++; | |
593 switch (*src) | |
594 { | |
595 case 'r': | |
596 src++; | |
597 dest = addStr(dest, regs[(opcode >> (*src - '0')) & 7]); | |
598 break; | |
599 case 'o': | |
600 dest = addStr(dest, "#0x"); | |
601 { | |
602 int val = (opcode >> 6) & 0x1f; | |
603 dest = addHex(dest, 8, val); | |
604 } | |
605 break; | |
606 case 'p': | |
607 dest = addStr(dest, "#0x"); | |
608 { | |
609 int val = (opcode >> 6) & 0x1f; | |
610 if (!(opcode & (1 << 12))) | |
611 val <<= 2; | |
612 dest = addHex(dest, 0, val); | |
613 } | |
614 break; | |
615 case 'e': | |
616 dest = addStr(dest, "#0x"); | |
617 dest = addHex(dest, 0, ((opcode >> 6) & 0x1f) << 1); | |
618 break; | |
619 case 'i': | |
620 dest = addStr(dest, "#0x"); | |
621 dest = addHex(dest, 0, (opcode >> 6) & 7); | |
622 break; | |
623 case 'h': | |
624 { | |
625 src++; | |
626 int reg = (opcode >> (*src - '0')) & 7; | |
627 src++; | |
628 if (opcode & (1 << (*src - '0'))) | |
629 reg += 8; | |
630 dest = addStr(dest, regs[reg]); | |
631 } | |
632 break; | |
633 case 'O': | |
634 dest = addStr(dest, "#0x"); | |
635 dest = addHex(dest, 0, (opcode & 0xff)); | |
636 break; | |
637 case 'I': | |
638 *dest++ = '$'; | |
639 dest = addHex(dest, 32, (offset & 0xfffffffc) + 4 + ((opcode & 0xff) << 2)); | |
640 break; | |
641 case 'J': | |
642 { | |
643 u32 value = debuggerReadMemory((offset & 0xfffffffc) + 4 + | |
644 ((opcode & 0xff) << 2)); | |
645 *dest++ = '$'; | |
646 dest = addHex(dest, 32, value); | |
647 const char *s = elfGetAddressSymbol(value); | |
648 if (*s) | |
649 { | |
650 *dest++ = ' '; | |
651 dest = addStr(dest, s); | |
652 } | |
653 } | |
654 break; | |
655 case 'K': | |
656 { | |
657 u32 value = (offset & 0xfffffffc) + 4 + ((opcode & 0xff) << 2); | |
658 *dest++ = '$'; | |
659 dest = addHex(dest, 32, value); | |
660 const char *s = elfGetAddressSymbol(value); | |
661 if (*s) | |
662 { | |
663 *dest++ = ' '; | |
664 dest = addStr(dest, s); | |
665 } | |
666 } | |
667 break; | |
668 case 'b': | |
669 if (opcode & (1 << 10)) | |
670 *dest++ = 'b'; | |
671 break; | |
672 case 'B': | |
673 if (opcode & (1 << 12)) | |
674 *dest++ = 'b'; | |
675 break; | |
676 case 'w': | |
677 dest = addStr(dest, "#0x"); | |
678 dest = addHex(dest, 0, (opcode & 0xff) << 2); | |
679 break; | |
680 case 'W': | |
681 *dest++ = '$'; | |
682 { | |
683 int add = opcode & 0xff; | |
684 if (add & 0x80) | |
685 add |= 0xffffff00; | |
686 dest = addHex(dest, 32, (offset & 0xfffffffe) + 4 + (add << 1)); | |
687 } | |
688 break; | |
689 case 'c': | |
690 dest = addStr(dest, conditions[(opcode >> 8) & 15]); | |
691 break; | |
692 case 's': | |
693 if (opcode & (1 << 7)) | |
694 *dest++ = '-'; | |
695 dest = addStr(dest, "#0x"); | |
696 dest = addHex(dest, 0, (opcode & 0x7f) << 2); | |
697 break; | |
698 case 'l': | |
699 { | |
700 int rlst = opcode & 0xff; | |
701 int msk = 0; | |
702 int not_first = 0; | |
703 while (msk < 8) | |
704 { | |
705 if (rlst & (1 << msk)) | |
706 { | |
707 int fr = msk; | |
708 while (rlst & (1 << msk)) | |
709 msk++; | |
710 int to = msk - 1; | |
711 if (not_first) | |
712 *dest++ = ','; | |
713 dest = addStr(dest, regs[fr]); | |
714 if (fr != to) | |
715 { | |
716 if (fr == to - 1) | |
717 *dest++ = ','; | |
718 else | |
719 *dest++ = '-'; | |
720 dest = addStr(dest, regs[to]); | |
721 } | |
722 not_first = 1; | |
723 } | |
724 else | |
725 msk++; | |
726 } | |
727 } | |
728 break; | |
729 case 'm': | |
730 *dest++ = '$'; | |
731 dest = addHex(dest, 8, opcode & 0xff); | |
732 break; | |
733 case 'Z': | |
734 *dest++ = '$'; | |
735 dest = addHex(dest, 16, (opcode & 0x7ff) << 1); | |
736 break; | |
737 case 'a': | |
738 *dest++ = '$'; | |
739 { | |
740 int add = opcode & 0x07ff; | |
741 if (add & 0x400) | |
742 add |= 0xfffff800; | |
743 add <<= 1; | |
744 dest = addHex(dest, 32, offset + 4 + add); | |
745 } | |
746 break; | |
747 case 'A': | |
748 { | |
749 int nopcode = debuggerReadHalfWord(offset + 2); | |
750 int add = opcode & 0x7ff; | |
751 if (add & 0x400) | |
752 add |= 0xfff800; | |
753 add = (add << 12) | ((nopcode & 0x7ff) << 1); | |
754 *dest++ = '$'; | |
755 dest = addHex(dest, 32, offset + 4 + add); | |
756 const char *s = elfGetAddressSymbol(offset + 4 + add); | |
757 if (*s) | |
758 { | |
759 *dest++ = ' '; | |
760 *dest++ = '('; | |
761 dest = addStr(dest, s); | |
762 *dest++ = ')'; | |
763 } | |
764 ret = 4; | |
765 } | |
766 break; | |
767 } | |
768 src++; | |
769 } | |
770 } | |
771 *dest++ = 0; | |
772 return ret; | |
773 } | |
774 |