xref: /aosp_15_r20/external/google-breakpad/src/common/windows/omap_unittest.cc (revision 9712c20fc9bbfbac4935993a2ca0b3958c5adad2)
1 // Copyright 2013 Google LLC
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are
5 // met:
6 //
7 //     * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 //     * Redistributions in binary form must reproduce the above
10 // copyright notice, this list of conditions and the following disclaimer
11 // in the documentation and/or other materials provided with the
12 // distribution.
13 //     * Neither the name of Google LLC nor the names of its
14 // contributors may be used to endorse or promote products derived from
15 // this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 
29 // Unittests for OMAP related functions.
30 
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>  // Must come first
33 #endif
34 
35 #include "common/windows/omap.h"
36 
37 #include "breakpad_googletest_includes.h"
38 
39 namespace google_breakpad {
40 
41 // Equality operators for ContainerEq. These must be outside of the anonymous
42 // namespace in order for them to be found.
operator ==(const MappedRange & mr1,const MappedRange & mr2)43 bool operator==(const MappedRange& mr1, const MappedRange& mr2) {
44   return mr1.rva_original == mr2.rva_original &&
45       mr1.rva_transformed == mr2.rva_transformed &&
46       mr1.length == mr2.length &&
47       mr1.injected == mr2.injected &&
48       mr1.removed == mr2.removed;
49 }
operator ==(const EndpointIndex & ei1,const EndpointIndex & ei2)50 bool operator==(const EndpointIndex& ei1, const EndpointIndex& ei2) {
51   return ei1.endpoint == ei2.endpoint && ei1.index == ei2.index;
52 }
53 
54 // Pretty printers for more meaningful error messages. Also need to be outside
55 // the anonymous namespace.
operator <<(std::ostream & os,const MappedRange & mr)56 std::ostream& operator<<(std::ostream& os, const MappedRange& mr) {
57   os << "MappedRange(rva_original=" << mr.rva_original
58      << ", rva_transformed=" << mr.rva_transformed
59      << ", length=" << mr.length
60      << ", injected=" << mr.injected
61      << ", removed=" << mr.removed << ")";
62   return os;
63 }
operator <<(std::ostream & os,const EndpointIndex & ei)64 std::ostream& operator<<(std::ostream& os, const EndpointIndex& ei) {
65   os << "EndpointIndex(endpoint=" << ei.endpoint
66      << ", index=" << ei.index << ")";
67   return os;
68 }
operator <<(std::ostream & os,const AddressRange & ar)69 std::ostream& operator<<(std::ostream& os, const AddressRange& ar) {
70   os << "AddressRange(rva=" << ar.rva << ", length=" << ar.length << ")";
71   return os;
72 }
73 
74 namespace {
75 
CreateOmap(DWORD rva,DWORD rvaTo)76 OMAP CreateOmap(DWORD rva, DWORD rvaTo) {
77   OMAP o = { rva, rvaTo };
78   return o;
79 }
80 
CreateMappedRange(DWORD rva_original,DWORD rva_transformed,DWORD length,DWORD injected,DWORD removed)81 MappedRange CreateMappedRange(DWORD rva_original,
82                               DWORD rva_transformed,
83                               DWORD length,
84                               DWORD injected,
85                               DWORD removed) {
86   MappedRange mr = { rva_original, rva_transformed, length, injected, removed };
87   return mr;
88 }
89 
CreateEndpointIndex(DWORD endpoint,size_t index)90 EndpointIndex CreateEndpointIndex(DWORD endpoint, size_t index) {
91   EndpointIndex ei = { endpoint, index };
92   return ei;
93 }
94 
95 //              (C is removed)
96 // Original   :  A B C D E F G H
97 // Transformed:  A B D F E * H1 G1 G2 H2
98 //              (* is injected, G is copied, H is split)
99 // A is implied.
100 
101 // Layout of the original image.
102 const AddressRange B(100, 15);
103 const AddressRange C(B.end(), 10);
104 const AddressRange D(C.end(), 25);
105 const AddressRange E(D.end(), 10);
106 const AddressRange F(E.end(), 40);
107 const AddressRange G(F.end(), 3);
108 const AddressRange H(G.end(), 7);
109 
110 // Layout of the transformed image.
111 const AddressRange Bt(100, 15);
112 const AddressRange Dt(Bt.end(), 20);  // D is shortened.
113 const AddressRange Ft(Dt.end(), F.length);
114 const AddressRange Et(Ft.end(), E.length);
115 const AddressRange injected(Et.end(), 5);
116 const AddressRange H1t(injected.end(), 4);  // H is split.
117 const AddressRange G1t(H1t.end(), G.length);  // G is copied.
118 const AddressRange G2t(G1t.end(), G.length);  // G is copied.
119 const AddressRange H2t(G2t.end(), 3);  // H is split.
120 
121 class BuildImageMapTest : public testing::Test {
122  public:
123   static const DWORD kInvalidAddress = 0xFFFFFFFF;
124 
InitOmapData()125   void InitOmapData() {
126     omap_data.length_original = H.end();
127 
128     // Build the OMAPTO vector (from transformed to original).
129     omap_data.omap_to.push_back(CreateOmap(Bt.rva, B.rva));
130     omap_data.omap_to.push_back(CreateOmap(Dt.rva, D.rva));
131     omap_data.omap_to.push_back(CreateOmap(Ft.rva, F.rva));
132     omap_data.omap_to.push_back(CreateOmap(Et.rva, E.rva));
133     omap_data.omap_to.push_back(CreateOmap(injected.rva, kInvalidAddress));
134     omap_data.omap_to.push_back(CreateOmap(H1t.rva, H.rva));
135     omap_data.omap_to.push_back(CreateOmap(G1t.rva, G.rva));
136     omap_data.omap_to.push_back(CreateOmap(G2t.rva, G.rva));
137     omap_data.omap_to.push_back(CreateOmap(H2t.rva, H.rva + H1t.length));
138     omap_data.omap_to.push_back(CreateOmap(H2t.end(), kInvalidAddress));
139 
140     // Build the OMAPFROM vector (from original to transformed).
141     omap_data.omap_from.push_back(CreateOmap(B.rva, Bt.rva));
142     omap_data.omap_from.push_back(CreateOmap(C.rva, kInvalidAddress));
143     omap_data.omap_from.push_back(CreateOmap(D.rva, Dt.rva));
144     omap_data.omap_from.push_back(CreateOmap(E.rva, Et.rva));
145     omap_data.omap_from.push_back(CreateOmap(F.rva, Ft.rva));
146     omap_data.omap_from.push_back(CreateOmap(G.rva, G1t.rva));
147     omap_data.omap_from.push_back(CreateOmap(H.rva, H1t.rva));
148     omap_data.omap_from.push_back(CreateOmap(H.rva + H1t.length, H2t.rva));
149     omap_data.omap_from.push_back(CreateOmap(H.end(), kInvalidAddress));
150   }
151 
152   OmapData omap_data;
153 };
154 
155 }  // namespace
156 
TEST_F(BuildImageMapTest,EmptyImageMapOnEmptyOmapData)157 TEST_F(BuildImageMapTest, EmptyImageMapOnEmptyOmapData) {
158   ASSERT_EQ(0u, omap_data.omap_from.size());
159   ASSERT_EQ(0u, omap_data.omap_to.size());
160   ASSERT_EQ(0u, omap_data.length_original);
161 
162   ImageMap image_map;
163   BuildImageMap(omap_data, &image_map);
164   EXPECT_EQ(0u, image_map.mapping.size());
165   EXPECT_EQ(0u, image_map.endpoint_index_map.size());
166 }
167 
TEST_F(BuildImageMapTest,ImageMapIsCorrect)168 TEST_F(BuildImageMapTest, ImageMapIsCorrect) {
169   InitOmapData();
170   ASSERT_LE(0u, omap_data.omap_from.size());
171   ASSERT_LE(0u, omap_data.omap_to.size());
172   ASSERT_LE(0u, omap_data.length_original);
173 
174   ImageMap image_map;
175   BuildImageMap(omap_data, &image_map);
176   EXPECT_LE(9u, image_map.mapping.size());
177   EXPECT_LE(9u, image_map.endpoint_index_map.size());
178 
179   Mapping mapping;
180   mapping.push_back(CreateMappedRange(0, 0, B.rva, 0, 0));
181   // C is removed, and it originally comes immediately after B.
182   mapping.push_back(CreateMappedRange(B.rva, Bt.rva, B.length, 0, C.length));
183   // D is shortened by a length of 5.
184   mapping.push_back(CreateMappedRange(D.rva, Dt.rva, Dt.length, 0, 5));
185   // The injected content comes immediately after E in the transformed image.
186   mapping.push_back(CreateMappedRange(E.rva, Et.rva, E.length, injected.length,
187                                       0));
188   mapping.push_back(CreateMappedRange(F.rva, Ft.rva, F.length, 0, 0));
189   // G is copied so creates two entries.
190   mapping.push_back(CreateMappedRange(G.rva, G1t.rva, G.length, 0, 0));
191   mapping.push_back(CreateMappedRange(G.rva, G2t.rva, G.length, 0, 0));
192   // H is split, so create two entries.
193   mapping.push_back(CreateMappedRange(H.rva, H1t.rva, H1t.length, 0, 0));
194   mapping.push_back(CreateMappedRange(H.rva + H1t.length, H2t.rva, H2t.length,
195                                       0, 0));
196   EXPECT_THAT(mapping,
197               testing::ContainerEq(image_map.mapping));
198 
199   EndpointIndexMap endpoint_index_map;
200   endpoint_index_map.push_back(CreateEndpointIndex(0, 0));
201   endpoint_index_map.push_back(CreateEndpointIndex(B.rva, 1));
202   endpoint_index_map.push_back(CreateEndpointIndex(D.rva, 2));
203   endpoint_index_map.push_back(CreateEndpointIndex(E.rva, 3));
204   endpoint_index_map.push_back(CreateEndpointIndex(F.rva, 4));
205   // G is duplicated so 2 ranges map back to it, hence the skip from 5 to 7.
206   endpoint_index_map.push_back(CreateEndpointIndex(G.rva, 5));
207   // H is split so we expect 2 endpoints to show up attributed to it.
208   endpoint_index_map.push_back(CreateEndpointIndex(H.rva, 7));
209   endpoint_index_map.push_back(CreateEndpointIndex(H.rva + H1t.length, 8));
210   endpoint_index_map.push_back(CreateEndpointIndex(H.end(), 9));
211   EXPECT_THAT(endpoint_index_map,
212               testing::ContainerEq(image_map.endpoint_index_map));
213 }
214 
215 namespace {
216 
217 class MapAddressRangeTest : public BuildImageMapTest {
218  public:
219   typedef BuildImageMapTest Super;
SetUp()220   virtual void SetUp() {
221     Super::SetUp();
222     InitOmapData();
223     BuildImageMap(omap_data, &image_map);
224   }
225 
226   ImageMap image_map;
227 
228  private:
229   using BuildImageMapTest::InitOmapData;
230   using BuildImageMapTest::omap_data;
231 };
232 
233 }  // namespace
234 
TEST_F(MapAddressRangeTest,EmptyImageMapReturnsIdentity)235 TEST_F(MapAddressRangeTest, EmptyImageMapReturnsIdentity) {
236   ImageMap im;
237   AddressRangeVector mapped_ranges;
238   AddressRange ar(0, 1024);
239   MapAddressRange(im, ar, &mapped_ranges);
240   EXPECT_EQ(1u, mapped_ranges.size());
241   EXPECT_EQ(ar, mapped_ranges[0]);
242 }
243 
TEST_F(MapAddressRangeTest,MapOutOfImage)244 TEST_F(MapAddressRangeTest, MapOutOfImage) {
245   AddressRangeVector mapped_ranges;
246   MapAddressRange(image_map, AddressRange(H.end() + 10, 10), &mapped_ranges);
247   EXPECT_EQ(0u, mapped_ranges.size());
248 }
249 
TEST_F(MapAddressRangeTest,MapIdentity)250 TEST_F(MapAddressRangeTest, MapIdentity) {
251   AddressRangeVector mapped_ranges;
252   MapAddressRange(image_map, B, &mapped_ranges);
253   EXPECT_EQ(1u, mapped_ranges.size());
254   EXPECT_THAT(mapped_ranges, testing::ElementsAre(B));
255 }
256 
TEST_F(MapAddressRangeTest,MapReorderedContiguous)257 TEST_F(MapAddressRangeTest, MapReorderedContiguous) {
258   AddressRangeVector mapped_ranges;
259 
260   AddressRange DEF(D.rva, F.end() - D.rva);
261   MapAddressRange(image_map, DEF, &mapped_ranges);
262   EXPECT_EQ(1u, mapped_ranges.size());
263 
264   AddressRange DFEt(Dt.rva, Et.end() - Dt.rva);
265   EXPECT_THAT(mapped_ranges, testing::ElementsAre(DFEt));
266 }
267 
TEST_F(MapAddressRangeTest,MapEmptySingle)268 TEST_F(MapAddressRangeTest, MapEmptySingle) {
269   AddressRangeVector mapped_ranges;
270   MapAddressRange(image_map, AddressRange(D.rva, 0), &mapped_ranges);
271   EXPECT_EQ(1u, mapped_ranges.size());
272   EXPECT_THAT(mapped_ranges, testing::ElementsAre(AddressRange(Dt.rva, 0)));
273 }
274 
TEST_F(MapAddressRangeTest,MapEmptyCopied)275 TEST_F(MapAddressRangeTest, MapEmptyCopied) {
276   AddressRangeVector mapped_ranges;
277   MapAddressRange(image_map, AddressRange(G.rva, 0), &mapped_ranges);
278   EXPECT_EQ(2u, mapped_ranges.size());
279   EXPECT_THAT(mapped_ranges, testing::ElementsAre(AddressRange(G1t.rva, 0),
280                                                   AddressRange(G2t.rva, 0)));
281 }
282 
TEST_F(MapAddressRangeTest,MapCopiedContiguous)283 TEST_F(MapAddressRangeTest, MapCopiedContiguous) {
284   AddressRangeVector mapped_ranges;
285   MapAddressRange(image_map, G, &mapped_ranges);
286   EXPECT_EQ(1u, mapped_ranges.size());
287   EXPECT_THAT(mapped_ranges, testing::ElementsAre(
288       AddressRange(G1t.rva, G2t.end() - G1t.rva)));
289 }
290 
TEST_F(MapAddressRangeTest,MapSplitDiscontiguous)291 TEST_F(MapAddressRangeTest, MapSplitDiscontiguous) {
292   AddressRangeVector mapped_ranges;
293   MapAddressRange(image_map, H, &mapped_ranges);
294   EXPECT_EQ(2u, mapped_ranges.size());
295   EXPECT_THAT(mapped_ranges, testing::ElementsAre(H1t, H2t));
296 }
297 
TEST_F(MapAddressRangeTest,MapInjected)298 TEST_F(MapAddressRangeTest, MapInjected) {
299   AddressRangeVector mapped_ranges;
300 
301   AddressRange EFGH(E.rva, H.end() - E.rva);
302   MapAddressRange(image_map, EFGH, &mapped_ranges);
303   EXPECT_EQ(1u, mapped_ranges.size());
304 
305   AddressRange FEHGGHt(Ft.rva, H2t.end() - Ft.rva);
306   EXPECT_THAT(mapped_ranges, testing::ElementsAre(FEHGGHt));
307 }
308 
TEST_F(MapAddressRangeTest,MapRemovedEntirely)309 TEST_F(MapAddressRangeTest, MapRemovedEntirely) {
310   AddressRangeVector mapped_ranges;
311   MapAddressRange(image_map, C, &mapped_ranges);
312   EXPECT_EQ(0u, mapped_ranges.size());
313 }
314 
TEST_F(MapAddressRangeTest,MapRemovedPartly)315 TEST_F(MapAddressRangeTest, MapRemovedPartly) {
316   AddressRangeVector mapped_ranges;
317   MapAddressRange(image_map, D, &mapped_ranges);
318   EXPECT_EQ(1u, mapped_ranges.size());
319   EXPECT_THAT(mapped_ranges, testing::ElementsAre(Dt));
320 }
321 
TEST_F(MapAddressRangeTest,MapFull)322 TEST_F(MapAddressRangeTest, MapFull) {
323   AddressRangeVector mapped_ranges;
324 
325   AddressRange AH(0, H.end());
326   MapAddressRange(image_map, AH, &mapped_ranges);
327   EXPECT_EQ(1u, mapped_ranges.size());
328 
329   AddressRange AHt(0, H2t.end());
330   EXPECT_THAT(mapped_ranges, testing::ElementsAre(AHt));
331 }
332 
333 }  // namespace google_breakpad
334