1 : // Copyright 2014 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/unreachable_block_transform.h"
16 :
17 : #include "base/files/scoped_temp_dir.h"
18 : #include "gmock/gmock.h"
19 : #include "gtest/gtest.h"
20 : #include "syzygy/block_graph/block_graph.h"
21 : #include "syzygy/optimize/application_profile.h"
22 : #include "syzygy/pe/pe_transform_policy.h"
23 :
24 : namespace optimize {
25 : namespace transforms {
26 :
27 : namespace {
28 :
29 : using block_graph::BlockGraph;
30 : using pe::ImageLayout;
31 :
32 : // Dummy code body.
33 : const uint8 kCodeBody1[] = { 0x74, 0x02, 0x33, 0xC0, 0xC3 };
34 : const uint8 kCodeBody2[] = { 0x0B, 0xC0, 0x75, 0xFC, 0xC3 };
35 :
36 : class UnreachableBlockTransformTest : public testing::Test {
37 : public:
38 E : UnreachableBlockTransformTest()
39 : : code1_(NULL), code2_(NULL), image_(&block_graph_) {
40 E : }
41 :
42 E : virtual void SetUp() {
43 : code1_ = block_graph_.AddBlock(BlockGraph::CODE_BLOCK,
44 : sizeof(kCodeBody1),
45 E : "code1");
46 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), code1_);
47 E : code1_->SetData(kCodeBody1, code1_->size());
48 :
49 : code2_ = block_graph_.AddBlock(BlockGraph::CODE_BLOCK,
50 : sizeof(kCodeBody2),
51 E : "code2");
52 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), code2_);
53 E : code2_->SetData(kCodeBody2, code2_->size());
54 :
55 : code3_ = block_graph_.AddBlock(BlockGraph::CODE_BLOCK,
56 : sizeof(kCodeBody2),
57 E : "code3");
58 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), code3_);
59 E : code3_->SetData(kCodeBody2, code2_->size());
60 :
61 :
62 : // Add a reference so that code1 is calling code2.
63 : code1_->SetReference(1, BlockGraph::Reference(BlockGraph::RELATIVE_REF,
64 : BlockGraph::Reference::kMaximumSize,
65 E : code2_, 0, 0));
66 :
67 : // Keep track of the original blocks id.
68 E : code1_id_ = code1_->id();
69 E : code2_id_ = code2_->id();
70 E : code3_id_ = code3_->id();
71 E : }
72 :
73 : protected:
74 : pe::PETransformPolicy policy_;
75 : BlockGraph block_graph_;
76 : BlockGraph::Block* code1_;
77 : BlockGraph::Block* code2_;
78 : BlockGraph::Block* code3_;
79 : BlockGraph::BlockId code1_id_;
80 : BlockGraph::BlockId code2_id_;
81 : BlockGraph::BlockId code3_id_;
82 : UnreachableBlockTransform tx_;
83 : ImageLayout image_;
84 : };
85 :
86 : } // namespace
87 :
88 E : TEST_F(UnreachableBlockTransformTest, UnusedBlockFromCode1) {
89 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), code1_);
90 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), code2_);
91 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), code3_);
92 :
93 : // Apply the unreachable transform.
94 E : EXPECT_TRUE(tx_.TransformBlockGraph(&policy_, &block_graph_, code1_));
95 :
96 : // Validates that code1_ and code2_ are still present and code3_ has been
97 : // removed by the transform.
98 E : EXPECT_EQ(code1_, block_graph_.GetBlockById(code1_id_));
99 E : EXPECT_EQ(code2_, block_graph_.GetBlockById(code2_id_));
100 E : EXPECT_EQ(NULL, block_graph_.GetBlockById(code3_id_));
101 E : }
102 :
103 E : TEST_F(UnreachableBlockTransformTest, UnusedBlockFromCode3) {
104 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), code1_);
105 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), code2_);
106 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), code3_);
107 :
108 : // Apply the unreachable transform.
109 E : EXPECT_TRUE(tx_.TransformBlockGraph(&policy_, &block_graph_, code3_));
110 :
111 : // Validates that code3_ is still present and other blocks have been
112 : // removed by the transform.
113 E : EXPECT_EQ(NULL, block_graph_.GetBlockById(code1_id_));
114 E : EXPECT_EQ(NULL, block_graph_.GetBlockById(code2_id_));
115 E : EXPECT_EQ(code3_, block_graph_.GetBlockById(code3_id_));
116 E : }
117 :
118 E : TEST_F(UnreachableBlockTransformTest, UsedPEParsedBlock) {
119 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), code1_);
120 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), code2_);
121 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), code3_);
122 :
123 : // Set code3_ as a root.
124 E : code3_->set_attribute(BlockGraph::PE_PARSED);
125 :
126 : // Apply the unreachable transform.
127 E : EXPECT_TRUE(tx_.TransformBlockGraph(&policy_, &block_graph_, code1_));
128 :
129 : // Validates that all blocks are still present.
130 E : EXPECT_EQ(code1_, block_graph_.GetBlockById(code1_id_));
131 E : EXPECT_EQ(code2_, block_graph_.GetBlockById(code2_id_));
132 E : EXPECT_EQ(code3_, block_graph_.GetBlockById(code3_id_));
133 E : }
134 :
135 E : TEST_F(UnreachableBlockTransformTest, UnreachableGraphProduced) {
136 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), code1_);
137 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), code2_);
138 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), code3_);
139 :
140 : // Set the target path to dump the unreachable graph.
141 E : base::ScopedTempDir temp_dir;
142 E : EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
143 E : base::FilePath temp_path = temp_dir.path().Append(L"deadcode.cachegrind");
144 E : tx_.set_unreachable_graph_path(temp_path);
145 :
146 : // Apply the unreachable transform.
147 E : EXPECT_TRUE(tx_.TransformBlockGraph(&policy_, &block_graph_, code1_));
148 :
149 : // Read the contents of the produced file.
150 E : std::string contents;
151 E : base::ReadFileToString(temp_path, &contents);
152 :
153 : // Validate the output.
154 E : const char expected[] = "events: Size Count\nob=\nfn=code3\n3 5 1\n\n";
155 E : EXPECT_STREQ(expected, contents.c_str());
156 E : }
157 :
158 :
159 : } // namespace transforms
160 : } // namespace optimize
|