<commit_before>//===-- EmulateInstructionARM.cpp -------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "EmulateInstructionARM.h"
#include "ARMUtils.h"

using namespace lldb;
using namespace lldb_private;

// ARM constants used during decoding
#define REG_RD          0
#define LDM_REGLIST     1
#define PC_REG          15
#define PC_REGLIST_BIT  0x8000

#define ARMv4     (1u << 0)
#define ARMv4T    (1u << 1)
#define ARMv5T    (1u << 2)
#define ARMv5TE   (1u << 3)
#define ARMv5TEJ  (1u << 4)
#define ARMv6     (1u << 5)
#define ARMv6K    (1u << 6)
#define ARMv6T2   (1u << 7)
#define ARMv7     (1u << 8)
#define ARMv8     (1u << 8)
#define ARMvAll   (0xffffffffu)

typedef enum
{
    eEncodingA1,
    eEncodingA2,
    eEncodingA3,
    eEncodingA4,
    eEncodingA5,
    eEncodingT1,
    eEncodingT2,
    eEncodingT3,
    eEncodingT4,
    eEncodingT5,
} ARMEncoding;

typedef enum
{
    eSize16,
    eSize32
} ARMInstrSize;

// Typedef for the callback function used during the emulation.
// Pass along (ARMEncoding)encoding as the callback data.
typedef bool (*EmulateCallback) (EmulateInstructionARM *emulator, ARMEncoding encoding);
    
typedef struct
{
    uint32_t mask;
    uint32_t value;
    uint32_t variants;
    ARMEncoding encoding;
    ARMInstrSize size;
    EmulateCallback callback;
    const char *name;
}  ARMOpcode;

static bool 
EmulateARMPushEncoding (EmulateInstructionARM *emulator, ARMEncoding encoding)
{
#if 0
    // ARM pseudo code...
    if (ConditionPassed())
    {
        EncodingSpecificOperations(); 
        NullCheckIfThumbEE(13); 
        address = SP - 4*BitCount(registers);

        for (i = 0 to 14)
        {
            if (registers<i> == ’1’)
            {
                if i == 13 && i != LowestSetBit(registers) // Only possible for encoding A1 
                    MemA[address,4] = bits(32) UNKNOWN;
                else 
                    MemA[address,4] = R[i];
                address = address + 4;
            }
        }

        if (registers<15> == ’1’) // Only possible for encoding A1 or A2 
            MemA[address,4] = PCStoreValue();
        
        SP = SP - 4*BitCount(registers);
    }
#endif

    bool success = false;
    const uint32_t opcode = emulator->OpcodeAsUnsigned (&success);
    if (!success)
        return false;

    if (emulator->ConditionPassed())
    {
        const uint32_t addr_byte_size = emulator->GetAddressByteSize();
        const addr_t sp = emulator->ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
        if (!success)
            return false;
        uint32_t registers = 0;
        uint32_t t; // t = UInt(Rt)
        switch (encoding) {
        case eEncodingT1:
            registers = EmulateInstruction::UnsignedBits (opcode, 7, 0);
            // The M bit represents LR.
            if (EmulateInstruction::UnsignedBits (opcode, 8, 8))
                registers |= 0x000eu;
            // if BitCount(registers) < 1 then UNPREDICTABLE;
            if (BitCount(registers) < 1)
                return false;
            break;
        case eEncodingT2:
            // Ignore bits 15 & 13.
            registers = EmulateInstruction::UnsignedBits (opcode, 15, 0) & ~0xa000;
            // if BitCount(registers) < 2 then UNPREDICTABLE;
            if (BitCount(registers) < 2)
                return false;
            break;
        case eEncodingT3:
            t = EmulateInstruction::UnsignedBits (opcode, 15, 12);
            // if BadReg(t) then UNPREDICTABLE;
            if (BadReg(t))
                return false;
            registers = (1u << t);
            break;
        case eEncodingA1:
            registers = EmulateInstruction::UnsignedBits (opcode, 15, 0);
            // Instead of return false, let's handle the following case as well,
            // which amounts to pushing one reg onto the full descending stacks.
            // if BitCount(register_list) < 2 then SEE STMDB / STMFD;
            break;
        case eEncodingA2:
            t = EmulateInstruction::UnsignedBits (opcode, 15, 12);
            // if t == 13 then UNPREDICTABLE;
            if (t == dwarf_sp)
                return false;
            registers = (1u << t);
            break;
        }
        addr_t sp_offset = addr_byte_size * EmulateInstruction::BitCount (registers);
        addr_t addr = sp - sp_offset;
        uint32_t i;
        
        EmulateInstruction::Context context = { EmulateInstruction::eContextPushRegisterOnStack, eRegisterKindDWARF, 0, 0 };
        for (i=0; i<15; ++i)
        {
            if (EmulateInstruction::BitIsSet (registers, 1u << i))
            {
                context.arg1 = dwarf_r0 + i;    // arg1 in the context is the DWARF register number
                context.arg2 = addr - sp;       // arg2 in the context is the stack pointer offset
                uint32_t reg_value = emulator->ReadRegisterUnsigned(eRegisterKindDWARF, context.arg1, 0, &success);
                if (!success)
                    return false;
                if (!emulator->WriteMemoryUnsigned (context, addr, reg_value, addr_byte_size))
                    return false;
                addr += addr_byte_size;
            }
        }
        
        if (EmulateInstruction::BitIsSet (registers, 1u << 15))
        {
            context.arg1 = dwarf_pc;    // arg1 in the context is the DWARF register number
            context.arg2 = addr - sp;   // arg2 in the context is the stack pointer offset
            const uint32_t pc = emulator->ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
            if (!success)
                return false;
            if (!emulator->WriteMemoryUnsigned (context, addr, pc + 8, addr_byte_size))
                return false;
        }
        
        context.type = EmulateInstruction::eContextAdjustStackPointer;
        context.arg0 = eRegisterKindGeneric;
        context.arg1 = LLDB_REGNUM_GENERIC_SP;
        context.arg2 = sp_offset;
    
        if (!emulator->WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp - sp_offset))
            return false;
    }
    return true;
}

static ARMOpcode g_arm_opcodes[] =
{
    { 0x0000fe00, 0x0000b400, ARMvAll,       eEncodingT1, eSize16, EmulateARMPushEncoding,
      "push<c> <registers>" },
    { 0xffff0000, 0xe8ad0000, ARMv6T2|ARMv7, eEncodingT2, eSize32, EmulateARMPushEncoding,
      "push<c>.w <registers> ; <registers> contains more than one register" },
    { 0xffff0fff, 0xf84d0d04, ARMv6T2|ARMv7, eEncodingT3, eSize32, EmulateARMPushEncoding,
      "push<c>.w <registers> ; <registers> contains one register, <Rt>" },
    { 0x0fff0000, 0x092d0000, ARMvAll,       eEncodingA1, eSize32, EmulateARMPushEncoding,
      "push<c> <registers> ; <registers> contains more than one register" },
    { 0x0fff0fff, 0x052d0004, ARMvAll,       eEncodingA2, eSize32, EmulateARMPushEncoding,
      "push<c> <registers> ; <registers> contains one register, <Rt>" }
};

static const size_t k_num_arm_opcodes = sizeof(g_arm_opcodes)/sizeof(ARMOpcode);

bool 
EmulateInstructionARM::ReadInstruction ()
{
    bool success = false;
    m_inst_cpsr = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, 0, &success);
    if (success)
    {<commit_msg>Fix typo of encoding T2 (push) in the original ARM Architecture Reference Manual, which has been corrected in the subsequent errata.<commit_after>//===-- EmulateInstructionARM.cpp -------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "EmulateInstructionARM.h"
#include "ARMUtils.h"

using namespace lldb;
using namespace lldb_private;

// ARM constants used during decoding
#define REG_RD          0
#define LDM_REGLIST     1
#define PC_REG          15
#define PC_REGLIST_BIT  0x8000

#define ARMv4     (1u << 0)
#define ARMv4T    (1u << 1)
#define ARMv5T    (1u << 2)
#define ARMv5TE   (1u << 3)
#define ARMv5TEJ  (1u << 4)
#define ARMv6     (1u << 5)
#define ARMv6K    (1u << 6)
#define ARMv6T2   (1u << 7)
#define ARMv7     (1u << 8)
#define ARMv8     (1u << 8)
#define ARMvAll   (0xffffffffu)

typedef enum
{
    eEncodingA1,
    eEncodingA2,
    eEncodingA3,
    eEncodingA4,
    eEncodingA5,
    eEncodingT1,
    eEncodingT2,
    eEncodingT3,
    eEncodingT4,
    eEncodingT5,
} ARMEncoding;

typedef enum
{
    eSize16,
    eSize32
} ARMInstrSize;

// Typedef for the callback function used during the emulation.
// Pass along (ARMEncoding)encoding as the callback data.
typedef bool (*EmulateCallback) (EmulateInstructionARM *emulator, ARMEncoding encoding);
    
typedef struct
{
    uint32_t mask;
    uint32_t value;
    uint32_t variants;
    ARMEncoding encoding;
    ARMInstrSize size;
    EmulateCallback callback;
    const char *name;
}  ARMOpcode;

static bool 
EmulateARMPushEncoding (EmulateInstructionARM *emulator, ARMEncoding encoding)
{
#if 0
    // ARM pseudo code...
    if (ConditionPassed())
    {
        EncodingSpecificOperations(); 
        NullCheckIfThumbEE(13); 
        address = SP - 4*BitCount(registers);

        for (i = 0 to 14)
        {
            if (registers<i> == ’1’)
            {
                if i == 13 && i != LowestSetBit(registers) // Only possible for encoding A1 
                    MemA[address,4] = bits(32) UNKNOWN;
                else 
                    MemA[address,4] = R[i];
                address = address + 4;
            }
        }

        if (registers<15> == ’1’) // Only possible for encoding A1 or A2 
            MemA[address,4] = PCStoreValue();
        
        SP = SP - 4*BitCount(registers);
    }
#endif

    bool success = false;
    const uint32_t opcode = emulator->OpcodeAsUnsigned (&success);
    if (!success)
        return false;

    if (emulator->ConditionPassed())
    {
        const uint32_t addr_byte_size = emulator->GetAddressByteSize();
        const addr_t sp = emulator->ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
        if (!success)
            return false;
        uint32_t registers = 0;
        uint32_t t; // t = UInt(Rt)
        switch (encoding) {
        case eEncodingT1:
            registers = EmulateInstruction::UnsignedBits (opcode, 7, 0);
            // The M bit represents LR.
            if (EmulateInstruction::UnsignedBits (opcode, 8, 8))
                registers |= 0x000eu;
            // if BitCount(registers) < 1 then UNPREDICTABLE;
            if (BitCount(registers) < 1)
                return false;
            break;
        case eEncodingT2:
            // Ignore bits 15 & 13.
            registers = EmulateInstruction::UnsignedBits (opcode, 15, 0) & ~0xa000;
            // if BitCount(registers) < 2 then UNPREDICTABLE;
            if (BitCount(registers) < 2)
                return false;
            break;
        case eEncodingT3:
            t = EmulateInstruction::UnsignedBits (opcode, 15, 12);
            // if BadReg(t) then UNPREDICTABLE;
            if (BadReg(t))
                return false;
            registers = (1u << t);
            break;
        case eEncodingA1:
            registers = EmulateInstruction::UnsignedBits (opcode, 15, 0);
            // Instead of return false, let's handle the following case as well,
            // which amounts to pushing one reg onto the full descending stacks.
            // if BitCount(register_list) < 2 then SEE STMDB / STMFD;
            break;
        case eEncodingA2:
            t = EmulateInstruction::UnsignedBits (opcode, 15, 12);
            // if t == 13 then UNPREDICTABLE;
            if (t == dwarf_sp)
                return false;
            registers = (1u << t);
            break;
        }
        addr_t sp_offset = addr_byte_size * EmulateInstruction::BitCount (registers);
        addr_t addr = sp - sp_offset;
        uint32_t i;
        
        EmulateInstruction::Context context = { EmulateInstruction::eContextPushRegisterOnStack, eRegisterKindDWARF, 0, 0 };
        for (i=0; i<15; ++i)
        {
            if (EmulateInstruction::BitIsSet (registers, 1u << i))
            {
                context.arg1 = dwarf_r0 + i;    // arg1 in the context is the DWARF register number
                context.arg2 = addr - sp;       // arg2 in the context is the stack pointer offset
                uint32_t reg_value = emulator->ReadRegisterUnsigned(eRegisterKindDWARF, context.arg1, 0, &success);
                if (!success)
                    return false;
                if (!emulator->WriteMemoryUnsigned (context, addr, reg_value, addr_byte_size))
                    return false;
                addr += addr_byte_size;
            }
        }
        
        if (EmulateInstruction::BitIsSet (registers, 1u << 15))
        {
            context.arg1 = dwarf_pc;    // arg1 in the context is the DWARF register number
            context.arg2 = addr - sp;   // arg2 in the context is the stack pointer offset
            const uint32_t pc = emulator->ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
            if (!success)
                return false;
            if (!emulator->WriteMemoryUnsigned (context, addr, pc + 8, addr_byte_size))
                return false;
        }
        
        context.type = EmulateInstruction::eContextAdjustStackPointer;
        context.arg0 = eRegisterKindGeneric;
        context.arg1 = LLDB_REGNUM_GENERIC_SP;
        context.arg2 = sp_offset;
    
        if (!emulator->WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp - sp_offset))
            return false;
    }
    return true;
}

static ARMOpcode g_arm_opcodes[] =
{
    { 0x0000fe00, 0x0000b400, ARMvAll,       eEncodingT1, eSize16, EmulateARMPushEncoding,
      "push<c> <registers>" },
    { 0xffff0000, 0xe92d0000, ARMv6T2|ARMv7, eEncodingT2, eSize32, EmulateARMPushEncoding,
      "push<c>.w <registers> ; <registers> contains more than one register" },
    { 0xffff0fff, 0xf84d0d04, ARMv6T2|ARMv7, eEncodingT3, eSize32, EmulateARMPushEncoding,
      "push<c>.w <registers> ; <registers> contains one register, <Rt>" },
    { 0x0fff0000, 0x092d0000, ARMvAll,       eEncodingA1, eSize32, EmulateARMPushEncoding,
      "push<c> <registers> ; <registers> contains more than one register" },
    { 0x0fff0fff, 0x052d0004, ARMvAll,       eEncodingA2, eSize32, EmulateARMPushEncoding,
      "push<c> <registers> ; <registers> contains one register, <Rt>" }
};

static const size_t k_num_arm_opcodes = sizeof(g_arm_opcodes)/sizeof(ARMOpcode);

bool 
EmulateInstructionARM::ReadInstruction ()
{
    bool success = false;
    m_inst_cpsr = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, 0, &success);
    if (success)
    {
{'fraction_non_alphanumeric': 0.11044638748274276, 'fraction_numerical': 0.033002432450200514, 'mean_word_length': 2.118491184911849, 'pattern_counts': {'":': 0, '<': 107, '<?xml version=': 0, '>': 57, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1788251', 'n_tokens_mistral': 5000, 'n_tokens_neox': 4664, 'n_words': 1226}