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