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