FreeCalypso > hg > freecalypso-reveng
diff leo-obj/tool/armdis.c @ 130:87b82398a08b
leo-obj project subtree started, tiobjd tool moved into it
author | Michael Spacefalcon <msokolov@ivan.Harhan.ORG> |
---|---|
date | Sun, 06 Apr 2014 22:14:39 +0000 |
parents | ticoff/armdis.c@2f23301d2f86 |
children | 2767ff8d26d5 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/leo-obj/tool/armdis.c Sun Apr 06 22:14:39 2014 +0000 @@ -0,0 +1,522 @@ +/* + * ARM state disassembly + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include "intstruct.h" +#include "globals.h" + +extern unsigned get_u16(), get_u32(); +extern struct internal_reloc *find_word32_reloc(); + +extern char *regnames[16], *condition_decode[16], *shift_types[4]; + +static char *dataproc_ops[16] = {"and", "eor", "sub", "rsb", + "add", "adc", "sbc", "rsc", + "tst", "teq", "cmp", "cmn", + "orr", "mov", "bic", "mvn"}; + +static void +arm_branch(off, word) + unsigned off, word; +{ + unsigned dest; + + dest = (word & 0x00FFFFFF) << 2; + if (dest & 0x02000000) + dest |= 0xFC000000; + dest += 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 if ((word & 0x0FB00FF0) == 0x01000090) + printf("swp%s%s\t%s, %s, [%s]\n", condition_decode[word>>28], + word&0x400000, "b", "", regnames[(word>>12)&0xF], + regnames[word&0xF], regnames[(word>>16)&0xF]); + else + printf("<invalid multiply>\n"); +} + +static int +check_ldr_litpool(sec, off, word, loff, size) + struct internal_scnhdr *sec; + unsigned off, word, loff; +{ + unsigned litoff, datum; + struct internal_reloc *rel; + + /* base reg must be 15 */ + if (((word >> 16) & 0xF) != 15) + return(0); + /* must be a load */ + if (!(word & 0x100000)) + return(0); + /* no writeback allowed */ + if (word & 0x200000) + return(0); + /* alignment */ + if (loff & (size - 1)) + return(0); + /* range */ + off += 8; + if (word & 0x800000) + litoff = off + loff; + else { + if (loff > off) + return(0); + litoff = off - loff; + } + if (litoff >= sec->size) + return(0); + /* all checks passed, proceed */ + rel = find_word32_reloc(sec, litoff); + switch (size) { + case 1: + datum = filemap[sec->data_offset + litoff]; + break; + case 2: + datum = get_u16(filemap + sec->data_offset + litoff); + break; + case 4: + datum = get_u32(filemap + sec->data_offset + litoff); + break; + } + putchar('='); + if (rel) + disasm_reloc_target(sec, rel, datum); + else + printf("0x%x", datum); + printf("\t; via 0x%x\n", litoff); + return(1); +} + +static void +ldr_str_imm_pre(sec, off, word) + struct internal_scnhdr *sec; + unsigned off, word; +{ + unsigned loff = word & 0xFFF; + + printf("%s%s%s\t%s, ", word&0x100000 ? "ldr" : "str", + condition_decode[word>>28], word&0x400000 ? "b" : "", + regnames[(word>>12)&0xF]); + if (check_ldr_litpool(sec, off, word, loff, word&0x400000 ? 1 : 4)) + return; + printf("[%s", 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(sec, off, word) + struct internal_scnhdr *sec; + unsigned off, word; +{ + unsigned loff; + + if (!(word&0x01000000) && word&0x200000) { + printf("<invalid ldrh/strh: P=0, W=1>\n"); + return; + } + if (!(word&0x400000) && word&0xF00) { + printf("<invalid ldrh/strh: SBZ!=0>\n"); + return; + } + printf("%s%s%s%c\t%s, ", word&0x100000 ? "ldr" : "str", + condition_decode[word>>28], + word&0x40 ? "s" : "", + word&0x20 ? 'h' : 'b', + regnames[(word>>12)&0xF]); + if (word & 0x400000) + loff = ((word & 0xF00) >> 4) | (word & 0xF); + switch (word & 0x01400000) { + case 0: + /* reg post */ + printf("[%s], %s%s", regnames[(word>>16)&0xF], + word&0x800000 ? "" : "-", regnames[word&0xF]); + break; + case 0x400000: + /* imm post */ + printf("[%s], #%s%u", regnames[(word>>16)&0xF], + word&0x800000 ? "" : "-", loff); + if (loff >= 10) + printf("\t; 0x%x", loff); + break; + case 0x01000000: + /* reg pre */ + printf("[%s, %s%s]%s", regnames[(word>>16)&0xF], + word&0x800000 ? "" : "-", regnames[word&0xF], + word&0x200000 ? "!" : ""); + break; + case 0x01400000: + /* imm pre */ + if (check_ldr_litpool(sec, off, word, loff, word&0x20 ? 2 : 1)) + return; + printf("[%s", 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); + break; + } + putchar('\n'); +} + +static void +dataproc_74_overlay(sec, off, word) + struct internal_scnhdr *sec; + unsigned off, word; +{ + if (word & 0x60) + ldr_str_ext(sec, off, word); + else + multiply(word); +} + +static void +ldm_stm(word) + unsigned word; +{ + int r, flag; + + printf("%s%s%c%c\t%s", word&0x100000 ? "ldm" : "stm", + condition_decode[word>>28], + word&0x800000 ? 'i' : 'd', word&0x01000000 ? 'b' : 'a', + regnames[(word>>16)&0xF]); + if (word & 0x200000) + putchar('!'); + fputs(", {", stdout); + flag = 0; + for (r = 0; r < 16; r++) + if (word & (1 << r)) { + if (flag) + fputs(", ", stdout); + fputs(regnames[r], stdout); + flag = 1; + } + putchar('}'); + if (word & 0x400000) + putchar('^'); + putchar('\n'); +} + +void +arm_disasm_line(sec, off) + struct internal_scnhdr *sec; + unsigned off; +{ + unsigned word; + + word = get_u32(filemap + sec->data_offset + off); + printf("%08x\t", 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(sec, 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(sec, off, word); + return; + case 6: + ldr_str_reg_post(word); + return; + case 7: + ldr_str_reg_pre(word); + return; + case 8: + case 9: + ldm_stm(word); + 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; + } +} + +void +arm_branch_reloc(sec, rel) + struct internal_scnhdr *sec; + struct internal_reloc *rel; +{ + unsigned word, dest; + + word = get_u32(filemap + sec->data_offset + rel->location); + printf("%08x R\t", word); + if ((word & 0x0E000000) != 0x0A000000) { + printf("<invalid ARM_B reloc: opcode not B or BL>\n"); + return; + } + dest = (word & 0x00FFFFFF) << 2; + if (dest & 0x02000000) + dest |= 0xFC000000; + dest += rel->location + 8; + printf("b%s%s\t", word&0x1000000 ? "l" : "", + condition_decode[word>>28]); + disasm_reloc_target(sec, rel, dest); + putchar('\n'); +}