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/pe/unittest_util.h"
16 :
17 : #include <imagehlp.h>
18 :
19 : #include <algorithm>
20 :
21 : #include "base/command_line.h"
22 : #include "base/file_util.h"
23 : #include "base/logging.h"
24 : #include "base/path_service.h"
25 : #include "base/process_util.h"
26 : #include "base/stringprintf.h"
27 : #include "base/utf_string_conversions.h"
28 : #include "base/win/pe_image.h"
29 : #include "gmock/gmock.h"
30 : #include "gtest/gtest.h"
31 : #include "sawbuck/common/com_utils.h"
32 : #include "syzygy/pe/pe_data.h"
33 :
34 : namespace testing {
35 :
36 : namespace {
37 :
38 : using pe::CvInfoPdb70;
39 :
40 : bool EnumImportsProc(const base::win::PEImage &image,
41 : const char* module,
42 : DWORD ordinal,
43 : const char* name,
44 : DWORD hint,
45 : IMAGE_THUNK_DATA* iat,
46 E : void* cookie) {
47 E : DCHECK(module != NULL);
48 E : DCHECK(iat != NULL);
49 E : DCHECK(cookie != NULL);
50 :
51 : std::set<std::string>* export_dll_imports =
52 E : reinterpret_cast<std::set<std::string>*>(cookie);
53 :
54 E : if (strcmp(module, "export_dll.dll") == 0) {
55 E : if (name != NULL) {
56 E : EXPECT_TRUE(export_dll_imports->insert(name).second);
57 E : } else {
58 E : std::string ordinal_name(base::StringPrintf("#%d", ordinal));
59 E : EXPECT_TRUE(export_dll_imports->insert(ordinal_name).second);
60 E : }
61 : }
62 :
63 E : return true;
64 E : }
65 :
66 E : void CheckLoadedDllHasSortedSafeSehTable(HMODULE module) {
67 : // Verify that the Safe SEH Table is sorted.
68 : // http://code.google.com/p/sawbuck/issues/detail?id=42
69 E : ASSERT_TRUE(module != NULL);
70 E : base::win::PEImage image(module);
71 :
72 : // Locate the load config directory.
73 : PIMAGE_LOAD_CONFIG_DIRECTORY load_config_directory =
74 : reinterpret_cast<PIMAGE_LOAD_CONFIG_DIRECTORY>(
75 E : image.GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG));
76 E : ASSERT_TRUE(load_config_directory != NULL);
77 :
78 : // Find the bounds of the Safe SEH Table.
79 : DWORD* seh_table_begin =
80 E : reinterpret_cast<DWORD*>(load_config_directory->SEHandlerTable);
81 E : size_t seh_table_size = load_config_directory->SEHandlerCount;
82 E : DWORD* seh_table_end = seh_table_begin + seh_table_size;
83 :
84 : // Unfortunately, std::is_sorted is an extension pre-c++0x. An equivalent
85 : // test is to see if there are any adjacent elements such that the first
86 : // is greater than its successor. So, let's look for the first element for
87 : // which this is true, and if we get to the end, then there were no such
88 : // elements.
89 : DWORD* out_of_order_iter = std::adjacent_find(seh_table_begin,
90 : seh_table_end,
91 E : std::greater<DWORD>());
92 E : ASSERT_TRUE(out_of_order_iter == seh_table_end)
93 E : << "The Safe SEH Table must be sorted.";
94 E : }
95 :
96 E : void CheckLoadedTestDll(HMODULE module) {
97 : // Validate that the DLL is properly constructed.
98 E : CheckLoadedDllHasSortedSafeSehTable(module);
99 :
100 : // Load the exported TestExport function and invoke it.
101 : typedef DWORD (WINAPI* TestExportFunc)(size_t buf_len, char* buf);
102 : TestExportFunc test_func = reinterpret_cast<TestExportFunc>(
103 E : ::GetProcAddress(module, "TestExport"));
104 E : ASSERT_TRUE(test_func != NULL);
105 :
106 E : char buffer[1024] = { 0 };
107 E : EXPECT_EQ(0, test_func(arraysize(buffer), buffer));
108 E : EXPECT_STREQ("The quick brown fox jumped over the lazy dog", buffer);
109 :
110 : // Load the exported TestUnusedFunc function and invoke it.
111 : typedef void (CALLBACK* TestUnusedFuncs)(HWND, HINSTANCE, LPSTR, int);
112 : TestUnusedFuncs test_func2 = reinterpret_cast<TestUnusedFuncs>(
113 E : ::GetProcAddress(module, "TestUnusedFuncs"));
114 E : ASSERT_TRUE(test_func2 != NULL);
115 E : test_func2(0, 0, 0, 0);
116 :
117 : // Check the image file for sanity.
118 E : base::win::PEImage image(module);
119 E : ASSERT_TRUE(image.VerifyMagic());
120 :
121 E : std::set<std::string> export_dll_imports;
122 : // Verify all the imports from export_dll.
123 E : ASSERT_TRUE(image.EnumAllImports(EnumImportsProc, &export_dll_imports));
124 :
125 E : std::set<std::string> expected_imports;
126 E : expected_imports.insert("kExportedData");
127 E : expected_imports.insert("function1");
128 E : expected_imports.insert("#7");
129 E : expected_imports.insert("function3");
130 E : EXPECT_THAT(expected_imports, testing::ContainerEq(export_dll_imports));
131 E : }
132 :
133 : } // namespace
134 :
135 : const wchar_t testing::kTestDllName[] = L"test_dll.dll";
136 : const wchar_t testing::kTestDllPdbName[] = L"test_dll.dll.pdb";
137 :
138 : const wchar_t kAsanInstrumentedTestDllName[] =
139 : L"asan_instrumented_test_dll.dll";
140 : const wchar_t kAsanInstrumentedTestDllPdbName[] =
141 : L"asan_instrumented_test_dll.dll.pdb";
142 : const wchar_t kBBEntryInstrumentedTestDllName[] =
143 : L"basic_block_entry_instrumented_test_dll.dll";
144 : const wchar_t kBBEntryInstrumentedTestDllPdbName[] =
145 : L"basic_block_entry_instrumented_test_dll.dll.pdb";
146 : const wchar_t kCallTraceInstrumentedTestDllName[] =
147 : L"call_trace_instrumented_test_dll.dll";
148 : const wchar_t kCallTraceInstrumentedTestDllPdbName[] =
149 : L"call_trace_instrumented_test_dll.dll.pdb";
150 : const wchar_t kCoverageInstrumentedTestDllName[] =
151 : L"coverage_instrumented_test_dll.dll";
152 : const wchar_t kCoverageInstrumentedTestDllPdbName[] =
153 : L"coverage_instrumented_test_dll.dll.pdb";
154 : const wchar_t kProfileInstrumentedTestDllName[] =
155 : L"profile_instrumented_test_dll.dll";
156 : const wchar_t kProfileInstrumentedTestDllPdbName[] =
157 : L"profile_instrumented_test_dll.dll.pdb";
158 : const wchar_t kRandomizedTestDllName[] =
159 : L"randomized_test_dll.dll";
160 : const wchar_t kRandomizedTestDllPdbName[] =
161 : L"randomized_test_dll.dll.pdb";
162 :
163 : const wchar_t *kBBEntryTraceFiles[4] = {
164 : L"basic_block_entry_traces\\trace-1.bin",
165 : L"basic_block_entry_traces\\trace-2.bin",
166 : L"basic_block_entry_traces\\trace-3.bin",
167 : L"basic_block_entry_traces\\trace-4.bin",
168 : };
169 :
170 : const wchar_t *kCallTraceTraceFiles[4] = {
171 : L"call_trace_traces\\trace-1.bin",
172 : L"call_trace_traces\\trace-2.bin",
173 : L"call_trace_traces\\trace-3.bin",
174 : L"call_trace_traces\\trace-4.bin",
175 : };
176 :
177 : const wchar_t *kCoverageTraceFiles[4] = {
178 : L"coverage_traces\\trace-1.bin",
179 : L"coverage_traces\\trace-2.bin",
180 : L"coverage_traces\\trace-3.bin",
181 : L"coverage_traces\\trace-4.bin",
182 : };
183 :
184 : const wchar_t *kProfileTraceFiles[4] = {
185 : L"profile_traces\\trace-1.bin",
186 : L"profile_traces\\trace-2.bin",
187 : L"profile_traces\\trace-3.bin",
188 : L"profile_traces\\trace-4.bin",
189 : };
190 :
191 E : ScopedHMODULE::ScopedHMODULE() : value_(0) {
192 E : }
193 :
194 : ScopedHMODULE::ScopedHMODULE(HMODULE v) : value_(v) {
195 : }
196 :
197 E : void ScopedHMODULE::Reset(HMODULE value) {
198 E : if (value_ != value) {
199 E : Release();
200 E : value_ = value;
201 : }
202 E : }
203 :
204 E : void ScopedHMODULE::Release() {
205 E : if (value_) {
206 E : ::FreeLibrary(value_);
207 E : value_ = 0;
208 : }
209 E : }
210 :
211 E : ScopedHMODULE::~ScopedHMODULE() {
212 E : Release();
213 E : }
214 :
215 : void PELibUnitTest::CheckTestDll(
216 E : const base::FilePath& path, ScopedHMODULE* module) {
217 E : DCHECK(module != NULL);
218 :
219 E : LOADED_IMAGE loaded_image = {};
220 : BOOL success = ::MapAndLoad(WideToUTF8(path.value()).c_str(),
221 : NULL,
222 : &loaded_image,
223 : FALSE,
224 E : FALSE);
225 E : EXPECT_EQ(ERROR_SUCCESS, ::GetLastError());
226 E : ASSERT_TRUE(success);
227 E : EXPECT_TRUE(::UnMapAndLoad(&loaded_image));
228 :
229 E : module->Reset(::LoadLibrary(path.value().c_str()));
230 E : if (*module == NULL) {
231 i : DWORD error = ::GetLastError();
232 i : LOG(ERROR) << "LoadLibrary failed: " << com::LogWe(error);
233 : }
234 E : ASSERT_TRUE(module != NULL);
235 E : CheckLoadedTestDll(*module);
236 E : }
237 :
238 E : void PELibUnitTest::CheckTestDll(const base::FilePath& path) {
239 E : ScopedHMODULE module;
240 E : CheckTestDll(path, &module);
241 E : }
242 :
243 : } // namespace testing
|