1 : // Copyright 2012 Google Inc.
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/pdb/pdb_writer.h"
16 :
17 : #include "base/file_util.h"
18 : #include "gtest/gtest.h"
19 : #include "syzygy/pdb/pdb_constants.h"
20 : #include "syzygy/pdb/pdb_reader.h"
21 :
22 : namespace pdb {
23 :
24 : namespace {
25 :
26 E : uint32 GetNumPages(uint32 num_bytes) {
27 E : return (num_bytes + pdb::kPdbPageSize - 1) / pdb::kPdbPageSize;
28 E : }
29 :
30 : class TestPdbWriter : public PdbWriter {
31 : public:
32 E : TestPdbWriter() {
33 E : FilePath path;
34 E : file_.reset(file_util::CreateAndOpenTemporaryFile(&path));
35 E : EXPECT_TRUE(file_.get() != NULL);
36 E : }
37 :
38 E : FILE* file() { return file_.get(); }
39 :
40 : using PdbWriter::StreamInfo;
41 : using PdbWriter::StreamInfoList;
42 : using PdbWriter::PadToPageBoundary;
43 : using PdbWriter::AppendStream;
44 : using PdbWriter::WriteDirectory;
45 : using PdbWriter::WriteDirectoryPages;
46 : using PdbWriter::WriteHeader;
47 : };
48 :
49 : class TestPdbStream : public PdbStream {
50 : public:
51 E : explicit TestPdbStream(uint32 length) : PdbStream(length) {
52 E : }
53 :
54 E : bool ReadBytes(void* dest, size_t count, size_t* bytes_read) {
55 E : DCHECK(bytes_read != NULL);
56 :
57 E : if (pos() == length()) {
58 E : *bytes_read = 0;
59 E : return true;
60 : }
61 :
62 E : count = std::min(count, length() - pos());
63 E : memset(dest, 0xFF, count);
64 E : Seek(pos() + count);
65 E : *bytes_read = count;
66 :
67 E : return true;
68 E : }
69 : };
70 :
71 : } // namespace
72 :
73 : using pdb::kPdbHeaderMagicString;
74 : using pdb::kPdbPageSize;
75 : using pdb::PdbHeader;
76 : using pdb::PdbReader;
77 :
78 E : TEST(PdbWriterTest, WritePdbFile) {
79 E : PdbFile pdb_file;
80 E : for (uint32 i = 0; i < 4; ++i) {
81 E : pdb_file.AppendStream(new TestPdbStream(1 << (8 + i)));
82 E : }
83 :
84 : // Test that we can create a pdb file and then read it successfully.
85 E : FilePath path;
86 E : EXPECT_TRUE(file_util::CreateTemporaryFile(&path));
87 : {
88 : // Create a scope so that the file gets closed.
89 E : TestPdbWriter writer;
90 E : EXPECT_TRUE(writer.Write(path, pdb_file));
91 E : }
92 :
93 E : PdbFile pdb_file_read;
94 E : PdbReader reader;
95 E : EXPECT_TRUE(reader.Read(path, &pdb_file_read));
96 E : EXPECT_EQ(pdb_file.StreamCount(), pdb_file_read.StreamCount());
97 :
98 E : for (size_t i = 0; i < pdb_file.StreamCount(); ++i) {
99 E : ASSERT_TRUE(pdb_file.GetStream(i) != NULL);
100 E : ASSERT_TRUE(pdb_file_read.GetStream(i) != NULL);
101 : EXPECT_EQ(pdb_file.GetStream(i)->length(),
102 E : pdb_file_read.GetStream(i)->length());
103 E : }
104 E : }
105 :
106 E : TEST(PdbWriterTest, PadToPageBoundary) {
107 : // Test that the right amount is padded for the given offset.
108 : uint32 test_cases[][2] = {
109 E : {0, 0}, // offset, padding.
110 E : {1, 1023},
111 E : {1023, 1},
112 E : {1024, 0},
113 E : {1025, 1023},
114 E : {2000, 48},
115 E : {3000, 72},
116 E : {4000, 96}
117 : };
118 :
119 E : TestPdbWriter writer;
120 E : uint32 total_bytes = 0;
121 E : for (uint32 i = 0; i < arraysize(test_cases); ++i) {
122 E : uint32* test_case = test_cases[i];
123 E : uint32 padding = 0;
124 E : EXPECT_TRUE(writer.PadToPageBoundary("", test_case[0], &padding));
125 E : EXPECT_EQ(test_case[1], padding);
126 E : total_bytes += padding;
127 E : }
128 :
129 : // Test that zeroes are padded successfully.
130 E : FILE* file = writer.file();
131 E : for (uint32 i = 0; i < total_bytes; ++i) {
132 E : EXPECT_EQ(0, fseek(file, i, SEEK_SET));
133 : uint8 buffer;
134 E : EXPECT_EQ(1, fread(&buffer, 1, 1, file));
135 E : EXPECT_EQ(0, buffer);
136 E : }
137 E : }
138 :
139 E : TEST(PdbWriterTest, AppendStream) {
140 : // Test that the bytes written corresponds to the stream length and padding.
141 E : TestPdbWriter writer;
142 E : size_t len = (1 << 17) + 123;
143 E : scoped_refptr<TestPdbStream> stream(new TestPdbStream(len));
144 : uint32 bytes_written;
145 E : EXPECT_TRUE(writer.AppendStream(stream.get(), &bytes_written));
146 E : EXPECT_EQ(GetNumPages(len) * kPdbPageSize, bytes_written);
147 :
148 : // Test that the correct data is written.
149 E : FILE* file = writer.file();
150 E : for (size_t i = 0; i < len; ++i) {
151 E : EXPECT_EQ(0, fseek(file, i, SEEK_SET));
152 : uint8 buffer;
153 E : EXPECT_EQ(1, fread(&buffer, 1, 1, file));
154 E : EXPECT_EQ(0xFF, buffer);
155 E : }
156 E : }
157 :
158 E : TEST(PdbWriterTest, WriteDirectory) {
159 : uint32 stream_lengths[] = {
160 E : kPdbPageSize + 10,
161 E : 2 * kPdbPageSize + 20,
162 : 4 * kPdbPageSize + 40
163 E : };
164 :
165 E : TestPdbWriter::StreamInfoList stream_info_list;
166 E : uint32 total_bytes = 0;
167 E : for (uint32 i = 0; i < arraysize(stream_lengths); ++i) {
168 : TestPdbWriter::StreamInfo stream_info;
169 E : stream_info.offset = total_bytes;
170 E : stream_info.length = stream_lengths[i];
171 E : stream_info_list.push_back(stream_info);
172 E : total_bytes += GetNumPages(stream_lengths[i]) * kPdbPageSize;
173 E : };
174 :
175 E : TestPdbWriter writer;
176 E : uint32 dir_size = 0;
177 E : uint32 bytes_written = 0;
178 : EXPECT_TRUE(
179 E : writer.WriteDirectory(stream_info_list, &dir_size, &bytes_written));
180 :
181 : // Test the directory size.
182 : // The number of streams.
183 E : uint32 expected_dir_size = sizeof(uint32);
184 : // The length of each stream.
185 E : expected_dir_size += stream_info_list.size() * sizeof(uint32);
186 : // The page numbers of each stream.
187 E : for (uint32 i = 0; i < arraysize(stream_lengths); ++i) {
188 E : expected_dir_size += GetNumPages(stream_lengths[i]) * sizeof(uint32);
189 E : }
190 E : EXPECT_EQ(expected_dir_size, dir_size);
191 E : EXPECT_EQ(GetNumPages(dir_size) * kPdbPageSize, bytes_written);
192 :
193 : // Test the directory contents.
194 E : FILE* file = writer.file();
195 E : EXPECT_EQ(0, fseek(file, 0, SEEK_SET));
196 :
197 : uint32 num_streams;
198 E : EXPECT_EQ(1, fread(&num_streams, sizeof(uint32), 1, file));
199 E : EXPECT_EQ(arraysize(stream_lengths), num_streams);
200 :
201 E : for (uint32 i = 0; i < arraysize(stream_lengths); ++i) {
202 E : uint32 stream_length = 0;
203 E : EXPECT_EQ(1, fread(&stream_length, sizeof(uint32), 1, file));
204 E : EXPECT_EQ(stream_lengths[i], stream_length);
205 E : }
206 :
207 E : uint32 page_count = 0;
208 E : for (uint32 i = 0; i < arraysize(stream_lengths); ++i) {
209 E : uint32 num_pages = GetNumPages(stream_lengths[i]);
210 E : for (uint32 j = 0; j < num_pages; ++j) {
211 E : uint32 page_num = 0;
212 E : EXPECT_EQ(1, fread(&page_num, sizeof(uint32), 1, file));
213 E : EXPECT_EQ(page_count + j, page_num);
214 E : }
215 E : page_count += num_pages;
216 E : }
217 E : }
218 :
219 E : TEST(PdbWriterTest, WriteDirectoryPages) {
220 E : TestPdbWriter writer;
221 E : uint32 dir_size = (1 << 12) + 234;
222 E : uint32 dir_page = 15;
223 E : uint32 dir_pages_size = 0;
224 E : uint32 bytes_written = 0;
225 : EXPECT_TRUE(writer.WriteDirectoryPages(dir_size, dir_page, &dir_pages_size,
226 E : &bytes_written));
227 :
228 : // Test the directory pages size.
229 E : uint32 num_dir_pages = GetNumPages(dir_size);
230 E : EXPECT_EQ(num_dir_pages * sizeof(uint32), dir_pages_size);
231 E : EXPECT_EQ(GetNumPages(dir_pages_size) * kPdbPageSize, bytes_written);
232 :
233 : // Test the directory pages contents.
234 E : FILE* file = writer.file();
235 E : EXPECT_EQ(0, fseek(file, 0, SEEK_SET));
236 E : for (uint32 i = 0; i < num_dir_pages; ++i) {
237 E : uint32 page_num = 0;
238 E : EXPECT_EQ(1, fread(&page_num, sizeof(uint32), 1, file));
239 E : EXPECT_EQ(dir_page + i, page_num);
240 E : }
241 E : }
242 :
243 E : TEST(PdbWriterTest, WriteHeader) {
244 E : TestPdbWriter writer;
245 E : uint32 file_size = 1 << 20;
246 E : uint32 dir_size = (1 << 12) + 234;
247 E : uint32 dir_root_size = (1 << 6) + 64;
248 E : uint32 dir_root_page = 4;
249 : EXPECT_TRUE(writer.WriteHeader(file_size, dir_size, dir_root_size,
250 E : dir_root_page));
251 :
252 : // Test the header contents.
253 E : FILE* file = writer.file();
254 E : EXPECT_EQ(0, fseek(file, 0, SEEK_SET));
255 E : PdbHeader header = { 0 };
256 E : EXPECT_EQ(1, fread(&header, sizeof(header), 1, file));
257 :
258 : EXPECT_EQ(0, memcmp(header.magic_string, kPdbHeaderMagicString,
259 E : sizeof(kPdbHeaderMagicString)));
260 E : EXPECT_EQ(kPdbPageSize, header.page_size);
261 E : EXPECT_EQ(1, header.free_page_map);
262 E : EXPECT_EQ(GetNumPages(file_size), header.num_pages);
263 E : EXPECT_EQ(dir_size, header.directory_size);
264 E : EXPECT_EQ(0, header.reserved);
265 :
266 E : uint32 num_dir_root_pages = GetNumPages(dir_root_size);
267 E : for (uint32 i = 0; i < num_dir_root_pages; ++i) {
268 E : EXPECT_EQ(dir_root_page + i, header.root_pages[i]);
269 E : }
270 E : }
271 :
272 : } // namespace pdb
|