ddraw: Use wined3d_get_adapter_display_mode() in ddraw7_GetFourCCCodes().
[wine/multimedia.git] / programs / winedbg / be_arm.c
blob866ab61295f04d7234d73ddee3cf8c3fb33c483c
1 /*
2 * Debugger ARM specific functions
4 * Copyright 2000-2003 Marcus Meissner
5 * 2004 Eric Pouech
6 * 2010-2012 André Hentschel
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "debugger.h"
25 #if defined(__arm__) && !defined(__ARMEB__)
28 * Switch to disassemble Thumb code.
30 static BOOL db_disasm_thumb = FALSE;
33 * Flag to indicate whether we need to display instruction,
34 * or whether we just need to know the address of the next
35 * instruction.
37 static BOOL db_display = FALSE;
39 #define ARM_INSN_SIZE 4
40 #define THUMB_INSN_SIZE 2
41 #define THUMB2_INSN_SIZE 4
43 #define ROR32(n, r) (((n) >> (r)) | ((n) << (32 - (r))))
45 #define get_cond(ins) tbl_cond[(ins >> 28) & 0x0f]
46 #define get_nibble(ins, num) ((ins >> (num * 4)) & 0x0f)
48 static char const tbl_regs[][4] = {
49 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",
50 "fp", "ip", "sp", "lr", "pc", "cpsr"
53 static char const tbl_addrmode[][3] = {
54 "da", "ia", "db", "ib"
57 static char const tbl_cond[][3] = {
58 "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", "hi", "ls", "ge", "lt", "gt", "le", "", ""
61 static char const tbl_dataops[][4] = {
62 "and", "eor", "sub", "rsb", "add", "adc", "sbc", "rsc", "tst", "teq", "cmp", "cmn", "orr",
63 "mov", "bic", "mvn"
66 static char const tbl_shifts[][4] = {
67 "lsl", "lsr", "asr", "ror"
70 static char const tbl_hiops_t[][4] = {
71 "add", "cmp", "mov", "bx"
74 static char const tbl_aluops_t[][4] = {
75 "and", "eor", "lsl", "lsr", "asr", "adc", "sbc", "ror", "tst", "neg", "cmp", "cmn", "orr",
76 "mul", "bic", "mvn"
79 static char const tbl_immops_t[][4] = {
80 "mov", "cmp", "add", "sub"
83 static char const tbl_sregops_t[][5] = {
84 "strh", "ldsb", "ldrh", "ldsh"
87 static UINT db_get_inst(void* addr, int size)
89 UINT result = 0;
90 char buffer[4];
92 if (dbg_read_memory(addr, buffer, size))
94 switch (size)
96 case 4:
97 result = *(UINT*)buffer;
98 break;
99 case 2:
100 result = *(WORD*)buffer;
101 break;
104 return result;
107 static void db_printsym(unsigned int addr)
109 ADDRESS64 a;
111 a.Mode = AddrModeFlat;
112 a.Offset = addr;
114 print_address(&a, TRUE);
117 static UINT arm_disasm_branch(UINT inst, ADDRESS64 *addr)
119 short link = (inst >> 24) & 0x01;
120 int offset = (inst << 2) & 0x03ffffff;
122 if (offset & 0x02000000) offset |= 0xfc000000;
123 offset += 8;
125 dbg_printf("\n\tb%s%s\t", link ? "l" : "", get_cond(inst));
126 db_printsym(addr->Offset + offset);
127 return 0;
130 static UINT arm_disasm_branchreg(UINT inst, ADDRESS64 *addr)
132 dbg_printf("\n\tb%s\t%s", get_cond(inst), tbl_regs[get_nibble(inst, 0)]);
133 return 0;
136 static UINT arm_disasm_dataprocessing(UINT inst, ADDRESS64 *addr)
138 short condcodes = (inst >> 20) & 0x01;
139 short opcode = (inst >> 21) & 0x0f;
140 short immediate = (inst >> 25) & 0x01;
141 short no_op1 = (opcode & 0x0d) == 0x0d;
142 short no_dst = (opcode & 0x0c) == 0x08;
144 /* check for nop */
145 if (get_nibble(inst, 3) == 15 /* r15 */ && condcodes == 0 &&
146 opcode >= 8 /* tst */ && opcode <= 11 /* cmn */)
148 dbg_printf("\n\tnop");
149 return 0;
152 dbg_printf("\n\t%s%s%s", tbl_dataops[opcode], condcodes ? "s" : "", get_cond(inst));
153 if (!no_dst) dbg_printf("\t%s, ", tbl_regs[get_nibble(inst, 3)]);
154 else dbg_printf("\t");
156 if (no_op1)
158 if (immediate)
159 dbg_printf("#%u", ROR32(inst & 0xff, 2 * get_nibble(inst, 2)));
160 else
161 dbg_printf("%s", tbl_regs[get_nibble(inst, 0)]);
163 else
165 if (immediate)
166 dbg_printf("%s, #%u", tbl_regs[get_nibble(inst, 4)],
167 ROR32(inst & 0xff, 2 * get_nibble(inst, 2)));
168 else if (((inst >> 4) & 0xff) == 0x00) /* no shift */
169 dbg_printf("%s, %s", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
170 else if (((inst >> 4) & 0x09) == 0x01) /* register shift */
171 dbg_printf("%s, %s, %s %s", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)],
172 tbl_shifts[(inst >> 5) & 0x03], tbl_regs[(inst >> 8) & 0x0f]);
173 else if (((inst >> 4) & 0x01) == 0x00) /* immediate shift */
174 dbg_printf("%s, %s, %s #%d", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)],
175 tbl_shifts[(inst >> 5) & 0x03], (inst >> 7) & 0x1f);
176 else
177 return inst;
179 return 0;
182 static UINT arm_disasm_singletrans(UINT inst, ADDRESS64 *addr)
184 short load = (inst >> 20) & 0x01;
185 short writeback = (inst >> 21) & 0x01;
186 short byte = (inst >> 22) & 0x01;
187 short direction = (inst >> 23) & 0x01;
188 short indexing = (inst >> 24) & 0x01;
189 short immediate = !((inst >> 25) & 0x01);
190 short offset = inst & 0x0fff;
192 if (!direction) offset *= -1;
194 dbg_printf("\n\t%s%s%s%s", load ? "ldr" : "str", byte ? "b" : "", writeback ? "t" : "",
195 get_cond(inst));
196 dbg_printf("\t%s, ", tbl_regs[get_nibble(inst, 3)]);
197 if (indexing)
199 if (immediate)
200 dbg_printf("[%s, #%d]", tbl_regs[get_nibble(inst, 4)], offset);
201 else if (((inst >> 4) & 0xff) == 0x00) /* no shift */
202 dbg_printf("[%s, %s]", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
203 else if (((inst >> 4) & 0x01) == 0x00) /* immediate shift (there's no register shift) */
204 dbg_printf("[%s, %s, %s #%d]", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)],
205 tbl_shifts[(inst >> 5) & 0x03], (inst >> 7) & 0x1f);
206 else
207 return inst;
209 else
211 if (immediate)
212 dbg_printf("[%s], #%d", tbl_regs[get_nibble(inst, 4)], offset);
213 else if (((inst >> 4) & 0xff) == 0x00) /* no shift */
214 dbg_printf("[%s], %s", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
215 else if (((inst >> 4) & 0x01) == 0x00) /* immediate shift (there's no register shift) */
216 dbg_printf("[%s], %s, %s #%d", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)],
217 tbl_shifts[(inst >> 5) & 0x03], (inst >> 7) & 0x1f);
218 else
219 return inst;
221 return 0;
224 static UINT arm_disasm_halfwordtrans(UINT inst, ADDRESS64 *addr)
226 short halfword = (inst >> 5) & 0x01;
227 short sign = (inst >> 6) & 0x01;
228 short load = (inst >> 20) & 0x01;
229 short writeback = (inst >> 21) & 0x01;
230 short immediate = (inst >> 22) & 0x01;
231 short direction = (inst >> 23) & 0x01;
232 short indexing = (inst >> 24) & 0x01;
233 short offset = ((inst >> 4) & 0xf0) + (inst & 0x0f);
235 if (!direction) offset *= -1;
237 dbg_printf("\n\t%s%s%s%s%s", load ? "ldr" : "str", sign ? "s" : "",
238 halfword ? "h" : (sign ? "b" : ""), writeback ? "t" : "", get_cond(inst));
239 dbg_printf("\t%s, ", tbl_regs[get_nibble(inst, 3)]);
240 if (indexing)
242 if (immediate)
243 dbg_printf("[%s, #%d]", tbl_regs[get_nibble(inst, 4)], offset);
244 else
245 dbg_printf("[%s, %s]", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
247 else
249 if (immediate)
250 dbg_printf("[%s], #%d", tbl_regs[get_nibble(inst, 4)], offset);
251 else
252 dbg_printf("[%s], %s", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
254 return 0;
257 static UINT arm_disasm_blocktrans(UINT inst, ADDRESS64 *addr)
259 short load = (inst >> 20) & 0x01;
260 short writeback = (inst >> 21) & 0x01;
261 short psr = (inst >> 22) & 0x01;
262 short addrmode = (inst >> 23) & 0x03;
263 short i;
264 short last=15;
265 for (i=15;i>=0;i--)
266 if ((inst>>i) & 1)
268 last = i;
269 break;
272 dbg_printf("\n\t%s%s%s\t%s%s, {", load ? "ldm" : "stm", tbl_addrmode[addrmode], get_cond(inst),
273 tbl_regs[get_nibble(inst, 4)], writeback ? "!" : "");
274 for (i=0;i<=15;i++)
275 if ((inst>>i) & 1)
277 if (i == last) dbg_printf("%s", tbl_regs[i]);
278 else dbg_printf("%s, ", tbl_regs[i]);
280 dbg_printf("}%s", psr ? "^" : "");
281 return 0;
284 static UINT arm_disasm_swi(UINT inst, ADDRESS64 *addr)
286 UINT comment = inst & 0x00ffffff;
287 dbg_printf("\n\tswi%s\t#%d", get_cond(inst), comment);
288 return 0;
291 static UINT arm_disasm_coproctrans(UINT inst, ADDRESS64 *addr)
293 WORD CRm = inst & 0x0f;
294 WORD CP = (inst >> 5) & 0x07;
295 WORD CPnum = (inst >> 8) & 0x0f;
296 WORD CRn = (inst >> 16) & 0x0f;
297 WORD load = (inst >> 20) & 0x01;
298 WORD CP_Opc = (inst >> 21) & 0x07;
300 dbg_printf("\n\t%s%s\t%u, %u, %s, cr%u, cr%u, {%u}", load ? "mrc" : "mcr", get_cond(inst), CPnum,
301 CP, tbl_regs[get_nibble(inst, 3)], CRn, CRm, CP_Opc);
302 return 0;
305 static UINT arm_disasm_coprocdataop(UINT inst, ADDRESS64 *addr)
307 WORD CRm = inst & 0x0f;
308 WORD CP = (inst >> 5) & 0x07;
309 WORD CPnum = (inst >> 8) & 0x0f;
310 WORD CRd = (inst >> 12) & 0x0f;
311 WORD CRn = (inst >> 16) & 0x0f;
312 WORD CP_Opc = (inst >> 20) & 0x0f;
314 dbg_printf("\n\tcdp%s\t%u, %u, cr%u, cr%u, cr%u, {%u}", get_cond(inst),
315 CPnum, CP, CRd, CRn, CRm, CP_Opc);
316 return 0;
319 static UINT arm_disasm_coprocdatatrans(UINT inst, ADDRESS64 *addr)
321 WORD CPnum = (inst >> 8) & 0x0f;
322 WORD CRd = (inst >> 12) & 0x0f;
323 WORD load = (inst >> 20) & 0x01;
324 WORD writeback = (inst >> 21) & 0x01;
325 WORD translen = (inst >> 22) & 0x01;
326 WORD direction = (inst >> 23) & 0x01;
327 WORD indexing = (inst >> 24) & 0x01;
328 short offset = (inst & 0xff) << 2;
330 if (!direction) offset *= -1;
332 dbg_printf("\n\t%s%s%s", load ? "ldc" : "stc", translen ? "l" : "", get_cond(inst));
333 if (indexing)
334 dbg_printf("\t%u, cr%u, [%s, #%d]%s", CPnum, CRd, tbl_regs[get_nibble(inst, 4)], offset, writeback?"!":"");
335 else
336 dbg_printf("\t%u, cr%u, [%s], #%d", CPnum, CRd, tbl_regs[get_nibble(inst, 4)], offset);
337 return 0;
340 static WORD thumb_disasm_hireg(WORD inst, ADDRESS64 *addr)
342 short dst = inst & 0x07;
343 short src = (inst >> 3) & 0x07;
344 short h2 = (inst >> 6) & 0x01;
345 short h1 = (inst >> 7) & 0x01;
346 short op = (inst >> 8) & 0x03;
348 if (h1) dst += 8;
349 if (h2) src += 8;
351 if (op == 2 && dst == src) /* mov rx, rx */
353 dbg_printf("\n\tnop");
354 return 0;
357 if (op == 3)
358 dbg_printf("\n\tb%sx\t%s", h1?"l":"", tbl_regs[src]);
359 else
360 dbg_printf("\n\t%s\t%s, %s", tbl_hiops_t[op], tbl_regs[dst], tbl_regs[src]);
362 return 0;
365 static WORD thumb_disasm_aluop(WORD inst, ADDRESS64 *addr)
367 short dst = inst & 0x07;
368 short src = (inst >> 3) & 0x07;
369 short op = (inst >> 6) & 0x0f;
371 dbg_printf("\n\t%s\t%s, %s", tbl_aluops_t[op], tbl_regs[dst], tbl_regs[src]);
373 return 0;
376 static WORD thumb_disasm_pushpop(WORD inst, ADDRESS64 *addr)
378 short lrpc = (inst >> 8) & 0x01;
379 short load = (inst >> 11) & 0x01;
380 short i;
381 short last;
383 for (i=7;i>=0;i--)
384 if ((inst>>i) & 1) break;
385 last = i;
387 dbg_printf("\n\t%s\t{", load ? "pop" : "push");
389 for (i=0;i<=7;i++)
390 if ((inst>>i) & 1)
392 if (i == last) dbg_printf("%s", tbl_regs[i]);
393 else dbg_printf("%s, ", tbl_regs[i]);
395 if (lrpc)
396 dbg_printf("%s%s", last ? ", " : "", load ? "pc" : "lr");
398 dbg_printf("}");
399 return 0;
402 static WORD thumb_disasm_blocktrans(WORD inst, ADDRESS64 *addr)
404 short load = (inst >> 11) & 0x01;
405 short i;
406 short last;
408 for (i=7;i>=0;i--)
409 if ((inst>>i) & 1) break;
410 last = i;
412 dbg_printf("\n\t%s\t%s!, {", load ? "ldmia" : "stmia", tbl_regs[(inst >> 8) & 0x07]);
414 for (i=0;i<=7;i++)
415 if ((inst>>i) & 1)
417 if (i == last) dbg_printf("%s", tbl_regs[i]);
418 else dbg_printf("%s, ", tbl_regs[i]);
421 dbg_printf("}");
422 return 0;
425 static WORD thumb_disasm_condbranch(WORD inst, ADDRESS64 *addr)
427 WORD offset = inst & 0x00ff;
428 dbg_printf("\n\tb%s\t", tbl_cond[(inst >> 8) & 0x0f]);
429 db_printsym(addr->Offset + offset);
430 return 0;
433 static WORD thumb_disasm_uncondbranch(WORD inst, ADDRESS64 *addr)
435 short offset = (inst & 0x07ff) << 1;
437 if (offset & 0x0800) offset |= 0xf000;
438 offset += 4;
440 dbg_printf("\n\tb\t");
441 db_printsym(addr->Offset + offset);
442 return 0;
445 static WORD thumb_disasm_loadadr(WORD inst, ADDRESS64 *addr)
447 WORD src = (inst >> 11) & 0x01;
448 WORD offset = (inst & 0xff) << 2;
450 dbg_printf("\n\tadd\t%s, %s, #%d", tbl_regs[(inst >> 8) & 0x07], src ? "sp" : "pc", offset);
451 return 0;
454 static WORD thumb_disasm_swi(WORD inst, ADDRESS64 *addr)
456 WORD comment = inst & 0x00ff;
457 dbg_printf("\n\tswi\t#%d", comment);
458 return 0;
461 static WORD thumb_disasm_nop(WORD inst, ADDRESS64 *addr)
463 dbg_printf("\n\tnop");
464 return 0;
467 static WORD thumb_disasm_ldrpcrel(WORD inst, ADDRESS64 *addr)
469 WORD offset = (inst & 0xff) << 2;
470 dbg_printf("\n\tldr\t%s, [pc, #%u]", tbl_regs[(inst >> 8) & 0x07], offset);
471 return 0;
474 static WORD thumb_disasm_ldrsprel(WORD inst, ADDRESS64 *addr)
476 WORD offset = (inst & 0xff) << 2;
477 dbg_printf("\n\t%s\t%s, [sp, #%u]", (inst & 0x0800)?"ldr":"str", tbl_regs[(inst >> 8) & 0x07], offset);
478 return 0;
481 static WORD thumb_disasm_addsprel(WORD inst, ADDRESS64 *addr)
483 WORD offset = (inst & 0x7f) << 2;
484 if ((inst >> 7) & 0x01)
485 dbg_printf("\n\tsub\tsp, sp, #%u", offset);
486 else
487 dbg_printf("\n\tadd\tsp, sp, #%u", offset);
488 return 0;
491 static WORD thumb_disasm_ldrimm(WORD inst, ADDRESS64 *addr)
493 WORD offset = (inst & 0x07c0) >> 6;
494 dbg_printf("\n\t%s%s\t%s, [%s, #%u]", (inst & 0x0800)?"ldr":"str", (inst & 0x1000)?"b":"",
495 tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07], (inst & 0x1000)?offset:(offset << 2));
496 return 0;
499 static WORD thumb_disasm_ldrhimm(WORD inst, ADDRESS64 *addr)
501 WORD offset = (inst & 0x07c0) >> 5;
502 dbg_printf("\n\t%s\t%s, [%s, #%u]", (inst & 0x0800)?"ldrh":"strh",
503 tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07], offset);
504 return 0;
507 static WORD thumb_disasm_ldrreg(WORD inst, ADDRESS64 *addr)
509 dbg_printf("\n\t%s%s\t%s, [%s, %s]", (inst & 0x0800)?"ldr":"str", (inst & 0x0400)?"b":"",
510 tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07], tbl_regs[(inst >> 6) & 0x07]);
511 return 0;
514 static WORD thumb_disasm_ldrsreg(WORD inst, ADDRESS64 *addr)
516 dbg_printf("\n\t%s\t%s, [%s, %s]", tbl_sregops_t[(inst >> 10) & 0x03],
517 tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07], tbl_regs[(inst >> 6) & 0x07]);
518 return 0;
521 static WORD thumb_disasm_immop(WORD inst, ADDRESS64 *addr)
523 WORD op = (inst >> 11) & 0x03;
524 dbg_printf("\n\t%s\t%s, #%u", tbl_immops_t[op], tbl_regs[(inst >> 8) & 0x07], inst & 0xff);
525 return 0;
528 static WORD thumb_disasm_addsub(WORD inst, ADDRESS64 *addr)
530 WORD op = (inst >> 9) & 0x01;
531 WORD immediate = (inst >> 10) & 0x01;
533 dbg_printf("\n\t%s\t%s, %s, ", op ? "sub" : "add",
534 tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07]);
535 if (immediate)
536 dbg_printf("#%d", (inst >> 6) & 0x07);
537 else
538 dbg_printf("%s", tbl_regs[(inst >> 6) & 0x07]);
539 return 0;
542 static WORD thumb_disasm_movshift(WORD inst, ADDRESS64 *addr)
544 WORD op = (inst >> 11) & 0x03;
545 dbg_printf("\n\t%s\t%s, %s, #%u", tbl_shifts[op],
546 tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07], (inst >> 6) & 0x1f);
547 return 0;
550 static UINT thumb2_disasm_branchlinked(UINT inst, ADDRESS64 *addr)
552 UINT offset = (((inst & 0x07ff0000) >> 4) | ((inst & 0x000007ff) << 1)) + 4;
554 dbg_printf("\n\tbl\t");
555 db_printsym(addr->Offset + offset);
556 return 0;
559 static UINT thumb2_disasm_misc(UINT inst, ADDRESS64 *addr)
561 WORD op1 = (inst >> 20) & 0x03;
562 WORD op2 = (inst >> 4) & 0x03;
564 if (get_nibble(inst, 4) != get_nibble(inst, 0))
565 return inst;
567 if (op1 == 3 && op2 == 0)
569 dbg_printf("\n\tclz\t%s, %s\t", tbl_regs[get_nibble(inst, 2)], tbl_regs[get_nibble(inst, 0)]);
570 return 0;
573 if (op1 == 1)
575 switch (op2)
577 case 0:
578 dbg_printf("\n\trev\t");
579 break;
580 case 1:
581 dbg_printf("\n\trev16\t");
582 break;
583 case 2:
584 dbg_printf("\n\trbit\t");
585 break;
586 case 3:
587 dbg_printf("\n\trevsh\t");
588 break;
590 dbg_printf("%s, %s\t", tbl_regs[get_nibble(inst, 2)], tbl_regs[get_nibble(inst, 0)]);
591 return 0;
594 return inst;
597 static UINT thumb2_disasm_mul(UINT inst, ADDRESS64 *addr)
599 WORD op1 = (inst >> 20) & 0x07;
600 WORD op2 = (inst >> 4) & 0x03;
602 if (op1)
603 return inst;
605 if (op2 == 0 && get_nibble(inst, 3) != 0xf)
607 dbg_printf("\n\tmla\t%s, %s, %s, %s\t", tbl_regs[get_nibble(inst, 2)],
608 tbl_regs[get_nibble(inst, 4)],
609 tbl_regs[get_nibble(inst, 0)],
610 tbl_regs[get_nibble(inst, 3)]);
611 return 0;
614 if (op2 == 0 && get_nibble(inst, 3) == 0xf)
616 dbg_printf("\n\tmul\t%s, %s, %s\t", tbl_regs[get_nibble(inst, 2)],
617 tbl_regs[get_nibble(inst, 4)],
618 tbl_regs[get_nibble(inst, 0)]);
619 return 0;
622 if (op2 == 1)
624 dbg_printf("\n\tmls\t%s, %s, %s, %s\t", tbl_regs[get_nibble(inst, 2)],
625 tbl_regs[get_nibble(inst, 4)],
626 tbl_regs[get_nibble(inst, 0)],
627 tbl_regs[get_nibble(inst, 3)]);
628 return 0;
631 return inst;
634 static UINT thumb2_disasm_longmuldiv(UINT inst, ADDRESS64 *addr)
636 WORD op1 = (inst >> 20) & 0x07;
637 WORD op2 = (inst >> 4) & 0x0f;
639 if (op2 == 0)
641 switch (op1)
643 case 0:
644 dbg_printf("\n\tsmull\t");
645 break;
646 case 2:
647 dbg_printf("\n\tumull\t");
648 break;
649 case 4:
650 dbg_printf("\n\tsmlal\t");
651 break;
652 case 6:
653 dbg_printf("\n\tumlal\t");
654 break;
655 default:
656 return inst;
658 dbg_printf("%s, %s, %s, %s\t", tbl_regs[get_nibble(inst, 3)], tbl_regs[get_nibble(inst, 2)],
659 tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
660 return 0;
663 if (op2 == 0xffff)
665 switch (op1)
667 case 1:
668 dbg_printf("\n\tsdiv\t");
669 break;
670 case 3:
671 dbg_printf("\n\tudiv\t");
672 break;
673 default:
674 return inst;
676 dbg_printf("%s, %s, %s\t", tbl_regs[get_nibble(inst, 2)], tbl_regs[get_nibble(inst, 4)],
677 tbl_regs[get_nibble(inst, 0)]);
678 return 0;
681 return inst;
684 struct inst_arm
686 UINT mask;
687 UINT pattern;
688 UINT (*func)(UINT, ADDRESS64*);
691 static const struct inst_arm tbl_arm[] = {
692 { 0x0e000000, 0x0a000000, arm_disasm_branch },
693 { 0x0e000090, 0x00000090, arm_disasm_halfwordtrans },
694 { 0x0fffff00, 0x012fff00, arm_disasm_branchreg },
695 { 0x0c000000, 0x00000000, arm_disasm_dataprocessing },
696 { 0x0c000000, 0x04000000, arm_disasm_singletrans },
697 { 0x0e000000, 0x08000000, arm_disasm_blocktrans },
698 { 0x0f000000, 0x0f000000, arm_disasm_swi },
699 { 0x0f000010, 0x0e000010, arm_disasm_coproctrans },
700 { 0x0f000010, 0x0e000000, arm_disasm_coprocdataop },
701 { 0x0e000000, 0x0c000000, arm_disasm_coprocdatatrans },
702 { 0x00000000, 0x00000000, NULL }
705 struct inst_thumb16
707 WORD mask;
708 WORD pattern;
709 WORD (*func)(WORD, ADDRESS64*);
712 static const struct inst_thumb16 tbl_thumb16[] = {
713 { 0xfc00, 0x4400, thumb_disasm_hireg },
714 { 0xfc00, 0x4000, thumb_disasm_aluop },
715 { 0xf600, 0xb400, thumb_disasm_pushpop },
716 { 0xf000, 0xc000, thumb_disasm_blocktrans },
717 { 0xf000, 0xd000, thumb_disasm_condbranch },
718 { 0xf800, 0xe000, thumb_disasm_uncondbranch },
719 { 0xf000, 0xa000, thumb_disasm_loadadr },
720 { 0xf800, 0x4800, thumb_disasm_ldrpcrel },
721 { 0xf000, 0x9000, thumb_disasm_ldrsprel },
722 { 0xff00, 0xb000, thumb_disasm_addsprel },
723 { 0xe000, 0x6000, thumb_disasm_ldrimm },
724 { 0xf000, 0x8000, thumb_disasm_ldrhimm },
725 { 0xf200, 0x5000, thumb_disasm_ldrreg },
726 { 0xf200, 0x5200, thumb_disasm_ldrsreg },
727 { 0xe000, 0x2000, thumb_disasm_immop },
728 { 0xff00, 0xdf00, thumb_disasm_swi },
729 { 0xff00, 0xbf00, thumb_disasm_nop },
730 { 0xf800, 0x1800, thumb_disasm_addsub },
731 { 0xe000, 0x0000, thumb_disasm_movshift },
732 { 0x0000, 0x0000, NULL }
735 static const struct inst_arm tbl_thumb32[] = {
736 { 0xf800f800, 0xf000f800, thumb2_disasm_branchlinked },
737 { 0xffc0f0c0, 0xfa80f080, thumb2_disasm_misc },
738 { 0xff8000c0, 0xfb000000, thumb2_disasm_mul },
739 { 0xff8000f0, 0xfb800000, thumb2_disasm_longmuldiv },
740 { 0xff8000f0, 0xfb8000f0, thumb2_disasm_longmuldiv },
741 { 0x00000000, 0x00000000, NULL }
744 /***********************************************************************
745 * disasm_one_insn
747 * Disassemble instruction at 'addr'. addr is changed to point to the
748 * start of the next instruction.
750 void be_arm_disasm_one_insn(ADDRESS64 *addr, int display)
752 struct inst_arm *a_ptr = (struct inst_arm *)&tbl_arm;
753 struct inst_thumb16 *t_ptr = (struct inst_thumb16 *)&tbl_thumb16;
754 struct inst_arm *t2_ptr = (struct inst_arm *)&tbl_thumb32;
755 UINT inst;
756 WORD tinst;
757 int size;
758 int matched = 0;
760 char tmp[64];
761 DWORD_PTR* pval;
763 if (!memory_get_register(CV_ARM_CPSR, &pval, tmp, sizeof(tmp)))
764 dbg_printf("\n\tmemory_get_register failed: %s", tmp);
765 else
766 db_disasm_thumb=(*pval & 0x20)?TRUE:FALSE;
768 db_display = display;
770 if (!db_disasm_thumb)
772 size = ARM_INSN_SIZE;
773 inst = db_get_inst( memory_to_linear_addr(addr), size );
774 while (a_ptr->func) {
775 if ((inst & a_ptr->mask) == a_ptr->pattern) {
776 matched = 1;
777 break;
779 a_ptr++;
782 if (!matched) {
783 dbg_printf("\n\tUnknown ARM Instruction: %08x", inst);
784 addr->Offset += size;
786 else
788 if (!a_ptr->func(inst, addr))
789 addr->Offset += size;
791 return;
793 else
795 WORD *taddr = memory_to_linear_addr(addr);
796 tinst = db_get_inst( taddr, THUMB_INSN_SIZE );
797 switch (tinst & 0xf800)
799 case 0xe800:
800 case 0xf000:
801 case 0xf800:
802 size = THUMB2_INSN_SIZE;
803 taddr++;
804 inst = db_get_inst( taddr, THUMB_INSN_SIZE );
805 inst |= (tinst << 16);
807 while (t2_ptr->func) {
808 if ((inst & t2_ptr->mask) == t2_ptr->pattern) {
809 matched = 1;
810 break;
812 t2_ptr++;
815 if (!matched) {
816 dbg_printf("\n\tUnknown Thumb2 Instruction: %08x", inst);
817 addr->Offset += size;
819 else
821 if (!t2_ptr->func(inst, addr))
822 addr->Offset += size;
824 return;
825 default:
826 break;
829 size = THUMB_INSN_SIZE;
830 while (t_ptr->func) {
831 if ((tinst & t_ptr->mask) == t_ptr->pattern) {
832 matched = 1;
833 break;
835 t_ptr++;
838 if (!matched) {
839 dbg_printf("\n\tUnknown Thumb Instruction: %04x", tinst);
840 addr->Offset += size;
842 else
844 if (!t_ptr->func(tinst, addr))
845 addr->Offset += size;
847 return;
851 static unsigned be_arm_get_addr(HANDLE hThread, const CONTEXT* ctx,
852 enum be_cpu_addr bca, ADDRESS64* addr)
854 switch (bca)
856 case be_cpu_addr_pc:
857 return be_cpu_build_addr(hThread, ctx, addr, 0, ctx->Pc);
858 case be_cpu_addr_stack:
859 return be_cpu_build_addr(hThread, ctx, addr, 0, ctx->Sp);
860 case be_cpu_addr_frame:
861 return be_cpu_build_addr(hThread, ctx, addr, 0, ctx->Fp);
863 return FALSE;
866 static unsigned be_arm_get_register_info(int regno, enum be_cpu_addr* kind)
868 switch (regno)
870 case CV_ARM_PC: *kind = be_cpu_addr_pc; return TRUE;
871 case CV_ARM_R0 + 11: *kind = be_cpu_addr_frame; return TRUE;
872 case CV_ARM_SP: *kind = be_cpu_addr_stack; return TRUE;
874 return FALSE;
877 static void be_arm_single_step(CONTEXT* ctx, unsigned enable)
879 dbg_printf("be_arm_single_step: not done\n");
882 static void be_arm_print_context(HANDLE hThread, const CONTEXT* ctx, int all_regs)
884 static const char condflags[] = "NZCV";
885 int i;
886 char buf[8];
888 switch (ctx->Cpsr & 0x1F)
890 case 0: strcpy(buf, "User26"); break;
891 case 1: strcpy(buf, "FIQ26"); break;
892 case 2: strcpy(buf, "IRQ26"); break;
893 case 3: strcpy(buf, "SVC26"); break;
894 case 16: strcpy(buf, "User"); break;
895 case 17: strcpy(buf, "FIQ"); break;
896 case 18: strcpy(buf, "IRQ"); break;
897 case 19: strcpy(buf, "SVC"); break;
898 case 23: strcpy(buf, "ABT"); break;
899 case 27: strcpy(buf, "UND"); break;
900 default: strcpy(buf, "UNKNWN"); break;
903 dbg_printf("Register dump:\n");
904 dbg_printf("%s %s Mode\n", (ctx->Cpsr & 0x20) ? "Thumb" : "ARM", buf);
906 strcpy(buf, condflags);
907 for (i = 0; buf[i]; i++)
908 if (!((ctx->Cpsr >> 26) & (1 << (sizeof(condflags) - i))))
909 buf[i] = '-';
911 dbg_printf(" Pc:%04x Sp:%04x Lr:%04x Cpsr:%04x(%s)\n",
912 ctx->Pc, ctx->Sp, ctx->Lr, ctx->Cpsr, buf);
913 dbg_printf(" r0:%04x r1:%04x r2:%04x r3:%04x\n",
914 ctx->R0, ctx->R1, ctx->R2, ctx->R3);
915 dbg_printf(" r4:%04x r5:%04x r6:%04x r7:%04x r8:%04x\n",
916 ctx->R4, ctx->R5, ctx->R6, ctx->R7, ctx->R8 );
917 dbg_printf(" r9:%04x r10:%04x Fp:%04x Ip:%04x\n",
918 ctx->R9, ctx->R10, ctx->Fp, ctx->Ip );
920 if (all_regs) dbg_printf( "Floating point ARM dump not implemented\n" );
923 static void be_arm_print_segment_info(HANDLE hThread, const CONTEXT* ctx)
927 static struct dbg_internal_var be_arm_ctx[] =
929 {CV_ARM_R0 + 0, "r0", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R0), dbg_itype_unsigned_int},
930 {CV_ARM_R0 + 1, "r1", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R1), dbg_itype_unsigned_int},
931 {CV_ARM_R0 + 2, "r2", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R2), dbg_itype_unsigned_int},
932 {CV_ARM_R0 + 3, "r3", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R3), dbg_itype_unsigned_int},
933 {CV_ARM_R0 + 4, "r4", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R4), dbg_itype_unsigned_int},
934 {CV_ARM_R0 + 5, "r5", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R5), dbg_itype_unsigned_int},
935 {CV_ARM_R0 + 6, "r6", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R6), dbg_itype_unsigned_int},
936 {CV_ARM_R0 + 7, "r7", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R7), dbg_itype_unsigned_int},
937 {CV_ARM_R0 + 8, "r8", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R8), dbg_itype_unsigned_int},
938 {CV_ARM_R0 + 9, "r9", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R9), dbg_itype_unsigned_int},
939 {CV_ARM_R0 + 10, "r10", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R10), dbg_itype_unsigned_int},
940 {CV_ARM_R0 + 11, "r11", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Fp), dbg_itype_unsigned_int},
941 {CV_ARM_R0 + 12, "r12", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Ip), dbg_itype_unsigned_int},
942 {CV_ARM_SP, "sp", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Sp), dbg_itype_unsigned_int},
943 {CV_ARM_LR, "lr", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Lr), dbg_itype_unsigned_int},
944 {CV_ARM_PC, "pc", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Pc), dbg_itype_unsigned_int},
945 {CV_ARM_CPSR, "cpsr", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Cpsr), dbg_itype_unsigned_int},
946 {0, NULL, 0, dbg_itype_none}
949 static unsigned be_arm_is_step_over_insn(const void* insn)
951 dbg_printf("be_arm_is_step_over_insn: not done\n");
952 return FALSE;
955 static unsigned be_arm_is_function_return(const void* insn)
957 dbg_printf("be_arm_is_function_return: not done\n");
958 return FALSE;
961 static unsigned be_arm_is_break_insn(const void* insn)
963 dbg_printf("be_arm_is_break_insn: not done\n");
964 return FALSE;
967 static unsigned be_arm_is_func_call(const void* insn, ADDRESS64* callee)
969 return FALSE;
972 static unsigned be_arm_is_jump(const void* insn, ADDRESS64* jumpee)
974 return FALSE;
977 static unsigned be_arm_insert_Xpoint(HANDLE hProcess, const struct be_process_io* pio,
978 CONTEXT* ctx, enum be_xpoint_type type,
979 void* addr, unsigned long* val, unsigned size)
981 SIZE_T sz;
983 switch (type)
985 case be_xpoint_break:
986 if (!size) return 0;
987 if (!pio->read(hProcess, addr, val, 4, &sz) || sz != 4) return 0;
988 default:
989 dbg_printf("Unknown/unsupported bp type %c\n", type);
990 return 0;
992 return 1;
995 static unsigned be_arm_remove_Xpoint(HANDLE hProcess, const struct be_process_io* pio,
996 CONTEXT* ctx, enum be_xpoint_type type,
997 void* addr, unsigned long val, unsigned size)
999 SIZE_T sz;
1001 switch (type)
1003 case be_xpoint_break:
1004 if (!size) return 0;
1005 if (!pio->write(hProcess, addr, &val, 4, &sz) || sz == 4) return 0;
1006 break;
1007 default:
1008 dbg_printf("Unknown/unsupported bp type %c\n", type);
1009 return 0;
1011 return 1;
1014 static unsigned be_arm_is_watchpoint_set(const CONTEXT* ctx, unsigned idx)
1016 dbg_printf("be_arm_is_watchpoint_set: not done\n");
1017 return FALSE;
1020 static void be_arm_clear_watchpoint(CONTEXT* ctx, unsigned idx)
1022 dbg_printf("be_arm_clear_watchpoint: not done\n");
1025 static int be_arm_adjust_pc_for_break(CONTEXT* ctx, BOOL way)
1027 INT step = (ctx->Cpsr & 0x20) ? 2 : 4;
1029 if (way)
1031 ctx->Pc -= step;
1032 return -step;
1034 ctx->Pc += step;
1035 return step;
1038 static int be_arm_fetch_integer(const struct dbg_lvalue* lvalue, unsigned size,
1039 unsigned ext_sign, LONGLONG* ret)
1041 if (size != 1 && size != 2 && size != 4 && size != 8) return FALSE;
1043 memset(ret, 0, sizeof(*ret)); /* clear unread bytes */
1044 /* FIXME: this assumes that debuggee and debugger use the same
1045 * integral representation
1047 if (!memory_read_value(lvalue, size, ret)) return FALSE;
1049 /* propagate sign information */
1050 if (ext_sign && size < 8 && (*ret >> (size * 8 - 1)) != 0)
1052 ULONGLONG neg = -1;
1053 *ret |= neg << (size * 8);
1055 return TRUE;
1058 static int be_arm_fetch_float(const struct dbg_lvalue* lvalue, unsigned size,
1059 long double* ret)
1061 char tmp[sizeof(long double)];
1063 /* FIXME: this assumes that debuggee and debugger use the same
1064 * representation for reals
1066 if (!memory_read_value(lvalue, size, tmp)) return FALSE;
1068 switch (size)
1070 case sizeof(float): *ret = *(float*)tmp; break;
1071 case sizeof(double): *ret = *(double*)tmp; break;
1072 default: return FALSE;
1074 return TRUE;
1077 static int be_arm_store_integer(const struct dbg_lvalue* lvalue, unsigned size,
1078 unsigned is_signed, LONGLONG val)
1080 /* this is simple if we're on a little endian CPU */
1081 return memory_write_value(lvalue, size, &val);
1084 struct backend_cpu be_arm =
1086 IMAGE_FILE_MACHINE_ARMV7,
1088 be_cpu_linearize,
1089 be_cpu_build_addr,
1090 be_arm_get_addr,
1091 be_arm_get_register_info,
1092 be_arm_single_step,
1093 be_arm_print_context,
1094 be_arm_print_segment_info,
1095 be_arm_ctx,
1096 be_arm_is_step_over_insn,
1097 be_arm_is_function_return,
1098 be_arm_is_break_insn,
1099 be_arm_is_func_call,
1100 be_arm_is_jump,
1101 be_arm_disasm_one_insn,
1102 be_arm_insert_Xpoint,
1103 be_arm_remove_Xpoint,
1104 be_arm_is_watchpoint_set,
1105 be_arm_clear_watchpoint,
1106 be_arm_adjust_pc_for_break,
1107 be_arm_fetch_integer,
1108 be_arm_fetch_float,
1109 be_arm_store_integer,
1111 #endif