winedbg: Reorder disassembler functions to match instruction table order.
[wine] / programs / winedbg / be_arm.c
1 /*
2  * Debugger ARM specific functions
3  *
4  * Copyright 2000-2003 Marcus Meissner
5  *                2004 Eric Pouech
6  *           2010-2012 AndrĂ© Hentschel
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #include "debugger.h"
24
25 #if defined(__arm__) && !defined(__ARMEB__)
26
27 /*
28  * Switch to disassemble Thumb code.
29  */
30 static BOOL db_disasm_thumb = FALSE;
31
32 /*
33  * Flag to indicate whether we need to display instruction,
34  * or whether we just need to know the address of the next
35  * instruction.
36  */
37 static BOOL db_display = FALSE;
38
39 #define ARM_INSN_SIZE    4
40 #define THUMB_INSN_SIZE  2
41 #define THUMB2_INSN_SIZE 4
42
43 #define ROR32(n, r) (((n) >> (r)) | ((n) << (32 - (r))))
44
45 #define get_cond(ins)           tbl_cond[(ins >> 28) & 0x0f]
46 #define get_nibble(ins, num)    ((ins >> (num * 4)) & 0x0f)
47
48 static char const tbl_regs[][4] = {
49     "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",
50     "fp", "ip", "sp", "lr", "pc", "cpsr"
51 };
52
53 static char const tbl_addrmode[][3] = {
54     "da", "ia", "db", "ib"
55 };
56
57 static char const tbl_cond[][3] = {
58     "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", "hi", "ls", "ge", "lt", "gt", "le", "", ""
59 };
60
61 static char const tbl_dataops[][4] = {
62     "and", "eor", "sub", "rsb", "add", "adc", "sbc", "rsc", "tst", "teq", "cmp", "cmn", "orr",
63     "mov", "bic", "mvn"
64 };
65
66 static char const tbl_shifts[][4] = {
67     "lsl", "lsr", "asr", "ror"
68 };
69
70 static char const tbl_hiops_t[][4] = {
71     "add", "cmp", "mov", "bx"
72 };
73
74 static char const tbl_aluops_t[][4] = {
75     "and", "eor", "lsl", "lsr", "asr", "adc", "sbc", "ror", "tst", "neg", "cmp", "cmn", "orr",
76     "mul", "bic", "mvn"
77 };
78
79 static char const tbl_immops_t[][4] = {
80     "mov", "cmp", "add", "sub"
81 };
82
83 static char const tbl_sregops_t[][5] = {
84     "strh", "ldsb", "ldrh", "ldsh"
85 };
86
87 static char const tbl_miscops_t2[][6] = {
88     "rev", "rev16", "rbit", "revsh"
89 };
90
91 static char const tbl_width_t2[][2] = {
92     "b", "h", "", "?"
93 };
94
95 static char const tbl_special_regs_t2[][12] = {
96     "apsr", "iapsr", "eapsr", "xpsr", "rsvd", "ipsr", "epsr", "iepsr", "msp", "psp", "rsvd", "rsvd",
97     "rsvd", "rsvd", "rsvd", "rsvd", "primask", "basepri", "basepri_max", "faultmask", "control"
98 };
99
100 static char const tbl_hints_t2[][6] = {
101     "nop", "yield", "wfe", "wfi", "sev"
102 };
103
104 static UINT db_get_inst(void* addr, int size)
105 {
106     UINT result = 0;
107     char buffer[4];
108
109     if (dbg_read_memory(addr, buffer, size))
110     {
111         switch (size)
112         {
113         case 4:
114             result = *(UINT*)buffer;
115             break;
116         case 2:
117             result = *(WORD*)buffer;
118             break;
119         }
120     }
121     return result;
122 }
123
124 static void db_printsym(unsigned int addr)
125 {
126     ADDRESS64   a;
127
128     a.Mode   = AddrModeFlat;
129     a.Offset = addr;
130
131     print_address(&a, TRUE);
132 }
133
134 static UINT arm_disasm_branch(UINT inst, ADDRESS64 *addr)
135 {
136     short link = (inst >> 24) & 0x01;
137     int offset = (inst << 2) & 0x03ffffff;
138
139     if (offset & 0x02000000) offset |= 0xfc000000;
140     offset += 8;
141
142     dbg_printf("\n\tb%s%s\t", link ? "l" : "", get_cond(inst));
143     db_printsym(addr->Offset + offset);
144     return 0;
145 }
146
147 static UINT arm_disasm_mul(UINT inst, ADDRESS64 *addr)
148 {
149     short accu = (inst >> 21) & 0x01;
150     short condcodes = (inst >> 20) & 0x01;
151
152     if (accu)
153         dbg_printf("\n\tmla%s%s\t%s, %s, %s, %s", get_cond(inst), condcodes ? "s" : "",
154                    tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)],
155                    tbl_regs[get_nibble(inst, 2)], tbl_regs[get_nibble(inst, 3)]);
156     else
157         dbg_printf("\n\tmul%s%s\t%s, %s, %s", get_cond(inst), condcodes ? "s" : "",
158                    tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)],
159                    tbl_regs[get_nibble(inst, 2)]);
160     return 0;
161 }
162
163 static UINT arm_disasm_longmul(UINT inst, ADDRESS64 *addr)
164 {
165     short sign = (inst >> 22) & 0x01;
166     short accu = (inst >> 21) & 0x01;
167     short condcodes = (inst >> 20) & 0x01;
168
169     dbg_printf("\n\t%s%s%s%s\t%s, %s, %s, %s", sign ? "s" : "u", accu ? "mlal" : "mull",
170                get_cond(inst), condcodes ? "s" : "",
171                tbl_regs[get_nibble(inst, 3)], tbl_regs[get_nibble(inst, 4)],
172                tbl_regs[get_nibble(inst, 0)], tbl_regs[get_nibble(inst, 2)]);
173     return 0;
174 }
175
176 static UINT arm_disasm_swp(UINT inst, ADDRESS64 *addr)
177 {
178     short byte = (inst >> 22) & 0x01;
179
180     dbg_printf("\n\tswp%s%s\t%s, %s, [%s]", get_cond(inst), byte ? "b" : "",
181                tbl_regs[get_nibble(inst, 3)], tbl_regs[get_nibble(inst, 0)],
182                tbl_regs[get_nibble(inst, 4)]);
183     return 0;
184 }
185
186 static UINT arm_disasm_halfwordtrans(UINT inst, ADDRESS64 *addr)
187 {
188     short halfword  = (inst >> 5)  & 0x01;
189     short sign      = (inst >> 6)  & 0x01;
190     short load      = (inst >> 20) & 0x01;
191     short writeback = (inst >> 21) & 0x01;
192     short immediate = (inst >> 22) & 0x01;
193     short direction = (inst >> 23) & 0x01;
194     short indexing  = (inst >> 24) & 0x01;
195     short offset    = ((inst >> 4) & 0xf0) + (inst & 0x0f);
196
197     if (!direction) offset *= -1;
198
199     dbg_printf("\n\t%s%s%s%s%s", load ? "ldr" : "str", sign ? "s" : "",
200                halfword ? "h" : (sign ? "b" : ""), writeback ? "t" : "", get_cond(inst));
201     dbg_printf("\t%s, ", tbl_regs[get_nibble(inst, 3)]);
202     if (indexing)
203     {
204         if (immediate)
205             dbg_printf("[%s, #%d]", tbl_regs[get_nibble(inst, 4)], offset);
206         else
207             dbg_printf("[%s, %s]", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
208     }
209     else
210     {
211         if (immediate)
212             dbg_printf("[%s], #%d", tbl_regs[get_nibble(inst, 4)], offset);
213         else
214             dbg_printf("[%s], %s", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
215     }
216     return 0;
217 }
218
219 static UINT arm_disasm_branchreg(UINT inst, ADDRESS64 *addr)
220 {
221     dbg_printf("\n\tb%s\t%s", get_cond(inst), tbl_regs[get_nibble(inst, 0)]);
222     return 0;
223 }
224
225 static UINT arm_disasm_branchxchg(UINT inst, ADDRESS64 *addr)
226 {
227     dbg_printf("\n\tbx%s\t%s", get_cond(inst), tbl_regs[get_nibble(inst, 0)]);
228     return 0;
229 }
230
231 static UINT arm_disasm_mrstrans(UINT inst, ADDRESS64 *addr)
232 {
233     short src = (inst >> 22) & 0x01;
234
235     dbg_printf("\n\tmrs%s\t%s, %s", get_cond(inst), tbl_regs[get_nibble(inst, 3)],
236                src ? "spsr" : "cpsr");
237     return 0;
238 }
239
240 static UINT arm_disasm_msrtrans(UINT inst, ADDRESS64 *addr)
241 {
242     short immediate = (inst >> 25) & 0x01;
243     short dst = (inst >> 22) & 0x01;
244     short simple = (inst >> 16) & 0x01;
245
246     if (simple || !immediate)
247     {
248         dbg_printf("\n\tmsr%s\t%s, %s", get_cond(inst), dst ? "spsr" : "cpsr",
249                    tbl_regs[get_nibble(inst, 0)]);
250         return 0;
251     }
252
253     dbg_printf("\n\tmsr%s\t%s, #%u", get_cond(inst), dst ? "spsr" : "cpsr",
254                ROR32(inst & 0xff, 2 * get_nibble(inst, 2)));
255     return 0;
256 }
257
258 static UINT arm_disasm_wordmov(UINT inst, ADDRESS64 *addr)
259 {
260     short top = (inst >> 22) & 0x01;
261
262     dbg_printf("\n\tmov%s%s\t%s, #%u", top ? "t" : "w", get_cond(inst),
263                tbl_regs[get_nibble(inst, 3)], (get_nibble(inst, 4) << 12) | (inst & 0x0fff));
264     return 0;
265 }
266
267 static UINT arm_disasm_nop(UINT inst, ADDRESS64 *addr)
268 {
269     dbg_printf("\n\tnop%s", get_cond(inst));
270     return 0;
271 }
272
273 static UINT arm_disasm_dataprocessing(UINT inst, ADDRESS64 *addr)
274 {
275     short condcodes = (inst >> 20) & 0x01;
276     short opcode    = (inst >> 21) & 0x0f;
277     short immediate = (inst >> 25) & 0x01;
278     short no_op1    = (opcode & 0x0d) == 0x0d;
279     short no_dst    = (opcode & 0x0c) == 0x08;
280
281     dbg_printf("\n\t%s%s%s", tbl_dataops[opcode], condcodes ? "s" : "", get_cond(inst));
282     if (!no_dst) dbg_printf("\t%s, ", tbl_regs[get_nibble(inst, 3)]);
283     else dbg_printf("\t");
284
285     if (no_op1)
286     {
287         if (immediate)
288             dbg_printf("#%u", ROR32(inst & 0xff, 2 * get_nibble(inst, 2)));
289         else
290             dbg_printf("%s", tbl_regs[get_nibble(inst, 0)]);
291     }
292     else
293     {
294         if (immediate)
295             dbg_printf("%s, #%u", tbl_regs[get_nibble(inst, 4)],
296                        ROR32(inst & 0xff, 2 * get_nibble(inst, 2)));
297         else if (((inst >> 4) & 0xff) == 0x00) /* no shift */
298             dbg_printf("%s, %s", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
299         else if (((inst >> 4) & 0x09) == 0x01) /* register shift */
300             dbg_printf("%s, %s, %s %s", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)],
301                        tbl_shifts[(inst >> 5) & 0x03], tbl_regs[(inst >> 8) & 0x0f]);
302         else if (((inst >> 4) & 0x01) == 0x00) /* immediate shift */
303             dbg_printf("%s, %s, %s #%d", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)],
304                        tbl_shifts[(inst >> 5) & 0x03], (inst >> 7) & 0x1f);
305         else
306             return inst;
307     }
308     return 0;
309 }
310
311 static UINT arm_disasm_singletrans(UINT inst, ADDRESS64 *addr)
312 {
313     short load      = (inst >> 20) & 0x01;
314     short writeback = (inst >> 21) & 0x01;
315     short byte      = (inst >> 22) & 0x01;
316     short direction = (inst >> 23) & 0x01;
317     short indexing  = (inst >> 24) & 0x01;
318     short immediate = !((inst >> 25) & 0x01);
319     short offset    = inst & 0x0fff;
320
321     if (!direction) offset *= -1;
322
323     dbg_printf("\n\t%s%s%s%s", load ? "ldr" : "str", byte ? "b" : "", writeback ? "t" : "",
324                get_cond(inst));
325     dbg_printf("\t%s, ", tbl_regs[get_nibble(inst, 3)]);
326     if (indexing)
327     {
328         if (immediate)
329             dbg_printf("[%s, #%d]", tbl_regs[get_nibble(inst, 4)], offset);
330         else if (((inst >> 4) & 0xff) == 0x00) /* no shift */
331             dbg_printf("[%s, %s]", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
332         else if (((inst >> 4) & 0x01) == 0x00) /* immediate shift (there's no register shift) */
333             dbg_printf("[%s, %s, %s #%d]", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)],
334                        tbl_shifts[(inst >> 5) & 0x03], (inst >> 7) & 0x1f);
335         else
336             return inst;
337     }
338     else
339     {
340         if (immediate)
341             dbg_printf("[%s], #%d", tbl_regs[get_nibble(inst, 4)], offset);
342         else if (((inst >> 4) & 0xff) == 0x00) /* no shift */
343             dbg_printf("[%s], %s", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
344         else if (((inst >> 4) & 0x01) == 0x00) /* immediate shift (there's no register shift) */
345             dbg_printf("[%s], %s, %s #%d", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)],
346                        tbl_shifts[(inst >> 5) & 0x03], (inst >> 7) & 0x1f);
347         else
348             return inst;
349     }
350     return 0;
351 }
352
353 static UINT arm_disasm_blocktrans(UINT inst, ADDRESS64 *addr)
354 {
355     short load      = (inst >> 20) & 0x01;
356     short writeback = (inst >> 21) & 0x01;
357     short psr       = (inst >> 22) & 0x01;
358     short addrmode  = (inst >> 23) & 0x03;
359     short i;
360     short last=15;
361     for (i=15;i>=0;i--)
362         if ((inst>>i) & 1)
363         {
364             last = i;
365             break;
366         }
367
368     dbg_printf("\n\t%s%s%s\t%s%s, {", load ? "ldm" : "stm", tbl_addrmode[addrmode], get_cond(inst),
369                tbl_regs[get_nibble(inst, 4)], writeback ? "!" : "");
370     for (i=0;i<=15;i++)
371         if ((inst>>i) & 1)
372         {
373             if (i == last) dbg_printf("%s", tbl_regs[i]);
374             else dbg_printf("%s, ", tbl_regs[i]);
375         }
376     dbg_printf("}%s", psr ? "^" : "");
377     return 0;
378 }
379
380 static UINT arm_disasm_swi(UINT inst, ADDRESS64 *addr)
381 {
382     dbg_printf("\n\tswi%s\t#%d", get_cond(inst), inst & 0x00ffffff);
383     return 0;
384 }
385
386 static UINT arm_disasm_coproctrans(UINT inst, ADDRESS64 *addr)
387 {
388     WORD CRm    = inst & 0x0f;
389     WORD CP     = (inst >> 5)  & 0x07;
390     WORD CPnum  = (inst >> 8)  & 0x0f;
391     WORD CRn    = (inst >> 16) & 0x0f;
392     WORD load   = (inst >> 20) & 0x01;
393     WORD CP_Opc = (inst >> 21) & 0x07;
394
395     dbg_printf("\n\t%s%s\t%u, %u, %s, cr%u, cr%u, {%u}", load ? "mrc" : "mcr", get_cond(inst), CPnum,
396                CP, tbl_regs[get_nibble(inst, 3)], CRn, CRm, CP_Opc);
397     return 0;
398 }
399
400 static UINT arm_disasm_coprocdataop(UINT inst, ADDRESS64 *addr)
401 {
402     WORD CRm    = inst & 0x0f;
403     WORD CP     = (inst >> 5)  & 0x07;
404     WORD CPnum  = (inst >> 8)  & 0x0f;
405     WORD CRd    = (inst >> 12) & 0x0f;
406     WORD CRn    = (inst >> 16) & 0x0f;
407     WORD CP_Opc = (inst >> 20) & 0x0f;
408
409     dbg_printf("\n\tcdp%s\t%u, %u, cr%u, cr%u, cr%u, {%u}", get_cond(inst),
410                CPnum, CP, CRd, CRn, CRm, CP_Opc);
411     return 0;
412 }
413
414 static UINT arm_disasm_coprocdatatrans(UINT inst, ADDRESS64 *addr)
415 {
416     WORD CPnum  = (inst >> 8)  & 0x0f;
417     WORD CRd    = (inst >> 12) & 0x0f;
418     WORD load      = (inst >> 20) & 0x01;
419     WORD writeback = (inst >> 21) & 0x01;
420     WORD translen  = (inst >> 22) & 0x01;
421     WORD direction = (inst >> 23) & 0x01;
422     WORD indexing  = (inst >> 24) & 0x01;
423     short offset    = (inst & 0xff) << 2;
424
425     if (!direction) offset *= -1;
426
427     dbg_printf("\n\t%s%s%s", load ? "ldc" : "stc", translen ? "l" : "", get_cond(inst));
428     if (indexing)
429         dbg_printf("\t%u, cr%u, [%s, #%d]%s", CPnum, CRd, tbl_regs[get_nibble(inst, 4)], offset, writeback?"!":"");
430     else
431         dbg_printf("\t%u, cr%u, [%s], #%d", CPnum, CRd, tbl_regs[get_nibble(inst, 4)], offset);
432     return 0;
433 }
434
435 static WORD thumb_disasm_hireg(WORD inst, ADDRESS64 *addr)
436 {
437     short dst = inst & 0x07;
438     short src = (inst >> 3) & 0x07;
439     short h2  = (inst >> 6) & 0x01;
440     short h1  = (inst >> 7) & 0x01;
441     short op  = (inst >> 8) & 0x03;
442
443     if (h1) dst += 8;
444     if (h2) src += 8;
445
446     if (op == 2 && dst == src) /* mov rx, rx */
447     {
448         dbg_printf("\n\tnop");
449         return 0;
450     }
451
452     if (op == 3)
453         dbg_printf("\n\tb%sx\t%s", h1?"l":"", tbl_regs[src]);
454     else
455         dbg_printf("\n\t%s\t%s, %s", tbl_hiops_t[op], tbl_regs[dst], tbl_regs[src]);
456
457     return 0;
458 }
459
460 static WORD thumb_disasm_aluop(WORD inst, ADDRESS64 *addr)
461 {
462     short dst = inst & 0x07;
463     short src = (inst >> 3) & 0x07;
464     short op  = (inst >> 6) & 0x0f;
465
466     dbg_printf("\n\t%s\t%s, %s", tbl_aluops_t[op], tbl_regs[dst], tbl_regs[src]);
467
468     return 0;
469 }
470
471 static WORD thumb_disasm_pushpop(WORD inst, ADDRESS64 *addr)
472 {
473     short lrpc = (inst >> 8)  & 0x01;
474     short load = (inst >> 11) & 0x01;
475     short i;
476     short last;
477
478     for (i=7;i>=0;i--)
479         if ((inst>>i) & 1) break;
480     last = i;
481
482     dbg_printf("\n\t%s\t{", load ? "pop" : "push");
483
484     for (i=0;i<=7;i++)
485         if ((inst>>i) & 1)
486         {
487             if (i == last) dbg_printf("%s", tbl_regs[i]);
488             else dbg_printf("%s, ", tbl_regs[i]);
489         }
490     if (lrpc)
491         dbg_printf("%s%s", last ? ", " : "", load ? "pc" : "lr");
492
493     dbg_printf("}");
494     return 0;
495 }
496
497 static WORD thumb_disasm_blocktrans(WORD inst, ADDRESS64 *addr)
498 {
499     short load = (inst >> 11) & 0x01;
500     short i;
501     short last;
502
503     for (i=7;i>=0;i--)
504         if ((inst>>i) & 1) break;
505     last = i;
506
507     dbg_printf("\n\t%s\t%s!, {", load ? "ldmia" : "stmia", tbl_regs[(inst >> 8) & 0x07]);
508
509     for (i=0;i<=7;i++)
510         if ((inst>>i) & 1)
511         {
512             if (i == last) dbg_printf("%s", tbl_regs[i]);
513             else dbg_printf("%s, ", tbl_regs[i]);
514         }
515
516     dbg_printf("}");
517     return 0;
518 }
519
520 static WORD thumb_disasm_swi(WORD inst, ADDRESS64 *addr)
521 {
522     dbg_printf("\n\tswi\t#%d", inst & 0x00ff);
523     return 0;
524 }
525
526 static WORD thumb_disasm_condbranch(WORD inst, ADDRESS64 *addr)
527 {
528     WORD offset = inst & 0x00ff;
529     dbg_printf("\n\tb%s\t", tbl_cond[(inst >> 8) & 0x0f]);
530     db_printsym(addr->Offset + offset);
531     return 0;
532 }
533
534 static WORD thumb_disasm_uncondbranch(WORD inst, ADDRESS64 *addr)
535 {
536     short offset = (inst & 0x07ff) << 1;
537
538     if (offset & 0x0800) offset |= 0xf000;
539     offset += 4;
540
541     dbg_printf("\n\tb\t");
542     db_printsym(addr->Offset + offset);
543     return 0;
544 }
545
546 static WORD thumb_disasm_loadadr(WORD inst, ADDRESS64 *addr)
547 {
548     WORD src = (inst >> 11) & 0x01;
549     WORD offset = (inst & 0xff) << 2;
550
551     dbg_printf("\n\tadd\t%s, %s, #%d", tbl_regs[(inst >> 8) & 0x07], src ? "sp" : "pc", offset);
552     return 0;
553 }
554
555 static WORD thumb_disasm_ldrpcrel(WORD inst, ADDRESS64 *addr)
556 {
557     WORD offset = (inst & 0xff) << 2;
558     dbg_printf("\n\tldr\t%s, [pc, #%u]", tbl_regs[(inst >> 8) & 0x07], offset);
559     return 0;
560 }
561
562 static WORD thumb_disasm_ldrsprel(WORD inst, ADDRESS64 *addr)
563 {
564     WORD offset = (inst & 0xff) << 2;
565     dbg_printf("\n\t%s\t%s, [sp, #%u]", (inst & 0x0800)?"ldr":"str", tbl_regs[(inst >> 8) & 0x07], offset);
566     return 0;
567 }
568
569 static WORD thumb_disasm_addsprel(WORD inst, ADDRESS64 *addr)
570 {
571     WORD offset = (inst & 0x7f) << 2;
572     if ((inst >> 7) & 0x01)
573         dbg_printf("\n\tsub\tsp, sp, #%u", offset);
574     else
575         dbg_printf("\n\tadd\tsp, sp, #%u", offset);
576     return 0;
577 }
578
579 static WORD thumb_disasm_ldrimm(WORD inst, ADDRESS64 *addr)
580 {
581     WORD offset = (inst & 0x07c0) >> 6;
582     dbg_printf("\n\t%s%s\t%s, [%s, #%u]", (inst & 0x0800)?"ldr":"str", (inst & 0x1000)?"b":"",
583                tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07], (inst & 0x1000)?offset:(offset << 2));
584     return 0;
585 }
586
587 static WORD thumb_disasm_ldrhimm(WORD inst, ADDRESS64 *addr)
588 {
589     WORD offset = (inst & 0x07c0) >> 5;
590     dbg_printf("\n\t%s\t%s, [%s, #%u]", (inst & 0x0800)?"ldrh":"strh",
591                tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07], offset);
592     return 0;
593 }
594
595 static WORD thumb_disasm_ldrreg(WORD inst, ADDRESS64 *addr)
596 {
597     dbg_printf("\n\t%s%s\t%s, [%s, %s]", (inst & 0x0800)?"ldr":"str", (inst & 0x0400)?"b":"",
598                tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07], tbl_regs[(inst >> 6) & 0x07]);
599     return 0;
600 }
601
602 static WORD thumb_disasm_ldrsreg(WORD inst, ADDRESS64 *addr)
603 {
604     dbg_printf("\n\t%s\t%s, [%s, %s]", tbl_sregops_t[(inst >> 10) & 0x03],
605                tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07], tbl_regs[(inst >> 6) & 0x07]);
606     return 0;
607 }
608
609 static WORD thumb_disasm_immop(WORD inst, ADDRESS64 *addr)
610 {
611     WORD op = (inst >> 11) & 0x03;
612     dbg_printf("\n\t%s\t%s, #%u", tbl_immops_t[op], tbl_regs[(inst >> 8) & 0x07], inst & 0xff);
613     return 0;
614 }
615
616 static WORD thumb_disasm_nop(WORD inst, ADDRESS64 *addr)
617 {
618     dbg_printf("\n\tnop");
619     return 0;
620 }
621
622 static WORD thumb_disasm_addsub(WORD inst, ADDRESS64 *addr)
623 {
624     WORD op = (inst >> 9) & 0x01;
625     WORD immediate = (inst >> 10) & 0x01;
626
627     dbg_printf("\n\t%s\t%s, %s, ", op ? "sub" : "add",
628                tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07]);
629     if (immediate)
630         dbg_printf("#%d", (inst >> 6) & 0x07);
631     else
632         dbg_printf("%s", tbl_regs[(inst >> 6) & 0x07]);
633     return 0;
634 }
635
636 static WORD thumb_disasm_movshift(WORD inst, ADDRESS64 *addr)
637 {
638     WORD op = (inst >> 11) & 0x03;
639     dbg_printf("\n\t%s\t%s, %s, #%u", tbl_shifts[op],
640                tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07], (inst >> 6) & 0x1f);
641     return 0;
642 }
643
644 static UINT thumb2_disasm_srtrans(UINT inst, ADDRESS64 *addr)
645 {
646     UINT fromsr = (inst >> 21) & 0x03;
647     UINT sysreg = inst & 0xff;
648
649     if (fromsr == 3 && get_nibble(inst,4) == 0x0f && sysreg <= 20)
650     {
651         dbg_printf("\n\tmrs\t%s, %s", tbl_regs[get_nibble(inst, 2)], tbl_special_regs_t2[sysreg]);
652         return 0;
653     }
654
655     if (fromsr == 0 && sysreg <= 20)
656     {
657         dbg_printf("\n\tmsr\t%s, %s", tbl_special_regs_t2[sysreg], tbl_regs[get_nibble(inst, 4)]);
658         return 0;
659     }
660
661     return inst;
662 }
663
664 static UINT thumb2_disasm_hint(UINT inst, ADDRESS64 *addr)
665 {
666     WORD op1 = (inst >> 8) & 0x07;
667     WORD op2 = inst & 0xff;
668
669     if (op1) return inst;
670
671     if (op2 <= 4)
672     {
673         dbg_printf("\n\t%s", tbl_hints_t2[op2]);
674         return 0;
675     }
676
677     if (op2 & 0xf0)
678     {
679         dbg_printf("\n\tdbg\t#%u", get_nibble(inst, 0));
680         return 0;
681     }
682
683     return inst;
684 }
685
686 static UINT thumb2_disasm_miscctrl(UINT inst, ADDRESS64 *addr)
687 {
688     WORD op = (inst >> 4) & 0x0f;
689
690     switch (op)
691     {
692     case 2:
693         dbg_printf("\n\tclrex");
694         break;
695     case 4:
696         dbg_printf("\n\tdsb\t#%u", get_nibble(inst, 0));
697         break;
698     case 5:
699         dbg_printf("\n\tdmb\t#%u", get_nibble(inst, 0));
700         break;
701     case 6:
702         dbg_printf("\n\tisb\t#%u", get_nibble(inst, 0));
703         break;
704     default:
705         return inst;
706     }
707
708     return 0;
709 }
710
711 static UINT thumb2_disasm_branch(UINT inst, ADDRESS64 *addr)
712 {
713     UINT S  = (inst >> 26) & 0x01;
714     UINT L  = (inst >> 14) & 0x01;
715     UINT I1 = !(((inst >> 13) & 0x01) ^ S);
716     UINT C  = !((inst >> 12) & 0x01);
717     UINT I2 = !(((inst >> 11) & 0x01) ^ S);
718     UINT offset = (inst & 0x000007ff) << 1;
719
720     if (C)
721     {
722         offset |= I1 << 19 | I2 << 18 | (inst & 0x003f0000) >> 4;
723         if (S) offset |= 0x0fff << 20;
724     }
725     else
726     {
727         offset |= I1 << 23 | I2 << 22 | (inst & 0x03ff0000) >> 4;
728         if (S) offset |= 0xff << 24;
729     }
730
731     dbg_printf("\n\tb%s%s\t", L ? "l" : "", C ? tbl_cond[(inst >> 22) & 0x0f] : "");
732     db_printsym(addr->Offset + offset + 4);
733     return 0;
734 }
735
736 static UINT thumb2_disasm_misc(UINT inst, ADDRESS64 *addr)
737 {
738     WORD op1 = (inst >> 20) & 0x03;
739     WORD op2 = (inst >> 4) & 0x03;
740
741     if (get_nibble(inst, 4) != get_nibble(inst, 0))
742         return inst;
743
744     if (op1 == 3 && op2 == 0)
745     {
746         dbg_printf("\n\tclz\t%s, %s", tbl_regs[get_nibble(inst, 2)], tbl_regs[get_nibble(inst, 0)]);
747         return 0;
748     }
749
750     if (op1 == 1)
751     {
752         dbg_printf("\n\t%s\t%s, %s", tbl_miscops_t2[op2], tbl_regs[get_nibble(inst, 2)],
753                    tbl_regs[get_nibble(inst, 0)]);
754         return 0;
755     }
756
757     return inst;
758 }
759
760 static UINT thumb2_disasm_dataprocessingreg(UINT inst, ADDRESS64 *addr)
761 {
762     WORD op1 = (inst >> 20) & 0x07;
763     WORD op2 = (inst >> 4) & 0x0f;
764
765     if (!op2)
766     {
767         dbg_printf("\n\t%s%s\t%s, %s, %s", tbl_shifts[op1 >> 1], (op1 & 1)?"s":"",
768                    tbl_regs[get_nibble(inst, 2)], tbl_regs[get_nibble(inst, 4)],
769                    tbl_regs[get_nibble(inst, 0)]);
770         return 0;
771     }
772
773     if ((op2 & 0x0C) == 0x08 && get_nibble(inst, 4) == 0x0f)
774     {
775         dbg_printf("\n\t%sxt%s\t%s, %s", (op1 & 1)?"u":"s", (op1 & 4)?"b":"h",
776                    tbl_regs[get_nibble(inst, 2)], tbl_regs[get_nibble(inst, 0)]);
777         if (op2 & 0x03)
778             dbg_printf(", ROR #%u", (op2 & 3) * 8);
779         return 0;
780     }
781
782     return inst;
783 }
784
785 static UINT thumb2_disasm_mul(UINT inst, ADDRESS64 *addr)
786 {
787     WORD op1 = (inst >> 20) & 0x07;
788     WORD op2 = (inst >> 4) & 0x03;
789
790     if (op1)
791         return inst;
792
793     if (op2 == 0 && get_nibble(inst, 3) != 0xf)
794     {
795         dbg_printf("\n\tmla\t%s, %s, %s, %s", tbl_regs[get_nibble(inst, 2)],
796                                                 tbl_regs[get_nibble(inst, 4)],
797                                                 tbl_regs[get_nibble(inst, 0)],
798                                                 tbl_regs[get_nibble(inst, 3)]);
799         return 0;
800     }
801
802     if (op2 == 0 && get_nibble(inst, 3) == 0xf)
803     {
804         dbg_printf("\n\tmul\t%s, %s, %s", tbl_regs[get_nibble(inst, 2)],
805                                             tbl_regs[get_nibble(inst, 4)],
806                                             tbl_regs[get_nibble(inst, 0)]);
807         return 0;
808     }
809
810     if (op2 == 1)
811     {
812         dbg_printf("\n\tmls\t%s, %s, %s, %s", tbl_regs[get_nibble(inst, 2)],
813                                                 tbl_regs[get_nibble(inst, 4)],
814                                                 tbl_regs[get_nibble(inst, 0)],
815                                                 tbl_regs[get_nibble(inst, 3)]);
816         return 0;
817     }
818
819     return inst;
820 }
821
822 static UINT thumb2_disasm_longmuldiv(UINT inst, ADDRESS64 *addr)
823 {
824     WORD op1 = (inst >> 20) & 0x07;
825     WORD op2 = (inst >> 4) & 0x0f;
826
827     if (op2 == 0)
828     {
829         switch (op1)
830         {
831         case 0:
832             dbg_printf("\n\tsmull\t");
833             break;
834         case 2:
835             dbg_printf("\n\tumull\t");
836             break;
837         case 4:
838             dbg_printf("\n\tsmlal\t");
839             break;
840         case 6:
841             dbg_printf("\n\tumlal\t");
842             break;
843         default:
844             return inst;
845         }
846         dbg_printf("%s, %s, %s, %s", tbl_regs[get_nibble(inst, 3)], tbl_regs[get_nibble(inst, 2)],
847                                        tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
848         return 0;
849     }
850
851     if (op2 == 0xffff)
852     {
853         switch (op1)
854         {
855         case 1:
856             dbg_printf("\n\tsdiv\t");
857             break;
858         case 3:
859             dbg_printf("\n\tudiv\t");
860             break;
861         default:
862             return inst;
863         }
864         dbg_printf("%s, %s, %s", tbl_regs[get_nibble(inst, 2)], tbl_regs[get_nibble(inst, 4)],
865                                    tbl_regs[get_nibble(inst, 0)]);
866         return 0;
867     }
868
869     return inst;
870 }
871
872 static UINT thumb2_disasm_str(UINT inst, ADDRESS64 *addr)
873 {
874     WORD op1 = (inst >> 21) & 0x07;
875     WORD op2 = (inst >> 6) & 0x3f;
876
877     if ((op1 & 0x03) == 3) return inst;
878
879     if (!(op1 & 0x04) && inst & 0x0800)
880     {
881         int offset;
882         dbg_printf("\n\tstr%s\t%s, [%s", tbl_width_t2[op1 & 0x03], tbl_regs[get_nibble(inst, 3)],
883                    tbl_regs[get_nibble(inst, 4)]);
884
885         offset = inst & 0xff;
886         if (!(inst & 0x0200)) offset *= -1;
887
888         if (!(inst & 0x0400) && (inst & 0x0100)) dbg_printf("], #%i", offset);
889         else if (inst & 0x0400) dbg_printf(", #%i]%s", offset, (inst & 0x0100)?"!":"");
890         else return inst;
891         return 0;
892     }
893
894     if (!(op1 & 0x04) && !op2)
895     {
896         dbg_printf("\n\tstr%s\t%s, [%s, %s, LSL #%u]", tbl_width_t2[op1 & 0x03],
897                    tbl_regs[get_nibble(inst, 3)], tbl_regs[get_nibble(inst, 4)],
898                    tbl_regs[get_nibble(inst, 0)], (inst >> 4) & 0x3);
899         return 0;
900     }
901
902     if (op1 & 0x04)
903     {
904         dbg_printf("\n\tstr%s\t%s, [%s, #%u]", tbl_width_t2[op1 & 0x03],
905                    tbl_regs[get_nibble(inst, 3)], tbl_regs[get_nibble(inst, 4)], inst & 0x0fff);
906         return 0;
907     }
908
909     return inst;
910 }
911
912 static UINT thumb2_disasm_ldrword(UINT inst, ADDRESS64 *addr)
913 {
914     WORD op1 = (inst >> 23) & 0x01;
915     WORD op2 = (inst >> 6) & 0x3f;
916     int offset;
917
918     if (get_nibble(inst, 4) == 0x0f)
919     {
920         offset = inst & 0x0fff;
921
922         if (!op1) offset *= -1;
923         offset += 3;
924
925         dbg_printf("\n\tldr\t%s, ", tbl_regs[get_nibble(inst, 3)]);
926         db_printsym(addr->Offset + offset);
927         return 0;
928     }
929
930     if (!op1 && !op2)
931     {
932         dbg_printf("\n\tldr\t%s, [%s, %s, LSL #%u]", tbl_regs[get_nibble(inst, 3)],
933                    tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)], (inst >> 4) & 0x3);
934         return 0;
935     }
936
937     if (!op1 && (op2 & 0x3c) == 0x38)
938     {
939         dbg_printf("\n\tldrt\t%s, [%s, #%u]", tbl_regs[get_nibble(inst, 3)],
940                    tbl_regs[get_nibble(inst, 4)], inst & 0xff);
941         return 0;
942     }
943
944     dbg_printf("\n\tldr\t%s, [%s", tbl_regs[get_nibble(inst, 3)], tbl_regs[get_nibble(inst, 4)]);
945
946     if (op1)
947     {
948         dbg_printf(", #%u]", inst & 0x0fff);
949         return 0;
950     }
951
952     offset = inst & 0xff;
953     if (!(inst & 0x0200)) offset *= -1;
954
955     if (!(inst & 0x0400) && (inst & 0x0100)) dbg_printf("], #%i", offset);
956     else if (inst & 0x0400) dbg_printf(", #%i]%s", offset, (inst & 0x0100)?"!":"");
957     else return inst;
958
959     return 0;
960 }
961
962 static UINT thumb2_disasm_coprocdat(UINT inst, ADDRESS64 *addr)
963 {
964     WORD opc2 = (inst >> 5) & 0x07;
965
966     if (opc2)
967         dbg_printf("\n\tcdp%s\tp%u, #%u, cr%u, cr%u, cr%u, #%u", (inst & 0x10000000)?"2":"",
968                    get_nibble(inst, 2), get_nibble(inst, 5), get_nibble(inst, 3),
969                    get_nibble(inst, 4), get_nibble(inst, 0), opc2);
970     else
971         dbg_printf("\n\tcdp%s\tp%u, #%u, cr%u, cr%u, cr%u", (inst & 0x10000000)?"2":"",
972                    get_nibble(inst, 2), get_nibble(inst, 5), get_nibble(inst, 3),
973                    get_nibble(inst, 4), get_nibble(inst, 0));
974
975     return 0;
976 }
977
978 static UINT thumb2_disasm_coprocmov1(UINT inst, ADDRESS64 *addr)
979 {
980     WORD opc1 = (inst >> 21) & 0x07;
981     WORD opc2 = (inst >> 5) & 0x07;
982
983     if (opc2)
984         dbg_printf("\n\t%s%s\tp%u, #%u, %s, cr%u, cr%u, #%u", (inst & 0x00100000)?"mrc":"mcr",
985                    (inst & 0x10000000)?"2":"", get_nibble(inst, 2), opc1,
986                    tbl_regs[get_nibble(inst, 3)], get_nibble(inst, 4), get_nibble(inst, 0), opc2);
987     else
988         dbg_printf("\n\t%s%s\tp%u, #%u, %s, cr%u, cr%u", (inst & 0x00100000)?"mrc":"mcr",
989                    (inst & 0x10000000)?"2":"", get_nibble(inst, 2), opc1,
990                    tbl_regs[get_nibble(inst, 3)], get_nibble(inst, 4), get_nibble(inst, 0));
991
992     return 0;
993 }
994
995 static UINT thumb2_disasm_coprocmov2(UINT inst, ADDRESS64 *addr)
996 {
997     dbg_printf("\n\t%s%s\tp%u, #%u, %s, %s, cr%u", (inst & 0x00100000)?"mrrc":"mcrr",
998                (inst & 0x10000000)?"2":"", get_nibble(inst, 2), get_nibble(inst, 1),
999                tbl_regs[get_nibble(inst, 3)], tbl_regs[get_nibble(inst, 4)], get_nibble(inst, 0));
1000
1001     return 0;
1002 }
1003
1004 static UINT thumb2_disasm_coprocdatatrans(UINT inst, ADDRESS64 *addr)
1005 {
1006     WORD indexing  = (inst >> 24) & 0x01;
1007     WORD direction = (inst >> 23) & 0x01;
1008     WORD translen  = (inst >> 22) & 0x01;
1009     WORD writeback = (inst >> 21) & 0x01;
1010     WORD load      = (inst >> 20) & 0x01;
1011     short offset    = (inst & 0xff) << 2;
1012
1013     if (!direction) offset *= -1;
1014
1015     dbg_printf("\n\t%s%s%s", load ? "ldc" : "stc", (inst & 0x10000000)?"2":"", translen ? "l" : "");
1016     if (indexing)
1017     {
1018         if (load && get_nibble(inst, 4) == 15)
1019         {
1020             dbg_printf("\tp%u, cr%u, ", get_nibble(inst, 2), get_nibble(inst, 3));
1021             db_printsym(addr->Offset + offset + 4);
1022         }
1023         else
1024             dbg_printf("\tp%u, cr%u, [%s, #%d]%s", get_nibble(inst, 2), get_nibble(inst, 3), tbl_regs[get_nibble(inst, 4)], offset, writeback?"!":"");
1025     }
1026     else
1027     {
1028         if (writeback)
1029             dbg_printf("\tp%u, cr%u, [%s], #%d", get_nibble(inst, 2), get_nibble(inst, 3), tbl_regs[get_nibble(inst, 4)], offset);
1030         else
1031             dbg_printf("\tp%u, cr%u, [%s], {%u}", get_nibble(inst, 2), get_nibble(inst, 3), tbl_regs[get_nibble(inst, 4)], inst & 0xff);
1032     }
1033     return 0;
1034 }
1035
1036 struct inst_arm
1037 {
1038         UINT mask;
1039         UINT pattern;
1040         UINT (*func)(UINT, ADDRESS64*);
1041 };
1042
1043 static const struct inst_arm tbl_arm[] = {
1044     { 0x0e000000, 0x0a000000, arm_disasm_branch },
1045     { 0x0fc000f0, 0x00000090, arm_disasm_mul },
1046     { 0x0f8000f0, 0x00800090, arm_disasm_longmul },
1047     { 0x0fb00ff0, 0x01000090, arm_disasm_swp },
1048     { 0x0e000090, 0x00000090, arm_disasm_halfwordtrans },
1049     { 0x0ffffff0, 0x012fff00, arm_disasm_branchreg },
1050     { 0x0ffffff0, 0x012fff10, arm_disasm_branchxchg },
1051     { 0x0fbf0fff, 0x010f0000, arm_disasm_mrstrans },
1052     { 0x0dbef000, 0x0128f000, arm_disasm_msrtrans },
1053     { 0x0fb00000, 0x03000000, arm_disasm_wordmov },
1054     { 0x0fffffff, 0x0320f000, arm_disasm_nop },
1055     { 0x0c000000, 0x00000000, arm_disasm_dataprocessing },
1056     { 0x0c000000, 0x04000000, arm_disasm_singletrans },
1057     { 0x0e000000, 0x08000000, arm_disasm_blocktrans },
1058     { 0x0f000000, 0x0f000000, arm_disasm_swi },
1059     { 0x0f000010, 0x0e000010, arm_disasm_coproctrans },
1060     { 0x0f000010, 0x0e000000, arm_disasm_coprocdataop },
1061     { 0x0e000000, 0x0c000000, arm_disasm_coprocdatatrans },
1062     { 0x00000000, 0x00000000, NULL }
1063 };
1064
1065 struct inst_thumb16
1066 {
1067         WORD mask;
1068         WORD pattern;
1069         WORD (*func)(WORD, ADDRESS64*);
1070 };
1071
1072 static const struct inst_thumb16 tbl_thumb16[] = {
1073     { 0xfc00, 0x4400, thumb_disasm_hireg },
1074     { 0xfc00, 0x4000, thumb_disasm_aluop },
1075     { 0xf600, 0xb400, thumb_disasm_pushpop },
1076     { 0xf000, 0xc000, thumb_disasm_blocktrans },
1077     { 0xff00, 0xdf00, thumb_disasm_swi },
1078     { 0xf000, 0xd000, thumb_disasm_condbranch },
1079     { 0xf800, 0xe000, thumb_disasm_uncondbranch },
1080     { 0xf000, 0xa000, thumb_disasm_loadadr },
1081     { 0xf800, 0x4800, thumb_disasm_ldrpcrel },
1082     { 0xf000, 0x9000, thumb_disasm_ldrsprel },
1083     { 0xff00, 0xb000, thumb_disasm_addsprel },
1084     { 0xe000, 0x6000, thumb_disasm_ldrimm },
1085     { 0xf000, 0x8000, thumb_disasm_ldrhimm },
1086     { 0xf200, 0x5000, thumb_disasm_ldrreg },
1087     { 0xf200, 0x5200, thumb_disasm_ldrsreg },
1088     { 0xe000, 0x2000, thumb_disasm_immop },
1089     { 0xff00, 0xbf00, thumb_disasm_nop },
1090     { 0xf800, 0x1800, thumb_disasm_addsub },
1091     { 0xe000, 0x0000, thumb_disasm_movshift },
1092     { 0x0000, 0x0000, NULL }
1093 };
1094
1095 static const struct inst_arm tbl_thumb32[] = {
1096     { 0xfff0f000, 0xf3e08000, thumb2_disasm_srtrans },
1097     { 0xfff0f000, 0xf3808000, thumb2_disasm_srtrans },
1098     { 0xfff0d000, 0xf3a08000, thumb2_disasm_hint },
1099     { 0xfff0d000, 0xf3b08000, thumb2_disasm_miscctrl },
1100     { 0xf8008000, 0xf0008000, thumb2_disasm_branch },
1101     { 0xffc0f0c0, 0xfa80f080, thumb2_disasm_misc },
1102     { 0xff80f000, 0xfa00f000, thumb2_disasm_dataprocessingreg },
1103     { 0xff8000c0, 0xfb000000, thumb2_disasm_mul },
1104     { 0xff8000f0, 0xfb800000, thumb2_disasm_longmuldiv },
1105     { 0xff8000f0, 0xfb8000f0, thumb2_disasm_longmuldiv },
1106     { 0xff100000, 0xf8000000, thumb2_disasm_str },
1107     { 0xff700000, 0xf8500000, thumb2_disasm_ldrword },
1108     { 0xef000010, 0xee000000, thumb2_disasm_coprocdat },
1109     { 0xef000010, 0xee000010, thumb2_disasm_coprocmov1 },
1110     { 0xefe00000, 0xec400000, thumb2_disasm_coprocmov2 },
1111     { 0xee000000, 0xec000000, thumb2_disasm_coprocdatatrans },
1112     { 0x00000000, 0x00000000, NULL }
1113 };
1114
1115 /***********************************************************************
1116  *              disasm_one_insn
1117  *
1118  * Disassemble instruction at 'addr'. addr is changed to point to the
1119  * start of the next instruction.
1120  */
1121 void be_arm_disasm_one_insn(ADDRESS64 *addr, int display)
1122 {
1123     struct inst_arm *a_ptr = (struct inst_arm *)&tbl_arm;
1124     struct inst_thumb16 *t_ptr = (struct inst_thumb16 *)&tbl_thumb16;
1125     struct inst_arm *t2_ptr = (struct inst_arm *)&tbl_thumb32;
1126     UINT inst;
1127     WORD tinst;
1128     int size;
1129     int matched = 0;
1130
1131     char tmp[64];
1132     DWORD_PTR* pval;
1133
1134     if (!memory_get_register(CV_ARM_CPSR, &pval, tmp, sizeof(tmp)))
1135         dbg_printf("\n\tmemory_get_register failed: %s", tmp);
1136     else
1137         db_disasm_thumb = (*pval & 0x20) != 0;
1138
1139     db_display = display;
1140
1141     if (!db_disasm_thumb)
1142     {
1143         size = ARM_INSN_SIZE;
1144         inst = db_get_inst( memory_to_linear_addr(addr), size );
1145         while (a_ptr->func) {
1146             if ((inst & a_ptr->mask) == a_ptr->pattern) {
1147                     matched = 1;
1148                     break;
1149             }
1150             a_ptr++;
1151         }
1152
1153         if (!matched) {
1154             dbg_printf("\n\tUnknown ARM Instruction: %08x", inst);
1155             addr->Offset += size;
1156         }
1157         else
1158         {
1159             if (!a_ptr->func(inst, addr))
1160                 addr->Offset += size;
1161         }
1162         return;
1163     }
1164     else
1165     {
1166         WORD *taddr = memory_to_linear_addr(addr);
1167         tinst = db_get_inst( taddr, THUMB_INSN_SIZE );
1168         switch (tinst & 0xf800)
1169         {
1170             case 0xe800:
1171             case 0xf000:
1172             case 0xf800:
1173                 size = THUMB2_INSN_SIZE;
1174                 taddr++;
1175                 inst = db_get_inst( taddr, THUMB_INSN_SIZE );
1176                 inst |= (tinst << 16);
1177
1178                 while (t2_ptr->func) {
1179                     if ((inst & t2_ptr->mask) == t2_ptr->pattern) {
1180                             matched = 1;
1181                             break;
1182                     }
1183                     t2_ptr++;
1184                 }
1185
1186                 if (!matched) {
1187                     dbg_printf("\n\tUnknown Thumb2 Instruction: %08x", inst);
1188                     addr->Offset += size;
1189                 }
1190                 else
1191                 {
1192                     if (!t2_ptr->func(inst, addr))
1193                         addr->Offset += size;
1194                 }
1195                 return;
1196             default:
1197                 break;
1198         }
1199
1200         size = THUMB_INSN_SIZE;
1201         while (t_ptr->func) {
1202             if ((tinst & t_ptr->mask) == t_ptr->pattern) {
1203                     matched = 1;
1204                     break;
1205             }
1206             t_ptr++;
1207         }
1208
1209         if (!matched) {
1210             dbg_printf("\n\tUnknown Thumb Instruction: %04x", tinst);
1211             addr->Offset += size;
1212         }
1213         else
1214         {
1215             if (!t_ptr->func(tinst, addr))
1216                 addr->Offset += size;
1217         }
1218         return;
1219     }
1220 }
1221
1222 static unsigned be_arm_get_addr(HANDLE hThread, const CONTEXT* ctx,
1223                                 enum be_cpu_addr bca, ADDRESS64* addr)
1224 {
1225     switch (bca)
1226     {
1227     case be_cpu_addr_pc:
1228         return be_cpu_build_addr(hThread, ctx, addr, 0, ctx->Pc);
1229     case be_cpu_addr_stack:
1230         return be_cpu_build_addr(hThread, ctx, addr, 0, ctx->Sp);
1231     case be_cpu_addr_frame:
1232         return be_cpu_build_addr(hThread, ctx, addr, 0, ctx->Fp);
1233     }
1234     return FALSE;
1235 }
1236
1237 static unsigned be_arm_get_register_info(int regno, enum be_cpu_addr* kind)
1238 {
1239     switch (regno)
1240     {
1241     case CV_ARM_PC:  *kind = be_cpu_addr_pc; return TRUE;
1242     case CV_ARM_R0 + 11: *kind = be_cpu_addr_frame; return TRUE;
1243     case CV_ARM_SP:  *kind = be_cpu_addr_stack; return TRUE;
1244     }
1245     return FALSE;
1246 }
1247
1248 static void be_arm_single_step(CONTEXT* ctx, unsigned enable)
1249 {
1250     dbg_printf("be_arm_single_step: not done\n");
1251 }
1252
1253 static void be_arm_print_context(HANDLE hThread, const CONTEXT* ctx, int all_regs)
1254 {
1255     static const char condflags[] = "NZCV";
1256     int i;
1257     char        buf[8];
1258
1259     switch (ctx->Cpsr & 0x1F)
1260     {
1261     case 0:  strcpy(buf, "User26"); break;
1262     case 1:  strcpy(buf, "FIQ26"); break;
1263     case 2:  strcpy(buf, "IRQ26"); break;
1264     case 3:  strcpy(buf, "SVC26"); break;
1265     case 16: strcpy(buf, "User"); break;
1266     case 17: strcpy(buf, "FIQ"); break;
1267     case 18: strcpy(buf, "IRQ"); break;
1268     case 19: strcpy(buf, "SVC"); break;
1269     case 23: strcpy(buf, "ABT"); break;
1270     case 27: strcpy(buf, "UND"); break;
1271     default: strcpy(buf, "UNKNWN"); break;
1272     }
1273
1274     dbg_printf("Register dump:\n");
1275     dbg_printf("%s %s Mode\n", (ctx->Cpsr & 0x20) ? "Thumb" : "ARM", buf);
1276
1277     strcpy(buf, condflags);
1278     for (i = 0; buf[i]; i++)
1279         if (!((ctx->Cpsr >> 26) & (1 << (sizeof(condflags) - i))))
1280             buf[i] = '-';
1281
1282     dbg_printf(" Pc:%04x Sp:%04x Lr:%04x Cpsr:%04x(%s)\n",
1283                ctx->Pc, ctx->Sp, ctx->Lr, ctx->Cpsr, buf);
1284     dbg_printf(" r0:%04x r1:%04x r2:%04x r3:%04x\n",
1285                ctx->R0, ctx->R1, ctx->R2, ctx->R3);
1286     dbg_printf(" r4:%04x r5:%04x  r6:%04x  r7:%04x r8:%04x\n",
1287                ctx->R4, ctx->R5, ctx->R6, ctx->R7, ctx->R8 );
1288     dbg_printf(" r9:%04x r10:%04x Fp:%04x Ip:%04x\n",
1289                ctx->R9, ctx->R10, ctx->Fp, ctx->Ip );
1290
1291     if (all_regs) dbg_printf( "Floating point ARM dump not implemented\n" );
1292 }
1293
1294 static void be_arm_print_segment_info(HANDLE hThread, const CONTEXT* ctx)
1295 {
1296 }
1297
1298 static struct dbg_internal_var be_arm_ctx[] =
1299 {
1300     {CV_ARM_R0 +  0,    "r0",           (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R0),     dbg_itype_unsigned_int},
1301     {CV_ARM_R0 +  1,    "r1",           (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R1),     dbg_itype_unsigned_int},
1302     {CV_ARM_R0 +  2,    "r2",           (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R2),     dbg_itype_unsigned_int},
1303     {CV_ARM_R0 +  3,    "r3",           (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R3),     dbg_itype_unsigned_int},
1304     {CV_ARM_R0 +  4,    "r4",           (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R4),     dbg_itype_unsigned_int},
1305     {CV_ARM_R0 +  5,    "r5",           (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R5),     dbg_itype_unsigned_int},
1306     {CV_ARM_R0 +  6,    "r6",           (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R6),     dbg_itype_unsigned_int},
1307     {CV_ARM_R0 +  7,    "r7",           (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R7),     dbg_itype_unsigned_int},
1308     {CV_ARM_R0 +  8,    "r8",           (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R8),     dbg_itype_unsigned_int},
1309     {CV_ARM_R0 +  9,    "r9",           (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R9),     dbg_itype_unsigned_int},
1310     {CV_ARM_R0 +  10,   "r10",          (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R10),    dbg_itype_unsigned_int},
1311     {CV_ARM_R0 +  11,   "r11",          (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Fp),     dbg_itype_unsigned_int},
1312     {CV_ARM_R0 +  12,   "r12",          (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Ip),     dbg_itype_unsigned_int},
1313     {CV_ARM_SP,         "sp",           (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Sp),     dbg_itype_unsigned_int},
1314     {CV_ARM_LR,         "lr",           (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Lr),     dbg_itype_unsigned_int},
1315     {CV_ARM_PC,         "pc",           (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Pc),     dbg_itype_unsigned_int},
1316     {CV_ARM_CPSR,       "cpsr",         (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Cpsr),   dbg_itype_unsigned_int},
1317     {0,                 NULL,           0,                                         dbg_itype_none}
1318 };
1319
1320 static unsigned be_arm_is_step_over_insn(const void* insn)
1321 {
1322     dbg_printf("be_arm_is_step_over_insn: not done\n");
1323     return FALSE;
1324 }
1325
1326 static unsigned be_arm_is_function_return(const void* insn)
1327 {
1328     dbg_printf("be_arm_is_function_return: not done\n");
1329     return FALSE;
1330 }
1331
1332 static unsigned be_arm_is_break_insn(const void* insn)
1333 {
1334     dbg_printf("be_arm_is_break_insn: not done\n");
1335     return FALSE;
1336 }
1337
1338 static unsigned be_arm_is_func_call(const void* insn, ADDRESS64* callee)
1339 {
1340     return FALSE;
1341 }
1342
1343 static unsigned be_arm_is_jump(const void* insn, ADDRESS64* jumpee)
1344 {
1345     return FALSE;
1346 }
1347
1348 static unsigned be_arm_insert_Xpoint(HANDLE hProcess, const struct be_process_io* pio,
1349                                      CONTEXT* ctx, enum be_xpoint_type type,
1350                                      void* addr, unsigned long* val, unsigned size)
1351 {
1352     SIZE_T              sz;
1353
1354     switch (type)
1355     {
1356     case be_xpoint_break:
1357         if (!size) return 0;
1358         if (!pio->read(hProcess, addr, val, 4, &sz) || sz != 4) return 0;
1359     default:
1360         dbg_printf("Unknown/unsupported bp type %c\n", type);
1361         return 0;
1362     }
1363     return 1;
1364 }
1365
1366 static unsigned be_arm_remove_Xpoint(HANDLE hProcess, const struct be_process_io* pio,
1367                                      CONTEXT* ctx, enum be_xpoint_type type,
1368                                      void* addr, unsigned long val, unsigned size)
1369 {
1370     SIZE_T              sz;
1371
1372     switch (type)
1373     {
1374     case be_xpoint_break:
1375         if (!size) return 0;
1376         if (!pio->write(hProcess, addr, &val, 4, &sz) || sz == 4) return 0;
1377         break;
1378     default:
1379         dbg_printf("Unknown/unsupported bp type %c\n", type);
1380         return 0;
1381     }
1382     return 1;
1383 }
1384
1385 static unsigned be_arm_is_watchpoint_set(const CONTEXT* ctx, unsigned idx)
1386 {
1387     dbg_printf("be_arm_is_watchpoint_set: not done\n");
1388     return FALSE;
1389 }
1390
1391 static void be_arm_clear_watchpoint(CONTEXT* ctx, unsigned idx)
1392 {
1393     dbg_printf("be_arm_clear_watchpoint: not done\n");
1394 }
1395
1396 static int be_arm_adjust_pc_for_break(CONTEXT* ctx, BOOL way)
1397 {
1398     INT step = (ctx->Cpsr & 0x20) ? 2 : 4;
1399
1400     if (way)
1401     {
1402         ctx->Pc -= step;
1403         return -step;
1404     }
1405     ctx->Pc += step;
1406     return step;
1407 }
1408
1409 static int be_arm_fetch_integer(const struct dbg_lvalue* lvalue, unsigned size,
1410                                 unsigned ext_sign, LONGLONG* ret)
1411 {
1412     if (size != 1 && size != 2 && size != 4 && size != 8) return FALSE;
1413
1414     memset(ret, 0, sizeof(*ret)); /* clear unread bytes */
1415     /* FIXME: this assumes that debuggee and debugger use the same
1416      * integral representation
1417      */
1418     if (!memory_read_value(lvalue, size, ret)) return FALSE;
1419
1420     /* propagate sign information */
1421     if (ext_sign && size < 8 && (*ret >> (size * 8 - 1)) != 0)
1422     {
1423         ULONGLONG neg = -1;
1424         *ret |= neg << (size * 8);
1425     }
1426     return TRUE;
1427 }
1428
1429 static int be_arm_fetch_float(const struct dbg_lvalue* lvalue, unsigned size,
1430                               long double* ret)
1431 {
1432     char        tmp[sizeof(long double)];
1433
1434     /* FIXME: this assumes that debuggee and debugger use the same
1435      * representation for reals
1436      */
1437     if (!memory_read_value(lvalue, size, tmp)) return FALSE;
1438
1439     switch (size)
1440     {
1441     case sizeof(float):         *ret = *(float*)tmp;            break;
1442     case sizeof(double):        *ret = *(double*)tmp;           break;
1443     default:                    return FALSE;
1444     }
1445     return TRUE;
1446 }
1447
1448 static int be_arm_store_integer(const struct dbg_lvalue* lvalue, unsigned size,
1449                                 unsigned is_signed, LONGLONG val)
1450 {
1451     /* this is simple if we're on a little endian CPU */
1452     return memory_write_value(lvalue, size, &val);
1453 }
1454
1455 struct backend_cpu be_arm =
1456 {
1457     IMAGE_FILE_MACHINE_ARMNT,
1458     4,
1459     be_cpu_linearize,
1460     be_cpu_build_addr,
1461     be_arm_get_addr,
1462     be_arm_get_register_info,
1463     be_arm_single_step,
1464     be_arm_print_context,
1465     be_arm_print_segment_info,
1466     be_arm_ctx,
1467     be_arm_is_step_over_insn,
1468     be_arm_is_function_return,
1469     be_arm_is_break_insn,
1470     be_arm_is_func_call,
1471     be_arm_is_jump,
1472     be_arm_disasm_one_insn,
1473     be_arm_insert_Xpoint,
1474     be_arm_remove_Xpoint,
1475     be_arm_is_watchpoint_set,
1476     be_arm_clear_watchpoint,
1477     be_arm_adjust_pc_for_break,
1478     be_arm_fetch_integer,
1479     be_arm_fetch_float,
1480     be_arm_store_integer,
1481 };
1482 #endif