1 : // Copyright 2012 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/pdb/pdb_util.h"
16 :
17 : #include <objbase.h>
18 :
19 : #include "base/command_line.h"
20 : #include "base/path_service.h"
21 : #include "base/scoped_native_library.h"
22 : #include "base/files/scoped_temp_dir.h"
23 : #include "base/process/launch.h"
24 : #include "base/strings/utf_string_conversions.h"
25 : #include "base/win/pe_image.h"
26 : #include "gmock/gmock.h"
27 : #include "gtest/gtest.h"
28 : #include "syzygy/common/dbghelp_util.h"
29 : #include "syzygy/core/unittest_util.h"
30 : #include "syzygy/pdb/pdb_byte_stream.h"
31 : #include "syzygy/pdb/pdb_reader.h"
32 : #include "syzygy/pdb/pdb_writer.h"
33 : #include "syzygy/pdb/unittest_util.h"
34 : #include "syzygy/pe/pe_data.h"
35 : #include "syzygy/pe/unittest_util.h"
36 :
37 : namespace pdb {
38 :
39 : namespace {
40 :
41 : const wchar_t* kTempPdbFileName = L"temp.pdb";
42 : const wchar_t* kTempPdbFileName2 = L"temp2.pdb";
43 :
44 : const GUID kSampleGuid = {0xACDC900D, 0x9009, 0xFEED, {7, 6, 5, 4, 3, 2, 1, 0}};
45 :
46 : const PdbInfoHeader70 kSamplePdbHeader = {
47 : kPdbCurrentVersion,
48 : 1336402486, // 7 May 2012, 14:54:00 GMT.
49 : 999,
50 : {0xDEADBEEF, 0x900D, 0xF00D, {0, 1, 2, 3, 4, 5, 6, 7}}
51 : };
52 :
53 : const DbiHeader kSampleDbiHeader = {
54 : -1, // signature.
55 : 19990903, // version.
56 : 999, // age.
57 : };
58 :
59 : const OMAP kOmapToData[] = {
60 : {4096, 4096},
61 : {5012, 5012},
62 : {6064, 6064},
63 : {7048, 240504}
64 : };
65 :
66 : const OMAP kOmapFromData[] = {
67 : {4096, 4096},
68 : {5012, 5012},
69 : {240504, 7048}
70 : };
71 :
72 : class PdbUtilTest : public testing::Test {
73 : public:
74 E : PdbUtilTest() : process_(this) {
75 E : }
76 :
77 E : void SetUp() {
78 E : ASSERT_TRUE(common::SymInitialize(process_, NULL, false));
79 :
80 E : ASSERT_HRESULT_SUCCEEDED(::CoCreateGuid(&new_guid_));
81 E : ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
82 :
83 E : temp_pdb_file_path_ = temp_dir_.path().Append(kTempPdbFileName);
84 E : temp_pdb_file_path2_ = temp_dir_.path().Append(kTempPdbFileName2);
85 E : }
86 :
87 E : void TearDown() {
88 E : ASSERT_TRUE(::SymCleanup(process_));
89 E : }
90 :
91 : void VerifyGuidData(const base::FilePath& pdb_path,
92 : const GUID& guid) {
93 : DWORD64 base_address =
94 : ::SymLoadModuleExW(process_,
95 : NULL,
96 : pdb_path.value().c_str(),
97 : NULL,
98 : 1,
99 : 1,
100 : NULL,
101 : 0);
102 : EXPECT_NE(0, base_address);
103 :
104 : // Get the module info to verify that the new PDB has the GUID we specified.
105 : IMAGEHLP_MODULEW64 module_info = { sizeof(module_info) };
106 : EXPECT_TRUE(::SymGetModuleInfoW64(process_, base_address, &module_info));
107 : EXPECT_EQ(new_guid_, module_info.PdbSig70);
108 :
109 : EXPECT_TRUE(::SymUnloadModule64(process_, base_address));
110 : }
111 :
112 : void VerifyOmapData(const base::FilePath& pdb_path,
113 : const std::vector<OMAP>& omap_to_list,
114 E : const std::vector<OMAP>& omap_from_list) {
115 : DWORD64 base_address =
116 : ::SymLoadModuleExW(process_,
117 : NULL,
118 : pdb_path.value().c_str(),
119 : NULL,
120 : 1,
121 : 1,
122 : NULL,
123 E : 0);
124 E : ASSERT_NE(0, base_address);
125 :
126 E : OMAP* omap_to = NULL;
127 E : DWORD64 omap_to_length = 0;
128 E : OMAP* omap_from = NULL;
129 E : DWORD64 omap_from_length = 0;
130 E : ASSERT_TRUE(::SymGetOmaps(process_,
131 : base_address,
132 : &omap_to,
133 : &omap_to_length,
134 : &omap_from,
135 : &omap_from_length));
136 :
137 E : ASSERT_EQ(omap_to_list.size(), omap_to_length);
138 E : EXPECT_EQ(0, memcmp(&omap_to_list[0], omap_to,
139 : omap_to_list.size() * sizeof(OMAP)));
140 E : ASSERT_EQ(omap_from_list.size(), omap_from_length);
141 E : EXPECT_EQ(0, memcmp(&omap_from_list[0], omap_from,
142 : omap_from_list.size() * sizeof(OMAP)));
143 :
144 E : EXPECT_TRUE(::SymUnloadModule64(process_, base_address));
145 E : }
146 :
147 : protected:
148 : HANDLE process_;
149 : GUID new_guid_;
150 : base::ScopedTempDir temp_dir_;
151 : base::FilePath temp_pdb_file_path_;
152 : base::FilePath temp_pdb_file_path2_;
153 : };
154 :
155 : class TestPdbStream : public PdbStream {
156 : public:
157 E : TestPdbStream() : PdbStream(0), bytes_(NULL) {
158 E : }
159 :
160 : template<typename T> TestPdbStream(const T& t)
161 : : PdbStream(sizeof(T)),
162 E : bytes_(reinterpret_cast<const uint8*>(&t)) {
163 E : }
164 :
165 : virtual bool ReadBytes(void* dest,
166 : size_t count,
167 E : size_t* bytes_read) OVERRIDE {
168 E : if (pos() >= length())
169 i : return false;
170 E : size_t max_count = length() - pos();
171 E : *bytes_read = max_count < count ? max_count : count;
172 E : ::memcpy(dest, bytes_ + pos(), *bytes_read);
173 E : Seek(pos() + *bytes_read);
174 E : return *bytes_read == count;
175 E : }
176 :
177 : private:
178 : const uint8* const bytes_;
179 : };
180 :
181 : // Comparison operator for PdbInfoHeader70 objects.
182 : bool AreEqual(const PdbInfoHeader70& header1,
183 E : const PdbInfoHeader70& header2) {
184 E : return ::memcmp(&header1, &header2, sizeof(header1)) == 0;
185 E : }
186 :
187 : } // namespace
188 :
189 E : TEST(PdbBitSetTest, ReadEmptyStream) {
190 E : scoped_refptr<PdbStream> stream(new TestPdbStream());
191 E : PdbBitSet bs;
192 E : EXPECT_FALSE(bs.Read(stream.get()));
193 E : }
194 :
195 E : TEST(PdbBitSetTest, SimpleMutators) {
196 E : PdbBitSet bs;
197 E : EXPECT_TRUE(bs.IsEmpty());
198 E : EXPECT_EQ(bs.size(), 0u);
199 E : bs.Resize(43);
200 E : EXPECT_EQ(bs.size(), 64u);
201 :
202 E : for (size_t i = 0; i < 64; ++i)
203 E : EXPECT_FALSE(bs.IsSet(i));
204 :
205 E : bs.Toggle(15);
206 E : EXPECT_TRUE(bs.IsSet(15));
207 E : bs.Toggle(15);
208 E : EXPECT_FALSE(bs.IsSet(15));
209 :
210 E : bs.Set(25);
211 E : EXPECT_TRUE(bs.IsSet(25));
212 E : bs.Clear(25);
213 E : EXPECT_FALSE(bs.IsSet(25));
214 :
215 E : for (size_t i = 0; i < 64; i += 10)
216 E : bs.Set(i);
217 :
218 E : for (size_t i = 0; i < 64; ++i)
219 E : EXPECT_EQ((i % 10) == 0, bs.IsSet(i));
220 E : }
221 :
222 E : TEST(PdbBitSetTest, ReadEmptyBitSet) {
223 E : const uint32 kSize = 0;
224 E : scoped_refptr<PdbStream> stream(new TestPdbStream(kSize));
225 E : PdbBitSet bs;
226 E : EXPECT_TRUE(bs.Read(stream.get()));
227 E : EXPECT_TRUE(bs.IsEmpty());
228 E : EXPECT_EQ(bs.size(), 0u);
229 E : }
230 :
231 E : TEST(PdbBitSetTest, ReadSingleDwordBitSet) {
232 E : const uint32 kData[] = { 1, (1<<0) | (1<<5) | (1<<13) };
233 E : scoped_refptr<PdbStream> stream(new TestPdbStream(kData));
234 E : PdbBitSet bs;
235 E : EXPECT_TRUE(bs.Read(stream.get()));
236 E : EXPECT_FALSE(bs.IsEmpty());
237 E : EXPECT_EQ(bs.size(), 32u);
238 E : for (size_t i = 0; i < bs.size(); ++i)
239 E : EXPECT_EQ(i == 0 || i == 5 || i == 13, bs.IsSet(i));
240 E : }
241 :
242 E : TEST(PdbBitSetTest, ReadMultiDwordBitSet) {
243 E : const uint32 kData[] = { 2, (1<<0) | (1<<5) | (1<<13), (1<<5) };
244 E : scoped_refptr<PdbStream> stream(new TestPdbStream(kData));
245 E : PdbBitSet bs;
246 E : EXPECT_TRUE(bs.Read(stream.get()));
247 E : EXPECT_FALSE(bs.IsEmpty());
248 E : EXPECT_EQ(bs.size(), 64u);
249 E : for (size_t i = 0; i < bs.size(); ++i)
250 E : EXPECT_EQ(i == 0 || i == 5 || i == 13 || i == (32 + 5), bs.IsSet(i));
251 E : }
252 :
253 E : TEST(PdbBitSetTest, WriteEmptyBitSet) {
254 E : const uint32 kData[] = { 0 };
255 E : scoped_refptr<PdbStream> stream(new TestPdbStream(kData));
256 E : PdbBitSet bs;
257 E : EXPECT_TRUE(bs.Read(stream.get()));
258 :
259 E : scoped_refptr<PdbByteStream> reader(new PdbByteStream());
260 E : scoped_refptr<WritablePdbStream> writer(reader->GetWritablePdbStream());
261 E : EXPECT_TRUE(bs.Write(writer.get(), true));
262 E : EXPECT_EQ(sizeof(kData), reader->length());
263 :
264 E : std::vector<uint32> data;
265 E : EXPECT_TRUE(reader->Read(&data, arraysize(kData)));
266 E : EXPECT_THAT(data, testing::ElementsAreArray(kData));
267 E : }
268 :
269 E : TEST(PdbBitSetTest, WriteEmptyBitSetWithoutSize) {
270 E : const uint32 kData[] = { 0 };
271 E : scoped_refptr<PdbStream> stream(new TestPdbStream(kData));
272 E : PdbBitSet bs;
273 E : EXPECT_TRUE(bs.Read(stream.get()));
274 :
275 E : scoped_refptr<PdbByteStream> reader(new PdbByteStream());
276 E : scoped_refptr<WritablePdbStream> writer(reader->GetWritablePdbStream());
277 E : EXPECT_TRUE(bs.Write(writer.get(), false));
278 :
279 E : EXPECT_EQ(0, reader->length());
280 E : }
281 :
282 E : TEST(PdbBitSetTest, WriteBitSet) {
283 E : const uint32 kData[] = { 2, (1<<0) | (1<<5) | (1<<13), (1<<5) };
284 E : scoped_refptr<PdbStream> stream(new TestPdbStream(kData));
285 E : PdbBitSet bs;
286 E : EXPECT_TRUE(bs.Read(stream.get()));
287 :
288 E : scoped_refptr<PdbByteStream> reader(new PdbByteStream());
289 E : scoped_refptr<WritablePdbStream> writer(reader->GetWritablePdbStream());
290 E : EXPECT_TRUE(bs.Write(writer.get(), true));
291 E : EXPECT_EQ(sizeof(kData), reader->length());
292 :
293 E : std::vector<uint32> data;
294 E : EXPECT_TRUE(reader->Read(&data, arraysize(kData)));
295 E : EXPECT_THAT(data, testing::ElementsAreArray(kData));
296 E : }
297 :
298 E : TEST(PdbBitSetTest, WriteBitSetWithoutSize) {
299 E : const uint32 kInputData[] = { 2, (1 << 0) | (1 << 5) | (1 << 13), (1 << 5) };
300 E : const uint32 kExpectedData[] = { (1 << 0) | (1 << 5) | (1 << 13), (1 << 5) };
301 E : scoped_refptr<PdbStream> stream(new TestPdbStream(kInputData));
302 E : PdbBitSet bs;
303 E : EXPECT_TRUE(bs.Read(stream.get()));
304 :
305 E : scoped_refptr<PdbByteStream> reader(new PdbByteStream());
306 E : scoped_refptr<WritablePdbStream> writer(reader->GetWritablePdbStream());
307 E : EXPECT_TRUE(bs.Write(writer.get(), false));
308 E : EXPECT_EQ(sizeof(kExpectedData), reader->length());
309 :
310 E : std::vector<uint32> data;
311 E : EXPECT_TRUE(reader->Read(&data, arraysize(kExpectedData)));
312 E : EXPECT_THAT(data, testing::ElementsAreArray(kExpectedData));
313 E : }
314 :
315 E : TEST_F(PdbUtilTest, HashString) {
316 E : EXPECT_EQ(1024, HashString(""));
317 E : EXPECT_EQ(20527, HashString("___onexitend"));
318 E : EXPECT_EQ(24736, HashString("__imp____getmainargs"));
319 E : EXPECT_EQ(61647, HashString("___security_cookie"));
320 E : }
321 :
322 E : TEST_F(PdbUtilTest, GetDbiDbgHeaderOffsetTestDll) {
323 : // Test the test_dll.dll.pdb doesn't have Omap information.
324 E : PdbReader reader;
325 E : PdbFile pdb_file;
326 : EXPECT_TRUE(reader.Read(
327 : testing::GetSrcRelativePath(testing::kTestPdbFilePath),
328 E : &pdb_file));
329 :
330 E : PdbStream* dbi_stream = pdb_file.GetStream(kDbiStream);
331 : DbiHeader dbi_header;
332 E : EXPECT_TRUE(dbi_stream->Read(&dbi_header, 1));
333 :
334 E : uint32 offset = GetDbiDbgHeaderOffset(dbi_header);
335 E : EXPECT_LE(offset, dbi_stream->length() - sizeof(DbiDbgHeader));
336 :
337 E : EXPECT_TRUE(dbi_stream->Seek(offset));
338 : DbiDbgHeader dbi_dbg_header;
339 E : EXPECT_TRUE(dbi_stream->Read(&dbi_dbg_header, 1));
340 :
341 E : EXPECT_EQ(-1, dbi_dbg_header.omap_to_src);
342 E : EXPECT_EQ(-1, dbi_dbg_header.omap_from_src);
343 E : }
344 :
345 E : TEST_F(PdbUtilTest, GetDbiDbgHeaderOffsetOmappedTestDll) {
346 : // Test that omapped_test_dll.dll.pdb does have Omap information.
347 E : PdbReader reader;
348 E : PdbFile pdb_file;
349 : EXPECT_TRUE(reader.Read(
350 : testing::GetSrcRelativePath(testing::kOmappedTestPdbFilePath),
351 E : &pdb_file));
352 :
353 E : PdbStream* dbi_stream = pdb_file.GetStream(kDbiStream);
354 : DbiHeader dbi_header;
355 E : EXPECT_TRUE(dbi_stream->Read(&dbi_header, 1));
356 :
357 E : uint32 offset = GetDbiDbgHeaderOffset(dbi_header);
358 E : EXPECT_LE(offset, dbi_stream->length() - sizeof(DbiDbgHeader));
359 :
360 E : EXPECT_TRUE(dbi_stream->Seek(offset));
361 : DbiDbgHeader dbi_dbg_header;
362 E : EXPECT_TRUE(dbi_stream->Read(&dbi_dbg_header, 1));
363 :
364 E : EXPECT_NE(-1, dbi_dbg_header.omap_to_src);
365 E : EXPECT_NE(-1, dbi_dbg_header.omap_from_src);
366 E : }
367 :
368 E : TEST_F(PdbUtilTest, TestDllHasNoOmap) {
369 : // Test that test_dll.dll.pdb has no Omap information.
370 : base::FilePath test_pdb_file_path = testing::GetSrcRelativePath(
371 E : testing::kTestPdbFilePath);
372 : DWORD64 base_address =
373 : ::SymLoadModuleExW(process_,
374 : NULL,
375 : test_pdb_file_path.value().c_str(),
376 : NULL,
377 : 1,
378 : 1,
379 : NULL,
380 E : 0);
381 E : EXPECT_NE(0, base_address);
382 :
383 E : OMAP* omap_to = NULL;
384 E : DWORD64 omap_to_length = 0;
385 E : OMAP* omap_from = NULL;
386 E : DWORD64 omap_from_length = 0;
387 : EXPECT_FALSE(::SymGetOmaps(process_,
388 : base_address,
389 : &omap_to,
390 : &omap_to_length,
391 : &omap_from,
392 E : &omap_from_length));
393 :
394 E : EXPECT_TRUE(::SymUnloadModule64(process_, base_address));
395 E : }
396 :
397 E : TEST_F(PdbUtilTest, SetOmapToAndFromStream) {
398 : // Add Omap information to test_dll.pdb and test that the output file
399 : // has Omap information.
400 : std::vector<OMAP> omap_to_list(kOmapToData,
401 E : kOmapToData + arraysize(kOmapToData));
402 : std::vector<OMAP> omap_from_list(kOmapFromData,
403 E : kOmapFromData + arraysize(kOmapFromData));
404 :
405 : base::FilePath test_pdb_file_path = testing::GetSrcRelativePath(
406 E : testing::kTestPdbFilePath);
407 E : PdbReader pdb_reader;
408 E : PdbFile pdb_file;
409 E : ASSERT_TRUE(pdb_reader.Read(test_pdb_file_path, &pdb_file));
410 :
411 E : EXPECT_TRUE(SetOmapToStream(omap_to_list, &pdb_file));
412 E : EXPECT_TRUE(SetOmapFromStream(omap_from_list, &pdb_file));
413 :
414 E : PdbWriter pdb_writer;
415 E : ASSERT_TRUE(pdb_writer.Write(temp_pdb_file_path_, pdb_file));
416 :
417 : VerifyOmapData(temp_pdb_file_path_,
418 : omap_to_list,
419 E : omap_from_list);
420 E : }
421 :
422 E : TEST_F(PdbUtilTest, PdbHeaderMatchesImageDebugDirectory) {
423 E : PdbReader reader;
424 E : PdbFile pdb_file;
425 : EXPECT_TRUE(reader.Read(
426 : testing::GetSrcRelativePath(testing::kTestPdbFilePath),
427 E : &pdb_file));
428 :
429 E : PdbInfoHeader70 header = { 0 };
430 E : ASSERT_GE(pdb_file.StreamCount(), kPdbHeaderInfoStream);
431 E : ASSERT_TRUE(pdb_file.GetStream(kPdbHeaderInfoStream) != NULL);
432 E : EXPECT_TRUE(pdb_file.GetStream(kPdbHeaderInfoStream)->Read(&header, 1));
433 E : EXPECT_EQ(header.version, kPdbCurrentVersion);
434 :
435 E : base::NativeLibraryLoadError error;
436 : base::NativeLibrary test_dll =
437 : base::LoadNativeLibrary(
438 : testing::GetSrcRelativePath(testing::kTestDllFilePath),
439 E : &error);
440 E : ASSERT_TRUE(test_dll != NULL);
441 :
442 : // Make sure the DLL is unloaded on exit.
443 E : base::ScopedNativeLibrary test_dll_keeper(test_dll);
444 E : base::win::PEImage image(test_dll);
445 :
446 : // Retrieve the NT headers to make it easy to look at them in debugger.
447 E : const IMAGE_NT_HEADERS* nt_headers = image.GetNTHeaders();
448 :
449 : ASSERT_EQ(sizeof(IMAGE_DEBUG_DIRECTORY),
450 E : image.GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_DEBUG));
451 : const IMAGE_DEBUG_DIRECTORY* debug_directory =
452 : reinterpret_cast<const IMAGE_DEBUG_DIRECTORY*>(
453 E : image.GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_DEBUG));
454 :
455 E : ASSERT_EQ(IMAGE_DEBUG_TYPE_CODEVIEW, debug_directory->Type);
456 E : ASSERT_GE(debug_directory->SizeOfData, sizeof(pe::CvInfoPdb70));
457 :
458 : const pe::CvInfoPdb70* cv_info =
459 : reinterpret_cast<const pe::CvInfoPdb70*>(
460 E : image.RVAToAddr(debug_directory->AddressOfRawData));
461 :
462 E : ASSERT_EQ(pe::kPdb70Signature, cv_info->cv_signature);
463 E : ASSERT_EQ(header.signature, cv_info->signature);
464 E : ASSERT_EQ(header.pdb_age, cv_info->pdb_age);
465 E : }
466 :
467 E : TEST_F(PdbUtilTest, ReadPdbHeader) {
468 : const base::FilePath pdb_path = testing::GetSrcRelativePath(
469 E : testing::kTestPdbFilePath);
470 E : PdbInfoHeader70 pdb_header = {};
471 E : EXPECT_TRUE(ReadPdbHeader(pdb_path, &pdb_header));
472 E : }
473 :
474 E : TEST(EnsureStreamWritableTest, DoesNothingWhenAlreadyWritable) {
475 E : PdbFile pdb_file;
476 E : scoped_refptr<PdbStream> stream = new PdbByteStream();
477 E : size_t index = pdb_file.AppendStream(stream.get());
478 E : EXPECT_TRUE(EnsureStreamWritable(index, &pdb_file));
479 E : scoped_refptr<PdbStream> stream2 = pdb_file.GetStream(index);
480 E : EXPECT_EQ(stream.get(), stream2.get());
481 E : }
482 :
483 E : TEST(EnsureStreamWritableTest, WorksWhenReadOnly) {
484 E : PdbFile pdb_file;
485 E : scoped_refptr<PdbStream> stream = new TestPdbStream();
486 E : size_t index = pdb_file.AppendStream(stream.get());
487 E : EXPECT_TRUE(EnsureStreamWritable(index, &pdb_file));
488 E : scoped_refptr<PdbStream> stream2 = pdb_file.GetStream(index);
489 E : EXPECT_TRUE(stream2.get() != NULL);
490 E : EXPECT_NE(stream.get(), stream2.get());
491 E : EXPECT_TRUE(stream2->GetWritablePdbStream() != NULL);
492 E : }
493 :
494 E : TEST(EnsureStreamWritableTest, FailsWhenNonExistent) {
495 E : PdbFile pdb_file;
496 E : EXPECT_FALSE(EnsureStreamWritable(45, &pdb_file));
497 E : }
498 :
499 E : TEST(SetGuidTest, FailsWhenStreamsDoNotExist) {
500 E : PdbFile pdb_file;
501 :
502 : // Leave the Pdb header missing.
503 E : pdb_file.SetStream(kPdbHeaderInfoStream, NULL);
504 E : pdb_file.SetStream(kDbiStream, new TestPdbStream(kSampleDbiHeader));
505 E : EXPECT_FALSE(SetGuid(kSampleGuid, &pdb_file));
506 :
507 : // Add the header stream, but leave the Dbi header missing.
508 E : pdb_file.SetStream(kPdbHeaderInfoStream, new TestPdbStream(kSamplePdbHeader));
509 E : pdb_file.SetStream(kDbiStream, NULL);
510 E : EXPECT_FALSE(SetGuid(kSampleGuid, &pdb_file));
511 E : }
512 :
513 E : TEST(SetGuidTest, FailsWhenStreamsAreTooShort) {
514 E : PdbFile pdb_file;
515 :
516 E : const uint8 kByte = 6;
517 E : pdb_file.SetStream(kPdbHeaderInfoStream, new TestPdbStream(kByte));
518 E : pdb_file.SetStream(kDbiStream, new TestPdbStream(kSampleDbiHeader));
519 E : EXPECT_FALSE(SetGuid(kSampleGuid, &pdb_file));
520 :
521 E : pdb_file.SetStream(kPdbHeaderInfoStream, new TestPdbStream(kSamplePdbHeader));
522 E : pdb_file.SetStream(kDbiStream, new TestPdbStream(kByte));
523 E : EXPECT_FALSE(SetGuid(kSampleGuid, &pdb_file));
524 E : }
525 :
526 E : TEST(SetGuidTest, Succeeds) {
527 E : PdbFile pdb_file;
528 :
529 E : pdb_file.SetStream(kPdbHeaderInfoStream, new TestPdbStream(kSamplePdbHeader));
530 E : pdb_file.SetStream(kDbiStream, new TestPdbStream(kSampleDbiHeader));
531 :
532 : scoped_refptr<PdbStream> stream =
533 E : pdb_file.GetStream(kPdbHeaderInfoStream);
534 E : ASSERT_TRUE(stream.get() != NULL);
535 E : ASSERT_EQ(stream->length(), sizeof(PdbInfoHeader70));
536 :
537 E : uint32 time1 = static_cast<uint32>(time(NULL));
538 E : EXPECT_TRUE(SetGuid(kSampleGuid, &pdb_file));
539 E : uint32 time2 = static_cast<uint32>(time(NULL));
540 :
541 : // Read the new header.
542 E : PdbInfoHeader70 pdb_header = {};
543 E : stream = pdb_file.GetStream(kPdbHeaderInfoStream);
544 E : EXPECT_TRUE(stream->Seek(0));
545 E : EXPECT_TRUE(stream->Read(&pdb_header, 1));
546 :
547 : // Validate that the fields are as expected.
548 E : EXPECT_LE(time1, pdb_header.timestamp);
549 E : EXPECT_LE(pdb_header.timestamp, time2);
550 E : EXPECT_EQ(1u, pdb_header.pdb_age);
551 E : EXPECT_EQ(kSampleGuid, pdb_header.signature);
552 :
553 E : DbiHeader dbi_header = {};
554 E : stream = pdb_file.GetStream(kDbiStream);
555 E : ASSERT_TRUE(stream.get() != NULL);
556 E : ASSERT_EQ(stream->length(), sizeof(dbi_header));
557 :
558 E : EXPECT_TRUE(stream->Seek(0));
559 E : EXPECT_TRUE(stream->Read(&dbi_header, 1));
560 E : EXPECT_EQ(1u, dbi_header.age);
561 E : }
562 :
563 E : TEST(ReadHeaderInfoStreamTest, ReadFromPdbFile) {
564 : const base::FilePath pdb_path = testing::GetSrcRelativePath(
565 E : testing::kTestPdbFilePath);
566 :
567 E : PdbFile pdb_file;
568 E : PdbReader pdb_reader;
569 E : ASSERT_TRUE(pdb_reader.Read(pdb_path, &pdb_file));
570 :
571 E : PdbInfoHeader70 pdb_header = {};
572 E : NameStreamMap name_stream_map;
573 E : EXPECT_TRUE(ReadHeaderInfoStream(pdb_file, &pdb_header, &name_stream_map));
574 E : }
575 :
576 E : TEST(ReadHeaderInfoStreamTest, ReadEmptyStream) {
577 E : scoped_refptr<PdbStream> stream(new TestPdbStream());
578 E : PdbInfoHeader70 pdb_header = {};
579 E : NameStreamMap name_stream_map;
580 E : EXPECT_FALSE(ReadHeaderInfoStream(stream, &pdb_header, &name_stream_map));
581 E : }
582 :
583 E : TEST(ReadHeaderInfoStreamTest, ReadStreamWithOnlyHeader) {
584 E : scoped_refptr<PdbStream> reader(new PdbByteStream());
585 E : scoped_refptr<WritablePdbStream> writer(reader->GetWritablePdbStream());
586 :
587 E : PdbInfoHeader70 pdb_header = {};
588 E : ASSERT_TRUE(writer->Write(pdb_header));
589 :
590 E : NameStreamMap name_stream_map;
591 E : EXPECT_FALSE(ReadHeaderInfoStream(reader, &pdb_header, &name_stream_map));
592 E : }
593 :
594 E : TEST(ReadHeaderInfoStreamTest, ReadStreamWithEmptyNameStreamMap) {
595 E : scoped_refptr<PdbStream> reader(new PdbByteStream());
596 E : scoped_refptr<WritablePdbStream> writer(reader->GetWritablePdbStream());
597 :
598 E : PdbInfoHeader70 pdb_header = {};
599 E : ASSERT_TRUE(writer->Write(pdb_header));
600 E : ASSERT_TRUE(writer->Write(static_cast<uint32>(0))); // total string length.
601 E : ASSERT_TRUE(writer->Write(static_cast<uint32>(0))); // number of names.
602 E : ASSERT_TRUE(writer->Write(static_cast<uint32>(0))); // size of bitsets.
603 E : ASSERT_TRUE(writer->Write(static_cast<uint32>(0))); // first bitset.
604 E : ASSERT_TRUE(writer->Write(static_cast<uint32>(0))); // second bitset.
605 :
606 E : NameStreamMap name_stream_map;
607 E : EXPECT_TRUE(ReadHeaderInfoStream(reader, &pdb_header, &name_stream_map));
608 E : EXPECT_EQ(name_stream_map.size(), 0u);
609 E : }
610 :
611 E : TEST(ReadHeaderInfoStreamTest, ReadStreamWithNameStreamMap) {
612 E : scoped_refptr<PdbStream> reader(new PdbByteStream());
613 E : scoped_refptr<WritablePdbStream> writer(reader->GetWritablePdbStream());
614 :
615 E : PdbInfoHeader70 pdb_header = {};
616 E : ASSERT_TRUE(writer->Write(pdb_header));
617 E : ASSERT_TRUE(writer->Write(static_cast<uint32>(9))); // total string length.
618 E : uint32 offset1 = writer->pos();
619 E : ASSERT_TRUE(writer->Write(3, "/a")); // name 1.
620 E : uint32 offset2 = writer->pos();
621 E : ASSERT_TRUE(writer->Write(3, "/b")); // name 2.
622 E : uint32 offset3 = writer->pos();
623 E : ASSERT_TRUE(writer->Write(3, "/c")); // name 3.
624 E : ASSERT_TRUE(writer->Write(static_cast<uint32>(3))); // number of names.
625 E : ASSERT_TRUE(writer->Write(static_cast<uint32>(3))); // size of bitsets.
626 :
627 E : PdbBitSet present;
628 E : present.Resize(3);
629 E : present.Set(0);
630 E : present.Set(1);
631 E : present.Set(2);
632 E : ASSERT_TRUE(present.Write(writer, true));
633 :
634 E : ASSERT_TRUE(writer->Write(static_cast<uint32>(0))); // second bitset.
635 :
636 E : ASSERT_TRUE(writer->Write(0));
637 E : ASSERT_TRUE(writer->Write(static_cast<uint32>(42)));
638 E : ASSERT_TRUE(writer->Write(offset2 - offset1));
639 E : ASSERT_TRUE(writer->Write(static_cast<uint32>(7)));
640 E : ASSERT_TRUE(writer->Write(offset3 - offset1));
641 E : ASSERT_TRUE(writer->Write(static_cast<uint32>(95)));
642 :
643 E : NameStreamMap name_stream_map;
644 E : EXPECT_TRUE(ReadHeaderInfoStream(reader, &pdb_header, &name_stream_map));
645 :
646 E : NameStreamMap expected;
647 E : expected["/a"] = 42;
648 E : expected["/b"] = 7;
649 E : expected["/c"] = 95;
650 E : EXPECT_THAT(name_stream_map, testing::ContainerEq(expected));
651 E : }
652 :
653 E : TEST(ReadHeaderInfoStreamTest, ReadFromPdb) {
654 : const base::FilePath pdb_path = testing::GetSrcRelativePath(
655 E : testing::kTestPdbFilePath);
656 E : PdbFile pdb_file;
657 E : PdbReader pdb_reader;
658 E : EXPECT_TRUE(pdb_reader.Read(pdb_path, &pdb_file));
659 :
660 E : PdbInfoHeader70 pdb_header = {};
661 E : NameStreamMap name_stream_map;
662 : EXPECT_TRUE(ReadHeaderInfoStream(pdb_file.GetStream(kPdbHeaderInfoStream),
663 : &pdb_header,
664 E : &name_stream_map));
665 E : }
666 :
667 E : TEST(WriteHeaderInfoStreamTest, WriteToPdbFile) {
668 : const base::FilePath pdb_path = testing::GetSrcRelativePath(
669 E : testing::kTestPdbFilePath);
670 :
671 E : PdbFile pdb_file;
672 E : PdbReader pdb_reader;
673 E : ASSERT_TRUE(pdb_reader.Read(pdb_path, &pdb_file));
674 :
675 E : PdbInfoHeader70 pdb_header = {};
676 E : NameStreamMap name_stream_map;
677 E : ASSERT_TRUE(ReadHeaderInfoStream(pdb_file, &pdb_header, &name_stream_map));
678 :
679 E : pdb_header.pdb_age++;
680 E : name_stream_map["NewStream!"] = 999;
681 :
682 E : EXPECT_TRUE(WriteHeaderInfoStream(pdb_header, name_stream_map, &pdb_file));
683 :
684 E : PdbInfoHeader70 pdb_header2 = {};
685 E : NameStreamMap name_stream_map2;
686 E : ASSERT_TRUE(ReadHeaderInfoStream(pdb_file, &pdb_header2, &name_stream_map2));
687 :
688 E : EXPECT_TRUE(AreEqual(pdb_header, pdb_header2));
689 E : EXPECT_EQ(name_stream_map, name_stream_map2);
690 E : }
691 :
692 E : TEST(WriteHeaderInfoStreamTest, WriteEmpty) {
693 E : scoped_refptr<PdbStream> reader(new PdbByteStream());
694 E : scoped_refptr<WritablePdbStream> writer(reader->GetWritablePdbStream());
695 :
696 E : NameStreamMap name_stream_map;
697 : EXPECT_TRUE(WriteHeaderInfoStream(kSamplePdbHeader,
698 : name_stream_map,
699 E : writer.get()));
700 :
701 E : PdbInfoHeader70 read_pdb_header = {};
702 E : NameStreamMap read_name_stream_map;
703 : EXPECT_TRUE(ReadHeaderInfoStream(reader.get(),
704 : &read_pdb_header,
705 E : &read_name_stream_map));
706 :
707 : EXPECT_EQ(0, ::memcmp(&kSamplePdbHeader,
708 : &read_pdb_header,
709 E : sizeof(kSamplePdbHeader)));
710 E : EXPECT_THAT(name_stream_map, testing::ContainerEq(read_name_stream_map));
711 E : }
712 :
713 E : TEST(WriteHeaderInfoStreamTest, WriteNonEmpty) {
714 E : scoped_refptr<PdbStream> reader(new PdbByteStream());
715 E : scoped_refptr<WritablePdbStream> writer(reader->GetWritablePdbStream());
716 :
717 E : NameStreamMap name_stream_map;
718 E : name_stream_map["/StreamFoo"] = 9;
719 E : name_stream_map["/StreamBar"] = 42;
720 E : name_stream_map["/Stream/With/A/Path"] = 19;
721 : EXPECT_TRUE(WriteHeaderInfoStream(kSamplePdbHeader,
722 : name_stream_map,
723 E : writer.get()));
724 :
725 E : PdbInfoHeader70 read_pdb_header = {};
726 E : NameStreamMap read_name_stream_map;
727 : EXPECT_TRUE(ReadHeaderInfoStream(reader.get(),
728 : &read_pdb_header,
729 E : &read_name_stream_map));
730 :
731 : EXPECT_EQ(0, ::memcmp(&kSamplePdbHeader,
732 : &read_pdb_header,
733 E : sizeof(kSamplePdbHeader)));
734 E : EXPECT_THAT(name_stream_map, testing::ContainerEq(read_name_stream_map));
735 E : }
736 :
737 E : TEST_F(PdbUtilTest, NamedStreamsWorkWithPdbStr) {
738 : // We start by creating a PDB file (a copy of a checked in sample one) and
739 : // adding a new stream to it using our named-stream implementation.
740 : {
741 : base::FilePath orig_pdb_path = testing::GetSrcRelativePath(
742 E : testing::kTestPdbFilePath);
743 :
744 : // Read the sample PDB.
745 E : PdbReader pdb_reader;
746 E : PdbFile pdb_file;
747 E : ASSERT_TRUE(pdb_reader.Read(orig_pdb_path, &pdb_file));
748 :
749 : // Add a new stream to it.
750 E : scoped_refptr<PdbStream> foo_reader(new PdbByteStream());
751 : scoped_refptr<WritablePdbStream> foo_writer(
752 E : foo_reader->GetWritablePdbStream());
753 E : size_t foo_index = pdb_file.AppendStream(foo_reader.get());
754 E : foo_writer->WriteString("foo");
755 :
756 : // Get the PDB header stream.
757 : scoped_refptr<PdbStream> header_stream(pdb_file.GetStream(
758 E : kPdbHeaderInfoStream));
759 E : ASSERT_TRUE(header_stream.get() != NULL);
760 :
761 : // Read the existing name-stream map.
762 E : PdbInfoHeader70 pdb_header = {};
763 E : NameStreamMap name_stream_map;
764 : ASSERT_TRUE(ReadHeaderInfoStream(
765 E : header_stream, &pdb_header, &name_stream_map));
766 :
767 : // Add an entry for the new stream.
768 E : name_stream_map["foo"] = foo_index;
769 :
770 : // Write the new header stream to it.
771 E : scoped_refptr<PdbStream> new_header_reader(new PdbByteStream());
772 : scoped_refptr<WritablePdbStream> new_header_writer(
773 E : new_header_reader->GetWritablePdbStream());
774 : ASSERT_TRUE(pdb::WriteHeaderInfoStream(
775 E : pdb_header, name_stream_map, new_header_writer));
776 E : pdb_file.ReplaceStream(kPdbHeaderInfoStream, new_header_reader);
777 :
778 : // Write the PDB.
779 E : PdbWriter pdb_writer;
780 E : ASSERT_TRUE(pdb_writer.Write(temp_pdb_file_path_, pdb_file));
781 E : }
782 :
783 : // We've now created a new PDB file. We want to make sure that pdbstr.exe
784 : // plays nicely with our named streams by doing a few things:
785 : // (1) If we try to read a non-existing stream, we should get empty output.
786 : // (2) We should be able to read an existing stream and get non-empty output.
787 : // (3) We should be able to add a new stream, and then read it using our
788 : // mechanisms.
789 :
790 : // Get the path to pdbstr.exe, which we redistribute in third_party.
791 : base::FilePath pdbstr_path =
792 E : testing::GetSrcRelativePath(testing::kPdbStrPath);
793 :
794 : // Create the argument specifying the PDB path.
795 E : std::string pdb_arg = base::WideToUTF8(temp_pdb_file_path_.value());
796 E : pdb_arg.insert(0, "-p:");
797 :
798 : // First test: try to read a non-existing stream. Should produce no output.
799 : {
800 E : CommandLine cmd(pdbstr_path);
801 E : cmd.AppendArg(pdb_arg);
802 E : cmd.AppendArg("-r");
803 E : cmd.AppendArg("-s:nonexistent-stream-name");
804 E : std::string output;
805 E : ASSERT_TRUE(base::GetAppOutput(cmd, &output));
806 E : ASSERT_TRUE(output.empty());
807 E : }
808 :
809 : // Second test: read an existing stream (the one we just added). Should
810 : // exit without error and return the expected contents (with a trailing
811 : // newline).
812 : {
813 E : CommandLine cmd(pdbstr_path);
814 E : cmd.AppendArg(pdb_arg);
815 E : cmd.AppendArg("-r");
816 E : cmd.AppendArg("-s:foo");
817 E : std::string output;
818 E : ASSERT_TRUE(base::GetAppOutput(cmd, &output));
819 E : ASSERT_EQ(std::string("foo\r\n"), output);
820 E : }
821 :
822 : // Third test: Add another new stream. This should return without error, and
823 : // we should then be able to read the stream using our mechanisms.
824 : {
825 E : base::FilePath bar_txt = temp_dir_.path().Append(L"bar.txt");
826 : base::ScopedFILE bar_file(base::OpenFile(
827 E : bar_txt, "wb"));
828 E : fprintf(bar_file.get(), "bar");
829 E : bar_file.reset();
830 :
831 E : std::string bar_arg = base::WideToUTF8(bar_txt.value());
832 E : bar_arg.insert(0, "-i:");
833 :
834 E : CommandLine cmd(pdbstr_path);
835 E : cmd.AppendArg(pdb_arg);
836 E : cmd.AppendArg("-w");
837 E : cmd.AppendArg("-s:bar");
838 E : cmd.AppendArg(bar_arg);
839 E : std::string output;
840 E : ASSERT_TRUE(base::GetAppOutput(cmd, &output));
841 E : ASSERT_TRUE(output.empty());
842 :
843 E : PdbFile pdb_file;
844 E : PdbReader pdb_reader;
845 E : ASSERT_TRUE(pdb_reader.Read(temp_pdb_file_path_, &pdb_file));
846 :
847 : // Get the PDB header stream.
848 : scoped_refptr<PdbStream> header_stream(pdb_file.GetStream(
849 E : kPdbHeaderInfoStream));
850 E : ASSERT_TRUE(header_stream.get() != NULL);
851 :
852 : // Read the existing name-stream map.
853 E : PdbInfoHeader70 pdb_header = {};
854 E : NameStreamMap name_stream_map;
855 : ASSERT_TRUE(ReadHeaderInfoStream(
856 E : header_stream, &pdb_header, &name_stream_map));
857 :
858 : // There should be a 'bar' stream.
859 E : ASSERT_TRUE(name_stream_map.count("bar"));
860 :
861 : // Get the bar stream.
862 : scoped_refptr<PdbStream> bar_stream(pdb_file.GetStream(
863 E : name_stream_map["bar"]));
864 E : ASSERT_TRUE(bar_stream.get() != NULL);
865 :
866 : // Read all of the data and ensure it is as expected.
867 E : bar_stream->Seek(0);
868 E : std::string bar_data;
869 E : bar_data.resize(bar_stream->length());
870 E : ASSERT_TRUE(bar_stream->Read(&bar_data.at(0), bar_data.size()));
871 E : ASSERT_EQ("bar", bar_data);
872 E : }
873 E : }
874 :
875 E : TEST_F(PdbUtilTest, LoadNamedStreamFromPdbFile) {
876 E : PdbReader reader;
877 E : PdbFile pdb_file;
878 : EXPECT_TRUE(reader.Read(
879 : testing::GetOutputRelativePath(testing::kTestDllPdbName),
880 E : &pdb_file));
881 :
882 E : scoped_refptr<PdbStream> stream;
883 : EXPECT_TRUE(LoadNamedStreamFromPdbFile(
884 E : "StreamThatDoesNotExist", &pdb_file, &stream));
885 E : EXPECT_TRUE(stream.get() == NULL);
886 :
887 : // The MSVC toolchain produces a handful of named streams whose existence we
888 : // can rely on.
889 E : EXPECT_TRUE(LoadNamedStreamFromPdbFile("/LinkInfo", &pdb_file, &stream));
890 E : ASSERT_TRUE(stream.get() != NULL);
891 E : }
892 :
893 : } // namespace pdb
|