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 "breakpad_googletest_includes.h"
35 #include "client/windows/crash_generation/minidump_generator.h"
36 #include "client/windows/unittests/dump_analysis.h" // NOLINT
37
38 namespace {
39
40 // Minidump with stacks, PEB, TEB, and unloaded module list.
41 const MINIDUMP_TYPE kSmallDumpType = static_cast<MINIDUMP_TYPE>(
42 MiniDumpWithProcessThreadData | // Get PEB and TEB.
43 MiniDumpWithUnloadedModules); // Get unloaded modules when available.
44
45 // Minidump with all of the above, plus memory referenced from stack.
46 const MINIDUMP_TYPE kLargerDumpType = static_cast<MINIDUMP_TYPE>(
47 MiniDumpWithProcessThreadData | // Get PEB and TEB.
48 MiniDumpWithUnloadedModules | // Get unloaded modules when available.
49 MiniDumpWithIndirectlyReferencedMemory); // Get memory referenced by stack.
50
51 // Large dump with all process memory.
52 const MINIDUMP_TYPE kFullDumpType = static_cast<MINIDUMP_TYPE>(
53 MiniDumpWithFullMemory | // Full memory from process.
54 MiniDumpWithProcessThreadData | // Get PEB and TEB.
55 MiniDumpWithHandleData | // Get all handle information.
56 MiniDumpWithUnloadedModules); // Get unloaded modules when available.
57
58 class MinidumpTest: public testing::Test {
59 public:
MinidumpTest()60 MinidumpTest() {
61 wchar_t temp_dir_path[ MAX_PATH ] = {0};
62 ::GetTempPath(MAX_PATH, temp_dir_path);
63 dump_path_ = temp_dir_path;
64 }
65
SetUp()66 virtual void SetUp() {
67 // Make sure URLMon isn't loaded into our process.
68 ASSERT_EQ(NULL, ::GetModuleHandle(L"urlmon.dll"));
69
70 // Then load and unload it to ensure we have something to
71 // stock the unloaded module list with.
72 HMODULE urlmon = ::LoadLibrary(L"urlmon.dll");
73 ASSERT_TRUE(urlmon != NULL);
74 ASSERT_TRUE(::FreeLibrary(urlmon));
75 }
76
TearDown()77 virtual void TearDown() {
78 if (!dump_file_.empty()) {
79 ::DeleteFile(dump_file_.c_str());
80 dump_file_ = L"";
81 }
82 if (!full_dump_file_.empty()) {
83 ::DeleteFile(full_dump_file_.c_str());
84 full_dump_file_ = L"";
85 }
86 }
87
WriteDump(ULONG flags)88 bool WriteDump(ULONG flags) {
89 using google_breakpad::MinidumpGenerator;
90
91 // Fake exception is access violation on write to this.
92 EXCEPTION_RECORD ex_record = {
93 STATUS_ACCESS_VIOLATION, // ExceptionCode
94 0, // ExceptionFlags
95 NULL, // ExceptionRecord;
96 reinterpret_cast<void*>(static_cast<uintptr_t>(0xCAFEBABE)), // ExceptionAddress;
97 2, // NumberParameters;
98 { EXCEPTION_WRITE_FAULT, reinterpret_cast<ULONG_PTR>(this) }
99 };
100 CONTEXT ctx_record = {};
101 EXCEPTION_POINTERS ex_ptrs = {
102 &ex_record,
103 &ctx_record,
104 };
105
106 MinidumpGenerator generator(dump_path_,
107 ::GetCurrentProcess(),
108 ::GetCurrentProcessId(),
109 ::GetCurrentThreadId(),
110 ::GetCurrentThreadId(),
111 &ex_ptrs,
112 NULL,
113 static_cast<MINIDUMP_TYPE>(flags),
114 TRUE);
115 generator.GenerateDumpFile(&dump_file_);
116 generator.GenerateFullDumpFile(&full_dump_file_);
117 // And write a dump
118 bool result = generator.WriteMinidump();
119 return result == TRUE;
120 }
121
122 protected:
123 std::wstring dump_file_;
124 std::wstring full_dump_file_;
125
126 std::wstring dump_path_;
127 };
128
129 // We need to be able to get file information from Windows
HasFileInfo(const std::wstring & file_path)130 bool HasFileInfo(const std::wstring& file_path) {
131 DWORD dummy;
132 const wchar_t* path = file_path.c_str();
133 DWORD length = ::GetFileVersionInfoSize(path, &dummy);
134 if (length == 0)
135 return NULL;
136
137 void* data = calloc(length, 1);
138 if (!data)
139 return false;
140
141 if (!::GetFileVersionInfo(path, dummy, length, data)) {
142 free(data);
143 return false;
144 }
145
146 void* translate = NULL;
147 UINT page_count;
148 BOOL query_result = VerQueryValue(
149 data,
150 L"\\VarFileInfo\\Translation",
151 static_cast<void**>(&translate),
152 &page_count);
153
154 free(data);
155 if (query_result && translate) {
156 return true;
157 } else {
158 return false;
159 }
160 }
161
TEST_F(MinidumpTest,Version)162 TEST_F(MinidumpTest, Version) {
163 // Loads DbgHelp.dll in process
164 ImagehlpApiVersion();
165
166 HMODULE dbg_help = ::GetModuleHandle(L"dbghelp.dll");
167 ASSERT_TRUE(dbg_help != NULL);
168
169 wchar_t dbg_help_file[1024] = {};
170 ASSERT_TRUE(::GetModuleFileName(dbg_help,
171 dbg_help_file,
172 sizeof(dbg_help_file) /
173 sizeof(*dbg_help_file)));
174 ASSERT_TRUE(HasFileInfo(std::wstring(dbg_help_file)) != NULL);
175
176 // LOG(INFO) << "DbgHelp.dll version: " << file_info->file_version();
177 }
178
TEST_F(MinidumpTest,Normal)179 TEST_F(MinidumpTest, Normal) {
180 EXPECT_TRUE(WriteDump(MiniDumpNormal));
181 DumpAnalysis mini(dump_file_);
182
183 // We expect threads, modules and some memory.
184 EXPECT_TRUE(mini.HasStream(ThreadListStream));
185 EXPECT_TRUE(mini.HasStream(ModuleListStream));
186 EXPECT_TRUE(mini.HasStream(MemoryListStream));
187 EXPECT_TRUE(mini.HasStream(ExceptionStream));
188 EXPECT_TRUE(mini.HasStream(SystemInfoStream));
189 EXPECT_TRUE(mini.HasStream(MiscInfoStream));
190
191 EXPECT_FALSE(mini.HasStream(ThreadExListStream));
192 EXPECT_FALSE(mini.HasStream(Memory64ListStream));
193 EXPECT_FALSE(mini.HasStream(CommentStreamA));
194 EXPECT_FALSE(mini.HasStream(CommentStreamW));
195 EXPECT_FALSE(mini.HasStream(HandleDataStream));
196 EXPECT_FALSE(mini.HasStream(FunctionTableStream));
197 EXPECT_FALSE(mini.HasStream(UnloadedModuleListStream));
198 EXPECT_FALSE(mini.HasStream(MemoryInfoListStream));
199 EXPECT_FALSE(mini.HasStream(ThreadInfoListStream));
200 EXPECT_FALSE(mini.HasStream(HandleOperationListStream));
201 EXPECT_FALSE(mini.HasStream(TokenStream));
202
203 // We expect no PEB nor TEBs in this dump.
204 EXPECT_FALSE(mini.HasTebs());
205 EXPECT_FALSE(mini.HasPeb());
206
207 // We expect no off-stack memory in this dump.
208 EXPECT_FALSE(mini.HasMemory(this));
209 }
210
TEST_F(MinidumpTest,SmallDump)211 TEST_F(MinidumpTest, SmallDump) {
212 ASSERT_TRUE(WriteDump(kSmallDumpType));
213 DumpAnalysis mini(dump_file_);
214
215 EXPECT_TRUE(mini.HasStream(ThreadListStream));
216 EXPECT_TRUE(mini.HasStream(ModuleListStream));
217 EXPECT_TRUE(mini.HasStream(MemoryListStream));
218 EXPECT_TRUE(mini.HasStream(ExceptionStream));
219 EXPECT_TRUE(mini.HasStream(SystemInfoStream));
220 EXPECT_TRUE(mini.HasStream(UnloadedModuleListStream));
221 EXPECT_TRUE(mini.HasStream(MiscInfoStream));
222
223 // We expect PEB and TEBs in this dump.
224 EXPECT_TRUE(mini.HasTebs());
225 EXPECT_TRUE(mini.HasPeb());
226
227 EXPECT_FALSE(mini.HasStream(ThreadExListStream));
228 EXPECT_FALSE(mini.HasStream(Memory64ListStream));
229 EXPECT_FALSE(mini.HasStream(CommentStreamA));
230 EXPECT_FALSE(mini.HasStream(CommentStreamW));
231 EXPECT_FALSE(mini.HasStream(HandleDataStream));
232 EXPECT_FALSE(mini.HasStream(FunctionTableStream));
233 EXPECT_FALSE(mini.HasStream(MemoryInfoListStream));
234 EXPECT_FALSE(mini.HasStream(ThreadInfoListStream));
235 EXPECT_FALSE(mini.HasStream(HandleOperationListStream));
236 EXPECT_FALSE(mini.HasStream(TokenStream));
237
238 // We expect no off-stack memory in this dump.
239 EXPECT_FALSE(mini.HasMemory(this));
240 }
241
TEST_F(MinidumpTest,LargerDump)242 TEST_F(MinidumpTest, LargerDump) {
243 ASSERT_TRUE(WriteDump(kLargerDumpType));
244 DumpAnalysis mini(dump_file_);
245
246 // The dump should have all of these streams.
247 EXPECT_TRUE(mini.HasStream(ThreadListStream));
248 EXPECT_TRUE(mini.HasStream(ModuleListStream));
249 EXPECT_TRUE(mini.HasStream(MemoryListStream));
250 EXPECT_TRUE(mini.HasStream(ExceptionStream));
251 EXPECT_TRUE(mini.HasStream(SystemInfoStream));
252 EXPECT_TRUE(mini.HasStream(UnloadedModuleListStream));
253 EXPECT_TRUE(mini.HasStream(MiscInfoStream));
254
255 // We expect memory referenced by stack in this dump.
256 EXPECT_TRUE(mini.HasMemory(this));
257
258 // We expect PEB and TEBs in this dump.
259 EXPECT_TRUE(mini.HasTebs());
260 EXPECT_TRUE(mini.HasPeb());
261
262 EXPECT_FALSE(mini.HasStream(ThreadExListStream));
263 EXPECT_FALSE(mini.HasStream(Memory64ListStream));
264 EXPECT_FALSE(mini.HasStream(CommentStreamA));
265 EXPECT_FALSE(mini.HasStream(CommentStreamW));
266 EXPECT_FALSE(mini.HasStream(HandleDataStream));
267 EXPECT_FALSE(mini.HasStream(FunctionTableStream));
268 EXPECT_FALSE(mini.HasStream(MemoryInfoListStream));
269 EXPECT_FALSE(mini.HasStream(ThreadInfoListStream));
270 EXPECT_FALSE(mini.HasStream(HandleOperationListStream));
271 EXPECT_FALSE(mini.HasStream(TokenStream));
272 }
273
TEST_F(MinidumpTest,FullDump)274 TEST_F(MinidumpTest, FullDump) {
275 ASSERT_TRUE(WriteDump(kFullDumpType));
276 ASSERT_TRUE(dump_file_ != L"");
277 ASSERT_TRUE(full_dump_file_ != L"");
278 DumpAnalysis mini(dump_file_);
279 DumpAnalysis full(full_dump_file_);
280
281 // Either dumps can contain part of the information.
282
283 // The dump should have all of these streams.
284 EXPECT_TRUE(mini.HasStream(ThreadListStream));
285 EXPECT_TRUE(full.HasStream(ThreadListStream));
286 EXPECT_TRUE(mini.HasStream(ModuleListStream));
287 EXPECT_TRUE(full.HasStream(ModuleListStream));
288 EXPECT_TRUE(mini.HasStream(ExceptionStream));
289 EXPECT_TRUE(full.HasStream(ExceptionStream));
290 EXPECT_TRUE(mini.HasStream(SystemInfoStream));
291 EXPECT_TRUE(full.HasStream(SystemInfoStream));
292 EXPECT_TRUE(mini.HasStream(UnloadedModuleListStream));
293 EXPECT_TRUE(full.HasStream(UnloadedModuleListStream));
294 EXPECT_TRUE(mini.HasStream(MiscInfoStream));
295 EXPECT_TRUE(full.HasStream(MiscInfoStream));
296 EXPECT_TRUE(mini.HasStream(HandleDataStream));
297 EXPECT_TRUE(full.HasStream(HandleDataStream));
298
299 // We expect memory referenced by stack in this dump.
300 EXPECT_FALSE(mini.HasMemory(this));
301 EXPECT_TRUE(full.HasMemory(this));
302
303 // We expect PEB and TEBs in this dump.
304 EXPECT_TRUE(mini.HasTebs() || full.HasTebs());
305 EXPECT_TRUE(mini.HasPeb() || full.HasPeb());
306
307 EXPECT_TRUE(mini.HasStream(MemoryListStream));
308 EXPECT_TRUE(full.HasStream(Memory64ListStream));
309 EXPECT_FALSE(mini.HasStream(Memory64ListStream));
310 EXPECT_FALSE(full.HasStream(MemoryListStream));
311
312 // This is the only place we don't use OR because we want both not
313 // to have the streams.
314 EXPECT_FALSE(mini.HasStream(ThreadExListStream));
315 EXPECT_FALSE(full.HasStream(ThreadExListStream));
316 EXPECT_FALSE(mini.HasStream(CommentStreamA));
317 EXPECT_FALSE(full.HasStream(CommentStreamA));
318 EXPECT_FALSE(mini.HasStream(CommentStreamW));
319 EXPECT_FALSE(full.HasStream(CommentStreamW));
320 EXPECT_FALSE(mini.HasStream(FunctionTableStream));
321 EXPECT_FALSE(full.HasStream(FunctionTableStream));
322 EXPECT_FALSE(mini.HasStream(MemoryInfoListStream));
323 EXPECT_FALSE(full.HasStream(MemoryInfoListStream));
324 EXPECT_FALSE(mini.HasStream(ThreadInfoListStream));
325 EXPECT_FALSE(full.HasStream(ThreadInfoListStream));
326 EXPECT_FALSE(mini.HasStream(HandleOperationListStream));
327 EXPECT_FALSE(full.HasStream(HandleOperationListStream));
328 EXPECT_FALSE(mini.HasStream(TokenStream));
329 EXPECT_FALSE(full.HasStream(TokenStream));
330 }
331
332 } // namespace
333