strmbase: do not lock in BaseOutputPinImpl_GetDeliveryBuffer the MemInputPin will...
[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
42 #define ROR32(n, r) (((n) >> (r)) | ((n) << (32 - (r))))
43
44 #define get_cond(ins)           tbl_cond[(ins >> 28) & 0x0f]
45 #define get_nibble(ins, num)    ((ins >> (num * 4)) & 0x0f)
46
47 static char const tbl_regs[][4] = {
48     "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",
49     "fp", "ip", "sp", "lr", "pc", "cpsr"
50 };
51
52 static char const tbl_addrmode[][3] = {
53     "da", "ia", "db", "ib"
54 };
55
56 static char const tbl_cond[][3] = {
57     "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", "hi", "ls", "ge", "lt", "gt", "le", "", ""
58 };
59
60 static char const tbl_dataops[][4] = {
61     "and", "eor", "sub", "rsb", "add", "adc", "sbc", "rsc", "tst", "teq", "cmp", "cmn", "orr",
62     "mov", "bic", "mvn"
63 };
64
65 static char const tbl_shifts[][4] = {
66     "lsl", "lsr", "asr", "ror"
67 };
68
69 static char const tbl_hiops_t[][4] = {
70     "add", "cmp", "mov", "bx"
71 };
72
73 static char const tbl_aluops_t[][4] = {
74     "and", "eor", "lsl", "lsr", "asr", "adc", "sbc", "ror", "tst", "neg", "cmp", "cmn", "orr",
75     "mul", "bic", "mvn"
76 };
77
78 static char const tbl_immops_t[][4] = {
79     "mov", "cmp", "add", "sub"
80 };
81
82 static char const tbl_sregops_t[][5] = {
83     "strh", "ldsb", "ldrh", "ldsh"
84 };
85
86 static UINT db_get_inst(void* addr, int size)
87 {
88     UINT result = 0;
89     char buffer[4];
90
91     if (dbg_read_memory(addr, buffer, size))
92     {
93         switch (size)
94         {
95         case 4:
96             result = *(UINT*)buffer;
97             break;
98         case 2:
99             result = *(WORD*)buffer;
100             break;
101         }
102     }
103     return result;
104 }
105
106 static void db_printsym(unsigned int addr)
107 {
108     ADDRESS64   a;
109
110     a.Mode   = AddrModeFlat;
111     a.Offset = addr;
112
113     print_address(&a, TRUE);
114 }
115
116 static UINT arm_disasm_branch(UINT inst, ADDRESS64 *addr)
117 {
118     short link = (inst >> 24) & 0x01;
119     int offset = (inst << 2) & 0x03ffffff;
120
121     if (offset & 0x02000000) offset |= 0xfc000000;
122     offset += 8;
123
124     dbg_printf("\n\tb%s%s\t", link ? "l" : "", get_cond(inst));
125     db_printsym(addr->Offset + offset);
126     return 0;
127 }
128
129 static UINT arm_disasm_branchreg(UINT inst, ADDRESS64 *addr)
130 {
131     dbg_printf("\n\tb%s\t%s", get_cond(inst), tbl_regs[get_nibble(inst, 0)]);
132     return 0;
133 }
134
135 static UINT arm_disasm_dataprocessing(UINT inst, ADDRESS64 *addr)
136 {
137     short condcodes = (inst >> 20) & 0x01;
138     short opcode    = (inst >> 21) & 0x0f;
139     short immediate = (inst >> 25) & 0x01;
140     short no_op1    = (opcode & 0x0d) == 0x0d;
141     short no_dst    = (opcode & 0x0c) == 0x08;
142
143     /* check for nop */
144     if (get_nibble(inst, 3) == 15 /* r15 */ && condcodes == 0 &&
145         opcode >= 8 /* tst */ && opcode <= 11 /* cmn */)
146     {
147         dbg_printf("\n\tnop");
148         return 0;
149     }
150
151     dbg_printf("\n\t%s%s%s", tbl_dataops[opcode], condcodes ? "s" : "", get_cond(inst));
152     if (!no_dst) dbg_printf("\t%s, ", tbl_regs[get_nibble(inst, 3)]);
153     else dbg_printf("\t");
154
155     if (no_op1)
156     {
157         if (immediate)
158             dbg_printf("#%u", ROR32(inst & 0xff, 2 * get_nibble(inst, 2)));
159         else
160             dbg_printf("%s", tbl_regs[get_nibble(inst, 0)]);
161     }
162     else
163     {
164         if (immediate)
165             dbg_printf("%s, #%u", tbl_regs[get_nibble(inst, 4)],
166                        ROR32(inst & 0xff, 2 * get_nibble(inst, 2)));
167         else if (((inst >> 4) & 0xff) == 0x00) /* no shift */
168             dbg_printf("%s, %s", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
169         else if (((inst >> 4) & 0x09) == 0x01) /* register shift */
170             dbg_printf("%s, %s, %s %s", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)],
171                        tbl_shifts[(inst >> 5) & 0x03], tbl_regs[(inst >> 8) & 0x0f]);
172         else if (((inst >> 4) & 0x01) == 0x00) /* immediate shift */
173             dbg_printf("%s, %s, %s #%d", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)],
174                        tbl_shifts[(inst >> 5) & 0x03], (inst >> 7) & 0x1f);
175         else
176             return inst;
177     }
178     return 0;
179 }
180
181 static UINT arm_disasm_singletrans(UINT inst, ADDRESS64 *addr)
182 {
183     short load      = (inst >> 20) & 0x01;
184     short writeback = (inst >> 21) & 0x01;
185     short byte      = (inst >> 22) & 0x01;
186     short direction = (inst >> 23) & 0x01;
187     short indexing  = (inst >> 24) & 0x01;
188     short immediate = !((inst >> 25) & 0x01);
189     short offset    = inst & 0x0fff;
190
191     if (!direction) offset *= -1;
192
193     dbg_printf("\n\t%s%s%s%s", load ? "ldr" : "str", byte ? "b" : "", writeback ? "t" : "",
194                get_cond(inst));
195     dbg_printf("\t%s, ", tbl_regs[get_nibble(inst, 3)]);
196     if (indexing)
197     {
198         if (immediate)
199             dbg_printf("[%s, #%d]", tbl_regs[get_nibble(inst, 4)], offset);
200         else if (((inst >> 4) & 0xff) == 0x00) /* no shift */
201             dbg_printf("[%s, %s]", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
202         else if (((inst >> 4) & 0x01) == 0x00) /* immediate shift (there's no register shift) */
203             dbg_printf("[%s, %s, %s #%d]", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)],
204                        tbl_shifts[(inst >> 5) & 0x03], (inst >> 7) & 0x1f);
205         else
206             return inst;
207     }
208     else
209     {
210         if (immediate)
211             dbg_printf("[%s], #%d", tbl_regs[get_nibble(inst, 4)], offset);
212         else if (((inst >> 4) & 0xff) == 0x00) /* no shift */
213             dbg_printf("[%s], %s", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
214         else if (((inst >> 4) & 0x01) == 0x00) /* immediate shift (there's no register shift) */
215             dbg_printf("[%s], %s, %s #%d", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)],
216                        tbl_shifts[(inst >> 5) & 0x03], (inst >> 7) & 0x1f);
217         else
218             return inst;
219     }
220     return 0;
221 }
222
223 static UINT arm_disasm_halfwordtrans(UINT inst, ADDRESS64 *addr)
224 {
225     short halfword  = (inst >> 5)  & 0x01;
226     short sign      = (inst >> 6)  & 0x01;
227     short load      = (inst >> 20) & 0x01;
228     short writeback = (inst >> 21) & 0x01;
229     short immediate = (inst >> 22) & 0x01;
230     short direction = (inst >> 23) & 0x01;
231     short indexing  = (inst >> 24) & 0x01;
232     short offset    = ((inst >> 4) & 0xf0) + (inst & 0x0f);
233
234     if (!direction) offset *= -1;
235
236     dbg_printf("\n\t%s%s%s%s%s", load ? "ldr" : "str", sign ? "s" : "",
237                halfword ? "h" : (sign ? "b" : ""), writeback ? "t" : "", get_cond(inst));
238     dbg_printf("\t%s, ", tbl_regs[get_nibble(inst, 3)]);
239     if (indexing)
240     {
241         if (immediate)
242             dbg_printf("[%s, #%d]", tbl_regs[get_nibble(inst, 4)], offset);
243         else
244             dbg_printf("[%s, %s]", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
245     }
246     else
247     {
248         if (immediate)
249             dbg_printf("[%s], #%d", tbl_regs[get_nibble(inst, 4)], offset);
250         else
251             dbg_printf("[%s], %s", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
252     }
253     return 0;
254 }
255
256 static UINT arm_disasm_blocktrans(UINT inst, ADDRESS64 *addr)
257 {
258     short load      = (inst >> 20) & 0x01;
259     short writeback = (inst >> 21) & 0x01;
260     short psr       = (inst >> 22) & 0x01;
261     short addrmode  = (inst >> 23) & 0x03;
262     short i;
263     short last=15;
264     for (i=15;i>=0;i--)
265         if ((inst>>i) & 1)
266         {
267             last = i;
268             break;
269         }
270
271     dbg_printf("\n\t%s%s%s\t%s%s, {", load ? "ldm" : "stm", tbl_addrmode[addrmode], get_cond(inst),
272                tbl_regs[get_nibble(inst, 4)], writeback ? "!" : "");
273     for (i=0;i<=15;i++)
274         if ((inst>>i) & 1)
275         {
276             if (i == last) dbg_printf("%s", tbl_regs[i]);
277             else dbg_printf("%s, ", tbl_regs[i]);
278         }
279     dbg_printf("}%s", psr ? "^" : "");
280     return 0;
281 }
282
283 static UINT arm_disasm_swi(UINT inst, ADDRESS64 *addr)
284 {
285     UINT comment = inst & 0x00ffffff;
286     dbg_printf("\n\tswi%s\t#%d", get_cond(inst), comment);
287     return 0;
288 }
289
290 static UINT arm_disasm_coproctrans(UINT inst, ADDRESS64 *addr)
291 {
292     WORD CRm    = inst & 0x0f;
293     WORD CP     = (inst >> 5)  & 0x07;
294     WORD CPnum  = (inst >> 8)  & 0x0f;
295     WORD CRn    = (inst >> 16) & 0x0f;
296     WORD load   = (inst >> 20) & 0x01;
297     WORD CP_Opc = (inst >> 21) & 0x07;
298
299     dbg_printf("\n\t%s%s\t%u, %u, %s, cr%u, cr%u, {%u}", load ? "mrc" : "mcr", get_cond(inst), CPnum,
300                CP, tbl_regs[get_nibble(inst, 3)], CRn, CRm, CP_Opc);
301     return 0;
302 }
303
304 static UINT arm_disasm_coprocdataop(UINT inst, ADDRESS64 *addr)
305 {
306     WORD CRm    = inst & 0x0f;
307     WORD CP     = (inst >> 5)  & 0x07;
308     WORD CPnum  = (inst >> 8)  & 0x0f;
309     WORD CRd    = (inst >> 12) & 0x0f;
310     WORD CRn    = (inst >> 16) & 0x0f;
311     WORD CP_Opc = (inst >> 20) & 0x0f;
312
313     dbg_printf("\n\tcdp%s\t%u, %u, cr%u, cr%u, cr%u, {%u}", get_cond(inst),
314                CPnum, CP, CRd, CRn, CRm, CP_Opc);
315     return 0;
316 }
317
318 static UINT arm_disasm_coprocdatatrans(UINT inst, ADDRESS64 *addr)
319 {
320     WORD CPnum  = (inst >> 8)  & 0x0f;
321     WORD CRd    = (inst >> 12) & 0x0f;
322     WORD load      = (inst >> 20) & 0x01;
323     WORD writeback = (inst >> 21) & 0x01;
324     WORD translen  = (inst >> 22) & 0x01;
325     WORD direction = (inst >> 23) & 0x01;
326     WORD indexing  = (inst >> 24) & 0x01;
327     short offset    = (inst & 0xff) << 2;
328
329     if (!direction) offset *= -1;
330
331     dbg_printf("\n\t%s%s%s", load ? "ldc" : "stc", translen ? "l" : "", get_cond(inst));
332     if (indexing)
333         dbg_printf("\t%u, cr%u, [%s, #%d]%s", CPnum, CRd, tbl_regs[get_nibble(inst, 4)], offset, writeback?"!":"");
334     else
335         dbg_printf("\t%u, cr%u, [%s], #%d", CPnum, CRd, tbl_regs[get_nibble(inst, 4)], offset);
336     return 0;
337 }
338
339 static WORD thumb_disasm_hireg(WORD inst, ADDRESS64 *addr)
340 {
341     short dst = inst & 0x07;
342     short src = (inst >> 3) & 0x07;
343     short h2  = (inst >> 6) & 0x01;
344     short h1  = (inst >> 7) & 0x01;
345     short op  = (inst >> 8) & 0x03;
346
347     if (h1) dst += 8;
348     if (h2) src += 8;
349
350     if (op == 2 && dst == src) /* mov rx, rx */
351     {
352         dbg_printf("\n\tnop");
353         return 0;
354     }
355
356     if (op == 3)
357         dbg_printf("\n\tb%sx\t%s", h1?"l":"", tbl_regs[src]);
358     else
359         dbg_printf("\n\t%s\t%s, %s", tbl_hiops_t[op], tbl_regs[dst], tbl_regs[src]);
360
361     return 0;
362 }
363
364 static WORD thumb_disasm_aluop(WORD inst, ADDRESS64 *addr)
365 {
366     short dst = inst & 0x07;
367     short src = (inst >> 3) & 0x07;
368     short op  = (inst >> 6) & 0x0f;
369
370     dbg_printf("\n\t%s\t%s, %s", tbl_aluops_t[op], tbl_regs[dst], tbl_regs[src]);
371
372     return 0;
373 }
374
375 static WORD thumb_disasm_pushpop(WORD inst, ADDRESS64 *addr)
376 {
377     short lrpc = (inst >> 8)  & 0x01;
378     short load = (inst >> 11) & 0x01;
379     short i;
380     short last;
381
382     for (i=7;i>=0;i--)
383         if ((inst>>i) & 1) break;
384     last = i;
385
386     dbg_printf("\n\t%s\t{", load ? "pop" : "push");
387
388     for (i=0;i<=7;i++)
389         if ((inst>>i) & 1)
390         {
391             if (i == last) dbg_printf("%s", tbl_regs[i]);
392             else dbg_printf("%s, ", tbl_regs[i]);
393         }
394     if (lrpc)
395         dbg_printf("%s%s", last ? ", " : "", load ? "pc" : "lr");
396
397     dbg_printf("}");
398     return 0;
399 }
400
401 static WORD thumb_disasm_blocktrans(WORD inst, ADDRESS64 *addr)
402 {
403     short load = (inst >> 11) & 0x01;
404     short i;
405     short last;
406
407     for (i=7;i>=0;i--)
408         if ((inst>>i) & 1) break;
409     last = i;
410
411     dbg_printf("\n\t%s\t%s!, {", load ? "ldmia" : "stmia", tbl_regs[(inst >> 8) & 0x07]);
412
413     for (i=0;i<=7;i++)
414         if ((inst>>i) & 1)
415         {
416             if (i == last) dbg_printf("%s", tbl_regs[i]);
417             else dbg_printf("%s, ", tbl_regs[i]);
418         }
419
420     dbg_printf("}");
421     return 0;
422 }
423
424 static WORD thumb_disasm_longbl(WORD inst, ADDRESS64 *addr)
425 {
426     WORD inst2;
427     UINT offset = (inst & 0x07ff) << 12;
428
429     addr->Offset += 2;
430     inst2 = db_get_inst( memory_to_linear_addr(addr), 2 );
431     if (!((inst2 & 0xf800) == 0xf800)) return inst;
432
433     offset += (inst2 & 0x07ff) << 1;
434     dbg_printf("\n\tbl\t");
435     db_printsym(addr->Offset + offset);
436     return 0;
437 }
438
439 static WORD thumb_disasm_condbranch(WORD inst, ADDRESS64 *addr)
440 {
441     WORD offset = inst & 0x00ff;
442     dbg_printf("\n\tb%s\t", tbl_cond[(inst >> 8) & 0x0f]);
443     db_printsym(addr->Offset + offset);
444     return 0;
445 }
446
447 static WORD thumb_disasm_uncondbranch(WORD inst, ADDRESS64 *addr)
448 {
449     short offset = (inst & 0x07ff) << 1;
450
451     if (offset & 0x0800) offset |= 0xf000;
452     offset += 4;
453
454     dbg_printf("\n\tb\t");
455     db_printsym(addr->Offset + offset);
456     return 0;
457 }
458
459 static WORD thumb_disasm_loadadr(WORD inst, ADDRESS64 *addr)
460 {
461     WORD src = (inst >> 11) & 0x01;
462     WORD offset = (inst & 0xff) << 2;
463
464     dbg_printf("\n\tadd\t%s, %s, #%d", tbl_regs[(inst >> 8) & 0x07], src ? "sp" : "pc", offset);
465     return 0;
466 }
467
468 static WORD thumb_disasm_swi(WORD inst, ADDRESS64 *addr)
469 {
470     WORD comment = inst & 0x00ff;
471     dbg_printf("\n\tswi\t#%d", comment);
472     return 0;
473 }
474
475 static WORD thumb_disasm_nop(WORD inst, ADDRESS64 *addr)
476 {
477     dbg_printf("\n\tnop");
478     return 0;
479 }
480
481 static WORD thumb_disasm_ldrpcrel(WORD inst, ADDRESS64 *addr)
482 {
483     WORD offset = (inst & 0xff) << 2;
484     dbg_printf("\n\tldr\t%s, [pc, #%u]", tbl_regs[(inst >> 8) & 0x07], offset);
485     return 0;
486 }
487
488 static WORD thumb_disasm_ldrsprel(WORD inst, ADDRESS64 *addr)
489 {
490     WORD offset = (inst & 0xff) << 2;
491     dbg_printf("\n\t%s\t%s, [sp, #%u]", (inst & 0x0800)?"ldr":"str", tbl_regs[(inst >> 8) & 0x07], offset);
492     return 0;
493 }
494
495 static WORD thumb_disasm_addsprel(WORD inst, ADDRESS64 *addr)
496 {
497     WORD offset = (inst & 0x7f) << 2;
498     if ((inst >> 7) & 0x01)
499         dbg_printf("\n\tsub\tsp, sp, #%u", offset);
500     else
501         dbg_printf("\n\tadd\tsp, sp, #%u", offset);
502     return 0;
503 }
504
505 static WORD thumb_disasm_ldrimm(WORD inst, ADDRESS64 *addr)
506 {
507     WORD offset = (inst & 0x07c0) >> 6;
508     dbg_printf("\n\t%s%s\t%s, [%s, #%u]", (inst & 0x0800)?"ldr":"str", (inst & 0x1000)?"b":"",
509                tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07], (inst & 0x1000)?offset:(offset << 2));
510     return 0;
511 }
512
513 static WORD thumb_disasm_ldrhimm(WORD inst, ADDRESS64 *addr)
514 {
515     WORD offset = (inst & 0x07c0) >> 5;
516     dbg_printf("\n\t%s\t%s, [%s, #%u]", (inst & 0x0800)?"ldrh":"strh",
517                tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07], offset);
518     return 0;
519 }
520
521 static WORD thumb_disasm_ldrreg(WORD inst, ADDRESS64 *addr)
522 {
523     dbg_printf("\n\t%s%s\t%s, [%s, %s]", (inst & 0x0800)?"ldr":"str", (inst & 0x0400)?"b":"",
524                tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07], tbl_regs[(inst >> 6) & 0x07]);
525     return 0;
526 }
527
528 static WORD thumb_disasm_ldrsreg(WORD inst, ADDRESS64 *addr)
529 {
530     dbg_printf("\n\t%s\t%s, [%s, %s]", tbl_sregops_t[(inst >> 10) & 0x03],
531                tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07], tbl_regs[(inst >> 6) & 0x07]);
532     return 0;
533 }
534
535 static WORD thumb_disasm_immop(WORD inst, ADDRESS64 *addr)
536 {
537     WORD op = (inst >> 11) & 0x03;
538     dbg_printf("\n\t%s\t%s, #%u", tbl_immops_t[op], tbl_regs[(inst >> 8) & 0x07], inst & 0xff);
539     return 0;
540 }
541
542 static WORD thumb_disasm_addsub(WORD inst, ADDRESS64 *addr)
543 {
544     WORD op = (inst >> 9) & 0x01;
545     WORD immediate = (inst >> 10) & 0x01;
546
547     dbg_printf("\n\t%s\t%s, %s, ", op ? "sub" : "add",
548                tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07]);
549     if (immediate)
550         dbg_printf("#%d", (inst >> 6) & 0x07);
551     else
552         dbg_printf("%s", tbl_regs[(inst >> 6) & 0x07]);
553     return 0;
554 }
555
556 static WORD thumb_disasm_movshift(WORD inst, ADDRESS64 *addr)
557 {
558     WORD op = (inst >> 11) & 0x03;
559     dbg_printf("\n\t%s\t%s, %s, #%u", tbl_shifts[op],
560                tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07], (inst >> 6) & 0x1f);
561     return 0;
562 }
563
564 struct inst_arm
565 {
566         UINT mask;
567         UINT pattern;
568         UINT (*func)(UINT, ADDRESS64*);
569 };
570
571 static const struct inst_arm tbl_arm[] = {
572     { 0x0e000000, 0x0a000000, arm_disasm_branch },
573     { 0x0e000090, 0x00000090, arm_disasm_halfwordtrans },
574     { 0x0fffff00, 0x012fff00, arm_disasm_branchreg },
575     { 0x0c000000, 0x00000000, arm_disasm_dataprocessing },
576     { 0x0c000000, 0x04000000, arm_disasm_singletrans },
577     { 0x0e000000, 0x08000000, arm_disasm_blocktrans },
578     { 0x0f000000, 0x0f000000, arm_disasm_swi },
579     { 0x0f000010, 0x0e000010, arm_disasm_coproctrans },
580     { 0x0f000010, 0x0e000000, arm_disasm_coprocdataop },
581     { 0x0e000000, 0x0c000000, arm_disasm_coprocdatatrans },
582     { 0x00000000, 0x00000000, NULL }
583 };
584
585 struct inst_thumb16
586 {
587         WORD mask;
588         WORD pattern;
589         WORD (*func)(WORD, ADDRESS64*);
590 };
591
592 static const struct inst_thumb16 tbl_thumb16[] = {
593     { 0xfc00, 0x4400, thumb_disasm_hireg },
594     { 0xfc00, 0x4000, thumb_disasm_aluop },
595     { 0xf600, 0xb400, thumb_disasm_pushpop },
596     { 0xf000, 0xc000, thumb_disasm_blocktrans },
597     { 0xf800, 0xf000, thumb_disasm_longbl },
598     { 0xf000, 0xd000, thumb_disasm_condbranch },
599     { 0xf800, 0xe000, thumb_disasm_uncondbranch },
600     { 0xf000, 0xa000, thumb_disasm_loadadr },
601     { 0xf800, 0x4800, thumb_disasm_ldrpcrel },
602     { 0xf000, 0x9000, thumb_disasm_ldrsprel },
603     { 0xff00, 0xb000, thumb_disasm_addsprel },
604     { 0xe000, 0x6000, thumb_disasm_ldrimm },
605     { 0xf000, 0x8000, thumb_disasm_ldrhimm },
606     { 0xf200, 0x5000, thumb_disasm_ldrreg },
607     { 0xf200, 0x5200, thumb_disasm_ldrsreg },
608     { 0xe000, 0x2000, thumb_disasm_immop },
609     { 0xff00, 0xdf00, thumb_disasm_swi },
610     { 0xff00, 0xbf00, thumb_disasm_nop },
611     { 0xf800, 0x1800, thumb_disasm_addsub },
612     { 0xe000, 0x0000, thumb_disasm_movshift },
613     { 0x0000, 0x0000, NULL }
614 };
615
616 /***********************************************************************
617  *              disasm_one_insn
618  *
619  * Disassemble instruction at 'addr'. addr is changed to point to the
620  * start of the next instruction.
621  */
622 void be_arm_disasm_one_insn(ADDRESS64 *addr, int display)
623 {
624     struct inst_arm *a_ptr = (struct inst_arm *)&tbl_arm;
625     struct inst_thumb16 *t_ptr = (struct inst_thumb16 *)&tbl_thumb16;
626     UINT inst;
627     WORD tinst;
628     int size;
629     int matched = 0;
630
631     char tmp[64];
632     DWORD_PTR* pval;
633
634     if (!memory_get_register(CV_ARM_CPSR, &pval, tmp, sizeof(tmp)))
635         dbg_printf("\n\tmemory_get_register failed: %s", tmp);
636     else
637         db_disasm_thumb=(*pval & 0x20)?TRUE:FALSE;
638
639     if (db_disasm_thumb) size = THUMB_INSN_SIZE;
640     else size = ARM_INSN_SIZE;
641
642     db_display = display;
643     inst = db_get_inst( memory_to_linear_addr(addr), size );
644
645     if (!db_disasm_thumb)
646     {
647         while (a_ptr->func) {
648                 if ((inst & a_ptr->mask) ==  a_ptr->pattern) {
649                         matched = 1;
650                         break;
651                 }
652                 a_ptr++;
653         }
654
655         if (!matched) {
656                 dbg_printf("\n\tUnknown Instruction: %08x", inst);
657                 addr->Offset += size;
658                 return;
659         }
660         else
661         {
662             if (!a_ptr->func(inst, addr))
663                 addr->Offset += size;
664             return;
665         }
666     }
667     else
668     {
669         tinst = inst;
670         while (t_ptr->func) {
671                 if ((tinst & t_ptr->mask) ==  t_ptr->pattern) {
672                         matched = 1;
673                         break;
674                 }
675                 t_ptr++;
676         }
677
678         if (!matched) {
679                 dbg_printf("\n\tUnknown Instruction: %04x", tinst);
680                 addr->Offset += size;
681                 return;
682         }
683         else
684         {
685             if (!t_ptr->func(tinst, addr))
686                 addr->Offset += size;
687         }
688         return;
689     }
690 }
691
692 static unsigned be_arm_get_addr(HANDLE hThread, const CONTEXT* ctx,
693                                 enum be_cpu_addr bca, ADDRESS64* addr)
694 {
695     switch (bca)
696     {
697     case be_cpu_addr_pc:
698         return be_cpu_build_addr(hThread, ctx, addr, 0, ctx->Pc);
699     case be_cpu_addr_stack:
700         return be_cpu_build_addr(hThread, ctx, addr, 0, ctx->Sp);
701     case be_cpu_addr_frame:
702         return be_cpu_build_addr(hThread, ctx, addr, 0, ctx->Fp);
703     }
704     return FALSE;
705 }
706
707 static unsigned be_arm_get_register_info(int regno, enum be_cpu_addr* kind)
708 {
709     switch (regno)
710     {
711     case CV_ARM_PC:  *kind = be_cpu_addr_pc; return TRUE;
712     case CV_ARM_R0 + 11: *kind = be_cpu_addr_frame; return TRUE;
713     case CV_ARM_SP:  *kind = be_cpu_addr_stack; return TRUE;
714     }
715     return FALSE;
716 }
717
718 static void be_arm_single_step(CONTEXT* ctx, unsigned enable)
719 {
720     dbg_printf("be_arm_single_step: not done\n");
721 }
722
723 static void be_arm_print_context(HANDLE hThread, const CONTEXT* ctx, int all_regs)
724 {
725     static const char condflags[] = "NZCV";
726     int i;
727     char        buf[8];
728
729     switch (ctx->Cpsr & 0x1F)
730     {
731     case 0:  strcpy(buf, "User26"); break;
732     case 1:  strcpy(buf, "FIQ26"); break;
733     case 2:  strcpy(buf, "IRQ26"); break;
734     case 3:  strcpy(buf, "SVC26"); break;
735     case 16: strcpy(buf, "User"); break;
736     case 17: strcpy(buf, "FIQ"); break;
737     case 18: strcpy(buf, "IRQ"); break;
738     case 19: strcpy(buf, "SVC"); break;
739     case 23: strcpy(buf, "ABT"); break;
740     case 27: strcpy(buf, "UND"); break;
741     default: strcpy(buf, "UNKNWN"); break;
742     }
743
744     dbg_printf("Register dump:\n");
745     dbg_printf("%s %s Mode\n", (ctx->Cpsr & 0x20) ? "Thumb" : "ARM", buf);
746
747     strcpy(buf, condflags);
748     for (i = 0; buf[i]; i++)
749         if (!((ctx->Cpsr >> 26) & (1 << (sizeof(condflags) - i))))
750             buf[i] = '-';
751
752     dbg_printf(" Pc:%04x Sp:%04x Lr:%04x Cpsr:%04x(%s)\n",
753                ctx->Pc, ctx->Sp, ctx->Lr, ctx->Cpsr, buf);
754     dbg_printf(" r0:%04x r1:%04x r2:%04x r3:%04x\n",
755                ctx->R0, ctx->R1, ctx->R2, ctx->R3);
756     dbg_printf(" r4:%04x r5:%04x  r6:%04x  r7:%04x r8:%04x\n",
757                ctx->R4, ctx->R5, ctx->R6, ctx->R7, ctx->R8 );
758     dbg_printf(" r9:%04x r10:%04x Fp:%04x Ip:%04x\n",
759                ctx->R9, ctx->R10, ctx->Fp, ctx->Ip );
760
761     if (all_regs) dbg_printf( "Floating point ARM dump not implemented\n" );
762 }
763
764 static void be_arm_print_segment_info(HANDLE hThread, const CONTEXT* ctx)
765 {
766 }
767
768 static struct dbg_internal_var be_arm_ctx[] =
769 {
770     {CV_ARM_R0 +  0,    "r0",           (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R0),     dbg_itype_unsigned_int},
771     {CV_ARM_R0 +  1,    "r1",           (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R1),     dbg_itype_unsigned_int},
772     {CV_ARM_R0 +  2,    "r2",           (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R2),     dbg_itype_unsigned_int},
773     {CV_ARM_R0 +  3,    "r3",           (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R3),     dbg_itype_unsigned_int},
774     {CV_ARM_R0 +  4,    "r4",           (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R4),     dbg_itype_unsigned_int},
775     {CV_ARM_R0 +  5,    "r5",           (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R5),     dbg_itype_unsigned_int},
776     {CV_ARM_R0 +  6,    "r6",           (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R6),     dbg_itype_unsigned_int},
777     {CV_ARM_R0 +  7,    "r7",           (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R7),     dbg_itype_unsigned_int},
778     {CV_ARM_R0 +  8,    "r8",           (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R8),     dbg_itype_unsigned_int},
779     {CV_ARM_R0 +  9,    "r9",           (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R9),     dbg_itype_unsigned_int},
780     {CV_ARM_R0 +  10,   "r10",          (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R10),    dbg_itype_unsigned_int},
781     {CV_ARM_R0 +  11,   "r11",          (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Fp),     dbg_itype_unsigned_int},
782     {CV_ARM_R0 +  12,   "r12",          (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Ip),     dbg_itype_unsigned_int},
783     {CV_ARM_SP,         "sp",           (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Sp),     dbg_itype_unsigned_int},
784     {CV_ARM_LR,         "lr",           (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Lr),     dbg_itype_unsigned_int},
785     {CV_ARM_PC,         "pc",           (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Pc),     dbg_itype_unsigned_int},
786     {CV_ARM_CPSR,       "cpsr",         (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Cpsr),   dbg_itype_unsigned_int},
787     {0,                 NULL,           0,                                         dbg_itype_none}
788 };
789
790 static unsigned be_arm_is_step_over_insn(const void* insn)
791 {
792     dbg_printf("be_arm_is_step_over_insn: not done\n");
793     return FALSE;
794 }
795
796 static unsigned be_arm_is_function_return(const void* insn)
797 {
798     dbg_printf("be_arm_is_function_return: not done\n");
799     return FALSE;
800 }
801
802 static unsigned be_arm_is_break_insn(const void* insn)
803 {
804     dbg_printf("be_arm_is_break_insn: not done\n");
805     return FALSE;
806 }
807
808 static unsigned be_arm_is_func_call(const void* insn, ADDRESS64* callee)
809 {
810     return FALSE;
811 }
812
813 static unsigned be_arm_is_jump(const void* insn, ADDRESS64* jumpee)
814 {
815     return FALSE;
816 }
817
818 static unsigned be_arm_insert_Xpoint(HANDLE hProcess, const struct be_process_io* pio,
819                                      CONTEXT* ctx, enum be_xpoint_type type,
820                                      void* addr, unsigned long* val, unsigned size)
821 {
822     SIZE_T              sz;
823
824     switch (type)
825     {
826     case be_xpoint_break:
827         if (!size) return 0;
828         if (!pio->read(hProcess, addr, val, 4, &sz) || sz != 4) return 0;
829     default:
830         dbg_printf("Unknown/unsupported bp type %c\n", type);
831         return 0;
832     }
833     return 1;
834 }
835
836 static unsigned be_arm_remove_Xpoint(HANDLE hProcess, const struct be_process_io* pio,
837                                      CONTEXT* ctx, enum be_xpoint_type type,
838                                      void* addr, unsigned long val, unsigned size)
839 {
840     SIZE_T              sz;
841
842     switch (type)
843     {
844     case be_xpoint_break:
845         if (!size) return 0;
846         if (!pio->write(hProcess, addr, &val, 4, &sz) || sz == 4) return 0;
847         break;
848     default:
849         dbg_printf("Unknown/unsupported bp type %c\n", type);
850         return 0;
851     }
852     return 1;
853 }
854
855 static unsigned be_arm_is_watchpoint_set(const CONTEXT* ctx, unsigned idx)
856 {
857     dbg_printf("be_arm_is_watchpoint_set: not done\n");
858     return FALSE;
859 }
860
861 static void be_arm_clear_watchpoint(CONTEXT* ctx, unsigned idx)
862 {
863     dbg_printf("be_arm_clear_watchpoint: not done\n");
864 }
865
866 static int be_arm_adjust_pc_for_break(CONTEXT* ctx, BOOL way)
867 {
868     INT step = (ctx->Cpsr & 0x20) ? 2 : 4;
869
870     if (way)
871     {
872         ctx->Pc -= step;
873         return -step;
874     }
875     ctx->Pc += step;
876     return step;
877 }
878
879 static int be_arm_fetch_integer(const struct dbg_lvalue* lvalue, unsigned size,
880                                 unsigned ext_sign, LONGLONG* ret)
881 {
882     if (size != 1 && size != 2 && size != 4 && size != 8) return FALSE;
883
884     memset(ret, 0, sizeof(*ret)); /* clear unread bytes */
885     /* FIXME: this assumes that debuggee and debugger use the same
886      * integral representation
887      */
888     if (!memory_read_value(lvalue, size, ret)) return FALSE;
889
890     /* propagate sign information */
891     if (ext_sign && size < 8 && (*ret >> (size * 8 - 1)) != 0)
892     {
893         ULONGLONG neg = -1;
894         *ret |= neg << (size * 8);
895     }
896     return TRUE;
897 }
898
899 static int be_arm_fetch_float(const struct dbg_lvalue* lvalue, unsigned size,
900                               long double* ret)
901 {
902     char        tmp[sizeof(long double)];
903
904     /* FIXME: this assumes that debuggee and debugger use the same
905      * representation for reals
906      */
907     if (!memory_read_value(lvalue, size, tmp)) return FALSE;
908
909     switch (size)
910     {
911     case sizeof(float):         *ret = *(float*)tmp;            break;
912     case sizeof(double):        *ret = *(double*)tmp;           break;
913     default:                    return FALSE;
914     }
915     return TRUE;
916 }
917
918 static int be_arm_store_integer(const struct dbg_lvalue* lvalue, unsigned size,
919                                 unsigned is_signed, LONGLONG val)
920 {
921     /* this is simple if we're on a little endian CPU */
922     return memory_write_value(lvalue, size, &val);
923 }
924
925 struct backend_cpu be_arm =
926 {
927     IMAGE_FILE_MACHINE_ARMV7,
928     4,
929     be_cpu_linearize,
930     be_cpu_build_addr,
931     be_arm_get_addr,
932     be_arm_get_register_info,
933     be_arm_single_step,
934     be_arm_print_context,
935     be_arm_print_segment_info,
936     be_arm_ctx,
937     be_arm_is_step_over_insn,
938     be_arm_is_function_return,
939     be_arm_is_break_insn,
940     be_arm_is_func_call,
941     be_arm_is_jump,
942     be_arm_disasm_one_insn,
943     be_arm_insert_Xpoint,
944     be_arm_remove_Xpoint,
945     be_arm_is_watchpoint_set,
946     be_arm_clear_watchpoint,
947     be_arm_adjust_pc_for_break,
948     be_arm_fetch_integer,
949     be_arm_fetch_float,
950     be_arm_store_integer,
951 };
952 #endif