Home | History | Annotate | Download | only in unittests
      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