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