winedbg: Add partial ARM disassembler.
This commit is contained in:
parent
3b2fcdd426
commit
0fccc41c3f
|
@ -24,6 +24,310 @@
|
|||
|
||||
#if defined(__arm__) && !defined(__ARMEB__)
|
||||
|
||||
/*
|
||||
* Switch to disassemble Thumb code.
|
||||
*/
|
||||
static BOOL db_disasm_thumb = FALSE;
|
||||
|
||||
/*
|
||||
* Flag to indicate whether we need to display instruction,
|
||||
* or whether we just need to know the address of the next
|
||||
* instruction.
|
||||
*/
|
||||
static BOOL db_display = FALSE;
|
||||
|
||||
#define ARM_INSN_SIZE 4
|
||||
#define THUMB_INSN_SIZE 2
|
||||
|
||||
#define ROR32(n, r) (((n) >> (r)) | ((n) << (32 - (r))))
|
||||
|
||||
#define get_cond(ins) tbl_cond[(ins >> 28) & 0x0f]
|
||||
#define get_nibble(ins, num) ((ins >> (num * 4)) & 0x0f)
|
||||
|
||||
static char const tbl_addrmode[][3] = {
|
||||
"da", "ia", "db", "ib"
|
||||
};
|
||||
|
||||
static char const tbl_cond[][3] = {
|
||||
"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", "hi", "ls", "ge", "lt", "gt", "le", "", ""
|
||||
};
|
||||
|
||||
static char const tbl_dataops[][4] = {
|
||||
"and", "eor", "sub", "rsb", "add", "adc", "sbc", "rsc", "tst", "teq", "cmp", "cmn", "orr",
|
||||
"mov", "bic", "mvn"
|
||||
};
|
||||
|
||||
static UINT db_get_inst(void* addr, int size)
|
||||
{
|
||||
UINT result = 0;
|
||||
char buffer[4];
|
||||
|
||||
if (dbg_read_memory(addr, buffer, size))
|
||||
{
|
||||
switch (size)
|
||||
{
|
||||
case 4:
|
||||
result = *(UINT*)buffer;
|
||||
break;
|
||||
case 2:
|
||||
result = *(WORD*)buffer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static UINT arm_disasm_branch(UINT inst)
|
||||
{
|
||||
short link = (inst >> 24) & 0x01;
|
||||
int offset = (inst << 2) & 0x03ffffff;
|
||||
|
||||
if (offset & 0x02000000) offset |= 0xfc000000;
|
||||
offset += 8;
|
||||
|
||||
dbg_printf("\n\tb%s%s\t#%d/0x%08x", link ? "l" : "", get_cond(inst), offset, offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static UINT arm_disasm_dataprocessing(UINT inst)
|
||||
{
|
||||
short condcodes = (inst >> 20) & 0x01;
|
||||
short opcode = (inst >> 21) & 0x0f;
|
||||
short immediate = (inst >> 25) & 0x01;
|
||||
short no_op1 = (opcode & 0x0d) == 0x0d;
|
||||
|
||||
/* check for nop */
|
||||
if (get_nibble(inst, 3) == 15 /* r15 */ && condcodes == 0 &&
|
||||
opcode >= 8 /* tst */ && opcode <= 11 /* cmn */)
|
||||
{
|
||||
dbg_printf("\n\tnop");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dbg_printf("\n\t%s%s%s", tbl_dataops[opcode], condcodes ? "s" : "", get_cond(inst));
|
||||
if (no_op1)
|
||||
{
|
||||
if (immediate)
|
||||
dbg_printf("\tr%u, #%u", get_nibble(inst, 3),
|
||||
ROR32(inst & 0xff, 2 * get_nibble(inst, 2)));
|
||||
else
|
||||
dbg_printf("\tr%u, r%u", get_nibble(inst, 3), get_nibble(inst, 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (immediate)
|
||||
dbg_printf("\tr%u, r%u, #%u", get_nibble(inst, 3), get_nibble(inst, 4),
|
||||
ROR32(inst & 0xff, 2 * get_nibble(inst, 2)));
|
||||
else
|
||||
dbg_printf("\tr%u, r%u, r%u", get_nibble(inst, 3), get_nibble(inst, 4),
|
||||
get_nibble(inst, 0));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static UINT arm_disasm_singletrans(UINT inst)
|
||||
{
|
||||
short load = (inst >> 20) & 0x01;
|
||||
short writeback = (inst >> 21) & 0x01;
|
||||
short byte = (inst >> 22) & 0x01;
|
||||
short direction = (inst >> 23) & 0x01;
|
||||
/* FIXME: what to do with bit 24 (indexing) */
|
||||
short immediate = !((inst >> 25) & 0x01);
|
||||
short offset = inst & 0x0fff;
|
||||
|
||||
if (!direction) offset *= -1;
|
||||
|
||||
dbg_printf("\n\t%s%s%s%s", load ? "ldr" : "str", byte ? "b" : "", writeback ? "t" : "",
|
||||
get_cond(inst));
|
||||
if (immediate)
|
||||
dbg_printf("\tr%u, [r%u, #%d]", get_nibble(inst, 3), get_nibble(inst, 4), offset);
|
||||
else
|
||||
dbg_printf("\tr%u, r%u, r%u", get_nibble(inst, 3), get_nibble(inst, 4),
|
||||
get_nibble(inst, 0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static UINT arm_disasm_halfwordtrans(UINT inst)
|
||||
{
|
||||
short halfword = (inst >> 5) & 0x01;
|
||||
short sign = (inst >> 6) & 0x01;
|
||||
short load = (inst >> 20) & 0x01;
|
||||
short writeback = (inst >> 21) & 0x01;
|
||||
short immediate = (inst >> 22) & 0x01;
|
||||
short direction = (inst >> 23) & 0x01;
|
||||
/* FIXME: what to do with bit 24 (indexing) */
|
||||
short offset = ((inst >> 4) & 0xf0) + (inst & 0x0f);
|
||||
|
||||
if (!direction) offset *= -1;
|
||||
|
||||
dbg_printf("\n\t%s%s%s%s%s", load ? "ldr" : "str", sign ? "s" : "",
|
||||
halfword ? "h" : (sign ? "b" : ""), writeback ? "t" : "", get_cond(inst));
|
||||
if (immediate)
|
||||
dbg_printf("\tr%u, r%u, #%d", get_nibble(inst, 3), get_nibble(inst, 4), offset);
|
||||
else
|
||||
dbg_printf("\tr%u, r%u, r%u", get_nibble(inst, 3), get_nibble(inst, 4), get_nibble(inst, 0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static UINT arm_disasm_blocktrans(UINT inst)
|
||||
{
|
||||
short load = (inst >> 20) & 0x01;
|
||||
short writeback = (inst >> 21) & 0x01;
|
||||
short psr = (inst >> 22) & 0x01;
|
||||
short addrmode = (inst >> 23) & 0x03;
|
||||
short i;
|
||||
short last=15;
|
||||
for (i=15;i>=0;i--)
|
||||
if ((inst>>i) & 1)
|
||||
{
|
||||
last = i;
|
||||
break;
|
||||
}
|
||||
|
||||
dbg_printf("\n\t%s%s%s\tr%u%s, {", load ? "ldm" : "stm", tbl_addrmode[addrmode], get_cond(inst),
|
||||
get_nibble(inst, 4), writeback ? "!" : "");
|
||||
for (i=0;i<=15;i++)
|
||||
if ((inst>>i) & 1)
|
||||
{
|
||||
if (i == last) dbg_printf("r%u", i);
|
||||
else dbg_printf("r%u, ", i);
|
||||
}
|
||||
dbg_printf("}%s", psr ? "^" : "");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static UINT arm_disasm_swi(UINT inst)
|
||||
{
|
||||
UINT comment = inst & 0x00ffffff;
|
||||
dbg_printf("\n\tswi%s\t#%d/0x%08x", get_cond(inst), comment, comment);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static UINT arm_disasm_coproctrans(UINT inst)
|
||||
{
|
||||
WORD CRm = inst & 0x0f;
|
||||
WORD CP = (inst >> 5) & 0x07;
|
||||
WORD CPnum = (inst >> 8) & 0x0f;
|
||||
WORD CRn = (inst >> 16) & 0x0f;
|
||||
WORD load = (inst >> 20) & 0x01;
|
||||
WORD CP_Opc = (inst >> 21) & 0x07;
|
||||
|
||||
dbg_printf("\n\t%s%s\t%u, %u, r%u, cr%u, cr%u, {%u}", load ? "mrc" : "mcr", get_cond(inst), CPnum,
|
||||
CP, get_nibble(inst, 3), CRn, CRm, CP_Opc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static UINT arm_disasm_coprocdataop(UINT inst)
|
||||
{
|
||||
WORD CRm = inst & 0x0f;
|
||||
WORD CP = (inst >> 5) & 0x07;
|
||||
WORD CPnum = (inst >> 8) & 0x0f;
|
||||
WORD CRd = (inst >> 12) & 0x0f;
|
||||
WORD CRn = (inst >> 16) & 0x0f;
|
||||
WORD CP_Opc = (inst >> 20) & 0x0f;
|
||||
|
||||
dbg_printf("\n\tcdp%s\t%u, %u, cr%u, cr%u, cr%u, {%u}", get_cond(inst),
|
||||
CPnum, CP, CRd, CRn, CRm, CP_Opc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static UINT arm_disasm_coprocdatatrans(UINT inst)
|
||||
{
|
||||
WORD CPnum = (inst >> 8) & 0x0f;
|
||||
WORD CRd = (inst >> 12) & 0x0f;
|
||||
WORD load = (inst >> 20) & 0x01;
|
||||
/* FIXME: what to do with bit 21 (writeback) */
|
||||
WORD translen = (inst >> 22) & 0x01;
|
||||
WORD direction = (inst >> 23) & 0x01;
|
||||
/* FIXME: what to do with bit 24 (indexing) */
|
||||
short offset = (inst & 0xff) << 2;
|
||||
|
||||
if (!direction) offset *= -1;
|
||||
|
||||
dbg_printf("\n\t%s%s%s", load ? "ldc" : "stc", translen ? "l" : "", get_cond(inst));
|
||||
dbg_printf("\t%u, cr%u, [r%u, #%d]", CPnum, CRd, get_nibble(inst, 4), offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct inst_arm
|
||||
{
|
||||
UINT mask;
|
||||
UINT pattern;
|
||||
UINT (*func)(UINT);
|
||||
};
|
||||
|
||||
static const struct inst_arm tbl_arm[] = {
|
||||
{ 0x0e000000, 0x0a000000, arm_disasm_branch },
|
||||
{ 0x0c000000, 0x00000000, arm_disasm_dataprocessing },
|
||||
{ 0x0c000000, 0x04000000, arm_disasm_singletrans },
|
||||
{ 0x0e000090, 0x00000090, arm_disasm_halfwordtrans },
|
||||
{ 0x0e000000, 0x08000000, arm_disasm_blocktrans },
|
||||
{ 0x0f000000, 0x0f000000, arm_disasm_swi },
|
||||
{ 0x0f000010, 0x0e000010, arm_disasm_coproctrans },
|
||||
{ 0x0f000010, 0x0e000000, arm_disasm_coprocdataop },
|
||||
{ 0x0e000000, 0x0c000000, arm_disasm_coprocdatatrans },
|
||||
{ 0x00000000, 0x00000000, NULL }
|
||||
};
|
||||
|
||||
/***********************************************************************
|
||||
* disasm_one_insn
|
||||
*
|
||||
* Disassemble instruction at 'addr'. addr is changed to point to the
|
||||
* start of the next instruction.
|
||||
*/
|
||||
void be_arm_disasm_one_insn(ADDRESS64 *addr, int display)
|
||||
{
|
||||
struct inst_arm *a_ptr = (struct inst_arm *)&tbl_arm;
|
||||
UINT inst;
|
||||
int size;
|
||||
int matched = 0;
|
||||
|
||||
char tmp[64];
|
||||
DWORD_PTR* pval;
|
||||
|
||||
if (!memory_get_register(CV_ARM_CPSR, &pval, tmp, sizeof(tmp)))
|
||||
dbg_printf("\n\tmemory_get_register failed: %s\n",tmp);
|
||||
else
|
||||
db_disasm_thumb=(*pval & 0x20)?TRUE:FALSE;
|
||||
|
||||
if (db_disasm_thumb) size = THUMB_INSN_SIZE;
|
||||
else size = ARM_INSN_SIZE;
|
||||
|
||||
db_display = display;
|
||||
inst = db_get_inst( memory_to_linear_addr(addr), size );
|
||||
|
||||
if (!db_disasm_thumb)
|
||||
{
|
||||
while (a_ptr->func) {
|
||||
if ((inst & a_ptr->mask) == a_ptr->pattern) {
|
||||
matched = 1;
|
||||
break;
|
||||
}
|
||||
a_ptr++;
|
||||
}
|
||||
|
||||
if (!matched) {
|
||||
dbg_printf("\n\tUnknown Instruction: %08x\n", inst);
|
||||
addr->Offset += size;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!a_ptr->func(inst))
|
||||
{
|
||||
dbg_printf("\n");
|
||||
addr->Offset += size;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dbg_printf("\n\tThumb disassembling not yet implemented\n");
|
||||
addr->Offset += size;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned be_arm_get_addr(HANDLE hThread, const CONTEXT* ctx,
|
||||
enum be_cpu_addr bca, ADDRESS64* addr)
|
||||
{
|
||||
|
@ -150,11 +454,6 @@ static unsigned be_arm_is_jump(const void* insn, ADDRESS64* jumpee)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
static void be_arm_disasm_one_insn(ADDRESS64* addr, int display)
|
||||
{
|
||||
dbg_printf("Disasm NIY\n");
|
||||
}
|
||||
|
||||
static unsigned be_arm_insert_Xpoint(HANDLE hProcess, const struct be_process_io* pio,
|
||||
CONTEXT* ctx, enum be_xpoint_type type,
|
||||
void* addr, unsigned long* val, unsigned size)
|
||||
|
|
Loading…
Reference in New Issue