1 : // Copyright 2012 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/reorder/reorder_app.h"
16 :
17 : #include <string>
18 :
19 : #include "base/strings/stringprintf.h"
20 : #include "gmock/gmock.h"
21 : #include "gtest/gtest.h"
22 : #include "syzygy/block_graph/basic_block_decomposer.h"
23 : #include "syzygy/block_graph/typed_block.h"
24 : #include "syzygy/block_graph/unittest_util.h"
25 : #include "syzygy/common/unittest_util.h"
26 : #include "syzygy/core/unittest_util.h"
27 : #include "syzygy/pe/decomposer.h"
28 : #include "syzygy/pe/pe_utils.h"
29 : #include "syzygy/pe/unittest_util.h"
30 : #include "syzygy/reorder/reorderer.h"
31 :
32 : namespace reorder {
33 :
34 : using block_graph::BlockGraph;
35 : using application::Application;
36 : using core::RelativeAddress;
37 : using ::testing::ScopedLogLevelSaver;
38 :
39 : namespace {
40 :
41 : class TestReorderApp : public ReorderApp {
42 : public:
43 : using ReorderApp::kInvalidMode;
44 : using ReorderApp::kLinearOrderMode;
45 : using ReorderApp::kRandomOrderMode;
46 : using ReorderApp::kDeadCodeFinderMode;
47 : using ReorderApp::mode_;
48 : using ReorderApp::instrumented_image_path_;
49 : using ReorderApp::input_image_path_;
50 : using ReorderApp::output_file_path_;
51 : using ReorderApp::bb_entry_count_file_path_;
52 : using ReorderApp::trace_file_paths_;
53 : using ReorderApp::seed_;
54 : using ReorderApp::pretty_print_;
55 : using ReorderApp::flags_;
56 : using ReorderApp::kInstrumentedImage;
57 : using ReorderApp::kOutputFile;
58 : using ReorderApp::kInputImage;
59 : using ReorderApp::kBasicBlockEntryCounts;
60 : using ReorderApp::kSeed;
61 : using ReorderApp::kListDeadCode;
62 : using ReorderApp::kPrettyPrint;
63 : using ReorderApp::kReordererFlags;
64 : using ReorderApp::kInstrumentedDll;
65 : using ReorderApp::kInputDll;
66 : };
67 :
68 : typedef application::Application<TestReorderApp> TestApp;
69 :
70 : class ReorderAppTest : public testing::PELibUnitTest {
71 : public:
72 : typedef testing::PELibUnitTest Super;
73 :
74 : ReorderAppTest()
75 : : cmd_line_(base::FilePath(L"reorder.exe")),
76 : test_impl_(test_app_.implementation()),
77 : seed_(1234567),
78 E : pretty_print_(false) {
79 E : }
80 :
81 E : void SetUp() {
82 E : Super::SetUp();
83 :
84 : // Several of the tests generate progress and (deliberate) error messages
85 : // that would otherwise clutter the unit-test output.
86 E : logging::SetMinLogLevel(logging::LOG_FATAL);
87 :
88 : // Setup the IO streams.
89 E : CreateTemporaryDir(&temp_dir_);
90 E : stdin_path_ = temp_dir_.Append(L"NUL");
91 E : stdout_path_ = temp_dir_.Append(L"stdout.txt");
92 E : stderr_path_ = temp_dir_.Append(L"stderr.txt");
93 E : InitStreams(stdin_path_, stdout_path_, stderr_path_);
94 :
95 : // Initialize the (potential) input and output path values.
96 : abs_input_image_path_ = testing::GetExeTestDataRelativePath(
97 E : testing::kTestDllName);
98 E : input_image_path_ = testing::GetRelativePath(abs_input_image_path_);
99 :
100 : abs_instrumented_image_path_ = testing::GetExeTestDataRelativePath(
101 E : testing::kCallTraceInstrumentedTestDllName);
102 : instrumented_image_path_ = testing::GetRelativePath(
103 E : abs_instrumented_image_path_);
104 :
105 E : abs_output_file_path_ = testing::GetExeTestDataRelativePath(L"order.json");
106 E : output_file_path_ = testing::GetRelativePath(abs_output_file_path_);
107 :
108 : abs_bb_entry_count_file_path_ = testing::GetExeTestDataRelativePath(
109 E : L"basic_block_entry_traces\\entry_counts.json");
110 : bb_entry_count_file_path_ = testing::GetRelativePath(
111 E : abs_bb_entry_count_file_path_);
112 :
113 : abs_trace_file_path_ = testing::GetExeTestDataRelativePath(
114 E : testing::kCallTraceTraceFiles[0]);
115 E : trace_file_path_ = testing::GetRelativePath(abs_trace_file_path_);
116 :
117 : // Point the application at the test's command-line and IO streams.
118 E : test_app_.set_command_line(&cmd_line_);
119 E : test_app_.set_in(in());
120 E : test_app_.set_out(out());
121 E : test_app_.set_err(err());
122 E : }
123 :
124 : protected:
125 : // Stashes the current log-level before each test instance and restores it
126 : // after each test completes.
127 : ScopedLogLevelSaver log_level_saver;
128 :
129 : // @name The application under test.
130 : // @{
131 : TestApp test_app_;
132 : TestApp::Implementation& test_impl_;
133 : base::FilePath temp_dir_;
134 : base::FilePath stdin_path_;
135 : base::FilePath stdout_path_;
136 : base::FilePath stderr_path_;
137 : // @}
138 :
139 : // @name Command-line and parameters.
140 : // @{
141 : base::CommandLine cmd_line_;
142 : base::FilePath instrumented_image_path_;
143 : base::FilePath input_image_path_;
144 : base::FilePath output_file_path_;
145 : base::FilePath bb_entry_count_file_path_;
146 : base::FilePath trace_file_path_;
147 : uint32 seed_;
148 : bool pretty_print_;
149 : // @}
150 :
151 : // @name Expected final values of input parameters.
152 : // @{
153 : base::FilePath abs_input_image_path_;
154 : base::FilePath abs_instrumented_image_path_;
155 : base::FilePath abs_output_file_path_;
156 : base::FilePath abs_bb_entry_count_file_path_;
157 : base::FilePath abs_trace_file_path_;
158 : // @}
159 : };
160 :
161 : } // namespace
162 :
163 E : TEST_F(ReorderAppTest, GetHelp) {
164 E : cmd_line_.AppendSwitch("help");
165 E : ASSERT_FALSE(test_impl_.ParseCommandLine(&cmd_line_));
166 E : }
167 :
168 E : TEST_F(ReorderAppTest, EmptyCommandLineFails) {
169 E : ASSERT_FALSE(test_impl_.ParseCommandLine(&cmd_line_));
170 E : }
171 :
172 E : TEST_F(ReorderAppTest, ParseWithNeitherInstrumentedNorOrderFails) {
173 E : cmd_line_.AppendSwitchPath("input-image", input_image_path_);
174 :
175 E : ASSERT_FALSE(test_impl_.ParseCommandLine(&cmd_line_));
176 E : }
177 :
178 E : TEST_F(ReorderAppTest, ParseWithSeedAndListDeadCodeFails) {
179 : cmd_line_.AppendSwitchPath(
180 E : TestReorderApp::kInstrumentedImage, instrumented_image_path_);
181 E : cmd_line_.AppendSwitchPath(TestReorderApp::kOutputFile, output_file_path_);
182 E : cmd_line_.AppendSwitchPath(TestReorderApp::kInputImage, input_image_path_);
183 : cmd_line_.AppendSwitchASCII(
184 E : TestReorderApp::kSeed, base::StringPrintf("%d", seed_));
185 E : cmd_line_.AppendSwitch(TestReorderApp::kListDeadCode);
186 :
187 E : ASSERT_FALSE(test_impl_.ParseCommandLine(&cmd_line_));
188 E : }
189 :
190 E : TEST_F(ReorderAppTest, ParseWithEmptySeedFails) {
191 : cmd_line_.AppendSwitchPath(
192 E : TestReorderApp::kInstrumentedImage, instrumented_image_path_);
193 E : cmd_line_.AppendSwitchPath(TestReorderApp::kOutputFile, output_file_path_);
194 E : cmd_line_.AppendSwitch(TestReorderApp::kSeed);
195 :
196 E : ASSERT_FALSE(test_impl_.ParseCommandLine(&cmd_line_));
197 E : }
198 :
199 E : TEST_F(ReorderAppTest, ParseWithInvalidSeedFails) {
200 : cmd_line_.AppendSwitchPath(
201 E : TestReorderApp::kInstrumentedImage, instrumented_image_path_);
202 E : cmd_line_.AppendSwitchPath(TestReorderApp::kOutputFile, output_file_path_);
203 E : cmd_line_.AppendSwitchASCII(TestReorderApp::kSeed, "hello");
204 :
205 E : ASSERT_FALSE(test_impl_.ParseCommandLine(&cmd_line_));
206 E : }
207 :
208 E : TEST_F(ReorderAppTest, ParseWithInvalidFlagsFails) {
209 : cmd_line_.AppendSwitchPath(
210 E : TestReorderApp::kInstrumentedImage, instrumented_image_path_);
211 E : cmd_line_.AppendSwitchPath(TestReorderApp::kOutputFile, output_file_path_);
212 : cmd_line_.AppendSwitchASCII(
213 E : TestReorderApp::kReordererFlags, "no-data,no-code,hello");
214 :
215 E : ASSERT_FALSE(test_impl_.ParseCommandLine(&cmd_line_));
216 E : }
217 :
218 E : TEST_F(ReorderAppTest, ParseLinearOrderWithNoTraceFiles) {
219 : cmd_line_.AppendSwitchPath(
220 E : TestReorderApp::kInstrumentedImage, instrumented_image_path_);
221 E : cmd_line_.AppendSwitchPath(TestReorderApp::kOutputFile, output_file_path_);
222 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
223 E : }
224 :
225 E : TEST_F(ReorderAppTest, ParseMinimalLinearOrderCommandLine) {
226 : cmd_line_.AppendSwitchPath(
227 E : TestReorderApp::kInstrumentedImage, instrumented_image_path_);
228 E : cmd_line_.AppendSwitchPath(TestReorderApp::kOutputFile, output_file_path_);
229 E : cmd_line_.AppendArgPath(trace_file_path_);
230 :
231 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
232 :
233 E : EXPECT_EQ(TestReorderApp::kLinearOrderMode, test_impl_.mode_);
234 E : EXPECT_TRUE(test_impl_.input_image_path_.empty());
235 E : EXPECT_EQ(abs_instrumented_image_path_, test_impl_.instrumented_image_path_);
236 E : EXPECT_EQ(abs_output_file_path_, test_impl_.output_file_path_);
237 E : EXPECT_EQ(abs_trace_file_path_, test_impl_.trace_file_paths_.front());
238 E : EXPECT_EQ(0U, test_impl_.seed_);
239 E : EXPECT_FALSE(test_impl_.pretty_print_);
240 : EXPECT_EQ(Reorderer::kFlagReorderCode | Reorderer::kFlagReorderData,
241 E : test_impl_.flags_);
242 :
243 E : EXPECT_TRUE(test_impl_.SetUp());
244 E : }
245 :
246 E : TEST_F(ReorderAppTest, ParseFullLinearOrderCommandLine) {
247 : cmd_line_.AppendSwitchPath(
248 E : TestReorderApp::kInstrumentedImage, instrumented_image_path_);
249 E : cmd_line_.AppendSwitchPath(TestReorderApp::kOutputFile, output_file_path_);
250 E : cmd_line_.AppendSwitchPath(TestReorderApp::kInputImage, input_image_path_);
251 : cmd_line_.AppendSwitchPath(
252 E : TestReorderApp::kBasicBlockEntryCounts, bb_entry_count_file_path_);
253 : cmd_line_.AppendSwitchASCII(
254 E : TestReorderApp::kReordererFlags, "no-data,no-code");
255 E : cmd_line_.AppendSwitch(TestReorderApp::kPrettyPrint);
256 E : cmd_line_.AppendArgPath(trace_file_path_);
257 :
258 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
259 :
260 E : EXPECT_EQ(TestReorderApp::kLinearOrderMode, test_impl_.mode_);
261 E : EXPECT_EQ(abs_input_image_path_, test_impl_.input_image_path_);
262 E : EXPECT_EQ(abs_instrumented_image_path_, test_impl_.instrumented_image_path_);
263 E : EXPECT_EQ(abs_output_file_path_, test_impl_.output_file_path_);
264 : EXPECT_EQ(abs_bb_entry_count_file_path_,
265 E : test_impl_.bb_entry_count_file_path_);
266 E : EXPECT_EQ(abs_trace_file_path_, test_impl_.trace_file_paths_.front());
267 E : EXPECT_EQ(0U, test_impl_.seed_);
268 E : EXPECT_TRUE(test_impl_.pretty_print_);
269 E : EXPECT_EQ(0, test_impl_.flags_ & Reorderer::kFlagReorderCode);
270 E : EXPECT_EQ(0, test_impl_.flags_ & Reorderer::kFlagReorderData);
271 :
272 E : EXPECT_TRUE(test_impl_.SetUp());
273 E : }
274 :
275 E : TEST_F(ReorderAppTest, ParseMinimalDeprecatedLinearOrderCommandLine) {
276 : cmd_line_.AppendSwitchPath(
277 E : TestReorderApp::kInstrumentedDll, instrumented_image_path_);
278 E : cmd_line_.AppendSwitchPath(TestReorderApp::kOutputFile, output_file_path_);
279 E : cmd_line_.AppendArgPath(trace_file_path_);
280 :
281 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
282 :
283 E : EXPECT_EQ(TestReorderApp::kLinearOrderMode, test_impl_.mode_);
284 E : EXPECT_TRUE(test_impl_.input_image_path_.empty());
285 E : EXPECT_EQ(abs_instrumented_image_path_, test_impl_.instrumented_image_path_);
286 E : EXPECT_EQ(abs_output_file_path_, test_impl_.output_file_path_);
287 E : EXPECT_EQ(abs_trace_file_path_, test_impl_.trace_file_paths_.front());
288 E : EXPECT_EQ(0U, test_impl_.seed_);
289 E : EXPECT_FALSE(test_impl_.pretty_print_);
290 :
291 E : EXPECT_TRUE(test_impl_.SetUp());
292 E : }
293 :
294 E : TEST_F(ReorderAppTest, ParseFullDeprecatedLinearOrderCommandLine) {
295 : cmd_line_.AppendSwitchPath(
296 E : TestReorderApp::kInstrumentedDll, instrumented_image_path_);
297 E : cmd_line_.AppendSwitchPath(TestReorderApp::kOutputFile, output_file_path_);
298 E : cmd_line_.AppendSwitchPath(TestReorderApp::kInputDll, input_image_path_);
299 E : cmd_line_.AppendSwitch(TestReorderApp::kPrettyPrint);
300 E : cmd_line_.AppendArgPath(trace_file_path_);
301 :
302 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
303 :
304 E : EXPECT_EQ(TestReorderApp::kLinearOrderMode, test_impl_.mode_);
305 E : EXPECT_EQ(abs_input_image_path_, test_impl_.input_image_path_);
306 E : EXPECT_EQ(abs_instrumented_image_path_, test_impl_.instrumented_image_path_);
307 E : EXPECT_EQ(abs_output_file_path_, test_impl_.output_file_path_);
308 E : EXPECT_EQ(0U, test_impl_.seed_);
309 E : EXPECT_TRUE(test_impl_.pretty_print_);
310 :
311 E : EXPECT_TRUE(test_impl_.SetUp());
312 E : }
313 :
314 E : TEST_F(ReorderAppTest, ParseRandomOrderCommandLine) {
315 : cmd_line_.AppendSwitchPath(
316 E : TestReorderApp::kInstrumentedDll, instrumented_image_path_);
317 E : cmd_line_.AppendSwitchPath(TestReorderApp::kOutputFile, output_file_path_);
318 : cmd_line_.AppendSwitchASCII(
319 E : TestReorderApp::kSeed, base::StringPrintf("%d", seed_));
320 :
321 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
322 :
323 E : EXPECT_EQ(TestReorderApp::kRandomOrderMode, test_impl_.mode_);
324 E : EXPECT_TRUE(test_impl_.input_image_path_.empty());
325 E : EXPECT_EQ(abs_instrumented_image_path_, test_impl_.instrumented_image_path_);
326 E : EXPECT_EQ(abs_output_file_path_, test_impl_.output_file_path_);
327 E : EXPECT_EQ(seed_, test_impl_.seed_);
328 E : EXPECT_TRUE(test_impl_.trace_file_paths_.empty());
329 E : EXPECT_FALSE(test_impl_.pretty_print_);
330 :
331 E : EXPECT_TRUE(test_impl_.SetUp());
332 E : }
333 :
334 E : TEST_F(ReorderAppTest, ParseRandomOrderWithTraceFilesFails) {
335 : cmd_line_.AppendSwitchPath(
336 E : TestReorderApp::kInstrumentedImage, instrumented_image_path_);
337 E : cmd_line_.AppendSwitchPath(TestReorderApp::kOutputFile, output_file_path_);
338 : cmd_line_.AppendSwitchASCII(
339 E : TestReorderApp::kSeed, base::StringPrintf("%d", seed_));
340 E : cmd_line_.AppendArgPath(trace_file_path_);
341 :
342 E : ASSERT_FALSE(test_impl_.ParseCommandLine(&cmd_line_));
343 E : }
344 :
345 E : TEST_F(ReorderAppTest, ParseDeadCodeFinderCommandLine) {
346 : cmd_line_.AppendSwitchPath(
347 E : TestReorderApp::kInstrumentedDll, instrumented_image_path_);
348 E : cmd_line_.AppendSwitchPath(TestReorderApp::kOutputFile, output_file_path_);
349 E : cmd_line_.AppendSwitch(TestReorderApp::kListDeadCode);
350 E : cmd_line_.AppendSwitch(TestReorderApp::kPrettyPrint);
351 E : cmd_line_.AppendArgPath(trace_file_path_);
352 :
353 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
354 :
355 E : EXPECT_EQ(TestReorderApp::kDeadCodeFinderMode, test_impl_.mode_);
356 E : EXPECT_TRUE(test_impl_.input_image_path_.empty());
357 E : EXPECT_EQ(abs_instrumented_image_path_, test_impl_.instrumented_image_path_);
358 E : EXPECT_EQ(abs_output_file_path_, test_impl_.output_file_path_);
359 E : EXPECT_EQ(abs_trace_file_path_, test_impl_.trace_file_paths_.front());
360 E : EXPECT_EQ(0U, test_impl_.seed_);
361 E : EXPECT_TRUE(test_impl_.pretty_print_);
362 :
363 E : EXPECT_TRUE(test_impl_.SetUp());
364 E : }
365 :
366 E : TEST_F(ReorderAppTest, LinearOrderEndToEnd) {
367 : cmd_line_.AppendSwitchPath(
368 E : TestReorderApp::kInstrumentedImage, instrumented_image_path_);
369 E : cmd_line_.AppendSwitchPath(TestReorderApp::kOutputFile, output_file_path_);
370 E : cmd_line_.AppendSwitchPath(TestReorderApp::kInputImage, input_image_path_);
371 : cmd_line_.AppendSwitchPath(
372 E : TestReorderApp::kBasicBlockEntryCounts, bb_entry_count_file_path_);
373 E : cmd_line_.AppendSwitch(TestReorderApp::kPrettyPrint);
374 E : cmd_line_.AppendArgPath(trace_file_path_);
375 :
376 E : ASSERT_EQ(0, test_app_.Run());
377 E : }
378 :
379 E : TEST_F(ReorderAppTest, LinearOrderWithBasicBlockTrace) {
380 : cmd_line_.AppendSwitchPath(
381 E : TestReorderApp::kInstrumentedImage, instrumented_image_path_);
382 E : cmd_line_.AppendSwitchPath(TestReorderApp::kOutputFile, output_file_path_);
383 E : cmd_line_.AppendSwitchPath(TestReorderApp::kInputImage, input_image_path_);
384 : cmd_line_.AppendSwitchPath(
385 E : TestReorderApp::kBasicBlockEntryCounts, bb_entry_count_file_path_);
386 E : cmd_line_.AppendSwitch(TestReorderApp::kPrettyPrint);
387 E : cmd_line_.AppendArgPath(trace_file_path_);
388 :
389 : // Adding a Basic Block traces should be valid, and ignored.
390 : base::FilePath abs_bbtrace_file_path =
391 E : testing::GetExeTestDataRelativePath(testing::kBBEntryTraceFiles[0]);
392 : base::FilePath bbtrace_file_path =
393 E : testing::GetRelativePath(abs_bbtrace_file_path);
394 E : cmd_line_.AppendArgPath(abs_bbtrace_file_path);
395 :
396 E : ASSERT_EQ(0, test_app_.Run());
397 E : }
398 :
399 : } // namespace reorder
|