winedbg: Add partial Thumb disassembler.
[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, 2011 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_addrmode[][3] = {
48     "da", "ia", "db", "ib"
49 };
50
51 static char const tbl_cond[][3] = {
52     "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", "hi", "ls", "ge", "lt", "gt", "le", "", ""
53 };
54
55 static char const tbl_dataops[][4] = {
56     "and", "eor", "sub", "rsb", "add", "adc", "sbc", "rsc", "tst", "teq", "cmp", "cmn", "orr",
57     "mov", "bic", "mvn"
58 };
59
60 static char const tbl_hiops_t[][4] = {
61 "add", "cmp", "mov", "bx"
62 };
63
64 static char const tbl_immops_t[][4] = {
65 "mov", "cmp", "add", "sub"
66 };
67
68 static UINT db_get_inst(void* addr, int size)
69 {
70     UINT result = 0;
71     char buffer[4];
72
73     if (dbg_read_memory(addr, buffer, size))
74     {
75         switch (size)
76         {
77         case 4:
78             result = *(UINT*)buffer;
79             break;
80         case 2:
81             result = *(WORD*)buffer;
82             break;
83         }
84     }
85     return result;
86 }
87
88 static UINT arm_disasm_branch(UINT inst)
89 {
90     short link = (inst >> 24) & 0x01;
91     int offset = (inst << 2) & 0x03ffffff;
92
93     if (offset & 0x02000000) offset |= 0xfc000000;
94     offset += 8;
95
96     dbg_printf("\n\tb%s%s\t#%d/0x%08x", link ? "l" : "", get_cond(inst), offset, offset);
97     return 0;
98 }
99
100 static UINT arm_disasm_dataprocessing(UINT inst)
101 {
102     short condcodes = (inst >> 20) & 0x01;
103     short opcode    = (inst >> 21) & 0x0f;
104     short immediate = (inst >> 25) & 0x01;
105     short no_op1    = (opcode & 0x0d) == 0x0d;
106
107     /* check for nop */
108     if (get_nibble(inst, 3) == 15 /* r15 */ && condcodes == 0 &&
109         opcode >= 8 /* tst */ && opcode <= 11 /* cmn */)
110     {
111         dbg_printf("\n\tnop");
112         return 0;
113     }
114
115     dbg_printf("\n\t%s%s%s", tbl_dataops[opcode], condcodes ? "s" : "", get_cond(inst));
116     if (no_op1)
117     {
118         if (immediate)
119             dbg_printf("\tr%u, #%u", get_nibble(inst, 3),
120                        ROR32(inst & 0xff, 2 * get_nibble(inst, 2)));
121         else
122             dbg_printf("\tr%u, r%u", get_nibble(inst, 3), get_nibble(inst, 0));
123     }
124     else
125     {
126         if (immediate)
127             dbg_printf("\tr%u, r%u, #%u", get_nibble(inst, 3), get_nibble(inst, 4),
128                        ROR32(inst & 0xff, 2 * get_nibble(inst, 2)));
129         else
130             dbg_printf("\tr%u, r%u, r%u", get_nibble(inst, 3), get_nibble(inst, 4),
131                        get_nibble(inst, 0));
132     }
133     return 0;
134 }
135
136 static UINT arm_disasm_singletrans(UINT inst)
137 {
138     short load      = (inst >> 20) & 0x01;
139     short writeback = (inst >> 21) & 0x01;
140     short byte      = (inst >> 22) & 0x01;
141     short direction = (inst >> 23) & 0x01;
142     /* FIXME: what to do with bit 24 (indexing) */
143     short immediate = !((inst >> 25) & 0x01);
144     short offset    = inst & 0x0fff;
145
146     if (!direction) offset *= -1;
147
148     dbg_printf("\n\t%s%s%s%s", load ? "ldr" : "str", byte ? "b" : "", writeback ? "t" : "",
149                get_cond(inst));
150     if (immediate)
151         dbg_printf("\tr%u, [r%u, #%d]", get_nibble(inst, 3), get_nibble(inst, 4), offset);
152     else
153         dbg_printf("\tr%u, r%u, r%u", get_nibble(inst, 3), get_nibble(inst, 4),
154                    get_nibble(inst, 0));
155     return 0;
156 }
157
158 static UINT arm_disasm_halfwordtrans(UINT inst)
159 {
160     short halfword  = (inst >> 5)  & 0x01;
161     short sign      = (inst >> 6)  & 0x01;
162     short load      = (inst >> 20) & 0x01;
163     short writeback = (inst >> 21) & 0x01;
164     short immediate = (inst >> 22) & 0x01;
165     short direction = (inst >> 23) & 0x01;
166     /* FIXME: what to do with bit 24 (indexing) */
167     short offset    = ((inst >> 4) & 0xf0) + (inst & 0x0f);
168
169     if (!direction) offset *= -1;
170
171     dbg_printf("\n\t%s%s%s%s%s", load ? "ldr" : "str", sign ? "s" : "",
172                halfword ? "h" : (sign ? "b" : ""), writeback ? "t" : "", get_cond(inst));
173     if (immediate)
174         dbg_printf("\tr%u, r%u, #%d", get_nibble(inst, 3), get_nibble(inst, 4), offset);
175     else
176         dbg_printf("\tr%u, r%u, r%u", get_nibble(inst, 3), get_nibble(inst, 4), get_nibble(inst, 0));
177     return 0;
178 }
179
180 static UINT arm_disasm_blocktrans(UINT inst)
181 {
182     short load      = (inst >> 20) & 0x01;
183     short writeback = (inst >> 21) & 0x01;
184     short psr       = (inst >> 22) & 0x01;
185     short addrmode  = (inst >> 23) & 0x03;
186     short i;
187     short last=15;
188     for (i=15;i>=0;i--)
189         if ((inst>>i) & 1)
190         {
191             last = i;
192             break;
193         }
194
195     dbg_printf("\n\t%s%s%s\tr%u%s, {", load ? "ldm" : "stm", tbl_addrmode[addrmode], get_cond(inst),
196                get_nibble(inst, 4), writeback ? "!" : "");
197     for (i=0;i<=15;i++)
198         if ((inst>>i) & 1)
199         {
200             if (i == last) dbg_printf("r%u", i);
201             else dbg_printf("r%u, ", i);
202         }
203     dbg_printf("}%s", psr ? "^" : "");
204     return 0;
205 }
206
207 static UINT arm_disasm_swi(UINT inst)
208 {
209     UINT comment = inst & 0x00ffffff;
210     dbg_printf("\n\tswi%s\t#%d/0x%08x", get_cond(inst), comment, comment);
211     return 0;
212 }
213
214 static UINT arm_disasm_coproctrans(UINT inst)
215 {
216     WORD CRm    = inst & 0x0f;
217     WORD CP     = (inst >> 5)  & 0x07;
218     WORD CPnum  = (inst >> 8)  & 0x0f;
219     WORD CRn    = (inst >> 16) & 0x0f;
220     WORD load   = (inst >> 20) & 0x01;
221     WORD CP_Opc = (inst >> 21) & 0x07;
222
223     dbg_printf("\n\t%s%s\t%u, %u, r%u, cr%u, cr%u, {%u}", load ? "mrc" : "mcr", get_cond(inst), CPnum,
224                CP, get_nibble(inst, 3), CRn, CRm, CP_Opc);
225     return 0;
226 }
227
228 static UINT arm_disasm_coprocdataop(UINT inst)
229 {
230     WORD CRm    = inst & 0x0f;
231     WORD CP     = (inst >> 5)  & 0x07;
232     WORD CPnum  = (inst >> 8)  & 0x0f;
233     WORD CRd    = (inst >> 12) & 0x0f;
234     WORD CRn    = (inst >> 16) & 0x0f;
235     WORD CP_Opc = (inst >> 20) & 0x0f;
236
237     dbg_printf("\n\tcdp%s\t%u, %u, cr%u, cr%u, cr%u, {%u}", get_cond(inst),
238                CPnum, CP, CRd, CRn, CRm, CP_Opc);
239     return 0;
240 }
241
242 static UINT arm_disasm_coprocdatatrans(UINT inst)
243 {
244     WORD CPnum  = (inst >> 8)  & 0x0f;
245     WORD CRd    = (inst >> 12) & 0x0f;
246     WORD load      = (inst >> 20) & 0x01;
247     /* FIXME: what to do with bit 21 (writeback) */
248     WORD translen  = (inst >> 22) & 0x01;
249     WORD direction = (inst >> 23) & 0x01;
250     /* FIXME: what to do with bit 24 (indexing) */
251     short offset    = (inst & 0xff) << 2;
252
253     if (!direction) offset *= -1;
254
255     dbg_printf("\n\t%s%s%s", load ? "ldc" : "stc", translen ? "l" : "", get_cond(inst));
256     dbg_printf("\t%u, cr%u, [r%u, #%d]", CPnum, CRd, get_nibble(inst, 4), offset);
257     return 0;
258 }
259
260 static WORD thumb_disasm_hireg(WORD inst)
261 {
262     short dst = inst & 0x07;
263     short src = (inst >> 3) & 0x07;
264     short h2  = (inst >> 6) & 0x01;
265     short h1  = (inst >> 7) & 0x01;
266     short op  = (inst >> 8) & 0x03;
267
268     if (h1) dst += 8;
269     if (h2) src += 8;
270
271     if (op == 3)
272         dbg_printf("\n\tb%sx\tr%u", h1?"l":"", src);
273     else
274         dbg_printf("\n\t%s\tr%u, r%u", tbl_hiops_t[op], dst, src);
275
276     return 0;
277 }
278
279 static WORD thumb_disasm_blocktrans(WORD inst)
280 {
281     short lrpc = (inst >> 8)  & 0x01;
282     short load = (inst >> 11) & 0x01;
283     short i;
284     short last;
285
286     for (i=7;i>=0;i--)
287         if ((inst>>i) & 1) break;
288     last = i;
289
290     dbg_printf("\n\t%s\t{", load ? "pop" : "push");
291
292     for (i=0;i<=7;i++)
293         if ((inst>>i) & 1)
294         {
295             if (i == last) dbg_printf("r%u", i);
296             else dbg_printf("r%u, ", i);
297         }
298     if (lrpc)
299         dbg_printf(", %s", load ? "pc" : "lr");
300
301     dbg_printf("}");
302     return 0;
303 }
304
305 static WORD thumb_disasm_swi(WORD inst)
306 {
307     WORD comment = inst & 0x00ff;
308     dbg_printf("\n\tswi\t#%d", comment);
309     return 0;
310 }
311
312 static WORD thumb_disasm_nop(WORD inst)
313 {
314     dbg_printf("\n\tnop");
315     return 0;
316 }
317
318 static WORD thumb_disasm_ldrpcrel(WORD inst)
319 {
320     WORD offset = (inst & 0xff) << 2;
321     dbg_printf("\n\tldr\tr%u, [pc, #%u]", (inst >> 8) & 0x07, offset);
322     return 0;
323 }
324
325 static WORD thumb_disasm_ldrsprel(WORD inst)
326 {
327     WORD offset = (inst & 0xff) << 2;
328     dbg_printf("\n\t%s\tr%u, [sp, #%u]", (inst & 0x0800)?"ldr":"str", (inst >> 8) & 0x07, offset);
329     return 0;
330 }
331
332 static WORD thumb_disasm_ldrimm(WORD inst)
333 {
334     WORD offset = (inst & 0x07c0) >> 6;
335     dbg_printf("\n\t%s%s\tr%u, [r%u, #%u]", (inst & 0x0800)?"ldr":"str", (inst & 0x1000)?"b":"",
336                inst & 0x07, (inst >> 3) & 0x07, (inst & 0x1000)?offset:(offset << 2));
337     return 0;
338 }
339
340 static WORD thumb_disasm_immop(WORD inst)
341 {
342     WORD op = (inst >> 11) & 0x03;
343     dbg_printf("\n\t%s\tr%u, #%u", tbl_immops_t[op], (inst >> 8) & 0x07, inst & 0xff);
344     return 0;
345 }
346
347 struct inst_arm
348 {
349         UINT mask;
350         UINT pattern;
351         UINT (*func)(UINT);
352 };
353
354 static const struct inst_arm tbl_arm[] = {
355     { 0x0e000000, 0x0a000000, arm_disasm_branch },
356     { 0x0c000000, 0x00000000, arm_disasm_dataprocessing },
357     { 0x0c000000, 0x04000000, arm_disasm_singletrans },
358     { 0x0e000090, 0x00000090, arm_disasm_halfwordtrans },
359     { 0x0e000000, 0x08000000, arm_disasm_blocktrans },
360     { 0x0f000000, 0x0f000000, arm_disasm_swi },
361     { 0x0f000010, 0x0e000010, arm_disasm_coproctrans },
362     { 0x0f000010, 0x0e000000, arm_disasm_coprocdataop },
363     { 0x0e000000, 0x0c000000, arm_disasm_coprocdatatrans },
364     { 0x00000000, 0x00000000, NULL }
365 };
366
367 struct inst_thumb16
368 {
369         WORD mask;
370         WORD pattern;
371         WORD (*func)(WORD);
372 };
373
374 static const struct inst_thumb16 tbl_thumb16[] = {
375     { 0xfc00, 0x4400, thumb_disasm_hireg },
376     { 0xf600, 0xb400, thumb_disasm_blocktrans },
377     { 0xf800, 0x4800, thumb_disasm_ldrpcrel },
378     { 0xf000, 0x9000, thumb_disasm_ldrsprel },
379     { 0xe000, 0x6000, thumb_disasm_ldrimm },
380     { 0xe000, 0x2000, thumb_disasm_immop },
381     { 0xff00, 0xdf00, thumb_disasm_swi },
382     { 0xff00, 0xbf00, thumb_disasm_nop },
383     { 0x0000, 0x0000, NULL }
384 };
385
386 /***********************************************************************
387  *              disasm_one_insn
388  *
389  * Disassemble instruction at 'addr'. addr is changed to point to the
390  * start of the next instruction.
391  */
392 void be_arm_disasm_one_insn(ADDRESS64 *addr, int display)
393 {
394     struct inst_arm *a_ptr = (struct inst_arm *)&tbl_arm;
395     struct inst_thumb16 *t_ptr = (struct inst_thumb16 *)&tbl_thumb16;
396     UINT inst;
397     WORD tinst;
398     int size;
399     int matched = 0;
400
401     char tmp[64];
402     DWORD_PTR* pval;
403
404     if (!memory_get_register(CV_ARM_CPSR, &pval, tmp, sizeof(tmp)))
405         dbg_printf("\n\tmemory_get_register failed: %s\n",tmp);
406     else
407         db_disasm_thumb=(*pval & 0x20)?TRUE:FALSE;
408
409     if (db_disasm_thumb) size = THUMB_INSN_SIZE;
410     else size = ARM_INSN_SIZE;
411
412     db_display = display;
413     inst = db_get_inst( memory_to_linear_addr(addr), size );
414
415     if (!db_disasm_thumb)
416     {
417         while (a_ptr->func) {
418                 if ((inst & a_ptr->mask) ==  a_ptr->pattern) {
419                         matched = 1;
420                         break;
421                 }
422                 a_ptr++;
423         }
424
425         if (!matched) {
426                 dbg_printf("\n\tUnknown Instruction: %08x\n", inst);
427                 addr->Offset += size;
428                 return;
429         }
430         else
431         {
432             if (!a_ptr->func(inst))
433             {
434                 dbg_printf("\n");
435                 addr->Offset += size;
436             }
437             return;
438         }
439     }
440     else
441     {
442         tinst = inst;
443         while (t_ptr->func) {
444                 if ((tinst & t_ptr->mask) ==  t_ptr->pattern) {
445                         matched = 1;
446                         break;
447                 }
448                 t_ptr++;
449         }
450
451         if (!matched) {
452                 dbg_printf("\n\tUnknown Instruction: %08x\n", tinst);
453                 addr->Offset += size;
454                 return;
455         }
456         else
457         {
458             if (!t_ptr->func(tinst))
459             {
460                 dbg_printf("\n");
461                 addr->Offset += size;
462             }
463         }
464         return;
465     }
466 }
467
468 static unsigned be_arm_get_addr(HANDLE hThread, const CONTEXT* ctx,
469                                 enum be_cpu_addr bca, ADDRESS64* addr)
470 {
471     switch (bca)
472     {
473     case be_cpu_addr_pc:
474         return be_cpu_build_addr(hThread, ctx, addr, 0, ctx->Pc);
475     case be_cpu_addr_stack:
476         return be_cpu_build_addr(hThread, ctx, addr, 0, ctx->Sp);
477     case be_cpu_addr_frame:
478         return be_cpu_build_addr(hThread, ctx, addr, 0, ctx->Fp);
479     }
480     return FALSE;
481 }
482
483 static unsigned be_arm_get_register_info(int regno, enum be_cpu_addr* kind)
484 {
485     switch (regno)
486     {
487     case CV_ARM_PC:  *kind = be_cpu_addr_pc; return TRUE;
488     case CV_ARM_R0 + 11: *kind = be_cpu_addr_frame; return TRUE;
489     case CV_ARM_SP:  *kind = be_cpu_addr_stack; return TRUE;
490     }
491     return FALSE;
492 }
493
494 static void be_arm_single_step(CONTEXT* ctx, unsigned enable)
495 {
496     dbg_printf("be_arm_single_step: not done\n");
497 }
498
499 static void be_arm_print_context(HANDLE hThread, const CONTEXT* ctx, int all_regs)
500 {
501     static const char condflags[] = "NZCV";
502     int i;
503     char        buf[8];
504
505     switch (ctx->Cpsr & 0x1F)
506     {
507     case 0:  strcpy(buf, "User26"); break;
508     case 1:  strcpy(buf, "FIQ26"); break;
509     case 2:  strcpy(buf, "IRQ26"); break;
510     case 3:  strcpy(buf, "SVC26"); break;
511     case 16: strcpy(buf, "User"); break;
512     case 17: strcpy(buf, "FIQ"); break;
513     case 18: strcpy(buf, "IRQ"); break;
514     case 19: strcpy(buf, "SVC"); break;
515     case 23: strcpy(buf, "ABT"); break;
516     case 27: strcpy(buf, "UND"); break;
517     default: strcpy(buf, "UNKNWN"); break;
518     }
519
520     dbg_printf("Register dump:\n");
521     dbg_printf("%s %s Mode\n", (ctx->Cpsr & 0x20) ? "Thumb" : "ARM", buf);
522
523     strcpy(buf, condflags);
524     for (i = 0; buf[i]; i++)
525         if (!((ctx->Cpsr >> 26) & (1 << (sizeof(condflags) - i))))
526             buf[i] = '-';
527
528     dbg_printf(" Pc:%04x Sp:%04x Lr:%04x Cpsr:%04x(%s)\n",
529                ctx->Pc, ctx->Sp, ctx->Lr, ctx->Cpsr, buf);
530     dbg_printf(" r0:%04x r1:%04x r2:%04x r3:%04x\n",
531                ctx->R0, ctx->R1, ctx->R2, ctx->R3);
532     dbg_printf(" r4:%04x r5:%04x  r6:%04x  r7:%04x r8:%04x\n",
533                ctx->R4, ctx->R5, ctx->R6, ctx->R7, ctx->R8 );
534     dbg_printf(" r9:%04x r10:%04x Fp:%04x Ip:%04x\n",
535                ctx->R9, ctx->R10, ctx->Fp, ctx->Ip );
536
537     if (all_regs) dbg_printf( "Floating point ARM dump not implemented\n" );
538 }
539
540 static void be_arm_print_segment_info(HANDLE hThread, const CONTEXT* ctx)
541 {
542 }
543
544 static struct dbg_internal_var be_arm_ctx[] =
545 {
546     {CV_ARM_R0 +  0,    "r0",           (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R0),     dbg_itype_unsigned_int},
547     {CV_ARM_R0 +  1,    "r1",           (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R1),     dbg_itype_unsigned_int},
548     {CV_ARM_R0 +  2,    "r2",           (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R2),     dbg_itype_unsigned_int},
549     {CV_ARM_R0 +  3,    "r3",           (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R3),     dbg_itype_unsigned_int},
550     {CV_ARM_R0 +  4,    "r4",           (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R4),     dbg_itype_unsigned_int},
551     {CV_ARM_R0 +  5,    "r5",           (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R5),     dbg_itype_unsigned_int},
552     {CV_ARM_R0 +  6,    "r6",           (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R6),     dbg_itype_unsigned_int},
553     {CV_ARM_R0 +  7,    "r7",           (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R7),     dbg_itype_unsigned_int},
554     {CV_ARM_R0 +  8,    "r8",           (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R8),     dbg_itype_unsigned_int},
555     {CV_ARM_R0 +  9,    "r9",           (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R9),     dbg_itype_unsigned_int},
556     {CV_ARM_R0 +  10,   "r10",          (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R10),    dbg_itype_unsigned_int},
557     {CV_ARM_R0 +  11,   "r11",          (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Fp),     dbg_itype_unsigned_int},
558     {CV_ARM_R0 +  12,   "r12",          (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Ip),     dbg_itype_unsigned_int},
559     {CV_ARM_SP,         "sp",           (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Sp),     dbg_itype_unsigned_int},
560     {CV_ARM_LR,         "lr",           (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Lr),     dbg_itype_unsigned_int},
561     {CV_ARM_PC,         "pc",           (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Pc),     dbg_itype_unsigned_int},
562     {CV_ARM_CPSR,       "cpsr",         (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Cpsr),   dbg_itype_unsigned_int},
563     {0,                 NULL,           0,                                         dbg_itype_none}
564 };
565
566 static unsigned be_arm_is_step_over_insn(const void* insn)
567 {
568     dbg_printf("be_arm_is_step_over_insn: not done\n");
569     return FALSE;
570 }
571
572 static unsigned be_arm_is_function_return(const void* insn)
573 {
574     dbg_printf("be_arm_is_function_return: not done\n");
575     return FALSE;
576 }
577
578 static unsigned be_arm_is_break_insn(const void* insn)
579 {
580     dbg_printf("be_arm_is_break_insn: not done\n");
581     return FALSE;
582 }
583
584 static unsigned be_arm_is_func_call(const void* insn, ADDRESS64* callee)
585 {
586     return FALSE;
587 }
588
589 static unsigned be_arm_is_jump(const void* insn, ADDRESS64* jumpee)
590 {
591     return FALSE;
592 }
593
594 static unsigned be_arm_insert_Xpoint(HANDLE hProcess, const struct be_process_io* pio,
595                                      CONTEXT* ctx, enum be_xpoint_type type,
596                                      void* addr, unsigned long* val, unsigned size)
597 {
598     SIZE_T              sz;
599
600     switch (type)
601     {
602     case be_xpoint_break:
603         if (!size) return 0;
604         if (!pio->read(hProcess, addr, val, 4, &sz) || sz != 4) return 0;
605     default:
606         dbg_printf("Unknown/unsupported bp type %c\n", type);
607         return 0;
608     }
609     return 1;
610 }
611
612 static unsigned be_arm_remove_Xpoint(HANDLE hProcess, const struct be_process_io* pio,
613                                      CONTEXT* ctx, enum be_xpoint_type type,
614                                      void* addr, unsigned long val, unsigned size)
615 {
616     SIZE_T              sz;
617
618     switch (type)
619     {
620     case be_xpoint_break:
621         if (!size) return 0;
622         if (!pio->write(hProcess, addr, &val, 4, &sz) || sz == 4) return 0;
623         break;
624     default:
625         dbg_printf("Unknown/unsupported bp type %c\n", type);
626         return 0;
627     }
628     return 1;
629 }
630
631 static unsigned be_arm_is_watchpoint_set(const CONTEXT* ctx, unsigned idx)
632 {
633     dbg_printf("be_arm_is_watchpoint_set: not done\n");
634     return FALSE;
635 }
636
637 static void be_arm_clear_watchpoint(CONTEXT* ctx, unsigned idx)
638 {
639     dbg_printf("be_arm_clear_watchpoint: not done\n");
640 }
641
642 static int be_arm_adjust_pc_for_break(CONTEXT* ctx, BOOL way)
643 {
644     INT step = (ctx->Cpsr & 0x20) ? 2 : 4;
645
646     if (way)
647     {
648         ctx->Pc -= step;
649         return -step;
650     }
651     ctx->Pc += step;
652     return step;
653 }
654
655 static int be_arm_fetch_integer(const struct dbg_lvalue* lvalue, unsigned size,
656                                 unsigned ext_sign, LONGLONG* ret)
657 {
658     if (size != 1 && size != 2 && size != 4 && size != 8) return FALSE;
659
660     memset(ret, 0, sizeof(*ret)); /* clear unread bytes */
661     /* FIXME: this assumes that debuggee and debugger use the same
662      * integral representation
663      */
664     if (!memory_read_value(lvalue, size, ret)) return FALSE;
665
666     /* propagate sign information */
667     if (ext_sign && size < 8 && (*ret >> (size * 8 - 1)) != 0)
668     {
669         ULONGLONG neg = -1;
670         *ret |= neg << (size * 8);
671     }
672     return TRUE;
673 }
674
675 static int be_arm_fetch_float(const struct dbg_lvalue* lvalue, unsigned size,
676                               long double* ret)
677 {
678     char        tmp[sizeof(long double)];
679
680     /* FIXME: this assumes that debuggee and debugger use the same
681      * representation for reals
682      */
683     if (!memory_read_value(lvalue, size, tmp)) return FALSE;
684
685     switch (size)
686     {
687     case sizeof(float):         *ret = *(float*)tmp;            break;
688     case sizeof(double):        *ret = *(double*)tmp;           break;
689     default:                    return FALSE;
690     }
691     return TRUE;
692 }
693
694 static int be_arm_store_integer(const struct dbg_lvalue* lvalue, unsigned size,
695                                 unsigned is_signed, LONGLONG val)
696 {
697     /* this is simple if we're on a little endian CPU */
698     return memory_write_value(lvalue, size, &val);
699 }
700
701 struct backend_cpu be_arm =
702 {
703     IMAGE_FILE_MACHINE_ARMV7,
704     4,
705     be_cpu_linearize,
706     be_cpu_build_addr,
707     be_arm_get_addr,
708     be_arm_get_register_info,
709     be_arm_single_step,
710     be_arm_print_context,
711     be_arm_print_segment_info,
712     be_arm_ctx,
713     be_arm_is_step_over_insn,
714     be_arm_is_function_return,
715     be_arm_is_break_insn,
716     be_arm_is_func_call,
717     be_arm_is_jump,
718     be_arm_disasm_one_insn,
719     be_arm_insert_Xpoint,
720     be_arm_remove_Xpoint,
721     be_arm_is_watchpoint_set,
722     be_arm_clear_watchpoint,
723     be_arm_adjust_pc_for_break,
724     be_arm_fetch_integer,
725     be_arm_fetch_float,
726     be_arm_store_integer,
727 };
728 #endif