123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586 |
- // Copyright 2017 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "components/zucchini/address_translator.h"
- #include <algorithm>
- #include <string>
- #include <utility>
- #include "base/format_macros.h"
- #include "base/strings/stringprintf.h"
- #include "testing/gtest/include/gtest/gtest.h"
- namespace zucchini {
- namespace {
- // Test case structs. The convention of EXPECT() specifies "expectd" value
- // before ""actual". However, AddressTranslator interfaces explicitly state "X
- // to Y". So it is clearer in test cases to specify "input" before "expect".
- struct OffsetToRvaTestCase {
- offset_t input;
- rva_t expect;
- };
- struct RvaToOffsetTestCase {
- rva_t input;
- offset_t expect;
- };
- class TestAddressTranslator : public AddressTranslator {
- public:
- using AddressTranslator::AddressTranslator;
- // Initialize() alternative that parses a visual representation of offset and
- // RVA ranges. Illustrative example ("special" means '.' or '!'):
- // "..AAA...|....aaaa" => "..AAA..." for offsets, and "....aaaa" for RVAs:
- // - "..AAA...": First non-period character is at 2, so |offset_begin| = 2.
- // - "..AAA...": There are 3 non-special characters, so |offset_size| = +3.
- // - "....aaaa": First non-period character is at 4, so |rva_begin| = 4.
- // - "....aaaa": There are 4 non-special characters, so |rva_size| = +4.
- // For the special case of length-0 range, '!' can be used. For example,
- // "...!...." specifies |begin| = 3 and |size| = +0.
- AddressTranslator::Status InitializeWithStrings(
- const std::vector<std::string>& specs) {
- std::vector<Unit> units;
- units.reserve(specs.size());
- for (const std::string& s : specs) {
- size_t sep = s.find('|');
- CHECK_NE(sep, std::string::npos);
- std::string s1 = s.substr(0, sep);
- std::string s2 = s.substr(sep + 1);
- auto first_non_blank = [](const std::string& t) {
- auto is_blank = [](char ch) { return ch == '.'; };
- return std::find_if_not(t.begin(), t.end(), is_blank) - t.begin();
- };
- auto count_non_special = [](const std::string& t) {
- auto is_special = [](char ch) { return ch == '.' || ch == '!'; };
- return t.size() - std::count_if(t.begin(), t.end(), is_special);
- };
- units.push_back({static_cast<offset_t>(first_non_blank(s1)),
- static_cast<offset_t>(count_non_special(s1)),
- static_cast<rva_t>(first_non_blank(s2)),
- static_cast<rva_t>(count_non_special(s2))});
- }
- return Initialize(std::move(units));
- }
- };
- // Simple test: Initialize TestAddressTranslator using |specs|, and match
- // |expected| results re. success or failure.
- void SimpleTest(const std::vector<std::string>& specs,
- AddressTranslator::Status expected,
- const std::string& case_name) {
- TestAddressTranslator translator;
- auto result = translator.InitializeWithStrings(specs);
- EXPECT_EQ(expected, result) << case_name;
- }
- // Test AddressTranslator::Initialize's Unit overlap and error checks over
- // multiple test cases, each case consists of a fixed unit (specified as
- // string), and a variable string taken from an list.
- class TwoUnitOverlapTester {
- public:
- struct TestCase {
- std::string unit_str;
- AddressTranslator::Status expected;
- };
- static void RunTest(const std::string& unit_str1,
- const std::vector<TestCase>& test_cases) {
- for (size_t i = 0; i < test_cases.size(); ++i) {
- const auto& test_case = test_cases[i];
- const std::string& unit_str2 = test_case.unit_str;
- const std::string str =
- base::StringPrintf("Case #%" PRIuS ": %s", i, unit_str2.c_str());
- SimpleTest({unit_str1, unit_str2}, test_case.expected, str);
- // Switch order. Expect same results.
- SimpleTest({unit_str2, unit_str1}, test_case.expected, str);
- }
- }
- };
- } // namespace
- TEST(AddressTranslatorTest, Empty) {
- using AT = AddressTranslator;
- TestAddressTranslator translator;
- EXPECT_EQ(AT::kSuccess,
- translator.Initialize(std::vector<AddressTranslator::Unit>()));
- offset_t fake_offset_begin = translator.fake_offset_begin();
- // Optimized versions.
- AddressTranslator::OffsetToRvaCache offset_to_rva(translator);
- AddressTranslator::RvaToOffsetCache rva_to_offset(translator);
- EXPECT_EQ(kInvalidRva, translator.OffsetToRva(0U));
- EXPECT_EQ(kInvalidRva, translator.OffsetToRva(100U));
- EXPECT_EQ(kInvalidRva, offset_to_rva.Convert(0U));
- EXPECT_EQ(kInvalidRva, offset_to_rva.Convert(100U));
- EXPECT_EQ(kInvalidOffset, translator.RvaToOffset(0U));
- EXPECT_EQ(kInvalidOffset, translator.RvaToOffset(100U));
- EXPECT_EQ(kInvalidOffset, rva_to_offset.Convert(0U));
- EXPECT_EQ(kInvalidOffset, rva_to_offset.Convert(100U));
- EXPECT_EQ(kInvalidRva, translator.OffsetToRva(fake_offset_begin));
- EXPECT_EQ(kInvalidRva, offset_to_rva.Convert(fake_offset_begin));
- }
- TEST(AddressTranslatorTest, Single) {
- using AT = AddressTranslator;
- TestAddressTranslator translator;
- // Offsets to RVA: [10, 30) -> [100, 120).
- EXPECT_EQ(AT::kSuccess, translator.Initialize({{10U, +20U, 100U, +20U}}));
- offset_t fake_offset_begin = translator.fake_offset_begin();
- // Optimized versions.
- AddressTranslator::OffsetToRvaCache offset_to_rva(translator);
- AddressTranslator::RvaToOffsetCache rva_to_offset(translator);
- EXPECT_EQ(30U, fake_offset_begin); // Test implementation detail.
- // Offsets to RVAs.
- OffsetToRvaTestCase test_cases1[] = {
- {0U, kInvalidRva}, {9U, kInvalidRva}, {10U, 100U},
- {20U, 110U}, {29U, 119U}, {30U, kInvalidRva},
- };
- for (auto& test_case : test_cases1) {
- EXPECT_EQ(test_case.expect, translator.OffsetToRva(test_case.input));
- EXPECT_EQ(test_case.expect, offset_to_rva.Convert(test_case.input));
- }
- // RVAs to offsets.
- RvaToOffsetTestCase test_cases2[] = {
- {0U, kInvalidOffset}, {99U, kInvalidOffset}, {100U, 10U},
- {110U, 20U}, {119U, 29U}, {120U, kInvalidOffset},
- };
- for (auto& test_case : test_cases2) {
- EXPECT_EQ(test_case.expect, translator.RvaToOffset(test_case.input));
- EXPECT_EQ(test_case.expect, rva_to_offset.Convert(test_case.input));
- }
- }
- TEST(AddressTranslatorTest, SingleDanglingRva) {
- using AT = AddressTranslator;
- TestAddressTranslator translator;
- // Offsets to RVA: [10, 30) -> [100, 120 + 7), so has dangling RVAs.
- EXPECT_EQ(AT::kSuccess,
- translator.Initialize({{10U, +20U, 100U, +20U + 7U}}));
- offset_t fake_offset_begin = translator.fake_offset_begin();
- EXPECT_EQ(30U, fake_offset_begin); // Test implementation detail.
- // Optimized versions.
- AddressTranslator::OffsetToRvaCache offset_to_rva(translator);
- AddressTranslator::RvaToOffsetCache rva_to_offset(translator);
- // Offsets to RVAs.
- OffsetToRvaTestCase test_cases1[] = {
- {0U, kInvalidRva},
- {9U, kInvalidRva},
- {10U, 100U},
- {20U, 110U},
- {29U, 119U},
- {30U, kInvalidRva},
- // Fake offsets to dangling RVAs.
- {fake_offset_begin + 100U, kInvalidRva},
- {fake_offset_begin + 119U, kInvalidRva},
- {fake_offset_begin + 120U, 120U},
- {fake_offset_begin + 126U, 126U},
- {fake_offset_begin + 127U, kInvalidRva},
- };
- for (auto& test_case : test_cases1) {
- EXPECT_EQ(test_case.expect, translator.OffsetToRva(test_case.input));
- EXPECT_EQ(test_case.expect, offset_to_rva.Convert(test_case.input));
- }
- // RVAs to offsets.
- RvaToOffsetTestCase test_cases2[] = {
- {0U, kInvalidOffset},
- {99U, kInvalidOffset},
- {100U, 10U},
- {110U, 20U},
- {119U, 29U},
- // Dangling RVAs to fake offsets.
- {120U, fake_offset_begin + 120U},
- {126U, fake_offset_begin + 126U},
- {127U, kInvalidOffset},
- };
- for (auto& test_case : test_cases2) {
- EXPECT_EQ(test_case.expect, translator.RvaToOffset(test_case.input));
- EXPECT_EQ(test_case.expect, rva_to_offset.Convert(test_case.input));
- }
- }
- TEST(AddressTranslatorTest, BasicUsage) {
- using AT = AddressTranslator;
- TestAddressTranslator translator;
- // Offsets covered: [10, 30), [40, 70), [70, 110).
- // Map to RVAs: [200, 220 + 5), [300, 330), [100, 140), so has dangling RVAs.
- auto result = translator.Initialize({
- {10U, +20U, 200U, +20U + 5U}, // Has dangling RVAs.
- {40U, +30U, 300U, +20U}, // Extra offset truncated and ignored.
- {50U, +20U, 310U, +20U}, // Overlap with previous: Merged.
- {70U, +40U, 100U, +20U}, // Tangent with previous but inconsistent; extra
- // offset truncated and ignored.
- {90U, +20U, 120U, +20U}, // Tangent with previous and consistent: Merged.
- });
- EXPECT_EQ(AT::kSuccess, result);
- offset_t fake_offset_begin = translator.fake_offset_begin();
- EXPECT_EQ(110U, fake_offset_begin); // Test implementation detail.
- // Optimized versions.
- AddressTranslator::OffsetToRvaCache offset_to_rva(translator);
- AddressTranslator::RvaToOffsetCache rva_to_offset(translator);
- // Offsets to RVAs.
- OffsetToRvaTestCase test_cases1[] = {
- {0U, kInvalidRva},
- {9U, kInvalidRva},
- {10U, 200U},
- {20U, 210U},
- {29U, 219U},
- {30U, kInvalidRva},
- {39U, kInvalidRva},
- {40U, 300U},
- {55U, 315U},
- {69U, 329U},
- {70U, 100U},
- {90U, 120U},
- {109U, 139U},
- {110U, kInvalidRva},
- // Fake offsets to dangling RVAs.
- {fake_offset_begin + 220U, 220U},
- {fake_offset_begin + 224U, 224U},
- {fake_offset_begin + 225U, kInvalidRva},
- };
- for (auto& test_case : test_cases1) {
- EXPECT_EQ(test_case.expect, translator.OffsetToRva(test_case.input));
- EXPECT_EQ(test_case.expect, offset_to_rva.Convert(test_case.input));
- }
- // RVAs to offsets.
- RvaToOffsetTestCase test_cases2[] = {
- {0U, kInvalidOffset},
- {99U, kInvalidOffset},
- {100U, 70U},
- {120U, 90U},
- {139U, 109U},
- {140U, kInvalidOffset},
- {199U, kInvalidOffset},
- {200U, 10U},
- {210U, 20U},
- {219U, 29U},
- {225U, kInvalidOffset},
- {299U, kInvalidOffset},
- {300U, 40U},
- {315U, 55U},
- {329U, 69U},
- {330U, kInvalidOffset},
- // Dangling RVAs to fake offsets.
- {220U, fake_offset_begin + 220U},
- {224U, fake_offset_begin + 224U},
- {225U, kInvalidOffset},
- };
- for (auto& test_case : test_cases2) {
- EXPECT_EQ(test_case.expect, translator.RvaToOffset(test_case.input));
- EXPECT_EQ(test_case.expect, rva_to_offset.Convert(test_case.input));
- }
- }
- TEST(AddressTranslatorTest, Overflow) {
- using AT = AddressTranslator;
- // Test assumes that offset_t and rva_t to be 32-bit.
- static_assert(sizeof(offset_t) == 4 && sizeof(rva_t) == 4,
- "Needs to update test.");
- {
- AddressTranslator translator1;
- EXPECT_EQ(AT::kErrorOverflow,
- translator1.Initialize({{0, +0xC0000000U, 0, +0xC0000000U}}));
- }
- {
- AddressTranslator translator2;
- EXPECT_EQ(AT::kErrorOverflow,
- translator2.Initialize({{0, +0, 0, +0xC0000000U}}));
- }
- {
- // Units are okay, owing to but limitations of the heuristic to convert
- // dangling RVA to fake offset, AddressTranslator::Initialize() fails.
- AddressTranslator translator3;
- EXPECT_EQ(AT::kErrorFakeOffsetBeginTooLarge,
- translator3.Initialize(
- {{32, +0, 32, +0x50000000U}, {0x50000000U, +16, 0, +16}}));
- }
- }
- // Sanity test for TestAddressTranslator::InitializeWithStrings();
- TEST(AddressTranslatorTest, AddUnitAsString) {
- using AT = AddressTranslator;
- {
- TestAddressTranslator translator1;
- EXPECT_EQ(AT::kSuccess, translator1.InitializeWithStrings({"..A..|.aaa."}));
- AddressTranslator::Unit unit1 = translator1.units_sorted_by_offset()[0];
- EXPECT_EQ(2U, unit1.offset_begin);
- EXPECT_EQ(+1U, unit1.offset_size);
- EXPECT_EQ(1U, unit1.rva_begin);
- EXPECT_EQ(+3U, unit1.rva_size);
- }
- {
- TestAddressTranslator translator2;
- EXPECT_EQ(AT::kSuccess,
- translator2.InitializeWithStrings({".....!...|.bbbbbb..."}));
- AddressTranslator::Unit unit2 = translator2.units_sorted_by_offset()[0];
- EXPECT_EQ(5U, unit2.offset_begin);
- EXPECT_EQ(+0U, unit2.offset_size);
- EXPECT_EQ(1U, unit2.rva_begin);
- EXPECT_EQ(+6U, unit2.rva_size);
- }
- }
- // AddressTranslator::Initialize() lists Unit merging examples in comments. The
- // format is different from that used by InitializeWithStrings(), but adapting
- // them is easy, so we may as well do so.
- TEST(AddressTranslatorTest, OverlapFromComment) {
- using AT = AddressTranslator;
- constexpr auto OK = AT::kSuccess;
- struct {
- const char* rva_str; // RVA comes first in this case.
- const char* offset_str;
- AT::Status expected;
- } test_cases[] = {
- {"..ssssffff..", "..SSSSFFFF..", OK},
- {"..ssssffff..", "..SSSS..FFFF..", OK},
- {"..ssssffff..", "..FFFF..SSSS..", OK},
- {"..ssssffff..", "..SSOOFF..", AT::kErrorBadOverlap},
- {"..sssooofff..", "..SSSOOOFFF..", OK},
- {"..sssooofff..", "..SSSSSOFFFFF..", AT::kErrorBadOverlap},
- {"..sssooofff..", "..FFOOOOSS..", AT::kErrorBadOverlap},
- {"..sssooofff..", "..SSSOOOF..", OK},
- {"..sssooofff..", "..SSSOOOF..", OK},
- {"..sssooosss..", "..SSSOOOS..", OK},
- {"..sssooofff..", "..SSSOO..", OK},
- {"..sssooofff..", "..SSSOFFF..", AT::kErrorBadOverlapDanglingRva},
- {"..sssooosss..", "..SSSOOSSSS..", AT::kErrorBadOverlapDanglingRva},
- {"..oooooo..", "..OOO..", OK},
- };
- auto to_period = [](std::string s, char ch) { // |s| passed by value.
- std::replace(s.begin(), s.end(), ch, '.');
- return s;
- };
- size_t idx = 0;
- for (const auto& test_case : test_cases) {
- std::string base_str =
- std::string(test_case.offset_str) + "|" + test_case.rva_str;
- std::string unit_str1 = to_period(to_period(base_str, 'S'), 's');
- std::string unit_str2 = to_period(to_period(base_str, 'F'), 'f');
- SimpleTest({unit_str1, unit_str2}, test_case.expected,
- base::StringPrintf("Case #%" PRIuS, idx));
- ++idx;
- }
- }
- TEST(AddressTranslatorTest, Overlap) {
- using AT = AddressTranslator;
- constexpr auto OK = AT::kSuccess;
- constexpr const char* unit_str1 = "....AAA.......|.....aaa......";
- std::vector<TwoUnitOverlapTester::TestCase> test_cases = {
- //....AAA.......|.....aaa...... The first Unit. NOLINT
- {"....BBB.......|.....bbb......", OK},
- {"..BBB.........|...bbb........", OK},
- {"......BBB.....|.......bbb....", OK},
- {"..BBBBBBBBB...|...bbb........", OK}, // Extra offset get truncated.
- {"......BBBBBBBB|.......bbb....", OK},
- {"....BBB.......|.......bbb....", AT::kErrorBadOverlap},
- {"..BBB.........|.......bbb....", AT::kErrorBadOverlap},
- {".......BBB....|.......bbb....", AT::kErrorBadOverlap},
- //....AAA.......|.....aaa...... The first Unit. NOLINT
- {"....BBB.......|..........bbb.", AT::kErrorBadOverlap},
- {"..........BBB.|.......bbb....", AT::kErrorBadOverlap},
- {"......BBB.....|.....bbb......", AT::kErrorBadOverlap},
- {"......BBB.....|..bbb.........", AT::kErrorBadOverlap},
- {"......BBB.....|bbb...........", AT::kErrorBadOverlap},
- {"BBB...........|bbb...........", OK}, // Disjoint.
- {"........BBB...|.........bbb..", OK}, // Disjoint.
- {"BBB...........|..........bbb.", OK}, // Disjoint, offset elsewhere.
- //....AAA.......|.....aaa...... The first Unit. NOLINT
- {".BBB..........|..bbb.........", OK}, // Tangent.
- {".......BBB....|........bbb...", OK}, // Tangent.
- {".BBB..........|........bbb...", OK}, // Tangent, offset elsewhere.
- {"BBBBBB........|bbb...........", OK}, // Repeat, with extra offsets.
- {"........BBBB..|.........bbb..", OK},
- {"BBBBBB........|..........bbb.", OK},
- {".BBBBBB.......|..bbb.........", OK},
- {".......BBBBB..|........bbb...", OK},
- //....AAA.......|.....aaa...... The first Unit. NOLINT
- {".BBB..........|........bbb...", OK}, // Tangent, offset elsewhere.
- {"..BBB.........|........bbb...", AT::kErrorBadOverlap},
- {"...BB.........|....bb........", OK},
- {"....BB........|.....bb.......", OK},
- {".......BB.....|........bb....", OK},
- {"...BBBBBB.....|....bbbbbb....", OK},
- {"..BBBBBB......|...bbbbbb.....", OK},
- {"......BBBBBB..|.......bbbbbb.", OK},
- //....AAA.......|.....aaa...... The first Unit. NOLINT
- {"BBBBBBBBBBBBBB|bbbbbbbbbbbbbb", AT::kErrorBadOverlap},
- {"B.............|b.............", OK},
- {"B.............|.............b", OK},
- {"....B.........|.....b........", OK},
- {"....B.........|......b.......", AT::kErrorBadOverlap},
- {"....B.........|......b.......", AT::kErrorBadOverlap},
- {"....BBB.......|.....bb.......", OK},
- {"....BBBB......|.....bbb......", OK},
- //....AAA.......|.....aaa...... The first Unit. NOLINT
- {".........BBBBB|.b............", OK},
- {"....AAA.......|.....!........", OK},
- {"....!.........|.....!........", OK}, // Empty units gets deleted early.
- {"....!.........|..........!...", OK}, // Forgiving!
- };
- TwoUnitOverlapTester::RunTest(unit_str1, test_cases);
- }
- TEST(AddressTranslatorTest, OverlapOffsetMultiple) {
- using AT = AddressTranslator;
- // Simple case. Note that RVA ranges don't get merged.
- SimpleTest({"A..|a....", //
- ".A.|..a..", //
- "..A|....a"},
- AT::kSuccess, "Case #0");
- // Offset range 1 overlaps 2 and 3, but truncation takes place to trim down
- // offset ranges, so still successful.
- SimpleTest({"..A|a....", //
- ".AA|..a..", //
- "AAA|....a"},
- AT::kSuccess, "Case #1");
- // Offset range 2 and 3 overlap, so fail.
- SimpleTest({"A..|a....", //
- ".A.|..a..", //
- ".A.|....a"},
- AT::kErrorBadOverlap, "Case #2");
- }
- TEST(AddressTranslatorTest, OverlapDangling) {
- using AT = AddressTranslator;
- constexpr auto OK = AT::kSuccess;
- // First Unit has dangling offsets at
- constexpr const char* unit_str1 = "....AAA.......|.....aaaaaa...";
- std::vector<TwoUnitOverlapTester::TestCase> test_cases = {
- //....AAA.......|.....aaaaaa... The first Unit. NOLINT
- {"....BBB.......|.....bbbbbb...", OK},
- {"....BBB.......|.....bbbbb....", OK},
- {"....BBB.......|.....bbbb.....", OK},
- {"....BBB.......|.....bbb......", OK},
- {".....BBB......|......bbb.....", AT::kErrorBadOverlapDanglingRva},
- {".....BB.......|......bbb.....", OK},
- {"....BBB.......|.....bbbbbbbb.", OK},
- {"..BBBBB.......|...bbbbbbbb...", OK},
- //....AAA.......|.....aaaaaa... The first Unit. NOLINT
- {"......!.......|.bbb..........", AT::kErrorBadOverlap},
- {"..BBBBB.......|...bbbbb......", OK},
- {".......BBB....|.bbb..........", OK}, // Just tangent: Can go elsewhere.
- {".......BBB....|.bbbb.........", OK}, // Can be another dangling RVA.
- {".......!......|.bbbb.........", OK}, // Same with empty.
- {"......!.......|.......!......", OK}, // Okay, but gets deleted.
- {"......!.......|.......b......", AT::kErrorBadOverlapDanglingRva},
- {"......B.......|.......b......", OK},
- //....AAA.......|.....aaaaaa... The first Unit. NOLINT
- {"......BBBB....|.......bbbb...", AT::kErrorBadOverlapDanglingRva},
- {"......BB......|.......bb.....", AT::kErrorBadOverlapDanglingRva},
- {"......BB......|bb............", AT::kErrorBadOverlap},
- };
- TwoUnitOverlapTester::RunTest(unit_str1, test_cases);
- }
- // Tests implementation since algorithm is tricky.
- TEST(AddressTranslatorTest, Merge) {
- using AT = AddressTranslator;
- // Merge a bunch of overlapping Units into one big Unit.
- std::vector<std::string> test_case1 = {
- "AAA.......|.aaa......", // Comment to prevent wrap by formatter.
- "AA........|.aa.......", //
- "..AAA.....|...aaa....", //
- "....A.....|.....a....", //
- ".....AAA..|......aaa.", //
- "........A.|.........a", //
- };
- // Try all 6! permutations.
- std::sort(test_case1.begin(), test_case1.end());
- do {
- TestAddressTranslator translator1;
- EXPECT_EQ(AT::kSuccess, translator1.InitializeWithStrings(test_case1));
- EXPECT_EQ(9U, translator1.fake_offset_begin());
- AT::Unit expected{0U, +9U, 1U, +9U};
- EXPECT_EQ(1U, translator1.units_sorted_by_offset().size());
- EXPECT_EQ(expected, translator1.units_sorted_by_offset()[0]);
- EXPECT_EQ(1U, translator1.units_sorted_by_rva().size());
- EXPECT_EQ(expected, translator1.units_sorted_by_rva()[0]);
- } while (std::next_permutation(test_case1.begin(), test_case1.end()));
- // Merge RVA-adjacent Units into two Units.
- std::vector<std::string> test_case2 = {
- ".....A..|.a......", // First Unit.
- "......A.|..a.....", //
- "A.......|...a....", // Second Unit: RVA-adjacent to first Unit, but
- ".A......|....a...", // offset would become inconsistent, so a new
- "..A.....|.....a..", // Unit gets created.
- };
- // Try all 5! permutations.
- std::sort(test_case2.begin(), test_case2.end());
- do {
- TestAddressTranslator translator2;
- EXPECT_EQ(AT::kSuccess, translator2.InitializeWithStrings(test_case2));
- EXPECT_EQ(7U, translator2.fake_offset_begin());
- AT::Unit expected1{0U, +3U, 3U, +3U};
- AT::Unit expected2{5U, +2U, 1U, +2U};
- EXPECT_EQ(2U, translator2.units_sorted_by_offset().size());
- EXPECT_EQ(expected1, translator2.units_sorted_by_offset()[0]);
- EXPECT_EQ(expected2, translator2.units_sorted_by_offset()[1]);
- EXPECT_EQ(2U, translator2.units_sorted_by_rva().size());
- EXPECT_EQ(expected2, translator2.units_sorted_by_rva()[0]);
- EXPECT_EQ(expected1, translator2.units_sorted_by_rva()[1]);
- } while (std::next_permutation(test_case2.begin(), test_case2.end()));
- }
- TEST(AddressTranslatorTest, RvaToOffsetCache_IsValid) {
- AddressTranslator translator;
- // Notice that the second section has dangling RVA.
- ASSERT_EQ(AddressTranslator::kSuccess,
- translator.Initialize(
- {{0x04, +0x28, 0x1A00, +0x28}, {0x30, +0x10, 0x3A00, +0x30}}));
- AddressTranslator::RvaToOffsetCache rva_checker(translator);
- EXPECT_FALSE(rva_checker.IsValid(kInvalidRva));
- for (int i = 0; i < 0x28; ++i)
- EXPECT_TRUE(rva_checker.IsValid(0x1A00 + i));
- EXPECT_FALSE(rva_checker.IsValid(0x1A00 + 0x28));
- EXPECT_FALSE(rva_checker.IsValid(0x1A00 + 0x29));
- EXPECT_FALSE(rva_checker.IsValid(0x1A00 - 1));
- EXPECT_FALSE(rva_checker.IsValid(0x1A00 - 2));
- for (int i = 0; i < 0x30; ++i)
- EXPECT_TRUE(rva_checker.IsValid(0x3A00 + i));
- EXPECT_FALSE(rva_checker.IsValid(0x3A00 + 0x30));
- EXPECT_FALSE(rva_checker.IsValid(0x3A00 + 0x31));
- EXPECT_FALSE(rva_checker.IsValid(0x3A00 - 1));
- EXPECT_FALSE(rva_checker.IsValid(0x3A00 - 2));
- EXPECT_FALSE(rva_checker.IsValid(0));
- EXPECT_FALSE(rva_checker.IsValid(0x10));
- EXPECT_FALSE(rva_checker.IsValid(0x7FFFFFFFU));
- EXPECT_FALSE(rva_checker.IsValid(0xFFFFFFFFU));
- }
- } // namespace zucchini
|