xref: /aosp_15_r20/external/zucchini/arm_utils_unittest.cc (revision a03ca8b91e029cd15055c20c78c2e087c84792e4)
1*a03ca8b9SKrzysztof Kosiński // Copyright 2019 The Chromium Authors. All rights reserved.
2*a03ca8b9SKrzysztof Kosiński // Use of this source code is governed by a BSD-style license that can be
3*a03ca8b9SKrzysztof Kosiński // found in the LICENSE file.
4*a03ca8b9SKrzysztof Kosiński 
5*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/arm_utils.h"
6*a03ca8b9SKrzysztof Kosiński 
7*a03ca8b9SKrzysztof Kosiński #include <stddef.h>
8*a03ca8b9SKrzysztof Kosiński #include <stdint.h>
9*a03ca8b9SKrzysztof Kosiński 
10*a03ca8b9SKrzysztof Kosiński #include <algorithm>
11*a03ca8b9SKrzysztof Kosiński #include <cctype>
12*a03ca8b9SKrzysztof Kosiński #include <initializer_list>
13*a03ca8b9SKrzysztof Kosiński #include <map>
14*a03ca8b9SKrzysztof Kosiński #include <sstream>
15*a03ca8b9SKrzysztof Kosiński #include <string>
16*a03ca8b9SKrzysztof Kosiński #include <vector>
17*a03ca8b9SKrzysztof Kosiński 
18*a03ca8b9SKrzysztof Kosiński #include "base/check_op.h"
19*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/address_translator.h"
20*a03ca8b9SKrzysztof Kosiński #include "testing/gtest/include/gtest/gtest.h"
21*a03ca8b9SKrzysztof Kosiński 
22*a03ca8b9SKrzysztof Kosiński namespace zucchini {
23*a03ca8b9SKrzysztof Kosiński 
24*a03ca8b9SKrzysztof Kosiński namespace {
25*a03ca8b9SKrzysztof Kosiński 
26*a03ca8b9SKrzysztof Kosiński // "Clean slate" |code|s for branch instruction encodings with |disp| = 0, and
27*a03ca8b9SKrzysztof Kosiński // if applicable, |cond| = 0.
28*a03ca8b9SKrzysztof Kosiński uint32_t kCleanSlateB_A1 = 0x0A000000;    // A24.
29*a03ca8b9SKrzysztof Kosiński uint32_t kCleanSlateBL_A1 = 0x0B000000;   // A24.
30*a03ca8b9SKrzysztof Kosiński uint32_t kCleanSlateBLX_A2 = 0xFA000000;  // A24.
31*a03ca8b9SKrzysztof Kosiński uint16_t kCleanSlateB_T1 = 0xD000;        // T8.
32*a03ca8b9SKrzysztof Kosiński uint16_t kCleanSlateB_T2 = 0xE000;        // T11.
33*a03ca8b9SKrzysztof Kosiński uint32_t kCleanSlateB_T3 = 0xF0008000;    // T20.
34*a03ca8b9SKrzysztof Kosiński // For T24 encodings, |disp| = 0 means J1 = J2 = 1, so include 0x00002800.
35*a03ca8b9SKrzysztof Kosiński uint32_t kCleanSlateB_T4 = 0xF0009000 | 0x00002800;    // T24.
36*a03ca8b9SKrzysztof Kosiński uint32_t kCleanSlateBL_T1 = 0xF000D000 | 0x00002800;   // T24.
37*a03ca8b9SKrzysztof Kosiński uint32_t kCleanSlateBLX_T2 = 0xF000C000 | 0x00002800;  // T24.
38*a03ca8b9SKrzysztof Kosiński 
39*a03ca8b9SKrzysztof Kosiński // For AArch64.
40*a03ca8b9SKrzysztof Kosiński uint32_t kCleanSlate64TBZw = 0x36000000;   // Immd14.
41*a03ca8b9SKrzysztof Kosiński uint32_t kCleanSlate64TBZz = 0xB6000000;   // Immd14.
42*a03ca8b9SKrzysztof Kosiński uint32_t kCleanSlate64TBNZw = 0x37000000;  // Immd14.
43*a03ca8b9SKrzysztof Kosiński uint32_t kCleanSlate64TBNZz = 0xB7000000;  // Immd14.
44*a03ca8b9SKrzysztof Kosiński uint32_t kCleanSlate64Bcond = 0x54000000;  // Immd19.
45*a03ca8b9SKrzysztof Kosiński uint32_t kCleanSlate64CBZw = 0x34000000;   // Immd19.
46*a03ca8b9SKrzysztof Kosiński uint32_t kCleanSlate64CBZz = 0xB4000000;   // Immd19.
47*a03ca8b9SKrzysztof Kosiński uint32_t kCleanSlate64CBNZw = 0x35000000;  // Immd19.
48*a03ca8b9SKrzysztof Kosiński uint32_t kCleanSlate64CBNZz = 0xB5000000;  // Immd19.
49*a03ca8b9SKrzysztof Kosiński uint32_t kCleanSlate64B = 0x14000000;      // Immd26.
50*a03ca8b9SKrzysztof Kosiński uint32_t kCleanSlate64BL = 0x94000000;     // Immd26.
51*a03ca8b9SKrzysztof Kosiński 
52*a03ca8b9SKrzysztof Kosiński // Special case: Cond = 0xE => AL.
53*a03ca8b9SKrzysztof Kosiński uint32_t kCleanSlateBAL_A1 = kCleanSlateB_A1 | (0xE << 28);  //
54*a03ca8b9SKrzysztof Kosiński 
55*a03ca8b9SKrzysztof Kosiński // Test helper: Extracts |components| from |value| (may be |code| or |disp|)
56*a03ca8b9SKrzysztof Kosiński // based on |pattern|. Also performs consistency checks. On success, writes to
57*a03ca8b9SKrzysztof Kosiński // |*components| and returns true. Otherwise returns false.
58*a03ca8b9SKrzysztof Kosiński // Example (all numbers are in binary):
59*a03ca8b9SKrzysztof Kosiński //   |pattern| = "11110Scc cciiiiii 10(J1)0(J2)jjj jjjj...."
60*a03ca8b9SKrzysztof Kosiński //     |value| =  11110111 00111000 10 1  0 0  111 11000101
61*a03ca8b9SKrzysztof Kosiński // Result: Noting that all 0's and 1's are consistent, returns true with:
62*a03ca8b9SKrzysztof Kosiński //   |*components| = {S: 1, c: 1100, i: 111000, J1: 1, J2: 0, j: 1111100}
63*a03ca8b9SKrzysztof Kosiński // Rules for |pattern|:
64*a03ca8b9SKrzysztof Kosiński // * Spaces are ignored.
65*a03ca8b9SKrzysztof Kosiński // * '.' means "don't care".
66*a03ca8b9SKrzysztof Kosiński // * '0' and '1' are expected literals; mismatch leads to failure.
67*a03ca8b9SKrzysztof Kosiński // * A variable name is specified as:
68*a03ca8b9SKrzysztof Kosiński //   * A single letter.
69*a03ca8b9SKrzysztof Kosiński //   * "(var)", where "var" is a name that begins with a letter.
70*a03ca8b9SKrzysztof Kosiński // * If a variable's first letter is uppercase, then it's a singleton bit.
71*a03ca8b9SKrzysztof Kosiński //   * If repeated, consistency check is applied (must be identical).
72*a03ca8b9SKrzysztof Kosiński // * If a variable's first letter is lowercase, then it spans multiple bits.
73*a03ca8b9SKrzysztof Kosiński //   * These need not be contiguous, but order is preserved (big-endian).
SplitBits(const std::string & pattern,uint32_t value,std::map<std::string,uint32_t> * components)74*a03ca8b9SKrzysztof Kosiński static bool SplitBits(const std::string& pattern,
75*a03ca8b9SKrzysztof Kosiński                       uint32_t value,
76*a03ca8b9SKrzysztof Kosiński                       std::map<std::string, uint32_t>* components) {
77*a03ca8b9SKrzysztof Kosiński   CHECK(components);
78*a03ca8b9SKrzysztof Kosiński 
79*a03ca8b9SKrzysztof Kosiński   // Split |pattern| into |token_list|.
80*a03ca8b9SKrzysztof Kosiński   std::vector<std::string> token_list;
81*a03ca8b9SKrzysztof Kosiński   size_t bracket_start = std::string::npos;
82*a03ca8b9SKrzysztof Kosiński   for (size_t i = 0; i < pattern.size(); ++i) {
83*a03ca8b9SKrzysztof Kosiński     char ch = pattern[i];
84*a03ca8b9SKrzysztof Kosiński     if (bracket_start == std::string::npos) {
85*a03ca8b9SKrzysztof Kosiński       if (ch == '(')
86*a03ca8b9SKrzysztof Kosiński         bracket_start = i + 1;
87*a03ca8b9SKrzysztof Kosiński       else if (ch != ' ')  // Ignore space.
88*a03ca8b9SKrzysztof Kosiński         token_list.push_back(std::string(1, ch));
89*a03ca8b9SKrzysztof Kosiński     } else if (ch == ')') {
90*a03ca8b9SKrzysztof Kosiński       token_list.push_back(pattern.substr(bracket_start, i - bracket_start));
91*a03ca8b9SKrzysztof Kosiński       bracket_start = std::string::npos;
92*a03ca8b9SKrzysztof Kosiński     }
93*a03ca8b9SKrzysztof Kosiński   }
94*a03ca8b9SKrzysztof Kosiński   CHECK_EQ(std::string::npos, bracket_start);  // No dangling "(".
95*a03ca8b9SKrzysztof Kosiński 
96*a03ca8b9SKrzysztof Kosiński   // Process each token.
97*a03ca8b9SKrzysztof Kosiński   size_t num_tokens = token_list.size();
98*a03ca8b9SKrzysztof Kosiński   std::map<std::string, uint32_t> temp_components;
99*a03ca8b9SKrzysztof Kosiński   CHECK(num_tokens == 32 || (num_tokens == 16 && value <= 0xFFFF));
100*a03ca8b9SKrzysztof Kosiński   for (size_t i = 0; i < num_tokens; ++i) {
101*a03ca8b9SKrzysztof Kosiński     const std::string& token = token_list[i];
102*a03ca8b9SKrzysztof Kosiński     CHECK(!token.empty());
103*a03ca8b9SKrzysztof Kosiński     uint32_t bit = (value >> (num_tokens - 1 - i)) & 1;
104*a03ca8b9SKrzysztof Kosiński     if (token == "0" || token == "1") {
105*a03ca8b9SKrzysztof Kosiński       if (token[0] != static_cast<char>('0' + bit))
106*a03ca8b9SKrzysztof Kosiński         return false;  // Fail: Mismatch.
107*a03ca8b9SKrzysztof Kosiński     } else if (isupper(token[0])) {
108*a03ca8b9SKrzysztof Kosiński       if (temp_components.count(token)) {
109*a03ca8b9SKrzysztof Kosiński         if (temp_components[token] != bit)
110*a03ca8b9SKrzysztof Kosiński           return false;  // Fail: Singleton bit not uniform.
111*a03ca8b9SKrzysztof Kosiński       } else {
112*a03ca8b9SKrzysztof Kosiński         temp_components[token] = bit;
113*a03ca8b9SKrzysztof Kosiński       }
114*a03ca8b9SKrzysztof Kosiński     } else if (islower(token[0])) {
115*a03ca8b9SKrzysztof Kosiński       temp_components[token] = (temp_components[token] << 1) | bit;
116*a03ca8b9SKrzysztof Kosiński     } else if (token != ".") {
117*a03ca8b9SKrzysztof Kosiński       return false;  // Fail: Unrecognized token.
118*a03ca8b9SKrzysztof Kosiński     }
119*a03ca8b9SKrzysztof Kosiński   }
120*a03ca8b9SKrzysztof Kosiński   components->swap(temp_components);
121*a03ca8b9SKrzysztof Kosiński   return true;
122*a03ca8b9SKrzysztof Kosiński }
123*a03ca8b9SKrzysztof Kosiński 
124*a03ca8b9SKrzysztof Kosiński // AArch32 or AArch64 instruction specification for tests. May be 16-bit or
125*a03ca8b9SKrzysztof Kosiński // 32-bit (determined by INT_T).
126*a03ca8b9SKrzysztof Kosiński template <typename INT_T>
127*a03ca8b9SKrzysztof Kosiński struct ArmRelInstruction {
ArmRelInstructionzucchini::__anon81e55cf60111::ArmRelInstruction128*a03ca8b9SKrzysztof Kosiński   ArmRelInstruction(const std::string& code_pattern_in, INT_T code)
129*a03ca8b9SKrzysztof Kosiński       : code_pattern(code_pattern_in), clean_slate_code(code) {}
130*a03ca8b9SKrzysztof Kosiński 
131*a03ca8b9SKrzysztof Kosiński   // Code pattern for SplitBits().
132*a03ca8b9SKrzysztof Kosiński   std::string code_pattern;
133*a03ca8b9SKrzysztof Kosiński 
134*a03ca8b9SKrzysztof Kosiński   // "Clean slate" |code| encodes |disp| = 0.
135*a03ca8b9SKrzysztof Kosiński   INT_T clean_slate_code;
136*a03ca8b9SKrzysztof Kosiński };
137*a03ca8b9SKrzysztof Kosiński 
138*a03ca8b9SKrzysztof Kosiński // Tester for ARM Encode / Decode functions for |disp| <-> |code|.
139*a03ca8b9SKrzysztof Kosiński template <typename TRAITS>
140*a03ca8b9SKrzysztof Kosiński class ArmTranslatorEncodeDecodeTest {
141*a03ca8b9SKrzysztof Kosiński  public:
142*a03ca8b9SKrzysztof Kosiński   using CODE_T = typename TRAITS::code_t;
143*a03ca8b9SKrzysztof Kosiński 
ArmTranslatorEncodeDecodeTest()144*a03ca8b9SKrzysztof Kosiński   ArmTranslatorEncodeDecodeTest() {}
145*a03ca8b9SKrzysztof Kosiński 
146*a03ca8b9SKrzysztof Kosiński   // For each instruction (with |clean_slate_code| in |instr_list|) and for each
147*a03ca8b9SKrzysztof Kosiński   // |disp| in |good_disp_list|, forms |code| with |encode_fun()| and checks for
148*a03ca8b9SKrzysztof Kosiński   // success. Extracts |disp_out| with |decode_fun()| and checks that it's the
149*a03ca8b9SKrzysztof Kosiński   // original |disp|. For each (|disp|, |code|) pair, extracts components using
150*a03ca8b9SKrzysztof Kosiński   // SplitBits(), and checks that components from |toks_list| are identical. For
151*a03ca8b9SKrzysztof Kosiński   // each |disp| in |bad_disp_list|, checks that |decode_fun_()| fails.
Run(const std::string & disp_pattern,const std::vector<std::string> & toks_list,const std::vector<ArmRelInstruction<CODE_T>> & instr_list,const std::vector<arm_disp_t> & good_disp_list,const std::vector<arm_disp_t> & bad_disp_list)152*a03ca8b9SKrzysztof Kosiński   void Run(const std::string& disp_pattern,
153*a03ca8b9SKrzysztof Kosiński            const std::vector<std::string>& toks_list,
154*a03ca8b9SKrzysztof Kosiński            const std::vector<ArmRelInstruction<CODE_T>>& instr_list,
155*a03ca8b9SKrzysztof Kosiński            const std::vector<arm_disp_t>& good_disp_list,
156*a03ca8b9SKrzysztof Kosiński            const std::vector<arm_disp_t>& bad_disp_list) {
157*a03ca8b9SKrzysztof Kosiński     ArmAlign (*decode_fun)(CODE_T, arm_disp_t*) = TRAITS::Decode;
158*a03ca8b9SKrzysztof Kosiński     bool (*encode_fun)(arm_disp_t, CODE_T*) = TRAITS::Encode;
159*a03ca8b9SKrzysztof Kosiński 
160*a03ca8b9SKrzysztof Kosiński     for (const ArmRelInstruction<CODE_T> instr : instr_list) {
161*a03ca8b9SKrzysztof Kosiński       // Parse clean slate code bytes, and ensure it's well-formed.
162*a03ca8b9SKrzysztof Kosiński       std::map<std::string, uint32_t> clean_slate_code_components;
163*a03ca8b9SKrzysztof Kosiński       EXPECT_TRUE(SplitBits(instr.code_pattern, instr.clean_slate_code,
164*a03ca8b9SKrzysztof Kosiński                             &clean_slate_code_components));
165*a03ca8b9SKrzysztof Kosiński 
166*a03ca8b9SKrzysztof Kosiński       for (arm_disp_t disp : good_disp_list) {
167*a03ca8b9SKrzysztof Kosiński         CODE_T code = instr.clean_slate_code;
168*a03ca8b9SKrzysztof Kosiński         // Encode |disp| to |code|.
169*a03ca8b9SKrzysztof Kosiński         EXPECT_TRUE((*encode_fun)(disp, &code)) << disp;
170*a03ca8b9SKrzysztof Kosiński         arm_disp_t disp_out = 0;
171*a03ca8b9SKrzysztof Kosiński 
172*a03ca8b9SKrzysztof Kosiński         // Extract components (performs consistency checks) and compare.
173*a03ca8b9SKrzysztof Kosiński         std::map<std::string, uint32_t> disp_components;
174*a03ca8b9SKrzysztof Kosiński         EXPECT_TRUE(SplitBits(disp_pattern, static_cast<uint32_t>(disp),
175*a03ca8b9SKrzysztof Kosiński                               &disp_components));
176*a03ca8b9SKrzysztof Kosiński         std::map<std::string, uint32_t> code_components;
177*a03ca8b9SKrzysztof Kosiński         EXPECT_TRUE(SplitBits(instr.code_pattern, code, &code_components));
178*a03ca8b9SKrzysztof Kosiński         for (const std::string& tok : toks_list) {
179*a03ca8b9SKrzysztof Kosiński           EXPECT_EQ(1U, disp_components.count(tok)) << tok;
180*a03ca8b9SKrzysztof Kosiński           EXPECT_EQ(1U, code_components.count(tok)) << tok;
181*a03ca8b9SKrzysztof Kosiński           EXPECT_EQ(disp_components[tok], code_components[tok]) << tok;
182*a03ca8b9SKrzysztof Kosiński         }
183*a03ca8b9SKrzysztof Kosiński 
184*a03ca8b9SKrzysztof Kosiński         // Decode |code| to |disp_out|, check fidelity.
185*a03ca8b9SKrzysztof Kosiński         EXPECT_NE(kArmAlignFail, (*decode_fun)(code, &disp_out));
186*a03ca8b9SKrzysztof Kosiński         EXPECT_EQ(disp, disp_out);
187*a03ca8b9SKrzysztof Kosiński 
188*a03ca8b9SKrzysztof Kosiński         // Sanity check: Re-encode |disp| into |code|, ensure no change.
189*a03ca8b9SKrzysztof Kosiński         CODE_T code_copy = code;
190*a03ca8b9SKrzysztof Kosiński         EXPECT_TRUE((*encode_fun)(disp, &code));
191*a03ca8b9SKrzysztof Kosiński         EXPECT_EQ(code_copy, code);
192*a03ca8b9SKrzysztof Kosiński 
193*a03ca8b9SKrzysztof Kosiński         // Encode 0, ensure we get clean slate |code| back.
194*a03ca8b9SKrzysztof Kosiński         EXPECT_TRUE((*encode_fun)(0, &code));
195*a03ca8b9SKrzysztof Kosiński         EXPECT_EQ(instr.clean_slate_code, code);
196*a03ca8b9SKrzysztof Kosiński       }
197*a03ca8b9SKrzysztof Kosiński 
198*a03ca8b9SKrzysztof Kosiński       for (arm_disp_t disp : bad_disp_list) {
199*a03ca8b9SKrzysztof Kosiński         CODE_T code = instr.clean_slate_code;
200*a03ca8b9SKrzysztof Kosiński         EXPECT_FALSE((*encode_fun)(disp, &code)) << disp;
201*a03ca8b9SKrzysztof Kosiński         // Value does not get modified after failure.
202*a03ca8b9SKrzysztof Kosiński         EXPECT_EQ(instr.clean_slate_code, code);
203*a03ca8b9SKrzysztof Kosiński       }
204*a03ca8b9SKrzysztof Kosiński     }
205*a03ca8b9SKrzysztof Kosiński   }
206*a03ca8b9SKrzysztof Kosiński };
207*a03ca8b9SKrzysztof Kosiński 
208*a03ca8b9SKrzysztof Kosiński // Tester for ARM Write / Read functions for |target_rva| <-> |code|.
209*a03ca8b9SKrzysztof Kosiński template <typename TRAITS>
210*a03ca8b9SKrzysztof Kosiński class ArmTranslatorWriteReadTest {
211*a03ca8b9SKrzysztof Kosiński  public:
212*a03ca8b9SKrzysztof Kosiński   using CODE_T = typename TRAITS::code_t;
213*a03ca8b9SKrzysztof Kosiński 
ArmTranslatorWriteReadTest()214*a03ca8b9SKrzysztof Kosiński   ArmTranslatorWriteReadTest() {}
215*a03ca8b9SKrzysztof Kosiński 
216*a03ca8b9SKrzysztof Kosiński   // Expects successful Write() to |clean_slate_code| for each |target_rva_list|
217*a03ca8b9SKrzysztof Kosiński   // RVA, using each |instr_rva_list| RVA, and that the resulting |code| leads
218*a03ca8b9SKrzysztof Kosiński   // to successful Read(), which recovers |instr_rva|.
Accept(CODE_T clean_slate_code,const std::vector<rva_t> & instr_rva_list,const std::vector<rva_t> & target_rva_list)219*a03ca8b9SKrzysztof Kosiński   void Accept(CODE_T clean_slate_code,
220*a03ca8b9SKrzysztof Kosiński               const std::vector<rva_t>& instr_rva_list,
221*a03ca8b9SKrzysztof Kosiński               const std::vector<rva_t>& target_rva_list) {
222*a03ca8b9SKrzysztof Kosiński     bool (*read_fun)(rva_t, CODE_T, rva_t*) = TRAITS::Read;
223*a03ca8b9SKrzysztof Kosiński     bool (*write_fun)(rva_t, rva_t, CODE_T*) = TRAITS::Write;
224*a03ca8b9SKrzysztof Kosiński 
225*a03ca8b9SKrzysztof Kosiński     for (rva_t instr_rva : instr_rva_list) {
226*a03ca8b9SKrzysztof Kosiński       for (rva_t target_rva : target_rva_list) {
227*a03ca8b9SKrzysztof Kosiński         CODE_T code = clean_slate_code;
228*a03ca8b9SKrzysztof Kosiński         // Write |target_rva| to |code|.
229*a03ca8b9SKrzysztof Kosiński         EXPECT_TRUE((*write_fun)(instr_rva, target_rva, &code)) << target_rva;
230*a03ca8b9SKrzysztof Kosiński         rva_t target_rva_out = kInvalidRva;
231*a03ca8b9SKrzysztof Kosiński 
232*a03ca8b9SKrzysztof Kosiński         // Read |code| to |target_rva_out|, check fidelity.
233*a03ca8b9SKrzysztof Kosiński         EXPECT_TRUE((*read_fun)(instr_rva, code, &target_rva_out));
234*a03ca8b9SKrzysztof Kosiński         EXPECT_EQ(target_rva, target_rva_out);
235*a03ca8b9SKrzysztof Kosiński 
236*a03ca8b9SKrzysztof Kosiński         // Sanity check: Rewrite |target_rva| into |code|, ensure no change.
237*a03ca8b9SKrzysztof Kosiński         CODE_T code_copy = code;
238*a03ca8b9SKrzysztof Kosiński         EXPECT_TRUE((*write_fun)(instr_rva, target_rva, &code));
239*a03ca8b9SKrzysztof Kosiński         EXPECT_EQ(code_copy, code);
240*a03ca8b9SKrzysztof Kosiński       }
241*a03ca8b9SKrzysztof Kosiński     }
242*a03ca8b9SKrzysztof Kosiński   }
243*a03ca8b9SKrzysztof Kosiński 
244*a03ca8b9SKrzysztof Kosiński   // Expects failed Write() to |clean_slate_code| for each |target_rva_list|
245*a03ca8b9SKrzysztof Kosiński   // RVA, using each |instr_rva_list| RVA.
Reject(CODE_T clean_slate_code,const std::vector<rva_t> & instr_rva_list,const std::vector<rva_t> & target_rva_list)246*a03ca8b9SKrzysztof Kosiński   void Reject(CODE_T clean_slate_code,
247*a03ca8b9SKrzysztof Kosiński               const std::vector<rva_t>& instr_rva_list,
248*a03ca8b9SKrzysztof Kosiński               const std::vector<rva_t>& target_rva_list) {
249*a03ca8b9SKrzysztof Kosiński     bool (*write_fun)(rva_t, rva_t, CODE_T*) = TRAITS::Write;
250*a03ca8b9SKrzysztof Kosiński 
251*a03ca8b9SKrzysztof Kosiński     for (rva_t instr_rva : instr_rva_list) {
252*a03ca8b9SKrzysztof Kosiński       for (rva_t target_rva : target_rva_list) {
253*a03ca8b9SKrzysztof Kosiński         CODE_T code = clean_slate_code;
254*a03ca8b9SKrzysztof Kosiński         EXPECT_FALSE((*write_fun)(instr_rva, target_rva, &code)) << target_rva;
255*a03ca8b9SKrzysztof Kosiński         // Output variable is unmodified after failure.
256*a03ca8b9SKrzysztof Kosiński         EXPECT_EQ(clean_slate_code, code);
257*a03ca8b9SKrzysztof Kosiński       }
258*a03ca8b9SKrzysztof Kosiński     }
259*a03ca8b9SKrzysztof Kosiński   }
260*a03ca8b9SKrzysztof Kosiński };
261*a03ca8b9SKrzysztof Kosiński 
262*a03ca8b9SKrzysztof Kosiński }  // namespace
263*a03ca8b9SKrzysztof Kosiński 
264*a03ca8b9SKrzysztof Kosiński // Test for test helper.
TEST(ArmUtilsTest,SplitBits)265*a03ca8b9SKrzysztof Kosiński TEST(ArmUtilsTest, SplitBits) {
266*a03ca8b9SKrzysztof Kosiński   // If |expected| == "BAD" then we expect failure.
267*a03ca8b9SKrzysztof Kosiński   auto run_test = [](const std::string& expected, const std::string& pattern,
268*a03ca8b9SKrzysztof Kosiński                      uint32_t value) {
269*a03ca8b9SKrzysztof Kosiński     std::map<std::string, uint32_t> components;
270*a03ca8b9SKrzysztof Kosiński     if (expected == "BAD") {
271*a03ca8b9SKrzysztof Kosiński       EXPECT_FALSE(SplitBits(pattern, value, &components));
272*a03ca8b9SKrzysztof Kosiński       EXPECT_TRUE(components.empty());
273*a03ca8b9SKrzysztof Kosiński     } else {
274*a03ca8b9SKrzysztof Kosiński       EXPECT_TRUE(SplitBits(pattern, value, &components));
275*a03ca8b9SKrzysztof Kosiński       std::ostringstream oss;
276*a03ca8b9SKrzysztof Kosiński       // Not using AsHex<>, since number of digits is not fixed.
277*a03ca8b9SKrzysztof Kosiński       oss << std::uppercase << std::hex;
278*a03ca8b9SKrzysztof Kosiński       std::string sep = "";
279*a03ca8b9SKrzysztof Kosiński       for (auto it : components) {
280*a03ca8b9SKrzysztof Kosiński         oss << sep << it.first << "=" << it.second;
281*a03ca8b9SKrzysztof Kosiński         sep = ",";
282*a03ca8b9SKrzysztof Kosiński       }
283*a03ca8b9SKrzysztof Kosiński       EXPECT_EQ(expected, oss.str());
284*a03ca8b9SKrzysztof Kosiński     }
285*a03ca8b9SKrzysztof Kosiński   };
286*a03ca8b9SKrzysztof Kosiński 
287*a03ca8b9SKrzysztof Kosiński   run_test("a=ABCD0123", "aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa", 0xABCD0123);
288*a03ca8b9SKrzysztof Kosiński   run_test("a=ABCD,b=123", "aaaaaaaa aaaaaaaa bbbbbbbb bbbbbbbb", 0xABCD0123);
289*a03ca8b9SKrzysztof Kosiński   run_test("a=23,b=1,c=CD,d=AB", "dddddddd cccccccc bbbbbbbb aaaaaaaa",
290*a03ca8b9SKrzysztof Kosiński            0xABCD0123);
291*a03ca8b9SKrzysztof Kosiński   run_test("", "........ ........ ........ ........", 0xABCD0123);
292*a03ca8b9SKrzysztof Kosiński   run_test("t=AC02", " tttt.... tt tt.... tttt....tttt....  ", 0xABCD0123);
293*a03ca8b9SKrzysztof Kosiński 
294*a03ca8b9SKrzysztof Kosiński   run_test("a=8,b=C,c=E,d1=F", "aaaabbbb cccc(d1)(d1)(d1)(d1)", 0x8CEF);
295*a03ca8b9SKrzysztof Kosiński   run_test("a=F,b=7,c=3,d1=1", "abc(d1)abc(d1) abc(d1)abc(d1)", 0x8CEF);
296*a03ca8b9SKrzysztof Kosiński 
297*a03ca8b9SKrzysztof Kosiński   run_test("A1=0,X=1", "(A1)XX(A1) X(A1)(A1)(A1)   (X)(A1)(X)X(X)(X)X(A1)",
298*a03ca8b9SKrzysztof Kosiński            0x68BE);
299*a03ca8b9SKrzysztof Kosiński   run_test("BAD", "(A1)XX(A1) X(A1)(A1)(A1)   (X)(A1)(X)X(X)(X)X(A1)", 0x68BF);
300*a03ca8b9SKrzysztof Kosiński   run_test("BAD", "(A1)XX(A1) X(A1)(A1)(A1)   (X)(A1)(X)X(X)(X)X(A1)", 0x683E);
301*a03ca8b9SKrzysztof Kosiński 
302*a03ca8b9SKrzysztof Kosiński   run_test("A=1,B=0,a=C", "AAAAaaaa BBBB01..", 0xFC06);
303*a03ca8b9SKrzysztof Kosiński   run_test("A=1,B=0,a=4", "AAAAaaaa BBBB01..", 0xF406);
304*a03ca8b9SKrzysztof Kosiński   run_test("A=0,B=1,a=C", "AAAAaaaa BBBB01..", 0x0CF5);
305*a03ca8b9SKrzysztof Kosiński   run_test("BAD", "AAAAaaaa BBBB01..", 0xEC06);  // Non-uniform A.
306*a03ca8b9SKrzysztof Kosiński   run_test("BAD", "AAAAaaaa BBBB01..", 0xFC16);  // Non-uniform B.
307*a03ca8b9SKrzysztof Kosiński   run_test("BAD", "AAAAaaaa BBBB01..", 0xFC02);  // Constant mismatch.
308*a03ca8b9SKrzysztof Kosiński }
309*a03ca8b9SKrzysztof Kosiński 
TEST(AArch32Rel32Translator,Fetch)310*a03ca8b9SKrzysztof Kosiński TEST(AArch32Rel32Translator, Fetch) {
311*a03ca8b9SKrzysztof Kosiński   std::vector<uint8_t> bytes = {0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE};
312*a03ca8b9SKrzysztof Kosiński   ConstBufferView region(&bytes[0], bytes.size());
313*a03ca8b9SKrzysztof Kosiński   AArch32Rel32Translator translator;
314*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(0x76543210U, translator.FetchArmCode32(region, 0U));
315*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(0xFEDCBA98U, translator.FetchArmCode32(region, 4U));
316*a03ca8b9SKrzysztof Kosiński 
317*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(0x3210U, translator.FetchThumb2Code16(region, 0U));
318*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(0xFEDCU, translator.FetchThumb2Code16(region, 6U));
319*a03ca8b9SKrzysztof Kosiński 
320*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(0x32107654U, translator.FetchThumb2Code32(region, 0U));
321*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(0xBA98FEDCU, translator.FetchThumb2Code32(region, 4U));
322*a03ca8b9SKrzysztof Kosiński }
323*a03ca8b9SKrzysztof Kosiński 
TEST(AArch32Rel32Translator,Store)324*a03ca8b9SKrzysztof Kosiński TEST(AArch32Rel32Translator, Store) {
325*a03ca8b9SKrzysztof Kosiński   std::vector<uint8_t> expected = {
326*a03ca8b9SKrzysztof Kosiński       0xFF, 0xFF, 0xFF, 0xFF,  // Padding.
327*a03ca8b9SKrzysztof Kosiński       0x10, 0x32, 0x54, 0x76,  // ARM 32-bit.
328*a03ca8b9SKrzysztof Kosiński       0xFF, 0xFF,              // Padding.
329*a03ca8b9SKrzysztof Kosiński       0x42, 0x86,              // THUMB2 16-bit.
330*a03ca8b9SKrzysztof Kosiński       0xFF, 0xFF,              // Padding.
331*a03ca8b9SKrzysztof Kosiński       0xDC, 0xFE, 0x98, 0xBA,  // THUMB2 32-bit.
332*a03ca8b9SKrzysztof Kosiński       0xFF, 0xFF, 0xFF, 0xFF   // Padding.
333*a03ca8b9SKrzysztof Kosiński   };
334*a03ca8b9SKrzysztof Kosiński 
335*a03ca8b9SKrzysztof Kosiński   std::vector<uint8_t> bytes(4 * 2 + 2 * 3 + 4 * 2, 0xFF);
336*a03ca8b9SKrzysztof Kosiński   MutableBufferView region(&bytes[0], bytes.size());
337*a03ca8b9SKrzysztof Kosiński   CHECK_EQ(expected.size(), bytes.size());
338*a03ca8b9SKrzysztof Kosiński 
339*a03ca8b9SKrzysztof Kosiński   AArch32Rel32Translator translator;
340*a03ca8b9SKrzysztof Kosiński   translator.StoreArmCode32(region, 4U, 0x76543210U);
341*a03ca8b9SKrzysztof Kosiński   translator.StoreThumb2Code16(region, 10U, 0x8642U);
342*a03ca8b9SKrzysztof Kosiński   translator.StoreThumb2Code32(region, 14U, 0xFEDCBA98U);
343*a03ca8b9SKrzysztof Kosiński 
344*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(expected, bytes);
345*a03ca8b9SKrzysztof Kosiński }
346*a03ca8b9SKrzysztof Kosiński 
347*a03ca8b9SKrzysztof Kosiński // Detailed test of Encode/Decode: Check valid and invalid |disp| for various
348*a03ca8b9SKrzysztof Kosiński // clean slate |code| cases. Also check |disp| and |code| binary components,
349*a03ca8b9SKrzysztof Kosiński // which in AArch32Rel32Translator comments.
TEST(AArch32Rel32Translator,EncodeDecode)350*a03ca8b9SKrzysztof Kosiński TEST(AArch32Rel32Translator, EncodeDecode) {
351*a03ca8b9SKrzysztof Kosiński   // A24 tests.
352*a03ca8b9SKrzysztof Kosiński   ArmTranslatorEncodeDecodeTest<AArch32Rel32Translator::AddrTraits_A24>
353*a03ca8b9SKrzysztof Kosiński       test_A24;
354*a03ca8b9SKrzysztof Kosiński   for (int cond = 0; cond <= 0x0E; ++cond) {
355*a03ca8b9SKrzysztof Kosiński     ArmRelInstruction<uint32_t> B_A1_cond("cccc1010 Siiiiiii iiiiiiii iiiiiiii",
356*a03ca8b9SKrzysztof Kosiński                                           kCleanSlateB_A1 | (cond << 28));
357*a03ca8b9SKrzysztof Kosiński     ArmRelInstruction<uint32_t> BL_A1_cond(
358*a03ca8b9SKrzysztof Kosiński         "cccc1011 Siiiiiii iiiiiiii iiiiiiii", kCleanSlateBL_A1 | (cond << 28));
359*a03ca8b9SKrzysztof Kosiński     test_A24.Run("SSSSSSSi iiiiiiii iiiiiiii iiiiii00", {"S", "i"},
360*a03ca8b9SKrzysztof Kosiński                  {B_A1_cond, BL_A1_cond},
361*a03ca8b9SKrzysztof Kosiński                  {0x01FFFFFC, -0x02000000, 0, 4, -4, 0x40, 0x44},
362*a03ca8b9SKrzysztof Kosiński                  {2, -2, 0x41, 0x42, 0x43, 0x02000000, -0x02000004});
363*a03ca8b9SKrzysztof Kosiński   }
364*a03ca8b9SKrzysztof Kosiński   // BLX encoding A2, which has 2-byte alignment.
365*a03ca8b9SKrzysztof Kosiński   ArmRelInstruction<uint32_t> BLX_A2("1111101H Siiiiiii iiiiiiii iiiiiiii",
366*a03ca8b9SKrzysztof Kosiński                                      kCleanSlateBLX_A2);
367*a03ca8b9SKrzysztof Kosiński   test_A24.Run("SSSSSSSi iiiiiiii iiiiiiii iiiiiiH0", {"S", "i", "H"}, {BLX_A2},
368*a03ca8b9SKrzysztof Kosiński                {0x01FFFFFC, 0x01FFFFFE, -0x02000000, 0, 2, -2, 4, 0x40, 0x42},
369*a03ca8b9SKrzysztof Kosiński                {1, -1, 0x41, 0x43, 0x02000000, -0x02000002});
370*a03ca8b9SKrzysztof Kosiński 
371*a03ca8b9SKrzysztof Kosiński   // T8 tests.
372*a03ca8b9SKrzysztof Kosiński   ArmTranslatorEncodeDecodeTest<AArch32Rel32Translator::AddrTraits_T8> test_T8;
373*a03ca8b9SKrzysztof Kosiński   for (int cond = 0; cond <= 0x0E; ++cond) {
374*a03ca8b9SKrzysztof Kosiński     ArmRelInstruction<uint16_t> B_T1_cond("1101cccc Siiiiiii",
375*a03ca8b9SKrzysztof Kosiński                                           kCleanSlateB_T1 | (cond << 8));
376*a03ca8b9SKrzysztof Kosiński     test_T8.Run("SSSSSSSS SSSSSSSS SSSSSSSS iiiiiii0", {"S", "i"}, {B_T1_cond},
377*a03ca8b9SKrzysztof Kosiński                 {0x00FE, -0x0100, 0, 2, -2, 4, 0x40, 0x42},
378*a03ca8b9SKrzysztof Kosiński                 {1, -1, 0x41, 0x43, 0x0100, -0x0102});
379*a03ca8b9SKrzysztof Kosiński   }
380*a03ca8b9SKrzysztof Kosiński   ArmRelInstruction<uint16_t> B_T1_invalid("11011111 ........",
381*a03ca8b9SKrzysztof Kosiński                                            kCleanSlateB_T1 | (0x0F << 8));
382*a03ca8b9SKrzysztof Kosiński   test_T8.Run("........ ........ ........ ........", std::vector<std::string>(),
383*a03ca8b9SKrzysztof Kosiński               {B_T1_invalid}, std::vector<arm_disp_t>(),
384*a03ca8b9SKrzysztof Kosiński               {0x00FE, -0x0100, 0, 2, 4, 0x40, 0x41, 0x0100, -0x0102});
385*a03ca8b9SKrzysztof Kosiński 
386*a03ca8b9SKrzysztof Kosiński   // T11 tests.
387*a03ca8b9SKrzysztof Kosiński   ArmTranslatorEncodeDecodeTest<AArch32Rel32Translator::AddrTraits_T11>
388*a03ca8b9SKrzysztof Kosiński       test_T11;
389*a03ca8b9SKrzysztof Kosiński   ArmRelInstruction<uint16_t> B_T2("11100Sii iiiiiiii", kCleanSlateB_T2);
390*a03ca8b9SKrzysztof Kosiński   test_T11.Run("SSSSSSSS SSSSSSSS SSSSSiii iiiiiii0", {"S", "i"}, {B_T2},
391*a03ca8b9SKrzysztof Kosiński                {0x07FE, -0x0800, 0, 2, -2, 4, 0x40, 0x42},
392*a03ca8b9SKrzysztof Kosiński                {1, -1, 0x41, 0x43, 0x0800, -0x0802});
393*a03ca8b9SKrzysztof Kosiński 
394*a03ca8b9SKrzysztof Kosiński   // T20 tests.
395*a03ca8b9SKrzysztof Kosiński   ArmTranslatorEncodeDecodeTest<AArch32Rel32Translator::AddrTraits_T20>
396*a03ca8b9SKrzysztof Kosiński       test_T20;
397*a03ca8b9SKrzysztof Kosiński   for (int cond = 0; cond <= 0x0E; ++cond) {
398*a03ca8b9SKrzysztof Kosiński     ArmRelInstruction<uint32_t> B_T3_cond(
399*a03ca8b9SKrzysztof Kosiński         "11110Scc cciiiiii 10(J1)0(J2)jjj jjjjjjjj",
400*a03ca8b9SKrzysztof Kosiński         kCleanSlateB_T3 | (cond << 22));
401*a03ca8b9SKrzysztof Kosiński     test_T20.Run("SSSSSSSS SSSS(J2)(J1)ii iiiijjjj jjjjjjj0",
402*a03ca8b9SKrzysztof Kosiński                  {"S", "J2", "J1", "i", "j"}, {B_T3_cond},
403*a03ca8b9SKrzysztof Kosiński                  {0x000FFFFE, -0x00100000, 0, 2, -2, 4, 0x40, 0x42},
404*a03ca8b9SKrzysztof Kosiński                  {1, -1, 0x41, 0x43, 0x00100000, -0x00100002});
405*a03ca8b9SKrzysztof Kosiński   }
406*a03ca8b9SKrzysztof Kosiński   ArmRelInstruction<uint32_t> B_T3_invalid(
407*a03ca8b9SKrzysztof Kosiński       "11110.11 11...... 10.0.... ........", kCleanSlateB_T3 | (0x0F << 22));
408*a03ca8b9SKrzysztof Kosiński   test_T20.Run("........ ........ ........ ........",
409*a03ca8b9SKrzysztof Kosiński                std::vector<std::string>(), {B_T3_invalid},
410*a03ca8b9SKrzysztof Kosiński                std::vector<arm_disp_t>(),
411*a03ca8b9SKrzysztof Kosiński                {0x000FFFFE, -0x00100000, 0, 2, 4, 0x40, 0x42, 1, 0x41, 0x43,
412*a03ca8b9SKrzysztof Kosiński                 0x00100000, -0x00100002});
413*a03ca8b9SKrzysztof Kosiński 
414*a03ca8b9SKrzysztof Kosiński   // T24 tests.
415*a03ca8b9SKrzysztof Kosiński   ArmTranslatorEncodeDecodeTest<AArch32Rel32Translator::AddrTraits_T24>
416*a03ca8b9SKrzysztof Kosiński       test_T24;
417*a03ca8b9SKrzysztof Kosiński   // "Clean slate" means J1 = J2 = 1, so we include 0x00002800.
418*a03ca8b9SKrzysztof Kosiński   ArmRelInstruction<uint32_t> B_T4("11110Sii iiiiiiii 10(J1)1(J2)jjj jjjjjjjj",
419*a03ca8b9SKrzysztof Kosiński                                    kCleanSlateB_T4);
420*a03ca8b9SKrzysztof Kosiński   ArmRelInstruction<uint32_t> BL_T1("11110Sii iiiiiiii 11(J1)1(J2)jjj jjjjjjjj",
421*a03ca8b9SKrzysztof Kosiński                                     kCleanSlateBL_T1);
422*a03ca8b9SKrzysztof Kosiński   test_T24.Run("SSSSSSSS (I1)(I2)iiiiii iiiijjjj jjjjjjj0",
423*a03ca8b9SKrzysztof Kosiński                {"S", "i", "j"},  // Skip "J1", "J2", "I1", "I2" checks.
424*a03ca8b9SKrzysztof Kosiński                {B_T4, BL_T1},
425*a03ca8b9SKrzysztof Kosiński                {0x00FFFFFE, -0x01000000, 0, 2, -2, 4, -4, 0x40, 0x42},
426*a03ca8b9SKrzysztof Kosiński                {1, -1, 0x41, 0x43, 0x01000000, -0x01000002});
427*a03ca8b9SKrzysztof Kosiński 
428*a03ca8b9SKrzysztof Kosiński   // For BLX encoding T2, |disp| must be multiple of 4.
429*a03ca8b9SKrzysztof Kosiński   ArmRelInstruction<uint32_t> BLX_T2(
430*a03ca8b9SKrzysztof Kosiński       "11110Sii iiiiiiii 11(J1)0(J2)jjj jjjjjjj0", kCleanSlateBLX_T2);
431*a03ca8b9SKrzysztof Kosiński   test_T24.Run(
432*a03ca8b9SKrzysztof Kosiński       "SSSSSSSS (I1)(I2)iiiiii iiiijjjj jjjjjj00",
433*a03ca8b9SKrzysztof Kosiński       {"S", "i", "j"},  // Skip "J1", "J2", "I1", "I2" checks.
434*a03ca8b9SKrzysztof Kosiński       {BLX_T2}, {0x00FFFFFC, -0x01000000, 0, 4, -4, 0x40},
435*a03ca8b9SKrzysztof Kosiński       {1, -1, 2, -2, 0x41, 0x42, 0x43, 0x00FFFFFE, 0x01000000, -0x01000002});
436*a03ca8b9SKrzysztof Kosiński }
437*a03ca8b9SKrzysztof Kosiński 
TEST(AArch32Rel32Translator,WriteRead)438*a03ca8b9SKrzysztof Kosiński TEST(AArch32Rel32Translator, WriteRead) {
439*a03ca8b9SKrzysztof Kosiński   std::vector<rva_t> aligned4;
440*a03ca8b9SKrzysztof Kosiński   std::vector<rva_t> misaligned4;
441*a03ca8b9SKrzysztof Kosiński   std::vector<rva_t> aligned2;
442*a03ca8b9SKrzysztof Kosiński   std::vector<rva_t> misaligned2;
443*a03ca8b9SKrzysztof Kosiński   for (rva_t rva = 0x1FFC; rva <= 0x2010; ++rva) {
444*a03ca8b9SKrzysztof Kosiński     ((rva % 4 == 0) ? aligned4 : misaligned4).push_back(rva);
445*a03ca8b9SKrzysztof Kosiński     ((rva % 2 == 0) ? aligned2 : misaligned2).push_back(rva);
446*a03ca8b9SKrzysztof Kosiński   }
447*a03ca8b9SKrzysztof Kosiński   CHECK_EQ(6U, aligned4.size());
448*a03ca8b9SKrzysztof Kosiński   CHECK_EQ(15U, misaligned4.size());
449*a03ca8b9SKrzysztof Kosiński   CHECK_EQ(11U, aligned2.size());
450*a03ca8b9SKrzysztof Kosiński   CHECK_EQ(10U, misaligned2.size());
451*a03ca8b9SKrzysztof Kosiński 
452*a03ca8b9SKrzysztof Kosiński   // Helpers to convert an instruction's RVA to PC.
453*a03ca8b9SKrzysztof Kosiński   auto pcArm = [](rva_t instr_rva) -> rva_t { return instr_rva + 8; };
454*a03ca8b9SKrzysztof Kosiński   auto pcThumb2 = [](rva_t instr_rva) -> rva_t { return instr_rva + 4; };
455*a03ca8b9SKrzysztof Kosiński 
456*a03ca8b9SKrzysztof Kosiński   // A24 tests.
457*a03ca8b9SKrzysztof Kosiński   ArmTranslatorWriteReadTest<AArch32Rel32Translator::AddrTraits_A24> test_A24;
458*a03ca8b9SKrzysztof Kosiński   for (uint32_t clean_slate_code : {kCleanSlateB_A1, kCleanSlateBL_A1}) {
459*a03ca8b9SKrzysztof Kosiński     test_A24.Accept(clean_slate_code, aligned4, aligned4);
460*a03ca8b9SKrzysztof Kosiński     test_A24.Reject(clean_slate_code, aligned4, misaligned4);
461*a03ca8b9SKrzysztof Kosiński     test_A24.Reject(clean_slate_code, misaligned4, aligned4);
462*a03ca8b9SKrzysztof Kosiński     test_A24.Reject(clean_slate_code, misaligned4, misaligned4);
463*a03ca8b9SKrzysztof Kosiński     // Signed (24 + 2)-bit range, 4-byte aligned: [-0x02000000, 0x01FFFFFC].
464*a03ca8b9SKrzysztof Kosiński     test_A24.Accept(clean_slate_code, {0x15000000},
465*a03ca8b9SKrzysztof Kosiński                     {pcArm(0x13000000), pcArm(0x16FFFFFC)});
466*a03ca8b9SKrzysztof Kosiński     test_A24.Reject(clean_slate_code, {0x15000000},
467*a03ca8b9SKrzysztof Kosiński                     {pcArm(0x13000000 - 4), pcArm(0x16FFFFFC + 4)});
468*a03ca8b9SKrzysztof Kosiński   }
469*a03ca8b9SKrzysztof Kosiński 
470*a03ca8b9SKrzysztof Kosiński   // BLX complication: ARM -> THUMB2.
471*a03ca8b9SKrzysztof Kosiński   test_A24.Accept(kCleanSlateBLX_A2, aligned4, aligned2);
472*a03ca8b9SKrzysztof Kosiński   test_A24.Reject(kCleanSlateBLX_A2, aligned4, misaligned2);
473*a03ca8b9SKrzysztof Kosiński   test_A24.Reject(kCleanSlateBLX_A2, misaligned4, aligned2);
474*a03ca8b9SKrzysztof Kosiński   test_A24.Reject(kCleanSlateBLX_A2, misaligned4, misaligned2);
475*a03ca8b9SKrzysztof Kosiński   test_A24.Accept(kCleanSlateBLX_A2, {0x15000000},
476*a03ca8b9SKrzysztof Kosiński                   {pcArm(0x13000000), pcArm(0x16FFFFFE)});
477*a03ca8b9SKrzysztof Kosiński   test_A24.Reject(kCleanSlateBLX_A2, {0x15000000},
478*a03ca8b9SKrzysztof Kosiński                   {pcArm(0x13000000 - 4), pcArm(0x13000000 - 2),
479*a03ca8b9SKrzysztof Kosiński                    pcArm(0x16FFFFFE + 2), pcArm(0x16FFFFFE + 4)});
480*a03ca8b9SKrzysztof Kosiński 
481*a03ca8b9SKrzysztof Kosiński   // T8 tests.
482*a03ca8b9SKrzysztof Kosiński   ArmTranslatorWriteReadTest<AArch32Rel32Translator::AddrTraits_T8> test_T8;
483*a03ca8b9SKrzysztof Kosiński   test_T8.Accept(kCleanSlateB_T1, aligned2, aligned2);
484*a03ca8b9SKrzysztof Kosiński   test_T8.Reject(kCleanSlateB_T1, aligned2, misaligned2);
485*a03ca8b9SKrzysztof Kosiński   test_T8.Reject(kCleanSlateB_T1, misaligned2, aligned2);
486*a03ca8b9SKrzysztof Kosiński   test_T8.Reject(kCleanSlateB_T1, misaligned2, misaligned2);
487*a03ca8b9SKrzysztof Kosiński   // Signed (8 + 1)-bit range, 2-byte aligned: [-0x0100, 0x00FE].
488*a03ca8b9SKrzysztof Kosiński   test_T8.Accept(kCleanSlateB_T1, {0x10000500},
489*a03ca8b9SKrzysztof Kosiński                  {pcThumb2(0x10000400), pcThumb2(0x100005FE)});
490*a03ca8b9SKrzysztof Kosiński   test_T8.Reject(kCleanSlateB_T1, {0x10000500},
491*a03ca8b9SKrzysztof Kosiński                  {pcThumb2(0x10000400 - 2), pcThumb2(0x100005FE + 2)});
492*a03ca8b9SKrzysztof Kosiński 
493*a03ca8b9SKrzysztof Kosiński   // T11 tests.
494*a03ca8b9SKrzysztof Kosiński   ArmTranslatorWriteReadTest<AArch32Rel32Translator::AddrTraits_T11> test_T11;
495*a03ca8b9SKrzysztof Kosiński   test_T11.Accept(kCleanSlateB_T2, aligned2, aligned2);
496*a03ca8b9SKrzysztof Kosiński   test_T11.Reject(kCleanSlateB_T2, aligned2, misaligned2);
497*a03ca8b9SKrzysztof Kosiński   test_T11.Reject(kCleanSlateB_T2, misaligned2, aligned2);
498*a03ca8b9SKrzysztof Kosiński   test_T11.Reject(kCleanSlateB_T2, misaligned2, misaligned2);
499*a03ca8b9SKrzysztof Kosiński   // Signed (11 + 1)-bit range, 2-byte aligned: [-0x0800, 0x07FE].
500*a03ca8b9SKrzysztof Kosiński   test_T11.Accept(kCleanSlateB_T2, {0x10003000},
501*a03ca8b9SKrzysztof Kosiński                   {pcThumb2(0x10002800), pcThumb2(0x100037FE)});
502*a03ca8b9SKrzysztof Kosiński   test_T11.Reject(kCleanSlateB_T2, {0x10003000},
503*a03ca8b9SKrzysztof Kosiński                   {pcThumb2(0x10002800 - 2), pcThumb2(0x100037FE + 2)});
504*a03ca8b9SKrzysztof Kosiński 
505*a03ca8b9SKrzysztof Kosiński   // T20 tests.
506*a03ca8b9SKrzysztof Kosiński   ArmTranslatorWriteReadTest<AArch32Rel32Translator::AddrTraits_T20> test_T20;
507*a03ca8b9SKrzysztof Kosiński   test_T20.Accept(kCleanSlateB_T3, aligned2, aligned2);
508*a03ca8b9SKrzysztof Kosiński   test_T20.Reject(kCleanSlateB_T3, aligned2, misaligned2);
509*a03ca8b9SKrzysztof Kosiński   test_T20.Reject(kCleanSlateB_T3, misaligned2, aligned2);
510*a03ca8b9SKrzysztof Kosiński   test_T20.Reject(kCleanSlateB_T3, misaligned2, misaligned2);
511*a03ca8b9SKrzysztof Kosiński   // Signed (20 + 1)-bit range, 2-byte aligned: [-0x00100000, 0x000FFFFE].
512*a03ca8b9SKrzysztof Kosiński   test_T20.Accept(kCleanSlateB_T3, {0x10300000},
513*a03ca8b9SKrzysztof Kosiński                   {pcThumb2(0x10200000), pcThumb2(0x103FFFFE)});
514*a03ca8b9SKrzysztof Kosiński   test_T20.Reject(kCleanSlateB_T3, {0x10300000},
515*a03ca8b9SKrzysztof Kosiński                   {pcThumb2(0x10200000 - 2), pcThumb2(0x103FFFFE + 2)});
516*a03ca8b9SKrzysztof Kosiński 
517*a03ca8b9SKrzysztof Kosiński   // T24 tests.
518*a03ca8b9SKrzysztof Kosiński   ArmTranslatorWriteReadTest<AArch32Rel32Translator::AddrTraits_T24> test_T24;
519*a03ca8b9SKrzysztof Kosiński   for (uint32_t clean_slate_code : {kCleanSlateB_T4, kCleanSlateBL_T1}) {
520*a03ca8b9SKrzysztof Kosiński     test_T24.Accept(clean_slate_code, aligned2, aligned2);
521*a03ca8b9SKrzysztof Kosiński     test_T24.Reject(clean_slate_code, aligned2, misaligned2);
522*a03ca8b9SKrzysztof Kosiński     test_T24.Reject(clean_slate_code, misaligned2, aligned2);
523*a03ca8b9SKrzysztof Kosiński     test_T24.Reject(clean_slate_code, misaligned2, misaligned2);
524*a03ca8b9SKrzysztof Kosiński     // Signed (24 + 1)-bit range, 2-byte aligned: [-0x01000000, 0x00FFFFFE].
525*a03ca8b9SKrzysztof Kosiński     test_T24.Accept(clean_slate_code, {0x16000000},
526*a03ca8b9SKrzysztof Kosiński                     {pcThumb2(0x15000000), pcThumb2(0x16FFFFFE)});
527*a03ca8b9SKrzysztof Kosiński     test_T24.Reject(clean_slate_code, {0x16000000},
528*a03ca8b9SKrzysztof Kosiński                     {pcThumb2(0x15000000 - 2), pcThumb2(0x16FFFFFE + 2)});
529*a03ca8b9SKrzysztof Kosiński   }
530*a03ca8b9SKrzysztof Kosiński 
531*a03ca8b9SKrzysztof Kosiński   // BLX complication: THUMB2 -> ARM.
532*a03ca8b9SKrzysztof Kosiński   test_T24.Accept(kCleanSlateBLX_T2, aligned2, aligned4);
533*a03ca8b9SKrzysztof Kosiński   test_T24.Reject(kCleanSlateBLX_T2, aligned2, misaligned4);
534*a03ca8b9SKrzysztof Kosiński   test_T24.Reject(kCleanSlateBLX_T2, misaligned2, aligned4);
535*a03ca8b9SKrzysztof Kosiński   test_T24.Reject(kCleanSlateBLX_T2, misaligned2, misaligned4);
536*a03ca8b9SKrzysztof Kosiński   test_T24.Accept(kCleanSlateBLX_T2, {0x16000000},
537*a03ca8b9SKrzysztof Kosiński                   {pcThumb2(0x15000000), pcThumb2(0x16FFFFFC)});
538*a03ca8b9SKrzysztof Kosiński   test_T24.Reject(kCleanSlateBLX_T2, {0x16000000},
539*a03ca8b9SKrzysztof Kosiński                   {pcThumb2(0x15000000 - 4), pcThumb2(0x15000000 - 2),
540*a03ca8b9SKrzysztof Kosiński                    pcThumb2(0x16FFFFFC + 2), pcThumb2(0x16FFFFFC + 4)});
541*a03ca8b9SKrzysztof Kosiński }
542*a03ca8b9SKrzysztof Kosiński 
543*a03ca8b9SKrzysztof Kosiński // Typical usage in |target_rva| extraction.
TEST(AArch32Rel32Translator,Main)544*a03ca8b9SKrzysztof Kosiński TEST(AArch32Rel32Translator, Main) {
545*a03ca8b9SKrzysztof Kosiński   // ARM mode (32-bit).
546*a03ca8b9SKrzysztof Kosiński   // 00103050: 00 01 02 EA    B     00183458 ; B encoding A1 (cond = AL).
547*a03ca8b9SKrzysztof Kosiński   {
548*a03ca8b9SKrzysztof Kosiński     rva_t instr_rva = 0x00103050U;
549*a03ca8b9SKrzysztof Kosiński     AArch32Rel32Translator translator;
550*a03ca8b9SKrzysztof Kosiński     std::vector<uint8_t> bytes = {0x00, 0x01, 0x02, 0xEA};
551*a03ca8b9SKrzysztof Kosiński     MutableBufferView region(&bytes[0], bytes.size());
552*a03ca8b9SKrzysztof Kosiński     uint32_t code = translator.FetchArmCode32(region, 0U);
553*a03ca8b9SKrzysztof Kosiński     EXPECT_EQ(0xEA020100U, code);
554*a03ca8b9SKrzysztof Kosiński 
555*a03ca8b9SKrzysztof Kosiński     // |code| <-> |disp|.
556*a03ca8b9SKrzysztof Kosiński     arm_disp_t disp = 0;
557*a03ca8b9SKrzysztof Kosiński     EXPECT_EQ(kArmAlign4, translator.DecodeA24(code, &disp));
558*a03ca8b9SKrzysztof Kosiński     EXPECT_EQ(+0x00080400, disp);
559*a03ca8b9SKrzysztof Kosiński 
560*a03ca8b9SKrzysztof Kosiński     uint32_t code_from_disp = kCleanSlateBAL_A1;
561*a03ca8b9SKrzysztof Kosiński     EXPECT_TRUE(translator.EncodeA24(disp, &code_from_disp));
562*a03ca8b9SKrzysztof Kosiński     EXPECT_EQ(code, code_from_disp);
563*a03ca8b9SKrzysztof Kosiński 
564*a03ca8b9SKrzysztof Kosiński     // |code| <-> |target_rva|.
565*a03ca8b9SKrzysztof Kosiński     rva_t target_rva = kInvalidRva;
566*a03ca8b9SKrzysztof Kosiński     EXPECT_TRUE(translator.ReadA24(instr_rva, code, &target_rva));
567*a03ca8b9SKrzysztof Kosiński     // 0x00103050 + 8 + 0x00080400.
568*a03ca8b9SKrzysztof Kosiński     EXPECT_EQ(0x00183458U, target_rva);
569*a03ca8b9SKrzysztof Kosiński 
570*a03ca8b9SKrzysztof Kosiński     uint32_t code_from_rva = kCleanSlateBAL_A1;
571*a03ca8b9SKrzysztof Kosiński     EXPECT_TRUE(translator.WriteA24(instr_rva, target_rva, &code_from_rva));
572*a03ca8b9SKrzysztof Kosiński     EXPECT_EQ(code, code_from_rva);
573*a03ca8b9SKrzysztof Kosiński   }
574*a03ca8b9SKrzysztof Kosiński 
575*a03ca8b9SKrzysztof Kosiński   // THUMB2 mode (16-bit).
576*a03ca8b9SKrzysztof Kosiński   // 001030A2: F3 E7          B     0010308C ; B encoding T2.
577*a03ca8b9SKrzysztof Kosiński   {
578*a03ca8b9SKrzysztof Kosiński     rva_t instr_rva = 0x001030A2U;
579*a03ca8b9SKrzysztof Kosiński     AArch32Rel32Translator translator;
580*a03ca8b9SKrzysztof Kosiński     std::vector<uint8_t> bytes = {0xF3, 0xE7};
581*a03ca8b9SKrzysztof Kosiński     MutableBufferView region(&bytes[0], bytes.size());
582*a03ca8b9SKrzysztof Kosiński     uint16_t code = translator.FetchThumb2Code16(region, 0U);
583*a03ca8b9SKrzysztof Kosiński     // Sii iiiiiiii = 111 11110011 = -1101 = -0x0D.
584*a03ca8b9SKrzysztof Kosiński     EXPECT_EQ(0xE7F3U, code);
585*a03ca8b9SKrzysztof Kosiński 
586*a03ca8b9SKrzysztof Kosiński     // |code| <-> |disp|.
587*a03ca8b9SKrzysztof Kosiński     arm_disp_t disp = 0;
588*a03ca8b9SKrzysztof Kosiński     EXPECT_EQ(kArmAlign2, translator.DecodeT11(code, &disp));
589*a03ca8b9SKrzysztof Kosiński     EXPECT_EQ(-0x0000001A, disp);  // -0x0D * 2 = -0x1A.
590*a03ca8b9SKrzysztof Kosiński 
591*a03ca8b9SKrzysztof Kosiński     uint16_t code_from_disp = kCleanSlateB_T2;
592*a03ca8b9SKrzysztof Kosiński     EXPECT_TRUE(translator.EncodeT11(disp, &code_from_disp));
593*a03ca8b9SKrzysztof Kosiński     EXPECT_EQ(code, code_from_disp);
594*a03ca8b9SKrzysztof Kosiński 
595*a03ca8b9SKrzysztof Kosiński     // |code| <-> |target_rva|.
596*a03ca8b9SKrzysztof Kosiński     rva_t target_rva = kInvalidRva;
597*a03ca8b9SKrzysztof Kosiński     EXPECT_TRUE(translator.ReadT11(instr_rva, code, &target_rva));
598*a03ca8b9SKrzysztof Kosiński     // 0x001030A2 + 4 - 0x0000001A.
599*a03ca8b9SKrzysztof Kosiński     EXPECT_EQ(0x0010308CU, target_rva);
600*a03ca8b9SKrzysztof Kosiński 
601*a03ca8b9SKrzysztof Kosiński     uint16_t code_from_rva = kCleanSlateB_T2;
602*a03ca8b9SKrzysztof Kosiński     EXPECT_TRUE(translator.WriteT11(instr_rva, target_rva, &code_from_rva));
603*a03ca8b9SKrzysztof Kosiński     EXPECT_EQ(code, code_from_rva);
604*a03ca8b9SKrzysztof Kosiński   }
605*a03ca8b9SKrzysztof Kosiński 
606*a03ca8b9SKrzysztof Kosiński   // THUMB2 mode (32-bit).
607*a03ca8b9SKrzysztof Kosiński   // 001030A2: 00 F0 01 FA    BL    001034A8 ; BL encoding T1.
608*a03ca8b9SKrzysztof Kosiński   {
609*a03ca8b9SKrzysztof Kosiński     rva_t instr_rva = 0x001030A2U;
610*a03ca8b9SKrzysztof Kosiński     AArch32Rel32Translator translator;
611*a03ca8b9SKrzysztof Kosiński     std::vector<uint8_t> bytes = {0x00, 0xF0, 0x01, 0xFA};
612*a03ca8b9SKrzysztof Kosiński     MutableBufferView region(&bytes[0], bytes.size());
613*a03ca8b9SKrzysztof Kosiński     uint32_t code = translator.FetchThumb2Code32(region, 0U);
614*a03ca8b9SKrzysztof Kosiński     EXPECT_EQ(0xF000FA01U, code);
615*a03ca8b9SKrzysztof Kosiński 
616*a03ca8b9SKrzysztof Kosiński     // |code| <-> |disp|.
617*a03ca8b9SKrzysztof Kosiński     arm_disp_t disp = 0;
618*a03ca8b9SKrzysztof Kosiński     EXPECT_EQ(kArmAlign2, translator.DecodeT24(code, &disp));
619*a03ca8b9SKrzysztof Kosiński     EXPECT_EQ(+0x00000402, disp);
620*a03ca8b9SKrzysztof Kosiński 
621*a03ca8b9SKrzysztof Kosiński     uint32_t code_from_disp = kCleanSlateBL_T1;
622*a03ca8b9SKrzysztof Kosiński     EXPECT_TRUE(translator.EncodeT24(disp, &code_from_disp));
623*a03ca8b9SKrzysztof Kosiński     EXPECT_EQ(code, code_from_disp);
624*a03ca8b9SKrzysztof Kosiński 
625*a03ca8b9SKrzysztof Kosiński     // |code| <-> |target_rva|.
626*a03ca8b9SKrzysztof Kosiński     rva_t target_rva = kInvalidRva;
627*a03ca8b9SKrzysztof Kosiński     EXPECT_TRUE(translator.ReadT24(instr_rva, code, &target_rva));
628*a03ca8b9SKrzysztof Kosiński     // 0x001030A2 + 4 + 0x00000002.
629*a03ca8b9SKrzysztof Kosiński     EXPECT_EQ(0x001034A8U, target_rva);
630*a03ca8b9SKrzysztof Kosiński 
631*a03ca8b9SKrzysztof Kosiński     uint32_t code_from_rva = kCleanSlateBL_T1;
632*a03ca8b9SKrzysztof Kosiński     EXPECT_TRUE(translator.WriteT24(instr_rva, target_rva, &code_from_rva));
633*a03ca8b9SKrzysztof Kosiński     EXPECT_EQ(code, code_from_rva);
634*a03ca8b9SKrzysztof Kosiński   }
635*a03ca8b9SKrzysztof Kosiński }
636*a03ca8b9SKrzysztof Kosiński 
TEST(AArch32Rel32Translator,BLXComplication)637*a03ca8b9SKrzysztof Kosiński TEST(AArch32Rel32Translator, BLXComplication) {
638*a03ca8b9SKrzysztof Kosiński   auto run_test = [](rva_t instr_rva,
639*a03ca8b9SKrzysztof Kosiński                      std::vector<uint8_t> bytes,  // Pass by value.
640*a03ca8b9SKrzysztof Kosiński                      uint32_t expected_code, arm_disp_t expected_disp,
641*a03ca8b9SKrzysztof Kosiński                      uint32_t clean_slate_code, rva_t expected_target_rva) {
642*a03ca8b9SKrzysztof Kosiński     AArch32Rel32Translator translator;
643*a03ca8b9SKrzysztof Kosiński     MutableBufferView region(&bytes[0], bytes.size());
644*a03ca8b9SKrzysztof Kosiński     uint32_t code = translator.FetchThumb2Code32(region, 0U);
645*a03ca8b9SKrzysztof Kosiński     EXPECT_EQ(expected_code, code);
646*a03ca8b9SKrzysztof Kosiński 
647*a03ca8b9SKrzysztof Kosiński     // |code| <-> |disp|.
648*a03ca8b9SKrzysztof Kosiński     arm_disp_t disp = 0;
649*a03ca8b9SKrzysztof Kosiński     EXPECT_TRUE(translator.DecodeT24(code, &disp));
650*a03ca8b9SKrzysztof Kosiński     EXPECT_EQ(expected_disp, disp);
651*a03ca8b9SKrzysztof Kosiński 
652*a03ca8b9SKrzysztof Kosiński     uint32_t code_from_disp = clean_slate_code;
653*a03ca8b9SKrzysztof Kosiński     EXPECT_TRUE(translator.EncodeT24(disp, &code_from_disp));
654*a03ca8b9SKrzysztof Kosiński     EXPECT_EQ(code, code_from_disp);
655*a03ca8b9SKrzysztof Kosiński 
656*a03ca8b9SKrzysztof Kosiński     // |code| <-> |target_rva|.
657*a03ca8b9SKrzysztof Kosiński     rva_t target_rva = kInvalidRva;
658*a03ca8b9SKrzysztof Kosiński     EXPECT_TRUE(translator.ReadT24(instr_rva, code, &target_rva));
659*a03ca8b9SKrzysztof Kosiński     EXPECT_EQ(expected_target_rva, target_rva);
660*a03ca8b9SKrzysztof Kosiński 
661*a03ca8b9SKrzysztof Kosiński     uint32_t code_from_rva = clean_slate_code;
662*a03ca8b9SKrzysztof Kosiński     EXPECT_TRUE(translator.WriteT24(instr_rva, target_rva, &code_from_rva));
663*a03ca8b9SKrzysztof Kosiński     EXPECT_EQ(code, code_from_rva);
664*a03ca8b9SKrzysztof Kosiński   };
665*a03ca8b9SKrzysztof Kosiński 
666*a03ca8b9SKrzysztof Kosiński   // No complication, 4-byte aligned.
667*a03ca8b9SKrzysztof Kosiński   // 001030A0: 01 F0 06 B0    B     005040B0 ; B encoding T4.
668*a03ca8b9SKrzysztof Kosiński   run_test(0x001030A0U,  // Multiple of 4.
669*a03ca8b9SKrzysztof Kosiński            {0x01, 0xF0, 0x06, 0xB0}, 0xF001B006U, 0x0040100C, kCleanSlateB_T4,
670*a03ca8b9SKrzysztof Kosiński            // "Canonical" |target_rva|: 0x001030A0 + 4 + 0x0040100C.
671*a03ca8b9SKrzysztof Kosiński            0x005040B0U);
672*a03ca8b9SKrzysztof Kosiński 
673*a03ca8b9SKrzysztof Kosiński   // No complication, not 4-byte aligned.
674*a03ca8b9SKrzysztof Kosiński   // 001030A2: 01 F0 06 B0    B     005040B2 ; B encoding T4.
675*a03ca8b9SKrzysztof Kosiński   run_test(0x001030A2U,  // Shift by 2: Not multiple of 4.
676*a03ca8b9SKrzysztof Kosiński            {0x01, 0xF0, 0x06, 0xB0}, 0xF001B006U, 0x0040100C, kCleanSlateB_T4,
677*a03ca8b9SKrzysztof Kosiński            // Shifted by 2: 0x001030A2 + 4 + 0x0040100C.
678*a03ca8b9SKrzysztof Kosiński            0x005040B2U);
679*a03ca8b9SKrzysztof Kosiński 
680*a03ca8b9SKrzysztof Kosiński   // Repeat the above, but use BLX instead of B.
681*a03ca8b9SKrzysztof Kosiński 
682*a03ca8b9SKrzysztof Kosiński   // BLX complication, 4-byte aligned.
683*a03ca8b9SKrzysztof Kosiński   // 001030A0: 01 F0 06 E0    BLX   005040B0 ; BLX encoding T2.
684*a03ca8b9SKrzysztof Kosiński   run_test(0x001030A0U,  // Multiple of 4.
685*a03ca8b9SKrzysztof Kosiński            {0x01, 0xF0, 0x06, 0xE0}, 0xF001E006U, 0x0040100C, kCleanSlateBLX_T2,
686*a03ca8b9SKrzysztof Kosiński            // Canonical again: align_down_4(0x001030A0 + 4 + 0x0040100C).
687*a03ca8b9SKrzysztof Kosiński            0x005040B0U);
688*a03ca8b9SKrzysztof Kosiński 
689*a03ca8b9SKrzysztof Kosiński   // BLX complication, not 4-byte aligned.
690*a03ca8b9SKrzysztof Kosiński   // 001030A2: 01 F0 06 E0    BLX   005040B0 ; BLX encoding T2.
691*a03ca8b9SKrzysztof Kosiński   run_test(0x001030A2U,  // Shift by 2: Not multiple of 4.
692*a03ca8b9SKrzysztof Kosiński            {0x01, 0xF0, 0x06, 0xE0}, 0xF001E006U, 0x0040100C, kCleanSlateBLX_T2,
693*a03ca8b9SKrzysztof Kosiński            // No shift: align_down_4(0x001030A2 + 4 + 0x0040100C).
694*a03ca8b9SKrzysztof Kosiński            0x005040B0U);
695*a03ca8b9SKrzysztof Kosiński }
696*a03ca8b9SKrzysztof Kosiński 
TEST(AArch64Rel32Translator,FetchStore)697*a03ca8b9SKrzysztof Kosiński TEST(AArch64Rel32Translator, FetchStore) {
698*a03ca8b9SKrzysztof Kosiński   std::vector<uint8_t> bytes = {0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE};
699*a03ca8b9SKrzysztof Kosiński   std::vector<uint8_t> expected = {0xAB, 0x33, 0x22, 0x11,
700*a03ca8b9SKrzysztof Kosiński                                    0x69, 0x5A, 0xFF, 0x00};
701*a03ca8b9SKrzysztof Kosiński   MutableBufferView region(&bytes[0], bytes.size());
702*a03ca8b9SKrzysztof Kosiński   AArch64Rel32Translator translator;
703*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(0x76543210U, translator.FetchCode32(region, 0U));
704*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(0xFEDCBA98U, translator.FetchCode32(region, 4U));
705*a03ca8b9SKrzysztof Kosiński 
706*a03ca8b9SKrzysztof Kosiński   translator.StoreCode32(region, 0U, 0x112233ABU);
707*a03ca8b9SKrzysztof Kosiński   translator.StoreCode32(region, 4U, 0x00FF5A69);
708*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(expected, bytes);
709*a03ca8b9SKrzysztof Kosiński }
710*a03ca8b9SKrzysztof Kosiński 
TEST(AArch64Rel32Translator,EncodeDecode)711*a03ca8b9SKrzysztof Kosiński TEST(AArch64Rel32Translator, EncodeDecode) {
712*a03ca8b9SKrzysztof Kosiński   // Immd14 tests.
713*a03ca8b9SKrzysztof Kosiński   ArmTranslatorEncodeDecodeTest<AArch64Rel32Translator::AddrTraits_Immd14>
714*a03ca8b9SKrzysztof Kosiński       test_immd14;
715*a03ca8b9SKrzysztof Kosiński   for (int b40 : {0, 1, 7, 31}) {
716*a03ca8b9SKrzysztof Kosiński     uint32_t b40_mask = b40 << 19;
717*a03ca8b9SKrzysztof Kosiński     for (int Rt : {0, 1, 15, 30}) {
718*a03ca8b9SKrzysztof Kosiński       uint32_t mask = b40_mask | Rt;
719*a03ca8b9SKrzysztof Kosiński       ArmRelInstruction<uint32_t> TBZw_Rt("00110110 bbbbbSii iiiiiiii iiittttt",
720*a03ca8b9SKrzysztof Kosiński                                           kCleanSlate64TBZw | mask);
721*a03ca8b9SKrzysztof Kosiński       ArmRelInstruction<uint32_t> TBZz_Rt("10110110 bbbbbSii iiiiiiii iiittttt",
722*a03ca8b9SKrzysztof Kosiński                                           kCleanSlate64TBZz | mask);
723*a03ca8b9SKrzysztof Kosiński       ArmRelInstruction<uint32_t> TBNZw_Rt(
724*a03ca8b9SKrzysztof Kosiński           "00110111 bbbbbSii iiiiiiii iiittttt", kCleanSlate64TBNZw | mask);
725*a03ca8b9SKrzysztof Kosiński       ArmRelInstruction<uint32_t> TBNZz_Rt(
726*a03ca8b9SKrzysztof Kosiński           "10110111 bbbbbSii iiiiiiii iiittttt", kCleanSlate64TBNZz | mask);
727*a03ca8b9SKrzysztof Kosiński       test_immd14.Run("SSSSSSSS SSSSSSSS Siiiiiii iiiiii00", {"S", "i"},
728*a03ca8b9SKrzysztof Kosiński                       {TBZw_Rt, TBZz_Rt, TBNZw_Rt, TBNZz_Rt},
729*a03ca8b9SKrzysztof Kosiński                       {0x00007FFC, -0x00008000, 0, 4, -4, 0x40, 0x44},
730*a03ca8b9SKrzysztof Kosiński                       {2, -2, 0x41, 0x42, 0x43, 0x00008000, -0x00008004});
731*a03ca8b9SKrzysztof Kosiński     }
732*a03ca8b9SKrzysztof Kosiński   }
733*a03ca8b9SKrzysztof Kosiński 
734*a03ca8b9SKrzysztof Kosiński   // Immd19 tests.
735*a03ca8b9SKrzysztof Kosiński   ArmTranslatorEncodeDecodeTest<AArch64Rel32Translator::AddrTraits_Immd19>
736*a03ca8b9SKrzysztof Kosiński       test_immd19;
737*a03ca8b9SKrzysztof Kosiński   for (int cond = 0; cond <= 0x0E; ++cond) {
738*a03ca8b9SKrzysztof Kosiński     ArmRelInstruction<uint32_t> B_cond("01010100 Siiiiiii iiiiiiii iii0cccc",
739*a03ca8b9SKrzysztof Kosiński                                        kCleanSlate64Bcond | cond);
740*a03ca8b9SKrzysztof Kosiński     test_immd19.Run("SSSSSSSS SSSSiiii iiiiiiii iiiiii00", {"S", "i"}, {B_cond},
741*a03ca8b9SKrzysztof Kosiński                     {0x000FFFFC, -0x00100000, 0, 4, -4, 0x40, 0x44},
742*a03ca8b9SKrzysztof Kosiński                     {2, -2, 0x41, 0x42, 0x43, 0x00100000, -0x00100004});
743*a03ca8b9SKrzysztof Kosiński   }
744*a03ca8b9SKrzysztof Kosiński   for (int Rt : {0, 1, 15, 30}) {
745*a03ca8b9SKrzysztof Kosiński     ArmRelInstruction<uint32_t> CBZw_Rt("00110100 Siiiiiii iiiiiiii iiittttt",
746*a03ca8b9SKrzysztof Kosiński                                         kCleanSlate64CBZw | Rt);
747*a03ca8b9SKrzysztof Kosiński     ArmRelInstruction<uint32_t> CBZz_Rt("10110100 Siiiiiii iiiiiiii iiittttt",
748*a03ca8b9SKrzysztof Kosiński                                         kCleanSlate64CBZz | Rt);
749*a03ca8b9SKrzysztof Kosiński     ArmRelInstruction<uint32_t> CBNZw_Rt("00110101 Siiiiiii iiiiiiii iiittttt",
750*a03ca8b9SKrzysztof Kosiński                                          kCleanSlate64CBNZw | Rt);
751*a03ca8b9SKrzysztof Kosiński     ArmRelInstruction<uint32_t> CBNZz_Rt("10110101 Siiiiiii iiiiiiii iiittttt",
752*a03ca8b9SKrzysztof Kosiński                                          kCleanSlate64CBNZz | Rt);
753*a03ca8b9SKrzysztof Kosiński     test_immd19.Run("SSSSSSSS SSSSiiii iiiiiiii iiiiii00", {"S", "i"},
754*a03ca8b9SKrzysztof Kosiński                     {CBZw_Rt, CBZz_Rt, CBNZw_Rt, CBNZz_Rt},
755*a03ca8b9SKrzysztof Kosiński                     {0x000FFFFC, -0x00100000, 0, 4, -4, 0x40, 0x44},
756*a03ca8b9SKrzysztof Kosiński                     {2, -2, 0x41, 0x42, 0x43, 0x00100000, -0x00100004});
757*a03ca8b9SKrzysztof Kosiński   }
758*a03ca8b9SKrzysztof Kosiński 
759*a03ca8b9SKrzysztof Kosiński   // Immd26 tests.
760*a03ca8b9SKrzysztof Kosiński   ArmTranslatorEncodeDecodeTest<AArch64Rel32Translator::AddrTraits_Immd26>
761*a03ca8b9SKrzysztof Kosiński       test_immd26;
762*a03ca8b9SKrzysztof Kosiński   ArmRelInstruction<uint32_t> B("000101Si iiiiiiii iiiiiiii iiiiiiii",
763*a03ca8b9SKrzysztof Kosiński                                 kCleanSlate64B);
764*a03ca8b9SKrzysztof Kosiński   ArmRelInstruction<uint32_t> BL("100101Si iiiiiiii iiiiiiii iiiiiiii",
765*a03ca8b9SKrzysztof Kosiński                                  kCleanSlate64BL);
766*a03ca8b9SKrzysztof Kosiński   test_immd26.Run("SSSSSiii iiiiiiii iiiiiiii iiiiii00", {"S", "i"}, {B, BL},
767*a03ca8b9SKrzysztof Kosiński                   {0x07FFFFFC, -0x08000000, 0, 4, -4, 0x40, 0x44},
768*a03ca8b9SKrzysztof Kosiński                   {2, -2, 0x41, 0x42, 0x43, 0x08000000, -0x08000004});
769*a03ca8b9SKrzysztof Kosiński }
770*a03ca8b9SKrzysztof Kosiński 
TEST(AArch64Rel32Translator,WriteRead)771*a03ca8b9SKrzysztof Kosiński TEST(AArch64Rel32Translator, WriteRead) {
772*a03ca8b9SKrzysztof Kosiński   std::vector<rva_t> aligned4;
773*a03ca8b9SKrzysztof Kosiński   std::vector<rva_t> misaligned4;
774*a03ca8b9SKrzysztof Kosiński   for (rva_t rva = 0x1FFC; rva <= 0x2010; ++rva) {
775*a03ca8b9SKrzysztof Kosiński     ((rva % 4 == 0) ? aligned4 : misaligned4).push_back(rva);
776*a03ca8b9SKrzysztof Kosiński   }
777*a03ca8b9SKrzysztof Kosiński   CHECK_EQ(6U, aligned4.size());
778*a03ca8b9SKrzysztof Kosiński   CHECK_EQ(15U, misaligned4.size());
779*a03ca8b9SKrzysztof Kosiński 
780*a03ca8b9SKrzysztof Kosiński   // Helper to convert an instruction's RVA to PC.
781*a03ca8b9SKrzysztof Kosiński   auto pcAArch64 = [](rva_t instr_rva) -> rva_t { return instr_rva; };
782*a03ca8b9SKrzysztof Kosiński 
783*a03ca8b9SKrzysztof Kosiński   // Immd14 tests.
784*a03ca8b9SKrzysztof Kosiński   ArmTranslatorWriteReadTest<AArch64Rel32Translator::AddrTraits_Immd14>
785*a03ca8b9SKrzysztof Kosiński       test_immd14;
786*a03ca8b9SKrzysztof Kosiński   for (uint32_t clean_slate_code : {kCleanSlate64TBZw, kCleanSlate64TBZz,
787*a03ca8b9SKrzysztof Kosiński                                     kCleanSlate64TBNZw, kCleanSlate64TBNZz}) {
788*a03ca8b9SKrzysztof Kosiński     test_immd14.Accept(clean_slate_code, aligned4, aligned4);
789*a03ca8b9SKrzysztof Kosiński     test_immd14.Reject(clean_slate_code, aligned4, misaligned4);
790*a03ca8b9SKrzysztof Kosiński     test_immd14.Reject(clean_slate_code, misaligned4, aligned4);
791*a03ca8b9SKrzysztof Kosiński     test_immd14.Reject(clean_slate_code, misaligned4, misaligned4);
792*a03ca8b9SKrzysztof Kosiński     // Signed (14 + 2)-bit range, 4-byte aligned: [-0x00008000, 0x00007FFC].
793*a03ca8b9SKrzysztof Kosiński     test_immd14.Accept(clean_slate_code, {0x10040000},
794*a03ca8b9SKrzysztof Kosiński                        {pcAArch64(0x10038000), pcAArch64(0x10047FFC)});
795*a03ca8b9SKrzysztof Kosiński     test_immd14.Reject(clean_slate_code, {0x15000000},
796*a03ca8b9SKrzysztof Kosiński                        {pcAArch64(0x10038000 - 4), pcAArch64(0x10047FFC + 4)});
797*a03ca8b9SKrzysztof Kosiński   }
798*a03ca8b9SKrzysztof Kosiński 
799*a03ca8b9SKrzysztof Kosiński   // Immd19 tests.
800*a03ca8b9SKrzysztof Kosiński   ArmTranslatorWriteReadTest<AArch64Rel32Translator::AddrTraits_Immd19>
801*a03ca8b9SKrzysztof Kosiński       test_immd19;
802*a03ca8b9SKrzysztof Kosiński   for (uint32_t clean_slate_code :
803*a03ca8b9SKrzysztof Kosiński        {kCleanSlate64Bcond, kCleanSlate64CBZw, kCleanSlate64CBZz,
804*a03ca8b9SKrzysztof Kosiński         kCleanSlate64CBNZw, kCleanSlate64CBNZz}) {
805*a03ca8b9SKrzysztof Kosiński     test_immd19.Accept(clean_slate_code, aligned4, aligned4);
806*a03ca8b9SKrzysztof Kosiński     test_immd19.Reject(clean_slate_code, aligned4, misaligned4);
807*a03ca8b9SKrzysztof Kosiński     test_immd19.Reject(clean_slate_code, misaligned4, aligned4);
808*a03ca8b9SKrzysztof Kosiński     test_immd19.Reject(clean_slate_code, misaligned4, misaligned4);
809*a03ca8b9SKrzysztof Kosiński     // Signed (19 + 2)-bit range, 4-byte aligned: [-0x00100000, 0x000FFFFC].
810*a03ca8b9SKrzysztof Kosiński     test_immd19.Accept(clean_slate_code, {0x10300000},
811*a03ca8b9SKrzysztof Kosiński                        {pcAArch64(0x10200000), pcAArch64(0x103FFFFC)});
812*a03ca8b9SKrzysztof Kosiński     test_immd19.Reject(clean_slate_code, {0x10300000},
813*a03ca8b9SKrzysztof Kosiński                        {pcAArch64(0x10200000 - 4), pcAArch64(0x103FFFFC + 4)});
814*a03ca8b9SKrzysztof Kosiński   }
815*a03ca8b9SKrzysztof Kosiński 
816*a03ca8b9SKrzysztof Kosiński   // Immd26 tests.
817*a03ca8b9SKrzysztof Kosiński   ArmTranslatorWriteReadTest<AArch64Rel32Translator::AddrTraits_Immd26>
818*a03ca8b9SKrzysztof Kosiński       test_immd26;
819*a03ca8b9SKrzysztof Kosiński   for (uint32_t clean_slate_code : {kCleanSlate64B, kCleanSlate64BL}) {
820*a03ca8b9SKrzysztof Kosiński     test_immd26.Accept(clean_slate_code, aligned4, aligned4);
821*a03ca8b9SKrzysztof Kosiński     test_immd26.Reject(clean_slate_code, aligned4, misaligned4);
822*a03ca8b9SKrzysztof Kosiński     test_immd26.Reject(clean_slate_code, misaligned4, aligned4);
823*a03ca8b9SKrzysztof Kosiński     test_immd26.Reject(clean_slate_code, misaligned4, misaligned4);
824*a03ca8b9SKrzysztof Kosiński     // Signed (26 + 2)-bit range, 4-byte aligned: [-0x08000000, 0x07FFFFFC].
825*a03ca8b9SKrzysztof Kosiński     test_immd26.Accept(clean_slate_code, {0x30000000},
826*a03ca8b9SKrzysztof Kosiński                        {pcAArch64(0x28000000), pcAArch64(0x37FFFFFC)});
827*a03ca8b9SKrzysztof Kosiński     test_immd26.Reject(clean_slate_code, {0x30000000},
828*a03ca8b9SKrzysztof Kosiński                        {pcAArch64(0x28000000 - 4), pcAArch64(0x37FFFFFC + 4)});
829*a03ca8b9SKrzysztof Kosiński   }
830*a03ca8b9SKrzysztof Kosiński }
831*a03ca8b9SKrzysztof Kosiński 
832*a03ca8b9SKrzysztof Kosiński // Typical usage in |target_rva| extraction.
TEST(AArch64Rel32Translator,Main)833*a03ca8b9SKrzysztof Kosiński TEST(AArch64Rel32Translator, Main) {
834*a03ca8b9SKrzysztof Kosiński   // 00103050: 02 01 02 14    B     00183458
835*a03ca8b9SKrzysztof Kosiński   rva_t instr_rva = 0x00103050U;
836*a03ca8b9SKrzysztof Kosiński   AArch64Rel32Translator translator;
837*a03ca8b9SKrzysztof Kosiński   std::vector<uint8_t> bytes = {0x02, 0x01, 0x02, 0x14};
838*a03ca8b9SKrzysztof Kosiński   MutableBufferView region(&bytes[0], bytes.size());
839*a03ca8b9SKrzysztof Kosiński   uint32_t code = translator.FetchCode32(region, 0U);
840*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(0x14020102U, code);
841*a03ca8b9SKrzysztof Kosiński 
842*a03ca8b9SKrzysztof Kosiński   // |code| <-> |disp|.
843*a03ca8b9SKrzysztof Kosiński   arm_disp_t disp = 0;
844*a03ca8b9SKrzysztof Kosiński   EXPECT_TRUE(translator.DecodeImmd26(code, &disp));
845*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(+0x00080408, disp);
846*a03ca8b9SKrzysztof Kosiński 
847*a03ca8b9SKrzysztof Kosiński   uint32_t code_from_disp = kCleanSlate64B;
848*a03ca8b9SKrzysztof Kosiński   EXPECT_TRUE(translator.EncodeImmd26(disp, &code_from_disp));
849*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(code, code_from_disp);
850*a03ca8b9SKrzysztof Kosiński 
851*a03ca8b9SKrzysztof Kosiński   // |code| <-> |target_rva|.
852*a03ca8b9SKrzysztof Kosiński   rva_t target_rva = kInvalidRva;
853*a03ca8b9SKrzysztof Kosiński   EXPECT_TRUE(translator.ReadImmd26(instr_rva, code, &target_rva));
854*a03ca8b9SKrzysztof Kosiński   // 0x00103050 + 0 + 0x00080408.
855*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(0x00183458U, target_rva);
856*a03ca8b9SKrzysztof Kosiński 
857*a03ca8b9SKrzysztof Kosiński   uint32_t code_from_rva = kCleanSlate64B;
858*a03ca8b9SKrzysztof Kosiński   EXPECT_TRUE(translator.WriteImmd26(instr_rva, target_rva, &code_from_rva));
859*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(code, code_from_rva);
860*a03ca8b9SKrzysztof Kosiński }
861*a03ca8b9SKrzysztof Kosiński 
862*a03ca8b9SKrzysztof Kosiński }  // namespace zucchini
863