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 char const tbl_miscops_t2
[][6] = {
88 "rev", "rev16", "rbit", "revsh"
91 static char const tbl_width_t2
[][2] = {
95 static char const tbl_special_regs_t2
[][12] = {
96 "apsr", "iapsr", "eapsr", "xpsr", "rsvd", "ipsr", "epsr", "iepsr", "msp", "psp", "rsvd", "rsvd",
97 "rsvd", "rsvd", "rsvd", "rsvd", "primask", "basepri", "basepri_max", "faultmask", "control"
100 static char const tbl_hints_t2
[][6] = {
101 "nop", "yield", "wfe", "wfi", "sev"
104 static UINT
db_get_inst(void* addr
, int size
)
109 if (dbg_read_memory(addr
, buffer
, size
))
114 result
= *(UINT
*)buffer
;
117 result
= *(WORD
*)buffer
;
124 static void db_printsym(unsigned int addr
)
128 a
.Mode
= AddrModeFlat
;
131 print_address(&a
, TRUE
);
134 static UINT
arm_disasm_branch(UINT inst
, ADDRESS64
*addr
)
136 short link
= (inst
>> 24) & 0x01;
137 int offset
= (inst
<< 2) & 0x03ffffff;
139 if (offset
& 0x02000000) offset
|= 0xfc000000;
142 dbg_printf("\n\tb%s%s\t", link
? "l" : "", get_cond(inst
));
143 db_printsym(addr
->Offset
+ offset
);
147 static UINT
arm_disasm_mul(UINT inst
, ADDRESS64
*addr
)
149 short accu
= (inst
>> 21) & 0x01;
150 short condcodes
= (inst
>> 20) & 0x01;
153 dbg_printf("\n\tmla%s%s\t%s, %s, %s, %s", get_cond(inst
), condcodes
? "s" : "",
154 tbl_regs
[get_nibble(inst
, 4)], tbl_regs
[get_nibble(inst
, 0)],
155 tbl_regs
[get_nibble(inst
, 2)], tbl_regs
[get_nibble(inst
, 3)]);
157 dbg_printf("\n\tmul%s%s\t%s, %s, %s", get_cond(inst
), condcodes
? "s" : "",
158 tbl_regs
[get_nibble(inst
, 4)], tbl_regs
[get_nibble(inst
, 0)],
159 tbl_regs
[get_nibble(inst
, 2)]);
163 static UINT
arm_disasm_longmul(UINT inst
, ADDRESS64
*addr
)
165 short sign
= (inst
>> 22) & 0x01;
166 short accu
= (inst
>> 21) & 0x01;
167 short condcodes
= (inst
>> 20) & 0x01;
169 dbg_printf("\n\t%s%s%s%s\t%s, %s, %s, %s", sign
? "s" : "u", accu
? "mlal" : "mull",
170 get_cond(inst
), condcodes
? "s" : "",
171 tbl_regs
[get_nibble(inst
, 3)], tbl_regs
[get_nibble(inst
, 4)],
172 tbl_regs
[get_nibble(inst
, 0)], tbl_regs
[get_nibble(inst
, 2)]);
176 static UINT
arm_disasm_swp(UINT inst
, ADDRESS64
*addr
)
178 short byte
= (inst
>> 22) & 0x01;
180 dbg_printf("\n\tswp%s%s\t%s, %s, [%s]", get_cond(inst
), byte
? "b" : "",
181 tbl_regs
[get_nibble(inst
, 3)], tbl_regs
[get_nibble(inst
, 0)],
182 tbl_regs
[get_nibble(inst
, 4)]);
186 static UINT
arm_disasm_halfwordtrans(UINT inst
, ADDRESS64
*addr
)
188 short halfword
= (inst
>> 5) & 0x01;
189 short sign
= (inst
>> 6) & 0x01;
190 short load
= (inst
>> 20) & 0x01;
191 short writeback
= (inst
>> 21) & 0x01;
192 short immediate
= (inst
>> 22) & 0x01;
193 short direction
= (inst
>> 23) & 0x01;
194 short indexing
= (inst
>> 24) & 0x01;
195 short offset
= ((inst
>> 4) & 0xf0) + (inst
& 0x0f);
197 if (!direction
) offset
*= -1;
199 dbg_printf("\n\t%s%s%s%s%s", load
? "ldr" : "str", sign
? "s" : "",
200 halfword
? "h" : (sign
? "b" : ""), writeback
? "t" : "", get_cond(inst
));
201 dbg_printf("\t%s, ", tbl_regs
[get_nibble(inst
, 3)]);
205 dbg_printf("[%s, #%d]", tbl_regs
[get_nibble(inst
, 4)], offset
);
207 dbg_printf("[%s, %s]", tbl_regs
[get_nibble(inst
, 4)], tbl_regs
[get_nibble(inst
, 0)]);
212 dbg_printf("[%s], #%d", tbl_regs
[get_nibble(inst
, 4)], offset
);
214 dbg_printf("[%s], %s", tbl_regs
[get_nibble(inst
, 4)], tbl_regs
[get_nibble(inst
, 0)]);
219 static UINT
arm_disasm_branchreg(UINT inst
, ADDRESS64
*addr
)
221 dbg_printf("\n\tb%s\t%s", get_cond(inst
), tbl_regs
[get_nibble(inst
, 0)]);
225 static UINT
arm_disasm_branchxchg(UINT inst
, ADDRESS64
*addr
)
227 dbg_printf("\n\tbx%s\t%s", get_cond(inst
), tbl_regs
[get_nibble(inst
, 0)]);
231 static UINT
arm_disasm_mrstrans(UINT inst
, ADDRESS64
*addr
)
233 short src
= (inst
>> 22) & 0x01;
235 dbg_printf("\n\tmrs%s\t%s, %s", get_cond(inst
), tbl_regs
[get_nibble(inst
, 3)],
236 src
? "spsr" : "cpsr");
240 static UINT
arm_disasm_msrtrans(UINT inst
, ADDRESS64
*addr
)
242 short immediate
= (inst
>> 25) & 0x01;
243 short dst
= (inst
>> 22) & 0x01;
244 short simple
= (inst
>> 16) & 0x01;
246 if (simple
|| !immediate
)
248 dbg_printf("\n\tmsr%s\t%s, %s", get_cond(inst
), dst
? "spsr" : "cpsr",
249 tbl_regs
[get_nibble(inst
, 0)]);
253 dbg_printf("\n\tmsr%s\t%s, #%u", get_cond(inst
), dst
? "spsr" : "cpsr",
254 ROR32(inst
& 0xff, 2 * get_nibble(inst
, 2)));
258 static UINT
arm_disasm_wordmov(UINT inst
, ADDRESS64
*addr
)
260 short top
= (inst
>> 22) & 0x01;
262 dbg_printf("\n\tmov%s%s\t%s, #%u", top
? "t" : "w", get_cond(inst
),
263 tbl_regs
[get_nibble(inst
, 3)], (get_nibble(inst
, 4) << 12) | (inst
& 0x0fff));
267 static UINT
arm_disasm_nop(UINT inst
, ADDRESS64
*addr
)
269 dbg_printf("\n\tnop%s", get_cond(inst
));
273 static UINT
arm_disasm_dataprocessing(UINT inst
, ADDRESS64
*addr
)
275 short condcodes
= (inst
>> 20) & 0x01;
276 short opcode
= (inst
>> 21) & 0x0f;
277 short immediate
= (inst
>> 25) & 0x01;
278 short no_op1
= (opcode
& 0x0d) == 0x0d;
279 short no_dst
= (opcode
& 0x0c) == 0x08;
281 dbg_printf("\n\t%s%s%s", tbl_dataops
[opcode
], condcodes
? "s" : "", get_cond(inst
));
282 if (!no_dst
) dbg_printf("\t%s, ", tbl_regs
[get_nibble(inst
, 3)]);
283 else dbg_printf("\t");
288 dbg_printf("#%u", ROR32(inst
& 0xff, 2 * get_nibble(inst
, 2)));
290 dbg_printf("%s", tbl_regs
[get_nibble(inst
, 0)]);
295 dbg_printf("%s, #%u", tbl_regs
[get_nibble(inst
, 4)],
296 ROR32(inst
& 0xff, 2 * get_nibble(inst
, 2)));
297 else if (((inst
>> 4) & 0xff) == 0x00) /* no shift */
298 dbg_printf("%s, %s", tbl_regs
[get_nibble(inst
, 4)], tbl_regs
[get_nibble(inst
, 0)]);
299 else if (((inst
>> 4) & 0x09) == 0x01) /* register shift */
300 dbg_printf("%s, %s, %s %s", tbl_regs
[get_nibble(inst
, 4)], tbl_regs
[get_nibble(inst
, 0)],
301 tbl_shifts
[(inst
>> 5) & 0x03], tbl_regs
[(inst
>> 8) & 0x0f]);
302 else if (((inst
>> 4) & 0x01) == 0x00) /* immediate shift */
303 dbg_printf("%s, %s, %s #%d", tbl_regs
[get_nibble(inst
, 4)], tbl_regs
[get_nibble(inst
, 0)],
304 tbl_shifts
[(inst
>> 5) & 0x03], (inst
>> 7) & 0x1f);
311 static UINT
arm_disasm_singletrans(UINT inst
, ADDRESS64
*addr
)
313 short load
= (inst
>> 20) & 0x01;
314 short writeback
= (inst
>> 21) & 0x01;
315 short byte
= (inst
>> 22) & 0x01;
316 short direction
= (inst
>> 23) & 0x01;
317 short indexing
= (inst
>> 24) & 0x01;
318 short immediate
= !((inst
>> 25) & 0x01);
319 short offset
= inst
& 0x0fff;
321 if (!direction
) offset
*= -1;
323 dbg_printf("\n\t%s%s%s%s", load
? "ldr" : "str", byte
? "b" : "", writeback
? "t" : "",
325 dbg_printf("\t%s, ", tbl_regs
[get_nibble(inst
, 3)]);
329 dbg_printf("[%s, #%d]", tbl_regs
[get_nibble(inst
, 4)], offset
);
330 else if (((inst
>> 4) & 0xff) == 0x00) /* no shift */
331 dbg_printf("[%s, %s]", tbl_regs
[get_nibble(inst
, 4)], tbl_regs
[get_nibble(inst
, 0)]);
332 else if (((inst
>> 4) & 0x01) == 0x00) /* immediate shift (there's no register shift) */
333 dbg_printf("[%s, %s, %s #%d]", tbl_regs
[get_nibble(inst
, 4)], tbl_regs
[get_nibble(inst
, 0)],
334 tbl_shifts
[(inst
>> 5) & 0x03], (inst
>> 7) & 0x1f);
341 dbg_printf("[%s], #%d", tbl_regs
[get_nibble(inst
, 4)], offset
);
342 else if (((inst
>> 4) & 0xff) == 0x00) /* no shift */
343 dbg_printf("[%s], %s", tbl_regs
[get_nibble(inst
, 4)], tbl_regs
[get_nibble(inst
, 0)]);
344 else if (((inst
>> 4) & 0x01) == 0x00) /* immediate shift (there's no register shift) */
345 dbg_printf("[%s], %s, %s #%d", tbl_regs
[get_nibble(inst
, 4)], tbl_regs
[get_nibble(inst
, 0)],
346 tbl_shifts
[(inst
>> 5) & 0x03], (inst
>> 7) & 0x1f);
353 static UINT
arm_disasm_blocktrans(UINT inst
, ADDRESS64
*addr
)
355 short load
= (inst
>> 20) & 0x01;
356 short writeback
= (inst
>> 21) & 0x01;
357 short psr
= (inst
>> 22) & 0x01;
358 short addrmode
= (inst
>> 23) & 0x03;
368 dbg_printf("\n\t%s%s%s\t%s%s, {", load
? "ldm" : "stm", tbl_addrmode
[addrmode
], get_cond(inst
),
369 tbl_regs
[get_nibble(inst
, 4)], writeback
? "!" : "");
373 if (i
== last
) dbg_printf("%s", tbl_regs
[i
]);
374 else dbg_printf("%s, ", tbl_regs
[i
]);
376 dbg_printf("}%s", psr
? "^" : "");
380 static UINT
arm_disasm_swi(UINT inst
, ADDRESS64
*addr
)
382 dbg_printf("\n\tswi%s\t#%d", get_cond(inst
), inst
& 0x00ffffff);
386 static UINT
arm_disasm_coproctrans(UINT inst
, ADDRESS64
*addr
)
388 WORD CRm
= inst
& 0x0f;
389 WORD CP
= (inst
>> 5) & 0x07;
390 WORD CPnum
= (inst
>> 8) & 0x0f;
391 WORD CRn
= (inst
>> 16) & 0x0f;
392 WORD load
= (inst
>> 20) & 0x01;
393 WORD CP_Opc
= (inst
>> 21) & 0x07;
395 dbg_printf("\n\t%s%s\t%u, %u, %s, cr%u, cr%u, {%u}", load
? "mrc" : "mcr", get_cond(inst
), CPnum
,
396 CP
, tbl_regs
[get_nibble(inst
, 3)], CRn
, CRm
, CP_Opc
);
400 static UINT
arm_disasm_coprocdataop(UINT inst
, ADDRESS64
*addr
)
402 WORD CRm
= inst
& 0x0f;
403 WORD CP
= (inst
>> 5) & 0x07;
404 WORD CPnum
= (inst
>> 8) & 0x0f;
405 WORD CRd
= (inst
>> 12) & 0x0f;
406 WORD CRn
= (inst
>> 16) & 0x0f;
407 WORD CP_Opc
= (inst
>> 20) & 0x0f;
409 dbg_printf("\n\tcdp%s\t%u, %u, cr%u, cr%u, cr%u, {%u}", get_cond(inst
),
410 CPnum
, CP
, CRd
, CRn
, CRm
, CP_Opc
);
414 static UINT
arm_disasm_coprocdatatrans(UINT inst
, ADDRESS64
*addr
)
416 WORD CPnum
= (inst
>> 8) & 0x0f;
417 WORD CRd
= (inst
>> 12) & 0x0f;
418 WORD load
= (inst
>> 20) & 0x01;
419 WORD writeback
= (inst
>> 21) & 0x01;
420 WORD translen
= (inst
>> 22) & 0x01;
421 WORD direction
= (inst
>> 23) & 0x01;
422 WORD indexing
= (inst
>> 24) & 0x01;
423 short offset
= (inst
& 0xff) << 2;
425 if (!direction
) offset
*= -1;
427 dbg_printf("\n\t%s%s%s", load
? "ldc" : "stc", translen
? "l" : "", get_cond(inst
));
429 dbg_printf("\t%u, cr%u, [%s, #%d]%s", CPnum
, CRd
, tbl_regs
[get_nibble(inst
, 4)], offset
, writeback
?"!":"");
431 dbg_printf("\t%u, cr%u, [%s], #%d", CPnum
, CRd
, tbl_regs
[get_nibble(inst
, 4)], offset
);
435 static WORD
thumb_disasm_hireg(WORD inst
, ADDRESS64
*addr
)
437 short dst
= inst
& 0x07;
438 short src
= (inst
>> 3) & 0x07;
439 short h2
= (inst
>> 6) & 0x01;
440 short h1
= (inst
>> 7) & 0x01;
441 short op
= (inst
>> 8) & 0x03;
446 if (op
== 2 && dst
== src
) /* mov rx, rx */
448 dbg_printf("\n\tnop");
453 dbg_printf("\n\tb%sx\t%s", h1
?"l":"", tbl_regs
[src
]);
455 dbg_printf("\n\t%s\t%s, %s", tbl_hiops_t
[op
], tbl_regs
[dst
], tbl_regs
[src
]);
460 static WORD
thumb_disasm_aluop(WORD inst
, ADDRESS64
*addr
)
462 short dst
= inst
& 0x07;
463 short src
= (inst
>> 3) & 0x07;
464 short op
= (inst
>> 6) & 0x0f;
466 dbg_printf("\n\t%s\t%s, %s", tbl_aluops_t
[op
], tbl_regs
[dst
], tbl_regs
[src
]);
471 static WORD
thumb_disasm_pushpop(WORD inst
, ADDRESS64
*addr
)
473 short lrpc
= (inst
>> 8) & 0x01;
474 short load
= (inst
>> 11) & 0x01;
479 if ((inst
>>i
) & 1) break;
482 dbg_printf("\n\t%s\t{", load
? "pop" : "push");
487 if (i
== last
) dbg_printf("%s", tbl_regs
[i
]);
488 else dbg_printf("%s, ", tbl_regs
[i
]);
491 dbg_printf("%s%s", last
? ", " : "", load
? "pc" : "lr");
497 static WORD
thumb_disasm_blocktrans(WORD inst
, ADDRESS64
*addr
)
499 short load
= (inst
>> 11) & 0x01;
504 if ((inst
>>i
) & 1) break;
507 dbg_printf("\n\t%s\t%s!, {", load
? "ldmia" : "stmia", tbl_regs
[(inst
>> 8) & 0x07]);
512 if (i
== last
) dbg_printf("%s", tbl_regs
[i
]);
513 else dbg_printf("%s, ", tbl_regs
[i
]);
520 static WORD
thumb_disasm_swi(WORD inst
, ADDRESS64
*addr
)
522 dbg_printf("\n\tswi\t#%d", inst
& 0x00ff);
526 static WORD
thumb_disasm_condbranch(WORD inst
, ADDRESS64
*addr
)
528 WORD offset
= inst
& 0x00ff;
529 dbg_printf("\n\tb%s\t", tbl_cond
[(inst
>> 8) & 0x0f]);
530 db_printsym(addr
->Offset
+ offset
);
534 static WORD
thumb_disasm_uncondbranch(WORD inst
, ADDRESS64
*addr
)
536 short offset
= (inst
& 0x07ff) << 1;
538 if (offset
& 0x0800) offset
|= 0xf000;
541 dbg_printf("\n\tb\t");
542 db_printsym(addr
->Offset
+ offset
);
546 static WORD
thumb_disasm_loadadr(WORD inst
, ADDRESS64
*addr
)
548 WORD src
= (inst
>> 11) & 0x01;
549 WORD offset
= (inst
& 0xff) << 2;
551 dbg_printf("\n\tadd\t%s, %s, #%d", tbl_regs
[(inst
>> 8) & 0x07], src
? "sp" : "pc", offset
);
555 static WORD
thumb_disasm_ldrpcrel(WORD inst
, ADDRESS64
*addr
)
557 WORD offset
= (inst
& 0xff) << 2;
558 dbg_printf("\n\tldr\t%s, [pc, #%u]", tbl_regs
[(inst
>> 8) & 0x07], offset
);
562 static WORD
thumb_disasm_ldrsprel(WORD inst
, ADDRESS64
*addr
)
564 WORD offset
= (inst
& 0xff) << 2;
565 dbg_printf("\n\t%s\t%s, [sp, #%u]", (inst
& 0x0800)?"ldr":"str", tbl_regs
[(inst
>> 8) & 0x07], offset
);
569 static WORD
thumb_disasm_addsprel(WORD inst
, ADDRESS64
*addr
)
571 WORD offset
= (inst
& 0x7f) << 2;
572 if ((inst
>> 7) & 0x01)
573 dbg_printf("\n\tsub\tsp, sp, #%u", offset
);
575 dbg_printf("\n\tadd\tsp, sp, #%u", offset
);
579 static WORD
thumb_disasm_ldrimm(WORD inst
, ADDRESS64
*addr
)
581 WORD offset
= (inst
& 0x07c0) >> 6;
582 dbg_printf("\n\t%s%s\t%s, [%s, #%u]", (inst
& 0x0800)?"ldr":"str", (inst
& 0x1000)?"b":"",
583 tbl_regs
[inst
& 0x07], tbl_regs
[(inst
>> 3) & 0x07], (inst
& 0x1000)?offset
:(offset
<< 2));
587 static WORD
thumb_disasm_ldrhimm(WORD inst
, ADDRESS64
*addr
)
589 WORD offset
= (inst
& 0x07c0) >> 5;
590 dbg_printf("\n\t%s\t%s, [%s, #%u]", (inst
& 0x0800)?"ldrh":"strh",
591 tbl_regs
[inst
& 0x07], tbl_regs
[(inst
>> 3) & 0x07], offset
);
595 static WORD
thumb_disasm_ldrreg(WORD inst
, ADDRESS64
*addr
)
597 dbg_printf("\n\t%s%s\t%s, [%s, %s]", (inst
& 0x0800)?"ldr":"str", (inst
& 0x0400)?"b":"",
598 tbl_regs
[inst
& 0x07], tbl_regs
[(inst
>> 3) & 0x07], tbl_regs
[(inst
>> 6) & 0x07]);
602 static WORD
thumb_disasm_ldrsreg(WORD inst
, ADDRESS64
*addr
)
604 dbg_printf("\n\t%s\t%s, [%s, %s]", tbl_sregops_t
[(inst
>> 10) & 0x03],
605 tbl_regs
[inst
& 0x07], tbl_regs
[(inst
>> 3) & 0x07], tbl_regs
[(inst
>> 6) & 0x07]);
609 static WORD
thumb_disasm_immop(WORD inst
, ADDRESS64
*addr
)
611 WORD op
= (inst
>> 11) & 0x03;
612 dbg_printf("\n\t%s\t%s, #%u", tbl_immops_t
[op
], tbl_regs
[(inst
>> 8) & 0x07], inst
& 0xff);
616 static WORD
thumb_disasm_nop(WORD inst
, ADDRESS64
*addr
)
618 dbg_printf("\n\tnop");
622 static WORD
thumb_disasm_addsub(WORD inst
, ADDRESS64
*addr
)
624 WORD op
= (inst
>> 9) & 0x01;
625 WORD immediate
= (inst
>> 10) & 0x01;
627 dbg_printf("\n\t%s\t%s, %s, ", op
? "sub" : "add",
628 tbl_regs
[inst
& 0x07], tbl_regs
[(inst
>> 3) & 0x07]);
630 dbg_printf("#%d", (inst
>> 6) & 0x07);
632 dbg_printf("%s", tbl_regs
[(inst
>> 6) & 0x07]);
636 static WORD
thumb_disasm_movshift(WORD inst
, ADDRESS64
*addr
)
638 WORD op
= (inst
>> 11) & 0x03;
639 dbg_printf("\n\t%s\t%s, %s, #%u", tbl_shifts
[op
],
640 tbl_regs
[inst
& 0x07], tbl_regs
[(inst
>> 3) & 0x07], (inst
>> 6) & 0x1f);
644 static UINT
thumb2_disasm_srtrans(UINT inst
, ADDRESS64
*addr
)
646 UINT fromsr
= (inst
>> 21) & 0x03;
647 UINT sysreg
= inst
& 0xff;
649 if (fromsr
== 3 && get_nibble(inst
,4) == 0x0f && sysreg
<= 20)
651 dbg_printf("\n\tmrs\t%s, %s", tbl_regs
[get_nibble(inst
, 2)], tbl_special_regs_t2
[sysreg
]);
655 if (fromsr
== 0 && sysreg
<= 20)
657 dbg_printf("\n\tmsr\t%s, %s", tbl_special_regs_t2
[sysreg
], tbl_regs
[get_nibble(inst
, 4)]);
664 static UINT
thumb2_disasm_hint(UINT inst
, ADDRESS64
*addr
)
666 WORD op1
= (inst
>> 8) & 0x07;
667 WORD op2
= inst
& 0xff;
669 if (op1
) return inst
;
673 dbg_printf("\n\t%s", tbl_hints_t2
[op2
]);
679 dbg_printf("\n\tdbg\t#%u", get_nibble(inst
, 0));
686 static UINT
thumb2_disasm_miscctrl(UINT inst
, ADDRESS64
*addr
)
688 WORD op
= (inst
>> 4) & 0x0f;
693 dbg_printf("\n\tclrex");
696 dbg_printf("\n\tdsb\t#%u", get_nibble(inst
, 0));
699 dbg_printf("\n\tdmb\t#%u", get_nibble(inst
, 0));
702 dbg_printf("\n\tisb\t#%u", get_nibble(inst
, 0));
711 static UINT
thumb2_disasm_branch(UINT inst
, ADDRESS64
*addr
)
713 UINT S
= (inst
>> 26) & 0x01;
714 UINT L
= (inst
>> 14) & 0x01;
715 UINT I1
= !(((inst
>> 13) & 0x01) ^ S
);
716 UINT C
= !((inst
>> 12) & 0x01);
717 UINT I2
= !(((inst
>> 11) & 0x01) ^ S
);
718 UINT offset
= (inst
& 0x000007ff) << 1;
722 offset
|= I1
<< 19 | I2
<< 18 | (inst
& 0x003f0000) >> 4;
723 if (S
) offset
|= 0x0fff << 20;
727 offset
|= I1
<< 23 | I2
<< 22 | (inst
& 0x03ff0000) >> 4;
728 if (S
) offset
|= 0xff << 24;
731 dbg_printf("\n\tb%s%s\t", L
? "l" : "", C
? tbl_cond
[(inst
>> 22) & 0x0f] : "");
732 db_printsym(addr
->Offset
+ offset
+ 4);
736 static UINT
thumb2_disasm_misc(UINT inst
, ADDRESS64
*addr
)
738 WORD op1
= (inst
>> 20) & 0x03;
739 WORD op2
= (inst
>> 4) & 0x03;
741 if (get_nibble(inst
, 4) != get_nibble(inst
, 0))
744 if (op1
== 3 && op2
== 0)
746 dbg_printf("\n\tclz\t%s, %s", tbl_regs
[get_nibble(inst
, 2)], tbl_regs
[get_nibble(inst
, 0)]);
752 dbg_printf("\n\t%s\t%s, %s", tbl_miscops_t2
[op2
], tbl_regs
[get_nibble(inst
, 2)],
753 tbl_regs
[get_nibble(inst
, 0)]);
760 static UINT
thumb2_disasm_dataprocessingreg(UINT inst
, ADDRESS64
*addr
)
762 WORD op1
= (inst
>> 20) & 0x07;
763 WORD op2
= (inst
>> 4) & 0x0f;
767 dbg_printf("\n\t%s%s\t%s, %s, %s", tbl_shifts
[op1
>> 1], (op1
& 1)?"s":"",
768 tbl_regs
[get_nibble(inst
, 2)], tbl_regs
[get_nibble(inst
, 4)],
769 tbl_regs
[get_nibble(inst
, 0)]);
773 if ((op2
& 0x0C) == 0x08 && get_nibble(inst
, 4) == 0x0f)
775 dbg_printf("\n\t%sxt%s\t%s, %s", (op1
& 1)?"u":"s", (op1
& 4)?"b":"h",
776 tbl_regs
[get_nibble(inst
, 2)], tbl_regs
[get_nibble(inst
, 0)]);
778 dbg_printf(", ROR #%u", (op2
& 3) * 8);
785 static UINT
thumb2_disasm_mul(UINT inst
, ADDRESS64
*addr
)
787 WORD op1
= (inst
>> 20) & 0x07;
788 WORD op2
= (inst
>> 4) & 0x03;
793 if (op2
== 0 && get_nibble(inst
, 3) != 0xf)
795 dbg_printf("\n\tmla\t%s, %s, %s, %s", tbl_regs
[get_nibble(inst
, 2)],
796 tbl_regs
[get_nibble(inst
, 4)],
797 tbl_regs
[get_nibble(inst
, 0)],
798 tbl_regs
[get_nibble(inst
, 3)]);
802 if (op2
== 0 && get_nibble(inst
, 3) == 0xf)
804 dbg_printf("\n\tmul\t%s, %s, %s", tbl_regs
[get_nibble(inst
, 2)],
805 tbl_regs
[get_nibble(inst
, 4)],
806 tbl_regs
[get_nibble(inst
, 0)]);
812 dbg_printf("\n\tmls\t%s, %s, %s, %s", tbl_regs
[get_nibble(inst
, 2)],
813 tbl_regs
[get_nibble(inst
, 4)],
814 tbl_regs
[get_nibble(inst
, 0)],
815 tbl_regs
[get_nibble(inst
, 3)]);
822 static UINT
thumb2_disasm_longmuldiv(UINT inst
, ADDRESS64
*addr
)
824 WORD op1
= (inst
>> 20) & 0x07;
825 WORD op2
= (inst
>> 4) & 0x0f;
832 dbg_printf("\n\tsmull\t");
835 dbg_printf("\n\tumull\t");
838 dbg_printf("\n\tsmlal\t");
841 dbg_printf("\n\tumlal\t");
846 dbg_printf("%s, %s, %s, %s", tbl_regs
[get_nibble(inst
, 3)], tbl_regs
[get_nibble(inst
, 2)],
847 tbl_regs
[get_nibble(inst
, 4)], tbl_regs
[get_nibble(inst
, 0)]);
856 dbg_printf("\n\tsdiv\t");
859 dbg_printf("\n\tudiv\t");
864 dbg_printf("%s, %s, %s", tbl_regs
[get_nibble(inst
, 2)], tbl_regs
[get_nibble(inst
, 4)],
865 tbl_regs
[get_nibble(inst
, 0)]);
872 static UINT
thumb2_disasm_str(UINT inst
, ADDRESS64
*addr
)
874 WORD op1
= (inst
>> 21) & 0x07;
875 WORD op2
= (inst
>> 6) & 0x3f;
877 if ((op1
& 0x03) == 3) return inst
;
879 if (!(op1
& 0x04) && inst
& 0x0800)
882 dbg_printf("\n\tstr%s\t%s, [%s", tbl_width_t2
[op1
& 0x03], tbl_regs
[get_nibble(inst
, 3)],
883 tbl_regs
[get_nibble(inst
, 4)]);
885 offset
= inst
& 0xff;
886 if (!(inst
& 0x0200)) offset
*= -1;
888 if (!(inst
& 0x0400) && (inst
& 0x0100)) dbg_printf("], #%i", offset
);
889 else if (inst
& 0x0400) dbg_printf(", #%i]%s", offset
, (inst
& 0x0100)?"!":"");
894 if (!(op1
& 0x04) && !op2
)
896 dbg_printf("\n\tstr%s\t%s, [%s, %s, LSL #%u]", tbl_width_t2
[op1
& 0x03],
897 tbl_regs
[get_nibble(inst
, 3)], tbl_regs
[get_nibble(inst
, 4)],
898 tbl_regs
[get_nibble(inst
, 0)], (inst
>> 4) & 0x3);
904 dbg_printf("\n\tstr%s\t%s, [%s, #%u]", tbl_width_t2
[op1
& 0x03],
905 tbl_regs
[get_nibble(inst
, 3)], tbl_regs
[get_nibble(inst
, 4)], inst
& 0x0fff);
912 static UINT
thumb2_disasm_ldrword(UINT inst
, ADDRESS64
*addr
)
914 WORD op1
= (inst
>> 23) & 0x01;
915 WORD op2
= (inst
>> 6) & 0x3f;
918 if (get_nibble(inst
, 4) == 0x0f)
920 offset
= inst
& 0x0fff;
922 if (!op1
) offset
*= -1;
925 dbg_printf("\n\tldr\t%s, ", tbl_regs
[get_nibble(inst
, 3)]);
926 db_printsym(addr
->Offset
+ offset
);
932 dbg_printf("\n\tldr\t%s, [%s, %s, LSL #%u]", tbl_regs
[get_nibble(inst
, 3)],
933 tbl_regs
[get_nibble(inst
, 4)], tbl_regs
[get_nibble(inst
, 0)], (inst
>> 4) & 0x3);
937 if (!op1
&& (op2
& 0x3c) == 0x38)
939 dbg_printf("\n\tldrt\t%s, [%s, #%u]", tbl_regs
[get_nibble(inst
, 3)],
940 tbl_regs
[get_nibble(inst
, 4)], inst
& 0xff);
944 dbg_printf("\n\tldr\t%s, [%s", tbl_regs
[get_nibble(inst
, 3)], tbl_regs
[get_nibble(inst
, 4)]);
948 dbg_printf(", #%u]", inst
& 0x0fff);
952 offset
= inst
& 0xff;
953 if (!(inst
& 0x0200)) offset
*= -1;
955 if (!(inst
& 0x0400) && (inst
& 0x0100)) dbg_printf("], #%i", offset
);
956 else if (inst
& 0x0400) dbg_printf(", #%i]%s", offset
, (inst
& 0x0100)?"!":"");
962 static UINT
thumb2_disasm_preload(UINT inst
, ADDRESS64
*addr
)
964 WORD op1
= (inst
>> 23) & 0x03;
966 if (!(op1
& 0x01) && !((inst
>> 6) & 0x3f) && get_nibble(inst
, 4) != 15)
968 WORD shift
= (inst
>> 4) & 0x03;
969 dbg_printf("\n\t%s\t[%s, %s", op1
?"pli":"pld", tbl_regs
[get_nibble(inst
, 4)],
970 tbl_regs
[get_nibble(inst
, 0)]);
971 if (shift
) dbg_printf(", lsl #%u]", shift
);
972 else dbg_printf("]");
976 if (get_nibble(inst
, 4) != 15)
978 dbg_printf("\n\t%s\t[%s, #%d]", (op1
& 0x02)?"pli":"pld", tbl_regs
[get_nibble(inst
, 4)],
979 (op1
& 0x01)?(inst
& 0x0fff):(-1 * (inst
& 0xff)));
983 if (get_nibble(inst
, 4) == 15)
985 int offset
= inst
& 0x0fff;
986 if (!op1
) offset
*= -1;
987 dbg_printf("\n\t%s\t", (op1
& 0x02)?"pli":"pld");
988 db_printsym(addr
->Offset
+ offset
+ 4);
995 static UINT
thumb2_disasm_ldrnonword(UINT inst
, ADDRESS64
*addr
)
997 WORD op1
= (inst
>> 23) & 0x03;
998 WORD hw
= (inst
>> 21) & 0x01;
1000 if (!(op1
& 0x01) && !((inst
>> 6) & 0x3f) && get_nibble(inst
, 4) != 15)
1002 WORD shift
= (inst
>> 4) & 0x03;
1003 dbg_printf("\n\t%s%s\t%s, [%s, %s", op1
?"ldrs":"ldr", hw
?"h":"b",
1004 tbl_regs
[get_nibble(inst
, 3)], tbl_regs
[get_nibble(inst
, 4)],
1005 tbl_regs
[get_nibble(inst
, 0)]);
1006 if (shift
) dbg_printf(", lsl #%u]", shift
);
1007 else dbg_printf("]");
1011 if (!(op1
& 0x01) && ((inst
>> 8) & 0x0f) == 14 && get_nibble(inst
, 4) != 15)
1013 WORD offset
= inst
& 0xff;
1014 dbg_printf("\n\t%s%s\t%s, [%s", op1
?"ldrs":"ldr", hw
?"ht":"bt",
1015 tbl_regs
[get_nibble(inst
, 3)], tbl_regs
[get_nibble(inst
, 4)]);
1016 if (offset
) dbg_printf(", #%u]", offset
);
1017 else dbg_printf("]");
1021 if (get_nibble(inst
, 4) != 15)
1025 dbg_printf("\n\t%s%s\t%s, [%s", (op1
& 0x02)?"ldrs":"ldr", hw
?"h":"b",
1026 tbl_regs
[get_nibble(inst
, 3)], tbl_regs
[get_nibble(inst
, 4)]);
1030 dbg_printf(", #%u]", inst
& 0x0fff);
1034 offset
= inst
& 0xff;
1035 if (!(inst
& 0x0200)) offset
*= -1;
1037 if (!(inst
& 0x0400) && (inst
& 0x0100)) dbg_printf("], #%i", offset
);
1038 else if (inst
& 0x0400) dbg_printf(", #%i]%s", offset
, (inst
& 0x0100)?"!":"");
1044 if (get_nibble(inst
, 4) == 15)
1046 int offset
= inst
& 0x0fff;
1047 if (!op1
) offset
*= -1;
1048 dbg_printf("\n\t%s%s\t%s, ", (op1
& 0x02)?"ldrs":"ldr", hw
?"h":"b",
1049 tbl_regs
[get_nibble(inst
, 3)]);
1050 db_printsym(addr
->Offset
+ offset
+ 4);
1057 static UINT
thumb2_disasm_coprocdat(UINT inst
, ADDRESS64
*addr
)
1059 WORD opc2
= (inst
>> 5) & 0x07;
1061 dbg_printf("\n\tcdp%s\tp%u, #%u, cr%u, cr%u, cr%u", (inst
& 0x10000000)?"2":"",
1062 get_nibble(inst
, 2), get_nibble(inst
, 5), get_nibble(inst
, 3),
1063 get_nibble(inst
, 4), get_nibble(inst
, 0));
1065 if (opc2
) dbg_printf(", #%u", opc2
);
1069 static UINT
thumb2_disasm_coprocmov1(UINT inst
, ADDRESS64
*addr
)
1071 WORD opc1
= (inst
>> 21) & 0x07;
1072 WORD opc2
= (inst
>> 5) & 0x07;
1074 dbg_printf("\n\t%s%s\tp%u, #%u, %s, cr%u, cr%u", (inst
& 0x00100000)?"mrc":"mcr",
1075 (inst
& 0x10000000)?"2":"", get_nibble(inst
, 2), opc1
,
1076 tbl_regs
[get_nibble(inst
, 3)], get_nibble(inst
, 4), get_nibble(inst
, 0));
1078 if (opc2
) dbg_printf(", #%u", opc2
);
1082 static UINT
thumb2_disasm_coprocmov2(UINT inst
, ADDRESS64
*addr
)
1084 dbg_printf("\n\t%s%s\tp%u, #%u, %s, %s, cr%u", (inst
& 0x00100000)?"mrrc":"mcrr",
1085 (inst
& 0x10000000)?"2":"", get_nibble(inst
, 2), get_nibble(inst
, 1),
1086 tbl_regs
[get_nibble(inst
, 3)], tbl_regs
[get_nibble(inst
, 4)], get_nibble(inst
, 0));
1091 static UINT
thumb2_disasm_coprocdatatrans(UINT inst
, ADDRESS64
*addr
)
1093 WORD indexing
= (inst
>> 24) & 0x01;
1094 WORD direction
= (inst
>> 23) & 0x01;
1095 WORD translen
= (inst
>> 22) & 0x01;
1096 WORD writeback
= (inst
>> 21) & 0x01;
1097 WORD load
= (inst
>> 20) & 0x01;
1098 short offset
= (inst
& 0xff) << 2;
1100 if (!direction
) offset
*= -1;
1102 dbg_printf("\n\t%s%s%s", load
? "ldc" : "stc", (inst
& 0x10000000)?"2":"", translen
? "l" : "");
1105 if (load
&& get_nibble(inst
, 4) == 15)
1107 dbg_printf("\tp%u, cr%u, ", get_nibble(inst
, 2), get_nibble(inst
, 3));
1108 db_printsym(addr
->Offset
+ offset
+ 4);
1111 dbg_printf("\tp%u, cr%u, [%s, #%d]%s", get_nibble(inst
, 2), get_nibble(inst
, 3), tbl_regs
[get_nibble(inst
, 4)], offset
, writeback
?"!":"");
1116 dbg_printf("\tp%u, cr%u, [%s], #%d", get_nibble(inst
, 2), get_nibble(inst
, 3), tbl_regs
[get_nibble(inst
, 4)], offset
);
1118 dbg_printf("\tp%u, cr%u, [%s], {%u}", get_nibble(inst
, 2), get_nibble(inst
, 3), tbl_regs
[get_nibble(inst
, 4)], inst
& 0xff);
1127 UINT (*func
)(UINT
, ADDRESS64
*);
1130 static const struct inst_arm tbl_arm
[] = {
1131 { 0x0e000000, 0x0a000000, arm_disasm_branch
},
1132 { 0x0fc000f0, 0x00000090, arm_disasm_mul
},
1133 { 0x0f8000f0, 0x00800090, arm_disasm_longmul
},
1134 { 0x0fb00ff0, 0x01000090, arm_disasm_swp
},
1135 { 0x0e000090, 0x00000090, arm_disasm_halfwordtrans
},
1136 { 0x0ffffff0, 0x012fff00, arm_disasm_branchreg
},
1137 { 0x0ffffff0, 0x012fff10, arm_disasm_branchxchg
},
1138 { 0x0fbf0fff, 0x010f0000, arm_disasm_mrstrans
},
1139 { 0x0dbef000, 0x0128f000, arm_disasm_msrtrans
},
1140 { 0x0fb00000, 0x03000000, arm_disasm_wordmov
},
1141 { 0x0fffffff, 0x0320f000, arm_disasm_nop
},
1142 { 0x0c000000, 0x00000000, arm_disasm_dataprocessing
},
1143 { 0x0c000000, 0x04000000, arm_disasm_singletrans
},
1144 { 0x0e000000, 0x08000000, arm_disasm_blocktrans
},
1145 { 0x0f000000, 0x0f000000, arm_disasm_swi
},
1146 { 0x0f000010, 0x0e000010, arm_disasm_coproctrans
},
1147 { 0x0f000010, 0x0e000000, arm_disasm_coprocdataop
},
1148 { 0x0e000000, 0x0c000000, arm_disasm_coprocdatatrans
},
1149 { 0x00000000, 0x00000000, NULL
}
1156 WORD (*func
)(WORD
, ADDRESS64
*);
1159 static const struct inst_thumb16 tbl_thumb16
[] = {
1160 { 0xfc00, 0x4400, thumb_disasm_hireg
},
1161 { 0xfc00, 0x4000, thumb_disasm_aluop
},
1162 { 0xf600, 0xb400, thumb_disasm_pushpop
},
1163 { 0xf000, 0xc000, thumb_disasm_blocktrans
},
1164 { 0xff00, 0xdf00, thumb_disasm_swi
},
1165 { 0xf000, 0xd000, thumb_disasm_condbranch
},
1166 { 0xf800, 0xe000, thumb_disasm_uncondbranch
},
1167 { 0xf000, 0xa000, thumb_disasm_loadadr
},
1168 { 0xf800, 0x4800, thumb_disasm_ldrpcrel
},
1169 { 0xf000, 0x9000, thumb_disasm_ldrsprel
},
1170 { 0xff00, 0xb000, thumb_disasm_addsprel
},
1171 { 0xe000, 0x6000, thumb_disasm_ldrimm
},
1172 { 0xf000, 0x8000, thumb_disasm_ldrhimm
},
1173 { 0xf200, 0x5000, thumb_disasm_ldrreg
},
1174 { 0xf200, 0x5200, thumb_disasm_ldrsreg
},
1175 { 0xe000, 0x2000, thumb_disasm_immop
},
1176 { 0xff00, 0xbf00, thumb_disasm_nop
},
1177 { 0xf800, 0x1800, thumb_disasm_addsub
},
1178 { 0xe000, 0x0000, thumb_disasm_movshift
},
1179 { 0x0000, 0x0000, NULL
}
1182 static const struct inst_arm tbl_thumb32
[] = {
1183 { 0xfff0f000, 0xf3e08000, thumb2_disasm_srtrans
},
1184 { 0xfff0f000, 0xf3808000, thumb2_disasm_srtrans
},
1185 { 0xfff0d000, 0xf3a08000, thumb2_disasm_hint
},
1186 { 0xfff0d000, 0xf3b08000, thumb2_disasm_miscctrl
},
1187 { 0xf8008000, 0xf0008000, thumb2_disasm_branch
},
1188 { 0xffc0f0c0, 0xfa80f080, thumb2_disasm_misc
},
1189 { 0xff80f000, 0xfa00f000, thumb2_disasm_dataprocessingreg
},
1190 { 0xff8000c0, 0xfb000000, thumb2_disasm_mul
},
1191 { 0xff8000f0, 0xfb800000, thumb2_disasm_longmuldiv
},
1192 { 0xff8000f0, 0xfb8000f0, thumb2_disasm_longmuldiv
},
1193 { 0xff100000, 0xf8000000, thumb2_disasm_str
},
1194 { 0xff700000, 0xf8500000, thumb2_disasm_ldrword
},
1195 { 0xfe70f000, 0xf810f000, thumb2_disasm_preload
},
1196 { 0xfe500000, 0xf8100000, thumb2_disasm_ldrnonword
},
1197 { 0xef000010, 0xee000000, thumb2_disasm_coprocdat
},
1198 { 0xef000010, 0xee000010, thumb2_disasm_coprocmov1
},
1199 { 0xefe00000, 0xec400000, thumb2_disasm_coprocmov2
},
1200 { 0xee000000, 0xec000000, thumb2_disasm_coprocdatatrans
},
1201 { 0x00000000, 0x00000000, NULL
}
1204 /***********************************************************************
1207 * Disassemble instruction at 'addr'. addr is changed to point to the
1208 * start of the next instruction.
1210 void be_arm_disasm_one_insn(ADDRESS64
*addr
, int display
)
1212 struct inst_arm
*a_ptr
= (struct inst_arm
*)&tbl_arm
;
1213 struct inst_thumb16
*t_ptr
= (struct inst_thumb16
*)&tbl_thumb16
;
1214 struct inst_arm
*t2_ptr
= (struct inst_arm
*)&tbl_thumb32
;
1223 if (!memory_get_register(CV_ARM_CPSR
, &pval
, tmp
, sizeof(tmp
)))
1224 dbg_printf("\n\tmemory_get_register failed: %s", tmp
);
1226 db_disasm_thumb
= (*pval
& 0x20) != 0;
1228 db_display
= display
;
1230 if (!db_disasm_thumb
)
1232 size
= ARM_INSN_SIZE
;
1233 inst
= db_get_inst( memory_to_linear_addr(addr
), size
);
1234 while (a_ptr
->func
) {
1235 if ((inst
& a_ptr
->mask
) == a_ptr
->pattern
) {
1243 dbg_printf("\n\tUnknown ARM Instruction: %08x", inst
);
1244 addr
->Offset
+= size
;
1248 if (!a_ptr
->func(inst
, addr
))
1249 addr
->Offset
+= size
;
1255 WORD
*taddr
= memory_to_linear_addr(addr
);
1256 tinst
= db_get_inst( taddr
, THUMB_INSN_SIZE
);
1257 switch (tinst
& 0xf800)
1262 size
= THUMB2_INSN_SIZE
;
1264 inst
= db_get_inst( taddr
, THUMB_INSN_SIZE
);
1265 inst
|= (tinst
<< 16);
1267 while (t2_ptr
->func
) {
1268 if ((inst
& t2_ptr
->mask
) == t2_ptr
->pattern
) {
1276 dbg_printf("\n\tUnknown Thumb2 Instruction: %08x", inst
);
1277 addr
->Offset
+= size
;
1281 if (!t2_ptr
->func(inst
, addr
))
1282 addr
->Offset
+= size
;
1289 size
= THUMB_INSN_SIZE
;
1290 while (t_ptr
->func
) {
1291 if ((tinst
& t_ptr
->mask
) == t_ptr
->pattern
) {
1299 dbg_printf("\n\tUnknown Thumb Instruction: %04x", tinst
);
1300 addr
->Offset
+= size
;
1304 if (!t_ptr
->func(tinst
, addr
))
1305 addr
->Offset
+= size
;
1311 static unsigned be_arm_get_addr(HANDLE hThread
, const CONTEXT
* ctx
,
1312 enum be_cpu_addr bca
, ADDRESS64
* addr
)
1316 case be_cpu_addr_pc
:
1317 return be_cpu_build_addr(hThread
, ctx
, addr
, 0, ctx
->Pc
);
1318 case be_cpu_addr_stack
:
1319 return be_cpu_build_addr(hThread
, ctx
, addr
, 0, ctx
->Sp
);
1320 case be_cpu_addr_frame
:
1321 return be_cpu_build_addr(hThread
, ctx
, addr
, 0, ctx
->Fp
);
1326 static unsigned be_arm_get_register_info(int regno
, enum be_cpu_addr
* kind
)
1330 case CV_ARM_PC
: *kind
= be_cpu_addr_pc
; return TRUE
;
1331 case CV_ARM_R0
+ 11: *kind
= be_cpu_addr_frame
; return TRUE
;
1332 case CV_ARM_SP
: *kind
= be_cpu_addr_stack
; return TRUE
;
1337 static void be_arm_single_step(CONTEXT
* ctx
, unsigned enable
)
1339 dbg_printf("be_arm_single_step: not done\n");
1342 static void be_arm_print_context(HANDLE hThread
, const CONTEXT
* ctx
, int all_regs
)
1344 static const char condflags
[] = "NZCV";
1348 switch (ctx
->Cpsr
& 0x1F)
1350 case 0: strcpy(buf
, "User26"); break;
1351 case 1: strcpy(buf
, "FIQ26"); break;
1352 case 2: strcpy(buf
, "IRQ26"); break;
1353 case 3: strcpy(buf
, "SVC26"); break;
1354 case 16: strcpy(buf
, "User"); break;
1355 case 17: strcpy(buf
, "FIQ"); break;
1356 case 18: strcpy(buf
, "IRQ"); break;
1357 case 19: strcpy(buf
, "SVC"); break;
1358 case 23: strcpy(buf
, "ABT"); break;
1359 case 27: strcpy(buf
, "UND"); break;
1360 default: strcpy(buf
, "UNKNWN"); break;
1363 dbg_printf("Register dump:\n");
1364 dbg_printf("%s %s Mode\n", (ctx
->Cpsr
& 0x20) ? "Thumb" : "ARM", buf
);
1366 strcpy(buf
, condflags
);
1367 for (i
= 0; buf
[i
]; i
++)
1368 if (!((ctx
->Cpsr
>> 26) & (1 << (sizeof(condflags
) - i
))))
1371 dbg_printf(" Pc:%04x Sp:%04x Lr:%04x Cpsr:%04x(%s)\n",
1372 ctx
->Pc
, ctx
->Sp
, ctx
->Lr
, ctx
->Cpsr
, buf
);
1373 dbg_printf(" r0:%04x r1:%04x r2:%04x r3:%04x\n",
1374 ctx
->R0
, ctx
->R1
, ctx
->R2
, ctx
->R3
);
1375 dbg_printf(" r4:%04x r5:%04x r6:%04x r7:%04x r8:%04x\n",
1376 ctx
->R4
, ctx
->R5
, ctx
->R6
, ctx
->R7
, ctx
->R8
);
1377 dbg_printf(" r9:%04x r10:%04x Fp:%04x Ip:%04x\n",
1378 ctx
->R9
, ctx
->R10
, ctx
->Fp
, ctx
->Ip
);
1380 if (all_regs
) dbg_printf( "Floating point ARM dump not implemented\n" );
1383 static void be_arm_print_segment_info(HANDLE hThread
, const CONTEXT
* ctx
)
1387 static struct dbg_internal_var be_arm_ctx
[] =
1389 {CV_ARM_R0
+ 0, "r0", (DWORD_PTR
*)FIELD_OFFSET(CONTEXT
, R0
), dbg_itype_unsigned_int
},
1390 {CV_ARM_R0
+ 1, "r1", (DWORD_PTR
*)FIELD_OFFSET(CONTEXT
, R1
), dbg_itype_unsigned_int
},
1391 {CV_ARM_R0
+ 2, "r2", (DWORD_PTR
*)FIELD_OFFSET(CONTEXT
, R2
), dbg_itype_unsigned_int
},
1392 {CV_ARM_R0
+ 3, "r3", (DWORD_PTR
*)FIELD_OFFSET(CONTEXT
, R3
), dbg_itype_unsigned_int
},
1393 {CV_ARM_R0
+ 4, "r4", (DWORD_PTR
*)FIELD_OFFSET(CONTEXT
, R4
), dbg_itype_unsigned_int
},
1394 {CV_ARM_R0
+ 5, "r5", (DWORD_PTR
*)FIELD_OFFSET(CONTEXT
, R5
), dbg_itype_unsigned_int
},
1395 {CV_ARM_R0
+ 6, "r6", (DWORD_PTR
*)FIELD_OFFSET(CONTEXT
, R6
), dbg_itype_unsigned_int
},
1396 {CV_ARM_R0
+ 7, "r7", (DWORD_PTR
*)FIELD_OFFSET(CONTEXT
, R7
), dbg_itype_unsigned_int
},
1397 {CV_ARM_R0
+ 8, "r8", (DWORD_PTR
*)FIELD_OFFSET(CONTEXT
, R8
), dbg_itype_unsigned_int
},
1398 {CV_ARM_R0
+ 9, "r9", (DWORD_PTR
*)FIELD_OFFSET(CONTEXT
, R9
), dbg_itype_unsigned_int
},
1399 {CV_ARM_R0
+ 10, "r10", (DWORD_PTR
*)FIELD_OFFSET(CONTEXT
, R10
), dbg_itype_unsigned_int
},
1400 {CV_ARM_R0
+ 11, "r11", (DWORD_PTR
*)FIELD_OFFSET(CONTEXT
, Fp
), dbg_itype_unsigned_int
},
1401 {CV_ARM_R0
+ 12, "r12", (DWORD_PTR
*)FIELD_OFFSET(CONTEXT
, Ip
), dbg_itype_unsigned_int
},
1402 {CV_ARM_SP
, "sp", (DWORD_PTR
*)FIELD_OFFSET(CONTEXT
, Sp
), dbg_itype_unsigned_int
},
1403 {CV_ARM_LR
, "lr", (DWORD_PTR
*)FIELD_OFFSET(CONTEXT
, Lr
), dbg_itype_unsigned_int
},
1404 {CV_ARM_PC
, "pc", (DWORD_PTR
*)FIELD_OFFSET(CONTEXT
, Pc
), dbg_itype_unsigned_int
},
1405 {CV_ARM_CPSR
, "cpsr", (DWORD_PTR
*)FIELD_OFFSET(CONTEXT
, Cpsr
), dbg_itype_unsigned_int
},
1406 {0, NULL
, 0, dbg_itype_none
}
1409 static unsigned be_arm_is_step_over_insn(const void* insn
)
1411 dbg_printf("be_arm_is_step_over_insn: not done\n");
1415 static unsigned be_arm_is_function_return(const void* insn
)
1417 dbg_printf("be_arm_is_function_return: not done\n");
1421 static unsigned be_arm_is_break_insn(const void* insn
)
1423 dbg_printf("be_arm_is_break_insn: not done\n");
1427 static unsigned be_arm_is_func_call(const void* insn
, ADDRESS64
* callee
)
1432 static unsigned be_arm_is_jump(const void* insn
, ADDRESS64
* jumpee
)
1437 static unsigned be_arm_insert_Xpoint(HANDLE hProcess
, const struct be_process_io
* pio
,
1438 CONTEXT
* ctx
, enum be_xpoint_type type
,
1439 void* addr
, unsigned long* val
, unsigned size
)
1445 case be_xpoint_break
:
1446 if (!size
) return 0;
1447 if (!pio
->read(hProcess
, addr
, val
, 4, &sz
) || sz
!= 4) return 0;
1449 dbg_printf("Unknown/unsupported bp type %c\n", type
);
1455 static unsigned be_arm_remove_Xpoint(HANDLE hProcess
, const struct be_process_io
* pio
,
1456 CONTEXT
* ctx
, enum be_xpoint_type type
,
1457 void* addr
, unsigned long val
, unsigned size
)
1463 case be_xpoint_break
:
1464 if (!size
) return 0;
1465 if (!pio
->write(hProcess
, addr
, &val
, 4, &sz
) || sz
== 4) return 0;
1468 dbg_printf("Unknown/unsupported bp type %c\n", type
);
1474 static unsigned be_arm_is_watchpoint_set(const CONTEXT
* ctx
, unsigned idx
)
1476 dbg_printf("be_arm_is_watchpoint_set: not done\n");
1480 static void be_arm_clear_watchpoint(CONTEXT
* ctx
, unsigned idx
)
1482 dbg_printf("be_arm_clear_watchpoint: not done\n");
1485 static int be_arm_adjust_pc_for_break(CONTEXT
* ctx
, BOOL way
)
1487 INT step
= (ctx
->Cpsr
& 0x20) ? 2 : 4;
1498 static int be_arm_fetch_integer(const struct dbg_lvalue
* lvalue
, unsigned size
,
1499 unsigned ext_sign
, LONGLONG
* ret
)
1501 if (size
!= 1 && size
!= 2 && size
!= 4 && size
!= 8) return FALSE
;
1503 memset(ret
, 0, sizeof(*ret
)); /* clear unread bytes */
1504 /* FIXME: this assumes that debuggee and debugger use the same
1505 * integral representation
1507 if (!memory_read_value(lvalue
, size
, ret
)) return FALSE
;
1509 /* propagate sign information */
1510 if (ext_sign
&& size
< 8 && (*ret
>> (size
* 8 - 1)) != 0)
1513 *ret
|= neg
<< (size
* 8);
1518 static int be_arm_fetch_float(const struct dbg_lvalue
* lvalue
, unsigned size
,
1521 char tmp
[sizeof(long double)];
1523 /* FIXME: this assumes that debuggee and debugger use the same
1524 * representation for reals
1526 if (!memory_read_value(lvalue
, size
, tmp
)) return FALSE
;
1530 case sizeof(float): *ret
= *(float*)tmp
; break;
1531 case sizeof(double): *ret
= *(double*)tmp
; break;
1532 default: return FALSE
;
1537 static int be_arm_store_integer(const struct dbg_lvalue
* lvalue
, unsigned size
,
1538 unsigned is_signed
, LONGLONG val
)
1540 /* this is simple if we're on a little endian CPU */
1541 return memory_write_value(lvalue
, size
, &val
);
1544 struct backend_cpu be_arm
=
1546 IMAGE_FILE_MACHINE_ARMNT
,
1551 be_arm_get_register_info
,
1553 be_arm_print_context
,
1554 be_arm_print_segment_info
,
1556 be_arm_is_step_over_insn
,
1557 be_arm_is_function_return
,
1558 be_arm_is_break_insn
,
1559 be_arm_is_func_call
,
1561 be_arm_disasm_one_insn
,
1562 be_arm_insert_Xpoint
,
1563 be_arm_remove_Xpoint
,
1564 be_arm_is_watchpoint_set
,
1565 be_arm_clear_watchpoint
,
1566 be_arm_adjust_pc_for_break
,
1567 be_arm_fetch_integer
,
1569 be_arm_store_integer
,