aboutsummaryrefslogtreecommitdiff
path: root/arm_utils_unittest.cc
diff options
context:
space:
mode:
authorSamuel Huang <huangs@chromium.org>2019-01-18 19:36:50 +0000
committerCopybara-Service <copybara-worker@google.com>2021-07-25 20:45:25 -0700
commit4d20d0012bf46cdf678355af1a7be0eb1f05c80f (patch)
treeece4194582afbfe38fd9545b6cb04968976a18f3 /arm_utils_unittest.cc
parent3321a9e2309f02753ef88c1c96e999ac7a6fccfe (diff)
downloadzucchini-4d20d0012bf46cdf678355af1a7be0eb1f05c80f.tar.gz
[Zucchini] ARM code: Add alignment checks for Read*() / Write*(); add tests.
Read*() / Write*() functions for ARM code take |instr_rva|, and translate |code| <-> |target_rva|. Both |instr_rva| and |target_rva| must be properly aligned (2-bytes or 4-bytes), but previously such checks were only done on |target_rva - PC(instr_rva)|. This CL adds: * Alignment checks for input params of Read*() / Write*(). * Unit tests for Read*() / Write*(). Also update high-level comments in arm_utils.h. Bug: 918867 Change-Id: Ie37d2df621411920b54ef699edaed1d90eacba88 Reviewed-on: https://chromium-review.googlesource.com/c/1415753 Reviewed-by: Samuel Huang <huangs@chromium.org> Reviewed-by: Etienne Pierre-Doray <etiennep@chromium.org> Commit-Queue: Samuel Huang <huangs@chromium.org> Cr-Commit-Position: refs/heads/master@{#624236} NOKEYCHECK=True GitOrigin-RevId: 88de28e56330d97fe046755fee972495d5e5749d
Diffstat (limited to 'arm_utils_unittest.cc')
-rw-r--r--arm_utils_unittest.cc221
1 files changed, 217 insertions, 4 deletions
diff --git a/arm_utils_unittest.cc b/arm_utils_unittest.cc
index 1b328ee..2b669d0 100644
--- a/arm_utils_unittest.cc
+++ b/arm_utils_unittest.cc
@@ -16,6 +16,7 @@
#include <vector>
#include "base/logging.h"
+#include "components/zucchini/address_translator.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace zucchini {
@@ -30,7 +31,7 @@ uint32_t kCleanSlateBLX_A2 = 0xFA000000; // A24.
uint16_t kCleanSlateB_T1 = 0xD000; // T8.
uint16_t kCleanSlateB_T2 = 0xE000; // T11.
uint32_t kCleanSlateB_T3 = 0xF0008000; // T20.
-// For T4 encodings, |disp| = 0 means J1 = J2 = 1, so include 0x00002800.
+// For T24 encodings, |disp| = 0 means J1 = J2 = 1, so include 0x00002800.
uint32_t kCleanSlateB_T4 = 0xF0009000 | 0x00002800; // T24.
uint32_t kCleanSlateBL_T1 = 0xF000D000 | 0x00002800; // T24.
uint32_t kCleanSlateBLX_T2 = 0xF000C000 | 0x00002800; // T24.
@@ -134,7 +135,7 @@ struct ArmRelInstruction {
INT_T clean_slate_code;
};
-// Tester for Decode/Encode functions for ARM.
+// Tester for ARM Encode / Decode functions for |disp| <-> |code|.
template <typename TRAITS>
class ArmTranslatorEncodeDecodeTest {
public:
@@ -204,6 +205,60 @@ class ArmTranslatorEncodeDecodeTest {
}
};
+// Tester for ARM Write / Read functions for |target_rva| <-> |code|.
+template <typename TRAITS>
+class ArmTranslatorWriteReadTest {
+ public:
+ using CODE_T = typename TRAITS::code_t;
+
+ ArmTranslatorWriteReadTest() {}
+
+ // Expects successful Write() to |clean_slate_code| for each |target_rva_list|
+ // RVA, using each |instr_rva_list| RVA, and that the resulting |code| leads
+ // to successful Read(), which recovers |instr_rva|.
+ void Accept(CODE_T clean_slate_code,
+ const std::vector<rva_t>& instr_rva_list,
+ const std::vector<rva_t>& target_rva_list) {
+ bool (*read_fun)(rva_t, CODE_T, rva_t*) = TRAITS::Read;
+ bool (*write_fun)(rva_t, rva_t, CODE_T*) = TRAITS::Write;
+
+ for (rva_t instr_rva : instr_rva_list) {
+ for (rva_t target_rva : target_rva_list) {
+ CODE_T code = clean_slate_code;
+ // Write |target_rva| to |code|.
+ EXPECT_TRUE((*write_fun)(instr_rva, target_rva, &code)) << target_rva;
+ rva_t target_rva_out = kInvalidRva;
+
+ // Read |code| to |target_rva_out|, check fidelity.
+ EXPECT_TRUE((*read_fun)(instr_rva, code, &target_rva_out));
+ EXPECT_EQ(target_rva, target_rva_out);
+
+ // Sanity check: Rewrite |target_rva| into |code|, ensure no change.
+ CODE_T code_copy = code;
+ EXPECT_TRUE((*write_fun)(instr_rva, target_rva, &code));
+ EXPECT_EQ(code_copy, code);
+ }
+ }
+ }
+
+ // Expects failed Write() to |clean_slate_code| for each |target_rva_list|
+ // RVA, using each |instr_rva_list| RVA.
+ void Reject(CODE_T clean_slate_code,
+ const std::vector<rva_t>& instr_rva_list,
+ const std::vector<rva_t>& target_rva_list) {
+ bool (*write_fun)(rva_t, rva_t, CODE_T*) = TRAITS::Write;
+
+ for (rva_t instr_rva : instr_rva_list) {
+ for (rva_t target_rva : target_rva_list) {
+ CODE_T code = clean_slate_code;
+ EXPECT_FALSE((*write_fun)(instr_rva, target_rva, &code)) << target_rva;
+ // Output variable is unmodified after failure.
+ EXPECT_EQ(clean_slate_code, code);
+ }
+ }
+ }
+};
+
} // namespace
// Test for test helper.
@@ -377,7 +432,108 @@ TEST(Arm32Rel32Translator, EncodeDecode) {
}
TEST(Arm32Rel32Translator, WriteRead) {
- // TODO(huangs): Implement.
+ std::vector<rva_t> aligned4;
+ std::vector<rva_t> misaligned4;
+ std::vector<rva_t> aligned2;
+ std::vector<rva_t> misaligned2;
+ for (rva_t rva = 0x1FFC; rva <= 0x2010; ++rva) {
+ ((rva % 4 == 0) ? aligned4 : misaligned4).push_back(rva);
+ ((rva % 2 == 0) ? aligned2 : misaligned2).push_back(rva);
+ }
+ CHECK_EQ(6U, aligned4.size());
+ CHECK_EQ(15U, misaligned4.size());
+ CHECK_EQ(11U, aligned2.size());
+ CHECK_EQ(10U, misaligned2.size());
+
+ // Helpers to convert an instruction's RVA to PC.
+ auto pcArm = [](rva_t instr_rva) -> rva_t { return instr_rva + 8; };
+ auto pcThumb2 = [](rva_t instr_rva) -> rva_t { return instr_rva + 4; };
+
+ // A24 tests.
+ ArmTranslatorWriteReadTest<Arm32Rel32Translator::AddrTraits_A24> test_A24;
+ for (uint32_t clean_slate_code : {kCleanSlateB_A1, kCleanSlateBL_A1}) {
+ test_A24.Accept(clean_slate_code, aligned4, aligned4);
+ test_A24.Reject(clean_slate_code, aligned4, misaligned4);
+ test_A24.Reject(clean_slate_code, misaligned4, aligned4);
+ test_A24.Reject(clean_slate_code, misaligned4, misaligned4);
+ // Signed (24 + 2)-bit range, 4-byte aligned: [-0x02000000, 0x01FFFFFC].
+ test_A24.Accept(clean_slate_code, {0x15000000},
+ {pcArm(0x13000000), pcArm(0x16FFFFFC)});
+ test_A24.Reject(clean_slate_code, {0x15000000},
+ {pcArm(0x13000000 - 4), pcArm(0x16FFFFFC + 4)});
+ }
+
+ // BLX complication: ARM -> THUMB2.
+ test_A24.Accept(kCleanSlateBLX_A2, aligned4, aligned2);
+ test_A24.Reject(kCleanSlateBLX_A2, aligned4, misaligned2);
+ test_A24.Reject(kCleanSlateBLX_A2, misaligned4, aligned2);
+ test_A24.Reject(kCleanSlateBLX_A2, misaligned4, misaligned2);
+ test_A24.Accept(kCleanSlateBLX_A2, {0x15000000},
+ {pcArm(0x13000000), pcArm(0x16FFFFFE)});
+ test_A24.Reject(kCleanSlateBLX_A2, {0x15000000},
+ {pcArm(0x13000000 - 4), pcArm(0x13000000 - 2),
+ pcArm(0x16FFFFFE + 2), pcArm(0x16FFFFFE + 4)});
+
+ // T8 tests.
+ ArmTranslatorWriteReadTest<Arm32Rel32Translator::AddrTraits_T8> test_T8;
+ test_T8.Accept(kCleanSlateB_T1, aligned2, aligned2);
+ test_T8.Reject(kCleanSlateB_T1, aligned2, misaligned2);
+ test_T8.Reject(kCleanSlateB_T1, misaligned2, aligned2);
+ test_T8.Reject(kCleanSlateB_T1, misaligned2, misaligned2);
+ // Signed (8 + 1)-bit range, 2-byte aligned: [-0x0100, 0x00FE].
+ test_T8.Accept(kCleanSlateB_T1, {0x10000500},
+ {pcThumb2(0x10000400), pcThumb2(0x100005FE)});
+ test_T8.Reject(kCleanSlateB_T1, {0x10000500},
+ {pcThumb2(0x10000400 - 2), pcThumb2(0x100005FE + 2)});
+
+ // T11 tests.
+ ArmTranslatorWriteReadTest<Arm32Rel32Translator::AddrTraits_T11> test_T11;
+ test_T11.Accept(kCleanSlateB_T2, aligned2, aligned2);
+ test_T11.Reject(kCleanSlateB_T2, aligned2, misaligned2);
+ test_T11.Reject(kCleanSlateB_T2, misaligned2, aligned2);
+ test_T11.Reject(kCleanSlateB_T2, misaligned2, misaligned2);
+ // Signed (11 + 1)-bit range, 2-byte aligned: [-0x0800, 0x07FE].
+ test_T11.Accept(kCleanSlateB_T2, {0x10003000},
+ {pcThumb2(0x10002800), pcThumb2(0x100037FE)});
+ test_T11.Reject(kCleanSlateB_T2, {0x10003000},
+ {pcThumb2(0x10002800 - 2), pcThumb2(0x100037FE + 2)});
+
+ // T20 tests.
+ ArmTranslatorWriteReadTest<Arm32Rel32Translator::AddrTraits_T20> test_T20;
+ test_T20.Accept(kCleanSlateB_T3, aligned2, aligned2);
+ test_T20.Reject(kCleanSlateB_T3, aligned2, misaligned2);
+ test_T20.Reject(kCleanSlateB_T3, misaligned2, aligned2);
+ test_T20.Reject(kCleanSlateB_T3, misaligned2, misaligned2);
+ // Signed (20 + 1)-bit range, 2-byte aligned: [-0x00100000, 0x000FFFFE].
+ test_T20.Accept(kCleanSlateB_T3, {0x10300000},
+ {pcThumb2(0x10200000), pcThumb2(0x103FFFFE)});
+ test_T20.Reject(kCleanSlateB_T3, {0x10300000},
+ {pcThumb2(0x10200000 - 2), pcThumb2(0x103FFFFE + 2)});
+
+ // T24 tests.
+ ArmTranslatorWriteReadTest<Arm32Rel32Translator::AddrTraits_T24> test_T24;
+ for (uint32_t clean_slate_code : {kCleanSlateB_T4, kCleanSlateBL_T1}) {
+ test_T24.Accept(clean_slate_code, aligned2, aligned2);
+ test_T24.Reject(clean_slate_code, aligned2, misaligned2);
+ test_T24.Reject(clean_slate_code, misaligned2, aligned2);
+ test_T24.Reject(clean_slate_code, misaligned2, misaligned2);
+ // Signed (24 + 1)-bit range, 2-byte aligned: [-0x01000000, 0x00FFFFFE].
+ test_T24.Accept(clean_slate_code, {0x16000000},
+ {pcThumb2(0x15000000), pcThumb2(0x16FFFFFE)});
+ test_T24.Reject(clean_slate_code, {0x16000000},
+ {pcThumb2(0x15000000 - 2), pcThumb2(0x16FFFFFE + 2)});
+ }
+
+ // BLX complication: THUMB2 -> ARM.
+ test_T24.Accept(kCleanSlateBLX_T2, aligned2, aligned4);
+ test_T24.Reject(kCleanSlateBLX_T2, aligned2, misaligned4);
+ test_T24.Reject(kCleanSlateBLX_T2, misaligned2, aligned4);
+ test_T24.Reject(kCleanSlateBLX_T2, misaligned2, misaligned4);
+ test_T24.Accept(kCleanSlateBLX_T2, {0x16000000},
+ {pcThumb2(0x15000000), pcThumb2(0x16FFFFFC)});
+ test_T24.Reject(kCleanSlateBLX_T2, {0x16000000},
+ {pcThumb2(0x15000000 - 4), pcThumb2(0x15000000 - 2),
+ pcThumb2(0x16FFFFFC + 2), pcThumb2(0x16FFFFFC + 4)});
}
// Typical usage in |target_rva| extraction.
@@ -609,7 +765,64 @@ TEST(AArch64Rel32Translator, EncodeDecode) {
}
TEST(AArch64Rel32Translator, WriteRead) {
- // TODO(huangs): Implement.
+ std::vector<rva_t> aligned4;
+ std::vector<rva_t> misaligned4;
+ for (rva_t rva = 0x1FFC; rva <= 0x2010; ++rva) {
+ ((rva % 4 == 0) ? aligned4 : misaligned4).push_back(rva);
+ }
+ CHECK_EQ(6U, aligned4.size());
+ CHECK_EQ(15U, misaligned4.size());
+
+ // Helper to convert an instruction's RVA to PC.
+ auto pcAArch64 = [](rva_t instr_rva) -> rva_t { return instr_rva; };
+
+ // Immd14 tests.
+ ArmTranslatorWriteReadTest<AArch64Rel32Translator::AddrTraits_Immd14>
+ test_immd14;
+ for (uint32_t clean_slate_code : {kCleanSlate64TBZw, kCleanSlate64TBZz,
+ kCleanSlate64TBNZw, kCleanSlate64TBNZz}) {
+ test_immd14.Accept(clean_slate_code, aligned4, aligned4);
+ test_immd14.Reject(clean_slate_code, aligned4, misaligned4);
+ test_immd14.Reject(clean_slate_code, misaligned4, aligned4);
+ test_immd14.Reject(clean_slate_code, misaligned4, misaligned4);
+ // Signed (14 + 2)-bit range, 4-byte aligned: [-0x00008000, 0x00007FFC].
+ test_immd14.Accept(clean_slate_code, {0x10040000},
+ {pcAArch64(0x10038000), pcAArch64(0x10047FFC)});
+ test_immd14.Reject(clean_slate_code, {0x15000000},
+ {pcAArch64(0x10038000 - 4), pcAArch64(0x10047FFC + 4)});
+ }
+
+ // Immd19 tests.
+ ArmTranslatorWriteReadTest<AArch64Rel32Translator::AddrTraits_Immd19>
+ test_immd19;
+ for (uint32_t clean_slate_code :
+ {kCleanSlate64Bcond, kCleanSlate64CBZw, kCleanSlate64CBZz,
+ kCleanSlate64CBNZw, kCleanSlate64CBNZz}) {
+ test_immd19.Accept(clean_slate_code, aligned4, aligned4);
+ test_immd19.Reject(clean_slate_code, aligned4, misaligned4);
+ test_immd19.Reject(clean_slate_code, misaligned4, aligned4);
+ test_immd19.Reject(clean_slate_code, misaligned4, misaligned4);
+ // Signed (19 + 2)-bit range, 4-byte aligned: [-0x00100000, 0x000FFFFC].
+ test_immd19.Accept(clean_slate_code, {0x10300000},
+ {pcAArch64(0x10200000), pcAArch64(0x103FFFFC)});
+ test_immd19.Reject(clean_slate_code, {0x10300000},
+ {pcAArch64(0x10200000 - 4), pcAArch64(0x103FFFFC + 4)});
+ }
+
+ // Immd26 tests.
+ ArmTranslatorWriteReadTest<AArch64Rel32Translator::AddrTraits_Immd26>
+ test_immd26;
+ for (uint32_t clean_slate_code : {kCleanSlate64B, kCleanSlate64BL}) {
+ test_immd26.Accept(clean_slate_code, aligned4, aligned4);
+ test_immd26.Reject(clean_slate_code, aligned4, misaligned4);
+ test_immd26.Reject(clean_slate_code, misaligned4, aligned4);
+ test_immd26.Reject(clean_slate_code, misaligned4, misaligned4);
+ // Signed (26 + 2)-bit range, 4-byte aligned: [-0x08000000, 0x07FFFFFC].
+ test_immd26.Accept(clean_slate_code, {0x30000000},
+ {pcAArch64(0x28000000), pcAArch64(0x37FFFFFC)});
+ test_immd26.Reject(clean_slate_code, {0x30000000},
+ {pcAArch64(0x28000000 - 4), pcAArch64(0x37FFFFFC + 4)});
+ }
}
// Typical usage in |target_rva| extraction.