• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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