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