view arm7dis/armdis.c @ 90:f68d8e7a904f

armdis: implemented decoding of multiplication instructions
author Michael Spacefalcon <msokolov@ivan.Harhan.ORG>
date Sat, 29 Mar 2014 22:19:21 +0000
parents c5d52666d2eb
children daf69d5edb3f
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\n", regnames[word&0xF]);
			return;
		case 3:
			printf("%s, rrx\n", regnames[word&0xF]);
			return;
		default:
			c = 32;
		}
	}
	printf("%s, %s #%u\n", regnames[word&0xF], shift_types[t], c);
}

static void
op2_regbyreg(word)
	unsigned word;
{
	printf("%s, %s %s\n", 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);
}

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_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:
	case 5:
		printf("<ldr/str, immediate offset>\n");
		return;
	case 6:
	case 7:
		printf("<ldr/str, register offset>\n");
		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);
}