Coverage for /Syzygy/minidump/minidump_unittest.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
100.0%1801800.C++test

Line-by-line coverage:

   1    :  // Copyright 2015 Google Inc. All Rights Reserved.
   2    :  //
   3    :  // Licensed under the Apache License, Version 2.0 (the "License");
   4    :  // you may not use this file except in compliance with the License.
   5    :  // You may obtain a copy of the License at
   6    :  //
   7    :  //     http://www.apache.org/licenses/LICENSE-2.0
   8    :  //
   9    :  // Unless required by applicable law or agreed to in writing, software
  10    :  // distributed under the License is distributed on an "AS IS" BASIS,
  11    :  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12    :  // See the License for the specific language governing permissions and
  13    :  // limitations under the License.
  14    :  
  15    :  #include "syzygy/minidump/minidump.h"
  16    :  
  17    :  #include <stdint.h>
  18    :  #include <set>
  19    :  #include <string>
  20    :  #include <vector>
  21    :  
  22    :  #include "base/files/file_util.h"
  23    :  #include "base/files/scoped_temp_dir.h"
  24    :  #include "base/strings/utf_string_conversions.h"
  25    :  #include "gtest/gtest.h"
  26    :  #include "syzygy/core/unittest_util.h"
  27    :  #include "syzygy/minidump/unittest_util.h"
  28    :  
  29    :  namespace minidump {
  30    :  
  31    :  class FileMinidumpTest : public testing::Test {
  32    :   public:
  33  E :    void SetUp() override {
  34  E :      ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
  35  E :      dump_file_ = temp_dir_.path().Append(L"minidump.dmp");
  36  E :    }
  37    :  
  38  E :    const base::FilePath& dump_file() const { return dump_file_; }
  39    :  
  40    :   private:
  41    :    base::FilePath dump_file_;
  42    :    base::ScopedTempDir temp_dir_;
  43    :  };
  44    :  
  45    :  class ScopedMinidumpBuffer {
  46    :   public:
  47    :    template <typename ElementType>
  48  E :    void Append(const ElementType& element) {
  49  E :      Append(&element, sizeof(element));
  50  E :    }
  51  E :    void Append(const void* data, size_t data_len) {
  52  E :      const uint8_t* buf = reinterpret_cast<const uint8_t*>(data);
  53    :  
  54  E :      buf_.insert(buf_.end(), buf, buf + data_len);
  55  E :    }
  56    :  
  57  E :    const uint8_t* data() const { return buf_.data(); }
  58    :  
  59  E :    size_t len() const { return buf_.size(); }
  60    :  
  61    :   private:
  62    :    std::vector<uint8_t> buf_;
  63    :  };
  64    :  
  65  E :  TEST_F(FileMinidumpTest, OpenSuccedsForValidFile) {
  66  E :    FileMinidump minidump;
  67    :  
  68  E :    ASSERT_TRUE(minidump.Open(testing::TestMinidumps::GetNotepad32Dump()));
  69  E :    ASSERT_LE(1U, minidump.directory().size());
  70  E :  }
  71    :  
  72  E :  TEST_F(FileMinidumpTest, OpenFailsForInvalidFile) {
  73  E :    FileMinidump minidump;
  74    :  
  75    :    // Try opening a non-existing file.
  76  E :    ASSERT_FALSE(minidump.Open(dump_file()));
  77  E :  }
  78    :  
  79  E :  TEST_F(FileMinidumpTest, FindNextStream) {
  80  E :    FileMinidump minidump;
  81    :  
  82  E :    ASSERT_TRUE(minidump.Open(testing::TestMinidumps::GetNotepad32Dump()));
  83    :  
  84    :    Minidump::Stream sys_info =
  85  E :        minidump.FindNextStream(nullptr, SystemInfoStream);
  86  E :    ASSERT_TRUE(sys_info.IsValid());
  87    :  
  88  E :    MINIDUMP_SYSTEM_INFO info = {};
  89  E :    EXPECT_TRUE(sys_info.ReadAndAdvanceElement(&info));
  90    :  
  91    :    Minidump::Stream invalid =
  92  E :        minidump.FindNextStream(&sys_info, SystemInfoStream);
  93  E :    EXPECT_FALSE(invalid.IsValid());
  94  E :  }
  95    :  
  96  E :  TEST_F(FileMinidumpTest, ReadThreadInfo) {
  97  E :    FileMinidump minidump;
  98    :  
  99  E :    ASSERT_TRUE(minidump.Open(testing::TestMinidumps::GetNotepad32Dump()));
 100    :  
 101    :    Minidump::Stream thread_list =
 102  E :        minidump.FindNextStream(nullptr, ThreadListStream);
 103  E :    ASSERT_TRUE(thread_list.IsValid());
 104    :  
 105  E :    ULONG32 num_threads = 0;
 106  E :    ASSERT_TRUE(thread_list.ReadAndAdvanceElement(&num_threads));
 107    :  
 108  E :    for (size_t i = 0; i < num_threads; ++i) {
 109  E :      MINIDUMP_THREAD thread = {};
 110  E :      ASSERT_TRUE(thread_list.ReadAndAdvanceElement(&thread));
 111    :  
 112  E :      Minidump::Stream thread_memory = minidump.GetStreamFor(thread.Stack.Memory);
 113  E :      EXPECT_TRUE(thread_memory.IsValid());
 114    :  
 115    :      Minidump::Stream thread_context =
 116  E :          minidump.GetStreamFor(thread.ThreadContext);
 117  E :      EXPECT_TRUE(thread_context.IsValid());
 118    :  
 119  E :      CONTEXT ctx = {};
 120  E :      EXPECT_TRUE(thread_context.ReadAndAdvanceElement(&ctx));
 121  E :    }
 122  E :  }
 123    :  
 124  E :  TEST_F(FileMinidumpTest, GetMemoryList) {
 125  E :    FileMinidump minidump;
 126  E :    ASSERT_TRUE(minidump.Open(testing::TestMinidumps::GetNotepad32Dump()));
 127    :  
 128  E :    auto memory = minidump.GetMemoryList();
 129  E :    EXPECT_TRUE(memory.IsValid());
 130  E :    EXPECT_NE(0U, memory.header().NumberOfMemoryRanges);
 131    :  
 132    :    // TODO(siggi): what to do here?
 133  E :    size_t memory_count = 0;
 134  E :    size_t memory_size = 0;
 135  E :    for (const auto& element : memory) {
 136  E :      ++memory_count;
 137  E :      memory_size += element.Memory.DataSize;
 138  E :    }
 139    :  
 140  E :    ASSERT_EQ(memory.header().NumberOfMemoryRanges, memory_count);
 141  E :    ASSERT_LT(0u, memory_size);
 142  E :  }
 143    :  
 144  E :  TEST_F(FileMinidumpTest, GetModuleList) {
 145  E :    FileMinidump minidump;
 146  E :    ASSERT_TRUE(minidump.Open(testing::TestMinidumps::GetNotepad32Dump()));
 147    :  
 148  E :    auto modules = minidump.GetModuleList();
 149  E :    EXPECT_TRUE(modules.IsValid());
 150  E :    EXPECT_NE(0U, modules.header().NumberOfModules);
 151    :  
 152    :    // TODO(siggi): what to do here?
 153  E :    size_t module_count = 0;
 154  E :    size_t module_size = 0;
 155  E :    for (const auto& element : modules) {
 156  E :      ++module_count;
 157  E :      module_size += element.SizeOfImage;
 158  E :    }
 159    :  
 160  E :    ASSERT_EQ(modules.header().NumberOfModules, module_count);
 161  E :    ASSERT_LT(0u, module_size);
 162  E :  }
 163    :  
 164  E :  TEST_F(FileMinidumpTest, GetThreadList) {
 165  E :    FileMinidump minidump;
 166  E :    ASSERT_TRUE(minidump.Open(testing::TestMinidumps::GetNotepad32Dump()));
 167    :  
 168  E :    auto threads = minidump.GetThreadList();
 169  E :    EXPECT_TRUE(threads.IsValid());
 170  E :    EXPECT_NE(0U, threads.header().NumberOfThreads);
 171    :  
 172  E :    std::set<uint32_t> thread_id_set;
 173  E :    for (const auto& element : threads) {
 174  E :      ASSERT_TRUE(thread_id_set.insert(element.ThreadId).second);
 175  E :    }
 176    :  
 177  E :    ASSERT_LT(0u, thread_id_set.size());
 178  E :  }
 179    :  
 180    :  #if 0
 181    :  // TODO(siggi): This is apparently itanium-specific :/.
 182    :  TEST_F(FileMinidumpTest, GetThreadExList) {
 183    :    FileMinidump minidump;
 184    :    ASSERT_TRUE(minidump.Open(testing::TestMinidumps::GetNotepad64Dump()));
 185    :  
 186    :    auto threads = minidump.GetThreadExList();
 187    :    EXPECT_TRUE(threads.IsValid());
 188    :    EXPECT_NE(0U, threads.header().NumberOfThreads);
 189    :  
 190    :    std::set<uint32_t> thread_id_set;
 191    :    for (const auto& element : threads) {
 192    :      ASSERT_TRUE(thread_id_set.insert(element.ThreadId).second);
 193    :    }
 194    :  
 195    :    ASSERT_LT(0u, thread_id_set.size());
 196    :  }
 197    :  #endif
 198    :  
 199  E :  TEST(BufferMinidumpTest, InitFailsForInvalidFile) {
 200    :    // Opening an empty buffer should fail.
 201    :    {
 202  E :      uint8_t data = 0;
 203  E :      BufferMinidump minidump;
 204  E :      ASSERT_FALSE(minidump.Initialize(&data, 0));
 205  E :    }
 206    :  
 207    :    // Create a file with a header, but an invalid signature.
 208    :    {
 209  E :      MINIDUMP_HEADER hdr = {0};
 210    :  
 211  E :      ScopedMinidumpBuffer buf;
 212  E :      buf.Append(hdr);
 213    :  
 214  E :      BufferMinidump minidump;
 215  E :      ASSERT_FALSE(minidump.Initialize(buf.data(), buf.len()));
 216  E :    }
 217    :  
 218    :    // Create a file with a valid signature, but a zero-length directory.
 219    :    {
 220  E :      MINIDUMP_HEADER hdr = {0};
 221  E :      hdr.Signature = MINIDUMP_SIGNATURE;
 222    :  
 223  E :      ScopedMinidumpBuffer buf;
 224  E :      buf.Append(hdr);
 225    :  
 226  E :      BufferMinidump minidump;
 227  E :      ASSERT_FALSE(minidump.Initialize(buf.data(), buf.len()));
 228  E :    }
 229    :  
 230    :    // Create a file with a valid header, but a missing directory.
 231    :    {
 232  E :      MINIDUMP_HEADER hdr = {0};
 233  E :      hdr.Signature = MINIDUMP_SIGNATURE;
 234  E :      hdr.NumberOfStreams = 10;
 235  E :      hdr.StreamDirectoryRva = sizeof(hdr);
 236    :  
 237  E :      ScopedMinidumpBuffer buf;
 238  E :      buf.Append(hdr);
 239    :  
 240  E :      BufferMinidump minidump;
 241  E :      ASSERT_FALSE(minidump.Initialize(buf.data(), buf.len()));
 242  E :    }
 243  E :  }
 244    :  
 245  E :  TEST(BufferMinidumpTest, StreamTest) {
 246    :    // Create a buffer with some data to test the streams.
 247  E :    ScopedMinidumpBuffer buf;
 248    :  
 249    :    {
 250  E :      MINIDUMP_HEADER hdr = {0};
 251  E :      hdr.Signature = MINIDUMP_SIGNATURE;
 252  E :      hdr.NumberOfStreams = 1;
 253  E :      hdr.StreamDirectoryRva = sizeof(hdr);
 254    :  
 255  E :      buf.Append(hdr);
 256    :  
 257  E :      for (uint32_t i = 0; i < 100; ++i)
 258  E :        buf.Append(i);
 259    :    }
 260    :  
 261  E :    BufferMinidump minidump;
 262  E :    ASSERT_TRUE(minidump.Initialize(buf.data(), buf.len()));
 263    :  
 264    :    // Make a short, arbitrary location.
 265  E :    MINIDUMP_LOCATION_DESCRIPTOR loc = { 7, sizeof(MINIDUMP_HEADER) };
 266  E :    Minidump::Stream test = minidump.GetStreamFor(loc);
 267    :  
 268  E :    EXPECT_EQ(7U, test.remaining_length());
 269    :  
 270    :    // Read the first integer.
 271  E :    const uint32_t kSentinel = 0xCAFEBABE;
 272  E :    uint32_t tmp = kSentinel;
 273  E :    ASSERT_TRUE(test.ReadAndAdvanceElement(&tmp));
 274  E :    EXPECT_EQ(0U, tmp);
 275  E :    EXPECT_EQ(3U, test.remaining_length());
 276    :  
 277    :    // Reading another integer should fail, as the stream doesn't cover it.
 278  E :    tmp = kSentinel;
 279  E :    ASSERT_FALSE(test.ReadAndAdvanceElement(&tmp));
 280    :    // The failing read must not modify the input.
 281  E :    EXPECT_EQ(kSentinel, tmp);
 282    :  
 283    :    // Try the same thing with byte reads.
 284  E :    uint8_t bytes[10] = {};
 285  E :    ASSERT_FALSE(test.ReadBytes(4, &bytes));
 286    :  
 287    :    // A three-byte read should succeed.
 288  E :    ASSERT_TRUE(test.ReadAndAdvanceBytes(3, &bytes));
 289  E :    EXPECT_EQ(0U, test.remaining_length());
 290    :  
 291    :    // Little-endian byte order assumed.
 292  E :    EXPECT_EQ(1U, bytes[0]);
 293  E :    EXPECT_EQ(0U, bytes[1]);
 294  E :    EXPECT_EQ(0U, bytes[2]);
 295    :  
 296    :    // No moar data.
 297  E :    EXPECT_FALSE(test.ReadBytes(1, &bytes));
 298    :  
 299    :    // Reset the stream to test reading via a string.
 300  E :    test = minidump.GetStreamFor(loc);
 301  E :    std::string data;
 302  E :    ASSERT_TRUE(test.ReadAndAdvanceBytes(1, &data));
 303  E :    EXPECT_EQ(6U, test.remaining_length());
 304  E :    EXPECT_EQ(1U, data.size());
 305  E :    EXPECT_EQ(0, data[0]);
 306  E :  }
 307    :  
 308  E :  TEST(BufferMinidumpTest, ReadAndAdvanceString) {
 309  E :    wchar_t kSomeString[] = L"some string";
 310    :  
 311    :    // Create a minimal buffer to test reading a string.
 312  E :    ScopedMinidumpBuffer buf;
 313    :    {
 314    :      // Valid header.
 315  E :      MINIDUMP_HEADER hdr = {0};
 316  E :      hdr.Signature = MINIDUMP_SIGNATURE;
 317  E :      hdr.NumberOfStreams = 1;
 318  E :      hdr.StreamDirectoryRva = sizeof(hdr);
 319  E :      buf.Append(hdr);
 320    :  
 321    :      // Dummy directory.
 322  E :      MINIDUMP_DIRECTORY directory = {0};
 323  E :      buf.Append(directory);
 324    :  
 325    :      // A string. Note that although a null terminating character is written, it
 326    :      // is not counted in the size written to the file.
 327  E :      ULONG32 size_bytes = sizeof(kSomeString) - sizeof(wchar_t);
 328  E :      buf.Append(size_bytes);
 329  E :      buf.Append(kSomeString, sizeof(kSomeString));
 330    :    }
 331    :  
 332  E :    BufferMinidump minidump;
 333  E :    ASSERT_TRUE(minidump.Initialize(buf.data(), buf.len()));
 334    :  
 335    :    MINIDUMP_LOCATION_DESCRIPTOR loc = {
 336  E :        static_cast<ULONG32>(-1),
 337  E :        sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY)};
 338  E :    Minidump::Stream test = minidump.GetStreamFor(loc);
 339  E :    std::wstring recovered;
 340  E :    ASSERT_TRUE(test.ReadAndAdvanceString(&recovered));
 341  E :    ASSERT_EQ(kSomeString, recovered);
 342  E :  }
 343    :  
 344    :  }  // namespace minidump

Coverage information generated Fri Jul 29 11:00:21 2016.