1 : // Copyright 2013 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : #include "syzygy/optimize/transforms/chained_subgraph_transforms.h"
16 :
17 : #include "gmock/gmock.h"
18 : #include "gtest/gtest.h"
19 : #include "syzygy/block_graph/basic_block.h"
20 : #include "syzygy/block_graph/basic_block_subgraph.h"
21 : #include "syzygy/optimize/application_profile.h"
22 : #include "syzygy/pe/pe_transform_policy.h"
23 :
24 : namespace optimize {
25 : namespace transforms {
26 : namespace {
27 :
28 : using block_graph::BlockGraph;
29 : using block_graph::BasicBlockSubGraph;
30 : using optimize::transforms::ChainedSubgraphTransforms;
31 : using pe::ImageLayout;
32 : using testing::_;
33 : using testing::NotNull;
34 : using testing::Property;
35 : using testing::Return;
36 :
37 : // _asm ret
38 : const uint8 kCodeRet[] = { 0xC3 };
39 :
40 : // Dummy data.
41 : const uint8 kData[] = { 0x01, 0x02, 0x03, 0x04 };
42 :
43 : class MockSubGraphTransformInterface : public SubGraphTransformInterface {
44 : public:
45 : MOCK_METHOD5(TransformBasicBlockSubGraph,
46 : bool(const TransformPolicyInterface*,
47 : BlockGraph*,
48 : BasicBlockSubGraph*,
49 : ApplicationProfile*,
50 E : SubGraphProfile*));
51 : };
52 :
53 : class TestChainedBasicBlockTransforms: public ChainedSubgraphTransforms {
54 : public:
55 E : explicit TestChainedBasicBlockTransforms(ApplicationProfile* profile)
56 : : ChainedSubgraphTransforms(profile) {
57 E : }
58 :
59 : using ChainedSubgraphTransforms::profile_;
60 : using ChainedSubgraphTransforms::transforms_;
61 : };
62 :
63 : class ChainedSubgraphTransformsTest : public testing::Test {
64 : public:
65 E : ChainedSubgraphTransformsTest()
66 : : block_header_(NULL), image_(&block_graph_), profile_(&image_) {
67 E : }
68 :
69 E : virtual void SetUp() {
70 : // Create the blocks.
71 : block1_ =
72 E : block_graph_.AddBlock(BlockGraph::CODE_BLOCK, sizeof(kCodeRet), "b1");
73 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), block1_);
74 E : block1_->SetData(kCodeRet, sizeof(kCodeRet));
75 E : block1_->SetLabel(0, "code", BlockGraph::CODE_LABEL);
76 :
77 : block2_ =
78 E : block_graph_.AddBlock(BlockGraph::CODE_BLOCK, sizeof(kCodeRet), "b2");
79 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), block2_);
80 E : block2_->SetData(kCodeRet, sizeof(kCodeRet));
81 E : block2_->SetLabel(0, "code", BlockGraph::CODE_LABEL);
82 :
83 : block3_ =
84 E : block_graph_.AddBlock(BlockGraph::CODE_BLOCK, sizeof(kCodeRet), "b3");
85 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), block3_);
86 E : block3_->SetData(kCodeRet, sizeof(kCodeRet));
87 E : block3_->SetLabel(0, "code", BlockGraph::CODE_LABEL);
88 :
89 : block_header_ = block_graph_.AddBlock(BlockGraph::DATA_BLOCK,
90 : sizeof(kData),
91 E : "header");
92 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), block_header_);
93 E : block_header_->SetData(kData, sizeof(kData));
94 :
95 : // Create the text section.
96 E : BlockGraph::Section* section = block_graph_.AddSection(".text", 0);
97 E : pe::ImageLayout::SectionInfo section_info = {};
98 E : section_info.name = section->name();
99 E : section_info.addr = core::RelativeAddress(0x1000);
100 E : section_info.size = 0x1000;
101 E : section_info.data_size = 0x1000;
102 E : image_.sections.push_back(section_info);
103 :
104 : // Create the layout information.
105 E : block_header_->set_section(section->id());
106 E : block1_->set_section(section->id());
107 E : block2_->set_section(section->id());
108 E : block3_->set_section(section->id());
109 E : image_.blocks.InsertBlock(section_info.addr, block_header_);
110 E : image_.blocks.InsertBlock(section_info.addr + 100, block1_);
111 E : image_.blocks.InsertBlock(section_info.addr + 200, block2_);
112 E : image_.blocks.InsertBlock(section_info.addr + 300, block3_);
113 E : }
114 :
115 : protected:
116 : pe::PETransformPolicy policy_;
117 : BlockGraph block_graph_;
118 : BlockGraph::Block* block_header_;
119 : BlockGraph::Block* block1_;
120 : BlockGraph::Block* block2_;
121 : BlockGraph::Block* block3_;
122 : ImageLayout image_;
123 : ApplicationProfile profile_;
124 : scoped_ptr<SubGraphProfile> subgraph_profile_;
125 : };
126 :
127 : } // namespace
128 :
129 E : TEST_F(ChainedSubgraphTransformsTest, Constructor) {
130 E : TestChainedBasicBlockTransforms tx(&profile_);
131 E : EXPECT_EQ(&profile_, tx.profile_);
132 E : }
133 :
134 E : TEST_F(ChainedSubgraphTransformsTest, TransformBlockGraphWithoutTransforms) {
135 E : TestChainedBasicBlockTransforms tx(&profile_);
136 : ASSERT_TRUE(
137 E : ApplyBlockGraphTransform(&tx, &policy_, &block_graph_, block_header_));
138 E : }
139 :
140 E : TEST_F(ChainedSubgraphTransformsTest, TransformBlockGraph) {
141 E : TestChainedBasicBlockTransforms tx(&profile_);
142 E : MockSubGraphTransformInterface transform1;
143 E : MockSubGraphTransformInterface transform2;
144 E : tx.AppendTransform(&transform1);
145 E : tx.AppendTransform(&transform2);
146 :
147 : // Expect each transform to be applied to each block.
148 E : BlockGraph::Block* blocks[] = { block1_, block2_, block3_ };
149 E : MockSubGraphTransformInterface* transforms[] = { &transform1, &transform2 };
150 :
151 E : for (size_t i = 0; i < arraysize(blocks); ++i) {
152 E : for (size_t j = 0; j < arraysize(transforms); ++j) {
153 : EXPECT_CALL(
154 : *transforms[j],
155 : TransformBasicBlockSubGraph(&policy_,
156 : &block_graph_,
157 : Property(
158 : &BasicBlockSubGraph::original_block,
159 : blocks[i]),
160 : &profile_,
161 : NotNull()))
162 E : .WillOnce(Return(true));
163 E : }
164 E : }
165 :
166 : ASSERT_TRUE(
167 E : ApplyBlockGraphTransform(&tx, &policy_, &block_graph_, block_header_));
168 E : }
169 :
170 : } // namespace transforms
171 : } // namespace optimize
|