// Copyright 2019 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "components/zucchini/arm_utils.h" #include <stddef.h> #include <stdint.h> #include <algorithm> #include <initializer_list> #include <map> #include <sstream> #include <string> #include <vector> #include "base/check_op.h" #include "components/zucchini/address_translator.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/abseil-cpp/absl/strings/ascii.h" namespace zucchini { namespace { // "Clean slate" |code|s for branch instruction encodings with |disp| = 0, and // if applicable, |cond| = 0. uint32_t kCleanSlateB_A1 = …; // A24. uint32_t kCleanSlateBL_A1 = …; // A24. uint32_t kCleanSlateBLX_A2 = …; // A24. uint16_t kCleanSlateB_T1 = …; // T8. uint16_t kCleanSlateB_T2 = …; // T11. uint32_t kCleanSlateB_T3 = …; // T20. // For T24 encodings, |disp| = 0 means J1 = J2 = 1, so include 0x00002800. uint32_t kCleanSlateB_T4 = …; // T24. uint32_t kCleanSlateBL_T1 = …; // T24. uint32_t kCleanSlateBLX_T2 = …; // T24. // For AArch64. uint32_t kCleanSlate64TBZw = …; // Immd14. uint32_t kCleanSlate64TBZz = …; // Immd14. uint32_t kCleanSlate64TBNZw = …; // Immd14. uint32_t kCleanSlate64TBNZz = …; // Immd14. uint32_t kCleanSlate64Bcond = …; // Immd19. uint32_t kCleanSlate64CBZw = …; // Immd19. uint32_t kCleanSlate64CBZz = …; // Immd19. uint32_t kCleanSlate64CBNZw = …; // Immd19. uint32_t kCleanSlate64CBNZz = …; // Immd19. uint32_t kCleanSlate64B = …; // Immd26. uint32_t kCleanSlate64BL = …; // Immd26. // Special case: Cond = 0xE => AL. uint32_t kCleanSlateBAL_A1 = …; // // Test helper: Extracts |components| from |value| (may be |code| or |disp|) // based on |pattern|. Also performs consistency checks. On success, writes to // |*components| and returns true. Otherwise returns false. // Example (all numbers are in binary): // |pattern| = "11110Scc cciiiiii 10(J1)0(J2)jjj jjjj...." // |value| = 11110111 00111000 10 1 0 0 111 11000101 // Result: Noting that all 0's and 1's are consistent, returns true with: // |*components| = {S: 1, c: 1100, i: 111000, J1: 1, J2: 0, j: 1111100} // Rules for |pattern|: // * Spaces are ignored. // * '.' means "don't care". // * '0' and '1' are expected literals; mismatch leads to failure. // * A variable name is specified as: // * A single letter. // * "(var)", where "var" is a name that begins with a letter. // * If a variable's first letter is uppercase, then it's a singleton bit. // * If repeated, consistency check is applied (must be identical). // * If a variable's first letter is lowercase, then it spans multiple bits. // * These need not be contiguous, but order is preserved (big-endian). static bool SplitBits(const std::string& pattern, uint32_t value, std::map<std::string, uint32_t>* components) { … } // AArch32 or AArch64 instruction specification for tests. May be 16-bit or // 32-bit (determined by INT_T). template <typename INT_T> struct ArmRelInstruction { … }; // Tester for ARM Encode / Decode functions for |disp| <-> |code|. template <typename TRAITS> class ArmTranslatorEncodeDecodeTest { … }; // Tester for ARM Write / Read functions for |target_rva| <-> |code|. template <typename TRAITS> class ArmTranslatorWriteReadTest { … }; } // namespace // Test for test helper. TEST(ArmUtilsTest, SplitBits) { … } TEST(AArch32Rel32Translator, Fetch) { … } TEST(AArch32Rel32Translator, Store) { … } // Detailed test of Encode/Decode: Check valid and invalid |disp| for various // clean slate |code| cases. Also check |disp| and |code| binary components, // which in AArch32Rel32Translator comments. TEST(AArch32Rel32Translator, EncodeDecode) { … } TEST(AArch32Rel32Translator, WriteRead) { … } // Typical usage in |target_rva| extraction. TEST(AArch32Rel32Translator, Main) { … } TEST(AArch32Rel32Translator, BLXComplication) { … } TEST(AArch64Rel32Translator, FetchStore) { … } TEST(AArch64Rel32Translator, EncodeDecode) { … } TEST(AArch64Rel32Translator, WriteRead) { … } // Typical usage in |target_rva| extraction. TEST(AArch64Rel32Translator, Main) { … } } // namespace zucchini