xref: /aosp_15_r20/external/google-breakpad/src/client/windows/unittests/minidump_test.cc (revision 9712c20fc9bbfbac4935993a2ca0b3958c5adad2)
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