1 : // Copyright 2015 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/instrument/instrumenters/flummox_instrumenter.h"
16 :
17 : #include "base/command_line.h"
18 : #include "gtest/gtest.h"
19 : #include "syzygy/core/unittest_util.h"
20 : #include "syzygy/pe/unittest_util.h"
21 :
22 : namespace instrument {
23 : namespace instrumenters {
24 :
25 : namespace {
26 :
27 : static wchar_t kFlummoxConfigGoodPath[] =
28 : L"syzygy\\instrument\\test_data\\flummox-config-good.json";
29 :
30 : class TestFlummoxConfig : public FlummoxInstrumenter::FlummoxConfig {
31 : };
32 :
33 : class TestFlummoxInstrumenter : public FlummoxInstrumenter {
34 : public:
35 : using FlummoxInstrumenter::input_image_path_;
36 : using FlummoxInstrumenter::input_pdb_path_;
37 : using FlummoxInstrumenter::output_image_path_;
38 : using FlummoxInstrumenter::output_pdb_path_;
39 : using FlummoxInstrumenter::flummox_config_path_;
40 : using FlummoxInstrumenter::allow_overwrite_;
41 : using FlummoxInstrumenter::no_augment_pdb_;
42 : using FlummoxInstrumenter::no_strip_strings_;
43 : using FlummoxInstrumenter::debug_friendly_;
44 : using FlummoxInstrumenter::flummox_transform_;
45 : using FlummoxInstrumenter::InstrumentPrepare;
46 : using FlummoxInstrumenter::InstrumentImpl;
47 : using FlummoxInstrumenter::CreateRelinker;
48 : };
49 :
50 : class FlummoxInstrumenterTest : public testing::PELibUnitTest {
51 : public:
52 : typedef testing::PELibUnitTest Super;
53 :
54 E : FlummoxInstrumenterTest()
55 : : cmd_line_(base::FilePath(L"instrument.exe")) {
56 E : }
57 :
58 E : void SetUp() override {
59 E : testing::Test::SetUp();
60 :
61 : // Reduce clutter the unittest output.
62 E : logging::SetMinLogLevel(logging::LOG_FATAL);
63 :
64 : // Setup the IO streams.
65 E : CreateTemporaryDir(&temp_dir_);
66 E : stdin_path_ = temp_dir_.Append(L"NUL");
67 E : stdout_path_ = temp_dir_.Append(L"stdout.txt");
68 E : stderr_path_ = temp_dir_.Append(L"stderr.txt");
69 E : InitStreams(stdin_path_, stdout_path_, stderr_path_);
70 :
71 : // Initialize the (potential) input and output path values.
72 E : abs_input_image_path_ = testing::GetExeRelativePath(testing::kTestDllName);
73 E : input_image_path_ = testing::GetRelativePath(abs_input_image_path_);
74 E : abs_input_pdb_path_ = testing::GetExeRelativePath(testing::kTestDllPdbName);
75 E : input_pdb_path_ = testing::GetRelativePath(abs_input_pdb_path_);
76 : abs_flummox_config_path_ =
77 E : testing::GetSrcRelativePath(kFlummoxConfigGoodPath);
78 E : output_image_path_ = temp_dir_.Append(input_image_path_.BaseName());
79 E : output_pdb_path_ = temp_dir_.Append(input_pdb_path_.BaseName());
80 E : flummox_config_path_ = testing::GetRelativePath(abs_flummox_config_path_);
81 E : }
82 :
83 E : void SetUpValidCommandLine() {
84 E : cmd_line_.AppendSwitchPath("input-image", input_image_path_);
85 E : cmd_line_.AppendSwitchPath("output-image", output_image_path_);
86 E : cmd_line_.AppendSwitchPath("flummox-config-path", flummox_config_path_);
87 E : }
88 :
89 : protected:
90 : base::FilePath temp_dir_;
91 :
92 : // @name The redirected streams paths.
93 : // @{
94 : base::FilePath stdin_path_;
95 : base::FilePath stdout_path_;
96 : base::FilePath stderr_path_;
97 : // @}
98 :
99 : // @name Command-line and parameters.
100 : // @{
101 : base::CommandLine cmd_line_;
102 : base::FilePath input_image_path_;
103 : base::FilePath input_pdb_path_;
104 : base::FilePath output_image_path_;
105 : base::FilePath output_pdb_path_;
106 : base::FilePath flummox_config_path_;
107 : // @}
108 :
109 : // @name Expected final values of input parameters.
110 : // @{
111 : base::FilePath abs_input_image_path_;
112 : base::FilePath abs_input_pdb_path_;
113 : base::FilePath abs_flummox_config_path_;
114 : // @}
115 :
116 : // The fake instrumenter we delegate to.
117 : TestFlummoxInstrumenter instrumenter_;
118 : };
119 :
120 : } // namespace
121 :
122 :
123 E : TEST_F(FlummoxInstrumenterTest, ParseTargetListEmpty) {
124 E : TestFlummoxConfig config;
125 E : config.ReadFromJSON("{ \"targets\": {} }");
126 E : EXPECT_EQ(0U, config.target_set().size());
127 E : EXPECT_FALSE(config.add_copy());
128 E : }
129 :
130 E : TEST_F(FlummoxInstrumenterTest, ParseTargetListNormal) {
131 E : TestFlummoxConfig config;
132 : config.ReadFromJSON(R"JSON(
133 : {
134 : "targets": {
135 : "foo": [], // Comment
136 : "base::bar": [],
137 : //"unused": [],
138 : "__baz__": []
139 : },
140 : "add_copy": true
141 : }
142 E : )JSON");
143 E : EXPECT_EQ(3U, config.target_set().size());
144 E : EXPECT_NE(config.target_set().end(), config.target_set().find("foo"));
145 E : EXPECT_NE(config.target_set().end(), config.target_set().find("base::bar"));
146 E : EXPECT_NE(config.target_set().end(), config.target_set().find("__baz__"));
147 E : EXPECT_TRUE(config.add_copy());
148 E : }
149 :
150 E : TEST_F(FlummoxInstrumenterTest, ParseCommandLineMinimalCoverage) {
151 E : SetUpValidCommandLine();
152 :
153 E : EXPECT_TRUE(instrumenter_.ParseCommandLine(&cmd_line_));
154 :
155 E : EXPECT_EQ(abs_input_image_path_, instrumenter_.input_image_path_);
156 E : EXPECT_EQ(abs_flummox_config_path_, instrumenter_.flummox_config_path_);
157 E : EXPECT_EQ(output_image_path_, instrumenter_.output_image_path_);
158 :
159 E : EXPECT_FALSE(instrumenter_.allow_overwrite_);
160 E : EXPECT_FALSE(instrumenter_.no_augment_pdb_);
161 E : EXPECT_FALSE(instrumenter_.no_strip_strings_);
162 E : EXPECT_FALSE(instrumenter_.debug_friendly_);
163 E : }
164 :
165 E : TEST_F(FlummoxInstrumenterTest, ParseCommandLineFullCoverage) {
166 E : SetUpValidCommandLine();
167 E : cmd_line_.AppendSwitch("debug-friendly");
168 E : cmd_line_.AppendSwitchPath("input-pdb", input_pdb_path_);
169 E : cmd_line_.AppendSwitch("no-augment-pdb");
170 E : cmd_line_.AppendSwitch("no-strip-strings");
171 E : cmd_line_.AppendSwitchPath("output-pdb", output_pdb_path_);
172 E : cmd_line_.AppendSwitch("overwrite");
173 :
174 E : EXPECT_TRUE(instrumenter_.ParseCommandLine(&cmd_line_));
175 :
176 E : EXPECT_EQ(abs_input_image_path_, instrumenter_.input_image_path_);
177 E : EXPECT_EQ(abs_flummox_config_path_, instrumenter_.flummox_config_path_);
178 E : EXPECT_EQ(output_image_path_, instrumenter_.output_image_path_);
179 E : EXPECT_EQ(abs_input_pdb_path_, instrumenter_.input_pdb_path_);
180 E : EXPECT_EQ(output_pdb_path_, instrumenter_.output_pdb_path_);
181 E : EXPECT_TRUE(instrumenter_.allow_overwrite_);
182 E : EXPECT_TRUE(instrumenter_.no_augment_pdb_);
183 E : EXPECT_TRUE(instrumenter_.no_strip_strings_);
184 E : EXPECT_TRUE(instrumenter_.debug_friendly_);
185 E : }
186 :
187 E : TEST_F(FlummoxInstrumenterTest, InstrumentImpl) {
188 E : SetUpValidCommandLine();
189 :
190 E : EXPECT_TRUE(instrumenter_.ParseCommandLine(&cmd_line_));
191 E : EXPECT_TRUE(instrumenter_.InstrumentPrepare());
192 E : EXPECT_TRUE(instrumenter_.CreateRelinker());
193 E : EXPECT_TRUE(instrumenter_.InstrumentImpl());
194 : // Ensure that the test target lists are read.
195 : const auto& target_visited =
196 E : instrumenter_.flummox_transform_->target_visited();
197 E : EXPECT_EQ(2U, target_visited.size());
198 E : EXPECT_NE(target_visited.end(), target_visited.find("Used::M"));
199 E : EXPECT_NE(target_visited.end(), target_visited.find("TestUnusedFuncs"));
200 E : }
201 :
202 : } // namespace instrumenters
203 : } // namespace instrument
|