mirror of
https://git.suyu.dev/suyu/breakpad.git
synced 2026-02-13 07:13:02 +00:00
The Windows build has rotted a bit with the gtest/gmock updates. Update all of the paths to fix things up again. Change-Id: Id67ce76abfd331c0543aa4bd1138e9cc13a18c75 Reviewed-on: https://chromium-review.googlesource.com/441584 Reviewed-by: Mark Mentovai <mark@chromium.org>
330 lines
12 KiB
C++
330 lines
12 KiB
C++
// Copyright 2013 Google Inc. All rights reserved.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions are
|
|
// met:
|
|
//
|
|
// * Redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
// * Redistributions in binary form must reproduce the above
|
|
// copyright notice, this list of conditions and the following disclaimer
|
|
// in the documentation and/or other materials provided with the
|
|
// distribution.
|
|
// * Neither the name of Google Inc. nor the names of its
|
|
// contributors may be used to endorse or promote products derived from
|
|
// this software without specific prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
// Unittests for OMAP related functions.
|
|
|
|
#include "common/windows/omap.h"
|
|
|
|
#include "breakpad_googletest_includes.h"
|
|
|
|
namespace google_breakpad {
|
|
|
|
// Equality operators for ContainerEq. These must be outside of the anonymous
|
|
// namespace in order for them to be found.
|
|
bool operator==(const MappedRange& mr1, const MappedRange& mr2) {
|
|
return mr1.rva_original == mr2.rva_original &&
|
|
mr1.rva_transformed == mr2.rva_transformed &&
|
|
mr1.length == mr2.length &&
|
|
mr1.injected == mr2.injected &&
|
|
mr1.removed == mr2.removed;
|
|
}
|
|
bool operator==(const EndpointIndex& ei1, const EndpointIndex& ei2) {
|
|
return ei1.endpoint == ei2.endpoint && ei1.index == ei2.index;
|
|
}
|
|
|
|
// Pretty printers for more meaningful error messages. Also need to be outside
|
|
// the anonymous namespace.
|
|
std::ostream& operator<<(std::ostream& os, const MappedRange& mr) {
|
|
os << "MappedRange(rva_original=" << mr.rva_original
|
|
<< ", rva_transformed=" << mr.rva_transformed
|
|
<< ", length=" << mr.length
|
|
<< ", injected=" << mr.injected
|
|
<< ", removed=" << mr.removed << ")";
|
|
return os;
|
|
}
|
|
std::ostream& operator<<(std::ostream& os, const EndpointIndex& ei) {
|
|
os << "EndpointIndex(endpoint=" << ei.endpoint
|
|
<< ", index=" << ei.index << ")";
|
|
return os;
|
|
}
|
|
std::ostream& operator<<(std::ostream& os, const AddressRange& ar) {
|
|
os << "AddressRange(rva=" << ar.rva << ", length=" << ar.length << ")";
|
|
return os;
|
|
}
|
|
|
|
namespace {
|
|
|
|
OMAP CreateOmap(DWORD rva, DWORD rvaTo) {
|
|
OMAP o = { rva, rvaTo };
|
|
return o;
|
|
}
|
|
|
|
MappedRange CreateMappedRange(DWORD rva_original,
|
|
DWORD rva_transformed,
|
|
DWORD length,
|
|
DWORD injected,
|
|
DWORD removed) {
|
|
MappedRange mr = { rva_original, rva_transformed, length, injected, removed };
|
|
return mr;
|
|
}
|
|
|
|
EndpointIndex CreateEndpointIndex(DWORD endpoint, size_t index) {
|
|
EndpointIndex ei = { endpoint, index };
|
|
return ei;
|
|
}
|
|
|
|
// (C is removed)
|
|
// Original : A B C D E F G H
|
|
// Transformed: A B D F E * H1 G1 G2 H2
|
|
// (* is injected, G is copied, H is split)
|
|
// A is implied.
|
|
|
|
// Layout of the original image.
|
|
const AddressRange B(100, 15);
|
|
const AddressRange C(B.end(), 10);
|
|
const AddressRange D(C.end(), 25);
|
|
const AddressRange E(D.end(), 10);
|
|
const AddressRange F(E.end(), 40);
|
|
const AddressRange G(F.end(), 3);
|
|
const AddressRange H(G.end(), 7);
|
|
|
|
// Layout of the transformed image.
|
|
const AddressRange Bt(100, 15);
|
|
const AddressRange Dt(Bt.end(), 20); // D is shortened.
|
|
const AddressRange Ft(Dt.end(), F.length);
|
|
const AddressRange Et(Ft.end(), E.length);
|
|
const AddressRange injected(Et.end(), 5);
|
|
const AddressRange H1t(injected.end(), 4); // H is split.
|
|
const AddressRange G1t(H1t.end(), G.length); // G is copied.
|
|
const AddressRange G2t(G1t.end(), G.length); // G is copied.
|
|
const AddressRange H2t(G2t.end(), 3); // H is split.
|
|
|
|
class BuildImageMapTest : public testing::Test {
|
|
public:
|
|
static const DWORD kInvalidAddress = 0xFFFFFFFF;
|
|
|
|
void InitOmapData() {
|
|
omap_data.length_original = H.end();
|
|
|
|
// Build the OMAPTO vector (from transformed to original).
|
|
omap_data.omap_to.push_back(CreateOmap(Bt.rva, B.rva));
|
|
omap_data.omap_to.push_back(CreateOmap(Dt.rva, D.rva));
|
|
omap_data.omap_to.push_back(CreateOmap(Ft.rva, F.rva));
|
|
omap_data.omap_to.push_back(CreateOmap(Et.rva, E.rva));
|
|
omap_data.omap_to.push_back(CreateOmap(injected.rva, kInvalidAddress));
|
|
omap_data.omap_to.push_back(CreateOmap(H1t.rva, H.rva));
|
|
omap_data.omap_to.push_back(CreateOmap(G1t.rva, G.rva));
|
|
omap_data.omap_to.push_back(CreateOmap(G2t.rva, G.rva));
|
|
omap_data.omap_to.push_back(CreateOmap(H2t.rva, H.rva + H1t.length));
|
|
omap_data.omap_to.push_back(CreateOmap(H2t.end(), kInvalidAddress));
|
|
|
|
// Build the OMAPFROM vector (from original to transformed).
|
|
omap_data.omap_from.push_back(CreateOmap(B.rva, Bt.rva));
|
|
omap_data.omap_from.push_back(CreateOmap(C.rva, kInvalidAddress));
|
|
omap_data.omap_from.push_back(CreateOmap(D.rva, Dt.rva));
|
|
omap_data.omap_from.push_back(CreateOmap(E.rva, Et.rva));
|
|
omap_data.omap_from.push_back(CreateOmap(F.rva, Ft.rva));
|
|
omap_data.omap_from.push_back(CreateOmap(G.rva, G1t.rva));
|
|
omap_data.omap_from.push_back(CreateOmap(H.rva, H1t.rva));
|
|
omap_data.omap_from.push_back(CreateOmap(H.rva + H1t.length, H2t.rva));
|
|
omap_data.omap_from.push_back(CreateOmap(H.end(), kInvalidAddress));
|
|
}
|
|
|
|
OmapData omap_data;
|
|
};
|
|
|
|
} // namespace
|
|
|
|
TEST_F(BuildImageMapTest, EmptyImageMapOnEmptyOmapData) {
|
|
ASSERT_EQ(0u, omap_data.omap_from.size());
|
|
ASSERT_EQ(0u, omap_data.omap_to.size());
|
|
ASSERT_EQ(0u, omap_data.length_original);
|
|
|
|
ImageMap image_map;
|
|
BuildImageMap(omap_data, &image_map);
|
|
EXPECT_EQ(0u, image_map.mapping.size());
|
|
EXPECT_EQ(0u, image_map.endpoint_index_map.size());
|
|
}
|
|
|
|
TEST_F(BuildImageMapTest, ImageMapIsCorrect) {
|
|
InitOmapData();
|
|
ASSERT_LE(0u, omap_data.omap_from.size());
|
|
ASSERT_LE(0u, omap_data.omap_to.size());
|
|
ASSERT_LE(0u, omap_data.length_original);
|
|
|
|
ImageMap image_map;
|
|
BuildImageMap(omap_data, &image_map);
|
|
EXPECT_LE(9u, image_map.mapping.size());
|
|
EXPECT_LE(9u, image_map.endpoint_index_map.size());
|
|
|
|
Mapping mapping;
|
|
mapping.push_back(CreateMappedRange(0, 0, B.rva, 0, 0));
|
|
// C is removed, and it originally comes immediately after B.
|
|
mapping.push_back(CreateMappedRange(B.rva, Bt.rva, B.length, 0, C.length));
|
|
// D is shortened by a length of 5.
|
|
mapping.push_back(CreateMappedRange(D.rva, Dt.rva, Dt.length, 0, 5));
|
|
// The injected content comes immediately after E in the transformed image.
|
|
mapping.push_back(CreateMappedRange(E.rva, Et.rva, E.length, injected.length,
|
|
0));
|
|
mapping.push_back(CreateMappedRange(F.rva, Ft.rva, F.length, 0, 0));
|
|
// G is copied so creates two entries.
|
|
mapping.push_back(CreateMappedRange(G.rva, G1t.rva, G.length, 0, 0));
|
|
mapping.push_back(CreateMappedRange(G.rva, G2t.rva, G.length, 0, 0));
|
|
// H is split, so create two entries.
|
|
mapping.push_back(CreateMappedRange(H.rva, H1t.rva, H1t.length, 0, 0));
|
|
mapping.push_back(CreateMappedRange(H.rva + H1t.length, H2t.rva, H2t.length,
|
|
0, 0));
|
|
EXPECT_THAT(mapping,
|
|
testing::ContainerEq(image_map.mapping));
|
|
|
|
EndpointIndexMap endpoint_index_map;
|
|
endpoint_index_map.push_back(CreateEndpointIndex(0, 0));
|
|
endpoint_index_map.push_back(CreateEndpointIndex(B.rva, 1));
|
|
endpoint_index_map.push_back(CreateEndpointIndex(D.rva, 2));
|
|
endpoint_index_map.push_back(CreateEndpointIndex(E.rva, 3));
|
|
endpoint_index_map.push_back(CreateEndpointIndex(F.rva, 4));
|
|
// G is duplicated so 2 ranges map back to it, hence the skip from 5 to 7.
|
|
endpoint_index_map.push_back(CreateEndpointIndex(G.rva, 5));
|
|
// H is split so we expect 2 endpoints to show up attributed to it.
|
|
endpoint_index_map.push_back(CreateEndpointIndex(H.rva, 7));
|
|
endpoint_index_map.push_back(CreateEndpointIndex(H.rva + H1t.length, 8));
|
|
endpoint_index_map.push_back(CreateEndpointIndex(H.end(), 9));
|
|
EXPECT_THAT(endpoint_index_map,
|
|
testing::ContainerEq(image_map.endpoint_index_map));
|
|
}
|
|
|
|
namespace {
|
|
|
|
class MapAddressRangeTest : public BuildImageMapTest {
|
|
public:
|
|
typedef BuildImageMapTest Super;
|
|
virtual void SetUp() {
|
|
Super::SetUp();
|
|
InitOmapData();
|
|
BuildImageMap(omap_data, &image_map);
|
|
}
|
|
|
|
ImageMap image_map;
|
|
|
|
private:
|
|
using BuildImageMapTest::InitOmapData;
|
|
using BuildImageMapTest::omap_data;
|
|
};
|
|
|
|
} // namespace
|
|
|
|
TEST_F(MapAddressRangeTest, EmptyImageMapReturnsIdentity) {
|
|
ImageMap im;
|
|
AddressRangeVector mapped_ranges;
|
|
AddressRange ar(0, 1024);
|
|
MapAddressRange(im, ar, &mapped_ranges);
|
|
EXPECT_EQ(1u, mapped_ranges.size());
|
|
EXPECT_EQ(ar, mapped_ranges[0]);
|
|
}
|
|
|
|
TEST_F(MapAddressRangeTest, MapOutOfImage) {
|
|
AddressRangeVector mapped_ranges;
|
|
MapAddressRange(image_map, AddressRange(H.end() + 10, 10), &mapped_ranges);
|
|
EXPECT_EQ(0u, mapped_ranges.size());
|
|
}
|
|
|
|
TEST_F(MapAddressRangeTest, MapIdentity) {
|
|
AddressRangeVector mapped_ranges;
|
|
MapAddressRange(image_map, B, &mapped_ranges);
|
|
EXPECT_EQ(1u, mapped_ranges.size());
|
|
EXPECT_THAT(mapped_ranges, testing::ElementsAre(B));
|
|
}
|
|
|
|
TEST_F(MapAddressRangeTest, MapReorderedContiguous) {
|
|
AddressRangeVector mapped_ranges;
|
|
|
|
AddressRange DEF(D.rva, F.end() - D.rva);
|
|
MapAddressRange(image_map, DEF, &mapped_ranges);
|
|
EXPECT_EQ(1u, mapped_ranges.size());
|
|
|
|
AddressRange DFEt(Dt.rva, Et.end() - Dt.rva);
|
|
EXPECT_THAT(mapped_ranges, testing::ElementsAre(DFEt));
|
|
}
|
|
|
|
TEST_F(MapAddressRangeTest, MapEmptySingle) {
|
|
AddressRangeVector mapped_ranges;
|
|
MapAddressRange(image_map, AddressRange(D.rva, 0), &mapped_ranges);
|
|
EXPECT_EQ(1u, mapped_ranges.size());
|
|
EXPECT_THAT(mapped_ranges, testing::ElementsAre(AddressRange(Dt.rva, 0)));
|
|
}
|
|
|
|
TEST_F(MapAddressRangeTest, MapEmptyCopied) {
|
|
AddressRangeVector mapped_ranges;
|
|
MapAddressRange(image_map, AddressRange(G.rva, 0), &mapped_ranges);
|
|
EXPECT_EQ(2u, mapped_ranges.size());
|
|
EXPECT_THAT(mapped_ranges, testing::ElementsAre(AddressRange(G1t.rva, 0),
|
|
AddressRange(G2t.rva, 0)));
|
|
}
|
|
|
|
TEST_F(MapAddressRangeTest, MapCopiedContiguous) {
|
|
AddressRangeVector mapped_ranges;
|
|
MapAddressRange(image_map, G, &mapped_ranges);
|
|
EXPECT_EQ(1u, mapped_ranges.size());
|
|
EXPECT_THAT(mapped_ranges, testing::ElementsAre(
|
|
AddressRange(G1t.rva, G2t.end() - G1t.rva)));
|
|
}
|
|
|
|
TEST_F(MapAddressRangeTest, MapSplitDiscontiguous) {
|
|
AddressRangeVector mapped_ranges;
|
|
MapAddressRange(image_map, H, &mapped_ranges);
|
|
EXPECT_EQ(2u, mapped_ranges.size());
|
|
EXPECT_THAT(mapped_ranges, testing::ElementsAre(H1t, H2t));
|
|
}
|
|
|
|
TEST_F(MapAddressRangeTest, MapInjected) {
|
|
AddressRangeVector mapped_ranges;
|
|
|
|
AddressRange EFGH(E.rva, H.end() - E.rva);
|
|
MapAddressRange(image_map, EFGH, &mapped_ranges);
|
|
EXPECT_EQ(1u, mapped_ranges.size());
|
|
|
|
AddressRange FEHGGHt(Ft.rva, H2t.end() - Ft.rva);
|
|
EXPECT_THAT(mapped_ranges, testing::ElementsAre(FEHGGHt));
|
|
}
|
|
|
|
TEST_F(MapAddressRangeTest, MapRemovedEntirely) {
|
|
AddressRangeVector mapped_ranges;
|
|
MapAddressRange(image_map, C, &mapped_ranges);
|
|
EXPECT_EQ(0u, mapped_ranges.size());
|
|
}
|
|
|
|
TEST_F(MapAddressRangeTest, MapRemovedPartly) {
|
|
AddressRangeVector mapped_ranges;
|
|
MapAddressRange(image_map, D, &mapped_ranges);
|
|
EXPECT_EQ(1u, mapped_ranges.size());
|
|
EXPECT_THAT(mapped_ranges, testing::ElementsAre(Dt));
|
|
}
|
|
|
|
TEST_F(MapAddressRangeTest, MapFull) {
|
|
AddressRangeVector mapped_ranges;
|
|
|
|
AddressRange AH(0, H.end());
|
|
MapAddressRange(image_map, AH, &mapped_ranges);
|
|
EXPECT_EQ(1u, mapped_ranges.size());
|
|
|
|
AddressRange AHt(0, H2t.end());
|
|
EXPECT_THAT(mapped_ranges, testing::ElementsAre(AHt));
|
|
}
|
|
|
|
} // namespace google_breakpad
|