diff options
| -rw-r--r-- | src/core/core.vcxproj | 4 | ||||
| -rw-r--r-- | src/core/core.vcxproj.filters | 22 | ||||
| -rw-r--r-- | src/core/src/arm/disassembler/arm_disasm.cpp | 1003 | ||||
| -rw-r--r-- | src/core/src/arm/disassembler/arm_disasm.h | 146 | 
4 files changed, 1175 insertions, 0 deletions
diff --git a/src/core/core.vcxproj b/src/core/core.vcxproj index 22fc96fe2..b413beba9 100644 --- a/src/core/core.vcxproj +++ b/src/core/core.vcxproj @@ -181,8 +181,12 @@      </ProjectReference>    </ItemGroup>    <ItemGroup> +    <ClCompile Include="src\arm\disassembler\arm_disasm.cpp" />      <ClCompile Include="src\core.cpp" />    </ItemGroup> +  <ItemGroup> +    <ClInclude Include="src\arm\disassembler\arm_disasm.h" /> +  </ItemGroup>    <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />    <ImportGroup Label="ExtensionTargets">    </ImportGroup> diff --git a/src/core/core.vcxproj.filters b/src/core/core.vcxproj.filters new file mode 100644 index 000000000..3c0ae8786 --- /dev/null +++ b/src/core/core.vcxproj.filters @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> +  <ItemGroup> +    <ClCompile Include="src\core.cpp" /> +    <ClCompile Include="src\arm\disassembler\arm_disasm.cpp"> +      <Filter>arm\disassembler</Filter> +    </ClCompile> +  </ItemGroup> +  <ItemGroup> +    <Filter Include="arm"> +      <UniqueIdentifier>{b84ab55c-588b-45f0-a5ba-f9ebb0442f13}</UniqueIdentifier> +    </Filter> +    <Filter Include="arm\disassembler"> +      <UniqueIdentifier>{61100188-a726-4024-ab16-95ee242b446e}</UniqueIdentifier> +    </Filter> +  </ItemGroup> +  <ItemGroup> +    <ClInclude Include="src\arm\disassembler\arm_disasm.h"> +      <Filter>arm\disassembler</Filter> +    </ClInclude> +  </ItemGroup> +</Project>
\ No newline at end of file diff --git a/src/core/src/arm/disassembler/arm_disasm.cpp b/src/core/src/arm/disassembler/arm_disasm.cpp new file mode 100644 index 000000000..82571a681 --- /dev/null +++ b/src/core/src/arm/disassembler/arm_disasm.cpp @@ -0,0 +1,1003 @@ +// Copyright 2006 The Android Open Source Project + +#include <stdio.h> +#include <string.h> +#include "arm_disasm.h" + +static const char *cond_names[] = { +    "eq", +    "ne", +    "cs", +    "cc", +    "mi", +    "pl", +    "vs", +    "vc", +    "hi", +    "ls", +    "ge", +    "lt", +    "gt", +    "le", +    "", +    "RESERVED" +}; + +const char *opcode_names[] = { +    "invalid", +    "undefined", +    "adc", +    "add", +    "and", +    "b", +    "bl", +    "bic", +    "bkpt", +    "blx", +    "bx", +    "cdp", +    "clz", +    "cmn", +    "cmp", +    "eor", +    "ldc", +    "ldm", +    "ldr", +    "ldrb", +    "ldrbt", +    "ldrh", +    "ldrsb", +    "ldrsh", +    "ldrt", +    "mcr", +    "mla", +    "mov", +    "mrc", +    "mrs", +    "msr", +    "mul", +    "mvn", +    "orr", +    "pld", +    "rsb", +    "rsc", +    "sbc", +    "smlal", +    "smull", +    "stc", +    "stm", +    "str", +    "strb", +    "strbt", +    "strh", +    "strt", +    "sub", +    "swi", +    "swp", +    "swpb", +    "teq", +    "tst", +    "umlal", +    "umull", + +    "undefined", +    "adc", +    "add", +    "and", +    "asr", +    "b", +    "bic", +    "bkpt", +    "bl", +    "blx", +    "bx", +    "cmn", +    "cmp", +    "eor", +    "ldmia", +    "ldr", +    "ldrb", +    "ldrh", +    "ldrsb", +    "ldrsh", +    "lsl", +    "lsr", +    "mov", +    "mul", +    "mvn", +    "neg", +    "orr", +    "pop", +    "push", +    "ror", +    "sbc", +    "stmia", +    "str", +    "strb", +    "strh", +    "sub", +    "swi", +    "tst", + +    NULL +}; + +// Indexed by the shift type (bits 6-5) +static const char *shift_names[] = { +    "LSL", +    "LSR", +    "ASR", +    "ROR" +}; + +static const char* cond_to_str(int cond) { +    return cond_names[cond]; +} + +char *Arm::disasm(uint32_t addr, uint32_t insn, char *result) +{ +    static char   buf[80]; +    char          *ptr; + +    ptr = result ? result : buf; +    Opcode opcode = decode(insn); +    switch (opcode) { +        case OP_INVALID: +            sprintf(ptr, "Invalid"); +            return ptr; +        case OP_UNDEFINED: +            sprintf(ptr, "Undefined"); +            return ptr; +        case OP_ADC: +        case OP_ADD: +        case OP_AND: +        case OP_BIC: +        case OP_CMN: +        case OP_CMP: +        case OP_EOR: +        case OP_MOV: +        case OP_MVN: +        case OP_ORR: +        case OP_RSB: +        case OP_RSC: +        case OP_SBC: +        case OP_SUB: +        case OP_TEQ: +        case OP_TST: +            return disasm_alu(opcode, insn, ptr); +        case OP_B: +        case OP_BL: +            return disasm_branch(addr, opcode, insn, ptr); +        case OP_BKPT: +            return disasm_bkpt(insn, ptr); +        case OP_BLX: +            // not supported yet +            break; +        case OP_BX: +            return disasm_bx(insn, ptr); +        case OP_CDP: +            sprintf(ptr, "cdp"); +            return ptr; +        case OP_CLZ: +            return disasm_clz(insn, ptr); +        case OP_LDC: +            sprintf(ptr, "ldc"); +            return ptr; +        case OP_LDM: +        case OP_STM: +            return disasm_memblock(opcode, insn, ptr); +        case OP_LDR: +        case OP_LDRB: +        case OP_LDRBT: +        case OP_LDRT: +        case OP_STR: +        case OP_STRB: +        case OP_STRBT: +        case OP_STRT: +            return disasm_mem(insn, ptr); +        case OP_LDRH: +        case OP_LDRSB: +        case OP_LDRSH: +        case OP_STRH: +            return disasm_memhalf(insn, ptr); +        case OP_MCR: +        case OP_MRC: +            return disasm_mcr(opcode, insn, ptr); +        case OP_MLA: +            return disasm_mla(opcode, insn, ptr); +        case OP_MRS: +            return disasm_mrs(insn, ptr); +        case OP_MSR: +            return disasm_msr(insn, ptr); +        case OP_MUL: +            return disasm_mul(opcode, insn, ptr); +        case OP_PLD: +            return disasm_pld(insn, ptr); +        case OP_STC: +            sprintf(ptr, "stc"); +            return ptr; +        case OP_SWI: +            return disasm_swi(insn, ptr); +        case OP_SWP: +        case OP_SWPB: +            return disasm_swp(opcode, insn, ptr); +        case OP_UMLAL: +        case OP_UMULL: +        case OP_SMLAL: +        case OP_SMULL: +            return disasm_umlal(opcode, insn, ptr); +        default: +            sprintf(ptr, "Error"); +            return ptr; +    } +    return NULL; +} + +char *Arm::disasm_alu(Opcode opcode, uint32_t insn, char *ptr) +{ +    static const uint8_t kNoOperand1 = 1; +    static const uint8_t kNoDest = 2; +    static const uint8_t kNoSbit = 4; + +    char rn_str[20]; +    char rd_str[20]; +    uint8_t flags = 0; +    uint8_t cond = (insn >> 28) & 0xf; +    uint8_t is_immed = (insn >> 25) & 0x1; +    uint8_t bit_s = (insn >> 20) & 1; +    uint8_t rn = (insn >> 16) & 0xf; +    uint8_t rd = (insn >> 12) & 0xf; +    uint8_t immed = insn & 0xff; + +    const char *opname = opcode_names[opcode]; +    switch (opcode) { +        case OP_CMN: +        case OP_CMP: +        case OP_TEQ: +        case OP_TST: +            flags = kNoDest | kNoSbit; +            break; +        case OP_MOV: +        case OP_MVN: +            flags = kNoOperand1; +            break; +        default: +            break; +    } + +    // The "mov" instruction ignores the first operand (rn). +    rn_str[0] = 0; +    if ((flags & kNoOperand1) == 0) { +        sprintf(rn_str, "r%d, ", rn); +    } + +    // The following instructions do not write the result register (rd): +    // tst, teq, cmp, cmn. +    rd_str[0] = 0; +    if ((flags & kNoDest) == 0) { +        sprintf(rd_str, "r%d, ", rd); +    } + +    const char *sbit_str = ""; +    if (bit_s && !(flags & kNoSbit)) +        sbit_str = "s"; + +    if (is_immed) { +        sprintf(ptr, "%s%s%s\t%s%s#%u  ; 0x%x", +                opname, cond_to_str(cond), sbit_str, rd_str, rn_str, immed, immed); +        return ptr; +    } + +    uint8_t shift_is_reg = (insn >> 4) & 1; +    uint8_t rotate = (insn >> 8) & 0xf; +    uint8_t rm = insn & 0xf; +    uint8_t shift_type = (insn >> 5) & 0x3; +    uint8_t rs = (insn >> 8) & 0xf; +    uint8_t shift_amount = (insn >> 7) & 0x1f; +    uint32_t rotated_val = immed; +    uint8_t rotate2 = rotate << 1; +    rotated_val = (rotated_val >> rotate2) | (rotated_val << (32 - rotate2)); + +    if (!shift_is_reg && shift_type == 0 && shift_amount == 0) { +        sprintf(ptr, "%s%s%s\t%s%sr%d", +                opname, cond_to_str(cond), sbit_str, rd_str, rn_str, rm); +        return ptr; +    } + +    const char *shift_name = shift_names[shift_type]; +    if (shift_is_reg) { +        sprintf(ptr, "%s%s%s\t%s%sr%d, %s r%d", +                opname, cond_to_str(cond), sbit_str, rd_str, rn_str, rm, +                shift_name, rs); +        return ptr; +    } +    if (shift_amount == 0) { +        if (shift_type == 3) { +            sprintf(ptr, "%s%s%s\t%s%sr%d, RRX", +                    opname, cond_to_str(cond), sbit_str, rd_str, rn_str, rm); +            return ptr; +        } +        shift_amount = 32; +    } +    sprintf(ptr, "%s%s%s\t%s%sr%d, %s #%u", +            opname, cond_to_str(cond), sbit_str, rd_str, rn_str, rm, +            shift_name, shift_amount); +    return ptr; +} + +char *Arm::disasm_branch(uint32_t addr, Opcode opcode, uint32_t insn, char *ptr) +{ +    uint8_t cond = (insn >> 28) & 0xf; +    uint32_t offset = insn & 0xffffff; +    // Sign-extend the 24-bit offset +    if ((offset >> 23) & 1) +        offset |= 0xff000000; + +    // Pre-compute the left-shift and the prefetch offset +    offset <<= 2; +    offset += 8; +    addr += offset; +    const char *opname = opcode_names[opcode]; +    sprintf(ptr, "%s%s\t0x%x", opname, cond_to_str(cond), addr); +    return ptr; +} + +char *Arm::disasm_bx(uint32_t insn, char *ptr) +{ +    uint8_t cond = (insn >> 28) & 0xf; +    uint8_t rn = insn & 0xf; +    sprintf(ptr, "bx%s\tr%d", cond_to_str(cond), rn); +    return ptr; +} + +char *Arm::disasm_bkpt(uint32_t insn, char *ptr) +{ +    uint32_t immed = (((insn >> 8) & 0xfff) << 4) | (insn & 0xf); +    sprintf(ptr, "bkpt\t#%d", immed); +    return ptr; +} + +char *Arm::disasm_clz(uint32_t insn, char *ptr) +{ +    uint8_t cond = (insn >> 28) & 0xf; +    uint8_t rd = (insn >> 12) & 0xf; +    uint8_t rm = insn & 0xf; +    sprintf(ptr, "clz%s\tr%d, r%d", cond_to_str(cond), rd, rm); +    return ptr; +} + +char *Arm::disasm_memblock(Opcode opcode, uint32_t insn, char *ptr) +{ +    char tmp_reg[10], tmp_list[80]; + +    uint8_t cond = (insn >> 28) & 0xf; +    uint8_t write_back = (insn >> 21) & 0x1; +    uint8_t bit_s = (insn >> 22) & 0x1; +    uint8_t is_up = (insn >> 23) & 0x1; +    uint8_t is_pre = (insn >> 24) & 0x1; +    uint8_t rn = (insn >> 16) & 0xf; +    uint16_t reg_list = insn & 0xffff; + +    const char *opname = opcode_names[opcode]; + +    const char *bang = ""; +    if (write_back) +        bang = "!"; + +    const char *carret = ""; +    if (bit_s) +        carret = "^"; + +    const char *comma = ""; +    tmp_list[0] = 0; +    for (int ii = 0; ii < 16; ++ii) { +        if (reg_list & (1 << ii)) { +            sprintf(tmp_reg, "%sr%d", comma, ii); +            strcat(tmp_list, tmp_reg); +            comma = ","; +        } +    } + +    const char *addr_mode = ""; +    if (is_pre) { +        if (is_up) { +            addr_mode = "ib"; +        } else { +            addr_mode = "db"; +        } +    } else { +        if (is_up) { +            addr_mode = "ia"; +        } else { +            addr_mode = "da"; +        } +    } + +    sprintf(ptr, "%s%s%s\tr%d%s, {%s}%s", +            opname, cond_to_str(cond), addr_mode, rn, bang, tmp_list, carret); +    return ptr; +} + +char *Arm::disasm_mem(uint32_t insn, char *ptr) +{ +    uint8_t cond = (insn >> 28) & 0xf; +    uint8_t is_reg = (insn >> 25) & 0x1; +    uint8_t is_load = (insn >> 20) & 0x1; +    uint8_t write_back = (insn >> 21) & 0x1; +    uint8_t is_byte = (insn >> 22) & 0x1; +    uint8_t is_up = (insn >> 23) & 0x1; +    uint8_t is_pre = (insn >> 24) & 0x1; +    uint8_t rn = (insn >> 16) & 0xf; +    uint8_t rd = (insn >> 12) & 0xf; +    uint16_t offset = insn & 0xfff; + +    const char *opname = "ldr"; +    if (!is_load) +        opname = "str"; + +    const char *bang = ""; +    if (write_back) +        bang = "!"; + +    const char *minus = ""; +    if (is_up == 0) +        minus = "-"; + +    const char *byte = ""; +    if (is_byte) +        byte = "b"; + +    if (is_reg == 0) { +        if (is_pre) { +            if (offset == 0) { +                sprintf(ptr, "%s%s%s\tr%d, [r%d]", +                        opname, cond_to_str(cond), byte, rd, rn); +            } else { +                sprintf(ptr, "%s%s%s\tr%d, [r%d, #%s%u]%s", +                        opname, cond_to_str(cond), byte, rd, rn, minus, offset, bang); +            } +        } else { +            const char *transfer = ""; +            if (write_back) +                transfer = "t"; +            sprintf(ptr, "%s%s%s%s\tr%d, [r%d], #%s%u", +                    opname, cond_to_str(cond), byte, transfer, rd, rn, minus, offset); +        } +        return ptr; +    } + +    uint8_t rm = insn & 0xf; +    uint8_t shift_type = (insn >> 5) & 0x3; +    uint8_t shift_amount = (insn >> 7) & 0x1f; + +    const char *shift_name = shift_names[shift_type]; + +    if (is_pre) { +        if (shift_amount == 0) { +            if (shift_type == 0) { +                sprintf(ptr, "%s%s%s\tr%d, [r%d, %sr%d]%s", +                        opname, cond_to_str(cond), byte, rd, rn, minus, rm, bang); +                return ptr; +            } +            if (shift_type == 3) { +                sprintf(ptr, "%s%s%s\tr%d, [r%d, %sr%d, RRX]%s", +                        opname, cond_to_str(cond), byte, rd, rn, minus, rm, bang); +                return ptr; +            } +            shift_amount = 32; +        } +        sprintf(ptr, "%s%s%s\tr%d, [r%d, %sr%d, %s #%u]%s", +                opname, cond_to_str(cond), byte, rd, rn, minus, rm, +                shift_name, shift_amount, bang); +        return ptr; +    } + +    const char *transfer = ""; +    if (write_back) +        transfer = "t"; + +    if (shift_amount == 0) { +        if (shift_type == 0) { +            sprintf(ptr, "%s%s%s%s\tr%d, [r%d], %sr%d", +                    opname, cond_to_str(cond), byte, transfer, rd, rn, minus, rm); +            return ptr; +        } +        if (shift_type == 3) { +            sprintf(ptr, "%s%s%s%s\tr%d, [r%d], %sr%d, RRX", +                    opname, cond_to_str(cond), byte, transfer, rd, rn, minus, rm); +            return ptr; +        } +        shift_amount = 32; +    } + +    sprintf(ptr, "%s%s%s%s\tr%d, [r%d], %sr%d, %s #%u", +            opname, cond_to_str(cond), byte, transfer, rd, rn, minus, rm, +            shift_name, shift_amount); +    return ptr; +} + +char *Arm::disasm_memhalf(uint32_t insn, char *ptr) +{ +    uint8_t cond = (insn >> 28) & 0xf; +    uint8_t is_load = (insn >> 20) & 0x1; +    uint8_t write_back = (insn >> 21) & 0x1; +    uint8_t is_immed = (insn >> 22) & 0x1; +    uint8_t is_up = (insn >> 23) & 0x1; +    uint8_t is_pre = (insn >> 24) & 0x1; +    uint8_t rn = (insn >> 16) & 0xf; +    uint8_t rd = (insn >> 12) & 0xf; +    uint8_t bits_65 = (insn >> 5) & 0x3; +    uint8_t rm = insn & 0xf; +    uint8_t offset = (((insn >> 8) & 0xf) << 4) | (insn & 0xf); + +    const char *opname = "ldr"; +    if (is_load == 0) +        opname = "str"; + +    const char *width = ""; +    if (bits_65 == 1) +        width = "h"; +    else if (bits_65 == 2) +        width = "sb"; +    else +        width = "sh"; + +    const char *bang = ""; +    if (write_back) +        bang = "!"; +    const char *minus = ""; +    if (is_up == 0) +        minus = "-"; + +    if (is_immed) { +        if (is_pre) { +            if (offset == 0) { +                sprintf(ptr, "%s%sh\tr%d, [r%d]", opname, cond_to_str(cond), rd, rn); +            } else { +                sprintf(ptr, "%s%sh\tr%d, [r%d, #%s%u]%s", +                        opname, cond_to_str(cond), rd, rn, minus, offset, bang); +            } +        } else { +            sprintf(ptr, "%s%sh\tr%d, [r%d], #%s%u", +                    opname, cond_to_str(cond), rd, rn, minus, offset); +        } +        return ptr; +    } + +    if (is_pre) { +        sprintf(ptr, "%s%sh\tr%d, [r%d, %sr%d]%s", +                opname, cond_to_str(cond), rd, rn, minus, rm, bang); +    } else { +        sprintf(ptr, "%s%sh\tr%d, [r%d], %sr%d", +                opname, cond_to_str(cond), rd, rn, minus, rm); +    } +    return ptr; +} + +char *Arm::disasm_mcr(Opcode opcode, uint32_t insn, char *ptr) +{ +    uint8_t cond = (insn >> 28) & 0xf; +    uint8_t crn = (insn >> 16) & 0xf; +    uint8_t crd = (insn >> 12) & 0xf; +    uint8_t cpnum = (insn >> 8) & 0xf; +    uint8_t opcode2 = (insn >> 5) & 0x7; +    uint8_t crm = insn & 0xf; + +    const char *opname = opcode_names[opcode]; +    sprintf(ptr, "%s%s\t%d, 0, r%d, cr%d, cr%d, {%d}", +            opname, cond_to_str(cond), cpnum, crd, crn, crm, opcode2); +    return ptr; +} + +char *Arm::disasm_mla(Opcode opcode, uint32_t insn, char *ptr) +{ +    uint8_t cond = (insn >> 28) & 0xf; +    uint8_t rd = (insn >> 16) & 0xf; +    uint8_t rn = (insn >> 12) & 0xf; +    uint8_t rs = (insn >> 8) & 0xf; +    uint8_t rm = insn & 0xf; +    uint8_t bit_s = (insn >> 20) & 1; + +    const char *opname = opcode_names[opcode]; +    sprintf(ptr, "%s%s%s\tr%d, r%d, r%d, r%d", +            opname, cond_to_str(cond), bit_s ? "s" : "", rd, rm, rs, rn); +    return ptr; +} + +char *Arm::disasm_umlal(Opcode opcode, uint32_t insn, char *ptr) +{ +    uint8_t cond = (insn >> 28) & 0xf; +    uint8_t rdhi = (insn >> 16) & 0xf; +    uint8_t rdlo = (insn >> 12) & 0xf; +    uint8_t rs = (insn >> 8) & 0xf; +    uint8_t rm = insn & 0xf; +    uint8_t bit_s = (insn >> 20) & 1; + +    const char *opname = opcode_names[opcode]; +    sprintf(ptr, "%s%s%s\tr%d, r%d, r%d, r%d", +            opname, cond_to_str(cond), bit_s ? "s" : "", rdlo, rdhi, rm, rs); +    return ptr; +} + +char *Arm::disasm_mul(Opcode opcode, uint32_t insn, char *ptr) +{ +    uint8_t cond = (insn >> 28) & 0xf; +    uint8_t rd = (insn >> 16) & 0xf; +    uint8_t rs = (insn >> 8) & 0xf; +    uint8_t rm = insn & 0xf; +    uint8_t bit_s = (insn >> 20) & 1; + +    const char *opname = opcode_names[opcode]; +    sprintf(ptr, "%s%s%s\tr%d, r%d, r%d", +            opname, cond_to_str(cond), bit_s ? "s" : "", rd, rm, rs); +    return ptr; +} + +char *Arm::disasm_mrs(uint32_t insn, char *ptr) +{ +    uint8_t cond = (insn >> 28) & 0xf; +    uint8_t rd = (insn >> 12) & 0xf; +    uint8_t ps = (insn >> 22) & 1; + +    sprintf(ptr, "mrs%s\tr%d, %s", cond_to_str(cond), rd, ps ? "spsr" : "cpsr"); +    return ptr; +} + +char *Arm::disasm_msr(uint32_t insn, char *ptr) +{ +    char flags[8]; +    int flag_index = 0; +    uint8_t cond = (insn >> 28) & 0xf; +    uint8_t is_immed = (insn >> 25) & 0x1; +    uint8_t pd = (insn >> 22) & 1; +    uint8_t mask = (insn >> 16) & 0xf; + +    if (mask & 1) +        flags[flag_index++] = 'c'; +    if (mask & 2) +        flags[flag_index++] = 'x'; +    if (mask & 4) +        flags[flag_index++] = 's'; +    if (mask & 8) +        flags[flag_index++] = 'f'; +    flags[flag_index] = 0; + +    if (is_immed) { +        uint32_t immed = insn & 0xff; +        uint8_t rotate = (insn >> 8) & 0xf; +        uint8_t rotate2 = rotate << 1; +        uint32_t rotated_val = (immed >> rotate2) | (immed << (32 - rotate2)); +        sprintf(ptr, "msr%s\t%s_%s, #0x%x", +                cond_to_str(cond), pd ? "spsr" : "cpsr", flags, rotated_val); +        return ptr; +    } + +    uint8_t rm = insn & 0xf; + +    sprintf(ptr, "msr%s\t%s_%s, r%d", +            cond_to_str(cond), pd ? "spsr" : "cpsr", flags, rm); +    return ptr; +} + +char *Arm::disasm_pld(uint32_t insn, char *ptr) +{ +    uint8_t is_reg = (insn >> 25) & 0x1; +    uint8_t is_up = (insn >> 23) & 0x1; +    uint8_t rn = (insn >> 16) & 0xf; + +    const char *minus = ""; +    if (is_up == 0) +        minus = "-"; + +    if (is_reg) { +        uint8_t rm = insn & 0xf; +        sprintf(ptr, "pld\t[r%d, %sr%d]", rn, minus, rm); +        return ptr; +    } + +    uint16_t offset = insn & 0xfff; +    if (offset == 0) { +        sprintf(ptr, "pld\t[r%d]", rn); +    } else { +        sprintf(ptr, "pld\t[r%d, #%s%u]", rn, minus, offset); +    } +    return ptr; +} + +char *Arm::disasm_swi(uint32_t insn, char *ptr) +{ +    uint8_t cond = (insn >> 28) & 0xf; +    uint32_t sysnum = insn & 0x00ffffff; + +    sprintf(ptr, "swi%s 0x%x", cond_to_str(cond), sysnum); +    return ptr; +} + +char *Arm::disasm_swp(Opcode opcode, uint32_t insn, char *ptr) +{ +    uint8_t cond = (insn >> 28) & 0xf; +    uint8_t rn = (insn >> 16) & 0xf; +    uint8_t rd = (insn >> 12) & 0xf; +    uint8_t rm = insn & 0xf; + +    const char *opname = opcode_names[opcode]; +    sprintf(ptr, "%s%s\tr%d, r%d, [r%d]", opname, cond_to_str(cond), rd, rm, rn); +    return ptr; +} + +Opcode Arm::decode(uint32_t insn) { +    uint32_t bits27_26 = (insn >> 26) & 0x3; +    switch (bits27_26) { +        case 0x0: +            return decode00(insn); +        case 0x1: +            return decode01(insn); +        case 0x2: +            return decode10(insn); +        case 0x3: +            return decode11(insn); +    } +    return OP_INVALID; +} + +Opcode Arm::decode00(uint32_t insn) { +    uint8_t bit25 = (insn >> 25) & 0x1; +    uint8_t bit4 = (insn >> 4) & 0x1; +    if (bit25 == 0 && bit4 == 1) { +        if ((insn & 0x0ffffff0) == 0x012fff10) { +            // Bx instruction +            return OP_BX; +        } +        if ((insn & 0x0ff000f0) == 0x01600010) { +            // Clz instruction +            return OP_CLZ; +        } +        if ((insn & 0xfff000f0) == 0xe1200070) { +            // Bkpt instruction +            return OP_BKPT; +        } +        uint32_t bits7_4 = (insn >> 4) & 0xf; +        if (bits7_4 == 0x9) { +            if ((insn & 0x0ff00ff0) == 0x01000090) { +                // Swp instruction +                uint8_t bit22 = (insn >> 22) & 0x1; +                if (bit22) +                    return OP_SWPB; +                return OP_SWP; +            } +            // One of the multiply instructions +            return decode_mul(insn); +        } + +        uint8_t bit7 = (insn >> 7) & 0x1; +        if (bit7 == 1) { +            // One of the load/store halfword/byte instructions +            return decode_ldrh(insn); +        } +    } + +    // One of the data processing instructions +    return decode_alu(insn); +} + +Opcode Arm::decode01(uint32_t insn) { +    uint8_t is_reg = (insn >> 25) & 0x1; +    uint8_t bit4 = (insn >> 4) & 0x1; +    if (is_reg == 1 && bit4 == 1) +        return OP_UNDEFINED; +    uint8_t is_load = (insn >> 20) & 0x1; +    uint8_t is_byte = (insn >> 22) & 0x1; +    if ((insn & 0xfd70f000) == 0xf550f000) { +        // Pre-load +        return OP_PLD; +    } +    if (is_load) { +        if (is_byte) { +            // Load byte +            return OP_LDRB; +        } +        // Load word +        return OP_LDR; +    } +    if (is_byte) { +        // Store byte +        return OP_STRB; +    } +    // Store word +    return OP_STR; +} + +Opcode Arm::decode10(uint32_t insn) { +    uint8_t bit25 = (insn >> 25) & 0x1; +    if (bit25 == 0) { +        // LDM/STM +        uint8_t is_load = (insn >> 20) & 0x1; +        if (is_load) +            return OP_LDM; +        return OP_STM; +    } +    // Branch or Branch with link +    uint8_t is_link = (insn >> 24) & 1; +    uint32_t offset = insn & 0xffffff; + +    // Sign-extend the 24-bit offset +    if ((offset >> 23) & 1) +        offset |= 0xff000000; + +    // Pre-compute the left-shift and the prefetch offset +    offset <<= 2; +    offset += 8; +    if (is_link == 0) +        return OP_B; +    return OP_BL; +} + +Opcode Arm::decode11(uint32_t insn) { +    uint8_t bit25 = (insn >> 25) & 0x1; +    if (bit25 == 0) { +        // LDC, SDC +        uint8_t is_load = (insn >> 20) & 0x1; +        if (is_load) { +            // LDC +            return OP_LDC; +        } +        // STC +        return OP_STC; +    } + +    uint8_t bit24 = (insn >> 24) & 0x1; +    if (bit24 == 0x1) { +        // SWI +        return OP_SWI; +    } +   +    uint8_t bit4 = (insn >> 4) & 0x1; +    uint8_t cpnum = (insn >> 8) & 0xf; + +    if (cpnum == 15) { +        // Special case for coprocessor 15 +        uint8_t opcode = (insn >> 21) & 0x7; +        if (bit4 == 0 || opcode != 0) { +            // This is an unexpected bit pattern.  Create an undefined +            // instruction in case this is ever executed. +            return OP_UNDEFINED; +        } + +        // MRC, MCR +        uint8_t is_mrc = (insn >> 20) & 0x1; +        if (is_mrc) +            return OP_MRC; +        return OP_MCR; +    } + +    if (bit4 == 0) { +        // CDP +        return OP_CDP; +    } +    // MRC, MCR +    uint8_t is_mrc = (insn >> 20) & 0x1; +    if (is_mrc) +        return OP_MRC; +    return OP_MCR; +} + +Opcode Arm::decode_mul(uint32_t insn) { +    uint8_t bit24 = (insn >> 24) & 0x1; +    if (bit24 != 0) { +        // This is an unexpected bit pattern.  Create an undefined +        // instruction in case this is ever executed. +        return OP_UNDEFINED; +    } +    uint8_t bit23 = (insn >> 23) & 0x1; +    uint8_t bit22_U = (insn >> 22) & 0x1; +    uint8_t bit21_A = (insn >> 21) & 0x1; +    if (bit23 == 0) { +        // 32-bit multiply +        if (bit22_U != 0) { +            // This is an unexpected bit pattern.  Create an undefined +            // instruction in case this is ever executed. +            return OP_UNDEFINED; +        } +        if (bit21_A == 0) +            return OP_MUL; +        return OP_MLA; +    } +    // 64-bit multiply +    if (bit22_U == 0) { +        // Unsigned multiply long +        if (bit21_A == 0) +            return OP_UMULL; +        return OP_UMLAL; +    } +    // Signed multiply long +    if (bit21_A == 0) +        return OP_SMULL; +    return OP_SMLAL; +} + +Opcode Arm::decode_ldrh(uint32_t insn) { +    uint8_t is_load = (insn >> 20) & 0x1; +    uint8_t bits_65 = (insn >> 5) & 0x3; +    if (is_load) { +        if (bits_65 == 0x1) { +            // Load unsigned halfword +            return OP_LDRH; +        } else if (bits_65 == 0x2) { +            // Load signed byte +            return OP_LDRSB; +        } +        // Signed halfword +        if (bits_65 != 0x3) { +            // This is an unexpected bit pattern.  Create an undefined +            // instruction in case this is ever executed. +            return OP_UNDEFINED; +        } +        // Load signed halfword +        return OP_LDRSH; +    } +    // Store halfword +    if (bits_65 != 0x1) { +        // This is an unexpected bit pattern.  Create an undefined +        // instruction in case this is ever executed. +        return OP_UNDEFINED; +    } +    // Store halfword +    return OP_STRH; +} + +Opcode Arm::decode_alu(uint32_t insn) { +    uint8_t is_immed = (insn >> 25) & 0x1; +    uint8_t opcode = (insn >> 21) & 0xf; +    uint8_t bit_s = (insn >> 20) & 1; +    uint8_t shift_is_reg = (insn >> 4) & 1; +    uint8_t bit7 = (insn >> 7) & 1; +    if (!is_immed && shift_is_reg && (bit7 != 0)) { +        // This is an unexpected bit pattern.  Create an undefined +        // instruction in case this is ever executed. +        return OP_UNDEFINED; +    } +    switch (opcode) { +        case 0x0: +            return OP_AND; +        case 0x1: +            return OP_EOR; +        case 0x2: +            return OP_SUB; +        case 0x3: +            return OP_RSB; +        case 0x4: +            return OP_ADD; +        case 0x5: +            return OP_ADC; +        case 0x6: +            return OP_SBC; +        case 0x7: +            return OP_RSC; +        case 0x8: +            if (bit_s) +                return OP_TST; +            return OP_MRS; +        case 0x9: +            if (bit_s) +                return OP_TEQ; +            return OP_MSR; +        case 0xa: +            if (bit_s) +                return OP_CMP; +            return OP_MRS; +        case 0xb: +            if (bit_s) +                return OP_CMN; +            return OP_MSR; +        case 0xc: +            return OP_ORR; +        case 0xd: +            return OP_MOV; +        case 0xe: +            return OP_BIC; +        case 0xf: +            return OP_MVN; +    } +    // Unreachable +    return OP_INVALID; +}
\ No newline at end of file diff --git a/src/core/src/arm/disassembler/arm_disasm.h b/src/core/src/arm/disassembler/arm_disasm.h new file mode 100644 index 000000000..15c7bb557 --- /dev/null +++ b/src/core/src/arm/disassembler/arm_disasm.h @@ -0,0 +1,146 @@ +// Copyright 2006 The Android Open Source Project + +#ifndef ARMDIS_H +#define ARMDIS_H + +#include <stdint.h> + +// Note: this list of opcodes must match the list used to initialize +// the opflags[] array in opcode.cpp. +enum Opcode { +    OP_INVALID, +    OP_UNDEFINED, +    OP_ADC, +    OP_ADD, +    OP_AND, +    OP_B, +    OP_BL, +    OP_BIC, +    OP_BKPT, +    OP_BLX, +    OP_BX, +    OP_CDP, +    OP_CLZ, +    OP_CMN, +    OP_CMP, +    OP_EOR, +    OP_LDC, +    OP_LDM, +    OP_LDR, +    OP_LDRB, +    OP_LDRBT, +    OP_LDRH, +    OP_LDRSB, +    OP_LDRSH, +    OP_LDRT, +    OP_MCR, +    OP_MLA, +    OP_MOV, +    OP_MRC, +    OP_MRS, +    OP_MSR, +    OP_MUL, +    OP_MVN, +    OP_ORR, +    OP_PLD, +    OP_RSB, +    OP_RSC, +    OP_SBC, +    OP_SMLAL, +    OP_SMULL, +    OP_STC, +    OP_STM, +    OP_STR, +    OP_STRB, +    OP_STRBT, +    OP_STRH, +    OP_STRT, +    OP_SUB, +    OP_SWI, +    OP_SWP, +    OP_SWPB, +    OP_TEQ, +    OP_TST, +    OP_UMLAL, +    OP_UMULL, + +    // Define thumb opcodes +    OP_THUMB_UNDEFINED, +    OP_THUMB_ADC, +    OP_THUMB_ADD, +    OP_THUMB_AND, +    OP_THUMB_ASR, +    OP_THUMB_B, +    OP_THUMB_BIC, +    OP_THUMB_BKPT, +    OP_THUMB_BL, +    OP_THUMB_BLX, +    OP_THUMB_BX, +    OP_THUMB_CMN, +    OP_THUMB_CMP, +    OP_THUMB_EOR, +    OP_THUMB_LDMIA, +    OP_THUMB_LDR, +    OP_THUMB_LDRB, +    OP_THUMB_LDRH, +    OP_THUMB_LDRSB, +    OP_THUMB_LDRSH, +    OP_THUMB_LSL, +    OP_THUMB_LSR, +    OP_THUMB_MOV, +    OP_THUMB_MUL, +    OP_THUMB_MVN, +    OP_THUMB_NEG, +    OP_THUMB_ORR, +    OP_THUMB_POP, +    OP_THUMB_PUSH, +    OP_THUMB_ROR, +    OP_THUMB_SBC, +    OP_THUMB_STMIA, +    OP_THUMB_STR, +    OP_THUMB_STRB, +    OP_THUMB_STRH, +    OP_THUMB_SUB, +    OP_THUMB_SWI, +    OP_THUMB_TST, + +    OP_END                // must be last +}; + +class Arm { + public: +  static char *disasm(uint32_t addr, uint32_t insn, char *buffer); +  static Opcode decode(uint32_t insn); + + private: +  static Opcode decode00(uint32_t insn); +  static Opcode decode01(uint32_t insn); +  static Opcode decode10(uint32_t insn); +  static Opcode decode11(uint32_t insn); +  static Opcode decode_mul(uint32_t insn); +  static Opcode decode_ldrh(uint32_t insn); +  static Opcode decode_alu(uint32_t insn); + +  static char *disasm_alu(Opcode opcode, uint32_t insn, char *ptr); +  static char *disasm_branch(uint32_t addr, Opcode opcode, uint32_t insn, char *ptr); +  static char *disasm_bx(uint32_t insn, char *ptr); +  static char *disasm_bkpt(uint32_t insn, char *ptr); +  static char *disasm_clz(uint32_t insn, char *ptr); +  static char *disasm_memblock(Opcode opcode, uint32_t insn, char *ptr); +  static char *disasm_mem(uint32_t insn, char *ptr); +  static char *disasm_memhalf(uint32_t insn, char *ptr); +  static char *disasm_mcr(Opcode opcode, uint32_t insn, char *ptr); +  static char *disasm_mla(Opcode opcode, uint32_t insn, char *ptr); +  static char *disasm_umlal(Opcode opcode, uint32_t insn, char *ptr); +  static char *disasm_mul(Opcode opcode, uint32_t insn, char *ptr); +  static char *disasm_mrs(uint32_t insn, char *ptr); +  static char *disasm_msr(uint32_t insn, char *ptr); +  static char *disasm_pld(uint32_t insn, char *ptr); +  static char *disasm_swi(uint32_t insn, char *ptr); +  static char *disasm_swp(Opcode opcode, uint32_t insn, char *ptr); +}; + +extern char *disasm_insn_thumb(uint32_t pc, uint32_t insn1, uint32_t insn2, char *result); +extern Opcode decode_insn_thumb(uint32_t given); + +#endif /* ARMDIS_H */  | 
