1 // Copyright 2013 Google Inc. All rights reserved. 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 Inc. 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 #include "common/windows/omap.h" 32 33 #include "gmock/gmock.h" 34 #include "gtest/gtest.h" 35 36 namespace google_breakpad { 37 38 // Equality operators for ContainerEq. These must be outside of the anonymous 39 // namespace in order for them to be found. 40 bool operator==(const MappedRange& mr1, const MappedRange& mr2) { 41 return mr1.rva_original == mr2.rva_original && 42 mr1.rva_transformed == mr2.rva_transformed && 43 mr1.length == mr2.length && 44 mr1.injected == mr2.injected && 45 mr1.removed == mr2.removed; 46 } 47 bool operator==(const EndpointIndex& ei1, const EndpointIndex& ei2) { 48 return ei1.endpoint == ei2.endpoint && ei1.index == ei2.index; 49 } 50 51 // Pretty printers for more meaningful error messages. Also need to be outside 52 // the anonymous namespace. 53 std::ostream& operator<<(std::ostream& os, const MappedRange& mr) { 54 os << "MappedRange(rva_original=" << mr.rva_original 55 << ", rva_transformed=" << mr.rva_transformed 56 << ", length=" << mr.length 57 << ", injected=" << mr.injected 58 << ", removed=" << mr.removed << ")"; 59 return os; 60 } 61 std::ostream& operator<<(std::ostream& os, const EndpointIndex& ei) { 62 os << "EndpointIndex(endpoint=" << ei.endpoint 63 << ", index=" << ei.index << ")"; 64 return os; 65 } 66 std::ostream& operator<<(std::ostream& os, const AddressRange& ar) { 67 os << "AddressRange(rva=" << ar.rva << ", length=" << ar.length << ")"; 68 return os; 69 } 70 71 namespace { 72 73 OMAP CreateOmap(DWORD rva, DWORD rvaTo) { 74 OMAP o = { rva, rvaTo }; 75 return o; 76 } 77 78 MappedRange CreateMappedRange(DWORD rva_original, 79 DWORD rva_transformed, 80 DWORD length, 81 DWORD injected, 82 DWORD removed) { 83 MappedRange mr = { rva_original, rva_transformed, length, injected, removed }; 84 return mr; 85 } 86 87 EndpointIndex CreateEndpointIndex(DWORD endpoint, size_t index) { 88 EndpointIndex ei = { endpoint, index }; 89 return ei; 90 } 91 92 // (C is removed) 93 // Original : A B C D E F G H 94 // Transformed: A B D F E * H1 G1 G2 H2 95 // (* is injected, G is copied, H is split) 96 // A is implied. 97 98 // Layout of the original image. 99 const AddressRange B(100, 15); 100 const AddressRange C(B.end(), 10); 101 const AddressRange D(C.end(), 25); 102 const AddressRange E(D.end(), 10); 103 const AddressRange F(E.end(), 40); 104 const AddressRange G(F.end(), 3); 105 const AddressRange H(G.end(), 7); 106 107 // Layout of the transformed image. 108 const AddressRange Bt(100, 15); 109 const AddressRange Dt(Bt.end(), 20); // D is shortened. 110 const AddressRange Ft(Dt.end(), F.length); 111 const AddressRange Et(Ft.end(), E.length); 112 const AddressRange injected(Et.end(), 5); 113 const AddressRange H1t(injected.end(), 4); // H is split. 114 const AddressRange G1t(H1t.end(), G.length); // G is copied. 115 const AddressRange G2t(G1t.end(), G.length); // G is copied. 116 const AddressRange H2t(G2t.end(), 3); // H is split. 117 118 class BuildImageMapTest : public testing::Test { 119 public: 120 static const DWORD kInvalidAddress = 0xFFFFFFFF; 121 122 void InitOmapData() { 123 omap_data.length_original = H.end(); 124 125 // Build the OMAPTO vector (from transformed to original). 126 omap_data.omap_to.push_back(CreateOmap(Bt.rva, B.rva)); 127 omap_data.omap_to.push_back(CreateOmap(Dt.rva, D.rva)); 128 omap_data.omap_to.push_back(CreateOmap(Ft.rva, F.rva)); 129 omap_data.omap_to.push_back(CreateOmap(Et.rva, E.rva)); 130 omap_data.omap_to.push_back(CreateOmap(injected.rva, kInvalidAddress)); 131 omap_data.omap_to.push_back(CreateOmap(H1t.rva, H.rva)); 132 omap_data.omap_to.push_back(CreateOmap(G1t.rva, G.rva)); 133 omap_data.omap_to.push_back(CreateOmap(G2t.rva, G.rva)); 134 omap_data.omap_to.push_back(CreateOmap(H2t.rva, H.rva + H1t.length)); 135 omap_data.omap_to.push_back(CreateOmap(H2t.end(), kInvalidAddress)); 136 137 // Build the OMAPFROM vector (from original to transformed). 138 omap_data.omap_from.push_back(CreateOmap(B.rva, Bt.rva)); 139 omap_data.omap_from.push_back(CreateOmap(C.rva, kInvalidAddress)); 140 omap_data.omap_from.push_back(CreateOmap(D.rva, Dt.rva)); 141 omap_data.omap_from.push_back(CreateOmap(E.rva, Et.rva)); 142 omap_data.omap_from.push_back(CreateOmap(F.rva, Ft.rva)); 143 omap_data.omap_from.push_back(CreateOmap(G.rva, G1t.rva)); 144 omap_data.omap_from.push_back(CreateOmap(H.rva, H1t.rva)); 145 omap_data.omap_from.push_back(CreateOmap(H.rva + H1t.length, H2t.rva)); 146 omap_data.omap_from.push_back(CreateOmap(H.end(), kInvalidAddress)); 147 } 148 149 OmapData omap_data; 150 }; 151 152 } // namespace 153 154 TEST_F(BuildImageMapTest, EmptyImageMapOnEmptyOmapData) { 155 ASSERT_EQ(0u, omap_data.omap_from.size()); 156 ASSERT_EQ(0u, omap_data.omap_to.size()); 157 ASSERT_EQ(0u, omap_data.length_original); 158 159 ImageMap image_map; 160 BuildImageMap(omap_data, &image_map); 161 EXPECT_EQ(0u, image_map.mapping.size()); 162 EXPECT_EQ(0u, image_map.endpoint_index_map.size()); 163 } 164 165 TEST_F(BuildImageMapTest, ImageMapIsCorrect) { 166 InitOmapData(); 167 ASSERT_LE(0u, omap_data.omap_from.size()); 168 ASSERT_LE(0u, omap_data.omap_to.size()); 169 ASSERT_LE(0u, omap_data.length_original); 170 171 ImageMap image_map; 172 BuildImageMap(omap_data, &image_map); 173 EXPECT_LE(9u, image_map.mapping.size()); 174 EXPECT_LE(9u, image_map.endpoint_index_map.size()); 175 176 Mapping mapping; 177 mapping.push_back(CreateMappedRange(0, 0, B.rva, 0, 0)); 178 // C is removed, and it originally comes immediately after B. 179 mapping.push_back(CreateMappedRange(B.rva, Bt.rva, B.length, 0, C.length)); 180 // D is shortened by a length of 5. 181 mapping.push_back(CreateMappedRange(D.rva, Dt.rva, Dt.length, 0, 5)); 182 // The injected content comes immediately after E in the transformed image. 183 mapping.push_back(CreateMappedRange(E.rva, Et.rva, E.length, injected.length, 184 0)); 185 mapping.push_back(CreateMappedRange(F.rva, Ft.rva, F.length, 0, 0)); 186 // G is copied so creates two entries. 187 mapping.push_back(CreateMappedRange(G.rva, G1t.rva, G.length, 0, 0)); 188 mapping.push_back(CreateMappedRange(G.rva, G2t.rva, G.length, 0, 0)); 189 // H is split, so create two entries. 190 mapping.push_back(CreateMappedRange(H.rva, H1t.rva, H1t.length, 0, 0)); 191 mapping.push_back(CreateMappedRange(H.rva + H1t.length, H2t.rva, H2t.length, 192 0, 0)); 193 EXPECT_THAT(mapping, 194 testing::ContainerEq(image_map.mapping)); 195 196 EndpointIndexMap endpoint_index_map; 197 endpoint_index_map.push_back(CreateEndpointIndex(0, 0)); 198 endpoint_index_map.push_back(CreateEndpointIndex(B.rva, 1)); 199 endpoint_index_map.push_back(CreateEndpointIndex(D.rva, 2)); 200 endpoint_index_map.push_back(CreateEndpointIndex(E.rva, 3)); 201 endpoint_index_map.push_back(CreateEndpointIndex(F.rva, 4)); 202 // G is duplicated so 2 ranges map back to it, hence the skip from 5 to 7. 203 endpoint_index_map.push_back(CreateEndpointIndex(G.rva, 5)); 204 // H is split so we expect 2 endpoints to show up attributed to it. 205 endpoint_index_map.push_back(CreateEndpointIndex(H.rva, 7)); 206 endpoint_index_map.push_back(CreateEndpointIndex(H.rva + H1t.length, 8)); 207 endpoint_index_map.push_back(CreateEndpointIndex(H.end(), 9)); 208 EXPECT_THAT(endpoint_index_map, 209 testing::ContainerEq(image_map.endpoint_index_map)); 210 } 211 212 namespace { 213 214 class MapAddressRangeTest : public BuildImageMapTest { 215 public: 216 typedef BuildImageMapTest Super; 217 virtual void SetUp() { 218 Super::SetUp(); 219 InitOmapData(); 220 BuildImageMap(omap_data, &image_map); 221 } 222 223 ImageMap image_map; 224 225 private: 226 using BuildImageMapTest::InitOmapData; 227 using BuildImageMapTest::omap_data; 228 }; 229 230 } // namespace 231 232 TEST_F(MapAddressRangeTest, EmptyImageMapReturnsIdentity) { 233 ImageMap im; 234 AddressRangeVector mapped_ranges; 235 AddressRange ar(0, 1024); 236 MapAddressRange(im, ar, &mapped_ranges); 237 EXPECT_EQ(1u, mapped_ranges.size()); 238 EXPECT_EQ(ar, mapped_ranges[0]); 239 } 240 241 TEST_F(MapAddressRangeTest, MapOutOfImage) { 242 AddressRangeVector mapped_ranges; 243 MapAddressRange(image_map, AddressRange(H.end() + 10, 10), &mapped_ranges); 244 EXPECT_EQ(0u, mapped_ranges.size()); 245 } 246 247 TEST_F(MapAddressRangeTest, MapIdentity) { 248 AddressRangeVector mapped_ranges; 249 MapAddressRange(image_map, B, &mapped_ranges); 250 EXPECT_EQ(1u, mapped_ranges.size()); 251 EXPECT_THAT(mapped_ranges, testing::ElementsAre(B)); 252 } 253 254 TEST_F(MapAddressRangeTest, MapReorderedContiguous) { 255 AddressRangeVector mapped_ranges; 256 257 AddressRange DEF(D.rva, F.end() - D.rva); 258 MapAddressRange(image_map, DEF, &mapped_ranges); 259 EXPECT_EQ(1u, mapped_ranges.size()); 260 261 AddressRange DFEt(Dt.rva, Et.end() - Dt.rva); 262 EXPECT_THAT(mapped_ranges, testing::ElementsAre(DFEt)); 263 } 264 265 TEST_F(MapAddressRangeTest, MapEmptySingle) { 266 AddressRangeVector mapped_ranges; 267 MapAddressRange(image_map, AddressRange(D.rva, 0), &mapped_ranges); 268 EXPECT_EQ(1u, mapped_ranges.size()); 269 EXPECT_THAT(mapped_ranges, testing::ElementsAre(AddressRange(Dt.rva, 0))); 270 } 271 272 TEST_F(MapAddressRangeTest, MapEmptyCopied) { 273 AddressRangeVector mapped_ranges; 274 MapAddressRange(image_map, AddressRange(G.rva, 0), &mapped_ranges); 275 EXPECT_EQ(2u, mapped_ranges.size()); 276 EXPECT_THAT(mapped_ranges, testing::ElementsAre(AddressRange(G1t.rva, 0), 277 AddressRange(G2t.rva, 0))); 278 } 279 280 TEST_F(MapAddressRangeTest, MapCopiedContiguous) { 281 AddressRangeVector mapped_ranges; 282 MapAddressRange(image_map, G, &mapped_ranges); 283 EXPECT_EQ(1u, mapped_ranges.size()); 284 EXPECT_THAT(mapped_ranges, testing::ElementsAre( 285 AddressRange(G1t.rva, G2t.end() - G1t.rva))); 286 } 287 288 TEST_F(MapAddressRangeTest, MapSplitDiscontiguous) { 289 AddressRangeVector mapped_ranges; 290 MapAddressRange(image_map, H, &mapped_ranges); 291 EXPECT_EQ(2u, mapped_ranges.size()); 292 EXPECT_THAT(mapped_ranges, testing::ElementsAre(H1t, H2t)); 293 } 294 295 TEST_F(MapAddressRangeTest, MapInjected) { 296 AddressRangeVector mapped_ranges; 297 298 AddressRange EFGH(E.rva, H.end() - E.rva); 299 MapAddressRange(image_map, EFGH, &mapped_ranges); 300 EXPECT_EQ(1u, mapped_ranges.size()); 301 302 AddressRange FEHGGHt(Ft.rva, H2t.end() - Ft.rva); 303 EXPECT_THAT(mapped_ranges, testing::ElementsAre(FEHGGHt)); 304 } 305 306 TEST_F(MapAddressRangeTest, MapRemovedEntirely) { 307 AddressRangeVector mapped_ranges; 308 MapAddressRange(image_map, C, &mapped_ranges); 309 EXPECT_EQ(0u, mapped_ranges.size()); 310 } 311 312 TEST_F(MapAddressRangeTest, MapRemovedPartly) { 313 AddressRangeVector mapped_ranges; 314 MapAddressRange(image_map, D, &mapped_ranges); 315 EXPECT_EQ(1u, mapped_ranges.size()); 316 EXPECT_THAT(mapped_ranges, testing::ElementsAre(Dt)); 317 } 318 319 TEST_F(MapAddressRangeTest, MapFull) { 320 AddressRangeVector mapped_ranges; 321 322 AddressRange AH(0, H.end()); 323 MapAddressRange(image_map, AH, &mapped_ranges); 324 EXPECT_EQ(1u, mapped_ranges.size()); 325 326 AddressRange AHt(0, H2t.end()); 327 EXPECT_THAT(mapped_ranges, testing::ElementsAre(AHt)); 328 } 329 330 } // namespace google_breakpad 331