Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 1 | // Copyright 2017 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/rel32_finder.h" |
| 6 | |
| 7 | #include <stddef.h> |
| 8 | #include <stdint.h> |
| 9 | |
| 10 | #include <algorithm> |
| 11 | #include <iterator> |
| 12 | #include <string> |
| 13 | #include <utility> |
| 14 | #include <vector> |
| 15 | |
Hans Wennborg | 5a340be | 2020-04-28 11:06:24 +0000 | [diff] [blame] | 16 | #include "base/check_op.h" |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 17 | #include "base/format_macros.h" |
Samuel Huang | fa10b05 | 2021-08-05 16:46:38 +0000 | [diff] [blame] | 18 | #include "base/numerics/safe_conversions.h" |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 19 | #include "base/strings/stringprintf.h" |
Samuel Huang | fa10b05 | 2021-08-05 16:46:38 +0000 | [diff] [blame] | 20 | #include "components/zucchini/arm_utils.h" |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 21 | #include "components/zucchini/buffer_view.h" |
Samuel Huang | fa10b05 | 2021-08-05 16:46:38 +0000 | [diff] [blame] | 22 | #include "components/zucchini/disassembler_elf.h" |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 23 | #include "components/zucchini/image_utils.h" |
| 24 | #include "testing/gtest/include/gtest/gtest.h" |
| 25 | |
| 26 | namespace zucchini { |
| 27 | |
| 28 | TEST(Abs32GapFinderTest, All) { |
| 29 | const size_t kRegionTotal = 99; |
| 30 | std::vector<uint8_t> buffer(kRegionTotal); |
| 31 | ConstBufferView image(buffer.data(), buffer.size()); |
| 32 | |
| 33 | // Common test code that returns the resulting segments as a string. |
| 34 | auto run_test = [&](size_t rlo, size_t rhi, |
| 35 | std::vector<offset_t> abs32_locations, |
| 36 | std::ptrdiff_t abs32_width) -> std::string { |
| 37 | CHECK_LE(rlo, kRegionTotal); |
| 38 | CHECK_LE(rhi, kRegionTotal); |
| 39 | CHECK(std::is_sorted(abs32_locations.begin(), abs32_locations.end())); |
| 40 | CHECK_GT(abs32_width, 0); |
| 41 | ConstBufferView region = |
| 42 | ConstBufferView::FromRange(image.begin() + rlo, image.begin() + rhi); |
| 43 | Abs32GapFinder gap_finder(image, region, abs32_locations, abs32_width); |
| 44 | |
| 45 | std::string out_str; |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 46 | while (gap_finder.FindNext()) { |
| 47 | ConstBufferView gap = gap_finder.GetGap(); |
Samuel Huang | fa10b05 | 2021-08-05 16:46:38 +0000 | [diff] [blame] | 48 | size_t lo = base::checked_cast<size_t>(gap.begin() - image.begin()); |
| 49 | size_t hi = base::checked_cast<size_t>(gap.end() - image.begin()); |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 50 | out_str.append(base::StringPrintf("[%" PRIuS ",%" PRIuS ")", lo, hi)); |
| 51 | } |
| 52 | return out_str; |
| 53 | }; |
| 54 | |
| 55 | // Empty regions yield empty segments. |
Samuel Huang | fa10b05 | 2021-08-05 16:46:38 +0000 | [diff] [blame] | 56 | EXPECT_EQ("", run_test(0, 0, {}, 4)); |
| 57 | EXPECT_EQ("", run_test(9, 9, {}, 4)); |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 58 | EXPECT_EQ("", run_test(8, 8, {8}, 4)); |
| 59 | EXPECT_EQ("", run_test(8, 8, {0, 12}, 4)); |
| 60 | |
| 61 | // If no abs32 locations exist then the segment is the main range. |
Samuel Huang | fa10b05 | 2021-08-05 16:46:38 +0000 | [diff] [blame] | 62 | EXPECT_EQ("[0,99)", run_test(0, 99, {}, 4)); |
| 63 | EXPECT_EQ("[20,21)", run_test(20, 21, {}, 4)); |
| 64 | EXPECT_EQ("[51,55)", run_test(51, 55, {}, 4)); |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 65 | |
| 66 | // abs32 locations found near start of main range. |
| 67 | EXPECT_EQ("[10,20)", run_test(10, 20, {5}, 4)); |
| 68 | EXPECT_EQ("[10,20)", run_test(10, 20, {6}, 4)); |
| 69 | EXPECT_EQ("[11,20)", run_test(10, 20, {7}, 4)); |
| 70 | EXPECT_EQ("[12,20)", run_test(10, 20, {8}, 4)); |
| 71 | EXPECT_EQ("[13,20)", run_test(10, 20, {9}, 4)); |
| 72 | EXPECT_EQ("[14,20)", run_test(10, 20, {10}, 4)); |
| 73 | EXPECT_EQ("[10,11)[15,20)", run_test(10, 20, {11}, 4)); |
| 74 | |
| 75 | // abs32 locations found near end of main range. |
| 76 | EXPECT_EQ("[10,15)[19,20)", run_test(10, 20, {15}, 4)); |
| 77 | EXPECT_EQ("[10,16)", run_test(10, 20, {16}, 4)); |
| 78 | EXPECT_EQ("[10,17)", run_test(10, 20, {17}, 4)); |
| 79 | EXPECT_EQ("[10,18)", run_test(10, 20, {18}, 4)); |
| 80 | EXPECT_EQ("[10,19)", run_test(10, 20, {19}, 4)); |
| 81 | EXPECT_EQ("[10,20)", run_test(10, 20, {20}, 4)); |
| 82 | EXPECT_EQ("[10,20)", run_test(10, 20, {21}, 4)); |
| 83 | |
| 84 | // Main range completely eclipsed by abs32 location. |
| 85 | EXPECT_EQ("", run_test(10, 11, {7}, 4)); |
| 86 | EXPECT_EQ("", run_test(10, 11, {8}, 4)); |
| 87 | EXPECT_EQ("", run_test(10, 11, {9}, 4)); |
| 88 | EXPECT_EQ("", run_test(10, 11, {10}, 4)); |
| 89 | EXPECT_EQ("", run_test(10, 12, {8}, 4)); |
| 90 | EXPECT_EQ("", run_test(10, 12, {9}, 4)); |
| 91 | EXPECT_EQ("", run_test(10, 12, {10}, 4)); |
| 92 | EXPECT_EQ("", run_test(10, 13, {9}, 4)); |
| 93 | EXPECT_EQ("", run_test(10, 13, {10}, 4)); |
| 94 | EXPECT_EQ("", run_test(10, 14, {10}, 4)); |
| 95 | EXPECT_EQ("", run_test(10, 14, {8, 12}, 4)); |
| 96 | |
| 97 | // Partial eclipses. |
| 98 | EXPECT_EQ("[24,25)", run_test(20, 25, {20}, 4)); |
| 99 | EXPECT_EQ("[20,21)", run_test(20, 25, {21}, 4)); |
| 100 | EXPECT_EQ("[20,21)[25,26)", run_test(20, 26, {21}, 4)); |
| 101 | |
| 102 | // abs32 location outside main range. |
| 103 | EXPECT_EQ("[40,60)", run_test(40, 60, {36, 60}, 4)); |
| 104 | EXPECT_EQ("[41,61)", run_test(41, 61, {0, 10, 20, 30, 34, 62, 68, 80}, 4)); |
| 105 | |
| 106 | // Change abs32 width. |
| 107 | EXPECT_EQ("[10,11)[12,14)[16,19)", run_test(10, 20, {9, 11, 14, 15, 19}, 1)); |
| 108 | EXPECT_EQ("", run_test(10, 11, {10}, 1)); |
| 109 | EXPECT_EQ("[18,23)[29,31)", run_test(17, 31, {15, 23, 26, 31}, 3)); |
| 110 | EXPECT_EQ("[17,22)[25,26)[29,30)", run_test(17, 31, {14, 22, 26, 30}, 3)); |
| 111 | EXPECT_EQ("[10,11)[19,20)", run_test(10, 20, {11}, 8)); |
| 112 | |
| 113 | // Mixed cases with abs32 width = 4. |
| 114 | EXPECT_EQ("[10,15)[19,20)[24,25)", run_test(8, 25, {2, 6, 15, 20, 27}, 4)); |
| 115 | EXPECT_EQ("[0,25)[29,45)[49,50)", run_test(0, 50, {25, 45}, 4)); |
| 116 | EXPECT_EQ("[10,20)[28,50)", run_test(10, 50, {20, 24}, 4)); |
| 117 | EXPECT_EQ("[49,50)[54,60)[64,70)[74,80)[84,87)", |
| 118 | run_test(49, 87, {10, 20, 30, 40, 50, 60, 70, 80, 90}, 4)); |
| 119 | EXPECT_EQ("[0,10)[14,20)[24,25)[29,50)", run_test(0, 50, {10, 20, 25}, 4)); |
| 120 | } |
| 121 | |
| 122 | namespace { |
| 123 | |
| 124 | // A mock Rel32Finder to inject next search result on Scan(). |
| 125 | class TestRel32Finder : public Rel32Finder { |
| 126 | public: |
| 127 | using Rel32Finder::Rel32Finder; |
| 128 | |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 129 | // Rel32Finder: |
Samuel Huang | 0047fda | 2019-03-21 20:40:55 +0000 | [diff] [blame] | 130 | NextIterators Scan(ConstBufferView region) override { return next_result; } |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 131 | |
Samuel Huang | 0047fda | 2019-03-21 20:40:55 +0000 | [diff] [blame] | 132 | NextIterators next_result; |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 133 | }; |
| 134 | |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 135 | AddressTranslator GetTrivialTranslator(size_t size) { |
| 136 | AddressTranslator translator; |
| 137 | EXPECT_EQ(AddressTranslator::kSuccess, |
Samuel Huang | fa10b05 | 2021-08-05 16:46:38 +0000 | [diff] [blame] | 138 | translator.Initialize({{0, base::checked_cast<offset_t>(size), 0U, |
| 139 | base::checked_cast<rva_t>(size)}})); |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 140 | return translator; |
| 141 | } |
| 142 | |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 143 | } // namespace |
| 144 | |
| 145 | TEST(Rel32FinderTest, Scan) { |
| 146 | const size_t kRegionTotal = 99; |
| 147 | std::vector<uint8_t> buffer(kRegionTotal); |
| 148 | ConstBufferView image(buffer.data(), buffer.size()); |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 149 | AddressTranslator translator(GetTrivialTranslator(image.size())); |
| 150 | TestRel32Finder finder(image, translator); |
Samuel Huang | 0047fda | 2019-03-21 20:40:55 +0000 | [diff] [blame] | 151 | finder.SetRegion(image); |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 152 | |
| 153 | auto check_finder_state = [&](const TestRel32Finder& finder, |
| 154 | size_t expected_cursor, |
Samuel Huang | 0047fda | 2019-03-21 20:40:55 +0000 | [diff] [blame] | 155 | size_t expected_accept_it) { |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 156 | CHECK_LE(expected_cursor, kRegionTotal); |
Samuel Huang | 0047fda | 2019-03-21 20:40:55 +0000 | [diff] [blame] | 157 | CHECK_LE(expected_accept_it, kRegionTotal); |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 158 | |
| 159 | EXPECT_EQ(image.begin() + expected_cursor, finder.region().begin()); |
Samuel Huang | 0047fda | 2019-03-21 20:40:55 +0000 | [diff] [blame] | 160 | EXPECT_EQ(image.begin() + expected_accept_it, finder.accept_it()); |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 161 | }; |
| 162 | |
| 163 | check_finder_state(finder, 0, 0); |
| 164 | |
Samuel Huang | 0047fda | 2019-03-21 20:40:55 +0000 | [diff] [blame] | 165 | finder.next_result = {image.begin() + 1, image.begin() + 1}; |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 166 | EXPECT_TRUE(finder.FindNext()); |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 167 | check_finder_state(finder, 1, 1); |
| 168 | |
Samuel Huang | 0047fda | 2019-03-21 20:40:55 +0000 | [diff] [blame] | 169 | finder.next_result = {image.begin() + 2, image.begin() + 2}; |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 170 | EXPECT_TRUE(finder.FindNext()); |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 171 | check_finder_state(finder, 2, 2); |
| 172 | |
Samuel Huang | 0047fda | 2019-03-21 20:40:55 +0000 | [diff] [blame] | 173 | finder.next_result = {image.begin() + 5, image.begin() + 6}; |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 174 | EXPECT_TRUE(finder.FindNext()); |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 175 | check_finder_state(finder, 5, 6); |
| 176 | finder.Accept(); |
| 177 | check_finder_state(finder, 6, 6); |
| 178 | |
Samuel Huang | 0047fda | 2019-03-21 20:40:55 +0000 | [diff] [blame] | 179 | finder.next_result = {image.begin() + 7, image.begin() + 7}; |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 180 | EXPECT_TRUE(finder.FindNext()); |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 181 | check_finder_state(finder, 7, 7); |
| 182 | |
Samuel Huang | 0047fda | 2019-03-21 20:40:55 +0000 | [diff] [blame] | 183 | finder.next_result = {image.begin() + 8, image.begin() + 8}; |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 184 | EXPECT_TRUE(finder.FindNext()); |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 185 | check_finder_state(finder, 8, 8); |
| 186 | |
Samuel Huang | 0047fda | 2019-03-21 20:40:55 +0000 | [diff] [blame] | 187 | finder.next_result = {image.begin() + 99, image.begin() + 99}; |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 188 | EXPECT_TRUE(finder.FindNext()); |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 189 | check_finder_state(finder, 99, 99); |
| 190 | |
Samuel Huang | 0047fda | 2019-03-21 20:40:55 +0000 | [diff] [blame] | 191 | finder.next_result = {nullptr, nullptr}; |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 192 | EXPECT_FALSE(finder.FindNext()); |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 193 | check_finder_state(finder, 99, 99); |
| 194 | } |
| 195 | |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 196 | namespace { |
| 197 | |
| 198 | // X86 test data. (x) and +x entries are covered by abs32 references, which have |
| 199 | // width = 4. |
| 200 | constexpr uint8_t kDataX86[] = { |
| 201 | 0x55, // 00: push ebp |
| 202 | 0x8B, 0xEC, // 01: mov ebp,esp |
| 203 | 0xE8, 0, 0, 0, 0, // 03: call 08 |
| 204 | (0xE9), +0, +0, +0, 0, // 08: jmp 0D |
| 205 | 0x0F, 0x80, 0, 0, 0, 0, // 0D: jo 13 |
| 206 | 0x0F, 0x81, 0, 0, (0), +0, // 13: jno 19 |
| 207 | +0x0F, +0x82, 0, 0, 0, 0, // 19: jb 1F |
| 208 | 0x0F, 0x83, 0, 0, 0, 0, // 1F: jae 25 |
| 209 | 0x0F, (0x84), +0, +0, +0, (0), // 25: je 2B |
| 210 | +0x0F, +0x85, +0, 0, 0, 0, // 2B: jne 31 |
| 211 | 0x0F, 0x86, 0, 0, 0, 0, // 31: jbe 37 |
| 212 | 0x0F, 0x87, 0, 0, 0, 0, // 37: ja 3D |
| 213 | 0x0F, 0x88, 0, (0), +0, +0, // 3D: js 43 |
| 214 | +0x0F, 0x89, 0, 0, 0, 0, // 43: jns 49 |
| 215 | 0x0F, 0x8A, 0, 0, 0, 0, // 49: jp 4F |
| 216 | 0x0F, 0x8B, (0), +0, +0, +0, // 4F: jnp 55 |
| 217 | 0x0F, 0x8C, 0, 0, 0, 0, // 55: jl 5B |
| 218 | 0x0F, 0x8D, 0, 0, (0), +0, // 5B: jge 61 |
| 219 | +0x0F, +0x8E, (0), +0, +0, +0, // 61: jle 67 |
| 220 | 0x0F, 0x8F, 0, 0, 0, 0, // 67: jg 6D |
| 221 | 0x5D, // 6D: pop ebp |
| 222 | 0xC3, // C3: ret |
| 223 | }; |
| 224 | |
| 225 | // Abs32 locations corresponding to |kDataX86|, with width = 4. |
Samuel Huang | fa10b05 | 2021-08-05 16:46:38 +0000 | [diff] [blame] | 226 | constexpr offset_t kAbs32X86[] = {0x08, 0x17, 0x26, 0x2A, |
| 227 | 0x40, 0x51, 0x5F, 0x63}; |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 228 | |
| 229 | } // namespace |
| 230 | |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 231 | TEST(Rel32FinderX86Test, FindNext) { |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 232 | ConstBufferView image = |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 233 | ConstBufferView::FromRange(std::begin(kDataX86), std::end(kDataX86)); |
| 234 | AddressTranslator translator(GetTrivialTranslator(image.size())); |
| 235 | Rel32FinderX86 rel_finder(image, translator); |
Samuel Huang | 0047fda | 2019-03-21 20:40:55 +0000 | [diff] [blame] | 236 | rel_finder.SetRegion(image); |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 237 | |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 238 | // List of expected locations as pairs of {cursor offset, rel32 offset}, |
| 239 | // ignoring |kAbs32X86|. |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 240 | std::vector<std::pair<size_t, size_t>> expected_locations = { |
| 241 | {0x04, 0x04}, {0x09, 0x09}, {0x0E, 0x0F}, {0x14, 0x15}, {0x1A, 0x1B}, |
| 242 | {0x20, 0x21}, {0x26, 0x27}, {0x2C, 0x2D}, {0x32, 0x33}, {0x38, 0x39}, |
| 243 | {0x3E, 0x3F}, {0x44, 0x45}, {0x4A, 0x4B}, {0x50, 0x51}, {0x56, 0x57}, |
| 244 | {0x5C, 0x5D}, {0x62, 0x63}, {0x68, 0x69}, |
| 245 | }; |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 246 | for (auto location : expected_locations) { |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 247 | EXPECT_TRUE(rel_finder.FindNext()); |
| 248 | auto rel32 = rel_finder.GetRel32(); |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 249 | |
| 250 | EXPECT_EQ(location.first, |
| 251 | size_t(rel_finder.region().begin() - image.begin())); |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 252 | EXPECT_EQ(location.second, rel32.location); |
| 253 | EXPECT_EQ(image.begin() + (rel32.location + 4), rel_finder.accept_it()); |
| 254 | EXPECT_FALSE(rel32.can_point_outside_section); |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 255 | rel_finder.Accept(); |
| 256 | } |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 257 | EXPECT_FALSE(rel_finder.FindNext()); |
| 258 | } |
| 259 | |
| 260 | TEST(Rel32FinderX86Test, Integrated) { |
| 261 | // Truncated form of Rel32FinderIntel::Result. |
Samuel Huang | fa10b05 | 2021-08-05 16:46:38 +0000 | [diff] [blame] | 262 | using TruncatedResults = std::pair<offset_t, rva_t>; |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 263 | |
| 264 | ConstBufferView image = |
| 265 | ConstBufferView::FromRange(std::begin(kDataX86), std::end(kDataX86)); |
| 266 | std::vector<offset_t> abs32_locations(std::begin(kAbs32X86), |
| 267 | std::end(kAbs32X86)); |
Samuel Huang | fa10b05 | 2021-08-05 16:46:38 +0000 | [diff] [blame] | 268 | std::vector<TruncatedResults> results; |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 269 | |
Samuel Huang | fa10b05 | 2021-08-05 16:46:38 +0000 | [diff] [blame] | 270 | Abs32GapFinder gap_finder(image, image, abs32_locations, |
| 271 | DisassemblerElfX86::Traits::kVAWidth); |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 272 | AddressTranslator translator(GetTrivialTranslator(image.size())); |
| 273 | Rel32FinderX86 rel_finder(image, translator); |
| 274 | while (gap_finder.FindNext()) { |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 275 | rel_finder.SetRegion(gap_finder.GetGap()); |
| 276 | while (rel_finder.FindNext()) { |
| 277 | auto rel32 = rel_finder.GetRel32(); |
Samuel Huang | fa10b05 | 2021-08-05 16:46:38 +0000 | [diff] [blame] | 278 | rel_finder.Accept(); |
| 279 | results.emplace_back(TruncatedResults{rel32.location, rel32.target_rva}); |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 280 | } |
| 281 | } |
| 282 | |
Samuel Huang | fa10b05 | 2021-08-05 16:46:38 +0000 | [diff] [blame] | 283 | std::vector<TruncatedResults> expected_results = { |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 284 | {0x04, 0x08}, |
| 285 | /* {0x09, 0x0D}, */ {0x0F, 0x13}, |
| 286 | /* {0x15, 0x19}, */ /*{0x1B, 0x1F}, */ |
| 287 | {0x21, 0x25}, |
| 288 | /* {0x27, 0x2B}, */ /* {0x2D, 0x31}, */ {0x33, 0x37}, |
| 289 | {0x39, 0x3D}, |
| 290 | /* {0x3F, 0x43}, */ /* {0x45, 0x49}, */ {0x4B, 0x4F}, |
| 291 | /* {0x51, 0x55}, */ {0x57, 0x5B}, |
| 292 | /* {0x5D, 0x61}, */ /* {0x63, 0x67}, */ {0x69, 0x6D}, |
| 293 | }; |
Samuel Huang | fa10b05 | 2021-08-05 16:46:38 +0000 | [diff] [blame] | 294 | EXPECT_EQ(expected_results, results); |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 295 | } |
| 296 | |
| 297 | TEST(Rel32FinderX86Test, Accept) { |
| 298 | constexpr uint8_t data[] = { |
| 299 | 0xB9, 0x00, 0x00, 0x00, 0xE9, // 00: mov E9000000 |
| 300 | 0xE8, 0x00, 0x00, 0x00, 0xE9, // 05: call E900000A |
| 301 | 0xE8, 0x00, 0x00, 0x00, 0xE9, // 0A: call E900000F |
| 302 | }; |
| 303 | |
| 304 | ConstBufferView image = |
| 305 | ConstBufferView::FromRange(std::begin(data), std::end(data)); |
| 306 | |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 307 | auto next_location = [](Rel32FinderX86& rel_finder) -> offset_t { |
| 308 | EXPECT_TRUE(rel_finder.FindNext()); |
| 309 | auto rel32 = rel_finder.GetRel32(); |
| 310 | return rel32.location; |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 311 | }; |
| 312 | |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 313 | AddressTranslator translator(GetTrivialTranslator(image.size())); |
| 314 | Rel32FinderX86 rel_finder(image, translator); |
Samuel Huang | 0047fda | 2019-03-21 20:40:55 +0000 | [diff] [blame] | 315 | rel_finder.SetRegion(image); |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 316 | |
Samuel Huang | 0047fda | 2019-03-21 20:40:55 +0000 | [diff] [blame] | 317 | EXPECT_EQ(0x05U, next_location(rel_finder)); // False positive. |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 318 | rel_finder.Accept(); |
| 319 | // False negative: shadowed by 0x05 |
| 320 | // EXPECT_EQ(0x06, next_location(rel_finder)); |
Samuel Huang | 0047fda | 2019-03-21 20:40:55 +0000 | [diff] [blame] | 321 | EXPECT_EQ(0x0AU, next_location(rel_finder)); // False positive. |
| 322 | EXPECT_EQ(0x0BU, next_location(rel_finder)); // Found if 0x0A is discarded. |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 323 | } |
| 324 | |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 325 | namespace { |
| 326 | |
| 327 | // X64 test data. (x) and +x entries are covered by abs32 references, which have |
| 328 | // width = 8. |
| 329 | constexpr uint8_t kDataX64[] = { |
| 330 | 0x55, // 00: push ebp |
| 331 | 0x8B, 0xEC, // 01: mov ebp,esp |
| 332 | 0xE8, 0, 0, 0, 0, // 03: call 08 |
| 333 | 0xE9, 0, 0, 0, (0), // 08: jmp 0D |
| 334 | +0x0F, +0x80, +0, +0, +0, +0, // 0D: jo 13 |
| 335 | +0x0F, 0x81, 0, 0, 0, 0, // 13: jno 19 |
| 336 | 0x0F, 0x82, 0, 0, 0, 0, // 19: jb 1F |
| 337 | (0x0F), +0x83, +0, +0, +0, +0, // 1F: jae 25 |
| 338 | +0x0F, +0x84, 0, 0, 0, 0, // 25: je 2B |
| 339 | 0x0F, 0x85, 0, 0, 0, 0, // 2B: jne 31 |
| 340 | 0x0F, 0x86, (0), +0, +0, +0, // 31: jbe 37 |
| 341 | +0x0F, +0x87, +0, +0, (0), +0, // 37: ja 3D |
| 342 | +0x0F, +0x88, +0, +0, +0, +0, // 3D: js 43 |
| 343 | 0x0F, 0x89, 0, 0, 0, 0, // 43: jns 49 |
| 344 | (0x0F), +0x8A, +0, +0, +0, +0, // 49: jp 4F |
| 345 | +0x0F, +0x8B, 0, 0, 0, 0, // 4F: jnp 55 |
| 346 | 0x0F, 0x8C, 0, 0, 0, 0, // 55: jl 5B |
| 347 | 0x0F, 0x8D, 0, 0, 0, 0, // 5B: jge 61 |
| 348 | 0x0F, 0x8E, 0, 0, 0, 0, // 61: jle 67 |
| 349 | 0x0F, 0x8F, 0, (0), +0, +0, // 67: jg 6F |
| 350 | +0xFF, +0x15, +0, +0, +0, 0, // 6D: call [rip+00] # 73 |
| 351 | 0xFF, 0x25, 0, 0, 0, 0, // 73: jmp [rip+00] # 79 |
| 352 | 0x8B, 0x05, 0, 0, 0, 0, // 79: mov eax,[rip+00] # 7F |
| 353 | 0x8B, 0x3D, 0, 0, 0, 0, // 7F: mov edi,[rip+00] # 85 |
| 354 | 0x8D, 0x05, 0, 0, 0, 0, // 85: lea eax,[rip+00] # 8B |
| 355 | 0x8D, 0x3D, 0, 0, 0, 0, // 8B: lea edi,[rip+00] # 91 |
| 356 | 0x48, 0x8B, 0x05, 0, 0, 0, 0, // 91: mov rax,[rip+00] # 98 |
| 357 | 0x48, (0x8B), +0x3D, +0, +0, +0, +0, // 98: mov rdi,[rip+00] # 9F |
| 358 | +0x48, +0x8D, 0x05, 0, 0, 0, 0, // 9F: lea rax,[rip+00] # A6 |
| 359 | 0x48, 0x8D, 0x3D, 0, 0, 0, 0, // A6: lea rdi,[rip+00] # AD |
| 360 | 0x4C, 0x8B, 0x05, 0, 0, 0, (0), // AD: mov r8,[rip+00] # B4 |
| 361 | +0x4C, +0x8B, +0x3D, +0, +0, +0, +0, // B4: mov r15,[rip+00] # BB |
| 362 | 0x4C, 0x8D, 0x05, 0, 0, 0, 0, // BB: lea r8,[rip+00] # C2 |
| 363 | 0x4C, 0x8D, 0x3D, 0, 0, 0, 0, // C2: lea r15,[rip+00] # C9 |
| 364 | 0x66, 0x8B, 0x05, (0), +0, +0, +0, // C9: mov ax,[rip+00] # D0 |
| 365 | +0x66, +0x8B, +0x3D, +0, 0, 0, 0, // D0: mov di,[rip+00] # D7 |
| 366 | 0x66, 0x8D, 0x05, 0, 0, 0, 0, // D7: lea ax,[rip+00] # DE |
| 367 | 0x66, 0x8D, 0x3D, 0, 0, 0, 0, // DE: lea di,[rip+00] # E5 |
| 368 | 0x5D, // E5: pop ebp |
| 369 | 0xC3, // E6: ret |
| 370 | }; |
| 371 | |
| 372 | // Abs32 locations corresponding to |kDataX64|, with width = 8. |
Samuel Huang | fa10b05 | 2021-08-05 16:46:38 +0000 | [diff] [blame] | 373 | constexpr offset_t kAbs32X64[] = {0x0C, 0x1F, 0x33, 0x3B, 0x49, |
| 374 | 0x6A, 0x99, 0xB3, 0xCC}; |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 375 | |
| 376 | } // namespace |
| 377 | |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 378 | TEST(Rel32FinderX64Test, FindNext) { |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 379 | ConstBufferView image = |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 380 | ConstBufferView::FromRange(std::begin(kDataX64), std::end(kDataX64)); |
| 381 | AddressTranslator translator(GetTrivialTranslator(image.size())); |
| 382 | Rel32FinderX64 rel_finder(image, translator); |
Samuel Huang | 0047fda | 2019-03-21 20:40:55 +0000 | [diff] [blame] | 383 | rel_finder.SetRegion(image); |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 384 | |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 385 | // Lists of expected locations as pairs of {cursor offset, rel32 offset}, |
| 386 | // ignoring |kAbs32X64|. |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 387 | std::vector<std::pair<size_t, size_t>> expected_locations = { |
| 388 | {0x04, 0x04}, {0x09, 0x09}, {0x0E, 0x0F}, {0x14, 0x15}, {0x1A, 0x1B}, |
| 389 | {0x20, 0x21}, {0x26, 0x27}, {0x2C, 0x2D}, {0x32, 0x33}, {0x38, 0x39}, |
| 390 | {0x3E, 0x3F}, {0x44, 0x45}, {0x4A, 0x4B}, {0x50, 0x51}, {0x56, 0x57}, |
| 391 | {0x5C, 0x5D}, {0x62, 0x63}, {0x68, 0x69}, |
| 392 | }; |
| 393 | std::vector<std::pair<size_t, size_t>> expected_locations_rip = { |
| 394 | {0x6E, 0x6F}, {0x74, 0x75}, {0x7A, 0x7B}, {0x80, 0x81}, {0x86, 0x87}, |
| 395 | {0x8C, 0x8D}, {0x93, 0x94}, {0x9A, 0x9B}, {0xA1, 0xA2}, {0xA8, 0xA9}, |
| 396 | {0xAF, 0xB0}, {0xB6, 0xB7}, {0xBD, 0xBE}, {0xC4, 0xC5}, {0xCB, 0xCC}, |
| 397 | {0xD2, 0xD3}, {0xD9, 0xDA}, {0xE0, 0xE1}, |
| 398 | }; |
Samuel Huang | 0047fda | 2019-03-21 20:40:55 +0000 | [diff] [blame] | 399 | // Jump instructions, which cannot point outside section. |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 400 | for (auto location : expected_locations) { |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 401 | EXPECT_TRUE(rel_finder.FindNext()); |
| 402 | auto rel32 = rel_finder.GetRel32(); |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 403 | EXPECT_EQ(location.first, |
| 404 | size_t(rel_finder.region().begin() - image.begin())); |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 405 | EXPECT_EQ(location.second, rel32.location); |
| 406 | EXPECT_EQ(image.begin() + (rel32.location + 4), rel_finder.accept_it()); |
| 407 | EXPECT_FALSE(rel32.can_point_outside_section); |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 408 | rel_finder.Accept(); |
| 409 | } |
Samuel Huang | 0047fda | 2019-03-21 20:40:55 +0000 | [diff] [blame] | 410 | // PC-relative data access instructions, which can point outside section. |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 411 | for (auto location : expected_locations_rip) { |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 412 | EXPECT_TRUE(rel_finder.FindNext()); |
| 413 | auto rel32 = rel_finder.GetRel32(); |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 414 | EXPECT_EQ(location.first, |
| 415 | size_t(rel_finder.region().begin() - image.begin())); |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 416 | EXPECT_EQ(location.second, rel32.location); |
| 417 | EXPECT_EQ(image.begin() + (rel32.location + 4), rel_finder.accept_it()); |
| 418 | EXPECT_TRUE(rel32.can_point_outside_section); // Different from before. |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 419 | rel_finder.Accept(); |
| 420 | } |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 421 | EXPECT_FALSE(rel_finder.FindNext()); |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 422 | } |
| 423 | |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 424 | TEST(Rel32FinderX64Test, Integrated) { |
| 425 | // Truncated form of Rel32FinderIntel::Result. |
Samuel Huang | fa10b05 | 2021-08-05 16:46:38 +0000 | [diff] [blame] | 426 | using TruncatedResults = std::pair<offset_t, rva_t>; |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 427 | |
| 428 | ConstBufferView image = |
| 429 | ConstBufferView::FromRange(std::begin(kDataX64), std::end(kDataX64)); |
| 430 | std::vector<offset_t> abs32_locations(std::begin(kAbs32X64), |
| 431 | std::end(kAbs32X64)); |
Samuel Huang | fa10b05 | 2021-08-05 16:46:38 +0000 | [diff] [blame] | 432 | std::vector<TruncatedResults> results; |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 433 | |
Samuel Huang | fa10b05 | 2021-08-05 16:46:38 +0000 | [diff] [blame] | 434 | Abs32GapFinder gap_finder(image, image, abs32_locations, |
| 435 | DisassemblerElfX64::Traits::kVAWidth); |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 436 | AddressTranslator translator(GetTrivialTranslator(image.size())); |
| 437 | Rel32FinderX64 rel_finder(image, translator); |
| 438 | while (gap_finder.FindNext()) { |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 439 | rel_finder.SetRegion(gap_finder.GetGap()); |
| 440 | while (rel_finder.FindNext()) { |
| 441 | auto rel32 = rel_finder.GetRel32(); |
Samuel Huang | fa10b05 | 2021-08-05 16:46:38 +0000 | [diff] [blame] | 442 | rel_finder.Accept(); |
| 443 | results.emplace_back(TruncatedResults{rel32.location, rel32.target_rva}); |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 444 | } |
| 445 | } |
| 446 | |
Samuel Huang | fa10b05 | 2021-08-05 16:46:38 +0000 | [diff] [blame] | 447 | std::vector<TruncatedResults> expected_results = { |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 448 | {0x04, 0x08}, |
| 449 | /* {0x09, 0x0D}, */ |
Samuel Huang | fa10b05 | 2021-08-05 16:46:38 +0000 | [diff] [blame] | 450 | /* {0x0F, 0x13}, */ /* {0x15, 0x19}, */ {0x1B, 0x1F}, |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 451 | /* {0x21, 0x25}, */ /* {0x27, 0x2B}, */ {0x2D, 0x31}, |
| 452 | /* {0x33, 0x37}, */ /* {0x39, 0x3D}, */ |
| 453 | /* {0x3F, 0x43}, */ {0x45, 0x49}, |
| 454 | /* {0x4B, 0x4F}, */ /* {0x51, 0x55}, */ |
| 455 | {0x57, 0x5B}, |
| 456 | {0x5D, 0x61}, |
| 457 | {0x63, 0x67}, /* {0x69, 0x6F}, */ |
| 458 | /* {0x6F, 0x73}, */ {0x75, 0x79}, |
| 459 | {0x7B, 0x7F}, |
| 460 | {0x81, 0x85}, |
| 461 | {0x87, 0x8B}, |
| 462 | {0x8D, 0x91}, |
| 463 | {0x94, 0x98}, |
| 464 | /* {0x9B, 0x9F}, */ /* {0xA2, 0xA6}, */ {0xA9, 0xAD}, |
| 465 | /* {0xB0, 0xB4}, */ /* {0xB7, 0xBB}, */ {0xBE, 0xC2}, |
| 466 | {0xC5, 0xC9}, |
| 467 | /* {0xCC, 0xD0}, */ /* {0xD3, 0xD7}, */ {0xDA, 0xDE}, |
| 468 | {0xE1, 0xE5}, |
| 469 | }; |
Samuel Huang | fa10b05 | 2021-08-05 16:46:38 +0000 | [diff] [blame] | 470 | EXPECT_EQ(expected_results, results); |
| 471 | } |
| 472 | |
| 473 | namespace { |
| 474 | |
| 475 | // Runs the ARM rel32 extraction (nested) loop on |image| using |rel32_finder|, |
| 476 | // given |abs32_locations| for abs32 references each having |abs32_width|. |
| 477 | // Returns the list of extracted references. |
| 478 | template <class REL32_FINDER> |
| 479 | std::vector<typename REL32_FINDER::Result> ArmExtractRel32( |
| 480 | ConstBufferView image, |
| 481 | const std::vector<offset_t>& abs32_locations, |
| 482 | int abs32_width, |
| 483 | REL32_FINDER&& rel32_finder) { |
| 484 | std::vector<typename REL32_FINDER::Result> results; |
| 485 | Abs32GapFinder gap_finder(image, image, abs32_locations, abs32_width); |
| 486 | while (gap_finder.FindNext()) { |
| 487 | rel32_finder.SetRegion(gap_finder.GetGap()); |
| 488 | while (rel32_finder.FindNext()) { |
| 489 | typename REL32_FINDER::Result rel32 = rel32_finder.GetRel32(); |
| 490 | rel32_finder.Accept(); |
| 491 | results.emplace_back(rel32); |
| 492 | } |
| 493 | } |
| 494 | return results; |
| 495 | } |
| 496 | |
| 497 | } // namespace |
| 498 | |
| 499 | namespace { |
| 500 | |
| 501 | // AArch32 ARM mode test data. (x) and +x entries are covered by abs32 |
| 502 | // references (if used), which have width = 4. |
| 503 | constexpr uint8_t kDataAarch32ArmMode[] = { |
| 504 | 0x00, 0x01, 0x02, 0xEA, // 00: B 00080408 ; B encoding A1 |
| 505 | 0x00, 0x01, (0x02), +0xEA, // 04: B 0008040C ; B encoding A1 |
| 506 | +0x00, +0x01, 0x02, 0xEA, // 08: B 00080410 ; B encoding A1 |
| 507 | 0x00, 0x01, 0x02, 0xEA, // 0C: B 00080414 ; B encoding A1 |
| 508 | 0x00, 0x01, 0x02, (0xEA), // 10: B 00080418 ; B encoding A1 |
| 509 | +0x00, +0x01, +0x02, 0xEA, // 14: B 0008041C ; B encoding A1 |
| 510 | 0x00, 0x01, 0x02, 0xEA, // 18: B 00080420 ; B encoding A1 |
| 511 | }; |
| 512 | |
| 513 | // Abs32 locations corresponding to |kDataAarch32ArmMode|, with width = 4. |
| 514 | constexpr offset_t kAbs32Aarch32ArmMode[] = {0x6, 0x13}; |
| 515 | |
| 516 | } // namespace |
| 517 | |
| 518 | TEST(Rel32FinderAArch32Test, IntegratedArmModeWithoutAbs32) { |
| 519 | using AddrType = AArch32Rel32Translator::AddrType; |
| 520 | using Result = Rel32FinderAArch32::Result; |
| 521 | std::vector<Result> expected_results = { |
| 522 | {0x00, 0x80408, AddrType::ADDR_A24}, {0x04, 0x8040C, AddrType::ADDR_A24}, |
| 523 | {0x08, 0x80410, AddrType::ADDR_A24}, {0x0C, 0x80414, AddrType::ADDR_A24}, |
| 524 | {0x10, 0x80418, AddrType::ADDR_A24}, {0x14, 0x8041C, AddrType::ADDR_A24}, |
| 525 | {0x18, 0x80420, AddrType::ADDR_A24}, |
| 526 | }; |
| 527 | |
| 528 | ConstBufferView image = ConstBufferView::FromRange( |
| 529 | std::begin(kDataAarch32ArmMode), std::end(kDataAarch32ArmMode)); |
| 530 | AddressTranslator translator(GetTrivialTranslator(image.size())); |
| 531 | Rel32FinderAArch32 rel32_finder(image, translator, /* is_thumb2 */ false); |
| 532 | |
| 533 | std::vector<Result> results = ArmExtractRel32( |
| 534 | image, /* abs32_locations */ {}, DisassemblerElfAArch32::Traits::kVAWidth, |
| 535 | std::move(rel32_finder)); |
| 536 | |
| 537 | EXPECT_EQ(expected_results, results); |
| 538 | } |
| 539 | |
| 540 | TEST(Rel32FinderAArch32Test, IntegratedArmModeWithAbs32) { |
| 541 | using AddrType = AArch32Rel32Translator::AddrType; |
| 542 | using Result = Rel32FinderAArch32::Result; |
| 543 | std::vector<Result> expected_results = { |
| 544 | {0x00, 0x80408, AddrType::ADDR_A24}, |
| 545 | /* {0x04, 0x8040C, AddrType::ADDR_A24}, */ |
| 546 | /* {0x08, 0x80410, AddrType::ADDR_A24}, */ |
| 547 | {0x0C, 0x80414, AddrType::ADDR_A24}, |
| 548 | /* {0x10, 0x80418, AddrType::ADDR_A24}, */ |
| 549 | /* {0x14, 0x8041C, AddrType::ADDR_A24}, */ |
| 550 | {0x18, 0x80420, AddrType::ADDR_A24}, |
| 551 | }; |
| 552 | |
| 553 | ConstBufferView image = ConstBufferView::FromRange( |
| 554 | std::begin(kDataAarch32ArmMode), std::end(kDataAarch32ArmMode)); |
| 555 | std::vector<offset_t> abs32_locations(std::begin(kAbs32Aarch32ArmMode), |
| 556 | std::end(kAbs32Aarch32ArmMode)); |
| 557 | AddressTranslator translator(GetTrivialTranslator(image.size())); |
| 558 | Rel32FinderAArch32 rel32_finder(image, translator, /* is_thumb2 */ false); |
| 559 | |
| 560 | std::vector<Result> results = ArmExtractRel32( |
| 561 | image, abs32_locations, DisassemblerElfAArch32::Traits::kVAWidth, |
| 562 | std::move(rel32_finder)); |
| 563 | |
| 564 | EXPECT_EQ(expected_results, results); |
| 565 | } |
| 566 | |
| 567 | namespace { |
| 568 | |
| 569 | // AArch32 THUMB2 mode test data. (x) and +x entries are covered by abs32 |
| 570 | // references (if used), which have width = 4. |
| 571 | constexpr uint8_t kDataAarch32Thumb2Mode[] = { |
| 572 | 0x00, 0xDE, // 00: B.AL 00000004 ; B encoding T1 |
| 573 | 0x00, 0xDE, // 02: B.AL 00000006 ; B encoding T1 |
| 574 | 0x00, (0xDE), // 04: B.AL 00000008 ; B encoding T1 |
| 575 | +0x00, +0xDE, // 06: B.AL 0000000A ; B encoding T1 |
| 576 | +0x00, 0xE0, // 08: B 0000000C ; B encoding T2 |
| 577 | 0x00, 0xE0, // 0A: B 0000000E ; B encoding T2 |
| 578 | 0x00, 0xE0, // 0C: B 00000010 ; B encoding T2 |
| 579 | (0x00), +0xE0, // 0E: B 00000012 ; B encoding T2 |
| 580 | +0x00, +0xF0, 0x00, 0x80, // 10: B 00000014 ; B encoding T3 |
| 581 | 0x00, 0xF0, 0x00, 0x80, // 14: B 00000018 ; B encoding T3 |
| 582 | (0x00), +0xF0, +0x00, +0x80, // 18: B 0000001C ; B encoding T3 |
| 583 | 0x00, 0xF0, 0x00, 0x80, // 1C: B 00000020 ; B encoding T3 |
| 584 | 0x00, 0xF0, 0x00, 0xB8, // 20: B 00000024 ; B encoding T4 |
| 585 | 0x00, 0xF0, 0x00, (0xB8), // 24: B 00000028 ; B encoding T4 |
| 586 | +0xFE, +0xDE, // 28: B.AL 00000028 ; B encoding T1 |
| 587 | +0x00, 0xF0, 0x00, 0xF8, // 2A: BL 0000002E ; BL encoding T1 |
| 588 | 0x00, 0xF0, 0x00, 0xE8, // 2E: BLX 00000030 ; BLX encoding T2 |
| 589 | 0x00, 0x0B, // 32: NOP |
| 590 | 0x00, 0xF0, 0x00, 0xE8, // 34: BLX 00000038 ; BLX encoding T2 |
| 591 | 0x00, 0xF0, 0x00, 0xB8, // 38: B 0000003C ; B encoding T4 |
| 592 | }; |
| 593 | |
| 594 | // Abs32 locations corresponding to |kDataAarch32Thumb2Mode|, with width = 4. |
| 595 | constexpr offset_t kAbs32Aarch32Thumb2Mode[] = {0x05, 0x0E, 0x18, 0x27}; |
| 596 | |
| 597 | } // namespace |
| 598 | |
| 599 | TEST(Rel32FinderAArch32Test, IntegratedThumb2ModeWithoutAbs32) { |
| 600 | using AddrType = AArch32Rel32Translator::AddrType; |
| 601 | using Result = Rel32FinderAArch32::Result; |
| 602 | std::vector<Result> expected_results = { |
| 603 | {0x00, 0x04, AddrType::ADDR_T8}, {0x02, 0x06, AddrType::ADDR_T8}, |
| 604 | {0x04, 0x08, AddrType::ADDR_T8}, {0x06, 0x0A, AddrType::ADDR_T8}, |
| 605 | {0x08, 0x0C, AddrType::ADDR_T11}, {0x0A, 0x0E, AddrType::ADDR_T11}, |
| 606 | {0x0C, 0x10, AddrType::ADDR_T11}, {0x0E, 0x12, AddrType::ADDR_T11}, |
| 607 | {0x10, 0x14, AddrType::ADDR_T20}, {0x14, 0x18, AddrType::ADDR_T20}, |
| 608 | {0x18, 0x1C, AddrType::ADDR_T20}, {0x1C, 0x20, AddrType::ADDR_T20}, |
| 609 | {0x20, 0x24, AddrType::ADDR_T24}, {0x24, 0x28, AddrType::ADDR_T24}, |
| 610 | {0x28, 0x28, AddrType::ADDR_T8}, {0x2A, 0x2E, AddrType::ADDR_T24}, |
| 611 | {0x2E, 0x30, AddrType::ADDR_T24}, {0x34, 0x38, AddrType::ADDR_T24}, |
| 612 | {0x38, 0x3C, AddrType::ADDR_T24}, |
| 613 | }; |
| 614 | |
| 615 | ConstBufferView image = ConstBufferView::FromRange( |
| 616 | std::begin(kDataAarch32Thumb2Mode), std::end(kDataAarch32Thumb2Mode)); |
| 617 | AddressTranslator translator(GetTrivialTranslator(image.size())); |
| 618 | Rel32FinderAArch32 rel32_finder(image, translator, /* is_thumb2 */ true); |
| 619 | |
| 620 | std::vector<Result> results = ArmExtractRel32( |
| 621 | image, /* abs32_locations */ {}, DisassemblerElfAArch32::Traits::kVAWidth, |
| 622 | std::move(rel32_finder)); |
| 623 | |
| 624 | EXPECT_EQ(expected_results, results); |
| 625 | } |
| 626 | |
| 627 | TEST(Rel32FinderAArch32Test, IntegratedThumb2ModeWithAbs32) { |
| 628 | using AddrType = AArch32Rel32Translator::AddrType; |
| 629 | using Result = Rel32FinderAArch32::Result; |
| 630 | std::vector<Result> expected_results = { |
| 631 | {0x00, 0x04, AddrType::ADDR_T8}, |
| 632 | {0x02, 0x06, AddrType::ADDR_T8}, |
| 633 | /* {0x04, 0x08, AddrType::ADDR_T8}, */ |
| 634 | /* {0x06, 0x0A, AddrType::ADDR_T8}, */ |
| 635 | /* {0x08, 0x0C, AddrType::ADDR_T11}, */ |
| 636 | {0x0A, 0x0E, AddrType::ADDR_T11}, |
| 637 | {0x0C, 0x10, AddrType::ADDR_T11}, |
| 638 | /* {0x0E, 0x12, AddrType::ADDR_T11}, */ |
| 639 | /* {0x10, 0x14, AddrType::ADDR_T20}, */ |
| 640 | {0x14, 0x18, AddrType::ADDR_T20}, |
| 641 | /* {0x18, 0x1C, AddrType::ADDR_T20}, */ |
| 642 | {0x1C, 0x20, AddrType::ADDR_T20}, |
| 643 | {0x20, 0x24, AddrType::ADDR_T24}, |
| 644 | /* {0x24, 0x28, AddrType::ADDR_T24}, */ |
| 645 | /* {0x28, 0x28, AddrType::ADDR_T8}, */ |
| 646 | /* {0x2A, 0x2E, AddrType::ADDR_T24}, */ |
| 647 | // Abs32 reference 0x27 disrupts alignment, and THUMB2 disassembly starts |
| 648 | // at 0x2C, causing the following to be excluded! |
| 649 | /* {0x2E, 0x30, AddrType::ADDR_T24}, */ |
| 650 | {0x34, 0x38, AddrType::ADDR_T24}, |
| 651 | {0x38, 0x3C, AddrType::ADDR_T24}, |
| 652 | }; |
| 653 | |
| 654 | ConstBufferView image = ConstBufferView::FromRange( |
| 655 | std::begin(kDataAarch32Thumb2Mode), std::end(kDataAarch32Thumb2Mode)); |
| 656 | std::vector<offset_t> abs32_locations(std::begin(kAbs32Aarch32Thumb2Mode), |
| 657 | std::end(kAbs32Aarch32Thumb2Mode)); |
| 658 | AddressTranslator translator(GetTrivialTranslator(image.size())); |
| 659 | Rel32FinderAArch32 rel32_finder(image, translator, /* is_thumb2 */ true); |
| 660 | |
| 661 | std::vector<Result> results = ArmExtractRel32( |
| 662 | image, abs32_locations, DisassemblerElfAArch32::Traits::kVAWidth, |
| 663 | std::move(rel32_finder)); |
| 664 | |
| 665 | EXPECT_EQ(expected_results, results); |
| 666 | } |
| 667 | |
| 668 | namespace { |
| 669 | |
| 670 | // AArch32 THUMB2 mode test data. (x) and +x entries are covered by abs32 |
| 671 | // references (if used), which have width = 8. |
| 672 | constexpr uint8_t kDataAarch64[] = { |
| 673 | 0x0E, 0x00, 0x00, 0x36, // 00: TBZ X0,#0,00000000 ; Immd14 |
| 674 | 0x0E, 0x00, 0x00, (0x36), // 04: TBZ X0,#0,00000004 ; Immd14 |
| 675 | +0x0E, +0x00, +0x00, +0x36, // 08: TBZ X0,#0,00000008 ; Immd14 |
| 676 | +0x0E, +0x00, +0x00, 0x54, // 0C: B.AL 0000000C ; Immd19 |
| 677 | 0x0E, 0x00, 0x00, 0x54, // 10: B.AL 00000010 ; Immd19 |
| 678 | (0x0E), +0x00, +0x00, +0x54, // 14: B.AL 00000014 ; Immd19 |
| 679 | +0x00, +0x00, +0x00, +0x94, // 18: BL 00000018 ; Immd26 |
| 680 | 0x00, 0x00, 0x00, 0x14, // 1C: B 0000001C ; Immd26 |
| 681 | 0x00, 0x00, 0x00, 0x94, // 20: BL 00000020 ; Immd26 |
| 682 | 0x00, 0x00, 0x00, 0x14, // 24: B 00000024 ; Immd26 |
| 683 | }; |
| 684 | |
| 685 | // Abs32 locations corresponding to |kDataAarch64|, with width = 8. |
| 686 | constexpr offset_t kAbs32Aarch64[] = {0x07, 0x14}; |
| 687 | |
| 688 | } // namespace |
| 689 | |
| 690 | TEST(Rel32FinderAArch64Test, IntegratedWithoutAbs32) { |
| 691 | using AddrType = AArch64Rel32Translator::AddrType; |
| 692 | using Result = Rel32FinderAArch64::Result; |
| 693 | std::vector<Result> expected_results = { |
| 694 | {0x00, 0x00, AddrType::ADDR_IMMD14}, {0x04, 0x04, AddrType::ADDR_IMMD14}, |
| 695 | {0x08, 0x08, AddrType::ADDR_IMMD14}, {0x0C, 0x0C, AddrType::ADDR_IMMD19}, |
| 696 | {0x10, 0x10, AddrType::ADDR_IMMD19}, {0x14, 0x14, AddrType::ADDR_IMMD19}, |
| 697 | {0x18, 0x18, AddrType::ADDR_IMMD26}, {0x1C, 0x1C, AddrType::ADDR_IMMD26}, |
| 698 | {0x20, 0x20, AddrType::ADDR_IMMD26}, {0x24, 0x24, AddrType::ADDR_IMMD26}, |
| 699 | }; |
| 700 | |
| 701 | ConstBufferView image = ConstBufferView::FromRange(std::begin(kDataAarch64), |
| 702 | std::end(kDataAarch64)); |
| 703 | AddressTranslator translator(GetTrivialTranslator(image.size())); |
| 704 | Rel32FinderAArch64 rel32_finder(image, translator); |
| 705 | |
| 706 | std::vector<Result> results = ArmExtractRel32( |
| 707 | image, /* abs32_locations */ {}, DisassemblerElfAArch64::Traits::kVAWidth, |
| 708 | std::move(rel32_finder)); |
| 709 | |
| 710 | EXPECT_EQ(expected_results, results); |
| 711 | } |
| 712 | |
| 713 | TEST(Rel32FinderAArch64Test, IntegratedWithAbs32) { |
| 714 | using AddrType = AArch64Rel32Translator::AddrType; |
| 715 | using Result = Rel32FinderAArch64::Result; |
| 716 | std::vector<Result> expected_results = { |
| 717 | {0x00, 0x00, AddrType::ADDR_IMMD14}, |
| 718 | /* {0x04, 0x04, AddrType::ADDR_IMMD14}, */ |
| 719 | /* {0x08, 0x08, AddrType::ADDR_IMMD14}, */ |
| 720 | /* {0x0C, 0x0C, AddrType::ADDR_IMMD19}, */ |
| 721 | {0x10, 0x10, AddrType::ADDR_IMMD19}, |
| 722 | /* {0x14, 0x14, AddrType::ADDR_IMMD19}, */ |
| 723 | /* {0x18, 0x18, AddrType::ADDR_IMMD26}, */ |
| 724 | {0x1C, 0x1C, AddrType::ADDR_IMMD26}, |
| 725 | {0x20, 0x20, AddrType::ADDR_IMMD26}, |
| 726 | {0x24, 0x24, AddrType::ADDR_IMMD26}, |
| 727 | }; |
| 728 | |
| 729 | ConstBufferView image = ConstBufferView::FromRange(std::begin(kDataAarch64), |
| 730 | std::end(kDataAarch64)); |
| 731 | std::vector<offset_t> abs32_locations(std::begin(kAbs32Aarch64), |
| 732 | std::end(kAbs32Aarch64)); |
| 733 | AddressTranslator translator(GetTrivialTranslator(image.size())); |
| 734 | Rel32FinderAArch64 rel32_finder(image, translator); |
| 735 | |
| 736 | std::vector<Result> results = ArmExtractRel32( |
| 737 | image, abs32_locations, DisassemblerElfAArch64::Traits::kVAWidth, |
| 738 | std::move(rel32_finder)); |
| 739 | |
| 740 | EXPECT_EQ(expected_results, results); |
Samuel Huang | 1cec5a7 | 2021-06-01 18:29:53 +0000 | [diff] [blame] | 741 | } |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 742 | |
| 743 | } // namespace zucchini |