1 // Copyright (c) 2010, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 #include <windows.h>
31 #include <objbase.h>
32 #include <dbghelp.h>
33
34 #include "client/windows/crash_generation/minidump_generator.h"
35 #include "client/windows/unittests/dump_analysis.h" // NOLINT
36
37 #include "gtest/gtest.h"
38
39 namespace {
40
41 // Minidump with stacks, PEB, TEB, and unloaded module list.
42 const MINIDUMP_TYPE kSmallDumpType = static_cast<MINIDUMP_TYPE>(
43 MiniDumpWithProcessThreadData | // Get PEB and TEB.
44 MiniDumpWithUnloadedModules); // Get unloaded modules when available.
45
46 // Minidump with all of the above, plus memory referenced from stack.
47 const MINIDUMP_TYPE kLargerDumpType = static_cast<MINIDUMP_TYPE>(
48 MiniDumpWithProcessThreadData | // Get PEB and TEB.
49 MiniDumpWithUnloadedModules | // Get unloaded modules when available.
50 MiniDumpWithIndirectlyReferencedMemory); // Get memory referenced by stack.
51
52 // Large dump with all process memory.
53 const MINIDUMP_TYPE kFullDumpType = static_cast<MINIDUMP_TYPE>(
54 MiniDumpWithFullMemory | // Full memory from process.
55 MiniDumpWithProcessThreadData | // Get PEB and TEB.
56 MiniDumpWithHandleData | // Get all handle information.
57 MiniDumpWithUnloadedModules); // Get unloaded modules when available.
58
59 class MinidumpTest: public testing::Test {
60 public:
MinidumpTest()61 MinidumpTest() {
62 wchar_t temp_dir_path[ MAX_PATH ] = {0};
63 ::GetTempPath(MAX_PATH, temp_dir_path);
64 dump_path_ = temp_dir_path;
65 }
66
SetUp()67 virtual void SetUp() {
68 // Make sure URLMon isn't loaded into our process.
69 ASSERT_EQ(NULL, ::GetModuleHandle(L"urlmon.dll"));
70
71 // Then load and unload it to ensure we have something to
72 // stock the unloaded module list with.
73 HMODULE urlmon = ::LoadLibrary(L"urlmon.dll");
74 ASSERT_TRUE(urlmon != NULL);
75 ASSERT_TRUE(::FreeLibrary(urlmon));
76 }
77
TearDown()78 virtual void TearDown() {
79 if (!dump_file_.empty()) {
80 ::DeleteFile(dump_file_.c_str());
81 dump_file_ = L"";
82 }
83 if (!full_dump_file_.empty()) {
84 ::DeleteFile(full_dump_file_.c_str());
85 full_dump_file_ = L"";
86 }
87 }
88
WriteDump(ULONG flags)89 bool WriteDump(ULONG flags) {
90 using google_breakpad::MinidumpGenerator;
91
92 // Fake exception is access violation on write to this.
93 EXCEPTION_RECORD ex_record = {
94 STATUS_ACCESS_VIOLATION, // ExceptionCode
95 0, // ExceptionFlags
96 NULL, // ExceptionRecord;
97 reinterpret_cast<void*>(0xCAFEBABE), // ExceptionAddress;
98 2, // NumberParameters;
99 { EXCEPTION_WRITE_FAULT, reinterpret_cast<ULONG_PTR>(this) }
100 };
101 CONTEXT ctx_record = {};
102 EXCEPTION_POINTERS ex_ptrs = {
103 &ex_record,
104 &ctx_record,
105 };
106
107 MinidumpGenerator generator(dump_path_,
108 ::GetCurrentProcess(),
109 ::GetCurrentProcessId(),
110 ::GetCurrentThreadId(),
111 ::GetCurrentThreadId(),
112 &ex_ptrs,
113 NULL,
114 static_cast<MINIDUMP_TYPE>(flags),
115 TRUE);
116 generator.GenerateDumpFile(&dump_file_);
117 generator.GenerateFullDumpFile(&full_dump_file_);
118 // And write a dump
119 bool result = generator.WriteMinidump();
120 return result == TRUE;
121 }
122
123 protected:
124 std::wstring dump_file_;
125 std::wstring full_dump_file_;
126
127 std::wstring dump_path_;
128 };
129
130 // We need to be able to get file information from Windows
HasFileInfo(const std::wstring & file_path)131 bool HasFileInfo(const std::wstring& file_path) {
132 DWORD dummy;
133 const wchar_t* path = file_path.c_str();
134 DWORD length = ::GetFileVersionInfoSize(path, &dummy);
135 if (length == 0)
136 return NULL;
137
138 void* data = calloc(length, 1);
139 if (!data)
140 return false;
141
142 if (!::GetFileVersionInfo(path, dummy, length, data)) {
143 free(data);
144 return false;
145 }
146
147 void* translate = NULL;
148 UINT page_count;
149 BOOL query_result = VerQueryValue(
150 data,
151 L"\\VarFileInfo\\Translation",
152 static_cast<void**>(&translate),
153 &page_count);
154
155 free(data);
156 if (query_result && translate) {
157 return true;
158 } else {
159 return false;
160 }
161 }
162
TEST_F(MinidumpTest,Version)163 TEST_F(MinidumpTest, Version) {
164 // Loads DbgHelp.dll in process
165 ImagehlpApiVersion();
166
167 HMODULE dbg_help = ::GetModuleHandle(L"dbghelp.dll");
168 ASSERT_TRUE(dbg_help != NULL);
169
170 wchar_t dbg_help_file[1024] = {};
171 ASSERT_TRUE(::GetModuleFileName(dbg_help,
172 dbg_help_file,
173 sizeof(dbg_help_file) /
174 sizeof(*dbg_help_file)));
175 ASSERT_TRUE(HasFileInfo(std::wstring(dbg_help_file)) != NULL);
176
177 // LOG(INFO) << "DbgHelp.dll version: " << file_info->file_version();
178 }
179
TEST_F(MinidumpTest,Normal)180 TEST_F(MinidumpTest, Normal) {
181 EXPECT_TRUE(WriteDump(MiniDumpNormal));
182 DumpAnalysis mini(dump_file_);
183
184 // We expect threads, modules and some memory.
185 EXPECT_TRUE(mini.HasStream(ThreadListStream));
186 EXPECT_TRUE(mini.HasStream(ModuleListStream));
187 EXPECT_TRUE(mini.HasStream(MemoryListStream));
188 EXPECT_TRUE(mini.HasStream(ExceptionStream));
189 EXPECT_TRUE(mini.HasStream(SystemInfoStream));
190 EXPECT_TRUE(mini.HasStream(MiscInfoStream));
191
192 EXPECT_FALSE(mini.HasStream(ThreadExListStream));
193 EXPECT_FALSE(mini.HasStream(Memory64ListStream));
194 EXPECT_FALSE(mini.HasStream(CommentStreamA));
195 EXPECT_FALSE(mini.HasStream(CommentStreamW));
196 EXPECT_FALSE(mini.HasStream(HandleDataStream));
197 EXPECT_FALSE(mini.HasStream(FunctionTableStream));
198 EXPECT_FALSE(mini.HasStream(UnloadedModuleListStream));
199 EXPECT_FALSE(mini.HasStream(MemoryInfoListStream));
200 EXPECT_FALSE(mini.HasStream(ThreadInfoListStream));
201 EXPECT_FALSE(mini.HasStream(HandleOperationListStream));
202 EXPECT_FALSE(mini.HasStream(TokenStream));
203
204 // We expect no PEB nor TEBs in this dump.
205 EXPECT_FALSE(mini.HasTebs());
206 EXPECT_FALSE(mini.HasPeb());
207
208 // We expect no off-stack memory in this dump.
209 EXPECT_FALSE(mini.HasMemory(this));
210 }
211
TEST_F(MinidumpTest,SmallDump)212 TEST_F(MinidumpTest, SmallDump) {
213 ASSERT_TRUE(WriteDump(kSmallDumpType));
214 DumpAnalysis mini(dump_file_);
215
216 EXPECT_TRUE(mini.HasStream(ThreadListStream));
217 EXPECT_TRUE(mini.HasStream(ModuleListStream));
218 EXPECT_TRUE(mini.HasStream(MemoryListStream));
219 EXPECT_TRUE(mini.HasStream(ExceptionStream));
220 EXPECT_TRUE(mini.HasStream(SystemInfoStream));
221 EXPECT_TRUE(mini.HasStream(UnloadedModuleListStream));
222 EXPECT_TRUE(mini.HasStream(MiscInfoStream));
223
224 // We expect PEB and TEBs in this dump.
225 EXPECT_TRUE(mini.HasTebs());
226 EXPECT_TRUE(mini.HasPeb());
227
228 EXPECT_FALSE(mini.HasStream(ThreadExListStream));
229 EXPECT_FALSE(mini.HasStream(Memory64ListStream));
230 EXPECT_FALSE(mini.HasStream(CommentStreamA));
231 EXPECT_FALSE(mini.HasStream(CommentStreamW));
232 EXPECT_FALSE(mini.HasStream(HandleDataStream));
233 EXPECT_FALSE(mini.HasStream(FunctionTableStream));
234 EXPECT_FALSE(mini.HasStream(MemoryInfoListStream));
235 EXPECT_FALSE(mini.HasStream(ThreadInfoListStream));
236 EXPECT_FALSE(mini.HasStream(HandleOperationListStream));
237 EXPECT_FALSE(mini.HasStream(TokenStream));
238
239 // We expect no off-stack memory in this dump.
240 EXPECT_FALSE(mini.HasMemory(this));
241 }
242
TEST_F(MinidumpTest,LargerDump)243 TEST_F(MinidumpTest, LargerDump) {
244 ASSERT_TRUE(WriteDump(kLargerDumpType));
245 DumpAnalysis mini(dump_file_);
246
247 // The dump should have all of these streams.
248 EXPECT_TRUE(mini.HasStream(ThreadListStream));
249 EXPECT_TRUE(mini.HasStream(ModuleListStream));
250 EXPECT_TRUE(mini.HasStream(MemoryListStream));
251 EXPECT_TRUE(mini.HasStream(ExceptionStream));
252 EXPECT_TRUE(mini.HasStream(SystemInfoStream));
253 EXPECT_TRUE(mini.HasStream(UnloadedModuleListStream));
254 EXPECT_TRUE(mini.HasStream(MiscInfoStream));
255
256 // We expect memory referenced by stack in this dump.
257 EXPECT_TRUE(mini.HasMemory(this));
258
259 // We expect PEB and TEBs in this dump.
260 EXPECT_TRUE(mini.HasTebs());
261 EXPECT_TRUE(mini.HasPeb());
262
263 EXPECT_FALSE(mini.HasStream(ThreadExListStream));
264 EXPECT_FALSE(mini.HasStream(Memory64ListStream));
265 EXPECT_FALSE(mini.HasStream(CommentStreamA));
266 EXPECT_FALSE(mini.HasStream(CommentStreamW));
267 EXPECT_FALSE(mini.HasStream(HandleDataStream));
268 EXPECT_FALSE(mini.HasStream(FunctionTableStream));
269 EXPECT_FALSE(mini.HasStream(MemoryInfoListStream));
270 EXPECT_FALSE(mini.HasStream(ThreadInfoListStream));
271 EXPECT_FALSE(mini.HasStream(HandleOperationListStream));
272 EXPECT_FALSE(mini.HasStream(TokenStream));
273 }
274
TEST_F(MinidumpTest,FullDump)275 TEST_F(MinidumpTest, FullDump) {
276 ASSERT_TRUE(WriteDump(kFullDumpType));
277 ASSERT_TRUE(dump_file_ != L"");
278 ASSERT_TRUE(full_dump_file_ != L"");
279 DumpAnalysis mini(dump_file_);
280 DumpAnalysis full(full_dump_file_);
281
282 // Either dumps can contain part of the information.
283
284 // The dump should have all of these streams.
285 EXPECT_TRUE(mini.HasStream(ThreadListStream));
286 EXPECT_TRUE(full.HasStream(ThreadListStream));
287 EXPECT_TRUE(mini.HasStream(ModuleListStream));
288 EXPECT_TRUE(full.HasStream(ModuleListStream));
289 EXPECT_TRUE(mini.HasStream(ExceptionStream));
290 EXPECT_TRUE(full.HasStream(ExceptionStream));
291 EXPECT_TRUE(mini.HasStream(SystemInfoStream));
292 EXPECT_TRUE(full.HasStream(SystemInfoStream));
293 EXPECT_TRUE(mini.HasStream(UnloadedModuleListStream));
294 EXPECT_TRUE(full.HasStream(UnloadedModuleListStream));
295 EXPECT_TRUE(mini.HasStream(MiscInfoStream));
296 EXPECT_TRUE(full.HasStream(MiscInfoStream));
297 EXPECT_TRUE(mini.HasStream(HandleDataStream));
298 EXPECT_TRUE(full.HasStream(HandleDataStream));
299
300 // We expect memory referenced by stack in this dump.
301 EXPECT_FALSE(mini.HasMemory(this));
302 EXPECT_TRUE(full.HasMemory(this));
303
304 // We expect PEB and TEBs in this dump.
305 EXPECT_TRUE(mini.HasTebs() || full.HasTebs());
306 EXPECT_TRUE(mini.HasPeb() || full.HasPeb());
307
308 EXPECT_TRUE(mini.HasStream(MemoryListStream));
309 EXPECT_TRUE(full.HasStream(Memory64ListStream));
310 EXPECT_FALSE(mini.HasStream(Memory64ListStream));
311 EXPECT_FALSE(full.HasStream(MemoryListStream));
312
313 // This is the only place we don't use OR because we want both not
314 // to have the streams.
315 EXPECT_FALSE(mini.HasStream(ThreadExListStream));
316 EXPECT_FALSE(full.HasStream(ThreadExListStream));
317 EXPECT_FALSE(mini.HasStream(CommentStreamA));
318 EXPECT_FALSE(full.HasStream(CommentStreamA));
319 EXPECT_FALSE(mini.HasStream(CommentStreamW));
320 EXPECT_FALSE(full.HasStream(CommentStreamW));
321 EXPECT_FALSE(mini.HasStream(FunctionTableStream));
322 EXPECT_FALSE(full.HasStream(FunctionTableStream));
323 EXPECT_FALSE(mini.HasStream(MemoryInfoListStream));
324 EXPECT_FALSE(full.HasStream(MemoryInfoListStream));
325 EXPECT_FALSE(mini.HasStream(ThreadInfoListStream));
326 EXPECT_FALSE(full.HasStream(ThreadInfoListStream));
327 EXPECT_FALSE(mini.HasStream(HandleOperationListStream));
328 EXPECT_FALSE(full.HasStream(HandleOperationListStream));
329 EXPECT_FALSE(mini.HasStream(TokenStream));
330 EXPECT_FALSE(full.HasStream(TokenStream));
331 }
332
333 } // namespace
334