Home | History | Annotate | Download | only in windows
      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