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