winedbg: Add special register processing operators to Thumb2 disassembler.
[wine.git] / programs / winedbg / be_arm.c
bloba045e490a2a10144b9eb0fe9f3010dd05db1c948
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 char const tbl_miscops_t2[][6] = {
88 "rev", "rev16", "rbit", "revsh"
91 static char const tbl_width_t2[][2] = {
92 "b", "h", "", "?"
95 static char const tbl_special_regs_t2[][12] = {
96 "apsr", "iapsr", "eapsr", "xpsr", "rsvd", "ipsr", "epsr", "iepsr", "msp", "psp", "rsvd", "rsvd",
97 "rsvd", "rsvd", "rsvd", "rsvd", "primask", "basepri", "basepri_max", "faultmask", "control"
100 static UINT db_get_inst(void* addr, int size)
102 UINT result = 0;
103 char buffer[4];
105 if (dbg_read_memory(addr, buffer, size))
107 switch (size)
109 case 4:
110 result = *(UINT*)buffer;
111 break;
112 case 2:
113 result = *(WORD*)buffer;
114 break;
117 return result;
120 static void db_printsym(unsigned int addr)
122 ADDRESS64 a;
124 a.Mode = AddrModeFlat;
125 a.Offset = addr;
127 print_address(&a, TRUE);
130 static UINT arm_disasm_branch(UINT inst, ADDRESS64 *addr)
132 short link = (inst >> 24) & 0x01;
133 int offset = (inst << 2) & 0x03ffffff;
135 if (offset & 0x02000000) offset |= 0xfc000000;
136 offset += 8;
138 dbg_printf("\n\tb%s%s\t", link ? "l" : "", get_cond(inst));
139 db_printsym(addr->Offset + offset);
140 return 0;
143 static UINT arm_disasm_mul(UINT inst, ADDRESS64 *addr)
145 short accu = (inst >> 21) & 0x01;
146 short condcodes = (inst >> 20) & 0x01;
148 if (accu)
149 dbg_printf("\n\tmla%s%s\t%s, %s, %s, %s", get_cond(inst), condcodes ? "s" : "",
150 tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)],
151 tbl_regs[get_nibble(inst, 2)], tbl_regs[get_nibble(inst, 3)]);
152 else
153 dbg_printf("\n\tmul%s%s\t%s, %s, %s", get_cond(inst), condcodes ? "s" : "",
154 tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)],
155 tbl_regs[get_nibble(inst, 2)]);
156 return 0;
159 static UINT arm_disasm_longmul(UINT inst, ADDRESS64 *addr)
161 short sign = (inst >> 22) & 0x01;
162 short accu = (inst >> 21) & 0x01;
163 short condcodes = (inst >> 20) & 0x01;
165 dbg_printf("\n\t%s%s%s%s\t%s, %s, %s, %s", sign ? "s" : "u", accu ? "mlal" : "mull",
166 get_cond(inst), condcodes ? "s" : "",
167 tbl_regs[get_nibble(inst, 3)], tbl_regs[get_nibble(inst, 4)],
168 tbl_regs[get_nibble(inst, 0)], tbl_regs[get_nibble(inst, 2)]);
169 return 0;
172 static UINT arm_disasm_swp(UINT inst, ADDRESS64 *addr)
174 short byte = (inst >> 22) & 0x01;
176 dbg_printf("\n\tswp%s%s\t%s, %s, [%s]", get_cond(inst), byte ? "b" : "",
177 tbl_regs[get_nibble(inst, 3)], tbl_regs[get_nibble(inst, 0)],
178 tbl_regs[get_nibble(inst, 4)]);
179 return 0;
182 static UINT arm_disasm_branchreg(UINT inst, ADDRESS64 *addr)
184 dbg_printf("\n\tb%s\t%s", get_cond(inst), tbl_regs[get_nibble(inst, 0)]);
185 return 0;
188 static UINT arm_disasm_branchxchg(UINT inst, ADDRESS64 *addr)
190 dbg_printf("\n\tbx%s\t%s", get_cond(inst), tbl_regs[get_nibble(inst, 0)]);
191 return 0;
194 static UINT arm_disasm_mrstrans(UINT inst, ADDRESS64 *addr)
196 short src = (inst >> 22) & 0x01;
198 dbg_printf("\n\tmrs%s\t%s, %s", get_cond(inst), tbl_regs[get_nibble(inst, 3)],
199 src ? "spsr" : "cpsr");
200 return 0;
203 static UINT arm_disasm_msrtrans(UINT inst, ADDRESS64 *addr)
205 short immediate = (inst >> 25) & 0x01;
206 short dst = (inst >> 22) & 0x01;
207 short simple = (inst >> 16) & 0x01;
209 if (simple || !immediate)
211 dbg_printf("\n\tmsr%s\t%s, %s", get_cond(inst), dst ? "spsr" : "cpsr",
212 tbl_regs[get_nibble(inst, 0)]);
213 return 0;
216 dbg_printf("\n\tmsr%s\t%s, #%u", get_cond(inst), dst ? "spsr" : "cpsr",
217 ROR32(inst & 0xff, 2 * get_nibble(inst, 2)));
218 return 0;
221 static UINT arm_disasm_wordmov(UINT inst, ADDRESS64 *addr)
223 short top = (inst >> 22) & 0x01;
225 dbg_printf("\n\tmov%s%s\t%s, #%u", top ? "t" : "w", get_cond(inst),
226 tbl_regs[get_nibble(inst, 3)], (get_nibble(inst, 4) << 12) | (inst & 0x0fff));
227 return 0;
230 static UINT arm_disasm_nop(UINT inst, ADDRESS64 *addr)
232 dbg_printf("\n\tnop%s", get_cond(inst));
233 return 0;
236 static UINT arm_disasm_dataprocessing(UINT inst, ADDRESS64 *addr)
238 short condcodes = (inst >> 20) & 0x01;
239 short opcode = (inst >> 21) & 0x0f;
240 short immediate = (inst >> 25) & 0x01;
241 short no_op1 = (opcode & 0x0d) == 0x0d;
242 short no_dst = (opcode & 0x0c) == 0x08;
244 dbg_printf("\n\t%s%s%s", tbl_dataops[opcode], condcodes ? "s" : "", get_cond(inst));
245 if (!no_dst) dbg_printf("\t%s, ", tbl_regs[get_nibble(inst, 3)]);
246 else dbg_printf("\t");
248 if (no_op1)
250 if (immediate)
251 dbg_printf("#%u", ROR32(inst & 0xff, 2 * get_nibble(inst, 2)));
252 else
253 dbg_printf("%s", tbl_regs[get_nibble(inst, 0)]);
255 else
257 if (immediate)
258 dbg_printf("%s, #%u", tbl_regs[get_nibble(inst, 4)],
259 ROR32(inst & 0xff, 2 * get_nibble(inst, 2)));
260 else if (((inst >> 4) & 0xff) == 0x00) /* no shift */
261 dbg_printf("%s, %s", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
262 else if (((inst >> 4) & 0x09) == 0x01) /* register shift */
263 dbg_printf("%s, %s, %s %s", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)],
264 tbl_shifts[(inst >> 5) & 0x03], tbl_regs[(inst >> 8) & 0x0f]);
265 else if (((inst >> 4) & 0x01) == 0x00) /* immediate shift */
266 dbg_printf("%s, %s, %s #%d", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)],
267 tbl_shifts[(inst >> 5) & 0x03], (inst >> 7) & 0x1f);
268 else
269 return inst;
271 return 0;
274 static UINT arm_disasm_singletrans(UINT inst, ADDRESS64 *addr)
276 short load = (inst >> 20) & 0x01;
277 short writeback = (inst >> 21) & 0x01;
278 short byte = (inst >> 22) & 0x01;
279 short direction = (inst >> 23) & 0x01;
280 short indexing = (inst >> 24) & 0x01;
281 short immediate = !((inst >> 25) & 0x01);
282 short offset = inst & 0x0fff;
284 if (!direction) offset *= -1;
286 dbg_printf("\n\t%s%s%s%s", load ? "ldr" : "str", byte ? "b" : "", writeback ? "t" : "",
287 get_cond(inst));
288 dbg_printf("\t%s, ", tbl_regs[get_nibble(inst, 3)]);
289 if (indexing)
291 if (immediate)
292 dbg_printf("[%s, #%d]", tbl_regs[get_nibble(inst, 4)], offset);
293 else if (((inst >> 4) & 0xff) == 0x00) /* no shift */
294 dbg_printf("[%s, %s]", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
295 else if (((inst >> 4) & 0x01) == 0x00) /* immediate shift (there's no register shift) */
296 dbg_printf("[%s, %s, %s #%d]", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)],
297 tbl_shifts[(inst >> 5) & 0x03], (inst >> 7) & 0x1f);
298 else
299 return inst;
301 else
303 if (immediate)
304 dbg_printf("[%s], #%d", tbl_regs[get_nibble(inst, 4)], offset);
305 else if (((inst >> 4) & 0xff) == 0x00) /* no shift */
306 dbg_printf("[%s], %s", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
307 else if (((inst >> 4) & 0x01) == 0x00) /* immediate shift (there's no register shift) */
308 dbg_printf("[%s], %s, %s #%d", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)],
309 tbl_shifts[(inst >> 5) & 0x03], (inst >> 7) & 0x1f);
310 else
311 return inst;
313 return 0;
316 static UINT arm_disasm_halfwordtrans(UINT inst, ADDRESS64 *addr)
318 short halfword = (inst >> 5) & 0x01;
319 short sign = (inst >> 6) & 0x01;
320 short load = (inst >> 20) & 0x01;
321 short writeback = (inst >> 21) & 0x01;
322 short immediate = (inst >> 22) & 0x01;
323 short direction = (inst >> 23) & 0x01;
324 short indexing = (inst >> 24) & 0x01;
325 short offset = ((inst >> 4) & 0xf0) + (inst & 0x0f);
327 if (!direction) offset *= -1;
329 dbg_printf("\n\t%s%s%s%s%s", load ? "ldr" : "str", sign ? "s" : "",
330 halfword ? "h" : (sign ? "b" : ""), writeback ? "t" : "", get_cond(inst));
331 dbg_printf("\t%s, ", tbl_regs[get_nibble(inst, 3)]);
332 if (indexing)
334 if (immediate)
335 dbg_printf("[%s, #%d]", tbl_regs[get_nibble(inst, 4)], offset);
336 else
337 dbg_printf("[%s, %s]", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
339 else
341 if (immediate)
342 dbg_printf("[%s], #%d", tbl_regs[get_nibble(inst, 4)], offset);
343 else
344 dbg_printf("[%s], %s", tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
346 return 0;
349 static UINT arm_disasm_blocktrans(UINT inst, ADDRESS64 *addr)
351 short load = (inst >> 20) & 0x01;
352 short writeback = (inst >> 21) & 0x01;
353 short psr = (inst >> 22) & 0x01;
354 short addrmode = (inst >> 23) & 0x03;
355 short i;
356 short last=15;
357 for (i=15;i>=0;i--)
358 if ((inst>>i) & 1)
360 last = i;
361 break;
364 dbg_printf("\n\t%s%s%s\t%s%s, {", load ? "ldm" : "stm", tbl_addrmode[addrmode], get_cond(inst),
365 tbl_regs[get_nibble(inst, 4)], writeback ? "!" : "");
366 for (i=0;i<=15;i++)
367 if ((inst>>i) & 1)
369 if (i == last) dbg_printf("%s", tbl_regs[i]);
370 else dbg_printf("%s, ", tbl_regs[i]);
372 dbg_printf("}%s", psr ? "^" : "");
373 return 0;
376 static UINT arm_disasm_swi(UINT inst, ADDRESS64 *addr)
378 UINT comment = inst & 0x00ffffff;
379 dbg_printf("\n\tswi%s\t#%d", get_cond(inst), comment);
380 return 0;
383 static UINT arm_disasm_coproctrans(UINT inst, ADDRESS64 *addr)
385 WORD CRm = inst & 0x0f;
386 WORD CP = (inst >> 5) & 0x07;
387 WORD CPnum = (inst >> 8) & 0x0f;
388 WORD CRn = (inst >> 16) & 0x0f;
389 WORD load = (inst >> 20) & 0x01;
390 WORD CP_Opc = (inst >> 21) & 0x07;
392 dbg_printf("\n\t%s%s\t%u, %u, %s, cr%u, cr%u, {%u}", load ? "mrc" : "mcr", get_cond(inst), CPnum,
393 CP, tbl_regs[get_nibble(inst, 3)], CRn, CRm, CP_Opc);
394 return 0;
397 static UINT arm_disasm_coprocdataop(UINT inst, ADDRESS64 *addr)
399 WORD CRm = inst & 0x0f;
400 WORD CP = (inst >> 5) & 0x07;
401 WORD CPnum = (inst >> 8) & 0x0f;
402 WORD CRd = (inst >> 12) & 0x0f;
403 WORD CRn = (inst >> 16) & 0x0f;
404 WORD CP_Opc = (inst >> 20) & 0x0f;
406 dbg_printf("\n\tcdp%s\t%u, %u, cr%u, cr%u, cr%u, {%u}", get_cond(inst),
407 CPnum, CP, CRd, CRn, CRm, CP_Opc);
408 return 0;
411 static UINT arm_disasm_coprocdatatrans(UINT inst, ADDRESS64 *addr)
413 WORD CPnum = (inst >> 8) & 0x0f;
414 WORD CRd = (inst >> 12) & 0x0f;
415 WORD load = (inst >> 20) & 0x01;
416 WORD writeback = (inst >> 21) & 0x01;
417 WORD translen = (inst >> 22) & 0x01;
418 WORD direction = (inst >> 23) & 0x01;
419 WORD indexing = (inst >> 24) & 0x01;
420 short offset = (inst & 0xff) << 2;
422 if (!direction) offset *= -1;
424 dbg_printf("\n\t%s%s%s", load ? "ldc" : "stc", translen ? "l" : "", get_cond(inst));
425 if (indexing)
426 dbg_printf("\t%u, cr%u, [%s, #%d]%s", CPnum, CRd, tbl_regs[get_nibble(inst, 4)], offset, writeback?"!":"");
427 else
428 dbg_printf("\t%u, cr%u, [%s], #%d", CPnum, CRd, tbl_regs[get_nibble(inst, 4)], offset);
429 return 0;
432 static WORD thumb_disasm_hireg(WORD inst, ADDRESS64 *addr)
434 short dst = inst & 0x07;
435 short src = (inst >> 3) & 0x07;
436 short h2 = (inst >> 6) & 0x01;
437 short h1 = (inst >> 7) & 0x01;
438 short op = (inst >> 8) & 0x03;
440 if (h1) dst += 8;
441 if (h2) src += 8;
443 if (op == 2 && dst == src) /* mov rx, rx */
445 dbg_printf("\n\tnop");
446 return 0;
449 if (op == 3)
450 dbg_printf("\n\tb%sx\t%s", h1?"l":"", tbl_regs[src]);
451 else
452 dbg_printf("\n\t%s\t%s, %s", tbl_hiops_t[op], tbl_regs[dst], tbl_regs[src]);
454 return 0;
457 static WORD thumb_disasm_aluop(WORD inst, ADDRESS64 *addr)
459 short dst = inst & 0x07;
460 short src = (inst >> 3) & 0x07;
461 short op = (inst >> 6) & 0x0f;
463 dbg_printf("\n\t%s\t%s, %s", tbl_aluops_t[op], tbl_regs[dst], tbl_regs[src]);
465 return 0;
468 static WORD thumb_disasm_pushpop(WORD inst, ADDRESS64 *addr)
470 short lrpc = (inst >> 8) & 0x01;
471 short load = (inst >> 11) & 0x01;
472 short i;
473 short last;
475 for (i=7;i>=0;i--)
476 if ((inst>>i) & 1) break;
477 last = i;
479 dbg_printf("\n\t%s\t{", load ? "pop" : "push");
481 for (i=0;i<=7;i++)
482 if ((inst>>i) & 1)
484 if (i == last) dbg_printf("%s", tbl_regs[i]);
485 else dbg_printf("%s, ", tbl_regs[i]);
487 if (lrpc)
488 dbg_printf("%s%s", last ? ", " : "", load ? "pc" : "lr");
490 dbg_printf("}");
491 return 0;
494 static WORD thumb_disasm_blocktrans(WORD inst, ADDRESS64 *addr)
496 short load = (inst >> 11) & 0x01;
497 short i;
498 short last;
500 for (i=7;i>=0;i--)
501 if ((inst>>i) & 1) break;
502 last = i;
504 dbg_printf("\n\t%s\t%s!, {", load ? "ldmia" : "stmia", tbl_regs[(inst >> 8) & 0x07]);
506 for (i=0;i<=7;i++)
507 if ((inst>>i) & 1)
509 if (i == last) dbg_printf("%s", tbl_regs[i]);
510 else dbg_printf("%s, ", tbl_regs[i]);
513 dbg_printf("}");
514 return 0;
517 static WORD thumb_disasm_condbranch(WORD inst, ADDRESS64 *addr)
519 WORD offset = inst & 0x00ff;
520 dbg_printf("\n\tb%s\t", tbl_cond[(inst >> 8) & 0x0f]);
521 db_printsym(addr->Offset + offset);
522 return 0;
525 static WORD thumb_disasm_uncondbranch(WORD inst, ADDRESS64 *addr)
527 short offset = (inst & 0x07ff) << 1;
529 if (offset & 0x0800) offset |= 0xf000;
530 offset += 4;
532 dbg_printf("\n\tb\t");
533 db_printsym(addr->Offset + offset);
534 return 0;
537 static WORD thumb_disasm_loadadr(WORD inst, ADDRESS64 *addr)
539 WORD src = (inst >> 11) & 0x01;
540 WORD offset = (inst & 0xff) << 2;
542 dbg_printf("\n\tadd\t%s, %s, #%d", tbl_regs[(inst >> 8) & 0x07], src ? "sp" : "pc", offset);
543 return 0;
546 static WORD thumb_disasm_swi(WORD inst, ADDRESS64 *addr)
548 WORD comment = inst & 0x00ff;
549 dbg_printf("\n\tswi\t#%d", comment);
550 return 0;
553 static WORD thumb_disasm_nop(WORD inst, ADDRESS64 *addr)
555 dbg_printf("\n\tnop");
556 return 0;
559 static WORD thumb_disasm_ldrpcrel(WORD inst, ADDRESS64 *addr)
561 WORD offset = (inst & 0xff) << 2;
562 dbg_printf("\n\tldr\t%s, [pc, #%u]", tbl_regs[(inst >> 8) & 0x07], offset);
563 return 0;
566 static WORD thumb_disasm_ldrsprel(WORD inst, ADDRESS64 *addr)
568 WORD offset = (inst & 0xff) << 2;
569 dbg_printf("\n\t%s\t%s, [sp, #%u]", (inst & 0x0800)?"ldr":"str", tbl_regs[(inst >> 8) & 0x07], offset);
570 return 0;
573 static WORD thumb_disasm_addsprel(WORD inst, ADDRESS64 *addr)
575 WORD offset = (inst & 0x7f) << 2;
576 if ((inst >> 7) & 0x01)
577 dbg_printf("\n\tsub\tsp, sp, #%u", offset);
578 else
579 dbg_printf("\n\tadd\tsp, sp, #%u", offset);
580 return 0;
583 static WORD thumb_disasm_ldrimm(WORD inst, ADDRESS64 *addr)
585 WORD offset = (inst & 0x07c0) >> 6;
586 dbg_printf("\n\t%s%s\t%s, [%s, #%u]", (inst & 0x0800)?"ldr":"str", (inst & 0x1000)?"b":"",
587 tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07], (inst & 0x1000)?offset:(offset << 2));
588 return 0;
591 static WORD thumb_disasm_ldrhimm(WORD inst, ADDRESS64 *addr)
593 WORD offset = (inst & 0x07c0) >> 5;
594 dbg_printf("\n\t%s\t%s, [%s, #%u]", (inst & 0x0800)?"ldrh":"strh",
595 tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07], offset);
596 return 0;
599 static WORD thumb_disasm_ldrreg(WORD inst, ADDRESS64 *addr)
601 dbg_printf("\n\t%s%s\t%s, [%s, %s]", (inst & 0x0800)?"ldr":"str", (inst & 0x0400)?"b":"",
602 tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07], tbl_regs[(inst >> 6) & 0x07]);
603 return 0;
606 static WORD thumb_disasm_ldrsreg(WORD inst, ADDRESS64 *addr)
608 dbg_printf("\n\t%s\t%s, [%s, %s]", tbl_sregops_t[(inst >> 10) & 0x03],
609 tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07], tbl_regs[(inst >> 6) & 0x07]);
610 return 0;
613 static WORD thumb_disasm_immop(WORD inst, ADDRESS64 *addr)
615 WORD op = (inst >> 11) & 0x03;
616 dbg_printf("\n\t%s\t%s, #%u", tbl_immops_t[op], tbl_regs[(inst >> 8) & 0x07], inst & 0xff);
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_branch(UINT inst, ADDRESS64 *addr)
644 UINT S = (inst >> 26) & 0x01;
645 UINT L = (inst >> 14) & 0x01;
646 UINT I1 = !(((inst >> 13) & 0x01) ^ S);
647 UINT C = !((inst >> 12) & 0x01);
648 UINT I2 = !(((inst >> 11) & 0x01) ^ S);
649 UINT offset = (inst & 0x000007ff) << 1;
651 if (C)
653 offset |= I1 << 19 | I2 << 18 | (inst & 0x003f0000) >> 4;
654 offset += 4;
655 if (S) offset |= 0x0fff << 20;
657 else
659 offset |= I1 << 23 | I2 << 22 | (inst & 0x03ff0000) >> 4;
660 offset += 4;
661 if (S) offset |= 0xff << 24;
664 dbg_printf("\n\tb%s%s\t", L ? "l" : "", C ? tbl_cond[(inst >> 22) & 0x0f] : "");
665 db_printsym(addr->Offset + offset);
666 return 0;
669 static UINT thumb2_disasm_srtrans(UINT inst, ADDRESS64 *addr)
671 UINT fromsr = (inst >> 21) & 0x03;
672 UINT sysreg = inst & 0xff;
674 if (fromsr == 3 && get_nibble(inst,4) == 0x0f && sysreg <= 20)
676 dbg_printf("\n\tmrs\t%s, %s", tbl_regs[get_nibble(inst, 2)], tbl_special_regs_t2[sysreg]);
677 return 0;
680 if (fromsr == 0 && sysreg <= 20)
682 dbg_printf("\n\tmsr\t%s, %s", tbl_special_regs_t2[sysreg], tbl_regs[get_nibble(inst, 4)]);
683 return 0;
686 return inst;
689 static UINT thumb2_disasm_misc(UINT inst, ADDRESS64 *addr)
691 WORD op1 = (inst >> 20) & 0x03;
692 WORD op2 = (inst >> 4) & 0x03;
694 if (get_nibble(inst, 4) != get_nibble(inst, 0))
695 return inst;
697 if (op1 == 3 && op2 == 0)
699 dbg_printf("\n\tclz\t%s, %s", tbl_regs[get_nibble(inst, 2)], tbl_regs[get_nibble(inst, 0)]);
700 return 0;
703 if (op1 == 1)
705 dbg_printf("\n\t%s\t%s, %s", tbl_miscops_t2[op2], tbl_regs[get_nibble(inst, 2)],
706 tbl_regs[get_nibble(inst, 0)]);
707 return 0;
710 return inst;
713 static UINT thumb2_disasm_dataprocessingreg(UINT inst, ADDRESS64 *addr)
715 WORD op1 = (inst >> 20) & 0x07;
716 WORD op2 = (inst >> 4) & 0x0f;
718 if (!op2)
720 dbg_printf("\n\t%s%s\t%s, %s, %s", tbl_shifts[op1 >> 1], (op1 & 1)?"s":"",
721 tbl_regs[get_nibble(inst, 2)], tbl_regs[get_nibble(inst, 4)],
722 tbl_regs[get_nibble(inst, 0)]);
723 return 0;
726 if ((op2 & 0x0C) == 0x08 && get_nibble(inst, 4) == 0x0f)
728 dbg_printf("\n\t%sxt%s\t%s, %s", (op1 & 1)?"u":"s", (op1 & 4)?"b":"h",
729 tbl_regs[get_nibble(inst, 2)], tbl_regs[get_nibble(inst, 0)]);
730 if (op2 & 0x03)
731 dbg_printf(", ROR #%u", (op2 & 3) * 8);
732 return 0;
735 return inst;
738 static UINT thumb2_disasm_mul(UINT inst, ADDRESS64 *addr)
740 WORD op1 = (inst >> 20) & 0x07;
741 WORD op2 = (inst >> 4) & 0x03;
743 if (op1)
744 return inst;
746 if (op2 == 0 && get_nibble(inst, 3) != 0xf)
748 dbg_printf("\n\tmla\t%s, %s, %s, %s", tbl_regs[get_nibble(inst, 2)],
749 tbl_regs[get_nibble(inst, 4)],
750 tbl_regs[get_nibble(inst, 0)],
751 tbl_regs[get_nibble(inst, 3)]);
752 return 0;
755 if (op2 == 0 && get_nibble(inst, 3) == 0xf)
757 dbg_printf("\n\tmul\t%s, %s, %s", tbl_regs[get_nibble(inst, 2)],
758 tbl_regs[get_nibble(inst, 4)],
759 tbl_regs[get_nibble(inst, 0)]);
760 return 0;
763 if (op2 == 1)
765 dbg_printf("\n\tmls\t%s, %s, %s, %s", tbl_regs[get_nibble(inst, 2)],
766 tbl_regs[get_nibble(inst, 4)],
767 tbl_regs[get_nibble(inst, 0)],
768 tbl_regs[get_nibble(inst, 3)]);
769 return 0;
772 return inst;
775 static UINT thumb2_disasm_longmuldiv(UINT inst, ADDRESS64 *addr)
777 WORD op1 = (inst >> 20) & 0x07;
778 WORD op2 = (inst >> 4) & 0x0f;
780 if (op2 == 0)
782 switch (op1)
784 case 0:
785 dbg_printf("\n\tsmull\t");
786 break;
787 case 2:
788 dbg_printf("\n\tumull\t");
789 break;
790 case 4:
791 dbg_printf("\n\tsmlal\t");
792 break;
793 case 6:
794 dbg_printf("\n\tumlal\t");
795 break;
796 default:
797 return inst;
799 dbg_printf("%s, %s, %s, %s", tbl_regs[get_nibble(inst, 3)], tbl_regs[get_nibble(inst, 2)],
800 tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]);
801 return 0;
804 if (op2 == 0xffff)
806 switch (op1)
808 case 1:
809 dbg_printf("\n\tsdiv\t");
810 break;
811 case 3:
812 dbg_printf("\n\tudiv\t");
813 break;
814 default:
815 return inst;
817 dbg_printf("%s, %s, %s", tbl_regs[get_nibble(inst, 2)], tbl_regs[get_nibble(inst, 4)],
818 tbl_regs[get_nibble(inst, 0)]);
819 return 0;
822 return inst;
825 static UINT thumb2_disasm_str(UINT inst, ADDRESS64 *addr)
827 WORD op1 = (inst >> 21) & 0x07;
828 WORD op2 = (inst >> 6) & 0x3f;
830 if ((op1 & 0x03) == 3) return inst;
832 if (!(op1 & 0x04) && inst & 0x0800)
834 int offset;
835 dbg_printf("\n\tstr%s\t%s, [%s", tbl_width_t2[op1 & 0x03], tbl_regs[get_nibble(inst, 3)],
836 tbl_regs[get_nibble(inst, 4)]);
838 offset = inst & 0xff;
839 if (!(inst & 0x0200)) offset *= -1;
841 if (!(inst & 0x0400) && (inst & 0x0100)) dbg_printf("], #%i", offset);
842 else if (inst & 0x0400) dbg_printf(", #%i]%s", offset, (inst & 0x0100)?"!":"");
843 else return inst;
844 return 0;
847 if (!(op1 & 0x04) && !op2)
849 dbg_printf("\n\tstr%s\t%s, [%s, %s, LSL #%u]", tbl_width_t2[op1 & 0x03],
850 tbl_regs[get_nibble(inst, 3)], tbl_regs[get_nibble(inst, 4)],
851 tbl_regs[get_nibble(inst, 0)], (inst >> 4) & 0x3);
852 return 0;
855 if (op1 & 0x04)
857 dbg_printf("\n\tstr%s\t%s, [%s, #%u]", tbl_width_t2[op1 & 0x03],
858 tbl_regs[get_nibble(inst, 3)], tbl_regs[get_nibble(inst, 4)], inst & 0x0fff);
859 return 0;
862 return inst;
865 static UINT thumb2_disasm_ldrword(UINT inst, ADDRESS64 *addr)
867 WORD op1 = (inst >> 23) & 0x01;
868 WORD op2 = (inst >> 6) & 0x3f;
869 int offset;
871 if (get_nibble(inst, 4) == 0x0f)
873 offset = inst & 0x0fff;
875 if (!op1) offset *= -1;
876 offset += 3;
878 dbg_printf("\n\tldr\t%s, ", tbl_regs[get_nibble(inst, 3)]);
879 db_printsym(addr->Offset + offset);
880 return 0;
883 if (!op1 && !op2)
885 dbg_printf("\n\tldr\t%s, [%s, %s, LSL #%u]", tbl_regs[get_nibble(inst, 3)],
886 tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)], (inst >> 4) & 0x3);
887 return 0;
890 if (!op1 && (op2 & 0x3c) == 0x38)
892 dbg_printf("\n\tldrt\t%s, [%s, #%u]", tbl_regs[get_nibble(inst, 3)],
893 tbl_regs[get_nibble(inst, 4)], inst & 0xff);
894 return 0;
897 dbg_printf("\n\tldr\t%s, [%s", tbl_regs[get_nibble(inst, 3)], tbl_regs[get_nibble(inst, 4)]);
899 if (op1)
901 dbg_printf(", #%u]", inst & 0x0fff);
902 return 0;
905 offset = inst & 0xff;
906 if (!(inst & 0x0200)) offset *= -1;
908 if (!(inst & 0x0400) && (inst & 0x0100)) dbg_printf("], #%i", offset);
909 else if (inst & 0x0400) dbg_printf(", #%i]%s", offset, (inst & 0x0100)?"!":"");
910 else return inst;
912 return 0;
915 static UINT thumb2_disasm_coprocmov1(UINT inst, ADDRESS64 *addr)
917 WORD opc1 = (inst >> 21) & 0x07;
918 WORD opc2 = (inst >> 5) & 0x07;
920 if (opc2)
921 dbg_printf("\n\t%s%s\tp%u, #%u, %s, cr%u, cr%u, #%u", (inst & 0x00100000)?"mrc":"mcr",
922 (inst & 0x10000000)?"2":"", get_nibble(inst, 2), opc1,
923 tbl_regs[get_nibble(inst, 3)], get_nibble(inst, 4), get_nibble(inst, 0), opc2);
924 else
925 dbg_printf("\n\t%s%s\tp%u, #%u, %s, cr%u, cr%u", (inst & 0x00100000)?"mrc":"mcr",
926 (inst & 0x10000000)?"2":"", get_nibble(inst, 2), opc1,
927 tbl_regs[get_nibble(inst, 3)], get_nibble(inst, 4), get_nibble(inst, 0));
929 return 0;
932 struct inst_arm
934 UINT mask;
935 UINT pattern;
936 UINT (*func)(UINT, ADDRESS64*);
939 static const struct inst_arm tbl_arm[] = {
940 { 0x0e000000, 0x0a000000, arm_disasm_branch },
941 { 0x0fc000f0, 0x00000090, arm_disasm_mul },
942 { 0x0f8000f0, 0x00800090, arm_disasm_longmul },
943 { 0x0fb00ff0, 0x01000090, arm_disasm_swp },
944 { 0x0e000090, 0x00000090, arm_disasm_halfwordtrans },
945 { 0x0ffffff0, 0x012fff00, arm_disasm_branchreg },
946 { 0x0ffffff0, 0x012fff10, arm_disasm_branchxchg },
947 { 0x0fbf0fff, 0x010f0000, arm_disasm_mrstrans },
948 { 0x0dbef000, 0x0128f000, arm_disasm_msrtrans },
949 { 0x0fb00000, 0x03000000, arm_disasm_wordmov },
950 { 0x0fffffff, 0x0320f000, arm_disasm_nop },
951 { 0x0c000000, 0x00000000, arm_disasm_dataprocessing },
952 { 0x0c000000, 0x04000000, arm_disasm_singletrans },
953 { 0x0e000000, 0x08000000, arm_disasm_blocktrans },
954 { 0x0f000000, 0x0f000000, arm_disasm_swi },
955 { 0x0f000010, 0x0e000010, arm_disasm_coproctrans },
956 { 0x0f000010, 0x0e000000, arm_disasm_coprocdataop },
957 { 0x0e000000, 0x0c000000, arm_disasm_coprocdatatrans },
958 { 0x00000000, 0x00000000, NULL }
961 struct inst_thumb16
963 WORD mask;
964 WORD pattern;
965 WORD (*func)(WORD, ADDRESS64*);
968 static const struct inst_thumb16 tbl_thumb16[] = {
969 { 0xfc00, 0x4400, thumb_disasm_hireg },
970 { 0xfc00, 0x4000, thumb_disasm_aluop },
971 { 0xf600, 0xb400, thumb_disasm_pushpop },
972 { 0xf000, 0xc000, thumb_disasm_blocktrans },
973 { 0xf000, 0xd000, thumb_disasm_condbranch },
974 { 0xf800, 0xe000, thumb_disasm_uncondbranch },
975 { 0xf000, 0xa000, thumb_disasm_loadadr },
976 { 0xf800, 0x4800, thumb_disasm_ldrpcrel },
977 { 0xf000, 0x9000, thumb_disasm_ldrsprel },
978 { 0xff00, 0xb000, thumb_disasm_addsprel },
979 { 0xe000, 0x6000, thumb_disasm_ldrimm },
980 { 0xf000, 0x8000, thumb_disasm_ldrhimm },
981 { 0xf200, 0x5000, thumb_disasm_ldrreg },
982 { 0xf200, 0x5200, thumb_disasm_ldrsreg },
983 { 0xe000, 0x2000, thumb_disasm_immop },
984 { 0xff00, 0xdf00, thumb_disasm_swi },
985 { 0xff00, 0xbf00, thumb_disasm_nop },
986 { 0xf800, 0x1800, thumb_disasm_addsub },
987 { 0xe000, 0x0000, thumb_disasm_movshift },
988 { 0x0000, 0x0000, NULL }
991 static const struct inst_arm tbl_thumb32[] = {
992 { 0xf800f000, 0xf0008000, thumb2_disasm_branch },
993 { 0xff90f000, 0xf3808000, thumb2_disasm_srtrans },
994 { 0xffc0f0c0, 0xfa80f080, thumb2_disasm_misc },
995 { 0xff80f000, 0xfa00f000, thumb2_disasm_dataprocessingreg },
996 { 0xff8000c0, 0xfb000000, thumb2_disasm_mul },
997 { 0xff8000f0, 0xfb800000, thumb2_disasm_longmuldiv },
998 { 0xff8000f0, 0xfb8000f0, thumb2_disasm_longmuldiv },
999 { 0xff100000, 0xf8000000, thumb2_disasm_str },
1000 { 0xff700000, 0xf8500000, thumb2_disasm_ldrword },
1001 { 0xef000010, 0xee000010, thumb2_disasm_coprocmov1 },
1002 { 0x00000000, 0x00000000, NULL }
1005 /***********************************************************************
1006 * disasm_one_insn
1008 * Disassemble instruction at 'addr'. addr is changed to point to the
1009 * start of the next instruction.
1011 void be_arm_disasm_one_insn(ADDRESS64 *addr, int display)
1013 struct inst_arm *a_ptr = (struct inst_arm *)&tbl_arm;
1014 struct inst_thumb16 *t_ptr = (struct inst_thumb16 *)&tbl_thumb16;
1015 struct inst_arm *t2_ptr = (struct inst_arm *)&tbl_thumb32;
1016 UINT inst;
1017 WORD tinst;
1018 int size;
1019 int matched = 0;
1021 char tmp[64];
1022 DWORD_PTR* pval;
1024 if (!memory_get_register(CV_ARM_CPSR, &pval, tmp, sizeof(tmp)))
1025 dbg_printf("\n\tmemory_get_register failed: %s", tmp);
1026 else
1027 db_disasm_thumb = (*pval & 0x20) != 0;
1029 db_display = display;
1031 if (!db_disasm_thumb)
1033 size = ARM_INSN_SIZE;
1034 inst = db_get_inst( memory_to_linear_addr(addr), size );
1035 while (a_ptr->func) {
1036 if ((inst & a_ptr->mask) == a_ptr->pattern) {
1037 matched = 1;
1038 break;
1040 a_ptr++;
1043 if (!matched) {
1044 dbg_printf("\n\tUnknown ARM Instruction: %08x", inst);
1045 addr->Offset += size;
1047 else
1049 if (!a_ptr->func(inst, addr))
1050 addr->Offset += size;
1052 return;
1054 else
1056 WORD *taddr = memory_to_linear_addr(addr);
1057 tinst = db_get_inst( taddr, THUMB_INSN_SIZE );
1058 switch (tinst & 0xf800)
1060 case 0xe800:
1061 case 0xf000:
1062 case 0xf800:
1063 size = THUMB2_INSN_SIZE;
1064 taddr++;
1065 inst = db_get_inst( taddr, THUMB_INSN_SIZE );
1066 inst |= (tinst << 16);
1068 while (t2_ptr->func) {
1069 if ((inst & t2_ptr->mask) == t2_ptr->pattern) {
1070 matched = 1;
1071 break;
1073 t2_ptr++;
1076 if (!matched) {
1077 dbg_printf("\n\tUnknown Thumb2 Instruction: %08x", inst);
1078 addr->Offset += size;
1080 else
1082 if (!t2_ptr->func(inst, addr))
1083 addr->Offset += size;
1085 return;
1086 default:
1087 break;
1090 size = THUMB_INSN_SIZE;
1091 while (t_ptr->func) {
1092 if ((tinst & t_ptr->mask) == t_ptr->pattern) {
1093 matched = 1;
1094 break;
1096 t_ptr++;
1099 if (!matched) {
1100 dbg_printf("\n\tUnknown Thumb Instruction: %04x", tinst);
1101 addr->Offset += size;
1103 else
1105 if (!t_ptr->func(tinst, addr))
1106 addr->Offset += size;
1108 return;
1112 static unsigned be_arm_get_addr(HANDLE hThread, const CONTEXT* ctx,
1113 enum be_cpu_addr bca, ADDRESS64* addr)
1115 switch (bca)
1117 case be_cpu_addr_pc:
1118 return be_cpu_build_addr(hThread, ctx, addr, 0, ctx->Pc);
1119 case be_cpu_addr_stack:
1120 return be_cpu_build_addr(hThread, ctx, addr, 0, ctx->Sp);
1121 case be_cpu_addr_frame:
1122 return be_cpu_build_addr(hThread, ctx, addr, 0, ctx->Fp);
1124 return FALSE;
1127 static unsigned be_arm_get_register_info(int regno, enum be_cpu_addr* kind)
1129 switch (regno)
1131 case CV_ARM_PC: *kind = be_cpu_addr_pc; return TRUE;
1132 case CV_ARM_R0 + 11: *kind = be_cpu_addr_frame; return TRUE;
1133 case CV_ARM_SP: *kind = be_cpu_addr_stack; return TRUE;
1135 return FALSE;
1138 static void be_arm_single_step(CONTEXT* ctx, unsigned enable)
1140 dbg_printf("be_arm_single_step: not done\n");
1143 static void be_arm_print_context(HANDLE hThread, const CONTEXT* ctx, int all_regs)
1145 static const char condflags[] = "NZCV";
1146 int i;
1147 char buf[8];
1149 switch (ctx->Cpsr & 0x1F)
1151 case 0: strcpy(buf, "User26"); break;
1152 case 1: strcpy(buf, "FIQ26"); break;
1153 case 2: strcpy(buf, "IRQ26"); break;
1154 case 3: strcpy(buf, "SVC26"); break;
1155 case 16: strcpy(buf, "User"); break;
1156 case 17: strcpy(buf, "FIQ"); break;
1157 case 18: strcpy(buf, "IRQ"); break;
1158 case 19: strcpy(buf, "SVC"); break;
1159 case 23: strcpy(buf, "ABT"); break;
1160 case 27: strcpy(buf, "UND"); break;
1161 default: strcpy(buf, "UNKNWN"); break;
1164 dbg_printf("Register dump:\n");
1165 dbg_printf("%s %s Mode\n", (ctx->Cpsr & 0x20) ? "Thumb" : "ARM", buf);
1167 strcpy(buf, condflags);
1168 for (i = 0; buf[i]; i++)
1169 if (!((ctx->Cpsr >> 26) & (1 << (sizeof(condflags) - i))))
1170 buf[i] = '-';
1172 dbg_printf(" Pc:%04x Sp:%04x Lr:%04x Cpsr:%04x(%s)\n",
1173 ctx->Pc, ctx->Sp, ctx->Lr, ctx->Cpsr, buf);
1174 dbg_printf(" r0:%04x r1:%04x r2:%04x r3:%04x\n",
1175 ctx->R0, ctx->R1, ctx->R2, ctx->R3);
1176 dbg_printf(" r4:%04x r5:%04x r6:%04x r7:%04x r8:%04x\n",
1177 ctx->R4, ctx->R5, ctx->R6, ctx->R7, ctx->R8 );
1178 dbg_printf(" r9:%04x r10:%04x Fp:%04x Ip:%04x\n",
1179 ctx->R9, ctx->R10, ctx->Fp, ctx->Ip );
1181 if (all_regs) dbg_printf( "Floating point ARM dump not implemented\n" );
1184 static void be_arm_print_segment_info(HANDLE hThread, const CONTEXT* ctx)
1188 static struct dbg_internal_var be_arm_ctx[] =
1190 {CV_ARM_R0 + 0, "r0", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R0), dbg_itype_unsigned_int},
1191 {CV_ARM_R0 + 1, "r1", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R1), dbg_itype_unsigned_int},
1192 {CV_ARM_R0 + 2, "r2", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R2), dbg_itype_unsigned_int},
1193 {CV_ARM_R0 + 3, "r3", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R3), dbg_itype_unsigned_int},
1194 {CV_ARM_R0 + 4, "r4", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R4), dbg_itype_unsigned_int},
1195 {CV_ARM_R0 + 5, "r5", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R5), dbg_itype_unsigned_int},
1196 {CV_ARM_R0 + 6, "r6", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R6), dbg_itype_unsigned_int},
1197 {CV_ARM_R0 + 7, "r7", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R7), dbg_itype_unsigned_int},
1198 {CV_ARM_R0 + 8, "r8", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R8), dbg_itype_unsigned_int},
1199 {CV_ARM_R0 + 9, "r9", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R9), dbg_itype_unsigned_int},
1200 {CV_ARM_R0 + 10, "r10", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R10), dbg_itype_unsigned_int},
1201 {CV_ARM_R0 + 11, "r11", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Fp), dbg_itype_unsigned_int},
1202 {CV_ARM_R0 + 12, "r12", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Ip), dbg_itype_unsigned_int},
1203 {CV_ARM_SP, "sp", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Sp), dbg_itype_unsigned_int},
1204 {CV_ARM_LR, "lr", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Lr), dbg_itype_unsigned_int},
1205 {CV_ARM_PC, "pc", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Pc), dbg_itype_unsigned_int},
1206 {CV_ARM_CPSR, "cpsr", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Cpsr), dbg_itype_unsigned_int},
1207 {0, NULL, 0, dbg_itype_none}
1210 static unsigned be_arm_is_step_over_insn(const void* insn)
1212 dbg_printf("be_arm_is_step_over_insn: not done\n");
1213 return FALSE;
1216 static unsigned be_arm_is_function_return(const void* insn)
1218 dbg_printf("be_arm_is_function_return: not done\n");
1219 return FALSE;
1222 static unsigned be_arm_is_break_insn(const void* insn)
1224 dbg_printf("be_arm_is_break_insn: not done\n");
1225 return FALSE;
1228 static unsigned be_arm_is_func_call(const void* insn, ADDRESS64* callee)
1230 return FALSE;
1233 static unsigned be_arm_is_jump(const void* insn, ADDRESS64* jumpee)
1235 return FALSE;
1238 static unsigned be_arm_insert_Xpoint(HANDLE hProcess, const struct be_process_io* pio,
1239 CONTEXT* ctx, enum be_xpoint_type type,
1240 void* addr, unsigned long* val, unsigned size)
1242 SIZE_T sz;
1244 switch (type)
1246 case be_xpoint_break:
1247 if (!size) return 0;
1248 if (!pio->read(hProcess, addr, val, 4, &sz) || sz != 4) return 0;
1249 default:
1250 dbg_printf("Unknown/unsupported bp type %c\n", type);
1251 return 0;
1253 return 1;
1256 static unsigned be_arm_remove_Xpoint(HANDLE hProcess, const struct be_process_io* pio,
1257 CONTEXT* ctx, enum be_xpoint_type type,
1258 void* addr, unsigned long val, unsigned size)
1260 SIZE_T sz;
1262 switch (type)
1264 case be_xpoint_break:
1265 if (!size) return 0;
1266 if (!pio->write(hProcess, addr, &val, 4, &sz) || sz == 4) return 0;
1267 break;
1268 default:
1269 dbg_printf("Unknown/unsupported bp type %c\n", type);
1270 return 0;
1272 return 1;
1275 static unsigned be_arm_is_watchpoint_set(const CONTEXT* ctx, unsigned idx)
1277 dbg_printf("be_arm_is_watchpoint_set: not done\n");
1278 return FALSE;
1281 static void be_arm_clear_watchpoint(CONTEXT* ctx, unsigned idx)
1283 dbg_printf("be_arm_clear_watchpoint: not done\n");
1286 static int be_arm_adjust_pc_for_break(CONTEXT* ctx, BOOL way)
1288 INT step = (ctx->Cpsr & 0x20) ? 2 : 4;
1290 if (way)
1292 ctx->Pc -= step;
1293 return -step;
1295 ctx->Pc += step;
1296 return step;
1299 static int be_arm_fetch_integer(const struct dbg_lvalue* lvalue, unsigned size,
1300 unsigned ext_sign, LONGLONG* ret)
1302 if (size != 1 && size != 2 && size != 4 && size != 8) return FALSE;
1304 memset(ret, 0, sizeof(*ret)); /* clear unread bytes */
1305 /* FIXME: this assumes that debuggee and debugger use the same
1306 * integral representation
1308 if (!memory_read_value(lvalue, size, ret)) return FALSE;
1310 /* propagate sign information */
1311 if (ext_sign && size < 8 && (*ret >> (size * 8 - 1)) != 0)
1313 ULONGLONG neg = -1;
1314 *ret |= neg << (size * 8);
1316 return TRUE;
1319 static int be_arm_fetch_float(const struct dbg_lvalue* lvalue, unsigned size,
1320 long double* ret)
1322 char tmp[sizeof(long double)];
1324 /* FIXME: this assumes that debuggee and debugger use the same
1325 * representation for reals
1327 if (!memory_read_value(lvalue, size, tmp)) return FALSE;
1329 switch (size)
1331 case sizeof(float): *ret = *(float*)tmp; break;
1332 case sizeof(double): *ret = *(double*)tmp; break;
1333 default: return FALSE;
1335 return TRUE;
1338 static int be_arm_store_integer(const struct dbg_lvalue* lvalue, unsigned size,
1339 unsigned is_signed, LONGLONG val)
1341 /* this is simple if we're on a little endian CPU */
1342 return memory_write_value(lvalue, size, &val);
1345 struct backend_cpu be_arm =
1347 IMAGE_FILE_MACHINE_ARMNT,
1349 be_cpu_linearize,
1350 be_cpu_build_addr,
1351 be_arm_get_addr,
1352 be_arm_get_register_info,
1353 be_arm_single_step,
1354 be_arm_print_context,
1355 be_arm_print_segment_info,
1356 be_arm_ctx,
1357 be_arm_is_step_over_insn,
1358 be_arm_is_function_return,
1359 be_arm_is_break_insn,
1360 be_arm_is_func_call,
1361 be_arm_is_jump,
1362 be_arm_disasm_one_insn,
1363 be_arm_insert_Xpoint,
1364 be_arm_remove_Xpoint,
1365 be_arm_is_watchpoint_set,
1366 be_arm_clear_watchpoint,
1367 be_arm_adjust_pc_for_break,
1368 be_arm_fetch_integer,
1369 be_arm_fetch_float,
1370 be_arm_store_integer,
1372 #endif