omap_unittest.cc
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. 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 } 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. 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 } 64 std::ostream& operator<<(std::ostream& os, const EndpointIndex& ei) { 65 os << "EndpointIndex(endpoint=" << ei.endpoint 66 << ", index=" << ei.index << ")"; 67 return os; 68 } 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 76 OMAP CreateOmap(DWORD rva, DWORD rvaTo) { 77 OMAP o = { rva, rvaTo }; 78 return o; 79 } 80 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 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 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 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 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; 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 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 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 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 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 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 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 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 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 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 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 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 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