1 : // Copyright 2014 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 : // A harness for loading integration_tests_dll, and calling a test function
16 : // within it. This is intended for use with instrumented versions of the
17 : // DLL, and is required for certain tests that raise exceptions. The test has
18 : // to be moved to a separate process so as to avoid gtest interference in
19 : // exception handling.
20 :
21 : #include "base/command_line.h"
22 : #include "base/file_util.h"
23 : #include "base/logging.h"
24 : #include "base/files/file_path.h"
25 : #include "base/strings/string_number_conversions.h"
26 : #include "syzygy/common/com_utils.h"
27 : #include "syzygy/integration_tests/integration_tests_dll.h"
28 :
29 : namespace {
30 :
31 : typedef unsigned int (__stdcall* EndToEndTestFunction)(unsigned int);
32 :
33 : #define _STRINGIFY(s) #s
34 : #define STRINGIFY(s) _STRINGIFY(s)
35 :
36 : // An array of test names. The test integer ID is the position of the name in
37 : // the array.
38 : const char* kTestNames[] = {
39 : #define DEFINE_TEST_NAME(enum_name, function_name) STRINGIFY(enum_name),
40 : END_TO_END_TEST_ID_TABLE(DEFINE_TEST_NAME)
41 : #undef DEFINE_TEST_NAME
42 : };
43 :
44 : // Top level configuration and parameters.
45 : LPTOP_LEVEL_EXCEPTION_FILTER previous_unhandled_exception_filter = NULL;
46 E : base::FilePath dll;
47 : size_t test_id = 0;
48 : bool expect_exception = false;
49 :
50 E : bool ParseTestId(CommandLine* cmd_line) {
51 E : DCHECK_NE(reinterpret_cast<CommandLine*>(NULL), cmd_line);
52 :
53 E : std::string test = cmd_line->GetSwitchValueASCII("test");
54 E : if (test.empty()) {
55 i : LOG(ERROR) << "Must specify --test.";
56 i : return false;
57 : }
58 :
59 : // Search for the test by name
60 E : for (size_t i = 0; i < arraysize(kTestNames); ++i) {
61 E : if (test == kTestNames[i]) {
62 i : test_id = i;
63 i : return true;
64 : }
65 E : }
66 :
67 : // Try to convert the string to an integer.
68 E : if (!base::StringToSizeT(test, &test_id)) {
69 i : LOG(ERROR) << "Invalid test name or id: " << test;
70 i : return false;
71 : }
72 :
73 : // If integer parsing worked then ensure it's a valid test id.
74 E : if (test_id >= arraysize(kTestNames)) {
75 i : LOG(ERROR) << "Invalid test id: " << test_id;
76 i : return false;
77 : }
78 :
79 E : return true;
80 E : }
81 :
82 E : bool ParseCommandLine(CommandLine* cmd_line) {
83 E : DCHECK_NE(reinterpret_cast<CommandLine*>(NULL), cmd_line);
84 :
85 : // Parse and validate the path to the DLL.
86 E : dll = cmd_line->GetSwitchValuePath("dll");
87 E : if (dll.empty()) {
88 i : LOG(ERROR) << "Must specify --dll.";
89 i : return false;
90 : }
91 E : if (!base::PathExists(dll)) {
92 i : LOG(ERROR) << "File does not exist: " << dll.value();
93 i : return false;
94 : }
95 :
96 : // Parse the test ID.
97 E : if (!ParseTestId(cmd_line))
98 i : return false;
99 :
100 E : expect_exception = cmd_line->HasSwitch("expect-exception");
101 :
102 E : return true;
103 E : }
104 :
105 : // A utility function for terminating the process with a given return code.
106 E : void Exit(UINT code) {
107 E : if (code != 0) {
108 i : LOG(ERROR) << "Exiting with an error.";
109 i : } else {
110 E : VLOG(1) << "Terminating successfully.";
111 : }
112 E : ::TerminateProcess(::GetCurrentProcess(), code);
113 E : }
114 :
115 : // The base unhandled exception filter. If an exception is raised then this is
116 : // our exit path.
117 E : LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS* exception) {
118 E : VLOG(1) << "Entering UnhandledExceptionFilter.";
119 :
120 E : if (!expect_exception) {
121 i : LOG(ERROR) << "An exception was raised, but none was expected.";
122 i : Exit(1);
123 : }
124 E : Exit(0);
125 :
126 E : LOG(ERROR) << "Something went terribly wrong.";
127 i : return EXCEPTION_EXECUTE_HANDLER;
128 i : }
129 :
130 : } // namespace
131 :
132 E : int main(int argc, char** argv) {
133 : // Initialize the command-line.
134 E : CommandLine::Init(argc, argv);
135 E : CommandLine* cmd_line = CommandLine::ForCurrentProcess();
136 :
137 : // Initialize logging.
138 E : logging::LoggingSettings settings;
139 E : settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
140 E : settings.lock_log = logging::DONT_LOCK_LOG_FILE;
141 E : settings.delete_old = logging::APPEND_TO_OLD_LOG_FILE;
142 E : logging::InitLogging(settings);
143 E : logging::SetMinLogLevel(logging::LOG_ERROR);
144 E : if (cmd_line->HasSwitch("verbose"))
145 i : logging::SetMinLogLevel(logging::LOG_VERBOSE);
146 :
147 : // Parse the command-line.
148 E : if (!ParseCommandLine(cmd_line))
149 i : return 1;
150 :
151 : // Prevent dialog boxes from popping up.
152 E : ::SetErrorMode(SEM_FAILCRITICALERRORS);
153 :
154 E : VLOG(1) << "Registering unhandled exception filter and callback.";
155 : previous_unhandled_exception_filter = ::SetUnhandledExceptionFilter(
156 E : &MyUnhandledExceptionFilter);
157 :
158 : // Load the module.
159 E : LOG(INFO) << "Loading module: " << dll.value();
160 E : HMODULE module = ::LoadLibrary(dll.value().c_str());
161 E : if (module == NULL) {
162 i : DWORD error = ::GetLastError();
163 i : LOG(ERROR) << "LoadLibrary failed: " << common::LogWe(error);
164 i : return 1;
165 : }
166 :
167 : // Get the EndToEndTest function. It is the entry point for calling
168 : // the various tests.
169 E : LOG(INFO) << "Looking up EndToEndTest function.";
170 : EndToEndTestFunction func = reinterpret_cast<EndToEndTestFunction>(
171 E : ::GetProcAddress(module, "EndToEndTest"));
172 E : if (func == NULL) {
173 i : LOG(ERROR) << "Failed to find EndToEndTest function.";
174 i : return 1;
175 : }
176 :
177 : // Invoke the test function.
178 E : LOG(INFO) << "Invoking test " << test_id << ".";
179 E : size_t ret = func(test_id);
180 :
181 E : if (expect_exception) {
182 i : LOG(ERROR) << "Expected an exception, but none was raised.";
183 i : LOG(ERROR) << "Command-line: " << cmd_line->GetCommandLineString();
184 i : Exit(1);
185 : }
186 E : Exit(0);
187 :
188 E : LOG(ERROR) << "Something went terribly wrong.";
189 i : return 1;
190 i : }
|