view arm7dis/armdis.c @ 88:691551f0635b

armdis: implemented decoding of data processing instructions
author Michael Spacefalcon <msokolov@ivan.Harhan.ORG>
date Sat, 29 Mar 2014 20:28:13 +0000
parents f7fba8518fa2
children c5d52666d2eb
line wrap: on
line source

#include <sys/types.h>
#include <stdio.h>
#include <stdlib.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_74_overlay(off, word)
	unsigned off, word;
{
	printf("<dataproc overlay with 7&4 set>\n");
}

static void
dataproc_tstcmp_overlay(off, word)
	unsigned off, word;
{
	printf("<dataproc overlay with S=0 for tst/cmp>\n");
}

static void
dataproc(off, word)
	unsigned off, 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(off, word);
		return;
	}
}

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(off, word);
		return;
	case 2:
	case 3:
		dataproc(off, 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);
}