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/instrument/instrument_app.h"
16 :
17 : #include "base/environment.h"
18 : #include "base/strings/stringprintf.h"
19 : #include "gmock/gmock.h"
20 : #include "gtest/gtest.h"
21 : #include "syzygy/block_graph/unittest_util.h"
22 : #include "syzygy/common/unittest_util.h"
23 : #include "syzygy/core/unittest_util.h"
24 : #include "syzygy/instrument/instrumenters/entry_thunk_instrumenter.h"
25 : #include "syzygy/pe/pe_relinker.h"
26 : #include "syzygy/pe/pe_utils.h"
27 : #include "syzygy/pe/unittest_util.h"
28 : #include "syzygy/trace/protocol/call_trace_defs.h"
29 :
30 : namespace instrument {
31 :
32 : namespace {
33 :
34 : class TestInstrumentApp : public InstrumentApp {
35 : public:
36 : using InstrumentApp::instrumenter_;
37 : };
38 :
39 : typedef application::Application<TestInstrumentApp> TestApp;
40 :
41 : class InstrumentAppTest : public testing::PELibUnitTest {
42 : public:
43 : typedef testing::PELibUnitTest Super;
44 :
45 : InstrumentAppTest()
46 : : cmd_line_(base::FilePath(L"instrument.exe")),
47 E : test_impl_(test_app_.implementation()) {
48 E : }
49 :
50 E : void SetUp() {
51 E : Super::SetUp();
52 :
53 : // Several of the tests generate progress and (deliberate) error messages
54 : // that would otherwise clutter the unittest output.
55 E : logging::SetMinLogLevel(logging::LOG_FATAL);
56 :
57 : // Setup the IO streams.
58 E : CreateTemporaryDir(&temp_dir_);
59 E : stdin_path_ = temp_dir_.Append(L"NUL");
60 E : stdout_path_ = temp_dir_.Append(L"stdout.txt");
61 E : stderr_path_ = temp_dir_.Append(L"stderr.txt");
62 E : InitStreams(stdin_path_, stdout_path_, stderr_path_);
63 :
64 : // Initialize the (potential) input and output path values.
65 E : abs_input_dll_path_ = testing::GetExeRelativePath(testing::kTestDllName);
66 E : input_dll_path_ = testing::GetRelativePath(abs_input_dll_path_);
67 E : abs_input_pdb_path_ = testing::GetExeRelativePath(testing::kTestDllPdbName);
68 E : input_pdb_path_ = testing::GetRelativePath(abs_input_pdb_path_);
69 E : output_dll_path_ = temp_dir_.Append(input_dll_path_.BaseName());
70 E : output_pdb_path_ = temp_dir_.Append(input_pdb_path_.BaseName());
71 :
72 E : ASSERT_NO_FATAL_FAILURE(ConfigureTestApp(&test_app_));
73 E : }
74 :
75 : // Points the application at the fixture's command-line and IO streams.
76 : template<typename TestAppType>
77 E : void ConfigureTestApp(TestAppType* test_app) {
78 E : test_app->set_command_line(&cmd_line_);
79 E : test_app->set_in(in());
80 E : test_app->set_out(out());
81 E : test_app->set_err(err());
82 E : }
83 :
84 : // Stashes the current log-level before each test instance and restores it
85 : // after each test completes.
86 : testing::ScopedLogLevelSaver log_level_saver;
87 :
88 : // @name The application under test.
89 : // @{
90 : TestApp test_app_;
91 : TestApp::Implementation& test_impl_;
92 : base::FilePath temp_dir_;
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 : base::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 :
114 : } // namespace
115 :
116 E : TEST_F(InstrumentAppTest, GetHelp) {
117 E : cmd_line_.AppendSwitch("help");
118 E : ASSERT_FALSE(test_impl_.ParseCommandLine(&cmd_line_));
119 E : }
120 :
121 E : TEST_F(InstrumentAppTest, EmptyCommandLineFails) {
122 E : ASSERT_FALSE(test_impl_.ParseCommandLine(&cmd_line_));
123 E : }
124 :
125 E : TEST_F(InstrumentAppTest, ParseWithNoInputImageFails) {
126 E : cmd_line_.AppendSwitchPath("output-image", output_dll_path_);
127 E : ASSERT_FALSE(test_impl_.ParseCommandLine(&cmd_line_));
128 E : }
129 :
130 E : TEST_F(InstrumentAppTest, ParseWithNoOutputImageFails) {
131 E : cmd_line_.AppendSwitchPath("input-image", input_dll_path_);
132 E : ASSERT_FALSE(test_impl_.ParseCommandLine(&cmd_line_));
133 E : }
134 :
135 E : TEST_F(InstrumentAppTest, DeprecatedParseNoModeSpecifyDlls) {
136 E : cmd_line_.AppendSwitchPath("input-dll", input_dll_path_);
137 E : cmd_line_.AppendSwitchPath("output-dll", output_dll_path_);
138 :
139 E : EXPECT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
140 : instrumenters::EntryThunkInstrumenter* entry_thunk_instrumenter =
141 : reinterpret_cast<instrumenters::EntryThunkInstrumenter*>
142 E : (test_impl_.instrumenter_.get());
143 E : ASSERT_TRUE(entry_thunk_instrumenter != NULL);
144 : ASSERT_EQ(instrumenters::EntryThunkInstrumenter::CALL_TRACE,
145 E : entry_thunk_instrumenter->instrumentation_mode());
146 E : }
147 :
148 E : TEST_F(InstrumentAppTest, DeprecatedParseCallTraceClientRpc) {
149 E : cmd_line_.AppendSwitchASCII("call-trace-client", "RPC");
150 E : cmd_line_.AppendSwitchPath("input-dll", input_dll_path_);
151 E : cmd_line_.AppendSwitchPath("output-dll", output_dll_path_);
152 :
153 E : EXPECT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
154 : instrumenters::EntryThunkInstrumenter* entry_thunk_instrumenter =
155 : reinterpret_cast<instrumenters::EntryThunkInstrumenter*>
156 E : (test_impl_.instrumenter_.get());
157 E : ASSERT_TRUE(entry_thunk_instrumenter != NULL);
158 : ASSERT_EQ(instrumenters::EntryThunkInstrumenter::CALL_TRACE,
159 E : entry_thunk_instrumenter->instrumentation_mode());
160 E : }
161 :
162 E : TEST_F(InstrumentAppTest, DeprecatedParseCallTraceClientProfiler) {
163 E : cmd_line_.AppendSwitchASCII("call-trace-client", "profiler");
164 E : cmd_line_.AppendSwitchPath("input-dll", input_dll_path_);
165 E : cmd_line_.AppendSwitchPath("output-dll", output_dll_path_);
166 :
167 E : EXPECT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
168 : instrumenters::EntryThunkInstrumenter* entry_thunk_instrumenter =
169 : reinterpret_cast<instrumenters::EntryThunkInstrumenter*>
170 E : (test_impl_.instrumenter_.get());
171 E : ASSERT_TRUE(entry_thunk_instrumenter != NULL);
172 : ASSERT_EQ(instrumenters::EntryThunkInstrumenter::PROFILE,
173 E : entry_thunk_instrumenter->instrumentation_mode());
174 E : }
175 :
176 E : TEST_F(InstrumentAppTest, Run) {
177 E : cmd_line_.AppendSwitchPath("input-dll", input_dll_path_);
178 E : cmd_line_.AppendSwitchPath("output-dll", output_dll_path_);
179 :
180 E : EXPECT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
181 E : ASSERT_EQ(0, test_impl_.Run());
182 E : }
183 :
184 : } // namespace instrument
|