1 /* This file is part of the dynarmic project.
2  * Copyright (c) 2016 MerryMage
3  * SPDX-License-Identifier: 0BSD
4  */
5 
6 #include <algorithm>
7 #include <array>
8 #include <cinttypes>
9 #include <cstdio>
10 #include <cstring>
11 #include <functional>
12 #include <tuple>
13 
14 #include <catch.hpp>
15 
16 #include <dynarmic/A32/a32.h>
17 
18 #include "common/bit_util.h"
19 #include "common/common_types.h"
20 #include "frontend/A32/disassembler/disassembler.h"
21 #include "frontend/A32/FPSCR.h"
22 #include "frontend/A32/location_descriptor.h"
23 #include "frontend/A32/PSR.h"
24 #include "frontend/A32/translate/translate.h"
25 #include "frontend/ir/basic_block.h"
26 #include "ir_opt/passes.h"
27 #include "rand_int.h"
28 #include "testenv.h"
29 #include "unicorn_emu/a32_unicorn.h"
30 
31 using namespace Dynarmic;
32 
GetUserConfig(ThumbTestEnv * testenv)33 static A32::UserConfig GetUserConfig(ThumbTestEnv* testenv) {
34     A32::UserConfig user_config;
35     user_config.optimizations &= ~OptimizationFlag::FastDispatch;
36     user_config.callbacks = testenv;
37     return user_config;
38 }
39 
40 using WriteRecords = std::map<u32, u8>;
41 
42 struct ThumbInstGen final {
43 public:
ThumbInstGenThumbInstGen44     ThumbInstGen(const char* format, std::function<bool(u16)> is_valid = [](u16){ return true; }) : is_valid(is_valid) {
45         REQUIRE(strlen(format) == 16);
46 
47         for (int i = 0; i < 16; i++) {
48             const u16 bit = 1 << (15 - i);
49             switch (format[i]) {
50             case '0':
51                 mask |= bit;
52                 break;
53             case '1':
54                 bits |= bit;
55                 mask |= bit;
56                 break;
57             default:
58                 // Do nothing
59                 break;
60             }
61         }
62     }
GenerateThumbInstGen63     u16 Generate() const {
64         u16 inst;
65 
66         do {
67             const u16 random = RandInt<u16>(0, 0xFFFF);
68             inst = bits | (random & ~mask);
69         } while (!is_valid(inst));
70 
71         ASSERT((inst & mask) == bits);
72 
73         return inst;
74     }
75 private:
76     u16 bits = 0;
77     u16 mask = 0;
78     std::function<bool(u16)> is_valid;
79 };
80 
DoesBehaviorMatch(const A32Unicorn<ThumbTestEnv> & uni,const A32::Jit & jit,const WriteRecords & interp_write_records,const WriteRecords & jit_write_records)81 static bool DoesBehaviorMatch(const A32Unicorn<ThumbTestEnv>& uni, const A32::Jit& jit,
82                               const WriteRecords& interp_write_records, const WriteRecords& jit_write_records) {
83     const auto interp_regs = uni.GetRegisters();
84     const auto jit_regs = jit.Regs();
85 
86     return std::equal(interp_regs.begin(), interp_regs.end(), jit_regs.begin(), jit_regs.end()) &&
87            uni.GetCpsr() == jit.Cpsr() &&
88            interp_write_records == jit_write_records;
89 }
90 
RunInstance(size_t run_number,ThumbTestEnv & test_env,A32Unicorn<ThumbTestEnv> & uni,A32::Jit & jit,const ThumbTestEnv::RegisterArray & initial_regs,size_t instruction_count,size_t instructions_to_execute_count)91 static void RunInstance(size_t run_number, ThumbTestEnv& test_env, A32Unicorn<ThumbTestEnv>& uni, A32::Jit& jit, const ThumbTestEnv::RegisterArray& initial_regs,
92                         size_t instruction_count, size_t instructions_to_execute_count) {
93     uni.ClearPageCache();
94     jit.ClearCache();
95 
96     // Setup initial state
97 
98     uni.SetCpsr(0x000001F0);
99     uni.SetRegisters(initial_regs);
100     jit.SetCpsr(0x000001F0);
101     jit.Regs() = initial_regs;
102 
103     // Run interpreter
104     test_env.modified_memory.clear();
105     test_env.ticks_left = instructions_to_execute_count;
106     uni.SetPC(uni.GetPC() | 1);
107     uni.Run();
108     const bool uni_code_memory_modified = test_env.code_mem_modified_by_guest;
109     const auto interp_write_records = test_env.modified_memory;
110 
111     // Run jit
112     test_env.code_mem_modified_by_guest = false;
113     test_env.modified_memory.clear();
114     test_env.ticks_left = instructions_to_execute_count;
115     jit.Run();
116     const bool jit_code_memory_modified = test_env.code_mem_modified_by_guest;
117     const auto jit_write_records = test_env.modified_memory;
118     test_env.code_mem_modified_by_guest = false;
119 
120     REQUIRE(uni_code_memory_modified == jit_code_memory_modified);
121     if (uni_code_memory_modified) {
122         return;
123     }
124 
125     // Compare
126     if (!DoesBehaviorMatch(uni, jit, interp_write_records, jit_write_records)) {
127         printf("Failed at execution number %zu\n", run_number);
128 
129         printf("\nInstruction Listing: \n");
130         for (size_t i = 0; i < instruction_count; i++) {
131             printf("%04x %s\n", test_env.code_mem[i], A32::DisassembleThumb16(test_env.code_mem[i]).c_str());
132         }
133 
134         printf("\nInitial Register Listing: \n");
135         for (size_t i = 0; i < initial_regs.size(); i++) {
136             printf("%4zu: %08x\n", i, initial_regs[i]);
137         }
138 
139         printf("\nFinal Register Listing: \n");
140         printf("      unicorn   jit\n");
141         const auto uni_registers = uni.GetRegisters();
142         for (size_t i = 0; i < uni_registers.size(); i++) {
143             printf("%4zu: %08x %08x %s\n", i, uni_registers[i], jit.Regs()[i], uni_registers[i] != jit.Regs()[i] ? "*" : "");
144         }
145         printf("CPSR: %08x %08x %s\n", uni.GetCpsr(), jit.Cpsr(), uni.GetCpsr() != jit.Cpsr() ? "*" : "");
146 
147         printf("\nUnicorn Write Records:\n");
148         for (const auto& record : interp_write_records) {
149             printf("[%08x] = %02x\n", record.first, record.second);
150         }
151 
152         printf("\nJIT Write Records:\n");
153         for (const auto& record : jit_write_records) {
154             printf("[%08x] = %02x\n", record.first, record.second);
155         }
156 
157         A32::PSR cpsr;
158         cpsr.T(true);
159 
160         size_t num_insts = 0;
161         while (num_insts < instructions_to_execute_count) {
162             A32::LocationDescriptor descriptor = {u32(num_insts * 4), cpsr, A32::FPSCR{}};
163             IR::Block ir_block = A32::Translate(descriptor, [&test_env](u32 vaddr) { return test_env.MemoryReadCode(vaddr); }, {});
164             Optimization::A32GetSetElimination(ir_block);
165             Optimization::DeadCodeElimination(ir_block);
166             Optimization::A32ConstantMemoryReads(ir_block, &test_env);
167             Optimization::ConstantPropagation(ir_block);
168             Optimization::DeadCodeElimination(ir_block);
169             Optimization::VerificationPass(ir_block);
170             printf("\n\nIR:\n%s", IR::DumpBlock(ir_block).c_str());
171             printf("\n\nx86_64:\n%s", jit.Disassemble().c_str());
172             num_insts += ir_block.CycleCount();
173         }
174 
175 #ifdef _MSC_VER
176         __debugbreak();
177 #endif
178         FAIL();
179     }
180 }
181 
FuzzJitThumb(const size_t instruction_count,const size_t instructions_to_execute_count,const size_t run_count,const std::function<u16 ()> instruction_generator)182 void FuzzJitThumb(const size_t instruction_count, const size_t instructions_to_execute_count, const size_t run_count, const std::function<u16()> instruction_generator) {
183     ThumbTestEnv test_env;
184 
185     // Prepare memory.
186     test_env.code_mem.resize(instruction_count + 1);
187     test_env.code_mem.back() = 0xE7FE; // b +#0
188 
189     // Prepare test subjects
190     A32Unicorn uni{test_env};
191     A32::Jit jit{GetUserConfig(&test_env)};
192 
193     for (size_t run_number = 0; run_number < run_count; run_number++) {
194         ThumbTestEnv::RegisterArray initial_regs;
195         std::generate_n(initial_regs.begin(), initial_regs.size() - 1, []{ return RandInt<u32>(0, 0xFFFFFFFF); });
196         initial_regs[15] = 0;
197 
198         std::generate_n(test_env.code_mem.begin(), instruction_count, instruction_generator);
199 
200         RunInstance(run_number, test_env, uni, jit, initial_regs, instruction_count, instructions_to_execute_count);
201     }
202 }
203 
204 TEST_CASE("Fuzz Thumb instructions set 1", "[JitX64][Thumb]") {
205     const std::array instructions = {
206         ThumbInstGen("00000xxxxxxxxxxx"), // LSL <Rd>, <Rm>, #<imm5>
207         ThumbInstGen("00001xxxxxxxxxxx"), // LSR <Rd>, <Rm>, #<imm5>
208         ThumbInstGen("00010xxxxxxxxxxx"), // ASR <Rd>, <Rm>, #<imm5>
209         ThumbInstGen("000110oxxxxxxxxx"), // ADD/SUB_reg
210         ThumbInstGen("000111oxxxxxxxxx"), // ADD/SUB_imm
211         ThumbInstGen("001ooxxxxxxxxxxx"), // ADD/SUB/CMP/MOV_imm
212         ThumbInstGen("010000ooooxxxxxx"), // Data Processing
213         ThumbInstGen("010001000hxxxxxx"), // ADD (high registers)
214         ThumbInstGen("0100010101xxxxxx",  // CMP (high registers)
__anonae0dd4400502()215                      [](u16 inst){ return Common::Bits<3, 5>(inst) != 0b111; }), // R15 is UNPREDICTABLE
216         ThumbInstGen("0100010110xxxxxx",  // CMP (high registers)
__anonae0dd4400602()217                      [](u16 inst){ return Common::Bits<0, 2>(inst) != 0b111; }), // R15 is UNPREDICTABLE
218         ThumbInstGen("010001100hxxxxxx"), // MOV (high registers)
219         ThumbInstGen("10110000oxxxxxxx"), // Adjust stack pointer
220         ThumbInstGen("10110010ooxxxxxx"), // SXT/UXT
221         ThumbInstGen("1011101000xxxxxx"), // REV
222         ThumbInstGen("1011101001xxxxxx"), // REV16
223         ThumbInstGen("1011101011xxxxxx"), // REVSH
224         ThumbInstGen("01001xxxxxxxxxxx"), // LDR Rd, [PC, #]
225         ThumbInstGen("0101oooxxxxxxxxx"), // LDR/STR Rd, [Rn, Rm]
226         ThumbInstGen("011xxxxxxxxxxxxx"), // LDR(B)/STR(B) Rd, [Rn, #]
227         ThumbInstGen("1000xxxxxxxxxxxx"), // LDRH/STRH Rd, [Rn, #offset]
228         ThumbInstGen("1001xxxxxxxxxxxx"), // LDR/STR Rd, [SP, #]
229         ThumbInstGen("1011010xxxxxxxxx",  // PUSH
__anonae0dd4400702()230                      [](u16 inst){ return Common::Bits<0, 7>(inst) != 0; }), // Empty reg_list is UNPREDICTABLE
231         ThumbInstGen("10111100xxxxxxxx",  // POP (P = 0)
__anonae0dd4400802()232                      [](u16 inst){ return Common::Bits<0, 7>(inst) != 0; }), // Empty reg_list is UNPREDICTABLE
233         ThumbInstGen("1100xxxxxxxxxxxx", // STMIA/LDMIA
__anonae0dd4400902() 234                      [](u16 inst) {
235                          // Ensure that the architecturally undefined case of
236                          // the base register being within the list isn't hit.
237                          const u32 rn = Common::Bits<8, 10>(inst);
238                          return (inst & (1U << rn)) == 0 && Common::Bits<0, 7>(inst) != 0;
239                      }),
240         // TODO: We should properly test against swapped
241         //       endianness cases, however Unicorn doesn't
242         //       expose the intended endianness of a load/store
243         //       operation to memory through its hooks.
244 #if 0
245         ThumbInstGen("101101100101x000"), // SETEND
246 #endif
247     };
248 
__anonae0dd4400a02() 249     const auto instruction_select = [&]() -> u16 {
250         size_t inst_index = RandInt<size_t>(0, instructions.size() - 1);
251 
252         return instructions[inst_index].Generate();
253     };
254 
255     SECTION("single instructions") {
256         FuzzJitThumb(1, 2, 10000, instruction_select);
257     }
258 
259     SECTION("short blocks") {
260         FuzzJitThumb(5, 6, 3000, instruction_select);
261     }
262 
263     // TODO: Test longer blocks when Unicorn can consistently
264     //       run these without going into an infinite loop.
265 #if 0
266     SECTION("long blocks") {
267         FuzzJitThumb(1024, 1025, 1000, instruction_select);
268     }
269 #endif
270 }
271 
272 TEST_CASE("Fuzz Thumb instructions set 2 (affects PC)", "[JitX64][Thumb]") {
273     const std::array instructions = {
274         // TODO: We currently can't test BX/BLX as we have
275         //       no way of preventing the unpredictable
276         //       condition from occurring with the current interface.
277         //       (bits zero and one within the specified register
278         //       must not be address<1:0> == '10'.
279 #if 0
280         ThumbInstGen("01000111xmmmm000",  // BLX/BX
281                      [](u16 inst){
282                          const u32 Rm = Common::Bits<3, 6>(inst);
283                          return Rm != 15;
284                      }),
285 #endif
286         ThumbInstGen("1010oxxxxxxxxxxx"), // add to pc/sp
287         ThumbInstGen("11100xxxxxxxxxxx"), // B
288         ThumbInstGen("01000100h0xxxxxx"), // ADD (high registers)
289         ThumbInstGen("01000110h0xxxxxx"), // MOV (high registers)
290         ThumbInstGen("1101ccccxxxxxxxx",  // B<cond>
__anonae0dd4400b02()291                      [](u16 inst){
292                          const u32 c = Common::Bits<9, 12>(inst);
293                          return c < 0b1110; // Don't want SWI or undefined instructions.
294                      }),
295         ThumbInstGen("1011o0i1iiiiinnn"), // CBZ/CBNZ
296         ThumbInstGen("10110110011x0xxx"), // CPS
297 
298         // TODO: We currently have no control over the generated
299         //       values when creating new pages, so we can't
300         //       reliably test this yet.
301 #if 0
302         ThumbInstGen("10111101xxxxxxxx"), // POP (R = 1)
303 #endif
304     };
305 
__anonae0dd4400c02() 306     const auto instruction_select = [&]() -> u16 {
307         size_t inst_index = RandInt<size_t>(0, instructions.size() - 1);
308 
309         return instructions[inst_index].Generate();
310     };
311 
312     FuzzJitThumb(1, 1, 10000, instruction_select);
313 }
314 
315 TEST_CASE("Verify fix for off by one error in MemoryRead32 worked", "[Thumb]") {
316     ThumbTestEnv test_env;
317 
318     // Prepare test subjects
319     A32Unicorn<ThumbTestEnv> uni{test_env};
320     A32::Jit jit{GetUserConfig(&test_env)};
321 
322     constexpr ThumbTestEnv::RegisterArray initial_regs {
323         0xe90ecd70,
324         0x3e3b73c3,
325         0x571616f9,
326         0x0b1ef45a,
327         0xb3a829f2,
328         0x915a7a6a,
329         0x579c38f4,
330         0xd9ffe391,
331         0x55b6682b,
332         0x458d8f37,
333         0x8f3eb3dc,
334         0xe18c0e7d,
335         0x6752657a,
336         0x00001766,
337         0xdbbf23e3,
338         0x00000000,
339     };
340 
341     test_env.code_mem = {
342         0x40B8, // lsls r0, r7, #0
343         0x01CA, // lsls r2, r1, #7
344         0x83A1, // strh r1, [r4, #28]
345         0x708A, // strb r2, [r1, #2]
346         0xBCC4, // pop {r2, r6, r7}
347         0xE7FE, // b +#0
348     };
349 
350     RunInstance(1, test_env, uni, jit, initial_regs, 5, 5);
351 }
352