1 #include "mips_emulator.h"
2 #include <capstone.h>
3 
4 namespace REDasm {
5 
MIPSEmulator(DisassemblerAPI * disassembler)6 MIPSEmulator::MIPSEmulator(DisassemblerAPI *disassembler): EmulatorT<u32>(disassembler)
7 {
8     EMULATE_INSTRUCTION(MIPS_INS_LB,  &MIPSEmulator::emulateLxx);
9     EMULATE_INSTRUCTION(MIPS_INS_LBU, &MIPSEmulator::emulateLxx);
10     EMULATE_INSTRUCTION(MIPS_INS_LH,  &MIPSEmulator::emulateLxx);
11     EMULATE_INSTRUCTION(MIPS_INS_LWR, &MIPSEmulator::emulateLxx);
12     EMULATE_INSTRUCTION(MIPS_INS_LWL, &MIPSEmulator::emulateLxx);
13     EMULATE_INSTRUCTION(MIPS_INS_LW,  &MIPSEmulator::emulateLxx);
14     EMULATE_INSTRUCTION(MIPS_INS_LHU, &MIPSEmulator::emulateLxx);
15 
16     EMULATE_INSTRUCTION(MIPS_INS_SB,  &MIPSEmulator::emulateSxx);
17     EMULATE_INSTRUCTION(MIPS_INS_SH,  &MIPSEmulator::emulateSxx);
18     EMULATE_INSTRUCTION(MIPS_INS_SWL, &MIPSEmulator::emulateSxx);
19     EMULATE_INSTRUCTION(MIPS_INS_SW,  &MIPSEmulator::emulateSxx);
20     EMULATE_INSTRUCTION(MIPS_INS_SWR, &MIPSEmulator::emulateSxx);
21 
22     EMULATE_INSTRUCTION(MIPS_INS_ADD,   &MIPSEmulator::emulateMath);
23     EMULATE_INSTRUCTION(MIPS_INS_ADDI,  &MIPSEmulator::emulateMath);
24     EMULATE_INSTRUCTION(MIPS_INS_ADDIU, &MIPSEmulator::emulateMath);
25     EMULATE_INSTRUCTION(MIPS_INS_ADDU,  &MIPSEmulator::emulateMath);
26     EMULATE_INSTRUCTION(MIPS_INS_SUB,   &MIPSEmulator::emulateMath);
27     EMULATE_INSTRUCTION(MIPS_INS_SUBU,  &MIPSEmulator::emulateMath);
28     EMULATE_INSTRUCTION(MIPS_INS_MUL,   &MIPSEmulator::emulateMath);
29     EMULATE_INSTRUCTION(MIPS_INS_AND,   &MIPSEmulator::emulateMath);
30     EMULATE_INSTRUCTION(MIPS_INS_ANDI,  &MIPSEmulator::emulateMath);
31     EMULATE_INSTRUCTION(MIPS_INS_OR,    &MIPSEmulator::emulateMath);
32     EMULATE_INSTRUCTION(MIPS_INS_ORI,   &MIPSEmulator::emulateMath);
33     EMULATE_INSTRUCTION(MIPS_INS_XOR,   &MIPSEmulator::emulateMath);
34     EMULATE_INSTRUCTION(MIPS_INS_XORI,  &MIPSEmulator::emulateMath);
35     EMULATE_INSTRUCTION(MIPS_INS_SLL,   &MIPSEmulator::emulateMath);
36     EMULATE_INSTRUCTION(MIPS_INS_SLLV,  &MIPSEmulator::emulateMath);
37     EMULATE_INSTRUCTION(MIPS_INS_SRL,   &MIPSEmulator::emulateMath);
38     EMULATE_INSTRUCTION(MIPS_INS_SRLV,  &MIPSEmulator::emulateMath);
39     EMULATE_INSTRUCTION(MIPS_INS_SRAV,  &MIPSEmulator::emulateMath);
40     EMULATE_INSTRUCTION(MIPS_INS_LUI,   &MIPSEmulator::emulateLui);
41 
42     //EMULATE_INSTRUCTION(MIPS_INS_MULT, &MIPSEmulator::emulateMath);
43     //EMULATE_INSTRUCTION(MIPS_INS_MULTU, &MIPSEmulator::emulateMath);
44     //EMULATE_INSTRUCTION(MIPS_INS_DIV, &MIPSEmulator::emulateMath);
45     //EMULATE_INSTRUCTION(MIPS_INS_DIVU, &MIPSEmulator::emulateMath);
46 }
47 
emulate(const InstructionPtr & instruction)48 void MIPSEmulator::emulate(const InstructionPtr &instruction)
49 {
50     this->writeReg(MIPS_REG_ZERO, 0); // Initialize $zero
51     return Emulator::emulate(instruction);
52 }
53 
emulateMath(const InstructionPtr & instruction)54 void MIPSEmulator::emulateMath(const InstructionPtr &instruction) { this->aluOp(instruction, 0, 1, 2); }
55 
emulateLui(const InstructionPtr & instruction)56 void MIPSEmulator::emulateLui(const InstructionPtr &instruction)
57 {
58     u64 value = 0;
59 
60     if(!this->read(instruction->op(1), &value))
61         return;
62 
63     this->writeOp(instruction->op(0), static_cast<u32>(value << 16));
64 }
65 
emulateLxx(const InstructionPtr & instruction)66 void MIPSEmulator::emulateLxx(const InstructionPtr &instruction)
67 {
68     size_t size = 0;
69 
70     if((instruction->id == MIPS_INS_LB) || (instruction->id == MIPS_INS_LBU))
71         size = sizeof(u8);
72     else if((instruction->id == MIPS_INS_LH) || (instruction->id == MIPS_INS_LHU))
73         size = sizeof(u16);
74     else if((instruction->id == MIPS_INS_LW) || (instruction->id == MIPS_INS_LWL) || (instruction->id == MIPS_INS_LWR))
75         size = sizeof(u32);
76     else
77     {
78         this->unhandled(instruction);
79         return;
80     }
81 
82     u32 regvalue = 0, value = 0;
83     const Operand *op1 = instruction->op(0), *op2 = instruction->op(1);
84 
85     if(!this->readOp(op2, &value))
86         return;
87 
88     value += static_cast<u32>(op2->disp.displacement);
89 
90     if(!this->readMem(static_cast<u32>(value), &value, static_cast<u32>(size)))
91         return;
92 
93     this->readOp(op1, &regvalue);
94 
95     if(instruction->id == MIPS_INS_LWL)
96         regvalue = (regvalue & 0xFFFF) | (value & 0xFFFF0000);
97     else if(instruction->id == MIPS_INS_LWR)
98         regvalue = (regvalue & 0xFFFF) | (value & 0x0000FFFF);
99     else
100         regvalue = value;
101 
102     this->writeOp(op1, regvalue);
103 }
104 
emulateSxx(const InstructionPtr & instruction)105 void MIPSEmulator::emulateSxx(const InstructionPtr &instruction)
106 {
107     size_t size = 0;
108 
109     if(instruction->id == MIPS_INS_SB)
110         size = sizeof(u8);
111     else if(instruction->id == MIPS_INS_SH)
112         size = sizeof(u16);
113     else if((instruction->id == MIPS_INS_SW) || (instruction->id == MIPS_INS_SWL) || (instruction->id == MIPS_INS_SWR))
114         size = sizeof(u32);
115     else
116     {
117         this->unhandled(instruction);
118         return;
119     }
120 
121     u32 regvalue = 0, memloc = 0, memvalue = 0;
122     const Operand *op1 = instruction->op(0), *op2 = instruction->op(1);
123 
124     if(!this->readOp(op1, &regvalue) || !this->readOp(op2, &memloc))
125         return;
126 
127     this->readMem(static_cast<u32>(memloc), &memvalue, static_cast<u32>(size));
128 
129     if(instruction->id == MIPS_INS_SWL)
130         regvalue = (regvalue & 0xFFFF) | (memvalue & 0xFFFF0000);
131     else if(instruction->id == MIPS_INS_SWR)
132         regvalue = (regvalue & 0xFFFF) | (memvalue & 0x0000FFFF);
133 
134     this->writeMem(memloc, regvalue);
135 }
136 
137 } // namespace REDasm
138