Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1832 lines
48 KiB

//----------------------------------------------------------------------------
//
// Disassembly portions of ARM machine implementation.
//
// Copyright (C) Microsoft Corporation, 2001-2002.
//
//----------------------------------------------------------------------------
#include "ntsdp.hpp"
#include "arminst.h"
PSTR g_ArmCond[] =
{
"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
"hi", "ls", "ge", "lt", "gt", "le", "al", "nv",
};
PSTR g_ArmShift[] =
{
"lsl", "lsr", "asr", "ror", "rrx",
};
enum ARM_DECODE
{
ARMDEC_INVALID,
ARMDEC_ARTH_IMM,
ARMDEC_ARTH_ISHF,
ARMDEC_ARTH_RSHF,
ARMDEC_BI,
ARMDEC_BKPT,
ARMDEC_BXI,
ARMDEC_BXR,
ARMDEC_CDP,
ARMDEC_CLZ,
ARMDEC_CMP_IMM,
ARMDEC_CMP_ISHF,
ARMDEC_CMP_RSHF,
ARMDEC_LDC,
ARMDEC_LDM,
ARMDEC_LDR_IMM,
ARMDEC_LDR_RSHF,
ARMDEC_LDRH_IMM,
ARMDEC_LDRH_REG,
ARMDEC_MCR,
ARMDEC_MCRR,
ARMDEC_MOV_IMM,
ARMDEC_MOV_ISHF,
ARMDEC_MOV_RSHF,
ARMDEC_MRC,
ARMDEC_MRRC,
ARMDEC_MRS,
ARMDEC_MSR_IMM,
ARMDEC_MSR_REG,
ARMDEC_MUL,
ARMDEC_QADD,
ARMDEC_SMLA,
ARMDEC_SMLAL,
ARMDEC_SMUL,
ARMDEC_SWI,
ARMDEC_SWP,
ARMDEC_UNDEF,
};
struct ArmDecode
{
ULONG Mask;
ULONG Encoded;
ARM_DECODE Op;
PSTR Name;
};
#define ARTH_OP(Op, Name) \
0xffe00000, 0x02000000 | ((Op) << 21), ARMDEC_ARTH_IMM, Name, \
0xffe00010, 0x00000000 | ((Op) << 21), ARMDEC_ARTH_ISHF, Name, \
0xffe00090, 0x00000010 | ((Op) << 21), ARMDEC_ARTH_RSHF, Name
#define MOV_OP(Op, Name) \
0xffef0000, 0x02000000 | ((Op) << 21), ARMDEC_MOV_IMM, Name, \
0xffef0010, 0x00000000 | ((Op) << 21), ARMDEC_MOV_ISHF, Name, \
0xffef0090, 0x00000010 | ((Op) << 21), ARMDEC_MOV_RSHF, Name
#define CMP_OP(Op, Name) \
0xfff0f000, 0x02100000 | ((Op) << 21), ARMDEC_CMP_IMM, Name, \
0xfff0f010, 0x00100000 | ((Op) << 21), ARMDEC_CMP_ISHF, Name, \
0xfff0f090, 0x00100010 | ((Op) << 21), ARMDEC_CMP_RSHF, Name
#define LDC_OP(Op, Name) \
0xfe100000, 0x0c000000 | ((Op) << 20), ARMDEC_LDC, Name, \
0xfe100000, 0xfc000000 | ((Op) << 20), ARMDEC_LDC, Name ## "2"
#define LDM_OP(Op, Name) \
0xfe500000, 0x08000000 | ((Op) << 20), ARMDEC_LDM, Name, \
0xfe700000, 0x08400000 | ((Op) << 20), ARMDEC_LDM, Name
#define LDR_OP(Op, Name) \
0xfe100000, 0x04000000 | ((Op) << 20), ARMDEC_LDR_IMM, Name, \
0xfe100000, 0x06000000 | ((Op) << 20), ARMDEC_LDR_RSHF, Name
ArmDecode g_ArmDecode[] =
{
// Undefined instruction space.
0xf6000010, 0x06000010, ARMDEC_UNDEF, "???",
ARTH_OP(OP_ADC, "adc"),
ARTH_OP(OP_ADD, "add"),
ARTH_OP(OP_AND, "and"),
0xff000000, 0x0a000000, ARMDEC_BI, "b",
0xff000000, 0x0b000000, ARMDEC_BI, "bl",
ARTH_OP(OP_BIC, "bic"),
0xfff000f0, 0x01200070, ARMDEC_BKPT, "bkpt",
0xfe000000, 0xfa000000, ARMDEC_BXI, "blx",
0xfffffff0, 0x012fff30, ARMDEC_BXR, "blx",
0xfffffff0, 0x012fff10, ARMDEC_BXR, "bx",
0xff000010, 0x0e000000, ARMDEC_CDP, "cdp",
0xff000010, 0xfe000000, ARMDEC_CDP, "cdp2",
0xffff0ff0, 0x016f0f10, ARMDEC_CLZ, "clz",
CMP_OP(OP_CMN, "cmn"),
CMP_OP(OP_CMP, "cmp"),
ARTH_OP(OP_EOR, "eor"),
LDC_OP(1, "ldc"),
LDM_OP(1, "ldm"),
LDR_OP(1, "ldr"),
0xfe5000f0, 0x004000d0, ARMDEC_LDRH_IMM, "ldr",
0xfe500ff0, 0x000000d0, ARMDEC_LDRH_REG, "ldr",
0xfe5000f0, 0x005000b0, ARMDEC_LDRH_IMM, "ldr",
0xfe500ff0, 0x001000b0, ARMDEC_LDRH_REG, "ldr",
0xfe5000f0, 0x005000d0, ARMDEC_LDRH_IMM, "ldr",
0xfe500ff0, 0x001000d0, ARMDEC_LDRH_REG, "ldr",
0xfe5000f0, 0x005000f0, ARMDEC_LDRH_IMM, "ldr",
0xfe500ff0, 0x001000f0, ARMDEC_LDRH_REG, "ldr",
0xff100010, 0x0e000010, ARMDEC_MCR, "mcr",
0xff100010, 0xfe000010, ARMDEC_MCR, "mcr2",
0xfff00000, 0x0e400000, ARMDEC_MCRR, "mcrr",
0xffe000f0, 0x00200090, ARMDEC_MUL, "mla",
MOV_OP(OP_MOV, "mov"),
0xff100010, 0x0e100010, ARMDEC_MRC, "mrc",
0xff100010, 0xfe100010, ARMDEC_MRC, "mrc2",
0xfff00000, 0x0e500000, ARMDEC_MRRC, "mrrc",
0xffbf0fff, 0x010f0000, ARMDEC_MRS, "mrs",
0xffb0f000, 0x0320f000, ARMDEC_MSR_IMM, "msr",
0xffb0f0f0, 0x0120f000, ARMDEC_MSR_REG, "msr",
0xffe0f0f0, 0x00000090, ARMDEC_MUL, "mul",
MOV_OP(OP_MVN, "mvn"),
ARTH_OP(OP_ORR, "orr"),
ARTH_OP(OP_RSB, "rsb"),
ARTH_OP(OP_RSC, "rsc"),
ARTH_OP(OP_SBC, "sbc"),
0xfff00090, 0x01000080, ARMDEC_SMLA, "smla",
0xfff00090, 0x01400080, ARMDEC_SMLAL, "smlal",
0xffe000f0, 0x00e00090, ARMDEC_MUL, "smlal",
0xfff000b0, 0x01200080, ARMDEC_SMLA, "smlaw",
0xfff0f090, 0x01600080, ARMDEC_SMUL, "smulb",
0xffe000f0, 0x00c00090, ARMDEC_MUL, "smull",
0xfff0f0b0, 0x016000a0, ARMDEC_SMUL, "smulw",
0xff70f000, 0xf750f000, ARMDEC_LDR_IMM, "pld",
0xff70f000, 0xf550f000, ARMDEC_LDR_RSHF, "pld",
0xfff00ff0, 0x01000050, ARMDEC_QADD, "qadd",
0xfff00ff0, 0x01400050, ARMDEC_QADD, "qdadd",
0xfff00ff0, 0x01600050, ARMDEC_QADD, "qdsub",
0xfff00ff0, 0x01200050, ARMDEC_QADD, "qsub",
LDC_OP(0, "stc"),
LDM_OP(0, "stm"),
LDR_OP(0, "str"),
0xfe5000f0, 0x004000f0, ARMDEC_LDRH_IMM, "str",
0xfe500ff0, 0x000000f0, ARMDEC_LDRH_REG, "str",
0xfe5000f0, 0x004000b0, ARMDEC_LDRH_IMM, "str",
0xfe500ff0, 0x000000b0, ARMDEC_LDRH_REG, "str",
ARTH_OP(OP_SUB, "sub"),
0xff000000, 0x0f000000, ARMDEC_SWI, "swi",
0xffb00ff0, 0x01000090, ARMDEC_SWP, "swp",
CMP_OP(OP_TEQ, "teq"),
CMP_OP(OP_TST, "tst"),
0xffe000f0, 0x00a00090, ARMDEC_MUL, "umlal",
0xffe000f0, 0x00800090, ARMDEC_MUL, "umull",
// End marker.
0x00000000, 0x00000000, ARMDEC_INVALID, NULL,
};
BOOL
ArmMachineInfo::Disassemble(ProcessInfo* Process,
PADDR Addr, PSTR Buffer, BOOL EffAddr)
{
ARMI Instr;
m_DisStart = *Addr;
ADDRFLAT(&m_EffAddr, 0);
m_EaSize = 0;
m_BufStart = m_Buf = Buffer;
sprintAddr(&m_Buf, Addr);
*m_Buf++ = ' ';
if (m_Target->
ReadAllVirtual(Process, Flat(*Addr), &Instr, sizeof(Instr)) != S_OK)
{
AddrAdd(Addr, 4);
if (!(g_AsmOptions & DEBUG_ASMOPT_NO_CODE_BYTES))
{
BufferString("???????? ");
}
BufferString("???\n");
*m_Buf = 0;
return FALSE;
}
m_ArgCol = 19;
if (!(g_AsmOptions & DEBUG_ASMOPT_NO_CODE_BYTES))
{
BufferHex(Instr.instruction, 8, FALSE);
*m_Buf++ = ' ';
*m_Buf++ = ' ';
m_ArgCol += 10;
}
//
// All of the condition bits are AND'ed before being
// used to search the decode table. This allows simple
// matching and filtering for unconditional instructions.
//
ULONG InstrBits = Instr.instruction;
if ((InstrBits & COND_MASK) != COND_NV)
{
InstrBits &= ~COND_MASK;
}
ArmDecode* Decode = g_ArmDecode;
while (Decode->Mask)
{
if ((InstrBits & Decode->Mask) == Decode->Encoded)
{
break;
}
Decode++;
}
if (!Decode->Mask || Decode->Op == ARMDEC_UNDEF)
{
BufferString("???");
}
else
{
BufferString(Decode->Name);
BufferCond(Instr.instruction & COND_MASK);
switch(Decode->Op)
{
case ARMDEC_ARTH_IMM:
case ARMDEC_ARTH_ISHF:
case ARMDEC_ARTH_RSHF:
DisArmArth(Decode, &Instr);
break;
case ARMDEC_BI:
DisArmBi(Decode, &Instr);
break;
case ARMDEC_BKPT:
DisArmBkpt(Decode, &Instr);
break;
case ARMDEC_BXI:
DisArmBxi(Decode, &Instr);
break;
case ARMDEC_BXR:
DisArmBxr(Decode, &Instr);
break;
case ARMDEC_CDP:
DisArmCdp(Decode, &Instr);
break;
case ARMDEC_CLZ:
DisArmClz(Decode, &Instr);
break;
case ARMDEC_CMP_IMM:
case ARMDEC_CMP_ISHF:
case ARMDEC_CMP_RSHF:
DisArmCmp(Decode, &Instr);
break;
case ARMDEC_LDC:
DisArmLdc(Decode, &Instr);
break;
case ARMDEC_LDM:
DisArmLdm(Decode, &Instr);
break;
case ARMDEC_LDR_IMM:
case ARMDEC_LDR_RSHF:
DisArmLdr(Decode, &Instr);
break;
case ARMDEC_LDRH_IMM:
case ARMDEC_LDRH_REG:
DisArmLdrh(Decode, &Instr);
break;
case ARMDEC_MCR:
case ARMDEC_MRC:
DisArmMcr(Decode, &Instr);
break;
case ARMDEC_MCRR:
case ARMDEC_MRRC:
DisArmMcrr(Decode, &Instr);
break;
case ARMDEC_MOV_IMM:
case ARMDEC_MOV_ISHF:
case ARMDEC_MOV_RSHF:
DisArmMov(Decode, &Instr);
break;
case ARMDEC_MRS:
DisArmMrs(Decode, &Instr);
break;
case ARMDEC_MSR_IMM:
case ARMDEC_MSR_REG:
DisArmMsr(Decode, &Instr);
break;
case ARMDEC_MUL:
DisArmMul(Decode, &Instr);
break;
case ARMDEC_QADD:
DisArmQadd(Decode, &Instr);
break;
case ARMDEC_SMLA:
DisArmSmla(Decode, &Instr);
break;
case ARMDEC_SMLAL:
DisArmSmlal(Decode, &Instr);
break;
case ARMDEC_SMUL:
DisArmSmul(Decode, &Instr);
break;
case ARMDEC_SWI:
DisArmSwi(Decode, &Instr);
break;
case ARMDEC_SWP:
DisArmSwp(Decode, &Instr);
break;
default:
BufferString("** ARM diassembly bug **");
break;
}
}
*m_Buf++ = '\n';
*m_Buf = 0;
AddrAdd(Addr, 4);
return TRUE;
}
void
ArmMachineInfo::DisArmArth(ArmDecode* Decode, PARMI Instr)
{
if (Instr->dataproc.s)
{
*m_Buf++ = 's';
}
BufferBlanks(m_ArgCol);
BufferRegName(Instr->dataproc.rd);
*m_Buf++ = ',';
*m_Buf++ = ' ';
BufferRegName(Instr->dataproc.rn);
BufferArmDpArg(Instr);
}
void
ArmMachineInfo::DisArmBi(ArmDecode* Decode, PARMI Instr)
{
BufferBlanks(m_ArgCol);
BufferEffectiveAddress(Flat(m_DisStart) + 8 +
((LONG)Instr->bl.offset << 2), 4);
}
void
ArmMachineInfo::DisArmBkpt(ArmDecode* Decode, PARMI Instr)
{
BufferBlanks(m_ArgCol);
*m_Buf++ = '#';
*m_Buf++ = '0';
*m_Buf++ = 'x';
BufferHex((Instr->bkpt.immed2 << 4) || Instr->bkpt.immed1,
4, FALSE);
}
void
ArmMachineInfo::DisArmBxi(ArmDecode* Decode, PARMI Instr)
{
BufferBlanks(m_ArgCol);
BufferEffectiveAddress(Flat(m_DisStart) + 8 +
((LONG)Instr->blxi.offset << 2) +
(Instr->blxi.h << 1), 4);
}
void
ArmMachineInfo::DisArmBxr(ArmDecode* Decode, PARMI Instr)
{
BufferBlanks(m_ArgCol);
BufferRegName(Instr->bx.rn);
}
void
ArmMachineInfo::DisArmCdp(ArmDecode* Decode, PARMI Instr)
{
BufferBlanks(m_ArgCol);
*m_Buf++ = 'p';
BufferInt(Instr->cpdo.cpn, 0, FALSE);
*m_Buf++ = ',';
*m_Buf++ = ' ';
BufferInt(Instr->cpdo.cpop, 0, FALSE);
*m_Buf++ = ',';
*m_Buf++ = ' ';
*m_Buf++ = 'c';
BufferInt(Instr->cpdo.crd, 0, FALSE);
*m_Buf++ = ',';
*m_Buf++ = ' ';
*m_Buf++ = 'c';
BufferInt(Instr->cpdo.crn, 0, FALSE);
*m_Buf++ = ',';
*m_Buf++ = ' ';
*m_Buf++ = 'c';
BufferInt(Instr->cpdo.crm, 0, FALSE);
*m_Buf++ = ',';
*m_Buf++ = ' ';
BufferInt(Instr->cpdo.cp, 0, FALSE);
}
void
ArmMachineInfo::DisArmClz(ArmDecode* Decode, PARMI Instr)
{
BufferBlanks(m_ArgCol);
BufferRegName(Instr->clz.rd);
*m_Buf++ = ',';
*m_Buf++ = ' ';
BufferRegName(Instr->clz.rm);
}
void
ArmMachineInfo::DisArmCmp(ArmDecode* Decode, PARMI Instr)
{
BufferBlanks(m_ArgCol);
BufferRegName(Instr->dataproc.rn);
BufferArmDpArg(Instr);
}
void
ArmMachineInfo::DisArmLdc(ArmDecode* Decode, PARMI Instr)
{
if (Instr->cpdt.n)
{
*m_Buf++ = 'l';
}
BufferBlanks(m_ArgCol);
*m_Buf++ = 'p';
BufferInt(Instr->cpdt.cpn, 0, FALSE);
*m_Buf++ = ',';
*m_Buf++ = ' ';
*m_Buf++ = 'c';
BufferInt(Instr->cpdt.crd, 0, FALSE);
*m_Buf++ = ',';
*m_Buf++ = ' ';
*m_Buf++ = '[';
BufferRegName(Instr->cpdt.rn);
if (!Instr->cpdt.p)
{
*m_Buf++ = ']';
}
if (Instr->cpdt.offset)
{
*m_Buf++ = ',';
*m_Buf++ = ' ';
*m_Buf++ = '#';
*m_Buf++ = '0';
*m_Buf++ = 'x';
BufferHex(Instr->cpdt.offset, 2, FALSE);
}
if (Instr->cpdt.p)
{
*m_Buf++ = ']';
}
if (Instr->cpdt.w)
{
*m_Buf++ = '!';
}
}
void
ArmMachineInfo::DisArmLdm(ArmDecode* Decode, PARMI Instr)
{
ULONG i;
BOOL Separate = FALSE;
if (Instr->ldm.rn == ARM_SP)
{
*m_Buf++ = Instr->ldm.p ? 'e' : 'f';
*m_Buf++ = Instr->ldm.u ? 'd' : 'a';
}
else
{
*m_Buf++ = Instr->ldm.u ? 'i' : 'd';
*m_Buf++ = Instr->ldm.p ? 'b' : 'a';
}
BufferBlanks(m_ArgCol);
BufferRegName(Instr->ldm.rn);
if (Instr->ldm.w)
{
*m_Buf++ = '!';
}
*m_Buf++ = ',';
*m_Buf++ = ' ';
*m_Buf++ = '{';
for (i = 0; i < 16; i++)
{
if (Instr->ldm.reglist & (1 << i))
{
ULONG Len = 0;
if (Separate)
{
*m_Buf++ = ',';
*m_Buf++ = ' ';
}
else
{
Separate = TRUE;
}
BufferRegName(i);
do
{
Len++;
i++;
} while (i < 16 && (Instr->ldm.reglist & (1 << i)));
if (Len > 1)
{
if (Len > 2)
{
*m_Buf++ = ' ';
*m_Buf++ = '-';
}
else
{
*m_Buf++ = ',';
}
*m_Buf++ = ' ';
BufferRegName(i - 1);
}
}
}
*m_Buf++ = '}';
if (Instr->ldm.s)
{
*m_Buf++ = '^';
}
}
void
ArmMachineInfo::DisArmLdr(ArmDecode* Decode, PARMI Instr)
{
if (Instr->ldr.b)
{
*m_Buf++ = 'b';
}
if (!Instr->ldr.p && Instr->ldr.w)
{
*m_Buf++ = 't';
}
BufferBlanks(m_ArgCol);
BufferRegName(Instr->ldr.rd);
*m_Buf++ = ',';
*m_Buf++ = ' ';
*m_Buf++ = '[';
BufferRegName(Instr->ldr.rn);
if (Instr->ldr.p)
{
if (Instr->ldr.offset)
{
*m_Buf++ = ',';
*m_Buf++ = ' ';
if (!Instr->ldr.i)
{
*m_Buf++ = '#';
if (!Instr->ldr.u)
{
*m_Buf++ = '-';
}
*m_Buf++ = '0';
*m_Buf++ = 'x';
BufferHex(Instr->ldr.offset, 3, FALSE);
}
else
{
*m_Buf++ = Instr->ldr.u ? '+' : '-';
BufferArmShift(Instr->ldr.offset);
}
}
*m_Buf++ = ']';
}
else
{
*m_Buf++ = ']';
*m_Buf++ = ',';
*m_Buf++ = ' ';
if (!Instr->ldr.i)
{
*m_Buf++ = '#';
if (!Instr->ldr.u)
{
*m_Buf++ = '-';
}
*m_Buf++ = '0';
*m_Buf++ = 'x';
BufferHex(Instr->ldr.offset, 3, FALSE);
}
else
{
*m_Buf++ = Instr->ldr.u ? '+' : '-';
BufferArmShift(Instr->ldr.offset);
}
}
if (Instr->ldr.w)
{
*m_Buf++ = '!';
}
}
void
ArmMachineInfo::DisArmLdrh(ArmDecode* Decode, PARMI Instr)
{
if (!Instr->miscdt.l && Instr->miscdt.s)
{
*m_Buf++ = 'd';
}
else
{
if (Instr->miscdt.s)
{
*m_Buf++ = 's';
}
*m_Buf++ = Instr->miscdt.h ? 'h' : 'b';
}
BufferBlanks(m_ArgCol);
BufferRegName(Instr->miscdt.rd);
*m_Buf++ = ',';
*m_Buf++ = ' ';
*m_Buf++ = '[';
BufferRegName(Instr->miscdt.rn);
if (!Instr->miscdt.p)
{
*m_Buf++ = ']';
}
if (Instr->miscdt.i)
{
ULONG Offset =
(Instr->miscdt.operand2 << 4) | Instr->miscdt.operand1;
if (Offset)
{
*m_Buf++ = ',';
*m_Buf++ = ' ';
*m_Buf++ = '#';
if (!Instr->miscdt.u)
{
*m_Buf++ = '-';
}
*m_Buf++ = '0';
*m_Buf++ = 'x';
BufferHex(Offset, 2, FALSE);
}
}
else
{
*m_Buf++ = ',';
*m_Buf++ = ' ';
*m_Buf++ = Instr->miscdt.u ? '+' : '-';
BufferRegName(Instr->miscdt.operand1);
}
if (Instr->miscdt.p)
{
*m_Buf++ = ']';
if (Instr->miscdt.w)
{
*m_Buf++ = '!';
}
}
}
void
ArmMachineInfo::DisArmMcr(ArmDecode* Decode, PARMI Instr)
{
BufferBlanks(m_ArgCol);
*m_Buf++ = 'p';
BufferInt(Instr->cprt.cpn, 0, FALSE);
*m_Buf++ = ',';
*m_Buf++ = ' ';
BufferInt(Instr->cprt.cpop, 0, FALSE);
*m_Buf++ = ',';
*m_Buf++ = ' ';
BufferRegName(Instr->cprt.rd);
*m_Buf++ = ',';
*m_Buf++ = ' ';
*m_Buf++ = 'c';
BufferInt(Instr->cprt.crn, 0, FALSE);
*m_Buf++ = ',';
*m_Buf++ = ' ';
*m_Buf++ = 'c';
BufferInt(Instr->cprt.crm, 0, FALSE);
if (Instr->cprt.cp)
{
*m_Buf++ = ',';
*m_Buf++ = ' ';
BufferInt(Instr->cprt.cp, 0, FALSE);
}
}
void
ArmMachineInfo::DisArmMcrr(ArmDecode* Decode, PARMI Instr)
{
BufferBlanks(m_ArgCol);
*m_Buf++ = 'p';
BufferInt(Instr->mcrr.cpn, 0, FALSE);
*m_Buf++ = ',';
*m_Buf++ = ' ';
BufferInt(Instr->mcrr.cpop, 0, FALSE);
*m_Buf++ = ',';
*m_Buf++ = ' ';
BufferRegName(Instr->mcrr.rd);
*m_Buf++ = ',';
*m_Buf++ = ' ';
BufferInt(Instr->mcrr.rn, 0, FALSE);
*m_Buf++ = ',';
*m_Buf++ = ' ';
*m_Buf++ = 'c';
BufferInt(Instr->mcrr.crm, 0, FALSE);
}
void
ArmMachineInfo::DisArmMov(ArmDecode* Decode, PARMI Instr)
{
if (Instr->dataproc.s)
{
*m_Buf++ = 's';
}
BufferBlanks(m_ArgCol);
BufferRegName(Instr->dataproc.rd);
BufferArmDpArg(Instr);
}
void
ArmMachineInfo::DisArmMrs(ArmDecode* Decode, PARMI Instr)
{
BufferBlanks(m_ArgCol);
BufferRegName(Instr->dpmrs.rd);
*m_Buf++ = ',';
*m_Buf++ = ' ';
BufferString("psr");
}
void
ArmMachineInfo::DisArmMsr(ArmDecode* Decode, PARMI Instr)
{
BufferBlanks(m_ArgCol);
BufferString("psr_");
if (Instr->dpmsr.fc)
{
*m_Buf++ = 'c';
}
if (Instr->dpmsr.fx)
{
*m_Buf++ = 'x';
}
if (Instr->dpmsr.fs)
{
*m_Buf++ = 's';
}
if (Instr->dpmsr.ff)
{
*m_Buf++ = 'f';
}
if (Instr->dpmsr.i)
{
BufferArmDpArg(Instr);
}
else
{
*m_Buf++ = ',';
*m_Buf++ = ' ';
BufferRegName(Instr->dpmsr.operand & 0xf);
}
}
void
ArmMachineInfo::DisArmMul(ArmDecode* Decode, PARMI Instr)
{
if (Instr->mul.s)
{
*m_Buf++ = 's';
}
BufferBlanks(m_ArgCol);
if (Instr->mul.lng)
{
BufferRegName(Instr->mul.rn);
*m_Buf++ = ',';
*m_Buf++ = ' ';
}
BufferRegName(Instr->mul.rd);
*m_Buf++ = ',';
*m_Buf++ = ' ';
BufferRegName(Instr->mul.rm);
*m_Buf++ = ',';
*m_Buf++ = ' ';
BufferRegName(Instr->mul.rs);
if (Instr->mul.a && !Instr->mul.lng)
{
*m_Buf++ = ',';
*m_Buf++ = ' ';
BufferRegName(Instr->mul.rn);
}
}
void
ArmMachineInfo::DisArmQadd(ArmDecode* Decode, PARMI Instr)
{
BufferBlanks(m_ArgCol);
BufferRegName(Instr->qadd.rd);
*m_Buf++ = ',';
*m_Buf++ = ' ';
BufferRegName(Instr->qadd.rm);
*m_Buf++ = ',';
*m_Buf++ = ' ';
BufferRegName(Instr->qadd.rn);
}
void
ArmMachineInfo::DisArmSmla(ArmDecode* Decode, PARMI Instr)
{
if (strcmp(Decode->Name, "smlaw"))
{
*m_Buf++ = Instr->smla.x ? 't' : 'b';
}
*m_Buf++ = Instr->smla.y ? 't' : 'b';
BufferBlanks(m_ArgCol);
BufferRegName(Instr->smla.rd);
*m_Buf++ = ',';
*m_Buf++ = ' ';
BufferRegName(Instr->smla.rm);
*m_Buf++ = ',';
*m_Buf++ = ' ';
BufferRegName(Instr->smla.rs);
*m_Buf++ = ',';
*m_Buf++ = ' ';
BufferRegName(Instr->smla.rn);
}
void
ArmMachineInfo::DisArmSmlal(ArmDecode* Decode, PARMI Instr)
{
*m_Buf++ = Instr->smla.x ? 't' : 'b';
*m_Buf++ = Instr->smla.y ? 't' : 'b';
BufferBlanks(m_ArgCol);
BufferRegName(Instr->smlal.rdlo);
*m_Buf++ = ',';
*m_Buf++ = ' ';
BufferRegName(Instr->smlal.rdhi);
*m_Buf++ = ',';
*m_Buf++ = ' ';
BufferRegName(Instr->smlal.rm);
*m_Buf++ = ',';
*m_Buf++ = ' ';
BufferRegName(Instr->smlal.rs);
}
void
ArmMachineInfo::DisArmSmul(ArmDecode* Decode, PARMI Instr)
{
if (strcmp(Decode->Name, "smulw"))
{
*m_Buf++ = Instr->smul.x ? 't' : 'b';
}
*m_Buf++ = Instr->smul.y ? 't' : 'b';
BufferBlanks(m_ArgCol);
BufferRegName(Instr->smul.rd);
*m_Buf++ = ',';
*m_Buf++ = ' ';
BufferRegName(Instr->smul.rm);
*m_Buf++ = ',';
*m_Buf++ = ' ';
BufferRegName(Instr->smlal.rs);
}
void
ArmMachineInfo::DisArmSwi(ArmDecode* Decode, PARMI Instr)
{
BufferBlanks(m_ArgCol);
*m_Buf++ = '#';
*m_Buf++ = '0';
*m_Buf++ = 'x';
BufferHex(Instr->swi.comment, 6, FALSE);
}
void
ArmMachineInfo::DisArmSwp(ArmDecode* Decode, PARMI Instr)
{
if (Instr->swp.b)
{
*m_Buf++ = 'b';
}
BufferBlanks(m_ArgCol);
BufferRegName(Instr->swp.rd);
*m_Buf++ = ',';
*m_Buf++ = ' ';
BufferRegName(Instr->swp.rm);
*m_Buf++ = ',';
*m_Buf++ = ' ';
*m_Buf++ = '[';
BufferRegName(Instr->swp.rn);
*m_Buf++ = ']';
}
void
ArmMachineInfo::BufferEffectiveAddress(ULONG64 Offset, ULONG Size)
{
CHAR Symbol[MAX_SYMBOL_LEN];
ULONG64 Disp;
GetSymbol(Offset, Symbol, sizeof(Symbol), &Disp);
if (Symbol[0])
{
BufferString(Symbol);
if (Disp)
{
*m_Buf++ = '+';
*m_Buf++ = '0';
*m_Buf++ = 'x';
BufferHex(Disp, 8, TRUE);
}
*m_Buf++ = ' ';
*m_Buf++ = '(';
BufferHex(Offset, 8, FALSE);
*m_Buf++ = ')';
}
else
{
BufferHex(Offset, 8, FALSE);
}
// Save EA.
ADDRFLAT(&m_EffAddr, Offset);
m_EaSize = Size;
}
void
ArmMachineInfo::BufferArmDpArg(PARMI Instr)
{
*m_Buf++ = ',';
*m_Buf++ = ' ';
if (Instr->dataproc.bits & 1)
{
ULONG64 Immed;
*m_Buf++ = '#';
*m_Buf++ = '0';
*m_Buf++ = 'x';
// The immediate forms takes the low 8 bits as an unsigned
// value and rotates it right by twice the upper 4 bits to
// form a 32-bit immediate.
// Emulate the rotate by shifting a 64-bit value and piecing
// together the appropriate parts.
Immed = (((ULONG64)(Instr->dataproc.operand2 & 0xff)) << 32) >>
((Instr->dataproc.operand2 >> 7) & 0x1e);
BufferHex((ULONG)((Immed & 0xffffffff) | (Immed >> 32)), 8, FALSE);
}
else
{
BufferArmShift(Instr->dataproc.operand2);
}
}
void
ArmMachineInfo::BufferArmShift(ULONG Shift)
{
ULONG Op = (Shift >> 5) & 3;
ULONG Amount = (Shift >> 7) & 0x1f;
if (Op == 3 && !(Shift & 0x10) && Amount == 0)
{
// ror #0 is replaced by rrx.
Op = 4;
}
BufferRegName(Shift & 0xf);
if (Op == 0 && Amount == 0)
{
// No shift.
return;
}
*m_Buf++ = ',';
*m_Buf++ = ' ';
BufferString(g_ArmShift[Op]);
*m_Buf++ = ' ';
if (Shift & 0x10)
{
DBG_ASSERT(!(Shift & 0x80));
BufferRegName((Shift >> 8) & 0xf);
}
else
{
if ((Op == 1 || Op == 2) && Amount == 0)
{
// lsr #0 and asr #0 are actually [la]sr #32.
Amount = 32;
}
*m_Buf++ = '#';
BufferInt(Amount, 0, FALSE);
}
}
void
ArmMachineInfo::BufferRegName(ULONG Reg)
{
PCSTR Name = RegNameFromIndex(Reg + ARM_INT_FIRST);
if (Name)
{
BufferString(Name);
}
else
{
BufferString("ArmMachineInfo::BufferRegName invalid arg");
}
}
void
ArmMachineInfo::BufferCond(ULONG Cond)
{
if (Cond != COND_AL && Cond != COND_NV)
{
BufferString(g_ArmCond[Cond >> COND_SHIFT]);
}
}
BOOL
ArmMachineInfo::IsBreakpointInstruction(ProcessInfo* Process, PADDR Addr)
{
// XXX drewb - Presumably some form of BKPT, but what?
return FALSE;
}
HRESULT
ArmMachineInfo::InsertBreakpointInstruction(PUSER_DEBUG_SERVICES Services,
ULONG64 Process,
ULONG64 Offset,
ULONG Flags,
PUCHAR SaveInstr,
PULONG64 ChangeStart,
PULONG ChangeLen)
{
if (Flags != IBI_DEFAULT)
{
return E_INVALIDARG;
}
return E_NOTIMPL;
}
HRESULT
ArmMachineInfo::RemoveBreakpointInstruction(PUSER_DEBUG_SERVICES Services,
ULONG64 Process,
ULONG64 Offset,
PUCHAR SaveInstr,
PULONG64 ChangeStart,
PULONG ChangeLen)
{
return E_NOTIMPL;
}
void
ArmMachineInfo::AdjustPCPastBreakpointInstruction(PADDR Addr,
ULONG BreakType)
{
DBG_ASSERT(BreakType == DEBUG_BREAKPOINT_CODE);
AddrAdd(Addr, 4);
SetPC(Addr);
}
BOOL
ArmMachineInfo::IsCallDisasm(PCSTR Disasm)
{
// XXX.
return FALSE;
}
BOOL
ArmMachineInfo::IsReturnDisasm(PCSTR Disasm)
{
// XXX.
return FALSE;
}
BOOL
ArmMachineInfo::IsSystemCallDisasm(PCSTR Disasm)
{
// XXX.
return FALSE;
}
BOOL
ArmMachineInfo::IsDelayInstruction(PADDR Addr)
{
// ARM does not have delay slots.
return FALSE;
}
void
ArmMachineInfo::GetEffectiveAddr(PADDR Addr, PULONG Size)
{
*Addr = m_EffAddr;
*Size = m_EaSize;
}
BOOL
ArmCheckConditionCodes(
PARM_CONTEXT Context,
DWORD instr
)
/*++
Routine Description:
Checks the condition codes of the instruction and the values of the
condition flags in the current program status register, and determines
whether or not the instruction will be executed.
Return Value:
TRUE if the instruction will be executed, FALSE otherwise.
--*/
{
BOOL Execute = FALSE;
BOOL Nset = (Context->Psr & 0x80000000L) == 0x80000000L;
BOOL Zset = (Context->Psr & 0x40000000L) == 0x40000000L;
BOOL Cset = (Context->Psr & 0x20000000L) == 0x20000000L;
BOOL Vset = (Context->Psr & 0x10000000L) == 0x10000000L;
instr &= COND_MASK;
switch( instr )
{
case COND_EQ: // Z set
if ( Zset ) Execute = TRUE;
break;
case COND_NE: // Z clear
if ( !Zset ) Execute = TRUE;
break;
case COND_CS: // C set
if ( Cset ) Execute = TRUE;
break;
case COND_CC: // C clear
if ( !Cset ) Execute = TRUE;
break;
case COND_MI: // N set
if ( Nset ) Execute = TRUE;
break;
case COND_PL: // N clear
if ( !Nset ) Execute = TRUE;
break;
case COND_VS: // V set
if ( Vset ) Execute = TRUE;
break;
case COND_VC: // V clear
if ( !Vset ) Execute = TRUE;
break;
case COND_HI: // C set and Z clear
if ( Cset && !Zset ) Execute = TRUE;
break;
case COND_LS: // C clear or Z set
if ( !Cset || Zset ) Execute = TRUE;
break;
case COND_GE: // N == V
if (( Nset && Vset ) || ( !Nset && !Vset )) Execute = TRUE;
break;
case COND_LT: // N != V
if (( Nset && !Vset ) || ( !Nset && Vset )) Execute = TRUE;
break;
case COND_GT: // Z clear, and N == V
if ( !Zset &&
(( Nset && Vset ) || ( !Nset && !Vset ))) Execute = TRUE;
break;
case COND_LE: // Z set, and N != V
if ( Zset &&
(( Nset && !Vset ) || ( !Nset && Vset ))) Execute = TRUE;
break;
case COND_AL: // Always execute
case COND_NV:
Execute = TRUE;
break;
default:
DBG_ASSERT(FALSE);
break;
}
return Execute;
}
void
ArmMachineInfo::GetNextOffset(ProcessInfo* Process,
BOOL StepOver,
PADDR NextAddr, PULONG NextMachine)
{
ARMI instr;
PULONG Register = &m_Context.ArmContext.R0;
ULONG returnvalue;
BOOL QualifyReturnAddress = FALSE; // ADDED for ARM WINCE, fixes up LR
BOOL Ldm_instr = FALSE;
*NextMachine = m_ExecTypes[0];
GetPC(NextAddr);
if (m_Target->ReadAllVirtual(Process, Flat(*NextAddr), &instr.instruction,
sizeof(instr.instruction)) != S_OK)
{
// Couldn't read the instruction so just return the
// next offset.
AddrAdd(NextAddr, 4);
return;
}
//
// We are only testing for data processing, load multiple, bx and bl
// instructions. We might have to check regular loads and stores that
// have the PC as the destination.
//
if (!ArmCheckConditionCodes(&m_Context.ArmContext, instr.instruction))
{
//
// Instruction will not be executed. Bump PC normally.
//
AddrAdd(NextAddr, 4);
return;
}
if (( instr.instruction & BX_MASK ) == BX_INSTR )
{
ULONG Rn;
//
// Check Rn (lower 4 bits). To compute the target address:
// Mask out the T bit. We don't care if we're transferring to Thumb
// Shift bits 31-1 left 1 bit.
//
Rn = Register[ instr.bx.rn ];
Rn &= 0xfffffffe;
returnvalue = Rn << 1;
}
else if (( instr.instruction & DATA_PROC_MASK ) == DP_PC_INSTR )
{
ULONG Op1, Op2;
ULONG Cflag = (m_Context.ArmContext.Psr & 0x20000000L) == 0x20000000L;
ULONG shift;
//
// We are not making sure that data processing instructions are not the
// multiply instructions, because we are checking to make sure that the
// PC is the destination register. The PC is not a legal destination
// register on multiply instructions.
//
// Currently only the MOV instruction (returns, branches) and the ADDLS
// instruction (switch statement) are used. Both of these instructions
// use the addressing mode "Register, Logical shift left by immediate."
// I'm leaving the other cases in case they are used in the future.
//
//
// Figure out the addressing mode (there are 11 of them), and get the
// operands.
//
Op1 = Register[ instr.dataproc.rn ];
if ( instr.dataproc.rn == 15 )
{
//
// If this is the PC, add 8.
//
Op1 += 8;
}
if ( instr.dataproc.bits == 0x1 )
{
//
// Immediate addressing - Type 1
//
Op2 = _lrotr( instr.dpi.immediate, instr.dpi.rotate * 2 );
}
else
{
//
// Register addressing - start by getting the value of Rm.
//
Op2 = Register[ instr.dpshi.rm ];
if ( instr.dpshi.rm == 15 )
{
//
// If this is the PC, add 8.
//
Op2 += 8;
}
if ( instr.dprre.bits == 0x6 )
{
//
// Rotate right with extended - Type 11
//
Op2 = ( Cflag << 31 ) | ( Op2 >> 1 );
}
else if ( instr.dataproc.operand2 & 0x10 )
{
//
// Register shifts. Types 4, 6, 8, and 10
//
//
// Get the shift value from the least-significant byte of the
// shift register.
//
shift = Register[ instr.dpshr.rs ];
shift &= 0xff;
switch( instr.dpshr.bits )
{
case 0x1: // 4 Logical shift left by register
if ( shift >= 32 )
{
Op2 = 0;
}
else
{
Op2 = Op2 << shift;
}
break;
case 0x3: // 6 Logical shift right by register
if ( shift >= 32 )
{
Op2 = 0;
}
else
{
Op2 = Op2 >> shift;
}
break;
case 0x5: // 8 Arithmetic shift right by register
if ( shift >= 32 )
{
if ( Op2 & 0x80000000 )
{
Op2 = 0xffffffff;
}
else
{
Op2 = 0;
}
}
else
{
Op2 = (LONG)Op2 >> shift;
}
break;
case 0x7: // 10 Rotate right by register
if ( !( shift == 0 ) && !(( shift & 0xf ) == 0 ) )
{
Op2 = _lrotl( Op2, shift );
}
break;
default:
break;
}
}
else
{
//
// Immediate shifts. Types 2, 3, 5, 7, and 9
//
//
// Get the shift value from the instruction.
//
shift = instr.dpshi.shift;
switch( instr.dpshi.bits )
{
case 0x0: // 2,3 Register, Logical shift left by immediate
if ( shift != 0 )
{
Op2 = Op2 << shift;
}
break;
case 0x2: // 5 Logical shift right by immediate
if ( shift == 0 )
{
Op2 = 0;
}
else
{
Op2 = Op2 >> shift;
}
break;
case 0x4: // 7 Arithmetic shift right by immediate
if ( shift == 0 )
{
Op2 = 0;
}
else
{
Op2 = (LONG)Op2 >> shift;
}
break;
case 0x6: // 9 Rotate right by immediate
Op2 = _lrotl( Op2, shift );
break;
default:
break;
}
}
}
//
// Determine the result (the new PC), based on the opcode.
//
switch( instr.dataproc.opcode )
{
case OP_AND:
returnvalue = Op1 & Op2;
break;
case OP_EOR:
returnvalue = Op1 ^ Op2;
break;
case OP_SUB:
returnvalue = Op1 - Op2;
break;
case OP_RSB:
returnvalue = Op2 - Op1;
break;
case OP_ADD:
returnvalue = Op1 + Op2;
break;
case OP_ADC:
returnvalue = (Op1 + Op2) + Cflag;
break;
case OP_SBC:
returnvalue = (Op1 - Op2) - ~Cflag;
break;
case OP_RSC:
returnvalue = (Op2 - Op1) - ~Cflag;
break;
case OP_ORR:
returnvalue = Op1 | Op2;
break;
case OP_MOV:
if (( instr.dataproc.operand2 != 0xe ) && StepOver )
{
//
// A move from any register but LR to the PC is a call.
// We are stepping over, so bump the PC normally.
//
returnvalue = (ULONG)Flat(*NextAddr) + sizeof(ARMI);
}
else
{
//ie: mov pc, lr
returnvalue = Op2;
//[Moonshot 6841]: fix up the LR reg.
QualifyReturnAddress = TRUE;
}
break;
case OP_BIC:
returnvalue = Op1 & ~Op2;
break;
case OP_MVN:
returnvalue = ~Op2;
break;
case OP_TST:
case OP_TEQ:
case OP_CMP:
case OP_CMN:
default:
//
// This really isn't a branch. Bump the PC normally.
//
returnvalue = (ULONG)Flat(*NextAddr) + sizeof(ARMI);
break;
}
}
else if (( instr.instruction & LDM_PC_MASK ) == LDM_PC_INSTR )
{
// ie: ldmia sp!, {pc}
// Load multiple with the PC bit set. We don't need to check the
// step over flag in this case, because a load multiple is never a
// call, only a return.
//
ULONG RegList, i, count = 0, Rn;
//
// Get the address from Rn.
//
Rn = Register[ instr.ldm.rn ];
if ( instr.ldm.u )
{
//
// Increment the address. Check to see how many other registers
// are to be read.
//
RegList = instr.ldm.reglist;
for ( i = 0; i < 15; i++ )
{
if ( RegList & 0x1 ) count++;
RegList = RegList >> 1;
}
//
// Check the p bit to see how big to make the offset to the PC.
//
if ( instr.ldm.p )
{
// Before
count = (count + 1) * sizeof(ARMI);
}
else
{
// After
count = count * sizeof(ARMI);
}
Rn += count;
}
else
{
//
// Decrement the address. If we decrement before, we need to
// subract the instruction size now. Otherwise, do nothing.
//
if ( instr.ldm.p )
{
// Before
Rn -= sizeof(ARMI);
}
}
// reading values from the stack
if (m_Target->ReadAllVirtual(Process, EXTEND64(Rn), &returnvalue,
sizeof(returnvalue)) != S_OK)
{
// Unable to read, so what should be returned?
returnvalue = (ULONG)Flat(*NextAddr) + sizeof(ARMI);
}
//[Moonshot 6838]: fix up the LR reg.
QualifyReturnAddress = TRUE;
Ldm_instr = TRUE;
}
else if ((( instr.instruction & B_BL_MASK ) == B_INSTR ) ||
(( instr.instruction & B_BL_MASK ) == BL_INSTR ))
{
//
// If this is a call (branch and link), and we are stepping over, the
// next offset is the addr + 8.
//
if ( instr.bl.link && StepOver )
{
returnvalue = (ULONG)Flat(*NextAddr) + sizeof(ARMI);
}
else
{
LONG BranchOffset;
//
// To calculate the branch target:
// Shift the 24-bit offset left 2 bits
// Sign-extend it to 32 bits
// Add it to the contents of the PC
// (Which would be the current address + 8);
//
BranchOffset = instr.bl.offset;
BranchOffset <<= 2;
if( BranchOffset & 0x2000000 )
{
BranchOffset |= 0xfc000000;
}
returnvalue = (ULONG)Flat(*NextAddr) + BranchOffset;
returnvalue += 8;
}
}
else if ( instr.instruction == LDR_THUNK_2 )
{
//
// Need to handle import DLL thunk type branches to destination func Foo
//
// 0001ACA0: ldr r12, [pc] ; pc+8+0 = 0x0001ACA8
// 0001ACA4: ldr pc, [r12]
// 0001ACA8: DCD 0x0001C020 ; This memory location holds the address, of the address, of Foo
//
// 0001C020: DCD Foo ; This memory location holds the address of Foo
//
//
// Get the address of Foo from Rn.
// simple register indirect. no offsets, no scaling, no indexing addressing mode
//
if (m_Target->ReadAllVirtual(Process, EXTEND64(Register[instr.ldr.rn]),
&returnvalue,
sizeof(returnvalue)) != S_OK)
{
// Unable to read, so what should be returned?
returnvalue = (ULONG)Flat(*NextAddr) + sizeof(ARMI);
}
}
else
{
// Bump PC normally
returnvalue = (ULONG)Flat(*NextAddr) + sizeof(ARMI);
}
#if 0
//jvp
//[Moonshot 6838, 6841]: fix up the LR register.
// Taken from the same function in ppcmach.c
// The value we get from the LR register is not necessarily fully
// qualified. In WINCE, when a process is running it is mapped into the
// ZERO slot, meaning that the upper 6 bits contain 0. To fully
// qualify an address, the upper 6 bits contain the current process. The
// LR regs is set at runtime so we need to fix it up so breakpoint
// comparisons make sense.
if (QualifyReturnAddress == TRUE)
{
ULONG Status, NextOffset;
ARMI I1;
ADDR addr;
NextOffset = returnvalue;
ZeroMemory(&addr, sizeof(ADDR));
GetAddrOff(addr) = NextOffset;
TranslateAddress(hthd->hprc, 0, &addr, TRUE);
NextOffset = GetAddrOff(addr);
Status = STATUS_SUCCESS;
//
// Because the next offset translation is meant for NK, the
// stub and simulator will return STATUS_UNSUCCESSFUL.
//
// On a successful transaction our new address will be fully qualified
// otherwise, just leave.
if (Status == STATUS_SUCCESS)
{
if (!Ldm_instr)
{
// DP_PC_INSTR; Moonshot 6841
returnvalue = NextOffset; // fully qualified.
}
//since this is a ldm instruction, it's reading values from the stack;
//so do error checking to make sure that these values must be a valid
//instruction. At this moment, we know that NextOffset contains the address
//of the instruction after the branch instruction (also contains the value
//of LR). So make sure that the previous instruction (from the NextOffset)
//must be a branch instruction.
else if (NextOffset && (!(NextOffset % 4)))
{
AddrInit( &memaddr, 0, 0, NextOffset-4, TRUE, TRUE, FALSE, FALSE );
AddrReadMemory( hthd->hprc, //read previous instruction.
hthd,
&memaddr,
&I1.instruction,
sizeof(ARMI),
&cBytes );
//previous instruction must be a branch instruction.
if ( ((I1.instruction & BX_MASK ) == BX_INSTR ) ||
((I1.instruction & B_BL_MASK ) == B_INSTR) ||
((I1.instruction & B_BL_MASK ) == BL_INSTR) )
{
returnvalue = NextOffset; //fully qualified.
}
}
}
}
{
// make sure a fully fixed up offset is returned
ADDR addr;
DWORD dwTemp;
DWORD dwPC;
BOOL bReturn;
ZeroMemory(&addr, sizeof(ADDR));
GetAddrOff(addr) = returnvalue;
TranslateAddress(hthd->hprc, 0, &addr, TRUE);
if (!StepOver)
{
cBytes = 0;
dwTemp = 0;
returnvalue = GetAddrOff(addr);
bReturn = DbgReadMemory(hthd->hprc,
(LPVOID)returnvalue,
&dwTemp,
sizeof(DWORD),
&cBytes);
if (!bReturn || cBytes != sizeof(DWORD) || dwTemp == 0 )
{
returnvalue = pcaddr.addr.off + sizeof(ARMI);
GetAddrOff(addr) = returnvalue;
TranslateAddress(hthd->hprc, 0, &addr, TRUE);
dwPC = 0;
}
else
{
dwPC = returnvalue;
}
// Now need to find if its a thunk, if yes, we need to
// probe the thunk destination
if ( dwPC )
{
while (IsThunk(hthd, dwPC, NULL, &dwPC, NULL ) && dwPC)
{
GetAddrOff(addr) = dwPC;
TranslateAddress(hthd->hprc, 0, &addr, FALSE);
dwPC = GetAddrOff(addr);
cBytes = 0;
dwTemp = 0;
bReturn = DbgReadMemory(hthd->hprc,
(LPVOID)dwPC,
&dwTemp,
sizeof(DWORD),
&cBytes);
if (!bReturn || cBytes != sizeof(DWORD) || dwTemp == 0 )
{
returnvalue = pcaddr.addr.off + sizeof(ARMI);
GetAddrOff(addr) = returnvalue;
TranslateAddress(hthd->hprc, 0, &addr, TRUE);
break;
}
}
}
}
returnvalue = GetAddrOff(addr);
}
#endif
ADDRFLAT(NextAddr, EXTEND64(returnvalue));
}
void
ArmMachineInfo::IncrementBySmallestInstruction(PADDR Addr)
{
AddrAdd(Addr, 4);
}
void
ArmMachineInfo::DecrementBySmallestInstruction(PADDR Addr)
{
AddrSub(Addr, 4);
}
void
ArmMachineInfo::Assemble(ProcessInfo* Process,
PADDR Address, PSTR Input)
{
// Not going to implement assemble command at this time
ErrOut("No assemble support for ARM\n");
}