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