2 * Debugger ARM specific functions
4 * Copyright 2000-2003 Marcus Meissner
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
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
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",
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",
78 static char const tbl_immops_t[][4] = {
79 "mov", "cmp", "add", "sub"
82 static char const tbl_sregops_t[][5] = {
83 "strh", "ldsb", "ldrh", "ldsh"
86 static UINT db_get_inst(void* addr, int size)
91 if (dbg_read_memory(addr, buffer, size))
96 result = *(UINT*)buffer;
99 result = *(WORD*)buffer;
106 static void db_printsym(unsigned int addr)
110 a.Mode = AddrModeFlat;
113 print_address(&a, TRUE);
116 static UINT arm_disasm_branch(UINT inst, ADDRESS64 *addr)
118 short link = (inst >> 24) & 0x01;
119 int offset = (inst << 2) & 0x03ffffff;
121 if (offset & 0x02000000) offset |= 0xfc000000;
124 dbg_printf("\n\tb%s%s\t", link ? "l" : "", get_cond(inst));
125 db_printsym(addr->Offset + offset);
129 static UINT arm_disasm_branchreg(UINT inst, ADDRESS64 *addr)
131 dbg_printf("\n\tb%s\t%s", get_cond(inst), tbl_regs[get_nibble(inst, 0)]);
135 static UINT arm_disasm_dataprocessing(UINT inst, ADDRESS64 *addr)
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;
144 if (get_nibble(inst, 3) == 15 /* r15 */ && condcodes == 0 &&
145 opcode >= 8 /* tst */ && opcode <= 11 /* cmn */)
147 dbg_printf("\n\tnop");
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");
158 dbg_printf("#%u", ROR32(inst & 0xff, 2 * get_nibble(inst, 2)));
160 dbg_printf("%s", tbl_regs[get_nibble(inst, 0)]);
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);
181 static UINT arm_disasm_singletrans(UINT inst, ADDRESS64 *addr)
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;
191 if (!direction) offset *= -1;
193 dbg_printf("\n\t%s%s%s%s", load ? "ldr" : "str", byte ? "b" : "", writeback ? "t" : "",
195 dbg_printf("\t%s, ", tbl_regs[get_nibble(inst, 3)]);
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);
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);
223 static UINT arm_disasm_halfwordtrans(UINT inst, ADDRESS64 *addr)
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);
234 if (!direction) offset *= -1;
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)]);
242 dbg_printf("[%s, #%d]", tbl_regs[get_nibble(inst, 4)], offset);
244 dbg_printf("[%s, %s]", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
249 dbg_printf("[%s], #%d", tbl_regs[get_nibble(inst, 4)], offset);
251 dbg_printf("[%s], %s", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
256 static UINT arm_disasm_blocktrans(UINT inst, ADDRESS64 *addr)
258 short load = (inst >> 20) & 0x01;
259 short writeback = (inst >> 21) & 0x01;
260 short psr = (inst >> 22) & 0x01;
261 short addrmode = (inst >> 23) & 0x03;
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 ? "!" : "");
276 if (i == last) dbg_printf("%s", tbl_regs[i]);
277 else dbg_printf("%s, ", tbl_regs[i]);
279 dbg_printf("}%s", psr ? "^" : "");
283 static UINT arm_disasm_swi(UINT inst, ADDRESS64 *addr)
285 UINT comment = inst & 0x00ffffff;
286 dbg_printf("\n\tswi%s\t#%d", get_cond(inst), comment);
290 static UINT arm_disasm_coproctrans(UINT inst, ADDRESS64 *addr)
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;
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);
304 static UINT arm_disasm_coprocdataop(UINT inst, ADDRESS64 *addr)
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;
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);
318 static UINT arm_disasm_coprocdatatrans(UINT inst, ADDRESS64 *addr)
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;
329 if (!direction) offset *= -1;
331 dbg_printf("\n\t%s%s%s", load ? "ldc" : "stc", translen ? "l" : "", get_cond(inst));
333 dbg_printf("\t%u, cr%u, [%s, #%d]%s", CPnum, CRd, tbl_regs[get_nibble(inst, 4)], offset, writeback?"!":"");
335 dbg_printf("\t%u, cr%u, [%s], #%d", CPnum, CRd, tbl_regs[get_nibble(inst, 4)], offset);
339 static WORD thumb_disasm_hireg(WORD inst, ADDRESS64 *addr)
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;
350 if (op == 2 && dst == src) /* mov rx, rx */
352 dbg_printf("\n\tnop");
357 dbg_printf("\n\tb%sx\t%s", h1?"l":"", tbl_regs[src]);
359 dbg_printf("\n\t%s\t%s, %s", tbl_hiops_t[op], tbl_regs[dst], tbl_regs[src]);
364 static WORD thumb_disasm_aluop(WORD inst, ADDRESS64 *addr)
366 short dst = inst & 0x07;
367 short src = (inst >> 3) & 0x07;
368 short op = (inst >> 6) & 0x0f;
370 dbg_printf("\n\t%s\t%s, %s", tbl_aluops_t[op], tbl_regs[dst], tbl_regs[src]);
375 static WORD thumb_disasm_pushpop(WORD inst, ADDRESS64 *addr)
377 short lrpc = (inst >> 8) & 0x01;
378 short load = (inst >> 11) & 0x01;
383 if ((inst>>i) & 1) break;
386 dbg_printf("\n\t%s\t{", load ? "pop" : "push");
391 if (i == last) dbg_printf("%s", tbl_regs[i]);
392 else dbg_printf("%s, ", tbl_regs[i]);
395 dbg_printf("%s%s", last ? ", " : "", load ? "pc" : "lr");
401 static WORD thumb_disasm_blocktrans(WORD inst, ADDRESS64 *addr)
403 short load = (inst >> 11) & 0x01;
408 if ((inst>>i) & 1) break;
411 dbg_printf("\n\t%s\t%s!, {", load ? "ldmia" : "stmia", tbl_regs[(inst >> 8) & 0x07]);
416 if (i == last) dbg_printf("%s", tbl_regs[i]);
417 else dbg_printf("%s, ", tbl_regs[i]);
424 static WORD thumb_disasm_longbl(WORD inst, ADDRESS64 *addr)
427 UINT offset = (inst & 0x07ff) << 12;
430 inst2 = db_get_inst( memory_to_linear_addr(addr), 2 );
431 if (!((inst2 & 0xf800) == 0xf800)) return inst;
433 offset += (inst2 & 0x07ff) << 1;
434 dbg_printf("\n\tbl\t");
435 db_printsym(addr->Offset + offset);
439 static WORD thumb_disasm_condbranch(WORD inst, ADDRESS64 *addr)
441 WORD offset = inst & 0x00ff;
442 dbg_printf("\n\tb%s\t", tbl_cond[(inst >> 8) & 0x0f]);
443 db_printsym(addr->Offset + offset);
447 static WORD thumb_disasm_uncondbranch(WORD inst, ADDRESS64 *addr)
449 short offset = (inst & 0x07ff) << 1;
451 if (offset & 0x0800) offset |= 0xf000;
454 dbg_printf("\n\tb\t");
455 db_printsym(addr->Offset + offset);
459 static WORD thumb_disasm_loadadr(WORD inst, ADDRESS64 *addr)
461 WORD src = (inst >> 11) & 0x01;
462 WORD offset = (inst & 0xff) << 2;
464 dbg_printf("\n\tadd\t%s, %s, #%d", tbl_regs[(inst >> 8) & 0x07], src ? "sp" : "pc", offset);
468 static WORD thumb_disasm_swi(WORD inst, ADDRESS64 *addr)
470 WORD comment = inst & 0x00ff;
471 dbg_printf("\n\tswi\t#%d", comment);
475 static WORD thumb_disasm_nop(WORD inst, ADDRESS64 *addr)
477 dbg_printf("\n\tnop");
481 static WORD thumb_disasm_ldrpcrel(WORD inst, ADDRESS64 *addr)
483 WORD offset = (inst & 0xff) << 2;
484 dbg_printf("\n\tldr\t%s, [pc, #%u]", tbl_regs[(inst >> 8) & 0x07], offset);
488 static WORD thumb_disasm_ldrsprel(WORD inst, ADDRESS64 *addr)
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);
495 static WORD thumb_disasm_addsprel(WORD inst, ADDRESS64 *addr)
497 WORD offset = (inst & 0x7f) << 2;
498 if ((inst >> 7) & 0x01)
499 dbg_printf("\n\tsub\tsp, sp, #%u", offset);
501 dbg_printf("\n\tadd\tsp, sp, #%u", offset);
505 static WORD thumb_disasm_ldrimm(WORD inst, ADDRESS64 *addr)
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));
513 static WORD thumb_disasm_ldrhimm(WORD inst, ADDRESS64 *addr)
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);
521 static WORD thumb_disasm_ldrreg(WORD inst, ADDRESS64 *addr)
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]);
528 static WORD thumb_disasm_ldrsreg(WORD inst, ADDRESS64 *addr)
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]);
535 static WORD thumb_disasm_immop(WORD inst, ADDRESS64 *addr)
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);
542 static WORD thumb_disasm_addsub(WORD inst, ADDRESS64 *addr)
544 WORD op = (inst >> 9) & 0x01;
545 WORD immediate = (inst >> 10) & 0x01;
547 dbg_printf("\n\t%s\t%s, %s, ", op ? "sub" : "add",
548 tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07]);
550 dbg_printf("#%d", (inst >> 6) & 0x07);
552 dbg_printf("%s", tbl_regs[(inst >> 6) & 0x07]);
556 static WORD thumb_disasm_movshift(WORD inst, ADDRESS64 *addr)
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);
568 UINT (*func)(UINT, ADDRESS64*);
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 }
589 WORD (*func)(WORD, ADDRESS64*);
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 }
616 /***********************************************************************
619 * Disassemble instruction at 'addr'. addr is changed to point to the
620 * start of the next instruction.
622 void be_arm_disasm_one_insn(ADDRESS64 *addr, int display)
624 struct inst_arm *a_ptr = (struct inst_arm *)&tbl_arm;
625 struct inst_thumb16 *t_ptr = (struct inst_thumb16 *)&tbl_thumb16;
634 if (!memory_get_register(CV_ARM_CPSR, &pval, tmp, sizeof(tmp)))
635 dbg_printf("\n\tmemory_get_register failed: %s", tmp);
637 db_disasm_thumb=(*pval & 0x20)?TRUE:FALSE;
639 if (db_disasm_thumb) size = THUMB_INSN_SIZE;
640 else size = ARM_INSN_SIZE;
642 db_display = display;
643 inst = db_get_inst( memory_to_linear_addr(addr), size );
645 if (!db_disasm_thumb)
647 while (a_ptr->func) {
648 if ((inst & a_ptr->mask) == a_ptr->pattern) {
656 dbg_printf("\n\tUnknown Instruction: %08x", inst);
657 addr->Offset += size;
662 if (!a_ptr->func(inst, addr))
663 addr->Offset += size;
670 while (t_ptr->func) {
671 if ((tinst & t_ptr->mask) == t_ptr->pattern) {
679 dbg_printf("\n\tUnknown Instruction: %04x", tinst);
680 addr->Offset += size;
685 if (!t_ptr->func(tinst, addr))
686 addr->Offset += size;
692 static unsigned be_arm_get_addr(HANDLE hThread, const CONTEXT* ctx,
693 enum be_cpu_addr bca, ADDRESS64* addr)
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);
707 static unsigned be_arm_get_register_info(int regno, enum be_cpu_addr* kind)
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;
718 static void be_arm_single_step(CONTEXT* ctx, unsigned enable)
720 dbg_printf("be_arm_single_step: not done\n");
723 static void be_arm_print_context(HANDLE hThread, const CONTEXT* ctx, int all_regs)
725 static const char condflags[] = "NZCV";
729 switch (ctx->Cpsr & 0x1F)
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;
744 dbg_printf("Register dump:\n");
745 dbg_printf("%s %s Mode\n", (ctx->Cpsr & 0x20) ? "Thumb" : "ARM", buf);
747 strcpy(buf, condflags);
748 for (i = 0; buf[i]; i++)
749 if (!((ctx->Cpsr >> 26) & (1 << (sizeof(condflags) - i))))
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 );
761 if (all_regs) dbg_printf( "Floating point ARM dump not implemented\n" );
764 static void be_arm_print_segment_info(HANDLE hThread, const CONTEXT* ctx)
768 static struct dbg_internal_var be_arm_ctx[] =
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}
790 static unsigned be_arm_is_step_over_insn(const void* insn)
792 dbg_printf("be_arm_is_step_over_insn: not done\n");
796 static unsigned be_arm_is_function_return(const void* insn)
798 dbg_printf("be_arm_is_function_return: not done\n");
802 static unsigned be_arm_is_break_insn(const void* insn)
804 dbg_printf("be_arm_is_break_insn: not done\n");
808 static unsigned be_arm_is_func_call(const void* insn, ADDRESS64* callee)
813 static unsigned be_arm_is_jump(const void* insn, ADDRESS64* jumpee)
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)
826 case be_xpoint_break:
828 if (!pio->read(hProcess, addr, val, 4, &sz) || sz != 4) return 0;
830 dbg_printf("Unknown/unsupported bp type %c\n", type);
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)
844 case be_xpoint_break:
846 if (!pio->write(hProcess, addr, &val, 4, &sz) || sz == 4) return 0;
849 dbg_printf("Unknown/unsupported bp type %c\n", type);
855 static unsigned be_arm_is_watchpoint_set(const CONTEXT* ctx, unsigned idx)
857 dbg_printf("be_arm_is_watchpoint_set: not done\n");
861 static void be_arm_clear_watchpoint(CONTEXT* ctx, unsigned idx)
863 dbg_printf("be_arm_clear_watchpoint: not done\n");
866 static int be_arm_adjust_pc_for_break(CONTEXT* ctx, BOOL way)
868 INT step = (ctx->Cpsr & 0x20) ? 2 : 4;
879 static int be_arm_fetch_integer(const struct dbg_lvalue* lvalue, unsigned size,
880 unsigned ext_sign, LONGLONG* ret)
882 if (size != 1 && size != 2 && size != 4 && size != 8) return FALSE;
884 memset(ret, 0, sizeof(*ret)); /* clear unread bytes */
885 /* FIXME: this assumes that debuggee and debugger use the same
886 * integral representation
888 if (!memory_read_value(lvalue, size, ret)) return FALSE;
890 /* propagate sign information */
891 if (ext_sign && size < 8 && (*ret >> (size * 8 - 1)) != 0)
894 *ret |= neg << (size * 8);
899 static int be_arm_fetch_float(const struct dbg_lvalue* lvalue, unsigned size,
902 char tmp[sizeof(long double)];
904 /* FIXME: this assumes that debuggee and debugger use the same
905 * representation for reals
907 if (!memory_read_value(lvalue, size, tmp)) return FALSE;
911 case sizeof(float): *ret = *(float*)tmp; break;
912 case sizeof(double): *ret = *(double*)tmp; break;
913 default: return FALSE;
918 static int be_arm_store_integer(const struct dbg_lvalue* lvalue, unsigned size,
919 unsigned is_signed, LONGLONG val)
921 /* this is simple if we're on a little endian CPU */
922 return memory_write_value(lvalue, size, &val);
925 struct backend_cpu be_arm =
927 IMAGE_FILE_MACHINE_ARMV7,
932 be_arm_get_register_info,
934 be_arm_print_context,
935 be_arm_print_segment_info,
937 be_arm_is_step_over_insn,
938 be_arm_is_function_return,
939 be_arm_is_break_insn,
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,
950 be_arm_store_integer,