winevulkan: Update to VK spec version 1.2.188.
[wine.git] / programs / winedbg / be_arm.c
blobb09bc5319b7a260f23e7b93d35165f1d2cefc1ea
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 dbg_printf("\n\t%s%s%s%s%s", load ? "ldr" : "str", sign ? "s" : "",
196 halfword ? "h" : (sign ? "b" : ""), writeback ? "t" : "", get_cond(inst));
197 dbg_printf("\t%s, ", tbl_regs[get_nibble(inst, 3)]);
198 if (indexing)
200 if (immediate)
201 dbg_printf("[%s, #%s%d]", tbl_regs[get_nibble(inst, 4)], direction ? "" : "-", offset);
202 else
203 dbg_printf("[%s, %s]", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
205 else
207 if (immediate)
208 dbg_printf("[%s], #%s%d", tbl_regs[get_nibble(inst, 4)], direction ? "" : "-", offset);
209 else
210 dbg_printf("[%s], %s", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
212 return 0;
215 static UINT arm_disasm_branchxchg(UINT inst, ADDRESS64 *addr)
217 dbg_printf("\n\tbx%s\t%s", get_cond(inst), tbl_regs[get_nibble(inst, 0)]);
218 return 0;
221 static UINT arm_disasm_mrstrans(UINT inst, ADDRESS64 *addr)
223 short src = (inst >> 22) & 0x01;
225 dbg_printf("\n\tmrs%s\t%s, %s", get_cond(inst), tbl_regs[get_nibble(inst, 3)],
226 src ? "spsr" : "cpsr");
227 return 0;
230 static UINT arm_disasm_msrtrans(UINT inst, ADDRESS64 *addr)
232 short immediate = (inst >> 25) & 0x01;
233 short dst = (inst >> 22) & 0x01;
234 short simple = (inst >> 16) & 0x01;
236 if (simple || !immediate)
238 dbg_printf("\n\tmsr%s\t%s, %s", get_cond(inst), dst ? "spsr" : "cpsr",
239 tbl_regs[get_nibble(inst, 0)]);
240 return 0;
243 dbg_printf("\n\tmsr%s\t%s, #%u", get_cond(inst), dst ? "spsr" : "cpsr",
244 ROR32(inst & 0xff, 2 * get_nibble(inst, 2)));
245 return 0;
248 static UINT arm_disasm_wordmov(UINT inst, ADDRESS64 *addr)
250 short top = (inst >> 22) & 0x01;
252 dbg_printf("\n\tmov%s%s\t%s, #%u", top ? "t" : "w", get_cond(inst),
253 tbl_regs[get_nibble(inst, 3)], (get_nibble(inst, 4) << 12) | (inst & 0x0fff));
254 return 0;
257 static UINT arm_disasm_nop(UINT inst, ADDRESS64 *addr)
259 dbg_printf("\n\tnop%s", get_cond(inst));
260 return 0;
263 static UINT arm_disasm_dataprocessing(UINT inst, ADDRESS64 *addr)
265 short condcodes = (inst >> 20) & 0x01;
266 short opcode = (inst >> 21) & 0x0f;
267 short immediate = (inst >> 25) & 0x01;
268 short no_op1 = (opcode & 0x0d) == 0x0d;
269 short no_dst = (opcode & 0x0c) == 0x08;
271 dbg_printf("\n\t%s%s%s", tbl_dataops[opcode], condcodes ? "s" : "", get_cond(inst));
272 if (!no_dst) dbg_printf("\t%s, ", tbl_regs[get_nibble(inst, 3)]);
273 else dbg_printf("\t");
275 if (no_op1)
277 if (immediate)
278 dbg_printf("#%u", ROR32(inst & 0xff, 2 * get_nibble(inst, 2)));
279 else
280 dbg_printf("%s", tbl_regs[get_nibble(inst, 0)]);
282 else
284 if (immediate)
285 dbg_printf("%s, #%u", tbl_regs[get_nibble(inst, 4)],
286 ROR32(inst & 0xff, 2 * get_nibble(inst, 2)));
287 else if (((inst >> 4) & 0xff) == 0x00) /* no shift */
288 dbg_printf("%s, %s", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
289 else if (((inst >> 4) & 0x09) == 0x01) /* register shift */
290 dbg_printf("%s, %s, %s %s", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)],
291 tbl_shifts[(inst >> 5) & 0x03], tbl_regs[(inst >> 8) & 0x0f]);
292 else if (((inst >> 4) & 0x01) == 0x00) /* immediate shift */
293 dbg_printf("%s, %s, %s #%d", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)],
294 tbl_shifts[(inst >> 5) & 0x03], (inst >> 7) & 0x1f);
295 else
296 return inst;
298 return 0;
301 static UINT arm_disasm_singletrans(UINT inst, ADDRESS64 *addr)
303 short load = (inst >> 20) & 0x01;
304 short writeback = (inst >> 21) & 0x01;
305 short byte = (inst >> 22) & 0x01;
306 short direction = (inst >> 23) & 0x01;
307 short indexing = (inst >> 24) & 0x01;
308 short immediate = !((inst >> 25) & 0x01);
309 short offset = inst & 0x0fff;
311 dbg_printf("\n\t%s%s%s%s", load ? "ldr" : "str", byte ? "b" : "", writeback ? "t" : "",
312 get_cond(inst));
313 dbg_printf("\t%s, ", tbl_regs[get_nibble(inst, 3)]);
314 if (indexing)
316 if (immediate)
317 dbg_printf("[%s, #%s%d]", tbl_regs[get_nibble(inst, 4)], direction ? "" : "-", offset);
318 else if (((inst >> 4) & 0xff) == 0x00) /* no shift */
319 dbg_printf("[%s, %s]", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
320 else if (((inst >> 4) & 0x01) == 0x00) /* immediate shift (there's no register shift) */
321 dbg_printf("[%s, %s, %s #%d]", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)],
322 tbl_shifts[(inst >> 5) & 0x03], (inst >> 7) & 0x1f);
323 else
324 return inst;
326 else
328 if (immediate)
329 dbg_printf("[%s], #%s%d", tbl_regs[get_nibble(inst, 4)], direction ? "" : "-", offset);
330 else if (((inst >> 4) & 0xff) == 0x00) /* no shift */
331 dbg_printf("[%s], %s", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
332 else if (((inst >> 4) & 0x01) == 0x00) /* immediate shift (there's no register shift) */
333 dbg_printf("[%s], %s, %s #%d", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)],
334 tbl_shifts[(inst >> 5) & 0x03], (inst >> 7) & 0x1f);
335 else
336 return inst;
338 return 0;
341 static UINT arm_disasm_blocktrans(UINT inst, ADDRESS64 *addr)
343 short load = (inst >> 20) & 0x01;
344 short writeback = (inst >> 21) & 0x01;
345 short psr = (inst >> 22) & 0x01;
346 short addrmode = (inst >> 23) & 0x03;
347 short i;
348 short last=15;
349 for (i=15;i>=0;i--)
350 if ((inst>>i) & 1)
352 last = i;
353 break;
356 dbg_printf("\n\t%s%s%s\t%s%s, {", load ? "ldm" : "stm", tbl_addrmode[addrmode], get_cond(inst),
357 tbl_regs[get_nibble(inst, 4)], writeback ? "!" : "");
358 for (i=0;i<=15;i++)
359 if ((inst>>i) & 1)
361 if (i == last) dbg_printf("%s", tbl_regs[i]);
362 else dbg_printf("%s, ", tbl_regs[i]);
364 dbg_printf("}%s", psr ? "^" : "");
365 return 0;
368 static UINT arm_disasm_swi(UINT inst, ADDRESS64 *addr)
370 dbg_printf("\n\tswi%s\t#%d", get_cond(inst), inst & 0x00ffffff);
371 return 0;
374 static UINT arm_disasm_coproctrans(UINT inst, ADDRESS64 *addr)
376 WORD CRm = inst & 0x0f;
377 WORD CP = (inst >> 5) & 0x07;
378 WORD CPnum = (inst >> 8) & 0x0f;
379 WORD CRn = (inst >> 16) & 0x0f;
380 WORD load = (inst >> 20) & 0x01;
381 WORD CP_Opc = (inst >> 21) & 0x07;
383 dbg_printf("\n\t%s%s\t%u, %u, %s, cr%u, cr%u, {%u}", load ? "mrc" : "mcr", get_cond(inst), CPnum,
384 CP, tbl_regs[get_nibble(inst, 3)], CRn, CRm, CP_Opc);
385 return 0;
388 static UINT arm_disasm_coprocdataop(UINT inst, ADDRESS64 *addr)
390 WORD CRm = inst & 0x0f;
391 WORD CP = (inst >> 5) & 0x07;
392 WORD CPnum = (inst >> 8) & 0x0f;
393 WORD CRd = (inst >> 12) & 0x0f;
394 WORD CRn = (inst >> 16) & 0x0f;
395 WORD CP_Opc = (inst >> 20) & 0x0f;
397 dbg_printf("\n\tcdp%s\t%u, %u, cr%u, cr%u, cr%u, {%u}", get_cond(inst),
398 CPnum, CP, CRd, CRn, CRm, CP_Opc);
399 return 0;
402 static UINT arm_disasm_coprocdatatrans(UINT inst, ADDRESS64 *addr)
404 WORD CPnum = (inst >> 8) & 0x0f;
405 WORD CRd = (inst >> 12) & 0x0f;
406 WORD load = (inst >> 20) & 0x01;
407 WORD writeback = (inst >> 21) & 0x01;
408 WORD translen = (inst >> 22) & 0x01;
409 WORD direction = (inst >> 23) & 0x01;
410 WORD indexing = (inst >> 24) & 0x01;
411 short offset = (inst & 0xff) << 2;
413 dbg_printf("\n\t%s%s%s", load ? "ldc" : "stc", translen ? "l" : "", get_cond(inst));
414 if (indexing)
415 dbg_printf("\t%u, cr%u, [%s, #%s%d]%s", CPnum, CRd, tbl_regs[get_nibble(inst, 4)], direction ? "" : "-", offset, writeback?"!":"");
416 else
417 dbg_printf("\t%u, cr%u, [%s], #%s%d", CPnum, CRd, tbl_regs[get_nibble(inst, 4)], direction ? "" : "-", offset);
418 return 0;
421 static WORD thumb_disasm_hireg(WORD inst, ADDRESS64 *addr)
423 short dst = inst & 0x07;
424 short src = (inst >> 3) & 0x07;
425 short h2 = (inst >> 6) & 0x01;
426 short h1 = (inst >> 7) & 0x01;
427 short op = (inst >> 8) & 0x03;
429 if (h1) dst += 8;
430 if (h2) src += 8;
432 if (op == 2 && dst == src) /* mov rx, rx */
434 dbg_printf("\n\tnop");
435 return 0;
438 if (op == 3)
439 dbg_printf("\n\tb%sx\t%s", h1?"l":"", tbl_regs[src]);
440 else
441 dbg_printf("\n\t%s\t%s, %s", tbl_hiops_t[op], tbl_regs[dst], tbl_regs[src]);
443 return 0;
446 static WORD thumb_disasm_aluop(WORD inst, ADDRESS64 *addr)
448 short dst = inst & 0x07;
449 short src = (inst >> 3) & 0x07;
450 short op = (inst >> 6) & 0x0f;
452 dbg_printf("\n\t%s\t%s, %s", tbl_aluops_t[op], tbl_regs[dst], tbl_regs[src]);
454 return 0;
457 static WORD thumb_disasm_pushpop(WORD inst, ADDRESS64 *addr)
459 short lrpc = (inst >> 8) & 0x01;
460 short load = (inst >> 11) & 0x01;
461 short i;
462 short last;
464 for (i=7;i>=0;i--)
465 if ((inst>>i) & 1) break;
466 last = i;
468 dbg_printf("\n\t%s\t{", load ? "pop" : "push");
470 for (i=0;i<=7;i++)
471 if ((inst>>i) & 1)
473 if (i == last) dbg_printf("%s", tbl_regs[i]);
474 else dbg_printf("%s, ", tbl_regs[i]);
476 if (lrpc)
477 dbg_printf("%s%s", last ? ", " : "", load ? "pc" : "lr");
479 dbg_printf("}");
480 return 0;
483 static WORD thumb_disasm_blocktrans(WORD inst, ADDRESS64 *addr)
485 short load = (inst >> 11) & 0x01;
486 short i;
487 short last;
489 for (i=7;i>=0;i--)
490 if ((inst>>i) & 1) break;
491 last = i;
493 dbg_printf("\n\t%s\t%s!, {", load ? "ldmia" : "stmia", tbl_regs[(inst >> 8) & 0x07]);
495 for (i=0;i<=7;i++)
496 if ((inst>>i) & 1)
498 if (i == last) dbg_printf("%s", tbl_regs[i]);
499 else dbg_printf("%s, ", tbl_regs[i]);
502 dbg_printf("}");
503 return 0;
506 static WORD thumb_disasm_swi(WORD inst, ADDRESS64 *addr)
508 dbg_printf("\n\tswi\t#%d", inst & 0x00ff);
509 return 0;
512 static WORD thumb_disasm_condbranch(WORD inst, ADDRESS64 *addr)
514 WORD offset = inst & 0x00ff;
515 dbg_printf("\n\tb%s\t", tbl_cond[(inst >> 8) & 0x0f]);
516 db_printsym(addr->Offset + offset);
517 return 0;
520 static WORD thumb_disasm_uncondbranch(WORD inst, ADDRESS64 *addr)
522 short offset = (inst & 0x07ff) << 1;
524 if (offset & 0x0800) offset |= 0xf000;
525 offset += 4;
527 dbg_printf("\n\tb\t");
528 db_printsym(addr->Offset + offset);
529 return 0;
532 static WORD thumb_disasm_loadadr(WORD inst, ADDRESS64 *addr)
534 WORD src = (inst >> 11) & 0x01;
535 WORD offset = (inst & 0xff) << 2;
537 dbg_printf("\n\tadd\t%s, %s, #%d", tbl_regs[(inst >> 8) & 0x07], src ? "sp" : "pc", offset);
538 return 0;
541 static WORD thumb_disasm_ldrpcrel(WORD inst, ADDRESS64 *addr)
543 WORD offset = (inst & 0xff) << 2;
544 dbg_printf("\n\tldr\t%s, [pc, #%u]", tbl_regs[(inst >> 8) & 0x07], offset);
545 return 0;
548 static WORD thumb_disasm_ldrsprel(WORD inst, ADDRESS64 *addr)
550 WORD offset = (inst & 0xff) << 2;
551 dbg_printf("\n\t%s\t%s, [sp, #%u]", (inst & 0x0800)?"ldr":"str", tbl_regs[(inst >> 8) & 0x07], offset);
552 return 0;
555 static WORD thumb_disasm_addsprel(WORD inst, ADDRESS64 *addr)
557 WORD offset = (inst & 0x7f) << 2;
558 if ((inst >> 7) & 0x01)
559 dbg_printf("\n\tsub\tsp, sp, #%u", offset);
560 else
561 dbg_printf("\n\tadd\tsp, sp, #%u", offset);
562 return 0;
565 static WORD thumb_disasm_ldrimm(WORD inst, ADDRESS64 *addr)
567 WORD offset = (inst & 0x07c0) >> 6;
568 dbg_printf("\n\t%s%s\t%s, [%s, #%u]", (inst & 0x0800)?"ldr":"str", (inst & 0x1000)?"b":"",
569 tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07], (inst & 0x1000)?offset:(offset << 2));
570 return 0;
573 static WORD thumb_disasm_ldrhimm(WORD inst, ADDRESS64 *addr)
575 WORD offset = (inst & 0x07c0) >> 5;
576 dbg_printf("\n\t%s\t%s, [%s, #%u]", (inst & 0x0800)?"ldrh":"strh",
577 tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07], offset);
578 return 0;
581 static WORD thumb_disasm_ldrreg(WORD inst, ADDRESS64 *addr)
583 dbg_printf("\n\t%s%s\t%s, [%s, %s]", (inst & 0x0800)?"ldr":"str", (inst & 0x0400)?"b":"",
584 tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07], tbl_regs[(inst >> 6) & 0x07]);
585 return 0;
588 static WORD thumb_disasm_ldrsreg(WORD inst, ADDRESS64 *addr)
590 dbg_printf("\n\t%s\t%s, [%s, %s]", tbl_sregops_t[(inst >> 10) & 0x03],
591 tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07], tbl_regs[(inst >> 6) & 0x07]);
592 return 0;
595 static WORD thumb_disasm_immop(WORD inst, ADDRESS64 *addr)
597 WORD op = (inst >> 11) & 0x03;
598 dbg_printf("\n\t%s\t%s, #%u", tbl_immops_t[op], tbl_regs[(inst >> 8) & 0x07], inst & 0xff);
599 return 0;
602 static WORD thumb_disasm_nop(WORD inst, ADDRESS64 *addr)
604 dbg_printf("\n\tnop");
605 return 0;
608 static WORD thumb_disasm_addsub(WORD inst, ADDRESS64 *addr)
610 WORD op = (inst >> 9) & 0x01;
611 WORD immediate = (inst >> 10) & 0x01;
613 dbg_printf("\n\t%s\t%s, %s, ", op ? "sub" : "add",
614 tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07]);
615 if (immediate)
616 dbg_printf("#%d", (inst >> 6) & 0x07);
617 else
618 dbg_printf("%s", tbl_regs[(inst >> 6) & 0x07]);
619 return 0;
622 static WORD thumb_disasm_movshift(WORD inst, ADDRESS64 *addr)
624 WORD op = (inst >> 11) & 0x03;
625 dbg_printf("\n\t%s\t%s, %s, #%u", tbl_shifts[op],
626 tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07], (inst >> 6) & 0x1f);
627 return 0;
630 static UINT thumb2_disasm_srtrans(UINT inst, ADDRESS64 *addr)
632 UINT fromsr = (inst >> 21) & 0x03;
633 UINT sysreg = inst & 0xff;
635 if (fromsr == 3 && get_nibble(inst,4) == 0x0f && sysreg <= 20)
637 dbg_printf("\n\tmrs\t%s, %s", tbl_regs[get_nibble(inst, 2)], tbl_special_regs_t2[sysreg]);
638 return 0;
641 if (fromsr == 0 && sysreg <= 20)
643 dbg_printf("\n\tmsr\t%s, %s", tbl_special_regs_t2[sysreg], tbl_regs[get_nibble(inst, 4)]);
644 return 0;
647 return inst;
650 static UINT thumb2_disasm_hint(UINT inst, ADDRESS64 *addr)
652 WORD op1 = (inst >> 8) & 0x07;
653 WORD op2 = inst & 0xff;
655 if (op1) return inst;
657 if (op2 <= 4)
659 dbg_printf("\n\t%s", tbl_hints_t2[op2]);
660 return 0;
663 if (op2 & 0xf0)
665 dbg_printf("\n\tdbg\t#%u", get_nibble(inst, 0));
666 return 0;
669 return inst;
672 static UINT thumb2_disasm_miscctrl(UINT inst, ADDRESS64 *addr)
674 WORD op = (inst >> 4) & 0x0f;
676 switch (op)
678 case 2:
679 dbg_printf("\n\tclrex");
680 break;
681 case 4:
682 dbg_printf("\n\tdsb\t#%u", get_nibble(inst, 0));
683 break;
684 case 5:
685 dbg_printf("\n\tdmb\t#%u", get_nibble(inst, 0));
686 break;
687 case 6:
688 dbg_printf("\n\tisb\t#%u", get_nibble(inst, 0));
689 break;
690 default:
691 return inst;
694 return 0;
697 static UINT thumb2_disasm_branch(UINT inst, ADDRESS64 *addr)
699 UINT S = (inst >> 26) & 0x01;
700 UINT L = (inst >> 14) & 0x01;
701 UINT I1 = !(((inst >> 13) & 0x01) ^ S);
702 UINT C = !((inst >> 12) & 0x01);
703 UINT I2 = !(((inst >> 11) & 0x01) ^ S);
704 UINT offset = (inst & 0x000007ff) << 1;
706 if (C)
708 offset |= I1 << 19 | I2 << 18 | (inst & 0x003f0000) >> 4;
709 if (S) offset |= 0x0fff << 20;
711 else
713 offset |= I1 << 23 | I2 << 22 | (inst & 0x03ff0000) >> 4;
714 if (S) offset |= 0xff << 24;
717 dbg_printf("\n\tb%s%s\t", L ? "l" : "", C ? tbl_cond[(inst >> 22) & 0x0f] : "");
718 db_printsym(addr->Offset + offset + 4);
719 return 0;
722 static UINT thumb2_disasm_misc(UINT inst, ADDRESS64 *addr)
724 WORD op1 = (inst >> 20) & 0x03;
725 WORD op2 = (inst >> 4) & 0x03;
727 if (get_nibble(inst, 4) != get_nibble(inst, 0))
728 return inst;
730 if (op1 == 3 && op2 == 0)
732 dbg_printf("\n\tclz\t%s, %s", tbl_regs[get_nibble(inst, 2)], tbl_regs[get_nibble(inst, 0)]);
733 return 0;
736 if (op1 == 1)
738 dbg_printf("\n\t%s\t%s, %s", tbl_miscops_t2[op2], tbl_regs[get_nibble(inst, 2)],
739 tbl_regs[get_nibble(inst, 0)]);
740 return 0;
743 return inst;
746 static UINT thumb2_disasm_dataprocessingreg(UINT inst, ADDRESS64 *addr)
748 WORD op1 = (inst >> 20) & 0x07;
749 WORD op2 = (inst >> 4) & 0x0f;
751 if (!op2)
753 dbg_printf("\n\t%s%s\t%s, %s, %s", tbl_shifts[op1 >> 1], (op1 & 1)?"s":"",
754 tbl_regs[get_nibble(inst, 2)], tbl_regs[get_nibble(inst, 4)],
755 tbl_regs[get_nibble(inst, 0)]);
756 return 0;
759 if ((op2 & 0x0C) == 0x08 && get_nibble(inst, 4) == 0x0f)
761 dbg_printf("\n\t%sxt%s\t%s, %s", (op1 & 1)?"u":"s", (op1 & 4)?"b":"h",
762 tbl_regs[get_nibble(inst, 2)], tbl_regs[get_nibble(inst, 0)]);
763 if (op2 & 0x03)
764 dbg_printf(", ROR #%u", (op2 & 3) * 8);
765 return 0;
768 return inst;
771 static UINT thumb2_disasm_mul(UINT inst, ADDRESS64 *addr)
773 WORD op1 = (inst >> 20) & 0x07;
774 WORD op2 = (inst >> 4) & 0x03;
776 if (op1)
777 return inst;
779 if (op2 == 0 && get_nibble(inst, 3) != 0xf)
781 dbg_printf("\n\tmla\t%s, %s, %s, %s", tbl_regs[get_nibble(inst, 2)],
782 tbl_regs[get_nibble(inst, 4)],
783 tbl_regs[get_nibble(inst, 0)],
784 tbl_regs[get_nibble(inst, 3)]);
785 return 0;
788 if (op2 == 0 && get_nibble(inst, 3) == 0xf)
790 dbg_printf("\n\tmul\t%s, %s, %s", tbl_regs[get_nibble(inst, 2)],
791 tbl_regs[get_nibble(inst, 4)],
792 tbl_regs[get_nibble(inst, 0)]);
793 return 0;
796 if (op2 == 1)
798 dbg_printf("\n\tmls\t%s, %s, %s, %s", tbl_regs[get_nibble(inst, 2)],
799 tbl_regs[get_nibble(inst, 4)],
800 tbl_regs[get_nibble(inst, 0)],
801 tbl_regs[get_nibble(inst, 3)]);
802 return 0;
805 return inst;
808 static UINT thumb2_disasm_longmuldiv(UINT inst, ADDRESS64 *addr)
810 WORD op1 = (inst >> 20) & 0x07;
811 WORD op2 = (inst >> 4) & 0x0f;
813 if (op2 == 0)
815 switch (op1)
817 case 0:
818 dbg_printf("\n\tsmull\t");
819 break;
820 case 2:
821 dbg_printf("\n\tumull\t");
822 break;
823 case 4:
824 dbg_printf("\n\tsmlal\t");
825 break;
826 case 6:
827 dbg_printf("\n\tumlal\t");
828 break;
829 default:
830 return inst;
832 dbg_printf("%s, %s, %s, %s", tbl_regs[get_nibble(inst, 3)], tbl_regs[get_nibble(inst, 2)],
833 tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
834 return 0;
837 if (op2 == 0xffff)
839 switch (op1)
841 case 1:
842 dbg_printf("\n\tsdiv\t");
843 break;
844 case 3:
845 dbg_printf("\n\tudiv\t");
846 break;
847 default:
848 return inst;
850 dbg_printf("%s, %s, %s", tbl_regs[get_nibble(inst, 2)], tbl_regs[get_nibble(inst, 4)],
851 tbl_regs[get_nibble(inst, 0)]);
852 return 0;
855 return inst;
858 static UINT thumb2_disasm_str(UINT inst, ADDRESS64 *addr)
860 WORD op1 = (inst >> 21) & 0x07;
861 WORD op2 = (inst >> 6) & 0x3f;
863 if ((op1 & 0x03) == 3) return inst;
865 if (!(op1 & 0x04) && inst & 0x0800)
867 int offset;
868 dbg_printf("\n\tstr%s\t%s, [%s", tbl_width_t2[op1 & 0x03], tbl_regs[get_nibble(inst, 3)],
869 tbl_regs[get_nibble(inst, 4)]);
871 offset = inst & 0xff;
872 if (!(inst & 0x0200)) offset *= -1;
874 if (!(inst & 0x0400) && (inst & 0x0100)) dbg_printf("], #%i", offset);
875 else if (inst & 0x0400) dbg_printf(", #%i]%s", offset, (inst & 0x0100)?"!":"");
876 else return inst;
877 return 0;
880 if (!(op1 & 0x04) && !op2)
882 dbg_printf("\n\tstr%s\t%s, [%s, %s, LSL #%u]", tbl_width_t2[op1 & 0x03],
883 tbl_regs[get_nibble(inst, 3)], tbl_regs[get_nibble(inst, 4)],
884 tbl_regs[get_nibble(inst, 0)], (inst >> 4) & 0x3);
885 return 0;
888 if (op1 & 0x04)
890 dbg_printf("\n\tstr%s\t%s, [%s, #%u]", tbl_width_t2[op1 & 0x03],
891 tbl_regs[get_nibble(inst, 3)], tbl_regs[get_nibble(inst, 4)], inst & 0x0fff);
892 return 0;
895 return inst;
898 static UINT thumb2_disasm_ldrword(UINT inst, ADDRESS64 *addr)
900 WORD op1 = (inst >> 23) & 0x01;
901 WORD op2 = (inst >> 6) & 0x3f;
902 int offset;
904 if (get_nibble(inst, 4) == 0x0f)
906 offset = inst & 0x0fff;
908 if (!op1) offset *= -1;
909 offset += 3;
911 dbg_printf("\n\tldr\t%s, ", tbl_regs[get_nibble(inst, 3)]);
912 db_printsym(addr->Offset + offset);
913 return 0;
916 if (!op1 && !op2)
918 dbg_printf("\n\tldr\t%s, [%s, %s, LSL #%u]", tbl_regs[get_nibble(inst, 3)],
919 tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)], (inst >> 4) & 0x3);
920 return 0;
923 if (!op1 && (op2 & 0x3c) == 0x38)
925 dbg_printf("\n\tldrt\t%s, [%s, #%u]", tbl_regs[get_nibble(inst, 3)],
926 tbl_regs[get_nibble(inst, 4)], inst & 0xff);
927 return 0;
930 dbg_printf("\n\tldr\t%s, [%s", tbl_regs[get_nibble(inst, 3)], tbl_regs[get_nibble(inst, 4)]);
932 if (op1)
934 dbg_printf(", #%u]", inst & 0x0fff);
935 return 0;
938 offset = inst & 0xff;
939 if (!(inst & 0x0200)) offset *= -1;
941 if (!(inst & 0x0400) && (inst & 0x0100)) dbg_printf("], #%i", offset);
942 else if (inst & 0x0400) dbg_printf(", #%i]%s", offset, (inst & 0x0100)?"!":"");
943 else return inst;
945 return 0;
948 static UINT thumb2_disasm_preload(UINT inst, ADDRESS64 *addr)
950 WORD op1 = (inst >> 23) & 0x03;
952 if (!(op1 & 0x01) && !((inst >> 6) & 0x3f) && get_nibble(inst, 4) != 15)
954 WORD shift = (inst >> 4) & 0x03;
955 dbg_printf("\n\t%s\t[%s, %s", op1?"pli":"pld", tbl_regs[get_nibble(inst, 4)],
956 tbl_regs[get_nibble(inst, 0)]);
957 if (shift) dbg_printf(", lsl #%u]", shift);
958 else dbg_printf("]");
959 return 0;
962 if (get_nibble(inst, 4) != 15)
964 dbg_printf("\n\t%s\t[%s, #%d]", (op1 & 0x02)?"pli":"pld", tbl_regs[get_nibble(inst, 4)],
965 (op1 & 0x01)?(inst & 0x0fff):(-1 * (inst & 0xff)));
966 return 0;
969 if (get_nibble(inst, 4) == 15)
971 int offset = inst & 0x0fff;
972 if (!op1) offset *= -1;
973 dbg_printf("\n\t%s\t", (op1 & 0x02)?"pli":"pld");
974 db_printsym(addr->Offset + offset + 4);
975 return 0;
978 return inst;
981 static UINT thumb2_disasm_ldrnonword(UINT inst, ADDRESS64 *addr)
983 WORD op1 = (inst >> 23) & 0x03;
984 WORD hw = (inst >> 21) & 0x01;
986 if (!(op1 & 0x01) && !((inst >> 6) & 0x3f) && get_nibble(inst, 4) != 15)
988 WORD shift = (inst >> 4) & 0x03;
989 dbg_printf("\n\t%s%s\t%s, [%s, %s", op1?"ldrs":"ldr", hw?"h":"b",
990 tbl_regs[get_nibble(inst, 3)], tbl_regs[get_nibble(inst, 4)],
991 tbl_regs[get_nibble(inst, 0)]);
992 if (shift) dbg_printf(", lsl #%u]", shift);
993 else dbg_printf("]");
994 return 0;
997 if (!(op1 & 0x01) && ((inst >> 8) & 0x0f) == 14 && get_nibble(inst, 4) != 15)
999 WORD offset = inst & 0xff;
1000 dbg_printf("\n\t%s%s\t%s, [%s", op1?"ldrs":"ldr", hw?"ht":"bt",
1001 tbl_regs[get_nibble(inst, 3)], tbl_regs[get_nibble(inst, 4)]);
1002 if (offset) dbg_printf(", #%u]", offset);
1003 else dbg_printf("]");
1004 return 0;
1007 if (get_nibble(inst, 4) != 15)
1009 int offset;
1011 dbg_printf("\n\t%s%s\t%s, [%s", (op1 & 0x02)?"ldrs":"ldr", hw?"h":"b",
1012 tbl_regs[get_nibble(inst, 3)], tbl_regs[get_nibble(inst, 4)]);
1014 if (op1 & 0x01)
1016 dbg_printf(", #%u]", inst & 0x0fff);
1017 return 0;
1020 offset = inst & 0xff;
1021 if (!(inst & 0x0200)) offset *= -1;
1023 if (!(inst & 0x0400) && (inst & 0x0100)) dbg_printf("], #%i", offset);
1024 else if (inst & 0x0400) dbg_printf(", #%i]%s", offset, (inst & 0x0100)?"!":"");
1025 else return inst;
1027 return 0;
1030 if (get_nibble(inst, 4) == 15)
1032 int offset = inst & 0x0fff;
1033 if (!op1) offset *= -1;
1034 dbg_printf("\n\t%s%s\t%s, ", (op1 & 0x02)?"ldrs":"ldr", hw?"h":"b",
1035 tbl_regs[get_nibble(inst, 3)]);
1036 db_printsym(addr->Offset + offset + 4);
1037 return 0;
1040 return inst;
1043 static UINT thumb2_disasm_dataprocessing(UINT inst, ADDRESS64 *addr)
1045 WORD op = (inst >> 20) & 0x1f;
1046 WORD imm5 = ((inst >> 10) & 0x1c) + ((inst >> 6) & 0x03);
1048 switch (op)
1050 case 0:
1052 WORD offset = ((inst >> 15) & 0x0800) + ((inst >> 4) & 0x0700) + (inst & 0xff);
1053 if (get_nibble(inst, 4) == 15)
1055 dbg_printf("\n\tadr\t%s, ", tbl_regs[get_nibble(inst, 2)]);
1056 db_printsym(addr->Offset + offset + 4);
1058 else
1059 dbg_printf("\n\taddw\t%s, %s, #%u", tbl_regs[get_nibble(inst, 2)],
1060 tbl_regs[get_nibble(inst, 4)], offset);
1061 return 0;
1063 case 4:
1064 case 12:
1066 WORD offset = ((inst >> 15) & 0x0800) + ((inst >> 4) & 0xf000) +
1067 ((inst >> 4) & 0x0700) + (inst & 0xff);
1068 dbg_printf("\n\t%s\t%s, #%u", op == 12 ? "movt" : "movw", tbl_regs[get_nibble(inst, 2)],
1069 offset);
1070 return 0;
1072 case 10:
1074 int offset = ((inst >> 15) & 0x0800) + ((inst >> 4) & 0x0700) + (inst & 0xff);
1075 if (get_nibble(inst, 4) == 15)
1077 offset *= -1;
1078 dbg_printf("\n\tadr\t%s, ", tbl_regs[get_nibble(inst, 2)]);
1079 db_printsym(addr->Offset + offset + 4);
1081 else
1082 dbg_printf("\n\tsubw\t%s, %s, #%u", tbl_regs[get_nibble(inst, 2)],
1083 tbl_regs[get_nibble(inst, 4)], offset);
1084 return 0;
1086 case 16:
1087 case 18:
1088 case 24:
1089 case 26:
1091 BOOL sign = op < 24;
1092 WORD sh = (inst >> 21) & 0x01;
1093 WORD sat = (inst & 0x1f);
1094 if (sign) sat++;
1095 if (imm5)
1096 dbg_printf("\n\t%s\t%s, #%u, %s, %s #%u", sign ? "ssat" : "usat",
1097 tbl_regs[get_nibble(inst, 2)], sat, tbl_regs[get_nibble(inst, 4)],
1098 sh ? "asr" : "lsl", imm5);
1099 else
1100 dbg_printf("\n\t%s\t%s, #%u, %s", sign ? "ssat" : "usat", tbl_regs[get_nibble(inst, 2)],
1101 sat, tbl_regs[get_nibble(inst, 4)]);
1102 return 0;
1104 case 20:
1105 case 28:
1107 WORD width = (inst & 0x1f) + 1;
1108 dbg_printf("\n\t%s\t%s, %s, #%u, #%u", op == 28 ? "ubfx" : "sbfx",
1109 tbl_regs[get_nibble(inst, 2)], tbl_regs[get_nibble(inst, 4)], imm5, width);
1110 return 0;
1112 case 22:
1114 WORD msb = (inst & 0x1f) + 1 - imm5;
1115 if (get_nibble(inst, 4) == 15)
1116 dbg_printf("\n\tbfc\t%s, #%u, #%u", tbl_regs[get_nibble(inst, 2)], imm5, msb);
1117 else
1118 dbg_printf("\n\tbfi\t%s, %s, #%u, #%u", tbl_regs[get_nibble(inst, 2)],
1119 tbl_regs[get_nibble(inst, 4)], imm5, msb);
1120 return 0;
1122 default:
1123 return inst;
1127 static UINT thumb2_disasm_dataprocessingmod(UINT inst, ADDRESS64 *addr)
1129 WORD op = (inst >> 21) & 0x0f;
1130 WORD sf = (inst >> 20) & 0x01;
1131 WORD offset = ((inst >> 15) & 0x0800) + ((inst >> 4) & 0x0700) + (inst & 0xff);
1133 /* FIXME: use ThumbExpandImm_C */
1135 switch (op)
1137 case 0:
1138 if (get_nibble(inst, 2) == 15)
1139 dbg_printf("\n\ttst\t%s, #%u", tbl_regs[get_nibble(inst, 4)], offset);
1140 else
1141 dbg_printf("\n\tand%s\t%s, %s, #%u", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)],
1142 tbl_regs[get_nibble(inst, 4)], offset);
1143 return 0;
1144 case 1:
1145 dbg_printf("\n\tbic%s\t%s, %s, #%u", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)],
1146 tbl_regs[get_nibble(inst, 4)], offset);
1147 return 0;
1148 case 2:
1149 if (get_nibble(inst, 4) == 15)
1150 dbg_printf("\n\tmov%s\t%s, #%u", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)], offset);
1151 else
1152 dbg_printf("\n\torr%s\t%s, %s, #%u", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)],
1153 tbl_regs[get_nibble(inst, 4)], offset);
1154 return 0;
1155 case 3:
1156 if (get_nibble(inst, 4) == 15)
1157 dbg_printf("\n\tmvn%s\t%s, #%u", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)], offset);
1158 else
1159 dbg_printf("\n\torn%s\t%s, %s, #%u", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)],
1160 tbl_regs[get_nibble(inst, 4)], offset);
1161 return 0;
1162 case 4:
1163 if (get_nibble(inst, 2) == 15)
1164 dbg_printf("\n\tteq\t%s, #%u", tbl_regs[get_nibble(inst, 4)], offset);
1165 else
1166 dbg_printf("\n\teor%s\t%s, %s, #%u", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)],
1167 tbl_regs[get_nibble(inst, 4)], offset);
1168 return 0;
1169 case 8:
1170 if (get_nibble(inst, 2) == 15)
1171 dbg_printf("\n\tcmn\t%s, #%u", tbl_regs[get_nibble(inst, 4)], offset);
1172 else
1173 dbg_printf("\n\tadd%s\t%s, %s, #%u", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)],
1174 tbl_regs[get_nibble(inst, 4)], offset);
1175 return 0;
1176 case 10:
1177 dbg_printf("\n\tadc%s\t%s, %s, #%u", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)],
1178 tbl_regs[get_nibble(inst, 4)], offset);
1179 return 0;
1180 case 11:
1181 dbg_printf("\n\tsbc%s\t%s, %s, #%u", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)],
1182 tbl_regs[get_nibble(inst, 4)], offset);
1183 return 0;
1184 case 13:
1185 if (get_nibble(inst, 2) == 15)
1186 dbg_printf("\n\tcmp\t%s, #%u", tbl_regs[get_nibble(inst, 4)], offset);
1187 else
1188 dbg_printf("\n\tsub%s\t%s, %s, #%u", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)],
1189 tbl_regs[get_nibble(inst, 4)], offset);
1190 return 0;
1191 case 14:
1192 dbg_printf("\n\trsb%s\t%s, %s, #%u", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)],
1193 tbl_regs[get_nibble(inst, 4)], offset);
1194 return 0;
1195 default:
1196 return inst;
1200 static UINT thumb2_disasm_dataprocessingshift(UINT inst, ADDRESS64 *addr)
1202 WORD op = (inst >> 21) & 0x0f;
1203 WORD sf = (inst >> 20) & 0x01;
1204 WORD imm5 = ((inst >> 10) & 0x1c) + ((inst >> 6) & 0x03);
1205 WORD type = (inst >> 4) & 0x03;
1207 if (!imm5 && (type == 1 || type == 2)) imm5 = 32;
1208 else if (!imm5 && type == 3) type = 4;
1210 switch (op)
1212 case 0:
1213 if (get_nibble(inst, 2) == 15)
1214 dbg_printf("\n\ttst\t%s, %s", tbl_regs[get_nibble(inst, 4)],
1215 tbl_regs[get_nibble(inst, 0)]);
1216 else
1217 dbg_printf("\n\tand%s\t%s, %s, %s", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)],
1218 tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
1219 break;
1220 case 1:
1221 dbg_printf("\n\tbic%s\t%s, %s, %s", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)],
1222 tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
1223 break;
1224 case 2:
1225 if (get_nibble(inst, 4) == 15)
1227 if (type == 4)
1228 dbg_printf("\n\trrx%s\t%s, %s", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)], tbl_regs[get_nibble(inst, 0)]);
1229 else if (!type && !imm5)
1230 dbg_printf("\n\tmov%s\t%s, %s", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)], tbl_regs[get_nibble(inst, 0)]);
1231 else
1232 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);
1233 return 0;
1235 else
1236 dbg_printf("\n\torr%s\t%s, %s, %s", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)],
1237 tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
1238 break;
1239 case 3:
1240 if (get_nibble(inst, 4) == 15)
1241 dbg_printf("\n\tmvn%s\t%s, %s, %s", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)],
1242 tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
1243 else
1244 dbg_printf("\n\torn%s\t%s, %s, %s", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)],
1245 tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
1246 break;
1247 case 4:
1248 if (get_nibble(inst, 2) == 15)
1249 dbg_printf("\n\tteq\t%s, %s", tbl_regs[get_nibble(inst, 4)],
1250 tbl_regs[get_nibble(inst, 0)]);
1251 else
1252 dbg_printf("\n\teor%s\t%s, %s, %s", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)],
1253 tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
1254 break;
1255 case 8:
1256 if (get_nibble(inst, 2) == 15)
1257 dbg_printf("\n\tcmn\t%s, %s", tbl_regs[get_nibble(inst, 4)],
1258 tbl_regs[get_nibble(inst, 0)]);
1259 else
1260 dbg_printf("\n\tadd%s\t%s, %s, %s", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)],
1261 tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
1262 break;
1263 case 10:
1264 dbg_printf("\n\tadc%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 11:
1268 dbg_printf("\n\tsbc%s\t%s, %s, %s", sf ? "s" : "", tbl_regs[get_nibble(inst, 2)],
1269 tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
1270 break;
1271 case 13:
1272 if (get_nibble(inst, 2) == 15)
1273 dbg_printf("\n\tcmp\t%s, %s", tbl_regs[get_nibble(inst, 4)],
1274 tbl_regs[get_nibble(inst, 0)]);
1275 else
1276 dbg_printf("\n\tsub%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 14:
1280 dbg_printf("\n\trsb%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 default:
1284 return inst;
1287 if (type == 4)
1288 dbg_printf(", rrx");
1289 else if (type || imm5)
1290 dbg_printf(", %s #%u", tbl_shifts[type], imm5);
1291 return 0;
1294 static UINT thumb2_disasm_coprocdat(UINT inst, ADDRESS64 *addr)
1296 WORD opc2 = (inst >> 5) & 0x07;
1298 dbg_printf("\n\tcdp%s\tp%u, #%u, cr%u, cr%u, cr%u", (inst & 0x10000000)?"2":"",
1299 get_nibble(inst, 2), get_nibble(inst, 5), get_nibble(inst, 3),
1300 get_nibble(inst, 4), get_nibble(inst, 0));
1302 if (opc2) dbg_printf(", #%u", opc2);
1303 return 0;
1306 static UINT thumb2_disasm_coprocmov1(UINT inst, ADDRESS64 *addr)
1308 WORD opc1 = (inst >> 21) & 0x07;
1309 WORD opc2 = (inst >> 5) & 0x07;
1311 dbg_printf("\n\t%s%s\tp%u, #%u, %s, cr%u, cr%u", (inst & 0x00100000)?"mrc":"mcr",
1312 (inst & 0x10000000)?"2":"", get_nibble(inst, 2), opc1,
1313 tbl_regs[get_nibble(inst, 3)], get_nibble(inst, 4), get_nibble(inst, 0));
1315 if (opc2) dbg_printf(", #%u", opc2);
1316 return 0;
1319 static UINT thumb2_disasm_coprocmov2(UINT inst, ADDRESS64 *addr)
1321 dbg_printf("\n\t%s%s\tp%u, #%u, %s, %s, cr%u", (inst & 0x00100000)?"mrrc":"mcrr",
1322 (inst & 0x10000000)?"2":"", get_nibble(inst, 2), get_nibble(inst, 1),
1323 tbl_regs[get_nibble(inst, 3)], tbl_regs[get_nibble(inst, 4)], get_nibble(inst, 0));
1325 return 0;
1328 static UINT thumb2_disasm_coprocdatatrans(UINT inst, ADDRESS64 *addr)
1330 WORD indexing = (inst >> 24) & 0x01;
1331 WORD direction = (inst >> 23) & 0x01;
1332 WORD translen = (inst >> 22) & 0x01;
1333 WORD writeback = (inst >> 21) & 0x01;
1334 WORD load = (inst >> 20) & 0x01;
1335 short offset = (inst & 0xff) << 2;
1337 if (!direction) offset *= -1;
1339 dbg_printf("\n\t%s%s%s", load ? "ldc" : "stc", (inst & 0x10000000)?"2":"", translen ? "l" : "");
1340 if (indexing)
1342 if (load && get_nibble(inst, 4) == 15)
1344 dbg_printf("\tp%u, cr%u, ", get_nibble(inst, 2), get_nibble(inst, 3));
1345 db_printsym(addr->Offset + offset + 4);
1347 else
1348 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?"!":"");
1350 else
1352 if (writeback)
1353 dbg_printf("\tp%u, cr%u, [%s], #%d", get_nibble(inst, 2), get_nibble(inst, 3), tbl_regs[get_nibble(inst, 4)], offset);
1354 else
1355 dbg_printf("\tp%u, cr%u, [%s], {%u}", get_nibble(inst, 2), get_nibble(inst, 3), tbl_regs[get_nibble(inst, 4)], inst & 0xff);
1357 return 0;
1360 static UINT thumb2_disasm_ldrstrmul(UINT inst, ADDRESS64 *addr)
1362 short load = (inst >> 20) & 0x01;
1363 short writeback = (inst >> 21) & 0x01;
1364 short decbefore = (inst >> 24) & 0x01;
1365 short i;
1366 short last=15;
1367 for (i=15;i>=0;i--)
1368 if ((inst>>i) & 1)
1370 last = i;
1371 break;
1374 if (writeback && get_nibble(inst, 4) == 13)
1375 dbg_printf("\n\t%s\t{", load ? "pop" : "push");
1376 else
1377 dbg_printf("\n\t%s%s\t%s%s, {", load ? "ldm" : "stm", decbefore ? "db" : "ia",
1378 tbl_regs[get_nibble(inst, 4)], writeback ? "!" : "");
1379 for (i=0;i<=15;i++)
1380 if ((inst>>i) & 1)
1382 if (i == last) dbg_printf("%s", tbl_regs[i]);
1383 else dbg_printf("%s, ", tbl_regs[i]);
1385 dbg_printf("}");
1386 return 0;
1389 static UINT thumb2_disasm_ldrstrextbr(UINT inst, ADDRESS64 *addr)
1391 WORD op1 = (inst >> 23) & 0x03;
1392 WORD op2 = (inst >> 20) & 0x03;
1393 WORD op3 = (inst >> 4) & 0x0f;
1394 WORD indexing = (inst >> 24) & 0x01;
1395 WORD direction = (inst >> 23) & 0x01;
1396 WORD writeback = (inst >> 21) & 0x01;
1397 WORD load = (inst >> 20) & 0x01;
1398 short offset = (inst & 0xff) << 2;
1400 if (op1 == 1 && op2 == 1 && op3 < 2)
1402 WORD halfword = (inst >> 4) & 0x01;
1403 if (halfword)
1404 dbg_printf("\n\ttbh\t [%s, %s, lsl #1]", tbl_regs[get_nibble(inst, 4)],
1405 tbl_regs[get_nibble(inst, 0)]);
1406 else
1407 dbg_printf("\n\ttbb\t [%s, %s]", tbl_regs[get_nibble(inst, 4)],
1408 tbl_regs[get_nibble(inst, 0)]);
1409 return 0;
1412 if (op1 == 0 && op2 < 2)
1414 if (get_nibble(inst, 2) == 15)
1415 dbg_printf("\n\tldrex\t %s, [%s, #%u]", tbl_regs[get_nibble(inst, 3)],
1416 tbl_regs[get_nibble(inst, 4)], offset);
1417 else
1418 dbg_printf("\n\tstrex\t %s, %s, [%s, #%u]", tbl_regs[get_nibble(inst, 2)],
1419 tbl_regs[get_nibble(inst, 3)], tbl_regs[get_nibble(inst, 4)], offset);
1420 return 0;
1423 if (op1 == 1 && op2 < 2)
1425 WORD halfword = (inst >> 4) & 0x01;
1426 if (get_nibble(inst, 0) == 15)
1427 dbg_printf("\n\tldrex%s\t %s, [%s]", halfword ? "h" : "b",
1428 tbl_regs[get_nibble(inst, 3)], tbl_regs[get_nibble(inst, 4)]);
1429 else
1430 dbg_printf("\n\tstrex%s\t %s, %s, [%s]", halfword ? "h" : "b",
1431 tbl_regs[get_nibble(inst, 0)], tbl_regs[get_nibble(inst, 3)],
1432 tbl_regs[get_nibble(inst, 4)]);
1433 return 0;
1436 if (!direction) offset *= -1;
1437 dbg_printf("\n\t%s\t", load ? "ldrd" : "strd");
1438 if (indexing)
1440 if (load && get_nibble(inst, 4) == 15)
1442 dbg_printf("%s, %s, ", tbl_regs[get_nibble(inst, 3)], tbl_regs[get_nibble(inst, 2)]);
1443 db_printsym(addr->Offset + offset + 4);
1445 else
1446 dbg_printf("%s, %s, [%s, #%d]%s", tbl_regs[get_nibble(inst, 3)],
1447 tbl_regs[get_nibble(inst, 2)], tbl_regs[get_nibble(inst, 4)], offset,
1448 writeback?"!":"");
1450 else
1451 dbg_printf("%s, %s, [%s], #%d", tbl_regs[get_nibble(inst, 3)],
1452 tbl_regs[get_nibble(inst, 2)], tbl_regs[get_nibble(inst, 4)], offset);
1453 return 0;
1456 struct inst_arm
1458 UINT mask;
1459 UINT pattern;
1460 UINT (*func)(UINT, ADDRESS64*);
1463 static const struct inst_arm tbl_arm[] = {
1464 { 0x0e000000, 0x0a000000, arm_disasm_branch },
1465 { 0x0fc000f0, 0x00000090, arm_disasm_mul },
1466 { 0x0f8000f0, 0x00800090, arm_disasm_longmul },
1467 { 0x0fb00ff0, 0x01000090, arm_disasm_swp },
1468 { 0x0e000090, 0x00000090, arm_disasm_halfwordtrans },
1469 { 0x0ffffff0, 0x012fff10, arm_disasm_branchxchg },
1470 { 0x0fbf0fff, 0x010f0000, arm_disasm_mrstrans },
1471 { 0x0dbef000, 0x0128f000, arm_disasm_msrtrans },
1472 { 0x0fb00000, 0x03000000, arm_disasm_wordmov },
1473 { 0x0fffffff, 0x0320f000, arm_disasm_nop },
1474 { 0x0c000000, 0x00000000, arm_disasm_dataprocessing },
1475 { 0x0c000000, 0x04000000, arm_disasm_singletrans },
1476 { 0x0e000000, 0x08000000, arm_disasm_blocktrans },
1477 { 0x0f000000, 0x0f000000, arm_disasm_swi },
1478 { 0x0f000010, 0x0e000010, arm_disasm_coproctrans },
1479 { 0x0f000010, 0x0e000000, arm_disasm_coprocdataop },
1480 { 0x0e000000, 0x0c000000, arm_disasm_coprocdatatrans },
1481 { 0x00000000, 0x00000000, NULL }
1484 struct inst_thumb16
1486 WORD mask;
1487 WORD pattern;
1488 WORD (*func)(WORD, ADDRESS64*);
1491 static const struct inst_thumb16 tbl_thumb16[] = {
1492 { 0xfc00, 0x4400, thumb_disasm_hireg },
1493 { 0xfc00, 0x4000, thumb_disasm_aluop },
1494 { 0xf600, 0xb400, thumb_disasm_pushpop },
1495 { 0xf000, 0xc000, thumb_disasm_blocktrans },
1496 { 0xff00, 0xdf00, thumb_disasm_swi },
1497 { 0xf000, 0xd000, thumb_disasm_condbranch },
1498 { 0xf800, 0xe000, thumb_disasm_uncondbranch },
1499 { 0xf000, 0xa000, thumb_disasm_loadadr },
1500 { 0xf800, 0x4800, thumb_disasm_ldrpcrel },
1501 { 0xf000, 0x9000, thumb_disasm_ldrsprel },
1502 { 0xff00, 0xb000, thumb_disasm_addsprel },
1503 { 0xe000, 0x6000, thumb_disasm_ldrimm },
1504 { 0xf000, 0x8000, thumb_disasm_ldrhimm },
1505 { 0xf200, 0x5000, thumb_disasm_ldrreg },
1506 { 0xf200, 0x5200, thumb_disasm_ldrsreg },
1507 { 0xe000, 0x2000, thumb_disasm_immop },
1508 { 0xff00, 0xbf00, thumb_disasm_nop },
1509 { 0xf800, 0x1800, thumb_disasm_addsub },
1510 { 0xe000, 0x0000, thumb_disasm_movshift },
1511 { 0x0000, 0x0000, NULL }
1514 static const struct inst_arm tbl_thumb32[] = {
1515 { 0xfff0f000, 0xf3e08000, thumb2_disasm_srtrans },
1516 { 0xfff0f000, 0xf3808000, thumb2_disasm_srtrans },
1517 { 0xfff0d000, 0xf3a08000, thumb2_disasm_hint },
1518 { 0xfff0d000, 0xf3b08000, thumb2_disasm_miscctrl },
1519 { 0xf8008000, 0xf0008000, thumb2_disasm_branch },
1520 { 0xffc0f0c0, 0xfa80f080, thumb2_disasm_misc },
1521 { 0xff80f000, 0xfa00f000, thumb2_disasm_dataprocessingreg },
1522 { 0xff8000c0, 0xfb000000, thumb2_disasm_mul },
1523 { 0xff8000f0, 0xfb800000, thumb2_disasm_longmuldiv },
1524 { 0xff8000f0, 0xfb8000f0, thumb2_disasm_longmuldiv },
1525 { 0xff100000, 0xf8000000, thumb2_disasm_str },
1526 { 0xff700000, 0xf8500000, thumb2_disasm_ldrword },
1527 { 0xfe70f000, 0xf810f000, thumb2_disasm_preload },
1528 { 0xfe500000, 0xf8100000, thumb2_disasm_ldrnonword },
1529 { 0xfa008000, 0xf2000000, thumb2_disasm_dataprocessing },
1530 { 0xfa008000, 0xf0000000, thumb2_disasm_dataprocessingmod },
1531 { 0xfe008000, 0xea000000, thumb2_disasm_dataprocessingshift },
1532 { 0xef000010, 0xee000000, thumb2_disasm_coprocdat },
1533 { 0xef000010, 0xee000010, thumb2_disasm_coprocmov1 },
1534 { 0xefe00000, 0xec400000, thumb2_disasm_coprocmov2 },
1535 { 0xee000000, 0xec000000, thumb2_disasm_coprocdatatrans },
1536 { 0xfe402000, 0xe8000000, thumb2_disasm_ldrstrmul },
1537 { 0xfe400000, 0xe8400000, thumb2_disasm_ldrstrextbr },
1538 { 0x00000000, 0x00000000, NULL }
1541 /***********************************************************************
1542 * disasm_one_insn
1544 * Disassemble instruction at 'addr'. addr is changed to point to the
1545 * start of the next instruction.
1547 void be_arm_disasm_one_insn(ADDRESS64 *addr, int display)
1549 struct inst_arm *a_ptr = (struct inst_arm *)&tbl_arm;
1550 struct inst_thumb16 *t_ptr = (struct inst_thumb16 *)&tbl_thumb16;
1551 struct inst_arm *t2_ptr = (struct inst_arm *)&tbl_thumb32;
1552 UINT inst;
1553 WORD tinst;
1554 int size;
1555 int matched = 0;
1557 char tmp[64];
1558 DWORD_PTR* pval;
1560 if (!memory_get_register(CV_ARM_CPSR, &pval, tmp, sizeof(tmp)))
1561 dbg_printf("\n\tmemory_get_register failed: %s", tmp);
1562 else
1563 db_disasm_thumb = (*pval & 0x20) != 0;
1565 db_display = display;
1567 if (!db_disasm_thumb)
1569 size = ARM_INSN_SIZE;
1570 inst = db_get_inst( memory_to_linear_addr(addr), size );
1571 while (a_ptr->func) {
1572 if ((inst & a_ptr->mask) == a_ptr->pattern) {
1573 matched = 1;
1574 break;
1576 a_ptr++;
1579 if (!matched) {
1580 dbg_printf("\n\tUnknown ARM Instruction: %08x", inst);
1581 addr->Offset += size;
1583 else
1585 if (!a_ptr->func(inst, addr))
1586 addr->Offset += size;
1588 return;
1590 else
1592 WORD *taddr = memory_to_linear_addr(addr);
1593 tinst = db_get_inst( taddr, THUMB_INSN_SIZE );
1594 switch (tinst & 0xf800)
1596 case 0xe800:
1597 case 0xf000:
1598 case 0xf800:
1599 size = THUMB2_INSN_SIZE;
1600 taddr++;
1601 inst = db_get_inst( taddr, THUMB_INSN_SIZE );
1602 inst |= (tinst << 16);
1604 while (t2_ptr->func) {
1605 if ((inst & t2_ptr->mask) == t2_ptr->pattern) {
1606 matched = 1;
1607 break;
1609 t2_ptr++;
1612 if (!matched) {
1613 dbg_printf("\n\tUnknown Thumb2 Instruction: %08x", inst);
1614 addr->Offset += size;
1616 else
1618 if (!t2_ptr->func(inst, addr))
1619 addr->Offset += size;
1621 return;
1622 default:
1623 break;
1626 size = THUMB_INSN_SIZE;
1627 while (t_ptr->func) {
1628 if ((tinst & t_ptr->mask) == t_ptr->pattern) {
1629 matched = 1;
1630 break;
1632 t_ptr++;
1635 if (!matched) {
1636 dbg_printf("\n\tUnknown Thumb Instruction: %04x", tinst);
1637 addr->Offset += size;
1639 else
1641 if (!t_ptr->func(tinst, addr))
1642 addr->Offset += size;
1644 return;
1648 static BOOL be_arm_get_addr(HANDLE hThread, const dbg_ctx_t *ctx,
1649 enum be_cpu_addr bca, ADDRESS64* addr)
1651 switch (bca)
1653 case be_cpu_addr_pc:
1654 return be_cpu_build_addr(hThread, ctx, addr, 0, ctx->ctx.Pc);
1655 case be_cpu_addr_stack:
1656 return be_cpu_build_addr(hThread, ctx, addr, 0, ctx->ctx.Sp);
1657 case be_cpu_addr_frame:
1658 return be_cpu_build_addr(hThread, ctx, addr, 0, ctx->ctx.R11);
1660 return FALSE;
1663 static BOOL be_arm_get_register_info(int regno, enum be_cpu_addr* kind)
1665 switch (regno)
1667 case CV_ARM_PC: *kind = be_cpu_addr_pc; return TRUE;
1668 case CV_ARM_R0 + 11: *kind = be_cpu_addr_frame; return TRUE;
1669 case CV_ARM_SP: *kind = be_cpu_addr_stack; return TRUE;
1671 return FALSE;
1674 static void be_arm_single_step(dbg_ctx_t *ctx, BOOL enable)
1678 static void be_arm_print_context(HANDLE hThread, const dbg_ctx_t *ctx, int all_regs)
1680 static const char condflags[] = "NZCV";
1681 int i;
1682 char buf[8];
1684 switch (ctx->ctx.Cpsr & 0x1F)
1686 case 0: strcpy(buf, "User26"); break;
1687 case 1: strcpy(buf, "FIQ26"); break;
1688 case 2: strcpy(buf, "IRQ26"); break;
1689 case 3: strcpy(buf, "SVC26"); break;
1690 case 16: strcpy(buf, "User"); break;
1691 case 17: strcpy(buf, "FIQ"); break;
1692 case 18: strcpy(buf, "IRQ"); break;
1693 case 19: strcpy(buf, "SVC"); break;
1694 case 23: strcpy(buf, "ABT"); break;
1695 case 27: strcpy(buf, "UND"); break;
1696 default: strcpy(buf, "UNKNWN"); break;
1699 dbg_printf("Register dump:\n");
1700 dbg_printf("%s %s Mode\n", (ctx->ctx.Cpsr & 0x20) ? "Thumb" : "ARM", buf);
1702 strcpy(buf, condflags);
1703 for (i = 0; buf[i]; i++)
1704 if (!((ctx->ctx.Cpsr >> 26) & (1 << (sizeof(condflags) - i))))
1705 buf[i] = '-';
1707 dbg_printf(" Pc:%08x Sp:%08x Lr:%08x Cpsr:%08x(%s)\n",
1708 ctx->ctx.Pc, ctx->ctx.Sp, ctx->ctx.Lr, ctx->ctx.Cpsr, buf);
1709 dbg_printf(" r0:%08x r1:%08x r2:%08x r3:%08x\n",
1710 ctx->ctx.R0, ctx->ctx.R1, ctx->ctx.R2, ctx->ctx.R3);
1711 dbg_printf(" r4:%08x r5:%08x r6:%08x r7:%08x\n",
1712 ctx->ctx.R4, ctx->ctx.R5, ctx->ctx.R6, ctx->ctx.R7);
1713 dbg_printf(" r8:%08x r9:%08x r10:%08x r11:%08x r12:%08x\n",
1714 ctx->ctx.R8, ctx->ctx.R9, ctx->ctx.R10, ctx->ctx.R11, ctx->ctx.R12);
1716 if (all_regs) dbg_printf( "Floating point ARM dump not implemented\n" );
1719 static void be_arm_print_segment_info(HANDLE hThread, const dbg_ctx_t *ctx)
1723 static struct dbg_internal_var be_arm_ctx[] =
1725 {CV_ARM_R0 + 0, "r0", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R0), dbg_itype_unsigned_int},
1726 {CV_ARM_R0 + 1, "r1", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R1), dbg_itype_unsigned_int},
1727 {CV_ARM_R0 + 2, "r2", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R2), dbg_itype_unsigned_int},
1728 {CV_ARM_R0 + 3, "r3", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R3), dbg_itype_unsigned_int},
1729 {CV_ARM_R0 + 4, "r4", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R4), dbg_itype_unsigned_int},
1730 {CV_ARM_R0 + 5, "r5", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R5), dbg_itype_unsigned_int},
1731 {CV_ARM_R0 + 6, "r6", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R6), dbg_itype_unsigned_int},
1732 {CV_ARM_R0 + 7, "r7", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R7), dbg_itype_unsigned_int},
1733 {CV_ARM_R0 + 8, "r8", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R8), dbg_itype_unsigned_int},
1734 {CV_ARM_R0 + 9, "r9", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R9), dbg_itype_unsigned_int},
1735 {CV_ARM_R0 + 10, "r10", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R10), dbg_itype_unsigned_int},
1736 {CV_ARM_R0 + 11, "r11", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R11), dbg_itype_unsigned_int},
1737 {CV_ARM_R0 + 12, "r12", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R12), dbg_itype_unsigned_int},
1738 {CV_ARM_SP, "sp", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Sp), dbg_itype_unsigned_int},
1739 {CV_ARM_LR, "lr", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Lr), dbg_itype_unsigned_int},
1740 {CV_ARM_PC, "pc", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Pc), dbg_itype_unsigned_int},
1741 {CV_ARM_CPSR, "cpsr", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Cpsr), dbg_itype_unsigned_int},
1742 {0, NULL, 0, dbg_itype_none}
1745 static BOOL be_arm_is_step_over_insn(const void* insn)
1747 dbg_printf("be_arm_is_step_over_insn: not done\n");
1748 return FALSE;
1751 static BOOL be_arm_is_function_return(const void* insn)
1753 dbg_printf("be_arm_is_function_return: not done\n");
1754 return FALSE;
1757 static BOOL be_arm_is_break_insn(const void* insn)
1759 dbg_printf("be_arm_is_break_insn: not done\n");
1760 return FALSE;
1763 static BOOL be_arm_is_func_call(const void* insn, ADDRESS64* callee)
1765 return FALSE;
1768 static BOOL be_arm_is_jump(const void* insn, ADDRESS64* jumpee)
1770 return FALSE;
1773 static BOOL be_arm_insert_Xpoint(HANDLE hProcess, const struct be_process_io* pio,
1774 dbg_ctx_t *ctx, enum be_xpoint_type type,
1775 void* addr, unsigned long* val, unsigned size)
1777 SIZE_T sz;
1779 switch (type)
1781 case be_xpoint_break:
1782 if (!size) return FALSE;
1783 if (!pio->read(hProcess, addr, val, 4, &sz) || sz != 4) return FALSE;
1784 default:
1785 dbg_printf("Unknown/unsupported bp type %c\n", type);
1786 return FALSE;
1788 return TRUE;
1791 static BOOL be_arm_remove_Xpoint(HANDLE hProcess, const struct be_process_io* pio,
1792 dbg_ctx_t *ctx, enum be_xpoint_type type,
1793 void* addr, unsigned long val, unsigned size)
1795 SIZE_T sz;
1797 switch (type)
1799 case be_xpoint_break:
1800 if (!size) return FALSE;
1801 if (!pio->write(hProcess, addr, &val, 4, &sz) || sz == 4) return FALSE;
1802 break;
1803 default:
1804 dbg_printf("Unknown/unsupported bp type %c\n", type);
1805 return FALSE;
1807 return TRUE;
1810 static BOOL be_arm_is_watchpoint_set(const dbg_ctx_t *ctx, unsigned idx)
1812 dbg_printf("be_arm_is_watchpoint_set: not done\n");
1813 return FALSE;
1816 static void be_arm_clear_watchpoint(dbg_ctx_t *ctx, unsigned idx)
1818 dbg_printf("be_arm_clear_watchpoint: not done\n");
1821 static int be_arm_adjust_pc_for_break(dbg_ctx_t *ctx, BOOL way)
1823 INT step = (ctx->ctx.Cpsr & 0x20) ? 2 : 4;
1825 if (way)
1827 ctx->ctx.Pc -= step;
1828 return -step;
1830 ctx->ctx.Pc += step;
1831 return step;
1834 static BOOL be_arm_fetch_integer(const struct dbg_lvalue* lvalue, unsigned size,
1835 BOOL is_signed, LONGLONG* ret)
1837 if (size != 1 && size != 2 && size != 4 && size != 8) return FALSE;
1839 memset(ret, 0, sizeof(*ret)); /* clear unread bytes */
1840 /* FIXME: this assumes that debuggee and debugger use the same
1841 * integral representation
1843 if (!memory_read_value(lvalue, size, ret)) return FALSE;
1845 /* propagate sign information */
1846 if (is_signed && size < 8 && (*ret >> (size * 8 - 1)) != 0)
1848 ULONGLONG neg = -1;
1849 *ret |= neg << (size * 8);
1851 return TRUE;
1854 static BOOL be_arm_fetch_float(const struct dbg_lvalue* lvalue, unsigned size,
1855 long double* ret)
1857 char tmp[sizeof(long double)];
1859 /* FIXME: this assumes that debuggee and debugger use the same
1860 * representation for reals
1862 if (!memory_read_value(lvalue, size, tmp)) return FALSE;
1864 if (size == sizeof(float)) *ret = *(float*)tmp;
1865 else if (size == sizeof(double)) *ret = *(double*)tmp;
1866 else if (size == sizeof(long double)) *ret = *(long double*)tmp;
1867 else return FALSE;
1869 return TRUE;
1872 static BOOL be_arm_store_integer(const struct dbg_lvalue* lvalue, unsigned size,
1873 BOOL is_signed, LONGLONG val)
1875 /* this is simple if we're on a little endian CPU */
1876 return memory_write_value(lvalue, size, &val);
1879 static BOOL be_arm_get_context(HANDLE thread, dbg_ctx_t *ctx)
1881 ctx->ctx.ContextFlags = CONTEXT_ALL;
1882 return GetThreadContext(thread, &ctx->ctx);
1885 static BOOL be_arm_set_context(HANDLE thread, const dbg_ctx_t *ctx)
1887 return SetThreadContext(thread, &ctx->ctx);
1890 #define REG(f,n,t,r) {f, n, t, FIELD_OFFSET(CONTEXT, r), sizeof(((CONTEXT*)NULL)->r)}
1892 static struct gdb_register be_arm_gdb_register_map[] = {
1893 REG("core", "r0", NULL, R0),
1894 REG(NULL, "r1", NULL, R1),
1895 REG(NULL, "r2", NULL, R2),
1896 REG(NULL, "r3", NULL, R3),
1897 REG(NULL, "r4", NULL, R4),
1898 REG(NULL, "r5", NULL, R5),
1899 REG(NULL, "r6", NULL, R6),
1900 REG(NULL, "r7", NULL, R7),
1901 REG(NULL, "r8", NULL, R8),
1902 REG(NULL, "r9", NULL, R9),
1903 REG(NULL, "r10", NULL, R10),
1904 REG(NULL, "r11", NULL, R11),
1905 REG(NULL, "r12", NULL, R12),
1906 REG(NULL, "sp", "data_ptr", Sp),
1907 REG(NULL, "lr", "code_ptr", Lr),
1908 REG(NULL, "pc", "code_ptr", Pc),
1909 REG(NULL, "cpsr", NULL, Cpsr),
1912 struct backend_cpu be_arm =
1914 IMAGE_FILE_MACHINE_ARMNT,
1916 be_cpu_linearize,
1917 be_cpu_build_addr,
1918 be_arm_get_addr,
1919 be_arm_get_register_info,
1920 be_arm_single_step,
1921 be_arm_print_context,
1922 be_arm_print_segment_info,
1923 be_arm_ctx,
1924 be_arm_is_step_over_insn,
1925 be_arm_is_function_return,
1926 be_arm_is_break_insn,
1927 be_arm_is_func_call,
1928 be_arm_is_jump,
1929 be_arm_disasm_one_insn,
1930 be_arm_insert_Xpoint,
1931 be_arm_remove_Xpoint,
1932 be_arm_is_watchpoint_set,
1933 be_arm_clear_watchpoint,
1934 be_arm_adjust_pc_for_break,
1935 be_arm_fetch_integer,
1936 be_arm_fetch_float,
1937 be_arm_store_integer,
1938 be_arm_get_context,
1939 be_arm_set_context,
1940 be_arm_gdb_register_map,
1941 ARRAY_SIZE(be_arm_gdb_register_map),
1943 #endif