FreeCalypso > hg > freecalypso-reveng
view arm7dis/armdis.c @ 91:daf69d5edb3f
armdis: ldr/str decoding implemented (but not PC-relative ldr yet)
author | Michael Spacefalcon <msokolov@ivan.Harhan.ORG> |
---|---|
date | Sun, 30 Mar 2014 00:27:25 +0000 |
parents | f68d8e7a904f |
children | 708f2452d1ae |
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]; static char *dataproc_ops[16] = {"and", "eor", "sub", "rsb", "add", "adc", "sbc", "rsc", "tst", "teq", "cmp", "cmn", "orr", "mov", "bic", "mvn"}; static char *shift_types[4] = {"lsl", "lsr", "asr", "ror"}; static void arm_branch(off, word) unsigned off, word; { unsigned dest; dest = (word & 0x00FFFFFF) << 2; if (dest & 0x02000000) dest |= 0xFC000000; dest += base_vma + off + 8; printf("b%s%s\t0x%x\n", word&0x1000000 ? "l" : "", condition_decode[word>>28], dest); } static void op2_immed(word) unsigned word; { unsigned low8, rot, val; low8 = word & 0xFF; rot = (word & 0xF00) >> 7; val = (low8 << (32 - rot)) | (low8 >> rot); if (val <= 9) printf("#%u\n", val); else printf("#%u\t; 0x%x\n", val, val); } static void op2_regbyconst(word) unsigned word; { unsigned c, t; c = (word >> 7) & 0x1F; t = (word >> 5) & 3; if (!c) { switch (t) { case 0: printf("%s", regnames[word&0xF]); return; case 3: printf("%s, rrx", regnames[word&0xF]); return; default: c = 32; } } printf("%s, %s #%u", regnames[word&0xF], shift_types[t], c); } static void op2_regbyreg(word) unsigned word; { printf("%s, %s %s", regnames[word&0xF], shift_types[(word>>5)&3], regnames[(word>>8)&0xF]); } static void op2_regshift(word) unsigned word; { if (word & 0x10) op2_regbyreg(word); else op2_regbyconst(word); putchar('\n'); } static void dataproc_op2(word) unsigned word; { if (word & 0x02000000) op2_immed(word); else op2_regshift(word); } static void dataproc_tstcmp_overlay(word) unsigned word; { char msrmask[5], *cp; if ((word & 0x0FFFFFF0) == 0x012FFF10) { printf("bx%s\t%s\n", condition_decode[word>>28], regnames[word&0xF]); return; } else if ((word & 0x0FBF0FFF) == 0x010F0000) { printf("mrs%s\t%s, %cPSR\n", condition_decode[word>>28], regnames[(word>>12)&0xF], word&0x400000 ? 'S' : 'C'); return; } else if ((word & 0x0DB0F000) == 0x0120F000) { if (!(word & 0x02000000) && (word & 0xFF0)) { printf("<invalid MSR>\n"); return; } if (word & 0xF0000) { cp = msrmask; if (word & 0x80000) *cp++ = 'f'; if (word & 0x40000) *cp++ = 's'; if (word & 0x20000) *cp++ = 'x'; if (word & 0x10000) *cp++ = 'c'; *cp = '\0'; } else strcpy(msrmask, "null"); printf("msr%s\t%cPSR_%s, ", condition_decode[word>>28], word&0x400000 ? 'S' : 'C', msrmask); dataproc_op2(word); return; } printf("<invalid BX/MRS/MSR>\n"); } static void dataproc(word) unsigned word; { unsigned opc; opc = (word >> 21) & 0xF; switch (opc) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 0xC: case 0xE: printf("%s%s%s\t%s, %s, ", dataproc_ops[opc], condition_decode[word>>28], word&0x100000 ? "s" : "", regnames[(word>>12)&0xF], regnames[(word>>16)&0xF]); dataproc_op2(word); return; case 0xD: case 0xF: printf("%s%s%s\t%s, ", dataproc_ops[opc], condition_decode[word>>28], word&0x100000 ? "s" : "", regnames[(word>>12)&0xF]); dataproc_op2(word); return; case 8: case 9: case 0xA: case 0xB: if (word & 0x100000) { printf("%s%s\t%s, ", dataproc_ops[opc], condition_decode[word>>28], regnames[(word>>16)&0xF]); dataproc_op2(word); } else dataproc_tstcmp_overlay(word); return; } } static void multiply(word) unsigned word; { if ((word & 0x0FE000F0) == 0x90) printf("mul%s%s\t%s, %s, %s\n", condition_decode[word>>28], word&0x100000 ? "s" : "", regnames[(word>>16)&0xF], regnames[word&0xF], regnames[(word>>8)&0xF]); else if ((word & 0x0FE000F0) == 0x00200090) printf("mla%s%s\t%s, %s, %s, %s\n", condition_decode[word>>28], word&0x100000 ? "s" : "", regnames[(word>>16)&0xF], regnames[word&0xF], regnames[(word>>8)&0xF], regnames[(word>>12)&0xF]); else if ((word & 0x0F8000F0) == 0x00800090) printf("%c%sl%s%s\t%s, %s, %s, %s\n", word&0x400000 ? 's' : 'u', word&0x200000 ? "mla" : "mul", condition_decode[word>>28], word&0x100000 ? "s" : "", regnames[(word>>12)&0xF], regnames[(word>>16)&0xF], regnames[word&0xF], regnames[(word>>8)&0xF]); else printf("<invalid multiply>\n"); } static void ldr_str_imm_pre(off, word) unsigned off, word; { unsigned loff = word & 0xFFF; /* check for literal pool fetches will go here */ printf("%s%s%s\t%s, [%s", word&0x100000 ? "ldr" : "str", condition_decode[word>>28], word&0x400000 ? "b" : "", regnames[(word>>12)&0xF], regnames[(word>>16)&0xF]); if (loff || word&0x200000) printf(", #%s%u", word&0x800000 ? "" : "-", loff); putchar(']'); if (word & 0x200000) putchar('!'); if (loff >= 10) printf("\t; 0x%x", loff); putchar('\n'); } static void ldr_str_imm_post(word) unsigned word; { unsigned loff = word & 0xFFF; printf("%s%s%s%s\t%s, [%s], #%s%u", word&0x100000 ? "ldr" : "str", condition_decode[word>>28], word&0x400000 ? "b" : "", word&0x200000 ? "t" : "", regnames[(word>>12)&0xF], regnames[(word>>16)&0xF], word&0x800000 ? "" : "-", loff); if (loff >= 10) printf("\t; 0x%x", loff); putchar('\n'); } static void ldr_str_reg_pre(word) unsigned word; { if (word & 0x10) { printf("<invalid ldr/str: offset reg shift by reg>\n"); return; } printf("%s%s%s\t%s, [%s, ", word&0x100000 ? "ldr" : "str", condition_decode[word>>28], word&0x400000 ? "b" : "", regnames[(word>>12)&0xF], regnames[(word>>16)&0xF]); if (!(word & 0x800000)) putchar('-'); op2_regbyconst(word); putchar(']'); if (word & 0x200000) putchar('!'); putchar('\n'); } static void ldr_str_reg_post(word) unsigned word; { if (word & 0x10) { printf("<invalid ldr/str: offset reg shift by reg>\n"); return; } printf("%s%s%s%s\t%s, [%s], ", word&0x100000 ? "ldr" : "str", condition_decode[word>>28], word&0x400000 ? "b" : "", word&0x200000 ? "t" : "", regnames[(word>>12)&0xF], regnames[(word>>16)&0xF]); if (!(word & 0x800000)) putchar('-'); op2_regbyconst(word); putchar('\n'); } static void ldr_str_ext(off, word) unsigned off, word; { printf("<extended ldr/str>\n"); } static void dataproc_74_overlay(off, word) unsigned off, word; { if (word & 0x60) ldr_str_ext(off, word); else multiply(word); } void arm_disasm_line(off) unsigned off; { unsigned word; word = get_u32(filemap + off); printf("%8x:\t%08x\t", base_vma + off, word); if ((word >> 28) == 0xF) { printf("<invalid-F>\n"); return; } switch ((word >> 24) & 0xF) { case 0: case 1: if ((word & 0x90) == 0x90) dataproc_74_overlay(off, word); else dataproc(word); return; case 2: case 3: dataproc(word); return; case 4: ldr_str_imm_post(word); return; case 5: ldr_str_imm_pre(off, word); return; case 6: ldr_str_reg_post(word); return; case 7: ldr_str_reg_pre(word); return; case 8: case 9: printf("<ldm/stm>\n"); return; case 0xA: case 0xB: arm_branch(off, word); return; case 0xC: case 0xD: case 0xE: printf("<COPROCESSOR>\n"); return; case 0xF: printf("swi%s\t0x%x\n", condition_decode[word>>28], word & 0xFFFFFF); return; } } main(argc, argv) char **argv; { unsigned off; common_init(argc, argv, 4); for (off = 0; off < disasm_len; off += 4) arm_disasm_line(off); exit(0); }