winedbg: Print all available information about branch targets in ARM disassembler.
[wine/multimedia.git] / programs / winedbg / be_arm.c
blob7da28b67dae114c49716f55402e3ee100d61d929
1 /*
2 * Debugger ARM specific functions
4 * Copyright 2000-2003 Marcus Meissner
5 * 2004 Eric Pouech
6 * 2010-2012 André Hentschel
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.
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.
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
23 #include "debugger.h"
25 #if defined(__arm__) && !defined(__ARMEB__)
28 * Switch to disassemble Thumb code.
30 static BOOL db_disasm_thumb = FALSE;
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.
37 static BOOL db_display = FALSE;
39 #define ARM_INSN_SIZE 4
40 #define THUMB_INSN_SIZE 2
42 #define ROR32(n, r) (((n) >> (r)) | ((n) << (32 - (r))))
44 #define get_cond(ins) tbl_cond[(ins >> 28) & 0x0f]
45 #define get_nibble(ins, num) ((ins >> (num * 4)) & 0x0f)
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"
52 static char const tbl_addrmode[][3] = {
53 "da", "ia", "db", "ib"
56 static char const tbl_cond[][3] = {
57 "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", "hi", "ls", "ge", "lt", "gt", "le", "", ""
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"
65 static char const tbl_shifts[][4] = {
66 "lsl", "lsr", "asr", "ror"
69 static char const tbl_hiops_t[][4] = {
70 "add", "cmp", "mov", "bx"
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"
78 static char const tbl_immops_t[][4] = {
79 "mov", "cmp", "add", "sub"
82 static UINT db_get_inst(void* addr, int size)
84 UINT result = 0;
85 char buffer[4];
87 if (dbg_read_memory(addr, buffer, size))
89 switch (size)
91 case 4:
92 result = *(UINT*)buffer;
93 break;
94 case 2:
95 result = *(WORD*)buffer;
96 break;
99 return result;
102 static void db_printsym(unsigned int addr)
104 ADDRESS64 a;
106 a.Mode = AddrModeFlat;
107 a.Offset = addr;
109 print_address(&a, TRUE);
112 static UINT arm_disasm_branch(UINT inst, ADDRESS64 *addr)
114 short link = (inst >> 24) & 0x01;
115 int offset = (inst << 2) & 0x03ffffff;
117 if (offset & 0x02000000) offset |= 0xfc000000;
118 offset += 8;
120 dbg_printf("\n\tb%s%s\t", link ? "l" : "", get_cond(inst));
121 db_printsym(addr->Offset + offset);
122 return 0;
125 static UINT arm_disasm_branchreg(UINT inst, ADDRESS64 *addr)
127 dbg_printf("\n\tb%s\t%s", get_cond(inst), tbl_regs[get_nibble(inst, 0)]);
128 return 0;
131 static UINT arm_disasm_dataprocessing(UINT inst, ADDRESS64 *addr)
133 short condcodes = (inst >> 20) & 0x01;
134 short opcode = (inst >> 21) & 0x0f;
135 short immediate = (inst >> 25) & 0x01;
136 short no_op1 = (opcode & 0x0d) == 0x0d;
137 short no_dst = (opcode & 0x0c) == 0x08;
139 /* check for nop */
140 if (get_nibble(inst, 3) == 15 /* r15 */ && condcodes == 0 &&
141 opcode >= 8 /* tst */ && opcode <= 11 /* cmn */)
143 dbg_printf("\n\tnop");
144 return 0;
147 dbg_printf("\n\t%s%s%s", tbl_dataops[opcode], condcodes ? "s" : "", get_cond(inst));
148 if (!no_dst) dbg_printf("\t%s, ", tbl_regs[get_nibble(inst, 3)]);
149 else dbg_printf("\t");
151 if (no_op1)
153 if (immediate)
154 dbg_printf("#%u", ROR32(inst & 0xff, 2 * get_nibble(inst, 2)));
155 else
156 dbg_printf("%s", tbl_regs[get_nibble(inst, 0)]);
158 else
160 if (immediate)
161 dbg_printf("%s, #%u", tbl_regs[get_nibble(inst, 4)],
162 ROR32(inst & 0xff, 2 * get_nibble(inst, 2)));
163 else if (((inst >> 4) & 0xff) == 0x00) /* no shift */
164 dbg_printf("%s, %s", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
165 else if (((inst >> 4) & 0x09) == 0x01) /* register shift */
166 dbg_printf("%s, %s, %s %s", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)],
167 tbl_shifts[(inst >> 5) & 0x03], tbl_regs[(inst >> 8) & 0x0f]);
168 else if (((inst >> 4) & 0x01) == 0x00) /* immediate shift */
169 dbg_printf("%s, %s, %s #%d", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)],
170 tbl_shifts[(inst >> 5) & 0x03], (inst >> 7) & 0x1f);
171 else
172 return inst;
174 return 0;
177 static UINT arm_disasm_singletrans(UINT inst, ADDRESS64 *addr)
179 short load = (inst >> 20) & 0x01;
180 short writeback = (inst >> 21) & 0x01;
181 short byte = (inst >> 22) & 0x01;
182 short direction = (inst >> 23) & 0x01;
183 short indexing = (inst >> 24) & 0x01;
184 short immediate = !((inst >> 25) & 0x01);
185 short offset = inst & 0x0fff;
187 if (!direction) offset *= -1;
189 dbg_printf("\n\t%s%s%s%s", load ? "ldr" : "str", byte ? "b" : "", writeback ? "t" : "",
190 get_cond(inst));
191 dbg_printf("\t%s, ", tbl_regs[get_nibble(inst, 3)]);
192 if (indexing)
194 if (immediate)
195 dbg_printf("[%s, #%d]", tbl_regs[get_nibble(inst, 4)], offset);
196 else if (((inst >> 4) & 0xff) == 0x00) /* no shift */
197 dbg_printf("[%s, %s]", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
198 else if (((inst >> 4) & 0x01) == 0x00) /* immediate shift (there's no register shift) */
199 dbg_printf("[%s, %s, %s #%d]", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)],
200 tbl_shifts[(inst >> 5) & 0x03], (inst >> 7) & 0x1f);
201 else
202 return inst;
204 else
206 if (immediate)
207 dbg_printf("[%s], #%d", tbl_regs[get_nibble(inst, 4)], offset);
208 else if (((inst >> 4) & 0xff) == 0x00) /* no shift */
209 dbg_printf("[%s], %s", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
210 else if (((inst >> 4) & 0x01) == 0x00) /* immediate shift (there's no register shift) */
211 dbg_printf("[%s], %s, %s #%d", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)],
212 tbl_shifts[(inst >> 5) & 0x03], (inst >> 7) & 0x1f);
213 else
214 return inst;
216 return 0;
219 static UINT arm_disasm_halfwordtrans(UINT inst, ADDRESS64 *addr)
221 short halfword = (inst >> 5) & 0x01;
222 short sign = (inst >> 6) & 0x01;
223 short load = (inst >> 20) & 0x01;
224 short writeback = (inst >> 21) & 0x01;
225 short immediate = (inst >> 22) & 0x01;
226 short direction = (inst >> 23) & 0x01;
227 short indexing = (inst >> 24) & 0x01;
228 short offset = ((inst >> 4) & 0xf0) + (inst & 0x0f);
230 if (!direction) offset *= -1;
232 dbg_printf("\n\t%s%s%s%s%s", load ? "ldr" : "str", sign ? "s" : "",
233 halfword ? "h" : (sign ? "b" : ""), writeback ? "t" : "", get_cond(inst));
234 dbg_printf("\t%s, ", tbl_regs[get_nibble(inst, 3)]);
235 if (indexing)
237 if (immediate)
238 dbg_printf("[%s, #%d]", tbl_regs[get_nibble(inst, 4)], offset);
239 else
240 dbg_printf("[%s, %s]", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
242 else
244 if (immediate)
245 dbg_printf("[%s], #%d", tbl_regs[get_nibble(inst, 4)], offset);
246 else
247 dbg_printf("[%s], %s", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
249 return 0;
252 static UINT arm_disasm_blocktrans(UINT inst, ADDRESS64 *addr)
254 short load = (inst >> 20) & 0x01;
255 short writeback = (inst >> 21) & 0x01;
256 short psr = (inst >> 22) & 0x01;
257 short addrmode = (inst >> 23) & 0x03;
258 short i;
259 short last=15;
260 for (i=15;i>=0;i--)
261 if ((inst>>i) & 1)
263 last = i;
264 break;
267 dbg_printf("\n\t%s%s%s\t%s%s, {", load ? "ldm" : "stm", tbl_addrmode[addrmode], get_cond(inst),
268 tbl_regs[get_nibble(inst, 4)], writeback ? "!" : "");
269 for (i=0;i<=15;i++)
270 if ((inst>>i) & 1)
272 if (i == last) dbg_printf("%s", tbl_regs[i]);
273 else dbg_printf("%s, ", tbl_regs[i]);
275 dbg_printf("}%s", psr ? "^" : "");
276 return 0;
279 static UINT arm_disasm_swi(UINT inst, ADDRESS64 *addr)
281 UINT comment = inst & 0x00ffffff;
282 dbg_printf("\n\tswi%s\t#%d", get_cond(inst), comment);
283 return 0;
286 static UINT arm_disasm_coproctrans(UINT inst, ADDRESS64 *addr)
288 WORD CRm = inst & 0x0f;
289 WORD CP = (inst >> 5) & 0x07;
290 WORD CPnum = (inst >> 8) & 0x0f;
291 WORD CRn = (inst >> 16) & 0x0f;
292 WORD load = (inst >> 20) & 0x01;
293 WORD CP_Opc = (inst >> 21) & 0x07;
295 dbg_printf("\n\t%s%s\t%u, %u, %s, cr%u, cr%u, {%u}", load ? "mrc" : "mcr", get_cond(inst), CPnum,
296 CP, tbl_regs[get_nibble(inst, 3)], CRn, CRm, CP_Opc);
297 return 0;
300 static UINT arm_disasm_coprocdataop(UINT inst, ADDRESS64 *addr)
302 WORD CRm = inst & 0x0f;
303 WORD CP = (inst >> 5) & 0x07;
304 WORD CPnum = (inst >> 8) & 0x0f;
305 WORD CRd = (inst >> 12) & 0x0f;
306 WORD CRn = (inst >> 16) & 0x0f;
307 WORD CP_Opc = (inst >> 20) & 0x0f;
309 dbg_printf("\n\tcdp%s\t%u, %u, cr%u, cr%u, cr%u, {%u}", get_cond(inst),
310 CPnum, CP, CRd, CRn, CRm, CP_Opc);
311 return 0;
314 static UINT arm_disasm_coprocdatatrans(UINT inst, ADDRESS64 *addr)
316 WORD CPnum = (inst >> 8) & 0x0f;
317 WORD CRd = (inst >> 12) & 0x0f;
318 WORD load = (inst >> 20) & 0x01;
319 WORD writeback = (inst >> 21) & 0x01;
320 WORD translen = (inst >> 22) & 0x01;
321 WORD direction = (inst >> 23) & 0x01;
322 WORD indexing = (inst >> 24) & 0x01;
323 short offset = (inst & 0xff) << 2;
325 if (!direction) offset *= -1;
327 dbg_printf("\n\t%s%s%s", load ? "ldc" : "stc", translen ? "l" : "", get_cond(inst));
328 if (indexing)
329 dbg_printf("\t%u, cr%u, [%s, #%d]%s", CPnum, CRd, tbl_regs[get_nibble(inst, 4)], offset, writeback?"!":"");
330 else
331 dbg_printf("\t%u, cr%u, [%s], #%d", CPnum, CRd, tbl_regs[get_nibble(inst, 4)], offset);
332 return 0;
335 static WORD thumb_disasm_hireg(WORD inst, ADDRESS64 *addr)
337 short dst = inst & 0x07;
338 short src = (inst >> 3) & 0x07;
339 short h2 = (inst >> 6) & 0x01;
340 short h1 = (inst >> 7) & 0x01;
341 short op = (inst >> 8) & 0x03;
343 if (h1) dst += 8;
344 if (h2) src += 8;
346 if (op == 2 && dst == src) /* mov rx, rx */
348 dbg_printf("\n\tnop");
349 return 0;
352 if (op == 3)
353 dbg_printf("\n\tb%sx\t%s", h1?"l":"", tbl_regs[src]);
354 else
355 dbg_printf("\n\t%s\t%s, %s", tbl_hiops_t[op], tbl_regs[dst], tbl_regs[src]);
357 return 0;
360 static WORD thumb_disasm_aluop(WORD inst, ADDRESS64 *addr)
362 short dst = inst & 0x07;
363 short src = (inst >> 3) & 0x07;
364 short op = (inst >> 6) & 0x0f;
366 dbg_printf("\n\t%s\t%s, %s", tbl_aluops_t[op], tbl_regs[dst], tbl_regs[src]);
368 return 0;
371 static WORD thumb_disasm_blocktrans(WORD inst, ADDRESS64 *addr)
373 short lrpc = (inst >> 8) & 0x01;
374 short load = (inst >> 11) & 0x01;
375 short i;
376 short last;
378 for (i=7;i>=0;i--)
379 if ((inst>>i) & 1) break;
380 last = i;
382 dbg_printf("\n\t%s\t{", load ? "pop" : "push");
384 for (i=0;i<=7;i++)
385 if ((inst>>i) & 1)
387 if (i == last) dbg_printf("%s", tbl_regs[i]);
388 else dbg_printf("%s, ", tbl_regs[i]);
390 if (lrpc)
391 dbg_printf(", %s", load ? "pc" : "lr");
393 dbg_printf("}");
394 return 0;
397 static WORD thumb_disasm_longbl(WORD inst, ADDRESS64 *addr)
399 WORD inst2;
400 UINT offset = (inst & 0x07ff) << 12;
402 addr->Offset += 2;
403 inst2 = db_get_inst( memory_to_linear_addr(addr), 2 );
404 if (!((inst2 & 0xf800) == 0xf800)) return inst;
406 offset += (inst2 & 0x07ff) << 1;
407 dbg_printf("\n\tbl\t");
408 db_printsym(addr->Offset + offset);
409 return 0;
412 static WORD thumb_disasm_condbranch(WORD inst, ADDRESS64 *addr)
414 WORD offset = inst & 0x00ff;
415 dbg_printf("\n\tb%s\t", tbl_cond[(inst >> 8) & 0x0f]);
416 db_printsym(addr->Offset + offset);
417 return 0;
420 static WORD thumb_disasm_loadadr(WORD inst, ADDRESS64 *addr)
422 WORD src = (inst >> 11) & 0x01;
423 WORD offset = (inst & 0xff) << 2;
425 dbg_printf("\n\tadd\t%s, %s, #%d", tbl_regs[(inst >> 8) & 0x07], src ? "sp" : "pc", offset);
426 return 0;
429 static WORD thumb_disasm_swi(WORD inst, ADDRESS64 *addr)
431 WORD comment = inst & 0x00ff;
432 dbg_printf("\n\tswi\t#%d", comment);
433 return 0;
436 static WORD thumb_disasm_nop(WORD inst, ADDRESS64 *addr)
438 dbg_printf("\n\tnop");
439 return 0;
442 static WORD thumb_disasm_ldrpcrel(WORD inst, ADDRESS64 *addr)
444 WORD offset = (inst & 0xff) << 2;
445 dbg_printf("\n\tldr\t%s, [pc, #%u]", tbl_regs[(inst >> 8) & 0x07], offset);
446 return 0;
449 static WORD thumb_disasm_ldrsprel(WORD inst, ADDRESS64 *addr)
451 WORD offset = (inst & 0xff) << 2;
452 dbg_printf("\n\t%s\t%s, [sp, #%u]", (inst & 0x0800)?"ldr":"str", tbl_regs[(inst >> 8) & 0x07], offset);
453 return 0;
456 static WORD thumb_disasm_addsprel(WORD inst, ADDRESS64 *addr)
458 WORD offset = (inst & 0x7f) << 2;
459 if ((inst >> 7) & 0x01)
460 dbg_printf("\n\tsub\tsp, sp, #%u", offset);
461 else
462 dbg_printf("\n\tadd\tsp, sp, #%u", offset);
463 return 0;
466 static WORD thumb_disasm_ldrimm(WORD inst, ADDRESS64 *addr)
468 WORD offset = (inst & 0x07c0) >> 6;
469 dbg_printf("\n\t%s%s\t%s, [%s, #%u]", (inst & 0x0800)?"ldr":"str", (inst & 0x1000)?"b":"",
470 tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07], (inst & 0x1000)?offset:(offset << 2));
471 return 0;
474 static WORD thumb_disasm_immop(WORD inst, ADDRESS64 *addr)
476 WORD op = (inst >> 11) & 0x03;
477 dbg_printf("\n\t%s\t%s, #%u", tbl_immops_t[op], tbl_regs[(inst >> 8) & 0x07], inst & 0xff);
478 return 0;
481 static WORD thumb_disasm_addsub(WORD inst, ADDRESS64 *addr)
483 WORD op = (inst >> 9) & 0x01;
484 WORD immediate = (inst >> 10) & 0x01;
486 dbg_printf("\n\t%s\t%s, %s, ", op ? "sub" : "add",
487 tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07]);
488 if (immediate)
489 dbg_printf("#%d", (inst >> 6) & 0x07);
490 else
491 dbg_printf("%s", tbl_regs[(inst >> 6) & 0x07]);
492 return 0;
495 static WORD thumb_disasm_movshift(WORD inst, ADDRESS64 *addr)
497 WORD op = (inst >> 11) & 0x03;
498 dbg_printf("\n\t%s\t%s, %s, #%u", tbl_shifts[op],
499 tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07], (inst >> 6) & 0x1f);
500 return 0;
503 struct inst_arm
505 UINT mask;
506 UINT pattern;
507 UINT (*func)(UINT, ADDRESS64*);
510 static const struct inst_arm tbl_arm[] = {
511 { 0x0e000000, 0x0a000000, arm_disasm_branch },
512 { 0x0e000090, 0x00000090, arm_disasm_halfwordtrans },
513 { 0x0fffff00, 0x012fff00, arm_disasm_branchreg },
514 { 0x0c000000, 0x00000000, arm_disasm_dataprocessing },
515 { 0x0c000000, 0x04000000, arm_disasm_singletrans },
516 { 0x0e000000, 0x08000000, arm_disasm_blocktrans },
517 { 0x0f000000, 0x0f000000, arm_disasm_swi },
518 { 0x0f000010, 0x0e000010, arm_disasm_coproctrans },
519 { 0x0f000010, 0x0e000000, arm_disasm_coprocdataop },
520 { 0x0e000000, 0x0c000000, arm_disasm_coprocdatatrans },
521 { 0x00000000, 0x00000000, NULL }
524 struct inst_thumb16
526 WORD mask;
527 WORD pattern;
528 WORD (*func)(WORD, ADDRESS64*);
531 static const struct inst_thumb16 tbl_thumb16[] = {
532 { 0xfc00, 0x4400, thumb_disasm_hireg },
533 { 0xfc00, 0x4000, thumb_disasm_aluop },
534 { 0xf600, 0xb400, thumb_disasm_blocktrans },
535 { 0xf800, 0xf000, thumb_disasm_longbl },
536 { 0xf000, 0xd000, thumb_disasm_condbranch },
537 { 0xf000, 0xa000, thumb_disasm_loadadr },
538 { 0xf800, 0x4800, thumb_disasm_ldrpcrel },
539 { 0xf000, 0x9000, thumb_disasm_ldrsprel },
540 { 0xff00, 0xb000, thumb_disasm_addsprel },
541 { 0xe000, 0x6000, thumb_disasm_ldrimm },
542 { 0xe000, 0x2000, thumb_disasm_immop },
543 { 0xf000, 0xd000, thumb_disasm_condbranch },
544 { 0xff00, 0xdf00, thumb_disasm_swi },
545 { 0xff00, 0xbf00, thumb_disasm_nop },
546 { 0xf800, 0x1800, thumb_disasm_addsub },
547 { 0xe000, 0x0000, thumb_disasm_movshift },
548 { 0x0000, 0x0000, NULL }
551 /***********************************************************************
552 * disasm_one_insn
554 * Disassemble instruction at 'addr'. addr is changed to point to the
555 * start of the next instruction.
557 void be_arm_disasm_one_insn(ADDRESS64 *addr, int display)
559 struct inst_arm *a_ptr = (struct inst_arm *)&tbl_arm;
560 struct inst_thumb16 *t_ptr = (struct inst_thumb16 *)&tbl_thumb16;
561 UINT inst;
562 WORD tinst;
563 int size;
564 int matched = 0;
566 char tmp[64];
567 DWORD_PTR* pval;
569 if (!memory_get_register(CV_ARM_CPSR, &pval, tmp, sizeof(tmp)))
570 dbg_printf("\n\tmemory_get_register failed: %s", tmp);
571 else
572 db_disasm_thumb=(*pval & 0x20)?TRUE:FALSE;
574 if (db_disasm_thumb) size = THUMB_INSN_SIZE;
575 else size = ARM_INSN_SIZE;
577 db_display = display;
578 inst = db_get_inst( memory_to_linear_addr(addr), size );
580 if (!db_disasm_thumb)
582 while (a_ptr->func) {
583 if ((inst & a_ptr->mask) == a_ptr->pattern) {
584 matched = 1;
585 break;
587 a_ptr++;
590 if (!matched) {
591 dbg_printf("\n\tUnknown Instruction: %08x", inst);
592 addr->Offset += size;
593 return;
595 else
597 if (!a_ptr->func(inst, addr))
598 addr->Offset += size;
599 return;
602 else
604 tinst = inst;
605 while (t_ptr->func) {
606 if ((tinst & t_ptr->mask) == t_ptr->pattern) {
607 matched = 1;
608 break;
610 t_ptr++;
613 if (!matched) {
614 dbg_printf("\n\tUnknown Instruction: %04x", tinst);
615 addr->Offset += size;
616 return;
618 else
620 if (!t_ptr->func(tinst, addr))
621 addr->Offset += size;
623 return;
627 static unsigned be_arm_get_addr(HANDLE hThread, const CONTEXT* ctx,
628 enum be_cpu_addr bca, ADDRESS64* addr)
630 switch (bca)
632 case be_cpu_addr_pc:
633 return be_cpu_build_addr(hThread, ctx, addr, 0, ctx->Pc);
634 case be_cpu_addr_stack:
635 return be_cpu_build_addr(hThread, ctx, addr, 0, ctx->Sp);
636 case be_cpu_addr_frame:
637 return be_cpu_build_addr(hThread, ctx, addr, 0, ctx->Fp);
639 return FALSE;
642 static unsigned be_arm_get_register_info(int regno, enum be_cpu_addr* kind)
644 switch (regno)
646 case CV_ARM_PC: *kind = be_cpu_addr_pc; return TRUE;
647 case CV_ARM_R0 + 11: *kind = be_cpu_addr_frame; return TRUE;
648 case CV_ARM_SP: *kind = be_cpu_addr_stack; return TRUE;
650 return FALSE;
653 static void be_arm_single_step(CONTEXT* ctx, unsigned enable)
655 dbg_printf("be_arm_single_step: not done\n");
658 static void be_arm_print_context(HANDLE hThread, const CONTEXT* ctx, int all_regs)
660 static const char condflags[] = "NZCV";
661 int i;
662 char buf[8];
664 switch (ctx->Cpsr & 0x1F)
666 case 0: strcpy(buf, "User26"); break;
667 case 1: strcpy(buf, "FIQ26"); break;
668 case 2: strcpy(buf, "IRQ26"); break;
669 case 3: strcpy(buf, "SVC26"); break;
670 case 16: strcpy(buf, "User"); break;
671 case 17: strcpy(buf, "FIQ"); break;
672 case 18: strcpy(buf, "IRQ"); break;
673 case 19: strcpy(buf, "SVC"); break;
674 case 23: strcpy(buf, "ABT"); break;
675 case 27: strcpy(buf, "UND"); break;
676 default: strcpy(buf, "UNKNWN"); break;
679 dbg_printf("Register dump:\n");
680 dbg_printf("%s %s Mode\n", (ctx->Cpsr & 0x20) ? "Thumb" : "ARM", buf);
682 strcpy(buf, condflags);
683 for (i = 0; buf[i]; i++)
684 if (!((ctx->Cpsr >> 26) & (1 << (sizeof(condflags) - i))))
685 buf[i] = '-';
687 dbg_printf(" Pc:%04x Sp:%04x Lr:%04x Cpsr:%04x(%s)\n",
688 ctx->Pc, ctx->Sp, ctx->Lr, ctx->Cpsr, buf);
689 dbg_printf(" r0:%04x r1:%04x r2:%04x r3:%04x\n",
690 ctx->R0, ctx->R1, ctx->R2, ctx->R3);
691 dbg_printf(" r4:%04x r5:%04x r6:%04x r7:%04x r8:%04x\n",
692 ctx->R4, ctx->R5, ctx->R6, ctx->R7, ctx->R8 );
693 dbg_printf(" r9:%04x r10:%04x Fp:%04x Ip:%04x\n",
694 ctx->R9, ctx->R10, ctx->Fp, ctx->Ip );
696 if (all_regs) dbg_printf( "Floating point ARM dump not implemented\n" );
699 static void be_arm_print_segment_info(HANDLE hThread, const CONTEXT* ctx)
703 static struct dbg_internal_var be_arm_ctx[] =
705 {CV_ARM_R0 + 0, "r0", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R0), dbg_itype_unsigned_int},
706 {CV_ARM_R0 + 1, "r1", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R1), dbg_itype_unsigned_int},
707 {CV_ARM_R0 + 2, "r2", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R2), dbg_itype_unsigned_int},
708 {CV_ARM_R0 + 3, "r3", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R3), dbg_itype_unsigned_int},
709 {CV_ARM_R0 + 4, "r4", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R4), dbg_itype_unsigned_int},
710 {CV_ARM_R0 + 5, "r5", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R5), dbg_itype_unsigned_int},
711 {CV_ARM_R0 + 6, "r6", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R6), dbg_itype_unsigned_int},
712 {CV_ARM_R0 + 7, "r7", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R7), dbg_itype_unsigned_int},
713 {CV_ARM_R0 + 8, "r8", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R8), dbg_itype_unsigned_int},
714 {CV_ARM_R0 + 9, "r9", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R9), dbg_itype_unsigned_int},
715 {CV_ARM_R0 + 10, "r10", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R10), dbg_itype_unsigned_int},
716 {CV_ARM_R0 + 11, "r11", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Fp), dbg_itype_unsigned_int},
717 {CV_ARM_R0 + 12, "r12", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Ip), dbg_itype_unsigned_int},
718 {CV_ARM_SP, "sp", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Sp), dbg_itype_unsigned_int},
719 {CV_ARM_LR, "lr", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Lr), dbg_itype_unsigned_int},
720 {CV_ARM_PC, "pc", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Pc), dbg_itype_unsigned_int},
721 {CV_ARM_CPSR, "cpsr", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Cpsr), dbg_itype_unsigned_int},
722 {0, NULL, 0, dbg_itype_none}
725 static unsigned be_arm_is_step_over_insn(const void* insn)
727 dbg_printf("be_arm_is_step_over_insn: not done\n");
728 return FALSE;
731 static unsigned be_arm_is_function_return(const void* insn)
733 dbg_printf("be_arm_is_function_return: not done\n");
734 return FALSE;
737 static unsigned be_arm_is_break_insn(const void* insn)
739 dbg_printf("be_arm_is_break_insn: not done\n");
740 return FALSE;
743 static unsigned be_arm_is_func_call(const void* insn, ADDRESS64* callee)
745 return FALSE;
748 static unsigned be_arm_is_jump(const void* insn, ADDRESS64* jumpee)
750 return FALSE;
753 static unsigned be_arm_insert_Xpoint(HANDLE hProcess, const struct be_process_io* pio,
754 CONTEXT* ctx, enum be_xpoint_type type,
755 void* addr, unsigned long* val, unsigned size)
757 SIZE_T sz;
759 switch (type)
761 case be_xpoint_break:
762 if (!size) return 0;
763 if (!pio->read(hProcess, addr, val, 4, &sz) || sz != 4) return 0;
764 default:
765 dbg_printf("Unknown/unsupported bp type %c\n", type);
766 return 0;
768 return 1;
771 static unsigned be_arm_remove_Xpoint(HANDLE hProcess, const struct be_process_io* pio,
772 CONTEXT* ctx, enum be_xpoint_type type,
773 void* addr, unsigned long val, unsigned size)
775 SIZE_T sz;
777 switch (type)
779 case be_xpoint_break:
780 if (!size) return 0;
781 if (!pio->write(hProcess, addr, &val, 4, &sz) || sz == 4) return 0;
782 break;
783 default:
784 dbg_printf("Unknown/unsupported bp type %c\n", type);
785 return 0;
787 return 1;
790 static unsigned be_arm_is_watchpoint_set(const CONTEXT* ctx, unsigned idx)
792 dbg_printf("be_arm_is_watchpoint_set: not done\n");
793 return FALSE;
796 static void be_arm_clear_watchpoint(CONTEXT* ctx, unsigned idx)
798 dbg_printf("be_arm_clear_watchpoint: not done\n");
801 static int be_arm_adjust_pc_for_break(CONTEXT* ctx, BOOL way)
803 INT step = (ctx->Cpsr & 0x20) ? 2 : 4;
805 if (way)
807 ctx->Pc -= step;
808 return -step;
810 ctx->Pc += step;
811 return step;
814 static int be_arm_fetch_integer(const struct dbg_lvalue* lvalue, unsigned size,
815 unsigned ext_sign, LONGLONG* ret)
817 if (size != 1 && size != 2 && size != 4 && size != 8) return FALSE;
819 memset(ret, 0, sizeof(*ret)); /* clear unread bytes */
820 /* FIXME: this assumes that debuggee and debugger use the same
821 * integral representation
823 if (!memory_read_value(lvalue, size, ret)) return FALSE;
825 /* propagate sign information */
826 if (ext_sign && size < 8 && (*ret >> (size * 8 - 1)) != 0)
828 ULONGLONG neg = -1;
829 *ret |= neg << (size * 8);
831 return TRUE;
834 static int be_arm_fetch_float(const struct dbg_lvalue* lvalue, unsigned size,
835 long double* ret)
837 char tmp[sizeof(long double)];
839 /* FIXME: this assumes that debuggee and debugger use the same
840 * representation for reals
842 if (!memory_read_value(lvalue, size, tmp)) return FALSE;
844 switch (size)
846 case sizeof(float): *ret = *(float*)tmp; break;
847 case sizeof(double): *ret = *(double*)tmp; break;
848 default: return FALSE;
850 return TRUE;
853 static int be_arm_store_integer(const struct dbg_lvalue* lvalue, unsigned size,
854 unsigned is_signed, LONGLONG val)
856 /* this is simple if we're on a little endian CPU */
857 return memory_write_value(lvalue, size, &val);
860 struct backend_cpu be_arm =
862 IMAGE_FILE_MACHINE_ARMV7,
864 be_cpu_linearize,
865 be_cpu_build_addr,
866 be_arm_get_addr,
867 be_arm_get_register_info,
868 be_arm_single_step,
869 be_arm_print_context,
870 be_arm_print_segment_info,
871 be_arm_ctx,
872 be_arm_is_step_over_insn,
873 be_arm_is_function_return,
874 be_arm_is_break_insn,
875 be_arm_is_func_call,
876 be_arm_is_jump,
877 be_arm_disasm_one_insn,
878 be_arm_insert_Xpoint,
879 be_arm_remove_Xpoint,
880 be_arm_is_watchpoint_set,
881 be_arm_clear_watchpoint,
882 be_arm_adjust_pc_for_break,
883 be_arm_fetch_integer,
884 be_arm_fetch_float,
885 be_arm_store_integer,
887 #endif