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
41 #define THUMB2_INSN_SIZE 4
43 #define ROR32(n, r) (((n) >> (r)) | ((n) << (32 - (r))))
45 #define get_cond(ins) tbl_cond[(ins >> 28) & 0x0f]
46 #define get_nibble(ins, num) ((ins >> (num * 4)) & 0x0f)
48 static char const tbl_regs
[][4] = {
49 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",
50 "fp", "ip", "sp", "lr", "pc", "cpsr"
53 static char const tbl_addrmode
[][3] = {
54 "da", "ia", "db", "ib"
57 static char const tbl_cond
[][3] = {
58 "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", "hi", "ls", "ge", "lt", "gt", "le", "", ""
61 static char const tbl_dataops
[][4] = {
62 "and", "eor", "sub", "rsb", "add", "adc", "sbc", "rsc", "tst", "teq", "cmp", "cmn", "orr",
66 static char const tbl_shifts
[][4] = {
67 "lsl", "lsr", "asr", "ror"
70 static char const tbl_hiops_t
[][4] = {
71 "add", "cmp", "mov", "bx"
74 static char const tbl_aluops_t
[][4] = {
75 "and", "eor", "lsl", "lsr", "asr", "adc", "sbc", "ror", "tst", "neg", "cmp", "cmn", "orr",
79 static char const tbl_immops_t
[][4] = {
80 "mov", "cmp", "add", "sub"
83 static char const tbl_sregops_t
[][5] = {
84 "strh", "ldsb", "ldrh", "ldsh"
87 static UINT
db_get_inst(void* addr
, int size
)
92 if (dbg_read_memory(addr
, buffer
, size
))
97 result
= *(UINT
*)buffer
;
100 result
= *(WORD
*)buffer
;
107 static void db_printsym(unsigned int addr
)
111 a
.Mode
= AddrModeFlat
;
114 print_address(&a
, TRUE
);
117 static UINT
arm_disasm_branch(UINT inst
, ADDRESS64
*addr
)
119 short link
= (inst
>> 24) & 0x01;
120 int offset
= (inst
<< 2) & 0x03ffffff;
122 if (offset
& 0x02000000) offset
|= 0xfc000000;
125 dbg_printf("\n\tb%s%s\t", link
? "l" : "", get_cond(inst
));
126 db_printsym(addr
->Offset
+ offset
);
130 static UINT
arm_disasm_branchreg(UINT inst
, ADDRESS64
*addr
)
132 dbg_printf("\n\tb%s\t%s", get_cond(inst
), tbl_regs
[get_nibble(inst
, 0)]);
136 static UINT
arm_disasm_dataprocessing(UINT inst
, ADDRESS64
*addr
)
138 short condcodes
= (inst
>> 20) & 0x01;
139 short opcode
= (inst
>> 21) & 0x0f;
140 short immediate
= (inst
>> 25) & 0x01;
141 short no_op1
= (opcode
& 0x0d) == 0x0d;
142 short no_dst
= (opcode
& 0x0c) == 0x08;
145 if (get_nibble(inst
, 3) == 15 /* r15 */ && condcodes
== 0 &&
146 opcode
>= 8 /* tst */ && opcode
<= 11 /* cmn */)
148 dbg_printf("\n\tnop");
152 dbg_printf("\n\t%s%s%s", tbl_dataops
[opcode
], condcodes
? "s" : "", get_cond(inst
));
153 if (!no_dst
) dbg_printf("\t%s, ", tbl_regs
[get_nibble(inst
, 3)]);
154 else dbg_printf("\t");
159 dbg_printf("#%u", ROR32(inst
& 0xff, 2 * get_nibble(inst
, 2)));
161 dbg_printf("%s", tbl_regs
[get_nibble(inst
, 0)]);
166 dbg_printf("%s, #%u", tbl_regs
[get_nibble(inst
, 4)],
167 ROR32(inst
& 0xff, 2 * get_nibble(inst
, 2)));
168 else if (((inst
>> 4) & 0xff) == 0x00) /* no shift */
169 dbg_printf("%s, %s", tbl_regs
[get_nibble(inst
, 4)], tbl_regs
[get_nibble(inst
, 0)]);
170 else if (((inst
>> 4) & 0x09) == 0x01) /* register shift */
171 dbg_printf("%s, %s, %s %s", tbl_regs
[get_nibble(inst
, 4)], tbl_regs
[get_nibble(inst
, 0)],
172 tbl_shifts
[(inst
>> 5) & 0x03], tbl_regs
[(inst
>> 8) & 0x0f]);
173 else if (((inst
>> 4) & 0x01) == 0x00) /* immediate shift */
174 dbg_printf("%s, %s, %s #%d", tbl_regs
[get_nibble(inst
, 4)], tbl_regs
[get_nibble(inst
, 0)],
175 tbl_shifts
[(inst
>> 5) & 0x03], (inst
>> 7) & 0x1f);
182 static UINT
arm_disasm_singletrans(UINT inst
, ADDRESS64
*addr
)
184 short load
= (inst
>> 20) & 0x01;
185 short writeback
= (inst
>> 21) & 0x01;
186 short byte
= (inst
>> 22) & 0x01;
187 short direction
= (inst
>> 23) & 0x01;
188 short indexing
= (inst
>> 24) & 0x01;
189 short immediate
= !((inst
>> 25) & 0x01);
190 short offset
= inst
& 0x0fff;
192 if (!direction
) offset
*= -1;
194 dbg_printf("\n\t%s%s%s%s", load
? "ldr" : "str", byte
? "b" : "", writeback
? "t" : "",
196 dbg_printf("\t%s, ", tbl_regs
[get_nibble(inst
, 3)]);
200 dbg_printf("[%s, #%d]", tbl_regs
[get_nibble(inst
, 4)], offset
);
201 else if (((inst
>> 4) & 0xff) == 0x00) /* no shift */
202 dbg_printf("[%s, %s]", tbl_regs
[get_nibble(inst
, 4)], tbl_regs
[get_nibble(inst
, 0)]);
203 else if (((inst
>> 4) & 0x01) == 0x00) /* immediate shift (there's no register shift) */
204 dbg_printf("[%s, %s, %s #%d]", tbl_regs
[get_nibble(inst
, 4)], tbl_regs
[get_nibble(inst
, 0)],
205 tbl_shifts
[(inst
>> 5) & 0x03], (inst
>> 7) & 0x1f);
212 dbg_printf("[%s], #%d", tbl_regs
[get_nibble(inst
, 4)], offset
);
213 else if (((inst
>> 4) & 0xff) == 0x00) /* no shift */
214 dbg_printf("[%s], %s", tbl_regs
[get_nibble(inst
, 4)], tbl_regs
[get_nibble(inst
, 0)]);
215 else if (((inst
>> 4) & 0x01) == 0x00) /* immediate shift (there's no register shift) */
216 dbg_printf("[%s], %s, %s #%d", tbl_regs
[get_nibble(inst
, 4)], tbl_regs
[get_nibble(inst
, 0)],
217 tbl_shifts
[(inst
>> 5) & 0x03], (inst
>> 7) & 0x1f);
224 static UINT
arm_disasm_halfwordtrans(UINT inst
, ADDRESS64
*addr
)
226 short halfword
= (inst
>> 5) & 0x01;
227 short sign
= (inst
>> 6) & 0x01;
228 short load
= (inst
>> 20) & 0x01;
229 short writeback
= (inst
>> 21) & 0x01;
230 short immediate
= (inst
>> 22) & 0x01;
231 short direction
= (inst
>> 23) & 0x01;
232 short indexing
= (inst
>> 24) & 0x01;
233 short offset
= ((inst
>> 4) & 0xf0) + (inst
& 0x0f);
235 if (!direction
) offset
*= -1;
237 dbg_printf("\n\t%s%s%s%s%s", load
? "ldr" : "str", sign
? "s" : "",
238 halfword
? "h" : (sign
? "b" : ""), writeback
? "t" : "", get_cond(inst
));
239 dbg_printf("\t%s, ", tbl_regs
[get_nibble(inst
, 3)]);
243 dbg_printf("[%s, #%d]", tbl_regs
[get_nibble(inst
, 4)], offset
);
245 dbg_printf("[%s, %s]", tbl_regs
[get_nibble(inst
, 4)], tbl_regs
[get_nibble(inst
, 0)]);
250 dbg_printf("[%s], #%d", tbl_regs
[get_nibble(inst
, 4)], offset
);
252 dbg_printf("[%s], %s", tbl_regs
[get_nibble(inst
, 4)], tbl_regs
[get_nibble(inst
, 0)]);
257 static UINT
arm_disasm_blocktrans(UINT inst
, ADDRESS64
*addr
)
259 short load
= (inst
>> 20) & 0x01;
260 short writeback
= (inst
>> 21) & 0x01;
261 short psr
= (inst
>> 22) & 0x01;
262 short addrmode
= (inst
>> 23) & 0x03;
272 dbg_printf("\n\t%s%s%s\t%s%s, {", load
? "ldm" : "stm", tbl_addrmode
[addrmode
], get_cond(inst
),
273 tbl_regs
[get_nibble(inst
, 4)], writeback
? "!" : "");
277 if (i
== last
) dbg_printf("%s", tbl_regs
[i
]);
278 else dbg_printf("%s, ", tbl_regs
[i
]);
280 dbg_printf("}%s", psr
? "^" : "");
284 static UINT
arm_disasm_swi(UINT inst
, ADDRESS64
*addr
)
286 UINT comment
= inst
& 0x00ffffff;
287 dbg_printf("\n\tswi%s\t#%d", get_cond(inst
), comment
);
291 static UINT
arm_disasm_coproctrans(UINT inst
, ADDRESS64
*addr
)
293 WORD CRm
= inst
& 0x0f;
294 WORD CP
= (inst
>> 5) & 0x07;
295 WORD CPnum
= (inst
>> 8) & 0x0f;
296 WORD CRn
= (inst
>> 16) & 0x0f;
297 WORD load
= (inst
>> 20) & 0x01;
298 WORD CP_Opc
= (inst
>> 21) & 0x07;
300 dbg_printf("\n\t%s%s\t%u, %u, %s, cr%u, cr%u, {%u}", load
? "mrc" : "mcr", get_cond(inst
), CPnum
,
301 CP
, tbl_regs
[get_nibble(inst
, 3)], CRn
, CRm
, CP_Opc
);
305 static UINT
arm_disasm_coprocdataop(UINT inst
, ADDRESS64
*addr
)
307 WORD CRm
= inst
& 0x0f;
308 WORD CP
= (inst
>> 5) & 0x07;
309 WORD CPnum
= (inst
>> 8) & 0x0f;
310 WORD CRd
= (inst
>> 12) & 0x0f;
311 WORD CRn
= (inst
>> 16) & 0x0f;
312 WORD CP_Opc
= (inst
>> 20) & 0x0f;
314 dbg_printf("\n\tcdp%s\t%u, %u, cr%u, cr%u, cr%u, {%u}", get_cond(inst
),
315 CPnum
, CP
, CRd
, CRn
, CRm
, CP_Opc
);
319 static UINT
arm_disasm_coprocdatatrans(UINT inst
, ADDRESS64
*addr
)
321 WORD CPnum
= (inst
>> 8) & 0x0f;
322 WORD CRd
= (inst
>> 12) & 0x0f;
323 WORD load
= (inst
>> 20) & 0x01;
324 WORD writeback
= (inst
>> 21) & 0x01;
325 WORD translen
= (inst
>> 22) & 0x01;
326 WORD direction
= (inst
>> 23) & 0x01;
327 WORD indexing
= (inst
>> 24) & 0x01;
328 short offset
= (inst
& 0xff) << 2;
330 if (!direction
) offset
*= -1;
332 dbg_printf("\n\t%s%s%s", load
? "ldc" : "stc", translen
? "l" : "", get_cond(inst
));
334 dbg_printf("\t%u, cr%u, [%s, #%d]%s", CPnum
, CRd
, tbl_regs
[get_nibble(inst
, 4)], offset
, writeback
?"!":"");
336 dbg_printf("\t%u, cr%u, [%s], #%d", CPnum
, CRd
, tbl_regs
[get_nibble(inst
, 4)], offset
);
340 static WORD
thumb_disasm_hireg(WORD inst
, ADDRESS64
*addr
)
342 short dst
= inst
& 0x07;
343 short src
= (inst
>> 3) & 0x07;
344 short h2
= (inst
>> 6) & 0x01;
345 short h1
= (inst
>> 7) & 0x01;
346 short op
= (inst
>> 8) & 0x03;
351 if (op
== 2 && dst
== src
) /* mov rx, rx */
353 dbg_printf("\n\tnop");
358 dbg_printf("\n\tb%sx\t%s", h1
?"l":"", tbl_regs
[src
]);
360 dbg_printf("\n\t%s\t%s, %s", tbl_hiops_t
[op
], tbl_regs
[dst
], tbl_regs
[src
]);
365 static WORD
thumb_disasm_aluop(WORD inst
, ADDRESS64
*addr
)
367 short dst
= inst
& 0x07;
368 short src
= (inst
>> 3) & 0x07;
369 short op
= (inst
>> 6) & 0x0f;
371 dbg_printf("\n\t%s\t%s, %s", tbl_aluops_t
[op
], tbl_regs
[dst
], tbl_regs
[src
]);
376 static WORD
thumb_disasm_pushpop(WORD inst
, ADDRESS64
*addr
)
378 short lrpc
= (inst
>> 8) & 0x01;
379 short load
= (inst
>> 11) & 0x01;
384 if ((inst
>>i
) & 1) break;
387 dbg_printf("\n\t%s\t{", load
? "pop" : "push");
392 if (i
== last
) dbg_printf("%s", tbl_regs
[i
]);
393 else dbg_printf("%s, ", tbl_regs
[i
]);
396 dbg_printf("%s%s", last
? ", " : "", load
? "pc" : "lr");
402 static WORD
thumb_disasm_blocktrans(WORD inst
, ADDRESS64
*addr
)
404 short load
= (inst
>> 11) & 0x01;
409 if ((inst
>>i
) & 1) break;
412 dbg_printf("\n\t%s\t%s!, {", load
? "ldmia" : "stmia", tbl_regs
[(inst
>> 8) & 0x07]);
417 if (i
== last
) dbg_printf("%s", tbl_regs
[i
]);
418 else dbg_printf("%s, ", tbl_regs
[i
]);
425 static WORD
thumb_disasm_condbranch(WORD inst
, ADDRESS64
*addr
)
427 WORD offset
= inst
& 0x00ff;
428 dbg_printf("\n\tb%s\t", tbl_cond
[(inst
>> 8) & 0x0f]);
429 db_printsym(addr
->Offset
+ offset
);
433 static WORD
thumb_disasm_uncondbranch(WORD inst
, ADDRESS64
*addr
)
435 short offset
= (inst
& 0x07ff) << 1;
437 if (offset
& 0x0800) offset
|= 0xf000;
440 dbg_printf("\n\tb\t");
441 db_printsym(addr
->Offset
+ offset
);
445 static WORD
thumb_disasm_loadadr(WORD inst
, ADDRESS64
*addr
)
447 WORD src
= (inst
>> 11) & 0x01;
448 WORD offset
= (inst
& 0xff) << 2;
450 dbg_printf("\n\tadd\t%s, %s, #%d", tbl_regs
[(inst
>> 8) & 0x07], src
? "sp" : "pc", offset
);
454 static WORD
thumb_disasm_swi(WORD inst
, ADDRESS64
*addr
)
456 WORD comment
= inst
& 0x00ff;
457 dbg_printf("\n\tswi\t#%d", comment
);
461 static WORD
thumb_disasm_nop(WORD inst
, ADDRESS64
*addr
)
463 dbg_printf("\n\tnop");
467 static WORD
thumb_disasm_ldrpcrel(WORD inst
, ADDRESS64
*addr
)
469 WORD offset
= (inst
& 0xff) << 2;
470 dbg_printf("\n\tldr\t%s, [pc, #%u]", tbl_regs
[(inst
>> 8) & 0x07], offset
);
474 static WORD
thumb_disasm_ldrsprel(WORD inst
, ADDRESS64
*addr
)
476 WORD offset
= (inst
& 0xff) << 2;
477 dbg_printf("\n\t%s\t%s, [sp, #%u]", (inst
& 0x0800)?"ldr":"str", tbl_regs
[(inst
>> 8) & 0x07], offset
);
481 static WORD
thumb_disasm_addsprel(WORD inst
, ADDRESS64
*addr
)
483 WORD offset
= (inst
& 0x7f) << 2;
484 if ((inst
>> 7) & 0x01)
485 dbg_printf("\n\tsub\tsp, sp, #%u", offset
);
487 dbg_printf("\n\tadd\tsp, sp, #%u", offset
);
491 static WORD
thumb_disasm_ldrimm(WORD inst
, ADDRESS64
*addr
)
493 WORD offset
= (inst
& 0x07c0) >> 6;
494 dbg_printf("\n\t%s%s\t%s, [%s, #%u]", (inst
& 0x0800)?"ldr":"str", (inst
& 0x1000)?"b":"",
495 tbl_regs
[inst
& 0x07], tbl_regs
[(inst
>> 3) & 0x07], (inst
& 0x1000)?offset
:(offset
<< 2));
499 static WORD
thumb_disasm_ldrhimm(WORD inst
, ADDRESS64
*addr
)
501 WORD offset
= (inst
& 0x07c0) >> 5;
502 dbg_printf("\n\t%s\t%s, [%s, #%u]", (inst
& 0x0800)?"ldrh":"strh",
503 tbl_regs
[inst
& 0x07], tbl_regs
[(inst
>> 3) & 0x07], offset
);
507 static WORD
thumb_disasm_ldrreg(WORD inst
, ADDRESS64
*addr
)
509 dbg_printf("\n\t%s%s\t%s, [%s, %s]", (inst
& 0x0800)?"ldr":"str", (inst
& 0x0400)?"b":"",
510 tbl_regs
[inst
& 0x07], tbl_regs
[(inst
>> 3) & 0x07], tbl_regs
[(inst
>> 6) & 0x07]);
514 static WORD
thumb_disasm_ldrsreg(WORD inst
, ADDRESS64
*addr
)
516 dbg_printf("\n\t%s\t%s, [%s, %s]", tbl_sregops_t
[(inst
>> 10) & 0x03],
517 tbl_regs
[inst
& 0x07], tbl_regs
[(inst
>> 3) & 0x07], tbl_regs
[(inst
>> 6) & 0x07]);
521 static WORD
thumb_disasm_immop(WORD inst
, ADDRESS64
*addr
)
523 WORD op
= (inst
>> 11) & 0x03;
524 dbg_printf("\n\t%s\t%s, #%u", tbl_immops_t
[op
], tbl_regs
[(inst
>> 8) & 0x07], inst
& 0xff);
528 static WORD
thumb_disasm_addsub(WORD inst
, ADDRESS64
*addr
)
530 WORD op
= (inst
>> 9) & 0x01;
531 WORD immediate
= (inst
>> 10) & 0x01;
533 dbg_printf("\n\t%s\t%s, %s, ", op
? "sub" : "add",
534 tbl_regs
[inst
& 0x07], tbl_regs
[(inst
>> 3) & 0x07]);
536 dbg_printf("#%d", (inst
>> 6) & 0x07);
538 dbg_printf("%s", tbl_regs
[(inst
>> 6) & 0x07]);
542 static WORD
thumb_disasm_movshift(WORD inst
, ADDRESS64
*addr
)
544 WORD op
= (inst
>> 11) & 0x03;
545 dbg_printf("\n\t%s\t%s, %s, #%u", tbl_shifts
[op
],
546 tbl_regs
[inst
& 0x07], tbl_regs
[(inst
>> 3) & 0x07], (inst
>> 6) & 0x1f);
550 static UINT
thumb2_disasm_branchlinked(UINT inst
, ADDRESS64
*addr
)
552 UINT offset
= (((inst
& 0x07ff0000) >> 4) | ((inst
& 0x000007ff) << 1)) + 4;
554 dbg_printf("\n\tbl\t");
555 db_printsym(addr
->Offset
+ offset
);
559 static UINT
thumb2_disasm_misc(UINT inst
, ADDRESS64
*addr
)
561 WORD op1
= (inst
>> 20) & 0x03;
562 WORD op2
= (inst
>> 4) & 0x03;
564 if (get_nibble(inst
, 4) != get_nibble(inst
, 0))
567 if (op1
== 3 && op2
== 0)
569 dbg_printf("\n\tclz\t%s, %s\t", tbl_regs
[get_nibble(inst
, 2)], tbl_regs
[get_nibble(inst
, 0)]);
578 dbg_printf("\n\trev\t");
581 dbg_printf("\n\trev16\t");
584 dbg_printf("\n\trbit\t");
587 dbg_printf("\n\trevsh\t");
590 dbg_printf("%s, %s\t", tbl_regs
[get_nibble(inst
, 2)], tbl_regs
[get_nibble(inst
, 0)]);
597 static UINT
thumb2_disasm_mul(UINT inst
, ADDRESS64
*addr
)
599 WORD op1
= (inst
>> 20) & 0x07;
600 WORD op2
= (inst
>> 4) & 0x03;
605 if (op2
== 0 && get_nibble(inst
, 3) != 0xf)
607 dbg_printf("\n\tmla\t%s, %s, %s, %s\t", tbl_regs
[get_nibble(inst
, 2)],
608 tbl_regs
[get_nibble(inst
, 4)],
609 tbl_regs
[get_nibble(inst
, 0)],
610 tbl_regs
[get_nibble(inst
, 3)]);
614 if (op2
== 0 && get_nibble(inst
, 3) == 0xf)
616 dbg_printf("\n\tmul\t%s, %s, %s\t", tbl_regs
[get_nibble(inst
, 2)],
617 tbl_regs
[get_nibble(inst
, 4)],
618 tbl_regs
[get_nibble(inst
, 0)]);
624 dbg_printf("\n\tmls\t%s, %s, %s, %s\t", tbl_regs
[get_nibble(inst
, 2)],
625 tbl_regs
[get_nibble(inst
, 4)],
626 tbl_regs
[get_nibble(inst
, 0)],
627 tbl_regs
[get_nibble(inst
, 3)]);
634 static UINT
thumb2_disasm_longmuldiv(UINT inst
, ADDRESS64
*addr
)
636 WORD op1
= (inst
>> 20) & 0x07;
637 WORD op2
= (inst
>> 4) & 0x0f;
644 dbg_printf("\n\tsmull\t");
647 dbg_printf("\n\tumull\t");
650 dbg_printf("\n\tsmlal\t");
653 dbg_printf("\n\tumlal\t");
658 dbg_printf("%s, %s, %s, %s\t", tbl_regs
[get_nibble(inst
, 3)], tbl_regs
[get_nibble(inst
, 2)],
659 tbl_regs
[get_nibble(inst
, 4)], tbl_regs
[get_nibble(inst
, 0)]);
668 dbg_printf("\n\tsdiv\t");
671 dbg_printf("\n\tudiv\t");
676 dbg_printf("%s, %s, %s\t", tbl_regs
[get_nibble(inst
, 2)], tbl_regs
[get_nibble(inst
, 4)],
677 tbl_regs
[get_nibble(inst
, 0)]);
688 UINT (*func
)(UINT
, ADDRESS64
*);
691 static const struct inst_arm tbl_arm
[] = {
692 { 0x0e000000, 0x0a000000, arm_disasm_branch
},
693 { 0x0e000090, 0x00000090, arm_disasm_halfwordtrans
},
694 { 0x0fffff00, 0x012fff00, arm_disasm_branchreg
},
695 { 0x0c000000, 0x00000000, arm_disasm_dataprocessing
},
696 { 0x0c000000, 0x04000000, arm_disasm_singletrans
},
697 { 0x0e000000, 0x08000000, arm_disasm_blocktrans
},
698 { 0x0f000000, 0x0f000000, arm_disasm_swi
},
699 { 0x0f000010, 0x0e000010, arm_disasm_coproctrans
},
700 { 0x0f000010, 0x0e000000, arm_disasm_coprocdataop
},
701 { 0x0e000000, 0x0c000000, arm_disasm_coprocdatatrans
},
702 { 0x00000000, 0x00000000, NULL
}
709 WORD (*func
)(WORD
, ADDRESS64
*);
712 static const struct inst_thumb16 tbl_thumb16
[] = {
713 { 0xfc00, 0x4400, thumb_disasm_hireg
},
714 { 0xfc00, 0x4000, thumb_disasm_aluop
},
715 { 0xf600, 0xb400, thumb_disasm_pushpop
},
716 { 0xf000, 0xc000, thumb_disasm_blocktrans
},
717 { 0xf000, 0xd000, thumb_disasm_condbranch
},
718 { 0xf800, 0xe000, thumb_disasm_uncondbranch
},
719 { 0xf000, 0xa000, thumb_disasm_loadadr
},
720 { 0xf800, 0x4800, thumb_disasm_ldrpcrel
},
721 { 0xf000, 0x9000, thumb_disasm_ldrsprel
},
722 { 0xff00, 0xb000, thumb_disasm_addsprel
},
723 { 0xe000, 0x6000, thumb_disasm_ldrimm
},
724 { 0xf000, 0x8000, thumb_disasm_ldrhimm
},
725 { 0xf200, 0x5000, thumb_disasm_ldrreg
},
726 { 0xf200, 0x5200, thumb_disasm_ldrsreg
},
727 { 0xe000, 0x2000, thumb_disasm_immop
},
728 { 0xff00, 0xdf00, thumb_disasm_swi
},
729 { 0xff00, 0xbf00, thumb_disasm_nop
},
730 { 0xf800, 0x1800, thumb_disasm_addsub
},
731 { 0xe000, 0x0000, thumb_disasm_movshift
},
732 { 0x0000, 0x0000, NULL
}
735 static const struct inst_arm tbl_thumb32
[] = {
736 { 0xf800f800, 0xf000f800, thumb2_disasm_branchlinked
},
737 { 0xffc0f0c0, 0xfa80f080, thumb2_disasm_misc
},
738 { 0xff8000c0, 0xfb000000, thumb2_disasm_mul
},
739 { 0xff8000f0, 0xfb800000, thumb2_disasm_longmuldiv
},
740 { 0xff8000f0, 0xfb8000f0, thumb2_disasm_longmuldiv
},
741 { 0x00000000, 0x00000000, NULL
}
744 /***********************************************************************
747 * Disassemble instruction at 'addr'. addr is changed to point to the
748 * start of the next instruction.
750 void be_arm_disasm_one_insn(ADDRESS64
*addr
, int display
)
752 struct inst_arm
*a_ptr
= (struct inst_arm
*)&tbl_arm
;
753 struct inst_thumb16
*t_ptr
= (struct inst_thumb16
*)&tbl_thumb16
;
754 struct inst_arm
*t2_ptr
= (struct inst_arm
*)&tbl_thumb32
;
763 if (!memory_get_register(CV_ARM_CPSR
, &pval
, tmp
, sizeof(tmp
)))
764 dbg_printf("\n\tmemory_get_register failed: %s", tmp
);
766 db_disasm_thumb
=(*pval
& 0x20)?TRUE
:FALSE
;
768 db_display
= display
;
770 if (!db_disasm_thumb
)
772 size
= ARM_INSN_SIZE
;
773 inst
= db_get_inst( memory_to_linear_addr(addr
), size
);
774 while (a_ptr
->func
) {
775 if ((inst
& a_ptr
->mask
) == a_ptr
->pattern
) {
783 dbg_printf("\n\tUnknown ARM Instruction: %08x", inst
);
784 addr
->Offset
+= size
;
788 if (!a_ptr
->func(inst
, addr
))
789 addr
->Offset
+= size
;
795 WORD
*taddr
= memory_to_linear_addr(addr
);
796 tinst
= db_get_inst( taddr
, THUMB_INSN_SIZE
);
797 switch (tinst
& 0xf800)
802 size
= THUMB2_INSN_SIZE
;
804 inst
= db_get_inst( taddr
, THUMB_INSN_SIZE
);
805 inst
|= (tinst
<< 16);
807 while (t2_ptr
->func
) {
808 if ((inst
& t2_ptr
->mask
) == t2_ptr
->pattern
) {
816 dbg_printf("\n\tUnknown Thumb2 Instruction: %08x", inst
);
817 addr
->Offset
+= size
;
821 if (!t2_ptr
->func(inst
, addr
))
822 addr
->Offset
+= size
;
829 size
= THUMB_INSN_SIZE
;
830 while (t_ptr
->func
) {
831 if ((tinst
& t_ptr
->mask
) == t_ptr
->pattern
) {
839 dbg_printf("\n\tUnknown Thumb Instruction: %04x", tinst
);
840 addr
->Offset
+= size
;
844 if (!t_ptr
->func(tinst
, addr
))
845 addr
->Offset
+= size
;
851 static unsigned be_arm_get_addr(HANDLE hThread
, const CONTEXT
* ctx
,
852 enum be_cpu_addr bca
, ADDRESS64
* addr
)
857 return be_cpu_build_addr(hThread
, ctx
, addr
, 0, ctx
->Pc
);
858 case be_cpu_addr_stack
:
859 return be_cpu_build_addr(hThread
, ctx
, addr
, 0, ctx
->Sp
);
860 case be_cpu_addr_frame
:
861 return be_cpu_build_addr(hThread
, ctx
, addr
, 0, ctx
->Fp
);
866 static unsigned be_arm_get_register_info(int regno
, enum be_cpu_addr
* kind
)
870 case CV_ARM_PC
: *kind
= be_cpu_addr_pc
; return TRUE
;
871 case CV_ARM_R0
+ 11: *kind
= be_cpu_addr_frame
; return TRUE
;
872 case CV_ARM_SP
: *kind
= be_cpu_addr_stack
; return TRUE
;
877 static void be_arm_single_step(CONTEXT
* ctx
, unsigned enable
)
879 dbg_printf("be_arm_single_step: not done\n");
882 static void be_arm_print_context(HANDLE hThread
, const CONTEXT
* ctx
, int all_regs
)
884 static const char condflags
[] = "NZCV";
888 switch (ctx
->Cpsr
& 0x1F)
890 case 0: strcpy(buf
, "User26"); break;
891 case 1: strcpy(buf
, "FIQ26"); break;
892 case 2: strcpy(buf
, "IRQ26"); break;
893 case 3: strcpy(buf
, "SVC26"); break;
894 case 16: strcpy(buf
, "User"); break;
895 case 17: strcpy(buf
, "FIQ"); break;
896 case 18: strcpy(buf
, "IRQ"); break;
897 case 19: strcpy(buf
, "SVC"); break;
898 case 23: strcpy(buf
, "ABT"); break;
899 case 27: strcpy(buf
, "UND"); break;
900 default: strcpy(buf
, "UNKNWN"); break;
903 dbg_printf("Register dump:\n");
904 dbg_printf("%s %s Mode\n", (ctx
->Cpsr
& 0x20) ? "Thumb" : "ARM", buf
);
906 strcpy(buf
, condflags
);
907 for (i
= 0; buf
[i
]; i
++)
908 if (!((ctx
->Cpsr
>> 26) & (1 << (sizeof(condflags
) - i
))))
911 dbg_printf(" Pc:%04x Sp:%04x Lr:%04x Cpsr:%04x(%s)\n",
912 ctx
->Pc
, ctx
->Sp
, ctx
->Lr
, ctx
->Cpsr
, buf
);
913 dbg_printf(" r0:%04x r1:%04x r2:%04x r3:%04x\n",
914 ctx
->R0
, ctx
->R1
, ctx
->R2
, ctx
->R3
);
915 dbg_printf(" r4:%04x r5:%04x r6:%04x r7:%04x r8:%04x\n",
916 ctx
->R4
, ctx
->R5
, ctx
->R6
, ctx
->R7
, ctx
->R8
);
917 dbg_printf(" r9:%04x r10:%04x Fp:%04x Ip:%04x\n",
918 ctx
->R9
, ctx
->R10
, ctx
->Fp
, ctx
->Ip
);
920 if (all_regs
) dbg_printf( "Floating point ARM dump not implemented\n" );
923 static void be_arm_print_segment_info(HANDLE hThread
, const CONTEXT
* ctx
)
927 static struct dbg_internal_var be_arm_ctx
[] =
929 {CV_ARM_R0
+ 0, "r0", (DWORD_PTR
*)FIELD_OFFSET(CONTEXT
, R0
), dbg_itype_unsigned_int
},
930 {CV_ARM_R0
+ 1, "r1", (DWORD_PTR
*)FIELD_OFFSET(CONTEXT
, R1
), dbg_itype_unsigned_int
},
931 {CV_ARM_R0
+ 2, "r2", (DWORD_PTR
*)FIELD_OFFSET(CONTEXT
, R2
), dbg_itype_unsigned_int
},
932 {CV_ARM_R0
+ 3, "r3", (DWORD_PTR
*)FIELD_OFFSET(CONTEXT
, R3
), dbg_itype_unsigned_int
},
933 {CV_ARM_R0
+ 4, "r4", (DWORD_PTR
*)FIELD_OFFSET(CONTEXT
, R4
), dbg_itype_unsigned_int
},
934 {CV_ARM_R0
+ 5, "r5", (DWORD_PTR
*)FIELD_OFFSET(CONTEXT
, R5
), dbg_itype_unsigned_int
},
935 {CV_ARM_R0
+ 6, "r6", (DWORD_PTR
*)FIELD_OFFSET(CONTEXT
, R6
), dbg_itype_unsigned_int
},
936 {CV_ARM_R0
+ 7, "r7", (DWORD_PTR
*)FIELD_OFFSET(CONTEXT
, R7
), dbg_itype_unsigned_int
},
937 {CV_ARM_R0
+ 8, "r8", (DWORD_PTR
*)FIELD_OFFSET(CONTEXT
, R8
), dbg_itype_unsigned_int
},
938 {CV_ARM_R0
+ 9, "r9", (DWORD_PTR
*)FIELD_OFFSET(CONTEXT
, R9
), dbg_itype_unsigned_int
},
939 {CV_ARM_R0
+ 10, "r10", (DWORD_PTR
*)FIELD_OFFSET(CONTEXT
, R10
), dbg_itype_unsigned_int
},
940 {CV_ARM_R0
+ 11, "r11", (DWORD_PTR
*)FIELD_OFFSET(CONTEXT
, Fp
), dbg_itype_unsigned_int
},
941 {CV_ARM_R0
+ 12, "r12", (DWORD_PTR
*)FIELD_OFFSET(CONTEXT
, Ip
), dbg_itype_unsigned_int
},
942 {CV_ARM_SP
, "sp", (DWORD_PTR
*)FIELD_OFFSET(CONTEXT
, Sp
), dbg_itype_unsigned_int
},
943 {CV_ARM_LR
, "lr", (DWORD_PTR
*)FIELD_OFFSET(CONTEXT
, Lr
), dbg_itype_unsigned_int
},
944 {CV_ARM_PC
, "pc", (DWORD_PTR
*)FIELD_OFFSET(CONTEXT
, Pc
), dbg_itype_unsigned_int
},
945 {CV_ARM_CPSR
, "cpsr", (DWORD_PTR
*)FIELD_OFFSET(CONTEXT
, Cpsr
), dbg_itype_unsigned_int
},
946 {0, NULL
, 0, dbg_itype_none
}
949 static unsigned be_arm_is_step_over_insn(const void* insn
)
951 dbg_printf("be_arm_is_step_over_insn: not done\n");
955 static unsigned be_arm_is_function_return(const void* insn
)
957 dbg_printf("be_arm_is_function_return: not done\n");
961 static unsigned be_arm_is_break_insn(const void* insn
)
963 dbg_printf("be_arm_is_break_insn: not done\n");
967 static unsigned be_arm_is_func_call(const void* insn
, ADDRESS64
* callee
)
972 static unsigned be_arm_is_jump(const void* insn
, ADDRESS64
* jumpee
)
977 static unsigned be_arm_insert_Xpoint(HANDLE hProcess
, const struct be_process_io
* pio
,
978 CONTEXT
* ctx
, enum be_xpoint_type type
,
979 void* addr
, unsigned long* val
, unsigned size
)
985 case be_xpoint_break
:
987 if (!pio
->read(hProcess
, addr
, val
, 4, &sz
) || sz
!= 4) return 0;
989 dbg_printf("Unknown/unsupported bp type %c\n", type
);
995 static unsigned be_arm_remove_Xpoint(HANDLE hProcess
, const struct be_process_io
* pio
,
996 CONTEXT
* ctx
, enum be_xpoint_type type
,
997 void* addr
, unsigned long val
, unsigned size
)
1003 case be_xpoint_break
:
1004 if (!size
) return 0;
1005 if (!pio
->write(hProcess
, addr
, &val
, 4, &sz
) || sz
== 4) return 0;
1008 dbg_printf("Unknown/unsupported bp type %c\n", type
);
1014 static unsigned be_arm_is_watchpoint_set(const CONTEXT
* ctx
, unsigned idx
)
1016 dbg_printf("be_arm_is_watchpoint_set: not done\n");
1020 static void be_arm_clear_watchpoint(CONTEXT
* ctx
, unsigned idx
)
1022 dbg_printf("be_arm_clear_watchpoint: not done\n");
1025 static int be_arm_adjust_pc_for_break(CONTEXT
* ctx
, BOOL way
)
1027 INT step
= (ctx
->Cpsr
& 0x20) ? 2 : 4;
1038 static int be_arm_fetch_integer(const struct dbg_lvalue
* lvalue
, unsigned size
,
1039 unsigned ext_sign
, LONGLONG
* ret
)
1041 if (size
!= 1 && size
!= 2 && size
!= 4 && size
!= 8) return FALSE
;
1043 memset(ret
, 0, sizeof(*ret
)); /* clear unread bytes */
1044 /* FIXME: this assumes that debuggee and debugger use the same
1045 * integral representation
1047 if (!memory_read_value(lvalue
, size
, ret
)) return FALSE
;
1049 /* propagate sign information */
1050 if (ext_sign
&& size
< 8 && (*ret
>> (size
* 8 - 1)) != 0)
1053 *ret
|= neg
<< (size
* 8);
1058 static int be_arm_fetch_float(const struct dbg_lvalue
* lvalue
, unsigned size
,
1061 char tmp
[sizeof(long double)];
1063 /* FIXME: this assumes that debuggee and debugger use the same
1064 * representation for reals
1066 if (!memory_read_value(lvalue
, size
, tmp
)) return FALSE
;
1070 case sizeof(float): *ret
= *(float*)tmp
; break;
1071 case sizeof(double): *ret
= *(double*)tmp
; break;
1072 default: return FALSE
;
1077 static int be_arm_store_integer(const struct dbg_lvalue
* lvalue
, unsigned size
,
1078 unsigned is_signed
, LONGLONG val
)
1080 /* this is simple if we're on a little endian CPU */
1081 return memory_write_value(lvalue
, size
, &val
);
1084 struct backend_cpu be_arm
=
1086 IMAGE_FILE_MACHINE_ARMV7
,
1091 be_arm_get_register_info
,
1093 be_arm_print_context
,
1094 be_arm_print_segment_info
,
1096 be_arm_is_step_over_insn
,
1097 be_arm_is_function_return
,
1098 be_arm_is_break_insn
,
1099 be_arm_is_func_call
,
1101 be_arm_disasm_one_insn
,
1102 be_arm_insert_Xpoint
,
1103 be_arm_remove_Xpoint
,
1104 be_arm_is_watchpoint_set
,
1105 be_arm_clear_watchpoint
,
1106 be_arm_adjust_pc_for_break
,
1107 be_arm_fetch_integer
,
1109 be_arm_store_integer
,