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/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 common::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 common::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 E : abs_input_image_path_ = testing::GetExeRelativePath(testing::kTestDllName);
97 E : input_image_path_ = testing::GetRelativePath(abs_input_image_path_);
98 :
99 : abs_instrumented_image_path_ = testing::GetExeTestDataRelativePath(
100 E : testing::kCallTraceInstrumentedTestDllName);
101 : instrumented_image_path_ = testing::GetRelativePath(
102 E : abs_instrumented_image_path_);
103 :
104 E : abs_output_file_path_ = testing::GetExeTestDataRelativePath(L"order.json");
105 E : output_file_path_ = testing::GetRelativePath(abs_output_file_path_);
106 :
107 : abs_bb_entry_count_file_path_ = testing::GetExeTestDataRelativePath(
108 E : L"basic_block_entry_traces\\entry_counts.json");
109 : bb_entry_count_file_path_ = testing::GetRelativePath(
110 E : abs_bb_entry_count_file_path_);
111 :
112 : abs_trace_file_path_ = testing::GetExeTestDataRelativePath(
113 E : testing::kCallTraceTraceFiles[0]);
114 E : trace_file_path_ = testing::GetRelativePath(abs_trace_file_path_);
115 :
116 : // Point the application at the test's command-line and IO streams.
117 E : test_app_.set_command_line(&cmd_line_);
118 E : test_app_.set_in(in());
119 E : test_app_.set_out(out());
120 E : test_app_.set_err(err());
121 E : }
122 :
123 : protected:
124 : // Stashes the current log-level before each test instance and restores it
125 : // after each test completes.
126 : ScopedLogLevelSaver log_level_saver;
127 :
128 : // @name The application under test.
129 : // @{
130 : TestApp test_app_;
131 : TestApp::Implementation& test_impl_;
132 : base::FilePath temp_dir_;
133 : base::FilePath stdin_path_;
134 : base::FilePath stdout_path_;
135 : base::FilePath stderr_path_;
136 : // @}
137 :
138 : // @name Command-line and parameters.
139 : // @{
140 : CommandLine cmd_line_;
141 : base::FilePath instrumented_image_path_;
142 : base::FilePath input_image_path_;
143 : base::FilePath output_file_path_;
144 : base::FilePath bb_entry_count_file_path_;
145 : base::FilePath trace_file_path_;
146 : uint32 seed_;
147 : bool pretty_print_;
148 : // @}
149 :
150 : // @name Expected final values of input parameters.
151 : // @{
152 : base::FilePath abs_input_image_path_;
153 : base::FilePath abs_instrumented_image_path_;
154 : base::FilePath abs_output_file_path_;
155 : base::FilePath abs_bb_entry_count_file_path_;
156 : base::FilePath abs_trace_file_path_;
157 : // @}
158 : };
159 :
160 : } // namespace
161 :
162 E : TEST_F(ReorderAppTest, GetHelp) {
163 E : cmd_line_.AppendSwitch("help");
164 E : ASSERT_FALSE(test_impl_.ParseCommandLine(&cmd_line_));
165 E : }
166 :
167 E : TEST_F(ReorderAppTest, EmptyCommandLineFails) {
168 E : ASSERT_FALSE(test_impl_.ParseCommandLine(&cmd_line_));
169 E : }
170 :
171 E : TEST_F(ReorderAppTest, ParseWithNeitherInstrumentedNorOrderFails) {
172 E : cmd_line_.AppendSwitchPath("input-image", input_image_path_);
173 :
174 E : ASSERT_FALSE(test_impl_.ParseCommandLine(&cmd_line_));
175 E : }
176 :
177 E : TEST_F(ReorderAppTest, ParseWithSeedAndListDeadCodeFails) {
178 : cmd_line_.AppendSwitchPath(
179 E : TestReorderApp::kInstrumentedImage, instrumented_image_path_);
180 E : cmd_line_.AppendSwitchPath(TestReorderApp::kOutputFile, output_file_path_);
181 E : cmd_line_.AppendSwitchPath(TestReorderApp::kInputImage, input_image_path_);
182 : cmd_line_.AppendSwitchASCII(
183 E : TestReorderApp::kSeed, base::StringPrintf("%d", seed_));
184 E : cmd_line_.AppendSwitch(TestReorderApp::kListDeadCode);
185 :
186 E : ASSERT_FALSE(test_impl_.ParseCommandLine(&cmd_line_));
187 E : }
188 :
189 E : TEST_F(ReorderAppTest, ParseWithEmptySeedFails) {
190 : cmd_line_.AppendSwitchPath(
191 E : TestReorderApp::kInstrumentedImage, instrumented_image_path_);
192 E : cmd_line_.AppendSwitchPath(TestReorderApp::kOutputFile, output_file_path_);
193 E : cmd_line_.AppendSwitch(TestReorderApp::kSeed);
194 :
195 E : ASSERT_FALSE(test_impl_.ParseCommandLine(&cmd_line_));
196 E : }
197 :
198 E : TEST_F(ReorderAppTest, ParseWithInvalidSeedFails) {
199 : cmd_line_.AppendSwitchPath(
200 E : TestReorderApp::kInstrumentedImage, instrumented_image_path_);
201 E : cmd_line_.AppendSwitchPath(TestReorderApp::kOutputFile, output_file_path_);
202 E : cmd_line_.AppendSwitchASCII(TestReorderApp::kSeed, "hello");
203 :
204 E : ASSERT_FALSE(test_impl_.ParseCommandLine(&cmd_line_));
205 E : }
206 :
207 E : TEST_F(ReorderAppTest, ParseWithInvalidFlagsFails) {
208 : cmd_line_.AppendSwitchPath(
209 E : TestReorderApp::kInstrumentedImage, instrumented_image_path_);
210 E : cmd_line_.AppendSwitchPath(TestReorderApp::kOutputFile, output_file_path_);
211 : cmd_line_.AppendSwitchASCII(
212 E : TestReorderApp::kReordererFlags, "no-data,no-code,hello");
213 :
214 E : ASSERT_FALSE(test_impl_.ParseCommandLine(&cmd_line_));
215 E : }
216 :
217 E : TEST_F(ReorderAppTest, ParseLinearOrderWithNoTraceFiles) {
218 : cmd_line_.AppendSwitchPath(
219 E : TestReorderApp::kInstrumentedImage, instrumented_image_path_);
220 E : cmd_line_.AppendSwitchPath(TestReorderApp::kOutputFile, output_file_path_);
221 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
222 E : }
223 :
224 E : TEST_F(ReorderAppTest, ParseMinimalLinearOrderCommandLine) {
225 : cmd_line_.AppendSwitchPath(
226 E : TestReorderApp::kInstrumentedImage, instrumented_image_path_);
227 E : cmd_line_.AppendSwitchPath(TestReorderApp::kOutputFile, output_file_path_);
228 E : cmd_line_.AppendArgPath(trace_file_path_);
229 :
230 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
231 :
232 E : EXPECT_EQ(TestReorderApp::kLinearOrderMode, test_impl_.mode_);
233 E : EXPECT_TRUE(test_impl_.input_image_path_.empty());
234 E : EXPECT_EQ(abs_instrumented_image_path_, test_impl_.instrumented_image_path_);
235 E : EXPECT_EQ(abs_output_file_path_, test_impl_.output_file_path_);
236 E : EXPECT_EQ(abs_trace_file_path_, test_impl_.trace_file_paths_.front());
237 E : EXPECT_EQ(0U, test_impl_.seed_);
238 E : EXPECT_FALSE(test_impl_.pretty_print_);
239 : EXPECT_EQ(Reorderer::kFlagReorderCode | Reorderer::kFlagReorderData,
240 E : test_impl_.flags_);
241 :
242 E : EXPECT_TRUE(test_impl_.SetUp());
243 E : }
244 :
245 E : TEST_F(ReorderAppTest, ParseFullLinearOrderCommandLine) {
246 : cmd_line_.AppendSwitchPath(
247 E : TestReorderApp::kInstrumentedImage, instrumented_image_path_);
248 E : cmd_line_.AppendSwitchPath(TestReorderApp::kOutputFile, output_file_path_);
249 E : cmd_line_.AppendSwitchPath(TestReorderApp::kInputImage, input_image_path_);
250 : cmd_line_.AppendSwitchPath(
251 E : TestReorderApp::kBasicBlockEntryCounts, bb_entry_count_file_path_);
252 : cmd_line_.AppendSwitchASCII(
253 E : TestReorderApp::kReordererFlags, "no-data,no-code");
254 E : cmd_line_.AppendSwitch(TestReorderApp::kPrettyPrint);
255 E : cmd_line_.AppendArgPath(trace_file_path_);
256 :
257 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
258 :
259 E : EXPECT_EQ(TestReorderApp::kLinearOrderMode, test_impl_.mode_);
260 E : EXPECT_EQ(abs_input_image_path_, test_impl_.input_image_path_);
261 E : EXPECT_EQ(abs_instrumented_image_path_, test_impl_.instrumented_image_path_);
262 E : EXPECT_EQ(abs_output_file_path_, test_impl_.output_file_path_);
263 : EXPECT_EQ(abs_bb_entry_count_file_path_,
264 E : test_impl_.bb_entry_count_file_path_);
265 E : EXPECT_EQ(abs_trace_file_path_, test_impl_.trace_file_paths_.front());
266 E : EXPECT_EQ(0U, test_impl_.seed_);
267 E : EXPECT_TRUE(test_impl_.pretty_print_);
268 E : EXPECT_EQ(0, test_impl_.flags_ & Reorderer::kFlagReorderCode);
269 E : EXPECT_EQ(0, test_impl_.flags_ & Reorderer::kFlagReorderData);
270 :
271 E : EXPECT_TRUE(test_impl_.SetUp());
272 E : }
273 :
274 E : TEST_F(ReorderAppTest, ParseMinimalDeprecatedLinearOrderCommandLine) {
275 : cmd_line_.AppendSwitchPath(
276 E : TestReorderApp::kInstrumentedDll, instrumented_image_path_);
277 E : cmd_line_.AppendSwitchPath(TestReorderApp::kOutputFile, output_file_path_);
278 E : cmd_line_.AppendArgPath(trace_file_path_);
279 :
280 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
281 :
282 E : EXPECT_EQ(TestReorderApp::kLinearOrderMode, test_impl_.mode_);
283 E : EXPECT_TRUE(test_impl_.input_image_path_.empty());
284 E : EXPECT_EQ(abs_instrumented_image_path_, test_impl_.instrumented_image_path_);
285 E : EXPECT_EQ(abs_output_file_path_, test_impl_.output_file_path_);
286 E : EXPECT_EQ(abs_trace_file_path_, test_impl_.trace_file_paths_.front());
287 E : EXPECT_EQ(0U, test_impl_.seed_);
288 E : EXPECT_FALSE(test_impl_.pretty_print_);
289 :
290 E : EXPECT_TRUE(test_impl_.SetUp());
291 E : }
292 :
293 E : TEST_F(ReorderAppTest, ParseFullDeprecatedLinearOrderCommandLine) {
294 : cmd_line_.AppendSwitchPath(
295 E : TestReorderApp::kInstrumentedDll, instrumented_image_path_);
296 E : cmd_line_.AppendSwitchPath(TestReorderApp::kOutputFile, output_file_path_);
297 E : cmd_line_.AppendSwitchPath(TestReorderApp::kInputDll, input_image_path_);
298 E : cmd_line_.AppendSwitch(TestReorderApp::kPrettyPrint);
299 E : cmd_line_.AppendArgPath(trace_file_path_);
300 :
301 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
302 :
303 E : EXPECT_EQ(TestReorderApp::kLinearOrderMode, test_impl_.mode_);
304 E : EXPECT_EQ(abs_input_image_path_, test_impl_.input_image_path_);
305 E : EXPECT_EQ(abs_instrumented_image_path_, test_impl_.instrumented_image_path_);
306 E : EXPECT_EQ(abs_output_file_path_, test_impl_.output_file_path_);
307 E : EXPECT_EQ(0U, test_impl_.seed_);
308 E : EXPECT_TRUE(test_impl_.pretty_print_);
309 :
310 E : EXPECT_TRUE(test_impl_.SetUp());
311 E : }
312 :
313 E : TEST_F(ReorderAppTest, ParseRandomOrderCommandLine) {
314 : cmd_line_.AppendSwitchPath(
315 E : TestReorderApp::kInstrumentedDll, instrumented_image_path_);
316 E : cmd_line_.AppendSwitchPath(TestReorderApp::kOutputFile, output_file_path_);
317 : cmd_line_.AppendSwitchASCII(
318 E : TestReorderApp::kSeed, base::StringPrintf("%d", seed_));
319 :
320 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
321 :
322 E : EXPECT_EQ(TestReorderApp::kRandomOrderMode, test_impl_.mode_);
323 E : EXPECT_TRUE(test_impl_.input_image_path_.empty());
324 E : EXPECT_EQ(abs_instrumented_image_path_, test_impl_.instrumented_image_path_);
325 E : EXPECT_EQ(abs_output_file_path_, test_impl_.output_file_path_);
326 E : EXPECT_EQ(seed_, test_impl_.seed_);
327 E : EXPECT_TRUE(test_impl_.trace_file_paths_.empty());
328 E : EXPECT_FALSE(test_impl_.pretty_print_);
329 :
330 E : EXPECT_TRUE(test_impl_.SetUp());
331 E : }
332 :
333 E : TEST_F(ReorderAppTest, ParseRandomOrderWithTraceFilesFails) {
334 : cmd_line_.AppendSwitchPath(
335 E : TestReorderApp::kInstrumentedImage, instrumented_image_path_);
336 E : cmd_line_.AppendSwitchPath(TestReorderApp::kOutputFile, output_file_path_);
337 : cmd_line_.AppendSwitchASCII(
338 E : TestReorderApp::kSeed, base::StringPrintf("%d", seed_));
339 E : cmd_line_.AppendArgPath(trace_file_path_);
340 :
341 E : ASSERT_FALSE(test_impl_.ParseCommandLine(&cmd_line_));
342 E : }
343 :
344 E : TEST_F(ReorderAppTest, ParseDeadCodeFinderCommandLine) {
345 : cmd_line_.AppendSwitchPath(
346 E : TestReorderApp::kInstrumentedDll, instrumented_image_path_);
347 E : cmd_line_.AppendSwitchPath(TestReorderApp::kOutputFile, output_file_path_);
348 E : cmd_line_.AppendSwitch(TestReorderApp::kListDeadCode);
349 E : cmd_line_.AppendSwitch(TestReorderApp::kPrettyPrint);
350 E : cmd_line_.AppendArgPath(trace_file_path_);
351 :
352 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
353 :
354 E : EXPECT_EQ(TestReorderApp::kDeadCodeFinderMode, test_impl_.mode_);
355 E : EXPECT_TRUE(test_impl_.input_image_path_.empty());
356 E : EXPECT_EQ(abs_instrumented_image_path_, test_impl_.instrumented_image_path_);
357 E : EXPECT_EQ(abs_output_file_path_, test_impl_.output_file_path_);
358 E : EXPECT_EQ(abs_trace_file_path_, test_impl_.trace_file_paths_.front());
359 E : EXPECT_EQ(0U, test_impl_.seed_);
360 E : EXPECT_TRUE(test_impl_.pretty_print_);
361 :
362 E : EXPECT_TRUE(test_impl_.SetUp());
363 E : }
364 :
365 E : TEST_F(ReorderAppTest, LinearOrderEndToEnd) {
366 : cmd_line_.AppendSwitchPath(
367 E : TestReorderApp::kInstrumentedImage, instrumented_image_path_);
368 E : cmd_line_.AppendSwitchPath(TestReorderApp::kOutputFile, output_file_path_);
369 E : cmd_line_.AppendSwitchPath(TestReorderApp::kInputImage, input_image_path_);
370 : cmd_line_.AppendSwitchPath(
371 E : TestReorderApp::kBasicBlockEntryCounts, bb_entry_count_file_path_);
372 E : cmd_line_.AppendSwitch(TestReorderApp::kPrettyPrint);
373 E : cmd_line_.AppendArgPath(trace_file_path_);
374 :
375 E : ASSERT_EQ(0, test_app_.Run());
376 E : }
377 :
378 E : TEST_F(ReorderAppTest, LinearOrderWithBasicBlockTrace) {
379 : cmd_line_.AppendSwitchPath(
380 E : TestReorderApp::kInstrumentedImage, instrumented_image_path_);
381 E : cmd_line_.AppendSwitchPath(TestReorderApp::kOutputFile, output_file_path_);
382 E : cmd_line_.AppendSwitchPath(TestReorderApp::kInputImage, input_image_path_);
383 : cmd_line_.AppendSwitchPath(
384 E : TestReorderApp::kBasicBlockEntryCounts, bb_entry_count_file_path_);
385 E : cmd_line_.AppendSwitch(TestReorderApp::kPrettyPrint);
386 E : cmd_line_.AppendArgPath(trace_file_path_);
387 :
388 : // Adding a Basic Block traces should be valid, and ignored.
389 : base::FilePath abs_bbtrace_file_path =
390 E : testing::GetExeTestDataRelativePath(testing::kBBEntryTraceFiles[0]);
391 : base::FilePath bbtrace_file_path =
392 E : testing::GetRelativePath(abs_bbtrace_file_path);
393 E : cmd_line_.AppendArgPath(abs_bbtrace_file_path);
394 :
395 E : ASSERT_EQ(0, test_app_.Run());
396 E : }
397 :
398 : } // namespace reorder
|