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: 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 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 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 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 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 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 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 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 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 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