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