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
16 #include "base/check_op.h"
17 #include "base/format_macros.h"
18 #include "base/numerics/safe_conversions.h"
19 #include "base/strings/stringprintf.h"
20 #include "components/zucchini/arm_utils.h"
21 #include "components/zucchini/buffer_view.h"
22 #include "components/zucchini/disassembler_elf.h"
23 #include "components/zucchini/image_utils.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25
26 namespace zucchini {
27
TEST(Abs32GapFinderTest,All)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;
46 while (gap_finder.FindNext()) {
47 ConstBufferView gap = gap_finder.GetGap();
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());
50 out_str.append(base::StringPrintf("[%" PRIuS ",%" PRIuS ")", lo, hi));
51 }
52 return out_str;
53 };
54
55 // Empty regions yield empty segments.
56 EXPECT_EQ("", run_test(0, 0, {}, 4));
57 EXPECT_EQ("", run_test(9, 9, {}, 4));
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.
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));
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
129 // Rel32Finder:
Scan(ConstBufferView region)130 NextIterators Scan(ConstBufferView region) override { return next_result; }
131
132 NextIterators next_result;
133 };
134
GetTrivialTranslator(size_t size)135 AddressTranslator GetTrivialTranslator(size_t size) {
136 AddressTranslator translator;
137 EXPECT_EQ(AddressTranslator::kSuccess,
138 translator.Initialize({{0, base::checked_cast<offset_t>(size), 0U,
139 base::checked_cast<rva_t>(size)}}));
140 return translator;
141 }
142
143 } // namespace
144
TEST(Rel32FinderTest,Scan)145 TEST(Rel32FinderTest, Scan) {
146 const size_t kRegionTotal = 99;
147 std::vector<uint8_t> buffer(kRegionTotal);
148 ConstBufferView image(buffer.data(), buffer.size());
149 AddressTranslator translator(GetTrivialTranslator(image.size()));
150 TestRel32Finder finder(image, translator);
151 finder.SetRegion(image);
152
153 auto check_finder_state = [&](const TestRel32Finder& finder,
154 size_t expected_cursor,
155 size_t expected_accept_it) {
156 CHECK_LE(expected_cursor, kRegionTotal);
157 CHECK_LE(expected_accept_it, kRegionTotal);
158
159 EXPECT_EQ(image.begin() + expected_cursor, finder.region().begin());
160 EXPECT_EQ(image.begin() + expected_accept_it, finder.accept_it());
161 };
162
163 check_finder_state(finder, 0, 0);
164
165 finder.next_result = {image.begin() + 1, image.begin() + 1};
166 EXPECT_TRUE(finder.FindNext());
167 check_finder_state(finder, 1, 1);
168
169 finder.next_result = {image.begin() + 2, image.begin() + 2};
170 EXPECT_TRUE(finder.FindNext());
171 check_finder_state(finder, 2, 2);
172
173 finder.next_result = {image.begin() + 5, image.begin() + 6};
174 EXPECT_TRUE(finder.FindNext());
175 check_finder_state(finder, 5, 6);
176 finder.Accept();
177 check_finder_state(finder, 6, 6);
178
179 finder.next_result = {image.begin() + 7, image.begin() + 7};
180 EXPECT_TRUE(finder.FindNext());
181 check_finder_state(finder, 7, 7);
182
183 finder.next_result = {image.begin() + 8, image.begin() + 8};
184 EXPECT_TRUE(finder.FindNext());
185 check_finder_state(finder, 8, 8);
186
187 finder.next_result = {image.begin() + 99, image.begin() + 99};
188 EXPECT_TRUE(finder.FindNext());
189 check_finder_state(finder, 99, 99);
190
191 finder.next_result = {nullptr, nullptr};
192 EXPECT_FALSE(finder.FindNext());
193 check_finder_state(finder, 99, 99);
194 }
195
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.
226 constexpr offset_t kAbs32X86[] = {0x08, 0x17, 0x26, 0x2A,
227 0x40, 0x51, 0x5F, 0x63};
228
229 } // namespace
230
TEST(Rel32FinderX86Test,FindNext)231 TEST(Rel32FinderX86Test, FindNext) {
232 ConstBufferView image =
233 ConstBufferView::FromRange(std::begin(kDataX86), std::end(kDataX86));
234 AddressTranslator translator(GetTrivialTranslator(image.size()));
235 Rel32FinderX86 rel_finder(image, translator);
236 rel_finder.SetRegion(image);
237
238 // List of expected locations as pairs of {cursor offset, rel32 offset},
239 // ignoring |kAbs32X86|.
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 };
246 for (auto location : expected_locations) {
247 EXPECT_TRUE(rel_finder.FindNext());
248 auto rel32 = rel_finder.GetRel32();
249
250 EXPECT_EQ(location.first,
251 size_t(rel_finder.region().begin() - image.begin()));
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);
255 rel_finder.Accept();
256 }
257 EXPECT_FALSE(rel_finder.FindNext());
258 }
259
TEST(Rel32FinderX86Test,Integrated)260 TEST(Rel32FinderX86Test, Integrated) {
261 // Truncated form of Rel32FinderIntel::Result.
262 using TruncatedResults = std::pair<offset_t, rva_t>;
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));
268 std::vector<TruncatedResults> results;
269
270 Abs32GapFinder gap_finder(image, image, abs32_locations,
271 DisassemblerElfX86::Traits::kVAWidth);
272 AddressTranslator translator(GetTrivialTranslator(image.size()));
273 Rel32FinderX86 rel_finder(image, translator);
274 while (gap_finder.FindNext()) {
275 rel_finder.SetRegion(gap_finder.GetGap());
276 while (rel_finder.FindNext()) {
277 auto rel32 = rel_finder.GetRel32();
278 rel_finder.Accept();
279 results.emplace_back(TruncatedResults{rel32.location, rel32.target_rva});
280 }
281 }
282
283 std::vector<TruncatedResults> expected_results = {
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 };
294 EXPECT_EQ(expected_results, results);
295 }
296
TEST(Rel32FinderX86Test,Accept)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
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;
311 };
312
313 AddressTranslator translator(GetTrivialTranslator(image.size()));
314 Rel32FinderX86 rel_finder(image, translator);
315 rel_finder.SetRegion(image);
316
317 EXPECT_EQ(0x05U, next_location(rel_finder)); // False positive.
318 rel_finder.Accept();
319 // False negative: shadowed by 0x05
320 // EXPECT_EQ(0x06, next_location(rel_finder));
321 EXPECT_EQ(0x0AU, next_location(rel_finder)); // False positive.
322 EXPECT_EQ(0x0BU, next_location(rel_finder)); // Found if 0x0A is discarded.
323 }
324
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.
373 constexpr offset_t kAbs32X64[] = {0x0C, 0x1F, 0x33, 0x3B, 0x49,
374 0x6A, 0x99, 0xB3, 0xCC};
375
376 } // namespace
377
TEST(Rel32FinderX64Test,FindNext)378 TEST(Rel32FinderX64Test, FindNext) {
379 ConstBufferView image =
380 ConstBufferView::FromRange(std::begin(kDataX64), std::end(kDataX64));
381 AddressTranslator translator(GetTrivialTranslator(image.size()));
382 Rel32FinderX64 rel_finder(image, translator);
383 rel_finder.SetRegion(image);
384
385 // Lists of expected locations as pairs of {cursor offset, rel32 offset},
386 // ignoring |kAbs32X64|.
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 };
399 // Jump instructions, which cannot point outside section.
400 for (auto location : expected_locations) {
401 EXPECT_TRUE(rel_finder.FindNext());
402 auto rel32 = rel_finder.GetRel32();
403 EXPECT_EQ(location.first,
404 size_t(rel_finder.region().begin() - image.begin()));
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);
408 rel_finder.Accept();
409 }
410 // PC-relative data access instructions, which can point outside section.
411 for (auto location : expected_locations_rip) {
412 EXPECT_TRUE(rel_finder.FindNext());
413 auto rel32 = rel_finder.GetRel32();
414 EXPECT_EQ(location.first,
415 size_t(rel_finder.region().begin() - image.begin()));
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.
419 rel_finder.Accept();
420 }
421 EXPECT_FALSE(rel_finder.FindNext());
422 }
423
TEST(Rel32FinderX64Test,Integrated)424 TEST(Rel32FinderX64Test, Integrated) {
425 // Truncated form of Rel32FinderIntel::Result.
426 using TruncatedResults = std::pair<offset_t, rva_t>;
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));
432 std::vector<TruncatedResults> results;
433
434 Abs32GapFinder gap_finder(image, image, abs32_locations,
435 DisassemblerElfX64::Traits::kVAWidth);
436 AddressTranslator translator(GetTrivialTranslator(image.size()));
437 Rel32FinderX64 rel_finder(image, translator);
438 while (gap_finder.FindNext()) {
439 rel_finder.SetRegion(gap_finder.GetGap());
440 while (rel_finder.FindNext()) {
441 auto rel32 = rel_finder.GetRel32();
442 rel_finder.Accept();
443 results.emplace_back(TruncatedResults{rel32.location, rel32.target_rva});
444 }
445 }
446
447 std::vector<TruncatedResults> expected_results = {
448 {0x04, 0x08},
449 /* {0x09, 0x0D}, */
450 /* {0x0F, 0x13}, */ /* {0x15, 0x19}, */ {0x1B, 0x1F},
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 };
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>
ArmExtractRel32(ConstBufferView image,const std::vector<offset_t> & abs32_locations,int abs32_width,REL32_FINDER && 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
TEST(Rel32FinderAArch32Test,IntegratedArmModeWithoutAbs32)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
TEST(Rel32FinderAArch32Test,IntegratedArmModeWithAbs32)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
TEST(Rel32FinderAArch32Test,IntegratedThumb2ModeWithoutAbs32)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
TEST(Rel32FinderAArch32Test,IntegratedThumb2ModeWithAbs32)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
TEST(Rel32FinderAArch64Test,IntegratedWithoutAbs32)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
TEST(Rel32FinderAArch64Test,IntegratedWithAbs32)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);
741 }
742
743 } // namespace zucchini
744