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/instrument/instrumenters/entry_thunk_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 : class TestEntryThunkInstrumenter : public EntryThunkInstrumenter {
28 : public:
29 : using EntryThunkInstrumenter::agent_dll_;
30 : using EntryThunkInstrumenter::input_dll_path_;
31 : using EntryThunkInstrumenter::input_pdb_path_;
32 : using EntryThunkInstrumenter::output_dll_path_;
33 : using EntryThunkInstrumenter::output_pdb_path_;
34 : using EntryThunkInstrumenter::allow_overwrite_;
35 : using EntryThunkInstrumenter::new_decomposer_;
36 : using EntryThunkInstrumenter::no_augment_pdb_;
37 : using EntryThunkInstrumenter::no_parse_debug_info_;
38 : using EntryThunkInstrumenter::no_strip_strings_;
39 : using EntryThunkInstrumenter::instrument_unsafe_references_;
40 : using EntryThunkInstrumenter::module_entry_only_;
41 : using EntryThunkInstrumenter::thunk_imports_;
42 : using EntryThunkInstrumenter::debug_friendly_;
43 : using EntryThunkInstrumenter::instrumentation_mode_;
44 : using EntryThunkInstrumenter::kAgentDllProfile;
45 : using EntryThunkInstrumenter::kAgentDllRpc;
46 :
47 E : explicit TestEntryThunkInstrumenter(Mode instrumentation_mode)
48 : : EntryThunkInstrumenter(instrumentation_mode) {
49 E : }
50 : };
51 :
52 : class EntryThunkInstrumenterTest : public testing::PELibUnitTest {
53 : public:
54 : typedef testing::PELibUnitTest Super;
55 :
56 E : EntryThunkInstrumenterTest()
57 : : cmd_line_(base::FilePath(L"instrument.exe")) {
58 E : }
59 :
60 E : virtual void SetUp() OVERRIDE {
61 E : testing::Test::SetUp();
62 :
63 : // Several of the tests generate progress and (deliberate) error messages
64 : // that would otherwise clutter the unittest output.
65 E : logging::SetMinLogLevel(logging::LOG_FATAL);
66 :
67 : // Setup the IO streams.
68 E : CreateTemporaryDir(&temp_dir_);
69 E : stdin_path_ = temp_dir_.Append(L"NUL");
70 E : stdout_path_ = temp_dir_.Append(L"stdout.txt");
71 E : stderr_path_ = temp_dir_.Append(L"stderr.txt");
72 E : InitStreams(stdin_path_, stdout_path_, stderr_path_);
73 :
74 : // Initialize the (potential) input and output path values.
75 E : abs_input_dll_path_ = testing::GetExeRelativePath(testing::kTestDllName);
76 E : input_dll_path_ = testing::GetRelativePath(abs_input_dll_path_);
77 E : abs_input_pdb_path_ = testing::GetExeRelativePath(testing::kTestDllPdbName);
78 E : input_pdb_path_ = testing::GetRelativePath(abs_input_pdb_path_);
79 E : output_dll_path_ = temp_dir_.Append(input_dll_path_.BaseName());
80 E : output_pdb_path_ = temp_dir_.Append(input_pdb_path_.BaseName());
81 E : }
82 :
83 E : void SetUpValidCommandLine() {
84 E : cmd_line_.AppendSwitchPath("input-dll", input_dll_path_);
85 E : cmd_line_.AppendSwitchPath("output-dll", output_dll_path_);
86 E : }
87 :
88 : protected:
89 : base::FilePath temp_dir_;
90 :
91 : // @name The redirected streams paths.
92 : // @{
93 : base::FilePath stdin_path_;
94 : base::FilePath stdout_path_;
95 : base::FilePath stderr_path_;
96 : // @}
97 :
98 : // @name Command-line and parameters.
99 : // @{
100 : CommandLine cmd_line_;
101 : base::FilePath input_dll_path_;
102 : base::FilePath input_pdb_path_;
103 : base::FilePath output_dll_path_;
104 : base::FilePath output_pdb_path_;
105 : // @}
106 :
107 : // @name Expected final values of input parameters.
108 : // @{
109 : base::FilePath abs_input_dll_path_;
110 : base::FilePath abs_input_pdb_path_;
111 : // @}
112 :
113 : // The fake instrumenter we delegate to.
114 : scoped_ptr<TestEntryThunkInstrumenter> instrumenter_;
115 : };
116 :
117 : } // namespace
118 :
119 E : TEST_F(EntryThunkInstrumenterTest, ParseMinimalCallTrace) {
120 E : SetUpValidCommandLine();
121 : instrumenter_.reset(
122 E : new TestEntryThunkInstrumenter(EntryThunkInstrumenter::CALL_TRACE));
123 :
124 E : EXPECT_TRUE(instrumenter_->ParseCommandLine(&cmd_line_));
125 :
126 : EXPECT_EQ(EntryThunkInstrumenter::CALL_TRACE,
127 E : instrumenter_->instrumentation_mode_);
128 E : EXPECT_EQ(abs_input_dll_path_, instrumenter_->input_dll_path_);
129 E : EXPECT_EQ(output_dll_path_, instrumenter_->output_dll_path_);
130 : EXPECT_EQ(std::string(TestEntryThunkInstrumenter::kAgentDllRpc),
131 E : instrumenter_->agent_dll_);
132 E : EXPECT_FALSE(instrumenter_->allow_overwrite_);
133 E : EXPECT_FALSE(instrumenter_->new_decomposer_);
134 E : EXPECT_FALSE(instrumenter_->no_augment_pdb_);
135 E : EXPECT_FALSE(instrumenter_->no_parse_debug_info_);
136 E : EXPECT_FALSE(instrumenter_->no_strip_strings_);
137 E : EXPECT_FALSE(instrumenter_->debug_friendly_);
138 E : EXPECT_FALSE(instrumenter_->thunk_imports_);
139 E : EXPECT_TRUE(instrumenter_->instrument_unsafe_references_);
140 E : EXPECT_FALSE(instrumenter_->module_entry_only_);
141 E : }
142 :
143 E : TEST_F(EntryThunkInstrumenterTest, ParseFullCallTrace) {
144 E : SetUpValidCommandLine();
145 : instrumenter_.reset(
146 E : new TestEntryThunkInstrumenter(EntryThunkInstrumenter::CALL_TRACE));
147 :
148 E : cmd_line_.AppendSwitchASCII("agent", "foo.dll");
149 E : cmd_line_.AppendSwitch("debug-friendly");
150 E : cmd_line_.AppendSwitchPath("input-pdb", input_pdb_path_);
151 E : cmd_line_.AppendSwitch("new-decomposer");
152 E : cmd_line_.AppendSwitch("no-augment-pdb");
153 E : cmd_line_.AppendSwitch("no-parse-debug-info");
154 E : cmd_line_.AppendSwitch("no-strip-strings");
155 E : cmd_line_.AppendSwitchPath("output-pdb", output_pdb_path_);
156 E : cmd_line_.AppendSwitch("overwrite");
157 E : cmd_line_.AppendSwitch("instrument-imports");
158 E : cmd_line_.AppendSwitch("module-entry-only");
159 E : cmd_line_.AppendSwitch("no-unsafe-refs");
160 :
161 E : EXPECT_TRUE(instrumenter_->ParseCommandLine(&cmd_line_));
162 :
163 : EXPECT_EQ(EntryThunkInstrumenter::CALL_TRACE,
164 E : instrumenter_->instrumentation_mode_);
165 E : EXPECT_EQ(abs_input_dll_path_, instrumenter_->input_dll_path_);
166 E : EXPECT_EQ(output_dll_path_, instrumenter_->output_dll_path_);
167 E : EXPECT_EQ(abs_input_pdb_path_, instrumenter_->input_pdb_path_);
168 E : EXPECT_EQ(output_pdb_path_, instrumenter_->output_pdb_path_);
169 E : EXPECT_EQ(std::string("foo.dll"), instrumenter_->agent_dll_);
170 E : EXPECT_TRUE(instrumenter_->allow_overwrite_);
171 E : EXPECT_TRUE(instrumenter_->new_decomposer_);
172 E : EXPECT_TRUE(instrumenter_->no_augment_pdb_);
173 E : EXPECT_TRUE(instrumenter_->no_parse_debug_info_);
174 E : EXPECT_TRUE(instrumenter_->no_strip_strings_);
175 E : EXPECT_TRUE(instrumenter_->debug_friendly_);
176 E : EXPECT_TRUE(instrumenter_->thunk_imports_);
177 E : EXPECT_FALSE(instrumenter_->instrument_unsafe_references_);
178 E : EXPECT_TRUE(instrumenter_->module_entry_only_);
179 E : }
180 :
181 E : TEST_F(EntryThunkInstrumenterTest, ParseMinimalProfile) {
182 E : SetUpValidCommandLine();
183 : instrumenter_.reset(
184 E : new TestEntryThunkInstrumenter(EntryThunkInstrumenter::PROFILE));
185 :
186 E : EXPECT_TRUE(instrumenter_->ParseCommandLine(&cmd_line_));
187 :
188 : EXPECT_EQ(EntryThunkInstrumenter::PROFILE,
189 E : instrumenter_->instrumentation_mode_);
190 E : EXPECT_EQ(abs_input_dll_path_, instrumenter_->input_dll_path_);
191 E : EXPECT_EQ(output_dll_path_, instrumenter_->output_dll_path_);
192 :
193 : EXPECT_EQ(std::string(TestEntryThunkInstrumenter::kAgentDllProfile),
194 E : instrumenter_->agent_dll_);
195 :
196 E : EXPECT_FALSE(instrumenter_->allow_overwrite_);
197 E : EXPECT_FALSE(instrumenter_->new_decomposer_);
198 E : EXPECT_FALSE(instrumenter_->no_augment_pdb_);
199 E : EXPECT_FALSE(instrumenter_->no_parse_debug_info_);
200 E : EXPECT_FALSE(instrumenter_->no_strip_strings_);
201 E : EXPECT_FALSE(instrumenter_->debug_friendly_);
202 E : EXPECT_FALSE(instrumenter_->thunk_imports_);
203 E : EXPECT_FALSE(instrumenter_->instrument_unsafe_references_);
204 E : EXPECT_FALSE(instrumenter_->module_entry_only_);
205 E : }
206 :
207 E : TEST_F(EntryThunkInstrumenterTest, ParseFullProfile) {
208 E : SetUpValidCommandLine();
209 : instrumenter_.reset(
210 E : new TestEntryThunkInstrumenter(EntryThunkInstrumenter::PROFILE));
211 E : cmd_line_.AppendSwitchASCII("agent", "foo.dll");
212 E : cmd_line_.AppendSwitch("debug-friendly");
213 E : cmd_line_.AppendSwitchPath("input-pdb", input_pdb_path_);
214 E : cmd_line_.AppendSwitch("new-decomposer");
215 E : cmd_line_.AppendSwitch("no-augment-pdb");
216 E : cmd_line_.AppendSwitch("no-parse-debug-info");
217 E : cmd_line_.AppendSwitch("no-strip-strings");
218 E : cmd_line_.AppendSwitchPath("output-pdb", output_pdb_path_);
219 E : cmd_line_.AppendSwitch("overwrite");
220 E : cmd_line_.AppendSwitch("instrument-imports");
221 :
222 E : EXPECT_TRUE(instrumenter_->ParseCommandLine(&cmd_line_));
223 :
224 : EXPECT_EQ(EntryThunkInstrumenter::PROFILE,
225 E : instrumenter_->instrumentation_mode_);
226 E : EXPECT_EQ(abs_input_dll_path_, instrumenter_->input_dll_path_);
227 E : EXPECT_EQ(output_dll_path_, instrumenter_->output_dll_path_);
228 E : EXPECT_EQ(abs_input_pdb_path_, instrumenter_->input_pdb_path_);
229 E : EXPECT_EQ(output_pdb_path_, instrumenter_->output_pdb_path_);
230 E : EXPECT_EQ(std::string("foo.dll"), instrumenter_->agent_dll_);
231 E : EXPECT_TRUE(instrumenter_->allow_overwrite_);
232 E : EXPECT_TRUE(instrumenter_->new_decomposer_);
233 E : EXPECT_TRUE(instrumenter_->no_augment_pdb_);
234 E : EXPECT_TRUE(instrumenter_->no_parse_debug_info_);
235 E : EXPECT_TRUE(instrumenter_->no_strip_strings_);
236 E : EXPECT_TRUE(instrumenter_->debug_friendly_);
237 E : EXPECT_TRUE(instrumenter_->thunk_imports_);
238 E : }
239 :
240 E : TEST_F(EntryThunkInstrumenterTest, InstrumentImplCallTrace) {
241 E : SetUpValidCommandLine();
242 : instrumenter_.reset(
243 E : new TestEntryThunkInstrumenter(EntryThunkInstrumenter::CALL_TRACE));
244 :
245 E : EXPECT_TRUE(instrumenter_->ParseCommandLine(&cmd_line_));
246 E : EXPECT_TRUE(instrumenter_->Instrument());
247 E : }
248 :
249 E : TEST_F(EntryThunkInstrumenterTest, InstrumentImplProfile) {
250 E : SetUpValidCommandLine();
251 : instrumenter_.reset(
252 E : new TestEntryThunkInstrumenter(EntryThunkInstrumenter::PROFILE));
253 :
254 E : EXPECT_TRUE(instrumenter_->ParseCommandLine(&cmd_line_));
255 E : EXPECT_TRUE(instrumenter_->Instrument());
256 :
257 E : }
258 : } // namespace instrumenters
259 : } // namespace instrument
|