kernel32/tests: Add UTF-7 stray + sign removal tests.
[wine.git] / programs / winedbg / be_arm.c
blobbf28a044c4b4cc465c83c1cf9e4004453cb6b25d
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 CONTEXT* 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->Pc);
1668 case be_cpu_addr_stack:
1669 return be_cpu_build_addr(hThread, ctx, addr, 0, ctx->Sp);
1670 case be_cpu_addr_frame:
1671 return be_cpu_build_addr(hThread, ctx, addr, 0, ctx->Fp);
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(CONTEXT* ctx, BOOL enable)
1691 static void be_arm_print_context(HANDLE hThread, const CONTEXT* ctx, int all_regs)
1693 static const char condflags[] = "NZCV";
1694 int i;
1695 char buf[8];
1697 switch (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->Cpsr & 0x20) ? "Thumb" : "ARM", buf);
1715 strcpy(buf, condflags);
1716 for (i = 0; buf[i]; i++)
1717 if (!((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->Pc, ctx->Sp, ctx->Lr, ctx->Cpsr, buf);
1722 dbg_printf(" r0:%08x r1:%08x r2:%08x r3:%08x\n",
1723 ctx->R0, ctx->R1, ctx->R2, ctx->R3);
1724 dbg_printf(" r4:%08x r5:%08x r6:%08x r7:%08x\n",
1725 ctx->R4, ctx->R5, ctx->R6, ctx->R7);
1726 dbg_printf(" r8:%08x r9:%08x r10:%08x Fp:%08x Ip:%08x\n",
1727 ctx->R8, ctx->R9, ctx->R10, ctx->Fp, ctx->Ip);
1729 if (all_regs) dbg_printf( "Floating point ARM dump not implemented\n" );
1732 static void be_arm_print_segment_info(HANDLE hThread, const CONTEXT* 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, Fp), dbg_itype_unsigned_int},
1750 {CV_ARM_R0 + 12, "r12", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Ip), 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 CONTEXT* 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 CONTEXT* 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 CONTEXT* ctx, unsigned idx)
1825 dbg_printf("be_arm_is_watchpoint_set: not done\n");
1826 return FALSE;
1829 static void be_arm_clear_watchpoint(CONTEXT* ctx, unsigned idx)
1831 dbg_printf("be_arm_clear_watchpoint: not done\n");
1834 static int be_arm_adjust_pc_for_break(CONTEXT* ctx, BOOL way)
1836 INT step = (ctx->Cpsr & 0x20) ? 2 : 4;
1838 if (way)
1840 ctx->Pc -= step;
1841 return -step;
1843 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 struct backend_cpu be_arm =
1894 IMAGE_FILE_MACHINE_ARMNT,
1896 be_cpu_linearize,
1897 be_cpu_build_addr,
1898 be_arm_get_addr,
1899 be_arm_get_register_info,
1900 be_arm_single_step,
1901 be_arm_print_context,
1902 be_arm_print_segment_info,
1903 be_arm_ctx,
1904 be_arm_is_step_over_insn,
1905 be_arm_is_function_return,
1906 be_arm_is_break_insn,
1907 be_arm_is_func_call,
1908 be_arm_is_jump,
1909 be_arm_disasm_one_insn,
1910 be_arm_insert_Xpoint,
1911 be_arm_remove_Xpoint,
1912 be_arm_is_watchpoint_set,
1913 be_arm_clear_watchpoint,
1914 be_arm_adjust_pc_for_break,
1915 be_arm_fetch_integer,
1916 be_arm_fetch_float,
1917 be_arm_store_integer,
1919 #endif