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');
+}