1 : // Copyright 2014 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/kasko/minidump.h"
16 :
17 : #include <Windows.h> // NOLINT
18 : #include <Dbgeng.h>
19 : #include <DbgHelp.h>
20 :
21 : #include <cstring>
22 : #include <vector>
23 :
24 : #include "base/bind.h"
25 : #include "base/file_util.h"
26 : #include "base/macros.h"
27 : #include "base/files/file_path.h"
28 : #include "base/files/memory_mapped_file.h"
29 : #include "base/files/scoped_temp_dir.h"
30 : #include "gtest/gtest.h"
31 : #include "syzygy/kasko/testing/minidump_unittest_helpers.h"
32 :
33 : namespace kasko {
34 :
35 : namespace {
36 :
37 : const char kCustomStreamContents[] = "hello world";
38 : uint32_t kCustomStreamType = LastReservedStream + 2468;
39 :
40 : void ValidateMinidump(IDebugClient4* debug_client,
41 : IDebugControl* debug_control,
42 E : IDebugSymbols* debug_symbols) {
43 : ASSERT_HRESULT_SUCCEEDED(
44 E : debug_symbols->GetModuleByModuleName("kasko_unittests", 0, NULL, NULL));
45 E : }
46 :
47 : } // namespace
48 :
49 : class MinidumpTest : public ::testing::Test {
50 : public:
51 E : MinidumpTest() {}
52 E : ~MinidumpTest() override {}
53 :
54 : // ::testing::Test implementation.
55 E : virtual void SetUp() override { temp_dir_.CreateUniqueTempDir(); }
56 :
57 : protected:
58 E : base::FilePath temp_dir() { return temp_dir_.path(); }
59 :
60 : private:
61 : base::ScopedTempDir temp_dir_;
62 : DISALLOW_COPY_AND_ASSIGN(MinidumpTest);
63 : };
64 :
65 E : TEST_F(MinidumpTest, GenerateAndLoad) {
66 : // Generate a minidump for the current process.
67 E : base::FilePath dump_file_path = temp_dir().Append(L"test.dump");
68 E : std::vector<CustomStream> custom_streams;
69 : ASSERT_TRUE(kasko::GenerateMinidump(dump_file_path, ::GetCurrentProcessId(),
70 : 0, NULL, SMALL_DUMP_TYPE,
71 E : custom_streams));
72 :
73 : ASSERT_HRESULT_SUCCEEDED(
74 E : testing::VisitMinidump(dump_file_path, base::Bind(&ValidateMinidump)));
75 E : }
76 :
77 E : TEST_F(MinidumpTest, CustomStream) {
78 : // Generate a minidump for the current process.
79 E : base::FilePath dump_file_path = temp_dir().Append(L"test.dump");
80 E : std::vector<CustomStream> custom_streams;
81 : CustomStream custom_stream = {kCustomStreamType,
82 : kCustomStreamContents,
83 E : sizeof(kCustomStreamContents)};
84 E : custom_streams.push_back(custom_stream);
85 : ASSERT_TRUE(kasko::GenerateMinidump(dump_file_path, ::GetCurrentProcessId(),
86 : 0, NULL, SMALL_DUMP_TYPE,
87 E : custom_streams));
88 :
89 : // Open the minidump file.
90 E : base::MemoryMappedFile memory_mapped_file;
91 E : ASSERT_TRUE(memory_mapped_file.Initialize(dump_file_path));
92 :
93 : // Access the custom stream.
94 E : MINIDUMP_DIRECTORY* dir = nullptr;
95 E : void* stream = nullptr;
96 E : ULONG stream_length = 0;
97 : ASSERT_TRUE(::MiniDumpReadDumpStream(
98 : const_cast<uint8*>(memory_mapped_file.data()), kCustomStreamType, &dir,
99 E : &stream, &stream_length));
100 :
101 : // Assert that the custom stream is what we expected.
102 E : ASSERT_EQ(sizeof(kCustomStreamContents), stream_length);
103 E : ASSERT_EQ(0, memcmp(stream, kCustomStreamContents, stream_length));
104 E : }
105 :
106 E : TEST_F(MinidumpTest, MinidumpType) {
107 : // Generate a minidump for the current process.
108 E : base::FilePath small_dump_file_path = temp_dir().Append(L"small.dump");
109 E : base::FilePath larger_dump_file_path = temp_dir().Append(L"larger.dump");
110 E : base::FilePath full_dump_file_path = temp_dir().Append(L"full.dump");
111 E : std::vector<CustomStream> custom_streams;
112 : ASSERT_TRUE(kasko::GenerateMinidump(small_dump_file_path,
113 : ::GetCurrentProcessId(), 0, NULL,
114 E : SMALL_DUMP_TYPE, custom_streams));
115 : ASSERT_TRUE(kasko::GenerateMinidump(larger_dump_file_path,
116 : ::GetCurrentProcessId(), 0, NULL,
117 E : LARGER_DUMP_TYPE, custom_streams));
118 : ASSERT_TRUE(kasko::GenerateMinidump(full_dump_file_path,
119 : ::GetCurrentProcessId(), 0, NULL,
120 E : FULL_DUMP_TYPE, custom_streams));
121 :
122 : // Use the relative file sizes to infer that the correct minidump type was
123 : // respected.
124 : // Other approaches (testing the memory ranges included in the dump) were
125 : // rejected due to the difficulty of deterministically knowing what should and
126 : // shouldn't be included in the various dump types.
127 E : int64 small_dump_size = 0;
128 E : int64 larger_dump_size = 0;
129 E : int64 full_dump_size = 0;
130 :
131 E : ASSERT_TRUE(base::GetFileSize(small_dump_file_path, &small_dump_size));
132 E : ASSERT_TRUE(base::GetFileSize(larger_dump_file_path, &larger_dump_size));
133 E : ASSERT_TRUE(base::GetFileSize(full_dump_file_path, &full_dump_size));
134 :
135 E : EXPECT_GT(full_dump_size, larger_dump_size);
136 E : EXPECT_GT(larger_dump_size, small_dump_size);
137 E : }
138 :
139 E : TEST_F(MinidumpTest, OverwriteExistingFile) {
140 E : base::ScopedTempDir temp_dir;
141 E : ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
142 E : base::FilePath dump_file_path;
143 E : ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir.path(), &dump_file_path));
144 E : std::vector<CustomStream> custom_streams;
145 : ASSERT_TRUE(kasko::GenerateMinidump(dump_file_path, ::GetCurrentProcessId(),
146 : 0, NULL, SMALL_DUMP_TYPE,
147 E : custom_streams));
148 : ASSERT_HRESULT_SUCCEEDED(
149 E : testing::VisitMinidump(dump_file_path, base::Bind(&ValidateMinidump)));
150 E : }
151 :
152 E : TEST_F(MinidumpTest, NonexistantTargetDirectory) {
153 E : base::ScopedTempDir temp_dir;
154 E : ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
155 E : std::vector<CustomStream> custom_streams;
156 : ASSERT_FALSE(kasko::GenerateMinidump(
157 : temp_dir.path().Append(L"Foobar").Append(L"HelloWorld"),
158 E : ::GetCurrentProcessId(), 0, NULL, SMALL_DUMP_TYPE, custom_streams));
159 E : }
160 :
161 : } // namespace kasko
|