• 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 "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