msadp32.acm: Avoid ARRAY_SIZE-like macros.
[wine.git] / programs / winedbg / be_arm.c
blobad0e2857cda2cf56c9defaa5b766f2429af3d74a
1 /*
2 * Debugger ARM specific functions
4 * Copyright 2010-2013 André Hentschel
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "debugger.h"
23 #if defined(__arm__) && !defined(__ARMEB__)
26 * Switch to disassemble Thumb code.
28 static BOOL db_disasm_thumb = FALSE;
31 * Flag to indicate whether we need to display instruction,
32 * or whether we just need to know the address of the next
33 * instruction.
35 static BOOL db_display = FALSE;
37 #define ARM_INSN_SIZE 4
38 #define THUMB_INSN_SIZE 2
39 #define THUMB2_INSN_SIZE 4
41 #define ROR32(n, r) (((n) >> (r)) | ((n) << (32 - (r))))
43 #define get_cond(ins) tbl_cond[(ins >> 28) & 0x0f]
44 #define get_nibble(ins, num) ((ins >> (num * 4)) & 0x0f)
46 static char const tbl_regs[][4] = {
47 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",
48 "fp", "ip", "sp", "lr", "pc", "cpsr"
51 static char const tbl_addrmode[][3] = {
52 "da", "ia", "db", "ib"
55 static char const tbl_cond[][3] = {
56 "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", "hi", "ls", "ge", "lt", "gt", "le", "", ""
59 static char const tbl_dataops[][4] = {
60 "and", "eor", "sub", "rsb", "add", "adc", "sbc", "rsc", "tst", "teq", "cmp", "cmn", "orr",
61 "mov", "bic", "mvn"
64 static char const tbl_shifts[][4] = {
65 "lsl", "lsr", "asr", "ror"
68 static char const tbl_hiops_t[][4] = {
69 "add", "cmp", "mov", "bx"
72 static char const tbl_aluops_t[][4] = {
73 "and", "eor", "lsl", "lsr", "asr", "adc", "sbc", "ror", "tst", "neg", "cmp", "cmn", "orr",
74 "mul", "bic", "mvn"
77 static char const tbl_immops_t[][4] = {
78 "mov", "cmp", "add", "sub"
81 static char const tbl_sregops_t[][5] = {
82 "strh", "ldsb", "ldrh", "ldsh"
85 static char const tbl_miscops_t2[][6] = {
86 "rev", "rev16", "rbit", "revsh"
89 static char const tbl_width_t2[][2] = {
90 "b", "h", "", "?"
93 static char const tbl_special_regs_t2[][12] = {
94 "apsr", "iapsr", "eapsr", "xpsr", "rsvd", "ipsr", "epsr", "iepsr", "msp", "psp", "rsvd", "rsvd",
95 "rsvd", "rsvd", "rsvd", "rsvd", "primask", "basepri", "basepri_max", "faultmask", "control"
98 static char const tbl_hints_t2[][6] = {
99 "nop", "yield", "wfe", "wfi", "sev"
102 static UINT db_get_inst(void* addr, int size)
104 UINT result = 0;
105 char buffer[4];
107 if (dbg_read_memory(addr, buffer, size))
109 switch (size)
111 case 4:
112 result = *(UINT*)buffer;
113 break;
114 case 2:
115 result = *(WORD*)buffer;
116 break;
119 return result;
122 static void db_printsym(unsigned int addr)
124 ADDRESS64 a;
126 a.Mode = AddrModeFlat;
127 a.Offset = addr;
129 print_address(&a, TRUE);
132 static UINT arm_disasm_branch(UINT inst, ADDRESS64 *addr)
134 short link = (inst >> 24) & 0x01;
135 int offset = (inst << 2) & 0x03ffffff;
137 if (offset & 0x02000000) offset |= 0xfc000000;
138 offset += 8;
140 dbg_printf("\n\tb%s%s\t", link ? "l" : "", get_cond(inst));
141 db_printsym(addr->Offset + offset);
142 return 0;
145 static UINT arm_disasm_mul(UINT inst, ADDRESS64 *addr)
147 short accu = (inst >> 21) & 0x01;
148 short condcodes = (inst >> 20) & 0x01;
150 if (accu)
151 dbg_printf("\n\tmla%s%s\t%s, %s, %s, %s", get_cond(inst), condcodes ? "s" : "",
152 tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)],
153 tbl_regs[get_nibble(inst, 2)], tbl_regs[get_nibble(inst, 3)]);
154 else
155 dbg_printf("\n\tmul%s%s\t%s, %s, %s", get_cond(inst), condcodes ? "s" : "",
156 tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)],
157 tbl_regs[get_nibble(inst, 2)]);
158 return 0;
161 static UINT arm_disasm_longmul(UINT inst, ADDRESS64 *addr)
163 short sign = (inst >> 22) & 0x01;
164 short accu = (inst >> 21) & 0x01;
165 short condcodes = (inst >> 20) & 0x01;
167 dbg_printf("\n\t%s%s%s%s\t%s, %s, %s, %s", sign ? "s" : "u", accu ? "mlal" : "mull",
168 get_cond(inst), condcodes ? "s" : "",
169 tbl_regs[get_nibble(inst, 3)], tbl_regs[get_nibble(inst, 4)],
170 tbl_regs[get_nibble(inst, 0)], tbl_regs[get_nibble(inst, 2)]);
171 return 0;
174 static UINT arm_disasm_swp(UINT inst, ADDRESS64 *addr)
176 short byte = (inst >> 22) & 0x01;
178 dbg_printf("\n\tswp%s%s\t%s, %s, [%s]", get_cond(inst), byte ? "b" : "",
179 tbl_regs[get_nibble(inst, 3)], tbl_regs[get_nibble(inst, 0)],
180 tbl_regs[get_nibble(inst, 4)]);
181 return 0;
184 static UINT arm_disasm_halfwordtrans(UINT inst, ADDRESS64 *addr)
186 short halfword = (inst >> 5) & 0x01;
187 short sign = (inst >> 6) & 0x01;
188 short load = (inst >> 20) & 0x01;
189 short writeback = (inst >> 21) & 0x01;
190 short immediate = (inst >> 22) & 0x01;
191 short direction = (inst >> 23) & 0x01;
192 short indexing = (inst >> 24) & 0x01;
193 short offset = ((inst >> 4) & 0xf0) + (inst & 0x0f);
195 if (!direction) offset *= -1;
197 dbg_printf("\n\t%s%s%s%s%s", load ? "ldr" : "str", sign ? "s" : "",
198 halfword ? "h" : (sign ? "b" : ""), writeback ? "t" : "", get_cond(inst));
199 dbg_printf("\t%s, ", tbl_regs[get_nibble(inst, 3)]);
200 if (indexing)
202 if (immediate)
203 dbg_printf("[%s, #%d]", tbl_regs[get_nibble(inst, 4)], offset);
204 else
205 dbg_printf("[%s, %s]", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
207 else
209 if (immediate)
210 dbg_printf("[%s], #%d", tbl_regs[get_nibble(inst, 4)], offset);
211 else
212 dbg_printf("[%s], %s", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
214 return 0;
217 static UINT arm_disasm_branchreg(UINT inst, ADDRESS64 *addr)
219 dbg_printf("\n\tb%s\t%s", get_cond(inst), tbl_regs[get_nibble(inst, 0)]);
220 return 0;
223 static UINT arm_disasm_branchxchg(UINT inst, ADDRESS64 *addr)
225 dbg_printf("\n\tbx%s\t%s", get_cond(inst), tbl_regs[get_nibble(inst, 0)]);
226 return 0;
229 static UINT arm_disasm_mrstrans(UINT inst, ADDRESS64 *addr)
231 short src = (inst >> 22) & 0x01;
233 dbg_printf("\n\tmrs%s\t%s, %s", get_cond(inst), tbl_regs[get_nibble(inst, 3)],
234 src ? "spsr" : "cpsr");
235 return 0;
238 static UINT arm_disasm_msrtrans(UINT inst, ADDRESS64 *addr)
240 short immediate = (inst >> 25) & 0x01;
241 short dst = (inst >> 22) & 0x01;
242 short simple = (inst >> 16) & 0x01;
244 if (simple || !immediate)
246 dbg_printf("\n\tmsr%s\t%s, %s", get_cond(inst), dst ? "spsr" : "cpsr",
247 tbl_regs[get_nibble(inst, 0)]);
248 return 0;
251 dbg_printf("\n\tmsr%s\t%s, #%u", get_cond(inst), dst ? "spsr" : "cpsr",
252 ROR32(inst & 0xff, 2 * get_nibble(inst, 2)));
253 return 0;
256 static UINT arm_disasm_wordmov(UINT inst, ADDRESS64 *addr)
258 short top = (inst >> 22) & 0x01;
260 dbg_printf("\n\tmov%s%s\t%s, #%u", top ? "t" : "w", get_cond(inst),
261 tbl_regs[get_nibble(inst, 3)], (get_nibble(inst, 4) << 12) | (inst & 0x0fff));
262 return 0;
265 static UINT arm_disasm_nop(UINT inst, ADDRESS64 *addr)
267 dbg_printf("\n\tnop%s", get_cond(inst));
268 return 0;
271 static UINT arm_disasm_dataprocessing(UINT inst, ADDRESS64 *addr)
273 short condcodes = (inst >> 20) & 0x01;
274 short opcode = (inst >> 21) & 0x0f;
275 short immediate = (inst >> 25) & 0x01;
276 short no_op1 = (opcode & 0x0d) == 0x0d;
277 short no_dst = (opcode & 0x0c) == 0x08;
279 dbg_printf("\n\t%s%s%s", tbl_dataops[opcode], condcodes ? "s" : "", get_cond(inst));
280 if (!no_dst) dbg_printf("\t%s, ", tbl_regs[get_nibble(inst, 3)]);
281 else dbg_printf("\t");
283 if (no_op1)
285 if (immediate)
286 dbg_printf("#%u", ROR32(inst & 0xff, 2 * get_nibble(inst, 2)));
287 else
288 dbg_printf("%s", tbl_regs[get_nibble(inst, 0)]);
290 else
292 if (immediate)
293 dbg_printf("%s, #%u", tbl_regs[get_nibble(inst, 4)],
294 ROR32(inst & 0xff, 2 * get_nibble(inst, 2)));
295 else if (((inst >> 4) & 0xff) == 0x00) /* no shift */
296 dbg_printf("%s, %s", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
297 else if (((inst >> 4) & 0x09) == 0x01) /* register shift */
298 dbg_printf("%s, %s, %s %s", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)],
299 tbl_shifts[(inst >> 5) & 0x03], tbl_regs[(inst >> 8) & 0x0f]);
300 else if (((inst >> 4) & 0x01) == 0x00) /* immediate shift */
301 dbg_printf("%s, %s, %s #%d", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)],
302 tbl_shifts[(inst >> 5) & 0x03], (inst >> 7) & 0x1f);
303 else
304 return inst;
306 return 0;
309 static UINT arm_disasm_singletrans(UINT inst, ADDRESS64 *addr)
311 short load = (inst >> 20) & 0x01;
312 short writeback = (inst >> 21) & 0x01;
313 short byte = (inst >> 22) & 0x01;
314 short direction = (inst >> 23) & 0x01;
315 short indexing = (inst >> 24) & 0x01;
316 short immediate = !((inst >> 25) & 0x01);
317 short offset = inst & 0x0fff;
319 if (!direction) offset *= -1;
321 dbg_printf("\n\t%s%s%s%s", load ? "ldr" : "str", byte ? "b" : "", writeback ? "t" : "",
322 get_cond(inst));
323 dbg_printf("\t%s, ", tbl_regs[get_nibble(inst, 3)]);
324 if (indexing)
326 if (immediate)
327 dbg_printf("[%s, #%d]", tbl_regs[get_nibble(inst, 4)], offset);
328 else if (((inst >> 4) & 0xff) == 0x00) /* no shift */
329 dbg_printf("[%s, %s]", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
330 else if (((inst >> 4) & 0x01) == 0x00) /* immediate shift (there's no register shift) */
331 dbg_printf("[%s, %s, %s #%d]", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)],
332 tbl_shifts[(inst >> 5) & 0x03], (inst >> 7) & 0x1f);
333 else
334 return inst;
336 else
338 if (immediate)
339 dbg_printf("[%s], #%d", tbl_regs[get_nibble(inst, 4)], offset);
340 else if (((inst >> 4) & 0xff) == 0x00) /* no shift */
341 dbg_printf("[%s], %s", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
342 else if (((inst >> 4) & 0x01) == 0x00) /* immediate shift (there's no register shift) */
343 dbg_printf("[%s], %s, %s #%d", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)],
344 tbl_shifts[(inst >> 5) & 0x03], (inst >> 7) & 0x1f);
345 else
346 return inst;
348 return 0;
351 static UINT arm_disasm_blocktrans(UINT inst, ADDRESS64 *addr)
353 short load = (inst >> 20) & 0x01;
354 short writeback = (inst >> 21) & 0x01;
355 short psr = (inst >> 22) & 0x01;
356 short addrmode = (inst >> 23) & 0x03;
357 short i;
358 short last=15;
359 for (i=15;i>=0;i--)
360 if ((inst>>i) & 1)
362 last = i;
363 break;
366 dbg_printf("\n\t%s%s%s\t%s%s, {", load ? "ldm" : "stm", tbl_addrmode[addrmode], get_cond(inst),
367 tbl_regs[get_nibble(inst, 4)], writeback ? "!" : "");
368 for (i=0;i<=15;i++)
369 if ((inst>>i) & 1)
371 if (i == last) dbg_printf("%s", tbl_regs[i]);
372 else dbg_printf("%s, ", tbl_regs[i]);
374 dbg_printf("}%s", psr ? "^" : "");
375 return 0;
378 static UINT arm_disasm_swi(UINT inst, ADDRESS64 *addr)
380 dbg_printf("\n\tswi%s\t#%d", get_cond(inst), inst & 0x00ffffff);
381 return 0;
384 static UINT arm_disasm_coproctrans(UINT inst, ADDRESS64 *addr)
386 WORD CRm = inst & 0x0f;
387 WORD CP = (inst >> 5) & 0x07;
388 WORD CPnum = (inst >> 8) & 0x0f;
389 WORD CRn = (inst >> 16) & 0x0f;
390 WORD load = (inst >> 20) & 0x01;
391 WORD CP_Opc = (inst >> 21) & 0x07;
393 dbg_printf("\n\t%s%s\t%u, %u, %s, cr%u, cr%u, {%u}", load ? "mrc" : "mcr", get_cond(inst), CPnum,
394 CP, tbl_regs[get_nibble(inst, 3)], CRn, CRm, CP_Opc);
395 return 0;
398 static UINT arm_disasm_coprocdataop(UINT inst, ADDRESS64 *addr)
400 WORD CRm = inst & 0x0f;
401 WORD CP = (inst >> 5) & 0x07;
402 WORD CPnum = (inst >> 8) & 0x0f;
403 WORD CRd = (inst >> 12) & 0x0f;
404 WORD CRn = (inst >> 16) & 0x0f;
405 WORD CP_Opc = (inst >> 20) & 0x0f;
407 dbg_printf("\n\tcdp%s\t%u, %u, cr%u, cr%u, cr%u, {%u}", get_cond(inst),
408 CPnum, CP, CRd, CRn, CRm, CP_Opc);
409 return 0;
412 static UINT arm_disasm_coprocdatatrans(UINT inst, ADDRESS64 *addr)
414 WORD CPnum = (inst >> 8) & 0x0f;
415 WORD CRd = (inst >> 12) & 0x0f;
416 WORD load = (inst >> 20) & 0x01;
417 WORD writeback = (inst >> 21) & 0x01;
418 WORD translen = (inst >> 22) & 0x01;
419 WORD direction = (inst >> 23) & 0x01;
420 WORD indexing = (inst >> 24) & 0x01;
421 short offset = (inst & 0xff) << 2;
423 if (!direction) offset *= -1;
425 dbg_printf("\n\t%s%s%s", load ? "ldc" : "stc", translen ? "l" : "", get_cond(inst));
426 if (indexing)
427 dbg_printf("\t%u, cr%u, [%s, #%d]%s", CPnum, CRd, tbl_regs[get_nibble(inst, 4)], offset, writeback?"!":"");
428 else
429 dbg_printf("\t%u, cr%u, [%s], #%d", CPnum, CRd, tbl_regs[get_nibble(inst, 4)], offset);
430 return 0;
433 static WORD thumb_disasm_hireg(WORD inst, ADDRESS64 *addr)
435 short dst = inst & 0x07;
436 short src = (inst >> 3) & 0x07;
437 short h2 = (inst >> 6) & 0x01;
438 short h1 = (inst >> 7) & 0x01;
439 short op = (inst >> 8) & 0x03;
441 if (h1) dst += 8;
442 if (h2) src += 8;
444 if (op == 2 && dst == src) /* mov rx, rx */
446 dbg_printf("\n\tnop");
447 return 0;
450 if (op == 3)
451 dbg_printf("\n\tb%sx\t%s", h1?"l":"", tbl_regs[src]);
452 else
453 dbg_printf("\n\t%s\t%s, %s", tbl_hiops_t[op], tbl_regs[dst], tbl_regs[src]);
455 return 0;
458 static WORD thumb_disasm_aluop(WORD inst, ADDRESS64 *addr)
460 short dst = inst & 0x07;
461 short src = (inst >> 3) & 0x07;
462 short op = (inst >> 6) & 0x0f;
464 dbg_printf("\n\t%s\t%s, %s", tbl_aluops_t[op], tbl_regs[dst], tbl_regs[src]);
466 return 0;
469 static WORD thumb_disasm_pushpop(WORD inst, ADDRESS64 *addr)
471 short lrpc = (inst >> 8) & 0x01;
472 short load = (inst >> 11) & 0x01;
473 short i;
474 short last;
476 for (i=7;i>=0;i--)
477 if ((inst>>i) & 1) break;
478 last = i;
480 dbg_printf("\n\t%s\t{", load ? "pop" : "push");
482 for (i=0;i<=7;i++)
483 if ((inst>>i) & 1)
485 if (i == last) dbg_printf("%s", tbl_regs[i]);
486 else dbg_printf("%s, ", tbl_regs[i]);
488 if (lrpc)
489 dbg_printf("%s%s", last ? ", " : "", load ? "pc" : "lr");
491 dbg_printf("}");
492 return 0;
495 static WORD thumb_disasm_blocktrans(WORD inst, ADDRESS64 *addr)
497 short load = (inst >> 11) & 0x01;
498 short i;
499 short last;
501 for (i=7;i>=0;i--)
502 if ((inst>>i) & 1) break;
503 last = i;
505 dbg_printf("\n\t%s\t%s!, {", load ? "ldmia" : "stmia", tbl_regs[(inst >> 8) & 0x07]);
507 for (i=0;i<=7;i++)
508 if ((inst>>i) & 1)
510 if (i == last) dbg_printf("%s", tbl_regs[i]);
511 else dbg_printf("%s, ", tbl_regs[i]);
514 dbg_printf("}");
515 return 0;
518 static WORD thumb_disasm_swi(WORD inst, ADDRESS64 *addr)
520 dbg_printf("\n\tswi\t#%d", inst & 0x00ff);
521 return 0;
524 static WORD thumb_disasm_condbranch(WORD inst, ADDRESS64 *addr)
526 WORD offset = inst & 0x00ff;
527 dbg_printf("\n\tb%s\t", tbl_cond[(inst >> 8) & 0x0f]);
528 db_printsym(addr->Offset + offset);
529 return 0;
532 static WORD thumb_disasm_uncondbranch(WORD inst, ADDRESS64 *addr)
534 short offset = (inst & 0x07ff) << 1;
536 if (offset & 0x0800) offset |= 0xf000;
537 offset += 4;
539 dbg_printf("\n\tb\t");
540 db_printsym(addr->Offset + offset);
541 return 0;
544 static WORD thumb_disasm_loadadr(WORD inst, ADDRESS64 *addr)
546 WORD src = (inst >> 11) & 0x01;
547 WORD offset = (inst & 0xff) << 2;
549 dbg_printf("\n\tadd\t%s, %s, #%d", tbl_regs[(inst >> 8) & 0x07], src ? "sp" : "pc", offset);
550 return 0;
553 static WORD thumb_disasm_ldrpcrel(WORD inst, ADDRESS64 *addr)
555 WORD offset = (inst & 0xff) << 2;
556 dbg_printf("\n\tldr\t%s, [pc, #%u]", tbl_regs[(inst >> 8) & 0x07], offset);
557 return 0;
560 static WORD thumb_disasm_ldrsprel(WORD inst, ADDRESS64 *addr)
562 WORD offset = (inst & 0xff) << 2;
563 dbg_printf("\n\t%s\t%s, [sp, #%u]", (inst & 0x0800)?"ldr":"str", tbl_regs[(inst >> 8) & 0x07], offset);
564 return 0;
567 static WORD thumb_disasm_addsprel(WORD inst, ADDRESS64 *addr)
569 WORD offset = (inst & 0x7f) << 2;
570 if ((inst >> 7) & 0x01)
571 dbg_printf("\n\tsub\tsp, sp, #%u", offset);
572 else
573 dbg_printf("\n\tadd\tsp, sp, #%u", offset);
574 return 0;
577 static WORD thumb_disasm_ldrimm(WORD inst, ADDRESS64 *addr)
579 WORD offset = (inst & 0x07c0) >> 6;
580 dbg_printf("\n\t%s%s\t%s, [%s, #%u]", (inst & 0x0800)?"ldr":"str", (inst & 0x1000)?"b":"",
581 tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07], (inst & 0x1000)?offset:(offset << 2));
582 return 0;
585 static WORD thumb_disasm_ldrhimm(WORD inst, ADDRESS64 *addr)
587 WORD offset = (inst & 0x07c0) >> 5;
588 dbg_printf("\n\t%s\t%s, [%s, #%u]", (inst & 0x0800)?"ldrh":"strh",
589 tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07], offset);
590 return 0;
593 static WORD thumb_disasm_ldrreg(WORD inst, ADDRESS64 *addr)
595 dbg_printf("\n\t%s%s\t%s, [%s, %s]", (inst & 0x0800)?"ldr":"str", (inst & 0x0400)?"b":"",
596 tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07], tbl_regs[(inst >> 6) & 0x07]);
597 return 0;
600 static WORD thumb_disasm_ldrsreg(WORD inst, ADDRESS64 *addr)
602 dbg_printf("\n\t%s\t%s, [%s, %s]", tbl_sregops_t[(inst >> 10) & 0x03],
603 tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07], tbl_regs[(inst >> 6) & 0x07]);
604 return 0;
607 static WORD thumb_disasm_immop(WORD inst, ADDRESS64 *addr)
609 WORD op = (inst >> 11) & 0x03;
610 dbg_printf("\n\t%s\t%s, #%u", tbl_immops_t[op], tbl_regs[(inst >> 8) & 0x07], inst & 0xff);
611 return 0;
614 static WORD thumb_disasm_nop(WORD inst, ADDRESS64 *addr)
616 dbg_printf("\n\tnop");
617 return 0;
620 static WORD thumb_disasm_addsub(WORD inst, ADDRESS64 *addr)
622 WORD op = (inst >> 9) & 0x01;
623 WORD immediate = (inst >> 10) & 0x01;
625 dbg_printf("\n\t%s\t%s, %s, ", op ? "sub" : "add",
626 tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07]);
627 if (immediate)
628 dbg_printf("#%d", (inst >> 6) & 0x07);
629 else
630 dbg_printf("%s", tbl_regs[(inst >> 6) & 0x07]);
631 return 0;
634 static WORD thumb_disasm_movshift(WORD inst, ADDRESS64 *addr)
636 WORD op = (inst >> 11) & 0x03;
637 dbg_printf("\n\t%s\t%s, %s, #%u", tbl_shifts[op],
638 tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07], (inst >> 6) & 0x1f);
639 return 0;
642 static UINT thumb2_disasm_srtrans(UINT inst, ADDRESS64 *addr)
644 UINT fromsr = (inst >> 21) & 0x03;
645 UINT sysreg = inst & 0xff;
647 if (fromsr == 3 && get_nibble(inst,4) == 0x0f && sysreg <= 20)
649 dbg_printf("\n\tmrs\t%s, %s", tbl_regs[get_nibble(inst, 2)], tbl_special_regs_t2[sysreg]);
650 return 0;
653 if (fromsr == 0 && sysreg <= 20)
655 dbg_printf("\n\tmsr\t%s, %s", tbl_special_regs_t2[sysreg], tbl_regs[get_nibble(inst, 4)]);
656 return 0;
659 return inst;
662 static UINT thumb2_disasm_hint(UINT inst, ADDRESS64 *addr)
664 WORD op1 = (inst >> 8) & 0x07;
665 WORD op2 = inst & 0xff;
667 if (op1) return inst;
669 if (op2 <= 4)
671 dbg_printf("\n\t%s", tbl_hints_t2[op2]);
672 return 0;
675 if (op2 & 0xf0)
677 dbg_printf("\n\tdbg\t#%u", get_nibble(inst, 0));
678 return 0;
681 return inst;
684 static UINT thumb2_disasm_miscctrl(UINT inst, ADDRESS64 *addr)
686 WORD op = (inst >> 4) & 0x0f;
688 switch (op)
690 case 2:
691 dbg_printf("\n\tclrex");
692 break;
693 case 4:
694 dbg_printf("\n\tdsb\t#%u", get_nibble(inst, 0));
695 break;
696 case 5:
697 dbg_printf("\n\tdmb\t#%u", get_nibble(inst, 0));
698 break;
699 case 6:
700 dbg_printf("\n\tisb\t#%u", get_nibble(inst, 0));
701 break;
702 default:
703 return inst;
706 return 0;
709 static UINT thumb2_disasm_branch(UINT inst, ADDRESS64 *addr)
711 UINT S = (inst >> 26) & 0x01;
712 UINT L = (inst >> 14) & 0x01;
713 UINT I1 = !(((inst >> 13) & 0x01) ^ S);
714 UINT C = !((inst >> 12) & 0x01);
715 UINT I2 = !(((inst >> 11) & 0x01) ^ S);
716 UINT offset = (inst & 0x000007ff) << 1;
718 if (C)
720 offset |= I1 << 19 | I2 << 18 | (inst & 0x003f0000) >> 4;
721 if (S) offset |= 0x0fff << 20;
723 else
725 offset |= I1 << 23 | I2 << 22 | (inst & 0x03ff0000) >> 4;
726 if (S) offset |= 0xff << 24;
729 dbg_printf("\n\tb%s%s\t", L ? "l" : "", C ? tbl_cond[(inst >> 22) & 0x0f] : "");
730 db_printsym(addr->Offset + offset + 4);
731 return 0;
734 static UINT thumb2_disasm_misc(UINT inst, ADDRESS64 *addr)
736 WORD op1 = (inst >> 20) & 0x03;
737 WORD op2 = (inst >> 4) & 0x03;
739 if (get_nibble(inst, 4) != get_nibble(inst, 0))
740 return inst;
742 if (op1 == 3 && op2 == 0)
744 dbg_printf("\n\tclz\t%s, %s", tbl_regs[get_nibble(inst, 2)], tbl_regs[get_nibble(inst, 0)]);
745 return 0;
748 if (op1 == 1)
750 dbg_printf("\n\t%s\t%s, %s", tbl_miscops_t2[op2], tbl_regs[get_nibble(inst, 2)],
751 tbl_regs[get_nibble(inst, 0)]);
752 return 0;
755 return inst;
758 static UINT thumb2_disasm_dataprocessingreg(UINT inst, ADDRESS64 *addr)
760 WORD op1 = (inst >> 20) & 0x07;
761 WORD op2 = (inst >> 4) & 0x0f;
763 if (!op2)
765 dbg_printf("\n\t%s%s\t%s, %s, %s", tbl_shifts[op1 >> 1], (op1 & 1)?"s":"",
766 tbl_regs[get_nibble(inst, 2)], tbl_regs[get_nibble(inst, 4)],
767 tbl_regs[get_nibble(inst, 0)]);
768 return 0;
771 if ((op2 & 0x0C) == 0x08 && get_nibble(inst, 4) == 0x0f)
773 dbg_printf("\n\t%sxt%s\t%s, %s", (op1 & 1)?"u":"s", (op1 & 4)?"b":"h",
774 tbl_regs[get_nibble(inst, 2)], tbl_regs[get_nibble(inst, 0)]);
775 if (op2 & 0x03)
776 dbg_printf(", ROR #%u", (op2 & 3) * 8);
777 return 0;
780 return inst;
783 static UINT thumb2_disasm_mul(UINT inst, ADDRESS64 *addr)
785 WORD op1 = (inst >> 20) & 0x07;
786 WORD op2 = (inst >> 4) & 0x03;
788 if (op1)
789 return inst;
791 if (op2 == 0 && get_nibble(inst, 3) != 0xf)
793 dbg_printf("\n\tmla\t%s, %s, %s, %s", tbl_regs[get_nibble(inst, 2)],
794 tbl_regs[get_nibble(inst, 4)],
795 tbl_regs[get_nibble(inst, 0)],
796 tbl_regs[get_nibble(inst, 3)]);
797 return 0;
800 if (op2 == 0 && get_nibble(inst, 3) == 0xf)
802 dbg_printf("\n\tmul\t%s, %s, %s", tbl_regs[get_nibble(inst, 2)],
803 tbl_regs[get_nibble(inst, 4)],
804 tbl_regs[get_nibble(inst, 0)]);
805 return 0;
808 if (op2 == 1)
810 dbg_printf("\n\tmls\t%s, %s, %s, %s", tbl_regs[get_nibble(inst, 2)],
811 tbl_regs[get_nibble(inst, 4)],
812 tbl_regs[get_nibble(inst, 0)],
813 tbl_regs[get_nibble(inst, 3)]);
814 return 0;
817 return inst;
820 static UINT thumb2_disasm_longmuldiv(UINT inst, ADDRESS64 *addr)
822 WORD op1 = (inst >> 20) & 0x07;
823 WORD op2 = (inst >> 4) & 0x0f;
825 if (op2 == 0)
827 switch (op1)
829 case 0:
830 dbg_printf("\n\tsmull\t");
831 break;
832 case 2:
833 dbg_printf("\n\tumull\t");
834 break;
835 case 4:
836 dbg_printf("\n\tsmlal\t");
837 break;
838 case 6:
839 dbg_printf("\n\tumlal\t");
840 break;
841 default:
842 return inst;
844 dbg_printf("%s, %s, %s, %s", tbl_regs[get_nibble(inst, 3)], tbl_regs[get_nibble(inst, 2)],
845 tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
846 return 0;
849 if (op2 == 0xffff)
851 switch (op1)
853 case 1:
854 dbg_printf("\n\tsdiv\t");
855 break;
856 case 3:
857 dbg_printf("\n\tudiv\t");
858 break;
859 default:
860 return inst;
862 dbg_printf("%s, %s, %s", tbl_regs[get_nibble(inst, 2)], tbl_regs[get_nibble(inst, 4)],
863 tbl_regs[get_nibble(inst, 0)]);
864 return 0;
867 return inst;
870 static UINT thumb2_disasm_str(UINT inst, ADDRESS64 *addr)
872 WORD op1 = (inst >> 21) & 0x07;
873 WORD op2 = (inst >> 6) & 0x3f;
875 if ((op1 & 0x03) == 3) return inst;
877 if (!(op1 & 0x04) && inst & 0x0800)
879 int offset;
880 dbg_printf("\n\tstr%s\t%s, [%s", tbl_width_t2[op1 & 0x03], tbl_regs[get_nibble(inst, 3)],
881 tbl_regs[get_nibble(inst, 4)]);
883 offset = inst & 0xff;
884 if (!(inst & 0x0200)) offset *= -1;
886 if (!(inst & 0x0400) && (inst & 0x0100)) dbg_printf("], #%i", offset);
887 else if (inst & 0x0400) dbg_printf(", #%i]%s", offset, (inst & 0x0100)?"!":"");
888 else return inst;
889 return 0;
892 if (!(op1 & 0x04) && !op2)
894 dbg_printf("\n\tstr%s\t%s, [%s, %s, LSL #%u]", tbl_width_t2[op1 & 0x03],
895 tbl_regs[get_nibble(inst, 3)], tbl_regs[get_nibble(inst, 4)],
896 tbl_regs[get_nibble(inst, 0)], (inst >> 4) & 0x3);
897 return 0;
900 if (op1 & 0x04)
902 dbg_printf("\n\tstr%s\t%s, [%s, #%u]", tbl_width_t2[op1 & 0x03],
903 tbl_regs[get_nibble(inst, 3)], tbl_regs[get_nibble(inst, 4)], inst & 0x0fff);
904 return 0;
907 return inst;
910 static UINT thumb2_disasm_ldrword(UINT inst, ADDRESS64 *addr)
912 WORD op1 = (inst >> 23) & 0x01;
913 WORD op2 = (inst >> 6) & 0x3f;
914 int offset;
916 if (get_nibble(inst, 4) == 0x0f)
918 offset = inst & 0x0fff;
920 if (!op1) offset *= -1;
921 offset += 3;
923 dbg_printf("\n\tldr\t%s, ", tbl_regs[get_nibble(inst, 3)]);
924 db_printsym(addr->Offset + offset);
925 return 0;
928 if (!op1 && !op2)
930 dbg_printf("\n\tldr\t%s, [%s, %s, LSL #%u]", tbl_regs[get_nibble(inst, 3)],
931 tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)], (inst >> 4) & 0x3);
932 return 0;
935 if (!op1 && (op2 & 0x3c) == 0x38)
937 dbg_printf("\n\tldrt\t%s, [%s, #%u]", tbl_regs[get_nibble(inst, 3)],
938 tbl_regs[get_nibble(inst, 4)], inst & 0xff);
939 return 0;
942 dbg_printf("\n\tldr\t%s, [%s", tbl_regs[get_nibble(inst, 3)], tbl_regs[get_nibble(inst, 4)]);
944 if (op1)
946 dbg_printf(", #%u]", inst & 0x0fff);
947 return 0;
950 offset = inst & 0xff;
951 if (!(inst & 0x0200)) offset *= -1;
953 if (!(inst & 0x0400) && (inst & 0x0100)) dbg_printf("], #%i", offset);
954 else if (inst & 0x0400) dbg_printf(", #%i]%s", offset, (inst & 0x0100)?"!":"");
955 else return inst;
957 return 0;
960 static UINT thumb2_disasm_preload(UINT inst, ADDRESS64 *addr)
962 WORD op1 = (inst >> 23) & 0x03;
964 if (!(op1 & 0x01) && !((inst >> 6) & 0x3f) && get_nibble(inst, 4) != 15)
966 WORD shift = (inst >> 4) & 0x03;
967 dbg_printf("\n\t%s\t[%s, %s", op1?"pli":"pld", tbl_regs[get_nibble(inst, 4)],
968 tbl_regs[get_nibble(inst, 0)]);
969 if (shift) dbg_printf(", lsl #%u]", shift);
970 else dbg_printf("]");
971 return 0;
974 if (get_nibble(inst, 4) != 15)
976 dbg_printf("\n\t%s\t[%s, #%d]", (op1 & 0x02)?"pli":"pld", tbl_regs[get_nibble(inst, 4)],
977 (op1 & 0x01)?(inst & 0x0fff):(-1 * (inst & 0xff)));
978 return 0;
981 if (get_nibble(inst, 4) == 15)
983 int offset = inst & 0x0fff;
984 if (!op1) offset *= -1;
985 dbg_printf("\n\t%s\t", (op1 & 0x02)?"pli":"pld");
986 db_printsym(addr->Offset + offset + 4);
987 return 0;
990 return inst;
993 static UINT thumb2_disasm_ldrnonword(UINT inst, ADDRESS64 *addr)
995 WORD op1 = (inst >> 23) & 0x03;
996 WORD hw = (inst >> 21) & 0x01;
998 if (!(op1 & 0x01) && !((inst >> 6) & 0x3f) && get_nibble(inst, 4) != 15)
1000 WORD shift = (inst >> 4) & 0x03;
1001 dbg_printf("\n\t%s%s\t%s, [%s, %s", op1?"ldrs":"ldr", hw?"h":"b",
1002 tbl_regs[get_nibble(inst, 3)], tbl_regs[get_nibble(inst, 4)],
1003 tbl_regs[get_nibble(inst, 0)]);
1004 if (shift) dbg_printf(", lsl #%u]", shift);
1005 else dbg_printf("]");
1006 return 0;
1009 if (!(op1 & 0x01) && ((inst >> 8) & 0x0f) == 14 && get_nibble(inst, 4) != 15)
1011 WORD offset = inst & 0xff;
1012 dbg_printf("\n\t%s%s\t%s, [%s", op1?"ldrs":"ldr", hw?"ht":"bt",
1013 tbl_regs[get_nibble(inst, 3)], tbl_regs[get_nibble(inst, 4)]);
1014 if (offset) dbg_printf(", #%u]", offset);
1015 else dbg_printf("]");
1016 return 0;
1019 if (get_nibble(inst, 4) != 15)
1021 int offset;
1023 dbg_printf("\n\t%s%s\t%s, [%s", (op1 & 0x02)?"ldrs":"ldr", hw?"h":"b",
1024 tbl_regs[get_nibble(inst, 3)], tbl_regs[get_nibble(inst, 4)]);
1026 if (op1 & 0x01)
1028 dbg_printf(", #%u]", inst & 0x0fff);
1029 return 0;
1032 offset = inst & 0xff;
1033 if (!(inst & 0x0200)) offset *= -1;
1035 if (!(inst & 0x0400) && (inst & 0x0100)) dbg_printf("], #%i", offset);
1036 else if (inst & 0x0400) dbg_printf(", #%i]%s", offset, (inst & 0x0100)?"!":"");
1037 else return inst;
1039 return 0;
1042 if (get_nibble(inst, 4) == 15)
1044 int offset = inst & 0x0fff;
1045 if (!op1) offset *= -1;
1046 dbg_printf("\n\t%s%s\t%s, ", (op1 & 0x02)?"ldrs":"ldr", hw?"h":"b",
1047 tbl_regs[get_nibble(inst, 3)]);
1048 db_printsym(addr->Offset + offset + 4);
1049 return 0;
1052 return inst;
1055 static UINT thumb2_disasm_dataprocessing(UINT inst, ADDRESS64 *addr)
1057 WORD op = (inst >> 20) & 0x1f;
1058 WORD imm5 = ((inst >> 10) & 0x1c) + ((inst >> 6) & 0x03);
1060 switch (op)
1062 case 0:
1064 WORD offset = ((inst >> 15) & 0x0800) + ((inst >> 4) & 0x0700) + (inst & 0xff);
1065 if (get_nibble(inst, 4) == 15)
1067 dbg_printf("\n\tadr\t%s, ", tbl_regs[get_nibble(inst, 2)]);
1068 db_printsym(addr->Offset + offset + 4);
1070 else
1071 dbg_printf("\n\taddw\t%s, %s, #%u", tbl_regs[get_nibble(inst, 2)],
1072 tbl_regs[get_nibble(inst, 4)], offset);
1073 return 0;
1075 case 4:
1076 case 12:
1078 WORD offset = ((inst >> 15) & 0x0800) + ((inst >> 4) & 0xf000) +
1079 ((inst >> 4) & 0x0700) + (inst & 0xff);
1080 dbg_printf("\n\t%s\t%s, #%u", op == 12 ? "movt" : "movw", tbl_regs[get_nibble(inst, 2)],
1081 offset);
1082 return 0;
1084 case 10:
1086 int offset = ((inst >> 15) & 0x0800) + ((inst >> 4) & 0x0700) + (inst & 0xff);
1087 if (get_nibble(inst, 4) == 15)
1089 offset *= -1;
1090 dbg_printf("\n\tadr\t%s, ", tbl_regs[get_nibble(inst, 2)]);
1091 db_printsym(addr->Offset + offset + 4);
1093 else
1094 dbg_printf("\n\tsubw\t%s, %s, #%u", tbl_regs[get_nibble(inst, 2)],
1095 tbl_regs[get_nibble(inst, 4)], offset);
1096 return 0;
1098 case 16:
1099 case 18:
1100 case 24:
1101 case 26:
1103 BOOL sign = op < 24;
1104 WORD sh = (inst >> 21) & 0x01;
1105 WORD sat = (inst & 0x1f);
1106 if (sign) sat++;
1107 if (imm5)
1108 dbg_printf("\n\t%s\t%s, #%u, %s, %s #%u", sign ? "ssat" : "usat",
1109 tbl_regs[get_nibble(inst, 2)], sat, tbl_regs[get_nibble(inst, 4)],
1110 sh ? "asr" : "lsl", imm5);
1111 else
1112 dbg_printf("\n\t%s\t%s, #%u, %s", sign ? "ssat" : "usat", tbl_regs[get_nibble(inst, 2)],
1113 sat, tbl_regs[get_nibble(inst, 4)]);
1114 return 0;
1116 case 20:
1117 case 28:
1119 WORD width = (inst & 0x1f) + 1;
1120 dbg_printf("\n\t%s\t%s, %s, #%u, #%u", op == 28 ? "ubfx" : "sbfx",
1121 tbl_regs[get_nibble(inst, 2)], tbl_regs[get_nibble(inst, 4)], imm5, width);
1122 return 0;
1124 case 22:
1126 WORD msb = (inst & 0x1f) + 1 - imm5;
1127 if (get_nibble(inst, 4) == 15)
1128 dbg_printf("\n\tbfc\t%s, #%u, #%u", tbl_regs[get_nibble(inst, 2)], imm5, msb);
1129 else
1130 dbg_printf("\n\tbfi\t%s, %s, #%u, #%u", tbl_regs[get_nibble(inst, 2)],
1131 tbl_regs[get_nibble(inst, 4)], imm5, msb);
1132 return 0;
1134 default:
1135 return inst;
1139 static UINT thumb2_disasm_dataprocessingmod(UINT inst, ADDRESS64 *addr)
1141 WORD op = (inst >> 21) & 0x0f;
1142 WORD sf = (inst >> 20) & 0x01;
1143 WORD offset = ((inst >> 15) & 0x0800) + ((inst >> 4) & 0x0700) + (inst & 0xff);
1145 /* FIXME: use ThumbExpandImm_C */
1147 switch (op)
1149 case 0:
1150 if (get_nibble(inst, 2) == 15)
1151 dbg_printf("\n\ttst\t%s, #%u", tbl_regs[get_nibble(inst, 4)], offset);
1152 else
1153 dbg_printf("\n\tand%s\t%s, %s, #%u", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)],
1154 tbl_regs[get_nibble(inst, 4)], offset);
1155 return 0;
1156 case 1:
1157 dbg_printf("\n\tbic%s\t%s, %s, #%u", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)],
1158 tbl_regs[get_nibble(inst, 4)], offset);
1159 return 0;
1160 case 2:
1161 if (get_nibble(inst, 4) == 15)
1162 dbg_printf("\n\tmov%s\t%s, #%u", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)], offset);
1163 else
1164 dbg_printf("\n\torr%s\t%s, %s, #%u", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)],
1165 tbl_regs[get_nibble(inst, 4)], offset);
1166 return 0;
1167 case 3:
1168 if (get_nibble(inst, 4) == 15)
1169 dbg_printf("\n\tmvn%s\t%s, #%u", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)], offset);
1170 else
1171 dbg_printf("\n\torn%s\t%s, %s, #%u", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)],
1172 tbl_regs[get_nibble(inst, 4)], offset);
1173 return 0;
1174 case 4:
1175 if (get_nibble(inst, 2) == 15)
1176 dbg_printf("\n\tteq\t%s, #%u", tbl_regs[get_nibble(inst, 4)], offset);
1177 else
1178 dbg_printf("\n\teor%s\t%s, %s, #%u", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)],
1179 tbl_regs[get_nibble(inst, 4)], offset);
1180 return 0;
1181 case 8:
1182 if (get_nibble(inst, 2) == 15)
1183 dbg_printf("\n\tcmn\t%s, #%u", tbl_regs[get_nibble(inst, 4)], offset);
1184 else
1185 dbg_printf("\n\tadd%s\t%s, %s, #%u", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)],
1186 tbl_regs[get_nibble(inst, 4)], offset);
1187 return 0;
1188 case 10:
1189 dbg_printf("\n\tadc%s\t%s, %s, #%u", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)],
1190 tbl_regs[get_nibble(inst, 4)], offset);
1191 return 0;
1192 case 11:
1193 dbg_printf("\n\tsbc%s\t%s, %s, #%u", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)],
1194 tbl_regs[get_nibble(inst, 4)], offset);
1195 return 0;
1196 case 13:
1197 if (get_nibble(inst, 2) == 15)
1198 dbg_printf("\n\tcmp\t%s, #%u", tbl_regs[get_nibble(inst, 4)], offset);
1199 else
1200 dbg_printf("\n\tsub%s\t%s, %s, #%u", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)],
1201 tbl_regs[get_nibble(inst, 4)], offset);
1202 return 0;
1203 case 14:
1204 dbg_printf("\n\trsb%s\t%s, %s, #%u", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)],
1205 tbl_regs[get_nibble(inst, 4)], offset);
1206 return 0;
1207 default:
1208 return inst;
1212 static UINT thumb2_disasm_dataprocessingshift(UINT inst, ADDRESS64 *addr)
1214 WORD op = (inst >> 21) & 0x0f;
1215 WORD sf = (inst >> 20) & 0x01;
1216 WORD imm5 = ((inst >> 10) & 0x1c) + ((inst >> 6) & 0x03);
1217 WORD type = (inst >> 4) & 0x03;
1219 if (!imm5 && (type == 1 || type == 2)) imm5 = 32;
1220 else if (!imm5 && type == 3) type = 4;
1222 switch (op)
1224 case 0:
1225 if (get_nibble(inst, 2) == 15)
1226 dbg_printf("\n\ttst\t%s, %s", tbl_regs[get_nibble(inst, 4)],
1227 tbl_regs[get_nibble(inst, 0)]);
1228 else
1229 dbg_printf("\n\tand%s\t%s, %s, %s", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)],
1230 tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
1231 break;
1232 case 1:
1233 dbg_printf("\n\tbic%s\t%s, %s, %s", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)],
1234 tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
1235 break;
1236 case 2:
1237 if (get_nibble(inst, 4) == 15)
1239 if (type == 4)
1240 dbg_printf("\n\trrx%s\t%s, %s", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)], tbl_regs[get_nibble(inst, 0)]);
1241 else if (!type && !imm5)
1242 dbg_printf("\n\tmov%s\t%s, %s", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)], tbl_regs[get_nibble(inst, 0)]);
1243 else
1244 dbg_printf("\n\t%s%s\t%s, %s, #%u", tbl_shifts[type], sf ? "s" : "", tbl_regs[get_nibble(inst, 2)], tbl_regs[get_nibble(inst, 0)], imm5);
1245 return 0;
1247 else
1248 dbg_printf("\n\torr%s\t%s, %s, %s", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)],
1249 tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
1250 break;
1251 case 3:
1252 if (get_nibble(inst, 4) == 15)
1253 dbg_printf("\n\tmvn%s\t%s, %s, %s", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)],
1254 tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
1255 else
1256 dbg_printf("\n\torn%s\t%s, %s, %s", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)],
1257 tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
1258 break;
1259 case 4:
1260 if (get_nibble(inst, 2) == 15)
1261 dbg_printf("\n\tteq\t%s, %s", tbl_regs[get_nibble(inst, 4)],
1262 tbl_regs[get_nibble(inst, 0)]);
1263 else
1264 dbg_printf("\n\teor%s\t%s, %s, %s", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)],
1265 tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
1266 break;
1267 case 8:
1268 if (get_nibble(inst, 2) == 15)
1269 dbg_printf("\n\tcmn\t%s, %s", tbl_regs[get_nibble(inst, 4)],
1270 tbl_regs[get_nibble(inst, 0)]);
1271 else
1272 dbg_printf("\n\tadd%s\t%s, %s, %s", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)],
1273 tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
1274 break;
1275 case 10:
1276 dbg_printf("\n\tadc%s\t%s, %s, %s", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)],
1277 tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
1278 break;
1279 case 11:
1280 dbg_printf("\n\tsbc%s\t%s, %s, %s", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)],
1281 tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
1282 break;
1283 case 13:
1284 if (get_nibble(inst, 2) == 15)
1285 dbg_printf("\n\tcmp\t%s, %s", tbl_regs[get_nibble(inst, 4)],
1286 tbl_regs[get_nibble(inst, 0)]);
1287 else
1288 dbg_printf("\n\tsub%s\t%s, %s, %s", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)],
1289 tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
1290 break;
1291 case 14:
1292 dbg_printf("\n\trsb%s\t%s, %s, %s", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)],
1293 tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
1294 break;
1295 default:
1296 return inst;
1299 if (type == 4)
1300 dbg_printf(", rrx");
1301 else if (type || imm5)
1302 dbg_printf(", %s #%u", tbl_shifts[type], imm5);
1303 return 0;
1306 static UINT thumb2_disasm_coprocdat(UINT inst, ADDRESS64 *addr)
1308 WORD opc2 = (inst >> 5) & 0x07;
1310 dbg_printf("\n\tcdp%s\tp%u, #%u, cr%u, cr%u, cr%u", (inst & 0x10000000)?"2":"",
1311 get_nibble(inst, 2), get_nibble(inst, 5), get_nibble(inst, 3),
1312 get_nibble(inst, 4), get_nibble(inst, 0));
1314 if (opc2) dbg_printf(", #%u", opc2);
1315 return 0;
1318 static UINT thumb2_disasm_coprocmov1(UINT inst, ADDRESS64 *addr)
1320 WORD opc1 = (inst >> 21) & 0x07;
1321 WORD opc2 = (inst >> 5) & 0x07;
1323 dbg_printf("\n\t%s%s\tp%u, #%u, %s, cr%u, cr%u", (inst & 0x00100000)?"mrc":"mcr",
1324 (inst & 0x10000000)?"2":"", get_nibble(inst, 2), opc1,
1325 tbl_regs[get_nibble(inst, 3)], get_nibble(inst, 4), get_nibble(inst, 0));
1327 if (opc2) dbg_printf(", #%u", opc2);
1328 return 0;
1331 static UINT thumb2_disasm_coprocmov2(UINT inst, ADDRESS64 *addr)
1333 dbg_printf("\n\t%s%s\tp%u, #%u, %s, %s, cr%u", (inst & 0x00100000)?"mrrc":"mcrr",
1334 (inst & 0x10000000)?"2":"", get_nibble(inst, 2), get_nibble(inst, 1),
1335 tbl_regs[get_nibble(inst, 3)], tbl_regs[get_nibble(inst, 4)], get_nibble(inst, 0));
1337 return 0;
1340 static UINT thumb2_disasm_coprocdatatrans(UINT inst, ADDRESS64 *addr)
1342 WORD indexing = (inst >> 24) & 0x01;
1343 WORD direction = (inst >> 23) & 0x01;
1344 WORD translen = (inst >> 22) & 0x01;
1345 WORD writeback = (inst >> 21) & 0x01;
1346 WORD load = (inst >> 20) & 0x01;
1347 short offset = (inst & 0xff) << 2;
1349 if (!direction) offset *= -1;
1351 dbg_printf("\n\t%s%s%s", load ? "ldc" : "stc", (inst & 0x10000000)?"2":"", translen ? "l" : "");
1352 if (indexing)
1354 if (load && get_nibble(inst, 4) == 15)
1356 dbg_printf("\tp%u, cr%u, ", get_nibble(inst, 2), get_nibble(inst, 3));
1357 db_printsym(addr->Offset + offset + 4);
1359 else
1360 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?"!":"");
1362 else
1364 if (writeback)
1365 dbg_printf("\tp%u, cr%u, [%s], #%d", get_nibble(inst, 2), get_nibble(inst, 3), tbl_regs[get_nibble(inst, 4)], offset);
1366 else
1367 dbg_printf("\tp%u, cr%u, [%s], {%u}", get_nibble(inst, 2), get_nibble(inst, 3), tbl_regs[get_nibble(inst, 4)], inst & 0xff);
1369 return 0;
1372 static UINT thumb2_disasm_ldrstrmul(UINT inst, ADDRESS64 *addr)
1374 short load = (inst >> 20) & 0x01;
1375 short writeback = (inst >> 21) & 0x01;
1376 short decbefore = (inst >> 24) & 0x01;
1377 short i;
1378 short last=15;
1379 for (i=15;i>=0;i--)
1380 if ((inst>>i) & 1)
1382 last = i;
1383 break;
1386 if (writeback && get_nibble(inst, 4) == 13)
1387 dbg_printf("\n\t%s\t{", load ? "pop" : "push");
1388 else
1389 dbg_printf("\n\t%s%s\t%s%s, {", load ? "ldm" : "stm", decbefore ? "db" : "ia",
1390 tbl_regs[get_nibble(inst, 4)], writeback ? "!" : "");
1391 for (i=0;i<=15;i++)
1392 if ((inst>>i) & 1)
1394 if (i == last) dbg_printf("%s", tbl_regs[i]);
1395 else dbg_printf("%s, ", tbl_regs[i]);
1397 dbg_printf("}");
1398 return 0;
1401 static UINT thumb2_disasm_ldrstrextbr(UINT inst, ADDRESS64 *addr)
1403 WORD op1 = (inst >> 23) & 0x03;
1404 WORD op2 = (inst >> 20) & 0x03;
1405 WORD op3 = (inst >> 4) & 0x0f;
1406 WORD indexing = (inst >> 24) & 0x01;
1407 WORD direction = (inst >> 23) & 0x01;
1408 WORD writeback = (inst >> 21) & 0x01;
1409 WORD load = (inst >> 20) & 0x01;
1410 short offset = (inst & 0xff) << 2;
1412 if (op1 == 1 && op2 == 1 && op3 < 2)
1414 WORD halfword = (inst >> 4) & 0x01;
1415 if (halfword)
1416 dbg_printf("\n\ttbh\t [%s, %s, lsl #1]", tbl_regs[get_nibble(inst, 4)],
1417 tbl_regs[get_nibble(inst, 0)]);
1418 else
1419 dbg_printf("\n\ttbb\t [%s, %s]", tbl_regs[get_nibble(inst, 4)],
1420 tbl_regs[get_nibble(inst, 0)]);
1421 return 0;
1424 if (op1 == 0 && op2 < 2)
1426 if (get_nibble(inst, 2) == 15)
1427 dbg_printf("\n\tldrex\t %s, [%s, #%u]", tbl_regs[get_nibble(inst, 3)],
1428 tbl_regs[get_nibble(inst, 4)], offset);
1429 else
1430 dbg_printf("\n\tstrex\t %s, %s, [%s, #%u]", tbl_regs[get_nibble(inst, 2)],
1431 tbl_regs[get_nibble(inst, 3)], tbl_regs[get_nibble(inst, 4)], offset);
1432 return 0;
1435 if (op1 == 1 && op2 < 2)
1437 WORD halfword = (inst >> 4) & 0x01;
1438 if (get_nibble(inst, 0) == 15)
1439 dbg_printf("\n\tldrex%s\t %s, [%s]", halfword ? "h" : "b",
1440 tbl_regs[get_nibble(inst, 3)], tbl_regs[get_nibble(inst, 4)]);
1441 else
1442 dbg_printf("\n\tstrex%s\t %s, %s, [%s]", halfword ? "h" : "b",
1443 tbl_regs[get_nibble(inst, 0)], tbl_regs[get_nibble(inst, 3)],
1444 tbl_regs[get_nibble(inst, 4)]);
1445 return 0;
1448 if (!direction) offset *= -1;
1449 dbg_printf("\n\t%s\t", load ? "ldrd" : "strd");
1450 if (indexing)
1452 if (load && get_nibble(inst, 4) == 15)
1454 dbg_printf("%s, %s, ", tbl_regs[get_nibble(inst, 3)], tbl_regs[get_nibble(inst, 2)]);
1455 db_printsym(addr->Offset + offset + 4);
1457 else
1458 dbg_printf("%s, %s, [%s, #%d]%s", tbl_regs[get_nibble(inst, 3)],
1459 tbl_regs[get_nibble(inst, 2)], tbl_regs[get_nibble(inst, 4)], offset,
1460 writeback?"!":"");
1462 else
1463 dbg_printf("%s, %s, [%s], #%d", tbl_regs[get_nibble(inst, 3)],
1464 tbl_regs[get_nibble(inst, 2)], tbl_regs[get_nibble(inst, 4)], offset);
1465 return 0;
1468 struct inst_arm
1470 UINT mask;
1471 UINT pattern;
1472 UINT (*func)(UINT, ADDRESS64*);
1475 static const struct inst_arm tbl_arm[] = {
1476 { 0x0e000000, 0x0a000000, arm_disasm_branch },
1477 { 0x0fc000f0, 0x00000090, arm_disasm_mul },
1478 { 0x0f8000f0, 0x00800090, arm_disasm_longmul },
1479 { 0x0fb00ff0, 0x01000090, arm_disasm_swp },
1480 { 0x0e000090, 0x00000090, arm_disasm_halfwordtrans },
1481 { 0x0ffffff0, 0x012fff00, arm_disasm_branchreg },
1482 { 0x0ffffff0, 0x012fff10, arm_disasm_branchxchg },
1483 { 0x0fbf0fff, 0x010f0000, arm_disasm_mrstrans },
1484 { 0x0dbef000, 0x0128f000, arm_disasm_msrtrans },
1485 { 0x0fb00000, 0x03000000, arm_disasm_wordmov },
1486 { 0x0fffffff, 0x0320f000, arm_disasm_nop },
1487 { 0x0c000000, 0x00000000, arm_disasm_dataprocessing },
1488 { 0x0c000000, 0x04000000, arm_disasm_singletrans },
1489 { 0x0e000000, 0x08000000, arm_disasm_blocktrans },
1490 { 0x0f000000, 0x0f000000, arm_disasm_swi },
1491 { 0x0f000010, 0x0e000010, arm_disasm_coproctrans },
1492 { 0x0f000010, 0x0e000000, arm_disasm_coprocdataop },
1493 { 0x0e000000, 0x0c000000, arm_disasm_coprocdatatrans },
1494 { 0x00000000, 0x00000000, NULL }
1497 struct inst_thumb16
1499 WORD mask;
1500 WORD pattern;
1501 WORD (*func)(WORD, ADDRESS64*);
1504 static const struct inst_thumb16 tbl_thumb16[] = {
1505 { 0xfc00, 0x4400, thumb_disasm_hireg },
1506 { 0xfc00, 0x4000, thumb_disasm_aluop },
1507 { 0xf600, 0xb400, thumb_disasm_pushpop },
1508 { 0xf000, 0xc000, thumb_disasm_blocktrans },
1509 { 0xff00, 0xdf00, thumb_disasm_swi },
1510 { 0xf000, 0xd000, thumb_disasm_condbranch },
1511 { 0xf800, 0xe000, thumb_disasm_uncondbranch },
1512 { 0xf000, 0xa000, thumb_disasm_loadadr },
1513 { 0xf800, 0x4800, thumb_disasm_ldrpcrel },
1514 { 0xf000, 0x9000, thumb_disasm_ldrsprel },
1515 { 0xff00, 0xb000, thumb_disasm_addsprel },
1516 { 0xe000, 0x6000, thumb_disasm_ldrimm },
1517 { 0xf000, 0x8000, thumb_disasm_ldrhimm },
1518 { 0xf200, 0x5000, thumb_disasm_ldrreg },
1519 { 0xf200, 0x5200, thumb_disasm_ldrsreg },
1520 { 0xe000, 0x2000, thumb_disasm_immop },
1521 { 0xff00, 0xbf00, thumb_disasm_nop },
1522 { 0xf800, 0x1800, thumb_disasm_addsub },
1523 { 0xe000, 0x0000, thumb_disasm_movshift },
1524 { 0x0000, 0x0000, NULL }
1527 static const struct inst_arm tbl_thumb32[] = {
1528 { 0xfff0f000, 0xf3e08000, thumb2_disasm_srtrans },
1529 { 0xfff0f000, 0xf3808000, thumb2_disasm_srtrans },
1530 { 0xfff0d000, 0xf3a08000, thumb2_disasm_hint },
1531 { 0xfff0d000, 0xf3b08000, thumb2_disasm_miscctrl },
1532 { 0xf8008000, 0xf0008000, thumb2_disasm_branch },
1533 { 0xffc0f0c0, 0xfa80f080, thumb2_disasm_misc },
1534 { 0xff80f000, 0xfa00f000, thumb2_disasm_dataprocessingreg },
1535 { 0xff8000c0, 0xfb000000, thumb2_disasm_mul },
1536 { 0xff8000f0, 0xfb800000, thumb2_disasm_longmuldiv },
1537 { 0xff8000f0, 0xfb8000f0, thumb2_disasm_longmuldiv },
1538 { 0xff100000, 0xf8000000, thumb2_disasm_str },
1539 { 0xff700000, 0xf8500000, thumb2_disasm_ldrword },
1540 { 0xfe70f000, 0xf810f000, thumb2_disasm_preload },
1541 { 0xfe500000, 0xf8100000, thumb2_disasm_ldrnonword },
1542 { 0xfa008000, 0xf2000000, thumb2_disasm_dataprocessing },
1543 { 0xfa008000, 0xf0000000, thumb2_disasm_dataprocessingmod },
1544 { 0xfe008000, 0xea000000, thumb2_disasm_dataprocessingshift },
1545 { 0xef000010, 0xee000000, thumb2_disasm_coprocdat },
1546 { 0xef000010, 0xee000010, thumb2_disasm_coprocmov1 },
1547 { 0xefe00000, 0xec400000, thumb2_disasm_coprocmov2 },
1548 { 0xee000000, 0xec000000, thumb2_disasm_coprocdatatrans },
1549 { 0xfe402000, 0xe8000000, thumb2_disasm_ldrstrmul },
1550 { 0xfe400000, 0xe8400000, thumb2_disasm_ldrstrextbr },
1551 { 0x00000000, 0x00000000, NULL }
1554 /***********************************************************************
1555 * disasm_one_insn
1557 * Disassemble instruction at 'addr'. addr is changed to point to the
1558 * start of the next instruction.
1560 void be_arm_disasm_one_insn(ADDRESS64 *addr, int display)
1562 struct inst_arm *a_ptr = (struct inst_arm *)&tbl_arm;
1563 struct inst_thumb16 *t_ptr = (struct inst_thumb16 *)&tbl_thumb16;
1564 struct inst_arm *t2_ptr = (struct inst_arm *)&tbl_thumb32;
1565 UINT inst;
1566 WORD tinst;
1567 int size;
1568 int matched = 0;
1570 char tmp[64];
1571 DWORD_PTR* pval;
1573 if (!memory_get_register(CV_ARM_CPSR, &pval, tmp, sizeof(tmp)))
1574 dbg_printf("\n\tmemory_get_register failed: %s", tmp);
1575 else
1576 db_disasm_thumb = (*pval & 0x20) != 0;
1578 db_display = display;
1580 if (!db_disasm_thumb)
1582 size = ARM_INSN_SIZE;
1583 inst = db_get_inst( memory_to_linear_addr(addr), size );
1584 while (a_ptr->func) {
1585 if ((inst & a_ptr->mask) == a_ptr->pattern) {
1586 matched = 1;
1587 break;
1589 a_ptr++;
1592 if (!matched) {
1593 dbg_printf("\n\tUnknown ARM Instruction: %08x", inst);
1594 addr->Offset += size;
1596 else
1598 if (!a_ptr->func(inst, addr))
1599 addr->Offset += size;
1601 return;
1603 else
1605 WORD *taddr = memory_to_linear_addr(addr);
1606 tinst = db_get_inst( taddr, THUMB_INSN_SIZE );
1607 switch (tinst & 0xf800)
1609 case 0xe800:
1610 case 0xf000:
1611 case 0xf800:
1612 size = THUMB2_INSN_SIZE;
1613 taddr++;
1614 inst = db_get_inst( taddr, THUMB_INSN_SIZE );
1615 inst |= (tinst << 16);
1617 while (t2_ptr->func) {
1618 if ((inst & t2_ptr->mask) == t2_ptr->pattern) {
1619 matched = 1;
1620 break;
1622 t2_ptr++;
1625 if (!matched) {
1626 dbg_printf("\n\tUnknown Thumb2 Instruction: %08x", inst);
1627 addr->Offset += size;
1629 else
1631 if (!t2_ptr->func(inst, addr))
1632 addr->Offset += size;
1634 return;
1635 default:
1636 break;
1639 size = THUMB_INSN_SIZE;
1640 while (t_ptr->func) {
1641 if ((tinst & t_ptr->mask) == t_ptr->pattern) {
1642 matched = 1;
1643 break;
1645 t_ptr++;
1648 if (!matched) {
1649 dbg_printf("\n\tUnknown Thumb Instruction: %04x", tinst);
1650 addr->Offset += size;
1652 else
1654 if (!t_ptr->func(tinst, addr))
1655 addr->Offset += size;
1657 return;
1661 static BOOL be_arm_get_addr(HANDLE hThread, const dbg_ctx_t *ctx,
1662 enum be_cpu_addr bca, ADDRESS64* addr)
1664 switch (bca)
1666 case be_cpu_addr_pc:
1667 return be_cpu_build_addr(hThread, ctx, addr, 0, ctx->ctx.Pc);
1668 case be_cpu_addr_stack:
1669 return be_cpu_build_addr(hThread, ctx, addr, 0, ctx->ctx.Sp);
1670 case be_cpu_addr_frame:
1671 return be_cpu_build_addr(hThread, ctx, addr, 0, ctx->ctx.R11);
1673 return FALSE;
1676 static BOOL be_arm_get_register_info(int regno, enum be_cpu_addr* kind)
1678 switch (regno)
1680 case CV_ARM_PC: *kind = be_cpu_addr_pc; return TRUE;
1681 case CV_ARM_R0 + 11: *kind = be_cpu_addr_frame; return TRUE;
1682 case CV_ARM_SP: *kind = be_cpu_addr_stack; return TRUE;
1684 return FALSE;
1687 static void be_arm_single_step(dbg_ctx_t *ctx, BOOL enable)
1691 static void be_arm_print_context(HANDLE hThread, const dbg_ctx_t *ctx, int all_regs)
1693 static const char condflags[] = "NZCV";
1694 int i;
1695 char buf[8];
1697 switch (ctx->ctx.Cpsr & 0x1F)
1699 case 0: strcpy(buf, "User26"); break;
1700 case 1: strcpy(buf, "FIQ26"); break;
1701 case 2: strcpy(buf, "IRQ26"); break;
1702 case 3: strcpy(buf, "SVC26"); break;
1703 case 16: strcpy(buf, "User"); break;
1704 case 17: strcpy(buf, "FIQ"); break;
1705 case 18: strcpy(buf, "IRQ"); break;
1706 case 19: strcpy(buf, "SVC"); break;
1707 case 23: strcpy(buf, "ABT"); break;
1708 case 27: strcpy(buf, "UND"); break;
1709 default: strcpy(buf, "UNKNWN"); break;
1712 dbg_printf("Register dump:\n");
1713 dbg_printf("%s %s Mode\n", (ctx->ctx.Cpsr & 0x20) ? "Thumb" : "ARM", buf);
1715 strcpy(buf, condflags);
1716 for (i = 0; buf[i]; i++)
1717 if (!((ctx->ctx.Cpsr >> 26) & (1 << (sizeof(condflags) - i))))
1718 buf[i] = '-';
1720 dbg_printf(" Pc:%08x Sp:%08x Lr:%08x Cpsr:%08x(%s)\n",
1721 ctx->ctx.Pc, ctx->ctx.Sp, ctx->ctx.Lr, ctx->ctx.Cpsr, buf);
1722 dbg_printf(" r0:%08x r1:%08x r2:%08x r3:%08x\n",
1723 ctx->ctx.R0, ctx->ctx.R1, ctx->ctx.R2, ctx->ctx.R3);
1724 dbg_printf(" r4:%08x r5:%08x r6:%08x r7:%08x\n",
1725 ctx->ctx.R4, ctx->ctx.R5, ctx->ctx.R6, ctx->ctx.R7);
1726 dbg_printf(" r8:%08x r9:%08x r10:%08x r11:%08x r12:%08x\n",
1727 ctx->ctx.R8, ctx->ctx.R9, ctx->ctx.R10, ctx->ctx.R11, ctx->ctx.R12);
1729 if (all_regs) dbg_printf( "Floating point ARM dump not implemented\n" );
1732 static void be_arm_print_segment_info(HANDLE hThread, const dbg_ctx_t *ctx)
1736 static struct dbg_internal_var be_arm_ctx[] =
1738 {CV_ARM_R0 + 0, "r0", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R0), dbg_itype_unsigned_int},
1739 {CV_ARM_R0 + 1, "r1", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R1), dbg_itype_unsigned_int},
1740 {CV_ARM_R0 + 2, "r2", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R2), dbg_itype_unsigned_int},
1741 {CV_ARM_R0 + 3, "r3", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R3), dbg_itype_unsigned_int},
1742 {CV_ARM_R0 + 4, "r4", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R4), dbg_itype_unsigned_int},
1743 {CV_ARM_R0 + 5, "r5", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R5), dbg_itype_unsigned_int},
1744 {CV_ARM_R0 + 6, "r6", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R6), dbg_itype_unsigned_int},
1745 {CV_ARM_R0 + 7, "r7", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R7), dbg_itype_unsigned_int},
1746 {CV_ARM_R0 + 8, "r8", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R8), dbg_itype_unsigned_int},
1747 {CV_ARM_R0 + 9, "r9", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R9), dbg_itype_unsigned_int},
1748 {CV_ARM_R0 + 10, "r10", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R10), dbg_itype_unsigned_int},
1749 {CV_ARM_R0 + 11, "r11", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R11), dbg_itype_unsigned_int},
1750 {CV_ARM_R0 + 12, "r12", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R12), dbg_itype_unsigned_int},
1751 {CV_ARM_SP, "sp", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Sp), dbg_itype_unsigned_int},
1752 {CV_ARM_LR, "lr", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Lr), dbg_itype_unsigned_int},
1753 {CV_ARM_PC, "pc", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Pc), dbg_itype_unsigned_int},
1754 {CV_ARM_CPSR, "cpsr", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Cpsr), dbg_itype_unsigned_int},
1755 {0, NULL, 0, dbg_itype_none}
1758 static BOOL be_arm_is_step_over_insn(const void* insn)
1760 dbg_printf("be_arm_is_step_over_insn: not done\n");
1761 return FALSE;
1764 static BOOL be_arm_is_function_return(const void* insn)
1766 dbg_printf("be_arm_is_function_return: not done\n");
1767 return FALSE;
1770 static BOOL be_arm_is_break_insn(const void* insn)
1772 dbg_printf("be_arm_is_break_insn: not done\n");
1773 return FALSE;
1776 static BOOL be_arm_is_func_call(const void* insn, ADDRESS64* callee)
1778 return FALSE;
1781 static BOOL be_arm_is_jump(const void* insn, ADDRESS64* jumpee)
1783 return FALSE;
1786 static BOOL be_arm_insert_Xpoint(HANDLE hProcess, const struct be_process_io* pio,
1787 dbg_ctx_t *ctx, enum be_xpoint_type type,
1788 void* addr, unsigned long* val, unsigned size)
1790 SIZE_T sz;
1792 switch (type)
1794 case be_xpoint_break:
1795 if (!size) return FALSE;
1796 if (!pio->read(hProcess, addr, val, 4, &sz) || sz != 4) return FALSE;
1797 default:
1798 dbg_printf("Unknown/unsupported bp type %c\n", type);
1799 return FALSE;
1801 return TRUE;
1804 static BOOL be_arm_remove_Xpoint(HANDLE hProcess, const struct be_process_io* pio,
1805 dbg_ctx_t *ctx, enum be_xpoint_type type,
1806 void* addr, unsigned long val, unsigned size)
1808 SIZE_T sz;
1810 switch (type)
1812 case be_xpoint_break:
1813 if (!size) return FALSE;
1814 if (!pio->write(hProcess, addr, &val, 4, &sz) || sz == 4) return FALSE;
1815 break;
1816 default:
1817 dbg_printf("Unknown/unsupported bp type %c\n", type);
1818 return FALSE;
1820 return TRUE;
1823 static BOOL be_arm_is_watchpoint_set(const dbg_ctx_t *ctx, unsigned idx)
1825 dbg_printf("be_arm_is_watchpoint_set: not done\n");
1826 return FALSE;
1829 static void be_arm_clear_watchpoint(dbg_ctx_t *ctx, unsigned idx)
1831 dbg_printf("be_arm_clear_watchpoint: not done\n");
1834 static int be_arm_adjust_pc_for_break(dbg_ctx_t *ctx, BOOL way)
1836 INT step = (ctx->ctx.Cpsr & 0x20) ? 2 : 4;
1838 if (way)
1840 ctx->ctx.Pc -= step;
1841 return -step;
1843 ctx->ctx.Pc += step;
1844 return step;
1847 static BOOL be_arm_fetch_integer(const struct dbg_lvalue* lvalue, unsigned size,
1848 BOOL is_signed, LONGLONG* ret)
1850 if (size != 1 && size != 2 && size != 4 && size != 8) return FALSE;
1852 memset(ret, 0, sizeof(*ret)); /* clear unread bytes */
1853 /* FIXME: this assumes that debuggee and debugger use the same
1854 * integral representation
1856 if (!memory_read_value(lvalue, size, ret)) return FALSE;
1858 /* propagate sign information */
1859 if (is_signed && size < 8 && (*ret >> (size * 8 - 1)) != 0)
1861 ULONGLONG neg = -1;
1862 *ret |= neg << (size * 8);
1864 return TRUE;
1867 static BOOL be_arm_fetch_float(const struct dbg_lvalue* lvalue, unsigned size,
1868 long double* ret)
1870 char tmp[sizeof(long double)];
1872 /* FIXME: this assumes that debuggee and debugger use the same
1873 * representation for reals
1875 if (!memory_read_value(lvalue, size, tmp)) return FALSE;
1877 if (size == sizeof(float)) *ret = *(float*)tmp;
1878 else if (size == sizeof(double)) *ret = *(double*)tmp;
1879 else if (size == sizeof(long double)) *ret = *(long double*)tmp;
1880 else return FALSE;
1882 return TRUE;
1885 static BOOL be_arm_store_integer(const struct dbg_lvalue* lvalue, unsigned size,
1886 BOOL is_signed, LONGLONG val)
1888 /* this is simple if we're on a little endian CPU */
1889 return memory_write_value(lvalue, size, &val);
1892 static BOOL be_arm_get_context(HANDLE thread, dbg_ctx_t *ctx)
1894 ctx->ctx.ContextFlags = CONTEXT_ALL;
1895 return GetThreadContext(thread, &ctx->ctx);
1898 static BOOL be_arm_set_context(HANDLE thread, const dbg_ctx_t *ctx)
1900 return SetThreadContext(thread, &ctx->ctx);
1903 #define REG(r,gs) {FIELD_OFFSET(CONTEXT, r), sizeof(((CONTEXT*)NULL)->r), gs}
1905 static struct gdb_register be_arm_gdb_register_map[] = {
1906 REG(R0, 4),
1907 REG(R1, 4),
1908 REG(R2, 4),
1909 REG(R3, 4),
1910 REG(R4, 4),
1911 REG(R5, 4),
1912 REG(R6, 4),
1913 REG(R7, 4),
1914 REG(R8, 4),
1915 REG(R9, 4),
1916 REG(R10, 4),
1917 REG(R11, 4),
1918 REG(R12, 4),
1919 REG(Sp, 4),
1920 REG(Lr, 4),
1921 REG(Pc, 4),
1922 REG(Cpsr, 4),
1925 struct backend_cpu be_arm =
1927 IMAGE_FILE_MACHINE_ARMNT,
1929 be_cpu_linearize,
1930 be_cpu_build_addr,
1931 be_arm_get_addr,
1932 be_arm_get_register_info,
1933 be_arm_single_step,
1934 be_arm_print_context,
1935 be_arm_print_segment_info,
1936 be_arm_ctx,
1937 be_arm_is_step_over_insn,
1938 be_arm_is_function_return,
1939 be_arm_is_break_insn,
1940 be_arm_is_func_call,
1941 be_arm_is_jump,
1942 be_arm_disasm_one_insn,
1943 be_arm_insert_Xpoint,
1944 be_arm_remove_Xpoint,
1945 be_arm_is_watchpoint_set,
1946 be_arm_clear_watchpoint,
1947 be_arm_adjust_pc_for_break,
1948 be_arm_fetch_integer,
1949 be_arm_fetch_float,
1950 be_arm_store_integer,
1951 be_arm_get_context,
1952 be_arm_set_context,
1953 be_arm_gdb_register_map,
1954 ARRAY_SIZE(be_arm_gdb_register_map),
1956 #endif