diff arm7dis/thumbdis.c @ 97:fb5ea2758482

thumbdis written, compiles
author Michael Spacefalcon <msokolov@ivan.Harhan.ORG>
date Sun, 30 Mar 2014 23:32:26 +0000
parents
children 78e4702884e3
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arm7dis/thumbdis.c	Sun Mar 30 23:32:26 2014 +0000
@@ -0,0 +1,408 @@
+#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 *opc[3] = {"add", "cmp", "mov"};
+	int reg1, reg2;
+
+	if (word & 0xC0) {
+		reg1 = word & 7;
+		if (word & 0x80)
+			reg1 += 8;
+		reg2 = (word >> 3) & 0xF;
+		printf("%s\t%s, %s\n", opc[(word>>8)&3],
+			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 & 0xFF) << 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);
+}