FreeCalypso > hg > freecalypso-reveng
view arm7dis/thumbdis.c @ 103:a10acb1688e0
thumbdis: buglet in the decoding of sub-from-sp
author | Michael Spacefalcon <msokolov@ivan.Harhan.ORG> |
---|---|
date | Mon, 31 Mar 2014 01:59:28 +0000 |
parents | 78e4702884e3 |
children | c883e60df239 |
line wrap: on
line source
#include <sys/types.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <strings.h> extern char *binfilename; extern u_char *filemap; extern unsigned disasm_len, base_vma; extern unsigned get_u16(), get_u32(); extern char *regnames[16], *condition_decode[16], *shift_types[4]; static void format_1_2(word) unsigned word; { unsigned op, imm; op = (word >> 11) & 3; if (op != 3) { /* format 1 */ imm = (word >> 6) & 0x1F; if (op != 0 && imm == 0) imm = 32; printf("%s\t%s, %s, #%u\n", shift_types[op], regnames[word&7], regnames[(word>>3)&7], imm); return; } /* format 2 */ printf("%s\t%s, %s, ", word&0x200 ? "sub" : "add", regnames[word&7], regnames[(word>>3)&7]); if (word & 0x400) printf("#%u\n", (word >> 6) & 7); else printf("%s\n", regnames[(word >> 6) & 7]); } static void format_3(word) unsigned word; { static char *opctab[4] = {"mov", "cmp", "add", "sub"}; unsigned imm; imm = word & 0xFF; printf("%s\t%s, #%u", opctab[(word>>11)&3], regnames[(word>>8)&7], imm); if (imm > 9) printf("\t; 0x%x", imm); putchar('\n'); } static void format_4(word) unsigned word; { static char *opc[16] = {"and", "eor", "lsl", "lsr", "asr", "adc", "sbc", "ror", "tst", "neg", "cmp", "cmn", "orr", "mul", "bic", "mvn"}; printf("%s\t%s, %s\n", opc[(word>>6)&0xF], regnames[word&7], regnames[(word>>3)&7]); } static void format_5_bx(word) unsigned word; { if (word & 0x80) printf("<invalid: blx instead of bx>\n"); else printf("bx\t%s\n", regnames[(word>>3)&0xF]); } static void format_5_hiops(word) unsigned word; { static char *opctab[3] = {"add", "cmp", "mov"}; int reg1, reg2, op; if (word & 0xC0) { reg1 = word & 7; if (word & 0x80) reg1 += 8; reg2 = (word >> 3) & 0xF; op = (word >> 8) & 3; if (op == 2 && reg1 == reg2 && reg1 != 15) printf("nop\t\t\t(mov %s, %s)\n", regnames[reg1], regnames[reg2]); else printf("%s\t%s, %s\n", opctab[op], regnames[reg1], regnames[reg2]); } else printf("<invalid: hi-reg format with both low regs>\n"); } static void format_5(word) unsigned word; { if ((word & 0x300) == 0x300) format_5_bx(word); else format_5_hiops(word); } static void format_6(off, word) unsigned off, word; { unsigned loff, litoff; loff = (word & 0xFF) << 2; off &= ~3; off += 4; litoff = off + loff; if (litoff+4 <= disasm_len) printf("ldr\t%s, =0x%x\t; via 0x%x\n", regnames[(word>>8)&7], get_u32(filemap + litoff), base_vma + litoff); else printf("ldr\t%s, [pc, #%u]\t(0x%x)\n", regnames[(word>>8)&7], loff, base_vma + litoff); } static void format_7(word) unsigned word; { printf("%s%s\t%s, [%s, %s]\n", word&0x800 ? "ldr" : "str", word&0x400 ? "b" : "", regnames[word&7], regnames[(word>>3)&7], regnames[(word>>6)&7]); } static void format_8(word) unsigned word; { static char *opc[4] = {"strh", "ldrsb", "ldrh", "ldrsh"}; printf("%s\t%s, [%s, %s]\n", opc[(word>>10)&3], regnames[word&7], regnames[(word>>3)&7], regnames[(word>>6)&7]); } static void format_9(word) unsigned word; { unsigned loff; loff = (word >> 6) & 0x1F; if (!(word & 0x1000)) loff <<= 2; printf("%s%s\t%s, [%s, #%u]", word&0x800 ? "ldr" : "str", word&0x1000 ? "b" : "", regnames[word&7], regnames[(word>>3)&7], loff); if (loff >= 10) printf("\t; 0x%x", loff); putchar('\n'); } static void format_10(word) unsigned word; { unsigned loff; loff = (word >> 6) & 0x1F; loff <<= 1; printf("%sh\t%s, [%s, #%u]", word&0x800 ? "ldr" : "str", regnames[word&7], regnames[(word>>3)&7], loff); if (loff >= 10) printf("\t; 0x%x", loff); putchar('\n'); } static void format_11(word) unsigned word; { unsigned loff; loff = (word & 0xFF) << 2; printf("%s\t%s, [sp, #%u]", word&0x800 ? "ldr" : "str", regnames[(word>>8)&7], loff); if (loff >= 10) printf("\t; 0x%x", loff); putchar('\n'); } static void format_12(off, word) unsigned off, word; { unsigned loff; loff = (word & 0xFF) << 2; printf("add\t%s, %s, #%u", regnames[(word>>8)&7], word&0x800 ? "sp" : "pc", loff); if (loff >= 10) printf("\t; 0x%x", loff); putchar('\n'); } static void format_13(word) unsigned word; { unsigned loff; if ((word & 0xFF00) != 0xB000) { printf("<invalid format 13>\n"); return; } loff = (word & 0x7F) << 2; printf("%s\tsp, #%u", word&0x80 ? "sub" : "add", loff); if (loff >= 10) printf("\t; 0x%x", loff); putchar('\n'); } static void format_14(word) unsigned word; { int r, flag; if ((word & 0xF600) != 0xB400) { printf("<invalid format 14>\n"); return; } printf("%s\t{", word&0x800 ? "pop" : "push"); flag = 0; for (r = 0; r < 9; r++) if (word & (1 << r)) { if (flag) fputs(", ", stdout); if (r == 8) fputs(word&0x800 ? "pc" : "lr", stdout); else fputs(regnames[r], stdout); flag = 1; } putchar('}'); putchar('\n'); } static void format_15(word) unsigned word; { int r, flag; printf("%sia\t%s!, {", word&0x800 ? "ldm" : "stm", regnames[(word>>8)&7]); flag = 0; for (r = 0; r < 8; r++) if (word & (1 << r)) { if (flag) fputs(", ", stdout); fputs(regnames[r], stdout); flag = 1; } putchar('}'); putchar('\n'); } static void format_16_17(off, word) unsigned off, word; { unsigned cond; unsigned dest; cond = (word >> 8) & 0xF; switch (cond) { case 0xE: printf("<invalid: bal>\n"); return; case 0xF: printf("swi\t0x%x\n", word & 0xFF); return; } dest = (word & 0xFF) << 1; if (dest & 0x00000100) dest |= 0xFFFFFE00; dest += base_vma + off + 4; printf("b%s\t0x%x\n", condition_decode[cond], dest); } static void format_18(off, word) unsigned off, word; { unsigned dest; if (word & 0x800) { printf("<invalid format 18>\n"); return; } dest = (word & 0x7FF) << 1; if (dest & 0x00000800) dest |= 0xFFFFF000; dest += base_vma + off + 4; printf("b\t0x%x\n", dest); } void thumb_disasm_line(off) unsigned off; { unsigned word; word = get_u16(filemap + off); printf("%8x:\t%04x\t\t", base_vma + off, word); switch (word >> 12) { case 0: case 1: format_1_2(word); return; case 2: case 3: format_3(word); return; case 4: if (word & 0x800) format_6(off, word); else if (word & 0x400) format_5(word); else format_4(word); return; case 5: if (word & 0x200) format_8(word); else format_7(word); return; case 6: case 7: format_9(word); return; case 8: format_10(word); return; case 9: format_11(word); return; case 0xA: format_12(off, word); return; case 0xB: if (word & 0x400) format_14(word); else format_13(word); return; case 0xC: format_15(word); return; case 0xD: format_16_17(off, word); return; case 0xE: format_18(off, word); return; case 0xF: printf("<half-bl>\n"); return; } } thumb_check_bl(off) unsigned off; { unsigned ins1, ins2; unsigned dest; if (off + 4 > disasm_len) return(0); ins1 = get_u16(filemap + off); if ((ins1 & 0xF800) != 0xF000) return(0); ins2 = get_u16(filemap + off + 2); if ((ins2 & 0xF800) != 0xF800) return(0); /* match */ dest = ((ins1 & 0x7FF) << 12) | ((ins2 & 0x7FF) << 1); if (dest & 0x00400000) dest |= 0xFF800000; dest += base_vma + off + 4; printf("%8x:\t%04x %04x\tbl\t0x%x\n", base_vma + off, ins1, ins2, dest); return(1); } main(argc, argv) char **argv; { unsigned off; common_init(argc, argv, 2); for (off = 0; off < disasm_len; ) { if (thumb_check_bl(off)) off += 4; else { thumb_disasm_line(off); off += 2; } } exit(0); }